pm-starter 2026.11.5 → 2026.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.11.9 - 2026-11-09
4
+
5
+ ### Dependencies
6
+
7
+ - Bump the pm-toolchain group with 3 updates ([#199](https://github.com/unbraind/pm-starter/pull/199))
8
+ - Bump unbraind/pm-github/.github/workflows/pm-github-closeout.yml ([#198](https://github.com/unbraind/pm-starter/pull/198))
9
+ - Bump unbraind/pm-github/.github/workflows/pm-github-sync.yml ([#197](https://github.com/unbraind/pm-starter/pull/197))
10
+ - Bump the codeql-action group with 2 updates ([#196](https://github.com/unbraind/pm-starter/pull/196))
11
+
3
12
  ## 2026.11.5 - 2026-11-05
4
13
 
5
14
  ### Fixed
package/README.md CHANGED
@@ -213,6 +213,73 @@ npm run build
213
213
  pm install ./my-extension --project
214
214
  ```
215
215
 
216
+ ## Recommended extension tests
217
+
218
+ Use `createExtensionTestHarness` from `@unbrained/pm-cli/sdk/testing` for positive
219
+ registration and handler tests. It activates the real host registration API and
220
+ runs registered handlers through host dispatch. Pair it with an initialized
221
+ `PmClient` tracker in a temporary directory, including a tracker outside Git:
222
+
223
+ ```ts
224
+ import assert from "node:assert/strict";
225
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
226
+ import { tmpdir } from "node:os";
227
+ import { join } from "node:path";
228
+ import test from "node:test";
229
+ import { PmClient } from "@unbrained/pm-cli/sdk";
230
+ import { createExtensionTestHarness } from "@unbrained/pm-cli/sdk/testing";
231
+ import extension from "../index.ts";
232
+
233
+ test("registered command reads a real tracker", async (t) => {
234
+ const directory = mkdtempSync(join(tmpdir(), "extension-test-"));
235
+ t.after(() => rmSync(directory, { recursive: true, force: true }));
236
+ const pmRoot = join(directory, ".agents", "pm"); // Tracker storage, not workspace root.
237
+ const client = new PmClient({ pmRoot, noExtensions: true, author: "test" });
238
+ await client.init("example", { defaults: true, mergeFence: false, agentGuidance: "skip" });
239
+ await client.create({ id: "example", type: "Task", title: "Example" });
240
+
241
+ const manifest: unknown = JSON.parse(readFileSync(new URL("../manifest.json", import.meta.url), "utf8"));
242
+ const harness = await createExtensionTestHarness({ default: extension, manifest });
243
+ t.after(() => harness.deactivate());
244
+ harness.assertCommandContract({ name: "starter greet", flags: ["--name", "--uppercase"] });
245
+ harness.assertFlags({ name: "list", flags: ["--starter-tag"] });
246
+ harness.assertItemField({ name: "starter_origin", type: "string" });
247
+ harness.assertItemType({ name: "StarterNote", folder: "starter-notes" });
248
+
249
+ // A nonempty pmRoot makes the harness inject a real host-bound ctx.sdk.
250
+ const outcome = await harness.runCommand({ command: "starter demo", pmRoot });
251
+ assert.equal(outcome.handled, true);
252
+ assert.deepEqual(outcome.warnings, []);
253
+ assert.equal((outcome.result as { item_count: number }).item_count, 1);
254
+ });
255
+ ```
256
+
257
+ Keep the manifest's capabilities accurate; this example uses the package's actual
258
+ manifest so missing declarations fail activation. Copy the assertion names and
259
+ expected receipts to match your own extension. The pinned development SDK supplies
260
+ these testing helpers; they do not change the installed extension's host floor.
261
+
262
+ Use `assertHook`, `assertImporter`, `assertExporter` and the other `assert*`
263
+ methods to verify registered surfaces, then `runCommand`, `runRendererOverride`,
264
+ `runImporter`, `runExporter` or `runHook` to exercise behavior. Importers and
265
+ exporters also register command paths, so they appear in the host command registry.
266
+ The harness dispatches one requested surface; it does not run the entire CLI
267
+ parser/preflight/render pipeline or automatically install hooks on a separate
268
+ `PmClient`. Pass parsed command flags in `options`, global host options in `global`,
269
+ and real committed mutation data when invoking an observe-only write hook.
270
+
271
+ Retain package rules as assertions: USAGE errors, inert importer and laboratory
272
+ mutation refusals, renderer ownership, and receipt contents are starter behavior
273
+ the SDK cannot prescribe. Pure option tests and the focused callback/subprocess
274
+ failure doubles in `test/commands.test.ts` stay unit tests; use
275
+ `activateExtensionForTest` directly for deliberate failed-activation or old-host
276
+ compatibility tests. Positive smoke tests must use the supported harness instead
277
+ of a handwritten `ExtensionApi` registration sink. See `test/smoke.test.ts` for
278
+ registration, invocation, output receipt and mutation-context examples.
279
+
280
+ Run `node --test --test-concurrency=2 test/smoke.test.ts` and `npm run build:test`
281
+ when adapting this pattern, then the package's full gate.
282
+
216
283
  ## License
217
284
 
218
285
  MIT
package/dist/index.js CHANGED
@@ -1060,7 +1060,7 @@ function setupFlags(api) {
1060
1060
  const defineExtension = (module) => module;
1061
1061
  export default defineExtension({
1062
1062
  name: "pm-starter",
1063
- version: "2026.11.5",
1063
+ version: "2026.11.9",
1064
1064
  activate(api) {
1065
1065
  // Register every capability group. Each helper is defensive enough to be
1066
1066
  // safely deleted when you fork this scaffold for a real extension.
package/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm-starter",
3
- "version": "2026.11.5",
3
+ "version": "2026.11.9",
4
4
  "description": "Complete scaffold showing all 9 capability types: commands, renderers, hooks, schema, importers, search, parser, preflight, services. Includes plan workflow, context, and search integration examples plus guided setup. Use as a starting template for new extensions.",
5
5
  "author": "@unbraind",
6
6
  "entry": "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm-starter",
3
- "version": "2026.11.5",
3
+ "version": "2026.11.9",
4
4
  "description": "Complete starter/scaffold extension for pm-cli showing all capability types",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,9 +51,9 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "26.6.6",
54
- "@unbrained/pm-cli": "2026.11.4",
55
- "pm-changelog": "2026.10.31",
56
- "pm-ops": "2026.11.4",
54
+ "@unbrained/pm-cli": "2026.11.5",
55
+ "pm-changelog": "2026.11.5",
56
+ "pm-ops": "2026.11.5",
57
57
  "typescript": "7.0.2"
58
58
  },
59
59
  "keywords": [