Skip to content

docs(sdk): guide package scaffolds to define builders - #344

Merged
unbraind merged 4 commits into
mainfrom
sdk-define-scaffold-guidance
Jun 22, 2026
Merged

unbraind merged 4 commits into
mainfrom
sdk-define-scaffold-guidance

Conversation

@unbraind

Copy link
Copy Markdown
Owner

Summary

  • Close pm-3mph by aligning generated package scaffold guidance with the shipped zero-cost define* SDK builder ADR.
  • Keep generated runtime entrypoints import-free for local install-before-npm install, while documenting the defineCommand / defineAfterCommandHook upgrade path in generated package READMEs.
  • Add focused scaffold regression coverage, update package author docs, and regenerate package-owned CHANGELOG.md through pm-changelog.

Verification

  • node scripts/run-tests.mjs test -- tests/unit/extensions/extension-scaffold-define-guidance.spec.ts
  • pm test pm-3mph --run --progress
  • pnpm build
  • pnpm quality:static
  • node scripts/run-tests.mjs coverage = 100/100/100/100, 245 files, 4853 tests
  • pnpm security:scan
  • pnpm contracts:check
  • pnpm changelog:pm && pnpm changelog:pm:check
  • pm package doctor --project --detail deep --json
  • pm health --check-only --summary --json
  • Temp-dir smoke: pm init, pm package init --capability hooks, local install before dependencies, command invocation, generated README define* check, npm install --no-save current checkout, npm test
  • node scripts/release/sentry-telemetry-gate.mjs --json --sentry-window-days 14
  • pm telemetry status --json

GitHub / dependency checks

  • No open PRs at start of work.
  • No open GitHub issues at start of work.
  • Dependabot alerts API returned no open alerts.
  • pnpm audit --audit-level moderate found no known vulnerabilities.
  • pnpm outdated --format json only reported Node-major-bound @types/node 26 and commander 15 while current wanted versions remain pinned.
  • npm view pm-changelog version returned 2026.6.20, matching the installed managed extension version.

Close pm-3mph by aligning generated package scaffolds with the zero-cost define* SDK builder ADR.

- document the defineCommand/defineAfterCommandHook upgrade path in generated package READMEs while preserving import-free entrypoints for install-before-dependencies

- add scaffold regression coverage and update package authoring docs

- regenerate package-owned CHANGELOG.md through pm-changelog

Verification: node scripts/run-tests.mjs test -- tests/unit/extensions/extension-scaffold-define-guidance.spec.ts; pm test pm-3mph --run --progress; pnpm build; pnpm quality:static; node scripts/run-tests.mjs coverage (100/100/100/100, 245 files, 4853 tests); pnpm security:scan; pnpm contracts:check; pnpm changelog:pm && pnpm changelog:pm:check; pm package doctor --project --detail deep --json; pm health --check-only --summary --json; temp-dir package init/install/npm test smoke; sentry/telemetry gate.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @unbraind, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@unbraind

Copy link
Copy Markdown
Owner Author

@codex review
/gemini review
@gemini-code-assist
@coderabbitai full review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@unbraind, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 37 minutes and 20 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: f25ff5fa-5c63-4ea9-ae32-3a844142e6d5

📥 Commits

Reviewing files that changed from the base of the PR and between 46a231e and 22930e3.

📒 Files selected for processing (5)
  • .agents/pm/decisions/pm-3mph.toon
  • .agents/pm/history/pm-3mph.jsonl
  • docs/EXTENSIONS.md
  • src/cli/commands/extension/scaffold.ts
  • tests/unit/extensions/extension-scaffold-define-guidance.spec.ts
📝 Walkthrough

Walkthrough

Adds an "Authoring With define* Builders" section to the scaffold-generated package README in scaffold.ts, with a new Vitest spec verifying its presence in local-install scaffolds and absence in standalone scaffolds. Companion updates to docs/EXTENSIONS.md and CHANGELOG.md align documentation, and the pm-3mph ADR is closed with full lifecycle records.

Changes

Extension scaffold define* guidance

Layer / File(s) Summary
Scaffold README define* section and tests
src/cli/commands/extension/scaffold.ts, tests/unit/extensions/extension-scaffold-define-guidance.spec.ts
Inserts an "Authoring With define* Builders" README section into the package scaffold output, including a defineCommand/defineAfterCommandHook snippet and a pass-through/validation note. A new Vitest spec asserts that the local-install scaffold README contains the section and SDK import while the standalone scaffold omits it, and that neither variant adds a runtime SDK import to the entrypoint.
EXTENSIONS.md and CHANGELOG updates
docs/EXTENSIONS.md, CHANGELOG.md
Adds a clarification in EXTENSIONS.md that the generated entrypoint stays import-free for the first local install and should later graduate to define* builders; inserts a new authoring-notes paragraph enumerating define* builder types. Adds a CHANGELOG entry for the define* builders ADR.
ADR pm-3mph closure records
.agents/pm/decisions/pm-3mph.toon, .agents/pm/history/pm-3mph.jsonl
Transitions the pm-3mph ADR from open to closed, recording resolution, expected/actual results, evidence comments, affected files, a regression test reference, and a close reason. The JSONL history records the full lifecycle from in_progress assignment through artifact additions, test-run evidence, closeout metadata, and a final release step.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • unbraind/pm-cli#321: Also modifies buildStarterExtensionScaffoldFiles scaffold output, updating the generated README/testing scaffolding with index.test.js, .gitignore, and npm test.
  • unbraind/pm-cli#342: Introduces the SDK define* authoring builders that this PR's scaffold guidance and ADR closeout reference.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: updating generated package scaffolds with guidance for the define builders SDK pattern.
Description check ✅ Passed The description is directly related to the changeset, providing clear context about closing an ADR, updating scaffold documentation, and adding test coverage.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get PR details
gh pr view 344 --repo unbraind/pm-cli --json title,body,additions,deletions,changedFiles,baseRefName,headRefName

echo "---FILES---"
gh pr diff 344 --repo unbraind/pm-cli --name-only

echo "---DIFF---"
gh pr diff 344 --repo unbraind/pm-cli

Length of output: 30132



@unbraind — here is the full review.


Review: docs(sdk): guide package scaffolds to define builders

Overall: The PR is well-scoped, thoroughly verified, and the code matches the stated intent. The three substantive areas (scaffold template, docs, tests) are internally consistent. A few minor observations below.


src/cli/commands/extension/scaffold.ts

1. defineAfterCommandHook example shown for all package capabilities

The new README block is added to the generated template regardless of the capability flag:

"export const afterCommandHook = defineAfterCommandHook((context) => {",

For a --capability commands-only package there is no hook registration, so showing defineAfterCommandHook in the upgrade path could be slightly confusing — a reader might wonder why it's there when the scaffold has no hook. It's not wrong (it's reference documentation), but it may cause unnecessary questions. Consider either:

  • scoping the hook example to capabilities that include hooks, or
  • adding a brief comment like // (only needed if you add hook registrations) to make it clear it's optional.

2. Generated command name in the snippet

JSON.stringify(commandName) correctly handles names with spaces or special characters — good defensive choice.


tests/unit/extensions/extension-scaffold-define-guidance.spec.ts

3. Missing coverage for package + commands

The spec covers:

  • package + hooks → section present ✅
  • extension + commands → section absent ✅

It doesn't exercise package + commands. If the define* section is only conditional on the type (package), a third test would confirm the section appears for commands-capability packages and make the coverage exhaustive:

it("adds define* guidance to package scaffolds with commands capability", () => {
  const scaffold = buildStarterExtensionScaffoldFiles("tool-kit", "tool kit ping", "package", "commands");
  expect(scaffold["README.md"] ?? "").toContain("## Authoring With define* Builders");
  expect(scaffold["index.js"] ?? "").not.toContain('from "`@unbrained/pm-cli/sdk`"');
});

docs/EXTENSIONS.md

4. Paragraph density

The existing pm package init paragraph is already very long (a single wall of text). The new sentence is consistent with the established style, so this isn't a blocker — just flagging that a follow-up refactor into bullet points or sub-sections would improve skimmability as the paragraph continues to grow.

5. Placement of the new define* paragraph — ✅ correct

Inserting the define* builders recommendation between the "import ergonomics" discussion and the createExtensionTestHarness guidance is the right logical position.


CHANGELOG.md

define\* backslash-escape is correct for Markdown rendering in the changelog — no issues.


Agent / PM tracking files

Append-only, well-structured, no issues.


Summary table

Area Finding Severity
scaffold.ts defineAfterCommandHook shown for all capabilities Minor
Test spec package+commands combination not exercised Minor
EXTENSIONS.md Long single paragraph style Nit
Everything else Correct and consistent ✅

The changes are approved from a logic and correctness standpoint. The two minor items above are worth a quick pass before merging but won't break anything.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request closes the ADR pm-3mph by updating the extension documentation and package scaffolds to guide authors on upgrading to zero-cost define* SDK builders, while keeping the initial entrypoint import-free. A unit test was also added to verify the scaffolded output. The reviewer suggested expanding the README code example to include the activate and deactivate functions so that the example is fully functional and copy-pasteable.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/cli/commands/extension/scaffold.ts Outdated
Comment on lines +617 to +630
"```js",
'import { defineCommand, defineAfterCommandHook } from "@unbrained/pm-cli/sdk";',
"",
"export const pingCommand = defineCommand({",
` name: ${JSON.stringify(commandName)},`,
' description: "Starter scaffold command. Replace with your own behavior.",',
" run: (context) => ({ ok: true, command: context.command }),",
"});",
"",
"export const afterCommandHook = defineAfterCommandHook((context) => {",
" if (!context.ok) return;",
" // React to context.affected here as your package grows.",
"});",
"```",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The code example showing how to use the define* builders is helpful, but it only defines the command and hook without showing how they should be registered inside the activate function. If a package author replaces their index.js with this example, the extension will fail to load because it lacks the activate export and registration calls. Showing the complete activate and deactivate exports makes the example fully copy-pasteable and functional.

      "import { defineCommand, defineAfterCommandHook } from \"@unbrained/pm-cli/sdk\";",
      "",
      "export const pingCommand = defineCommand({",
      "  name: " + JSON.stringify(commandName) + ",",
      "  description: \"Starter scaffold command. Replace with your own behavior.\",",
      "  run: (context) => ({ ok: true, command: context.command }),",
      "});",
      "",
      "export const afterCommandHook = defineAfterCommandHook((context) => {",
      "  if (!context.ok) return;",
      "  // React to context.affected here as your package grows.",
      "});",
      "",
      "export function activate(api) {",
      "  api.registerCommand(pingCommand);",
      "  api.hooks.afterCommand(afterCommandHook);",
      "}",
      "",
      "export function deactivate() {}",
      "",
      "export default {",
      "  activate,",
      "  deactivate,",
      "};",

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/EXTENSIONS.md`:
- Around line 424-425: The new documentation section introducing the "Prefer the
`define*` builders" guidance in docs/EXTENSIONS.md (lines 424-425) lacks a
tracker reference to the pm-3mph ADR decision that drove this change, which
violates the coding guideline for documentation files. Add an inline tracker
reference to pm-3mph near or within this section to improve traceability and
connect the documentation guidance to its underlying decision. The reference
should be formatted as a link following the pattern already established in the
codebase, placed where it provides clear context that this guidance originated
from the pm-3mph decision.
- Line 90: The expanded package init explanation on line 90 mentions upgrading
to SDK define* builders without referencing the pm-3mph ADR that introduced this
upgrade path. Locate the phrase "graduate exported command/hook definitions to
the SDK `define*` builders" in EXTENSIONS.md and convert the backtick-enclosed
"define* builders" text into a markdown link pointing to the pm-3mph ADR
decision document, following the inline reference pattern shown in the review
comment to provide consistency with coding guidelines and CHANGELOG patterns.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: d07697a3-5202-4ec0-9c62-266f516cf689

📥 Commits

Reviewing files that changed from the base of the PR and between d55645d and 46a231e.

📒 Files selected for processing (6)
  • .agents/pm/decisions/pm-3mph.toon
  • .agents/pm/history/pm-3mph.jsonl
  • CHANGELOG.md
  • docs/EXTENSIONS.md
  • src/cli/commands/extension/scaffold.ts
  • tests/unit/extensions/extension-scaffold-define-guidance.spec.ts

Comment thread docs/EXTENSIONS.md Resolved
Comment thread docs/EXTENSIONS.md Resolved
Address PR #344 CodeRabbit feedback by marking the hook builder example as optional unless a package declares/registers hooks, and by covering package+commands scaffolds for the generated define* guidance.

Verification: node scripts/run-tests.mjs test -- tests/unit/extensions/extension-scaffold-define-guidance.spec.ts; pnpm build; pnpm quality:static.
@unbraind

Copy link
Copy Markdown
Owner Author

New head pushed after addressing CodeRabbit minor feedback: 38d546e.

@codex review
/gemini review
@gemini-code-assist
@coderabbitai full review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh pr view 344 --repo unbraind/pm-cli --json title,body,additions,deletions,changedFiles,headRefOid

echo "---FILES---"
gh pr diff 344 --repo unbraind/pm-cli --name-only

echo "---DIFF---"
gh pr diff 344 --repo unbraind/pm-cli

Length of output: 32218



@unbraind — both minor items from the first review are cleanly resolved in 38d546e1. Here's the confirmation:


What was fixed

1. defineAfterCommandHook marked as optional ✅

The generated README snippet now includes an inline comment that makes the optional nature explicit:

export const afterCommandHook = defineAfterCommandHook((context) => {
  // Only add this when your package declares and registers hooks.
  if (!context.ok) return;
  // React to context.affected here as your package grows.
});

Clear, unambiguous, and doesn't require the reader to cross-reference the scaffold manifest.

2. package + commands test added ✅

it("documents the define* builder upgrade path for commands-only package scaffolds", () => {
  const scaffold = buildStarterExtensionScaffoldFiles("tool-kit", "tool kit ping", "package", "commands");
  // ...
  expect(readme).toContain("## Authoring With define* Builders");
  expect(readme).toContain("Only add this when your package declares and registers hooks.");
  expect(entrypoint).not.toContain('from "`@unbrained/pm-cli/sdk`"');
});

The three-test matrix now exhaustively covers the branching condition (package type → guidance present; extension type → guidance absent).


Remaining items

Area Status
defineAfterCommandHook shown for all capabilities ✅ Addressed — optional-hook comment added
package+commands test coverage gap ✅ Addressed — new first test case
EXTENSIONS.md paragraph density Nit — unchanged, fine for now

No new issues found in the follow-up diff. The PR is in good shape to merge.

[approve]

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request closes ADR pm-3mph by adding guidance on using zero-cost define* SDK builders to generated package READMEs and updating the extension authoring documentation. A new unit test suite has been added to verify this guidance while ensuring the entrypoint remains import-free. Feedback on the changes points out a potential runtime activation failure: the generated README always suggests using defineAfterCommandHook even if the scaffolded package lacks the hooks capability. The reviewer recommends dynamically tailoring the define* builder examples in the README to match the specific capability being scaffolded.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +611 to +632
"",
"## Authoring With define* Builders",
"`index.js` stays import-free so the package can be installed locally before",
"`npm install` materializes peer dependencies. After installing dependencies,",
"use the public SDK authoring builders for exported definitions you want",
"editor type-checking, contextual handler inference, and direct unit tests for:",
"```js",
'import { defineCommand, defineAfterCommandHook } from "@unbrained/pm-cli/sdk";',
"",
"export const pingCommand = defineCommand({",
` name: ${JSON.stringify(commandName)},`,
' description: "Starter scaffold command. Replace with your own behavior.",',
" run: (context) => ({ ok: true, command: context.command }),",
"});",
"",
"export const afterCommandHook = defineAfterCommandHook((context) => {",
" // Only add this when your package declares and registers hooks.",
" if (!context.ok) return;",
" // React to context.affected here as your package grows.",
"});",
"```",
"The builders return their argument unchanged; runtime validation still lives",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The generated README currently always suggests using defineAfterCommandHook even if the scaffolded package does not have the hooks capability. If a package author copies this example and registers the hook without declaring the hooks capability in manifest.json, it will cause a blocking extension_capability_missing activation failure at runtime.

We should dynamically tailor the define* builders example in the README to match the specific capability being scaffolded (e.g., showing defineSearchProvider and defineVectorStoreAdapter for search packages, defineImporter and defineExporter for importers, etc.).

      "",
      "## Authoring With define* Builders",
      "`index.js` stays import-free so the package can be installed locally before",
      "`npm install` materializes peer dependencies. After installing dependencies,",
      "use the public SDK authoring builders for exported definitions you want",
      "editor type-checking, contextual handler inference, and direct unit tests for:",
      "```js",
      "import { " + (
        capability === "hooks"
          ? "defineCommand, defineAfterCommandHook"
          : capability === "search"
          ? "defineCommand, defineSearchProvider, defineVectorStoreAdapter"
          : capability === "importers"
          ? "defineCommand, defineImporter, defineExporter"
          : "defineCommand"
      ) + " } from \"@unbrained/pm-cli/sdk\";",
      "",
      "export const pingCommand = defineCommand({",
      "  name: " + JSON.stringify(commandName) + ",",
      "  description: \"Starter scaffold command. Replace with your own behavior.\",",
      "  run: (context) => ({ ok: true, command: context.command }),",
      "});",
      ...(capability === "hooks"
        ? [
            "",
            "export const afterCommandHook = defineAfterCommandHook((context) => {",
            "  if (!context.ok) return;",
            "  // React to context.affected here as your package grows.",
            "});",
          ]
        : []),
      ...(capability === "search"
        ? [
            "",
            "export const searchProvider = defineSearchProvider({",
            "  name: " + JSON.stringify(extensionName + "-search") + ",",
            "  query: async (context) => {",
            "    const needle = context.query.toLowerCase();",
            "    const hits = context.documents",
            "      .filter((doc) => String(doc.metadata.title ?? '').toLowerCase().includes(needle))",
            "      .map((doc) => ({ id: doc.metadata.id, score: 1, matched_fields: ['title'] }));",
            "    return { hits };",
            "  },",
            "  embed: async (context) => [context.input.length],",
            "});",
            "",
            "export const vectorStoreAdapter = defineVectorStoreAdapter({",
            "  name: " + JSON.stringify(extensionName + "-vector") + ",",
            "  query: async (context) => [{ id: 'starter-vector-hit', score: context.limit }],",
            "  upsert: async (context) => ({ upserted: context.points.length }),",
            "  delete: async (context) => ({ deleted: context.ids.length }),",
            "});",
          ]
        : []),
      ...(capability === "importers"
        ? [
            "",
            "export const importer = defineImporter(async (context) => ({",
            "  imported: 1,",
            "  source: context.options.source ?? 'starter',",
            "  args: context.args,",
            "}));",
            "",
            "export const exporter = defineExporter(async (context) => ({",
            "  exported: true,",
            "  destination: context.options.destination ?? 'stdout',",
            "  args: context.args,",
            "}));",
          ]
        : []),
      "```",
      "The builders return their argument unchanged; runtime validation still lives",
      "in `api.register*`, and behavior validation lives in `sdk/testing`."

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request closes the ADR for SDK define* builders by updating the package scaffold generator to document the define* builder upgrade path in the generated README, while keeping the initial entrypoint import-free. It also updates the extension documentation and adds regression tests. The reviewer suggested expanding the README code example to show the complete entrypoint structure, including the activate function and default export, to prevent users from breaking their extensions when applying the guidance.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/cli/commands/extension/scaffold.ts Outdated
Comment on lines +617 to +631
"```js",
'import { defineCommand, defineAfterCommandHook } from "@unbrained/pm-cli/sdk";',
"",
"export const pingCommand = defineCommand({",
` name: ${JSON.stringify(commandName)},`,
' description: "Starter scaffold command. Replace with your own behavior.",',
" run: (context) => ({ ok: true, command: context.command }),",
"});",
"",
"export const afterCommandHook = defineAfterCommandHook((context) => {",
" // Only add this when your package declares and registers hooks.",
" if (!context.ok) return;",
" // React to context.affected here as your package grows.",
"});",
"```",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The code block in the generated README shows how to define the command and hook using the define* builders, but it does not show how to actually register them within the activate function or export the extension module. If a user replaces or updates their index.js following this example, they might inadvertently remove the activate export, causing the extension to fail to load.

Showing the complete entrypoint structure with the activate function and default export will make the guide fully actionable and prevent runtime loading issues.

      "```js",
      'import { defineCommand, defineAfterCommandHook } from "@unbrained/pm-cli/sdk";',
      "",
      "export const pingCommand = defineCommand({",
      `  name: ${JSON.stringify(commandName)},`,
      '  description: "Starter scaffold command. Replace with your own behavior.",',
      "  run: (context) => ({ ok: true, command: context.command }),",
      "});",
      "",
      "export const afterCommandHook = defineAfterCommandHook((context) => {",
      "  // Only add this when your package declares and registers hooks.",
      "  if (!context.ok) return;",
      "  // React to context.affected here as your package grows.",
      "});",
      "",
      "export function activate(api) {",
      "  api.registerCommand(pingCommand);",
      "  // api.hooks.afterCommand(afterCommandHook);",
      "}",
      "",
      "export default {",
      "  activate,",
      "};",
      "```",

Address PR #344 Gemini/CodeRabbit follow-up by making generated define* README examples complete and capability-aware, with activate/deactivate/default export shown and ADR links added to package-author docs.

Verification: node scripts/run-tests.mjs test -- tests/unit/extensions/extension-scaffold-define-guidance.spec.ts; pnpm build; pnpm quality:static; temp scaffold smoke for commands/search/importers/hooks plus hook package install/invoke/npm test.
@unbraind

Copy link
Copy Markdown
Owner Author

New head pushed after addressing Gemini and CodeRabbit follow-up: 338837f.

@codex review
/gemini review
@gemini-code-assist
@coderabbitai full review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh pr view 344 --repo unbraind/pm-cli --json title,body,additions,deletions,changedFiles,headRefOid

echo "---FILES---"
gh pr diff 344 --repo unbraind/pm-cli --name-only

echo "---DIFF---"
gh pr diff 344 --repo unbraind/pm-cli

Length of output: 38204



@unbraind — reviewed 338837fe. All changes are clean and the follow-up goes beyond the minimum:


What changed

scaffold.ts — capability-tailored examples ✅

The defineBuilderSnippet is now fully conditional per capability:

Capability Builders included
commands defineCommand only
hooks defineCommand + defineAfterCommandHook
search defineCommand + defineSearchProvider + defineVectorStoreAdapter
importers defineCommand + defineImporter + defineExporter

This is strictly better than the previous "mark it optional with a comment" approach — each scaffold now shows only what's relevant. The activate/deactivate/default export structure makes every example immediately copy-pasteable.

Test spec — exhaustive 4-test matrix ✅

Test Condition Assertion
commands package guidance present no defineAfterCommandHook leaked in
hooks package guidance present hook builder + registration present
search + importers packages guidance present each capability's builders + registrations correct
extension (standalone) guidance absent entrypoint stays import-free

docs/EXTENSIONS.md — ADR traceability ✅

Both new sentences now link to pm-3mph, satisfying the traceability request from the previous round.


Summary

No issues found. The PR is in excellent shape.

[approve]

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request closes the ADR pm-3mph by introducing guidance for the SDK define* builders in generated package scaffolds. It updates the scaffolding logic to generate capability-tailored README examples for defineCommand, defineAfterCommandHook, defineSearchProvider, defineVectorStoreAdapter, defineImporter, and defineExporter while keeping starter entrypoints import-free. Documentation and unit tests are also added. The reviewer pointed out that the generated snippet for the importers capability registers the importer and exporter without their required options object (which defines flags and actions), potentially causing runtime issues with undefined options. Corresponding test updates were also suggested to verify these options.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +660 to +665
if (capability === "importers") {
defineBuilderSnippet.push(
` api.registerImporter(${JSON.stringify(adapterName)}, importer);`,
` api.registerExporter(${JSON.stringify(adapterName)}, exporter);`,
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The generated define* builder snippet for the importers capability registers the importer and exporter without their third argument (the options object containing action, description, and flags). Omitting these options means the CLI won't register the --source and --destination flags, causing context.options.source and context.options.destination to be undefined at runtime and breaking the starter's functionality. We should include the full registration options in the README snippet.

    if (capability === "importers") {
      defineBuilderSnippet.push(
        "  api.registerImporter(" + JSON.stringify(adapterName) + ", importer, {",
        "    action: " + JSON.stringify(adapterName + " import") + ",",
        '    description: "Import starter records into pm context.",',
        '    flags: [',
        '      {',
        '        long: "--source",',
        '        value_name: "name",',
        '        value_type: "string",',
        '        description: "Source name or path to import from.",',
        '      },',
        '    ],',
        '  });',
        "  api.registerExporter(" + JSON.stringify(adapterName) + ", exporter, {",
        "    action: " + JSON.stringify(adapterName + " export") + ",",
        '    description: "Export pm context into starter records.",',
        '    flags: [',
        '      {',
        '        long: "--destination",',
        '        value_name: "name",',
        '        value_type: "string",',
        '        description: "Destination name or path to export to.",',
        '      },',
        '    ],',
        '  });',
      );
    }

Comment on lines +44 to +45
expect(importerReadme).toContain('api.registerImporter("sync kit items", importer);');
expect(importerReadme).toContain('api.registerExporter("sync kit items", exporter);');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the test assertions to verify that the generated importer and exporter registrations in the README include the options object.

Suggested change
expect(importerReadme).toContain('api.registerImporter("sync kit items", importer);');
expect(importerReadme).toContain('api.registerExporter("sync kit items", exporter);');
expect(importerReadme).toContain('api.registerImporter("sync kit items", importer, {');
expect(importerReadme).toContain('api.registerExporter("sync kit items", exporter, {');

@unbraind

Copy link
Copy Markdown
Owner Author

New head pushed after addressing Gemini importer options feedback: 22930e3.

@codex review
/gemini review
@gemini-code-assist
@coderabbitai full review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh pr view 344 --repo unbraind/pm-cli --json title,body,additions,deletions,changedFiles,headRefOid

echo "---FILES---"
gh pr diff 344 --repo unbraind/pm-cli --name-only

echo "---DIFF---"
gh pr diff 344 --repo unbraind/pm-cli

Length of output: 40379



@unbraind — reviewed 22930e32. The Gemini importer feedback is cleanly resolved.


What changed

scaffold.ts — full importer/exporter option objects ✅

The importers branch of defineBuilderSnippet now generates a complete, copy-pasteable registerImporter/registerExporter call:

Field registerImporter registerExporter
action "<name> import" "<name> export"
description import description export description
flags --source (string, value_name, description) --destination (string, value_name, description)

The handler bodies also demonstrate context.options.source / context.options.destination with sensible fallbacks, which is the right pattern to model for package authors.

Test spec — expanded importer assertions ✅

The third test now pins the full option shape for both sides of the importer pair, including action strings, flag long names, and adapter name derivation ("sync kit items" from "sync-kit").


Summary

Round Finding Status
Round 1 defineAfterCommandHook shown for all capabilities ✅ Resolved
Round 1 package+commands test coverage gap ✅ Resolved
Round 2 Capability-tailored examples + 4-test matrix ✅ Resolved
Round 3 ADR traceability in docs ✅ Resolved
Round 4 Importer/exporter option objects ✅ Resolved

No new issues. The PR is in excellent shape to merge.

[approve]

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request closes out the ADR pm-3mph by updating the decision records, changelog, and extension documentation to align with the zero-cost define* SDK builders. Specifically, it enhances the package scaffolding logic in src/cli/commands/extension/scaffold.ts to include detailed define* builder guidance and copy-pasteable code snippets in the generated README.md based on the selected capabilities (commands, hooks, search, or importers), while ensuring the generated entrypoint remains import-free for local installations. Additionally, a comprehensive suite of unit tests has been added in tests/unit/extensions/extension-scaffold-define-guidance.spec.ts to verify this scaffolding behavior. There are no review comments provided, so we have no feedback to address.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant