@workflow-cannon/workspace-kit 0.17.0 → 0.24.0

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.
Files changed (144) hide show
  1. package/README.md +23 -9
  2. package/dist/cli/doctor-planning-issues.js +3 -22
  3. package/dist/cli/run-command.js +22 -38
  4. package/dist/cli.js +95 -4
  5. package/dist/contracts/command-manifest.d.ts +17 -0
  6. package/dist/contracts/command-manifest.js +1 -0
  7. package/dist/contracts/index.d.ts +1 -1
  8. package/dist/contracts/module-contract.d.ts +12 -11
  9. package/dist/core/agent-instruction-surface.d.ts +33 -0
  10. package/dist/core/agent-instruction-surface.js +46 -0
  11. package/dist/core/config-cli.js +13 -17
  12. package/dist/core/config-metadata.js +101 -2
  13. package/dist/core/index.d.ts +4 -1
  14. package/dist/core/index.js +3 -0
  15. package/dist/core/module-command-router.js +19 -1
  16. package/dist/core/module-registry-resolve.d.ts +27 -0
  17. package/dist/core/module-registry-resolve.js +91 -0
  18. package/dist/core/module-registry.d.ts +14 -0
  19. package/dist/core/module-registry.js +57 -0
  20. package/dist/core/planning/build-plan-session-file.d.ts +29 -0
  21. package/dist/core/planning/build-plan-session-file.js +58 -0
  22. package/dist/core/planning/index.d.ts +17 -0
  23. package/dist/core/planning/index.js +15 -0
  24. package/dist/core/policy.js +18 -8
  25. package/dist/core/state/unified-state-db.d.ts +21 -0
  26. package/dist/core/state/unified-state-db.js +80 -0
  27. package/dist/core/workspace-kit-config.js +13 -1
  28. package/dist/modules/agent-behavior/builtins.d.ts +3 -0
  29. package/dist/modules/agent-behavior/builtins.js +71 -0
  30. package/dist/modules/agent-behavior/explain.d.ts +6 -0
  31. package/dist/modules/agent-behavior/explain.js +46 -0
  32. package/dist/modules/agent-behavior/index.d.ts +4 -0
  33. package/dist/modules/agent-behavior/index.js +461 -0
  34. package/dist/modules/agent-behavior/interview-session-file.d.ts +9 -0
  35. package/dist/modules/agent-behavior/interview-session-file.js +43 -0
  36. package/dist/modules/agent-behavior/interview.d.ts +13 -0
  37. package/dist/modules/agent-behavior/interview.js +88 -0
  38. package/dist/modules/agent-behavior/persistence.d.ts +6 -0
  39. package/dist/modules/agent-behavior/persistence.js +89 -0
  40. package/dist/modules/agent-behavior/store.d.ts +34 -0
  41. package/dist/modules/agent-behavior/store.js +119 -0
  42. package/dist/modules/agent-behavior/types.d.ts +28 -0
  43. package/dist/modules/agent-behavior/types.js +1 -0
  44. package/dist/modules/agent-behavior/validate.d.ts +11 -0
  45. package/dist/modules/agent-behavior/validate.js +123 -0
  46. package/dist/modules/approvals/index.js +54 -51
  47. package/dist/modules/approvals/policy-sensitive-commands.d.ts +4 -0
  48. package/dist/modules/approvals/policy-sensitive-commands.js +4 -0
  49. package/dist/modules/approvals/review-runtime.js +1 -2
  50. package/dist/modules/documentation/index.js +47 -45
  51. package/dist/modules/documentation/normalizer.d.ts +3 -0
  52. package/dist/modules/documentation/normalizer.js +171 -0
  53. package/dist/modules/documentation/parser.d.ts +7 -0
  54. package/dist/modules/documentation/parser.js +39 -0
  55. package/dist/modules/documentation/policy-sensitive-commands.d.ts +5 -0
  56. package/dist/modules/documentation/policy-sensitive-commands.js +8 -0
  57. package/dist/modules/documentation/renderer.d.ts +23 -0
  58. package/dist/modules/documentation/renderer.js +105 -0
  59. package/dist/modules/documentation/runtime-batch.d.ts +10 -0
  60. package/dist/modules/documentation/runtime-batch.js +67 -0
  61. package/dist/modules/documentation/runtime-config.d.ts +11 -0
  62. package/dist/modules/documentation/runtime-config.js +54 -0
  63. package/dist/modules/documentation/runtime-render-support.d.ts +8 -0
  64. package/dist/modules/documentation/runtime-render-support.js +36 -0
  65. package/dist/modules/documentation/runtime.js +22 -510
  66. package/dist/modules/documentation/types.d.ts +182 -0
  67. package/dist/modules/documentation/validator.d.ts +8 -0
  68. package/dist/modules/documentation/validator.js +234 -0
  69. package/dist/modules/documentation/view-models.d.ts +3 -0
  70. package/dist/modules/documentation/view-models.js +124 -0
  71. package/dist/modules/improvement/generate-recommendations-runtime.js +3 -3
  72. package/dist/modules/improvement/improvement-state.d.ts +2 -2
  73. package/dist/modules/improvement/improvement-state.js +52 -23
  74. package/dist/modules/improvement/index.js +140 -138
  75. package/dist/modules/improvement/ingest.d.ts +1 -1
  76. package/dist/modules/improvement/policy-sensitive-commands.d.ts +4 -0
  77. package/dist/modules/improvement/policy-sensitive-commands.js +7 -0
  78. package/dist/modules/index.d.ts +6 -0
  79. package/dist/modules/index.js +17 -0
  80. package/dist/modules/planning/artifact.d.ts +19 -0
  81. package/dist/modules/planning/artifact.js +72 -0
  82. package/dist/modules/planning/index.js +605 -6
  83. package/dist/modules/planning/question-engine.d.ts +25 -0
  84. package/dist/modules/planning/question-engine.js +284 -0
  85. package/dist/modules/planning/types.d.ts +9 -0
  86. package/dist/modules/planning/types.js +39 -0
  87. package/dist/modules/task-engine/doctor-planning-persistence.js +21 -13
  88. package/dist/modules/task-engine/index.d.ts +1 -2
  89. package/dist/modules/task-engine/index.js +1 -1143
  90. package/dist/modules/task-engine/migrate-task-persistence-runtime.js +31 -4
  91. package/dist/modules/task-engine/migrate-wishlist-intake-runtime.d.ts +2 -0
  92. package/dist/modules/task-engine/migrate-wishlist-intake-runtime.js +146 -0
  93. package/dist/modules/task-engine/planning-open.d.ts +2 -9
  94. package/dist/modules/task-engine/planning-open.js +4 -15
  95. package/dist/modules/task-engine/policy-sensitive-commands.d.ts +5 -0
  96. package/dist/modules/task-engine/policy-sensitive-commands.js +5 -0
  97. package/dist/modules/task-engine/sqlite-dual-planning.d.ts +11 -2
  98. package/dist/modules/task-engine/sqlite-dual-planning.js +134 -28
  99. package/dist/modules/task-engine/strict-task-validation.js +3 -0
  100. package/dist/modules/task-engine/suggestions.js +2 -1
  101. package/dist/modules/task-engine/task-engine-internal.d.ts +2 -0
  102. package/dist/modules/task-engine/task-engine-internal.js +1304 -0
  103. package/dist/modules/task-engine/task-type-validation.js +40 -0
  104. package/dist/modules/task-engine/wishlist-intake.d.ts +22 -0
  105. package/dist/modules/task-engine/wishlist-intake.js +180 -0
  106. package/dist/modules/task-engine/wishlist-validation.d.ts +4 -0
  107. package/dist/modules/task-engine/wishlist-validation.js +19 -0
  108. package/dist/modules/workspace-config/index.js +9 -11
  109. package/package.json +2 -2
  110. package/schemas/agent-behavior-profile.schema.json +52 -0
  111. package/schemas/task-engine-run-contracts.schema.json +80 -5
  112. package/src/modules/documentation/README.md +16 -25
  113. package/src/modules/documentation/RULES.md +9 -9
  114. package/src/modules/documentation/index.ts +54 -49
  115. package/src/modules/documentation/instructions/document-project.md +6 -6
  116. package/src/modules/documentation/instructions/generate-document.md +4 -4
  117. package/src/modules/documentation/normalizer.ts +187 -0
  118. package/src/modules/documentation/parser.ts +41 -0
  119. package/src/modules/documentation/policy-sensitive-commands.ts +8 -0
  120. package/src/modules/documentation/renderer.ts +121 -0
  121. package/src/modules/documentation/runtime-batch.ts +74 -0
  122. package/src/modules/documentation/runtime-config.ts +68 -0
  123. package/src/modules/documentation/runtime-render-support.ts +39 -0
  124. package/src/modules/documentation/runtime.ts +28 -600
  125. package/src/modules/documentation/schemas/documentation-schema.md +37 -54
  126. package/src/modules/documentation/types.ts +228 -0
  127. package/src/modules/documentation/validator.ts +247 -0
  128. package/src/modules/documentation/view-models.ts +132 -0
  129. package/src/modules/documentation/views/agents.view.yaml +18 -0
  130. package/src/modules/documentation/views/architecture.view.yaml +18 -0
  131. package/src/modules/documentation/views/principles.view.yaml +18 -0
  132. package/src/modules/documentation/views/readme.view.yaml +18 -0
  133. package/src/modules/documentation/views/releasing.view.yaml +18 -0
  134. package/src/modules/documentation/views/roadmap.view.yaml +18 -0
  135. package/src/modules/documentation/views/runbooks-consumer-cadence.view.yaml +18 -0
  136. package/src/modules/documentation/views/runbooks-parity-validation-flow.view.yaml +18 -0
  137. package/src/modules/documentation/views/runbooks-release-channels.view.yaml +18 -0
  138. package/src/modules/documentation/views/security.view.yaml +18 -0
  139. package/src/modules/documentation/views/support.view.yaml +18 -0
  140. package/src/modules/documentation/views/terms.view.yaml +18 -0
  141. package/src/modules/documentation/views/workbooks-phase2-config-policy-workbook.view.yaml +18 -0
  142. package/src/modules/documentation/views/workbooks-task-engine-workbook.view.yaml +18 -0
  143. package/src/modules/documentation/views/workbooks-transcript-automation-baseline.view.yaml +18 -0
  144. package/src/modules/documentation/state.md +0 -8
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- AI agents: `./.ai/` is the authoritative source of truth; read all files there before any analysis, planning, or code changes, and follow `./.ai/` over `README.md`, `./docs/`, and conflicting existing code patterns.
1
+ AI agents: read **`./.ai/`** first for machine-oriented contracts (module build rules, principles). For **conflicts between** `.ai/`, `docs/maintainers/`, `.cursor/rules/`, and code, use the ordered **Source-of-truth** list in [`docs/maintainers/AGENTS.md`](docs/maintainers/AGENTS.md) and the precedence note in [`docs/maintainers/ARCHITECTURE.md`](docs/maintainers/ARCHITECTURE.md) — do not rely on this README alone for governance precedence.
2
2
 
3
3
  <div align="center">
4
4
  <img src="title_image.png" alt="Workflow Cannon" width="720" />
@@ -19,12 +19,24 @@ pnpm install
19
19
  pnpm run build
20
20
  ```
21
21
 
22
- Verify the kit sees your workspace:
22
+ ### Where to start after build
23
23
 
24
- ```bash
25
- node dist/cli.js doctor
26
- node dist/cli.js --help
27
- ```
24
+ | Step | Command | What you get |
25
+ | --- | --- | --- |
26
+ | 1 | `node dist/cli.js --help` | Orientation: top-level commands, first-run path, doc pointers |
27
+ | 2 | `node dist/cli.js doctor` | Confirms kit contract files and config resolve |
28
+ | 3 | `node dist/cli.js run` | **Command menu** — every runnable `workspace-kit run <cmd>` |
29
+ | 4 | `node dist/cli.js run get-next-actions '{}'` | Read-only suggestion for what to do next |
30
+
31
+ **Developing:** after edits, `pnpm run build` then `pnpm test` (or `pnpm run phase5-gates` before larger changes). **`workspace-kit` is not on your PATH by default** — invoke it in one of these ways:
32
+
33
+ | Situation | Example |
34
+ | --- | --- |
35
+ | This repo, after `pnpm run build` | `node dist/cli.js --help` (same subcommands as `workspace-kit`) |
36
+ | This repo, dev dependency on PATH via pnpm | `pnpm exec workspace-kit --help` |
37
+ | Another project with the package installed | `npx workspace-kit --help` or `pnpm exec workspace-kit --help` |
38
+
39
+ **`workspace-kit run` with no subcommand is the full module command list** — that is the usual “what can I run?” answer.
28
40
 
29
41
  Try **read-only** task-engine queries:
30
42
 
@@ -33,16 +45,17 @@ node dist/cli.js run list-tasks '{}'
33
45
  node dist/cli.js run get-next-actions '{}'
34
46
  ```
35
47
 
36
- **Developing:** after edits, `pnpm run build` then `pnpm test` (or `pnpm run phase5-gates` before larger changes). If `workspace-kit` is not on your `PATH`, use `node dist/cli.js …` from the repo root (same as above).
37
-
38
48
  ## Quick start (use the package in another project)
39
49
 
40
50
  ```bash
41
51
  npm install @workflow-cannon/workspace-kit
42
52
  npx workspace-kit --help
53
+ npx workspace-kit run
43
54
  ```
44
55
 
45
- Or with pnpm: `pnpm add @workflow-cannon/workspace-kit` then `pnpm exec workspace-kit --help`.
56
+ `--help` prints the top-level guide; `run` with no subcommand lists every module command. In a repo that already contains maintainer docs, paths like `docs/maintainers/AGENT-CLI-MAP.md` match this repository; in a consumer project, use the copy shipped under `node_modules/@workflow-cannon/workspace-kit/` or your own docs link.
57
+
58
+ Or with pnpm: `pnpm add @workflow-cannon/workspace-kit` then `pnpm exec workspace-kit --help` and `pnpm exec workspace-kit run`.
46
59
 
47
60
  ## What this repo contains
48
61
 
@@ -79,6 +92,7 @@ Snapshot: [`docs/maintainers/data/workspace-kit-status.yaml`](docs/maintainers/d
79
92
  | Glossary | [`docs/maintainers/TERMS.md`](docs/maintainers/TERMS.md) |
80
93
  | Architecture | [`docs/maintainers/ARCHITECTURE.md`](docs/maintainers/ARCHITECTURE.md) |
81
94
  | Agent/CLI execution | [`docs/maintainers/AGENTS.md`](docs/maintainers/AGENTS.md) |
95
+ | CLI visual map (diagrams) | [`docs/maintainers/CLI-VISUAL-GUIDE.md`](docs/maintainers/CLI-VISUAL-GUIDE.md) |
82
96
 
83
97
  ## License
84
98
 
@@ -1,29 +1,10 @@
1
- import { ModuleRegistry } from "../core/module-registry.js";
2
- import { resolveWorkspaceConfigWithLayers } from "../core/workspace-kit-config.js";
1
+ import { resolveRegistryAndConfig } from "../core/module-registry-resolve.js";
3
2
  import { validatePlanningPersistenceForDoctor } from "../modules/task-engine/doctor-planning-persistence.js";
4
- import { documentationModule } from "../modules/documentation/index.js";
5
- import { taskEngineModule } from "../modules/task-engine/index.js";
6
- import { approvalsModule } from "../modules/approvals/index.js";
7
- import { planningModule } from "../modules/planning/index.js";
8
- import { improvementModule } from "../modules/improvement/index.js";
9
- import { workspaceConfigModule } from "../modules/workspace-config/index.js";
10
- const defaultRegistryModules = [
11
- workspaceConfigModule,
12
- documentationModule,
13
- taskEngineModule,
14
- approvalsModule,
15
- planningModule,
16
- improvementModule
17
- ];
3
+ import { defaultRegistryModules } from "../modules/index.js";
18
4
  /** Resolve layered config and run SQLite planning persistence checks for `workspace-kit doctor`. */
19
5
  export async function collectDoctorPlanningPersistenceIssues(cwd) {
20
6
  try {
21
- const registry = new ModuleRegistry(defaultRegistryModules);
22
- const { effective } = await resolveWorkspaceConfigWithLayers({
23
- workspacePath: cwd,
24
- registry,
25
- invocationConfig: {}
26
- });
7
+ const { effective } = await resolveRegistryAndConfig(cwd, defaultRegistryModules, {});
27
8
  return validatePlanningPersistenceForDoctor(cwd, effective);
28
9
  }
29
10
  catch (err) {
@@ -1,44 +1,15 @@
1
- import { ModuleRegistry } from "../core/module-registry.js";
2
1
  import { ModuleCommandRouter } from "../core/module-command-router.js";
2
+ import { resolveRegistryAndConfig } from "../core/module-registry-resolve.js";
3
3
  import { appendPolicyTrace, isSensitiveModuleCommandForEffective, parsePolicyApproval, AGENT_CLI_MAP_HUMAN_DOC, POLICY_APPROVAL_HUMAN_DOC, resolveActorWithFallback, resolvePolicyOperationIdForCommand } from "../core/policy.js";
4
4
  import { getSessionGrant, recordSessionGrant, resolveSessionId } from "../core/session-policy.js";
5
5
  import { applyResponseTemplateApplication } from "../core/response-template-shaping.js";
6
- import { resolveWorkspaceConfigWithLayers } from "../core/workspace-kit-config.js";
7
- import { documentationModule } from "../modules/documentation/index.js";
8
- import { taskEngineModule } from "../modules/task-engine/index.js";
9
- import { approvalsModule } from "../modules/approvals/index.js";
10
- import { planningModule } from "../modules/planning/index.js";
11
- import { improvementModule } from "../modules/improvement/index.js";
12
- import { workspaceConfigModule } from "../modules/workspace-config/index.js";
6
+ import { defaultRegistryModules } from "../modules/index.js";
13
7
  import { promptSensitiveRunApproval } from "./interactive-policy.js";
14
8
  export async function handleRunCommand(cwd, args, io, codes) {
15
9
  const { writeLine, writeError } = io;
16
- const allModules = [
17
- workspaceConfigModule,
18
- documentationModule,
19
- taskEngineModule,
20
- approvalsModule,
21
- planningModule,
22
- improvementModule
23
- ];
24
- const registry = new ModuleRegistry(allModules);
25
- const router = new ModuleCommandRouter(registry);
26
10
  const subcommand = args[1];
27
- if (!subcommand) {
28
- const commands = router.listCommands();
29
- writeLine("Available module commands:");
30
- for (const cmd of commands) {
31
- const desc = cmd.description ? ` — ${cmd.description}` : "";
32
- writeLine(` ${cmd.name} (${cmd.moduleId})${desc}`);
33
- }
34
- writeLine("");
35
- writeLine(`Usage: workspace-kit run <command> [json-args]`);
36
- writeLine(`Instruction files: src/modules/<module>/instructions/<command>.md — policy-sensitive runs need JSON policyApproval (${POLICY_APPROVAL_HUMAN_DOC}).`);
37
- writeLine(`Agent-oriented tier table + copy-paste patterns: ${AGENT_CLI_MAP_HUMAN_DOC}.`);
38
- return codes.success;
39
- }
40
11
  let commandArgs = {};
41
- if (args[2]) {
12
+ if (subcommand && args[2]) {
42
13
  try {
43
14
  const parsed = JSON.parse(args[2]);
44
15
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
@@ -59,20 +30,33 @@ export async function handleRunCommand(cwd, args, io, codes) {
59
30
  !Array.isArray(commandArgs.config)
60
31
  ? commandArgs.config
61
32
  : {};
33
+ let registry;
34
+ let router;
62
35
  let effective;
63
36
  try {
64
- const resolved = await resolveWorkspaceConfigWithLayers({
65
- workspacePath: cwd,
66
- registry,
67
- invocationConfig
68
- });
37
+ const resolved = await resolveRegistryAndConfig(cwd, defaultRegistryModules, invocationConfig);
38
+ registry = resolved.registry;
69
39
  effective = resolved.effective;
40
+ router = new ModuleCommandRouter(registry);
70
41
  }
71
42
  catch (err) {
72
43
  const message = err instanceof Error ? err.message : String(err);
73
- writeError(`Config resolution failed: ${message}`);
44
+ writeError(`Module registry / config resolution failed: ${message}`);
74
45
  return codes.validationFailure;
75
46
  }
47
+ if (!subcommand) {
48
+ const commands = router.listCommands();
49
+ writeLine("Available module commands:");
50
+ for (const cmd of commands) {
51
+ const desc = cmd.description ? ` — ${cmd.description}` : "";
52
+ writeLine(` ${cmd.name} (${cmd.moduleId})${desc}`);
53
+ }
54
+ writeLine("");
55
+ writeLine(`Usage: workspace-kit run <command> [json-args]`);
56
+ writeLine(`Instruction files: src/modules/<module>/instructions/<command>.md — policy-sensitive runs need JSON policyApproval (${POLICY_APPROVAL_HUMAN_DOC}).`);
57
+ writeLine(`Agent-oriented tier table + copy-paste patterns: ${AGENT_CLI_MAP_HUMAN_DOC}.`);
58
+ return codes.success;
59
+ }
76
60
  const actor = await resolveActorWithFallback(cwd, commandArgs, process.env);
77
61
  const sensitive = isSensitiveModuleCommandForEffective(subcommand, commandArgs, effective);
78
62
  const sessionId = resolveSessionId(process.env);
package/dist/cli.js CHANGED
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { pathToFileURL } from "node:url";
5
- import { AGENT_CLI_MAP_HUMAN_DOC, appendPolicyTrace, parsePolicyApprovalFromEnv, resolveActorWithFallback } from "./core/policy.js";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import { AGENT_CLI_MAP_HUMAN_DOC, POLICY_APPROVAL_HUMAN_DOC, appendPolicyTrace, parsePolicyApprovalFromEnv, resolveActorWithFallback } from "./core/policy.js";
6
+ import { buildAgentInstructionSurface } from "./core/agent-instruction-surface.js";
6
7
  import { runWorkspaceConfigCli } from "./core/config-cli.js";
7
8
  import { handleRunCommand } from "./cli/run-command.js";
8
9
  import { collectDoctorPlanningPersistenceIssues } from "./cli/doctor-planning-issues.js";
10
+ import { ModuleRegistryError } from "./core/module-registry.js";
11
+ import { resolveRegistryAndConfig } from "./core/module-registry-resolve.js";
12
+ import { defaultRegistryModules } from "./modules/index.js";
9
13
  const EXIT_SUCCESS = 0;
10
14
  const EXIT_VALIDATION_FAILURE = 1;
11
15
  const EXIT_USAGE_ERROR = 2;
@@ -281,6 +285,62 @@ async function resolvePackageVersion(cwd) {
281
285
  }
282
286
  return undefined;
283
287
  }
288
+ /** Version from the installed kit package (works from repo `dist/` or `node_modules`). */
289
+ async function readCliBundledPackageVersion() {
290
+ try {
291
+ const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
292
+ const parsed = await parseJsonFile(pkgPath);
293
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
294
+ const v = parsed.version;
295
+ return typeof v === "string" && v.length > 0 ? v : undefined;
296
+ }
297
+ }
298
+ catch {
299
+ /* ignore */
300
+ }
301
+ return undefined;
302
+ }
303
+ function writeDoctorFailureRemediation(writeError, issues) {
304
+ writeError("");
305
+ writeError("Next steps:");
306
+ const hasMissing = issues.some((issue) => issue.reason === "missing");
307
+ if (hasMissing) {
308
+ writeError(" - Kit files missing: run workspace-kit upgrade from the repo root (set WORKSPACE_KIT_POLICY_APPROVAL — see docs/maintainers/POLICY-APPROVAL.md).");
309
+ }
310
+ writeError(" - workspace-kit --help — orientation and top-level commands");
311
+ writeError(" - workspace-kit run — list module commands (after doctor passes)");
312
+ }
313
+ async function printWorkspaceKitTopLevelHelp(writeLine) {
314
+ const version = await readCliBundledPackageVersion();
315
+ const versionSuffix = version ? ` v${version}` : "";
316
+ writeLine(`Workflow Cannon — workspace-kit${versionSuffix} (${CANONICAL_KIT_NAME})`);
317
+ writeLine("");
318
+ writeLine("CLI for deterministic, policy-governed task workflows. Module commands are listed separately.");
319
+ writeLine("");
320
+ writeLine("Start here (first time in a kit-enabled repo)");
321
+ writeLine(" 1) workspace-kit doctor");
322
+ writeLine(" 2) workspace-kit run ← lists every module command (your command menu)");
323
+ writeLine(" 3) workspace-kit run get-next-actions '{}' ← safe read: suggested next work");
324
+ writeLine("");
325
+ writeLine("Top-level commands");
326
+ writeLine(" doctor Validate kit contract files, config, and persistence checks");
327
+ writeLine(" doctor --agent-instruction-surface JSON catalog of all declared instructions");
328
+ writeLine(" run <cmd> [json] Run a module command; omit <cmd> to list runnable commands");
329
+ writeLine(" config Show or change kit config (mutations need env approval — see below)");
330
+ writeLine(" check Validate workspace-kit.profile.json");
331
+ writeLine(" init Regenerate profile-driven artifacts (needs env approval)");
332
+ writeLine(" upgrade Refresh kit-managed baseline files (needs env approval)");
333
+ writeLine(" drift-check Fail if managed kit assets differ from expected content");
334
+ writeLine("");
335
+ writeLine("Policy & docs (paths are relative to a clone of this repo; npm consumers: open the package or docs site)");
336
+ writeLine(` ${AGENT_CLI_MAP_HUMAN_DOC} — tier table, copy-paste JSON for agents`);
337
+ writeLine(` ${POLICY_APPROVAL_HUMAN_DOC} — when policyApproval JSON vs env approval applies`);
338
+ writeLine("");
339
+ writeLine("Global options");
340
+ writeLine(" -h, --help Show this message");
341
+ writeLine(" -V, --version Print CLI version");
342
+ writeLine(" help Same as --help");
343
+ }
284
344
  async function readOwnedPathsDocument(cwd) {
285
345
  const ownedPathsPath = path.join(cwd, defaultWorkspaceKitPaths.ownedPaths);
286
346
  let parsed;
@@ -338,8 +398,18 @@ export async function runCli(args, options = {}) {
338
398
  const writeError = options.writeError ?? console.error;
339
399
  const readStdinLine = options.readStdinLine;
340
400
  const [command] = args;
401
+ if (command === "--version" || command === "-V") {
402
+ const v = await readCliBundledPackageVersion();
403
+ writeLine(v ?? "workspace-kit (version unknown)");
404
+ return EXIT_SUCCESS;
405
+ }
406
+ if (command === "--help" || command === "-h" || command === "help") {
407
+ await printWorkspaceKitTopLevelHelp(writeLine);
408
+ return EXIT_SUCCESS;
409
+ }
341
410
  if (!command) {
342
- writeError("Usage: workspace-kit <init|doctor|check|upgrade|drift-check|run|config>");
411
+ await printWorkspaceKitTopLevelHelp(writeLine);
412
+ writeError("Missing command. Re-run with a top-level command, or pass --help for the same guide.");
343
413
  return EXIT_USAGE_ERROR;
344
414
  }
345
415
  if (command === "config") {
@@ -581,9 +651,12 @@ export async function runCli(args, options = {}) {
581
651
  });
582
652
  }
583
653
  if (command !== "doctor") {
584
- writeError(`Unknown command '${command}'. Supported commands: init, doctor, check, upgrade, drift-check, run, config.`);
654
+ writeError(`Unknown command '${command}'. Supported: init, doctor, check, upgrade, drift-check, run, config. Run workspace-kit --help for a guided overview.`);
585
655
  return EXIT_USAGE_ERROR;
586
656
  }
657
+ const doctorRest = args.slice(1);
658
+ const wantAgentInstructionSurface = doctorRest.includes("--agent-instruction-surface") ||
659
+ doctorRest.includes("agent-instruction-surface");
587
660
  const issues = [];
588
661
  const requiredPaths = Object.values(defaultWorkspaceKitPaths).map((relativePath) => path.join(cwd, relativePath));
589
662
  for (const requiredPath of requiredPaths) {
@@ -613,8 +686,26 @@ export async function runCli(args, options = {}) {
613
686
  for (const issue of issues) {
614
687
  writeError(`- ${issue.path}: ${issue.reason}`);
615
688
  }
689
+ writeDoctorFailureRemediation(writeError, issues);
616
690
  return EXIT_VALIDATION_FAILURE;
617
691
  }
692
+ if (wantAgentInstructionSurface) {
693
+ try {
694
+ const { registry } = await resolveRegistryAndConfig(cwd, defaultRegistryModules);
695
+ const surface = buildAgentInstructionSurface(registry.getAllModules(), registry);
696
+ writeLine(JSON.stringify({ ok: true, code: "agent-instruction-surface", data: surface }, null, 2));
697
+ }
698
+ catch (error) {
699
+ const message = error instanceof Error ? error.message : String(error);
700
+ writeError(`workspace-kit doctor: could not build agent instruction surface: ${message}`);
701
+ writeError(" Hint: workspace-kit --help; fix config/module issues, then retry.");
702
+ if (error instanceof ModuleRegistryError) {
703
+ return EXIT_VALIDATION_FAILURE;
704
+ }
705
+ return EXIT_INTERNAL_ERROR;
706
+ }
707
+ return EXIT_SUCCESS;
708
+ }
618
709
  writeLine("workspace-kit doctor passed.");
619
710
  writeLine("All canonical workspace-kit contract files are present and parseable JSON.");
620
711
  writeLine("Effective workspace config resolved; task planning persistence checks passed (including SQLite when configured).");
@@ -0,0 +1,17 @@
1
+ import type { ModuleInstructionEntry } from "./module-contract.js";
2
+ /**
3
+ * Single-row command declaration for a module: instruction catalog metadata plus optional
4
+ * policy binding for Tier A/B `workspace-kit run` sensitivity (see `docs/maintainers/POLICY-APPROVAL.md`).
5
+ *
6
+ * Phase 20: policy bindings are assembled in `src/core/policy.ts` from per-module `policy-sensitive-commands.ts`
7
+ * files so operation ids are not duplicated alongside `COMMAND_TO_OPERATION`.
8
+ *
9
+ * Future: merge `ModuleInstructionEntry` generation from the same manifest rows (see `docs/maintainers/module-build-guide.md`).
10
+ */
11
+ export type ModuleCommandManifestRow = ModuleInstructionEntry & {
12
+ /**
13
+ * When set, this command requires JSON `policyApproval` (or session grant) for `workspace-kit run`
14
+ * when sensitive per `isSensitiveModuleCommand` rules in `src/core/policy.ts`.
15
+ */
16
+ policyOperationId?: string;
17
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- export type { ConfigRegistryView, ResponseTemplateApplicationMeta, ModuleCommand, ModuleCommandResult, ModuleCapability, ModuleDocumentContract, ModuleEvent, ModuleInstructionContract, ModuleInstructionEntry, ModuleLifecycleContext, ModuleRegistration, WorkflowModule } from "./module-contract.js";
1
+ export type { ConfigRegistryView, ResponseTemplateApplicationMeta, ModuleCommand, ModuleCommandResult, ModuleCapability, ModuleDocumentContract, ModuleInstructionContract, ModuleInstructionEntry, ModuleLifecycleContext, ModuleRegistration, WorkflowModule } from "./module-contract.js";
@@ -1,4 +1,4 @@
1
- export type ModuleCapability = "documentation" | "task-engine" | "planning" | "improvement" | "approvals" | "diagnostics" | "migration";
1
+ export type ModuleCapability = "documentation" | "task-engine" | "planning" | "improvement" | "approvals" | "diagnostics" | "migration" | "agent-behavior";
2
2
  export type ModuleDocumentContract = {
3
3
  path: string;
4
4
  format: "md";
@@ -14,6 +14,11 @@ export type ModuleInstructionEntry = {
14
14
  */
15
15
  file: string;
16
16
  description?: string;
17
+ /**
18
+ * Other module ids that must be enabled for this command to be registered in the
19
+ * command router (in addition to the owning module). Empty/omitted = no extra peers.
20
+ */
21
+ requiresPeers?: string[];
17
22
  };
18
23
  export type ModuleInstructionContract = {
19
24
  /**
@@ -22,10 +27,6 @@ export type ModuleInstructionContract = {
22
27
  directory: string;
23
28
  entries: ModuleInstructionEntry[];
24
29
  };
25
- export type ModuleEvent = {
26
- type: string;
27
- payload?: Record<string, unknown>;
28
- };
29
30
  export type ModuleCommand = {
30
31
  name: string;
31
32
  args?: Record<string, unknown>;
@@ -71,19 +72,19 @@ export type ModuleRegistration = {
71
72
  id: string;
72
73
  version: string;
73
74
  contractVersion: "1";
75
+ stateSchema: number;
74
76
  capabilities: ModuleCapability[];
75
77
  dependsOn: string[];
78
+ /**
79
+ * Other modules this module integrates with when present; unlike dependsOn,
80
+ * missing optional peers do not block registry construction or enablement.
81
+ */
82
+ optionalPeers?: string[];
76
83
  enabledByDefault: boolean;
77
84
  config: ModuleDocumentContract;
78
- state: ModuleDocumentContract;
79
85
  instructions: ModuleInstructionContract;
80
86
  };
81
87
  export interface WorkflowModule {
82
88
  registration: ModuleRegistration;
83
- onInstall?(ctx: ModuleLifecycleContext): Promise<void>;
84
- onConfigChange?(ctx: ModuleLifecycleContext): Promise<void>;
85
- onStart?(ctx: ModuleLifecycleContext): Promise<void>;
86
- onStop?(ctx: ModuleLifecycleContext): Promise<void>;
87
- onEvent?(event: ModuleEvent, ctx: ModuleLifecycleContext): Promise<void>;
88
89
  onCommand?(command: ModuleCommand, ctx: ModuleLifecycleContext): Promise<ModuleCommandResult>;
89
90
  }
@@ -0,0 +1,33 @@
1
+ import type { ModuleInstructionEntry, WorkflowModule } from "../contracts/module-contract.js";
2
+ import type { ModuleActivationReport, ModuleRegistry } from "./module-registry.js";
3
+ export type AgentInstructionDegradation = {
4
+ kind: "executable";
5
+ } | {
6
+ kind: "module_disabled";
7
+ } | {
8
+ kind: "peer_disabled";
9
+ missingPeers: string[];
10
+ };
11
+ export type AgentInstructionSurfaceRow = {
12
+ commandName: string;
13
+ moduleId: string;
14
+ /** Repo-relative path to the instruction markdown file. */
15
+ instructionPath: string;
16
+ executable: boolean;
17
+ degradation: AgentInstructionDegradation;
18
+ };
19
+ export type AgentInstructionSurfacePayload = {
20
+ schemaVersion: 1;
21
+ commands: AgentInstructionSurfaceRow[];
22
+ activationReport: ModuleActivationReport;
23
+ };
24
+ /**
25
+ * Classifies whether an instruction can be executed via the command router for the
26
+ * current enabled module set (owning module enabled + all requiresPeers enabled).
27
+ */
28
+ export declare function classifyInstructionExecution(mod: WorkflowModule, entry: ModuleInstructionEntry, registry: ModuleRegistry): AgentInstructionDegradation;
29
+ export declare function isInstructionExecutableForRegistry(mod: WorkflowModule, entry: ModuleInstructionEntry, registry: ModuleRegistry): boolean;
30
+ /**
31
+ * Full catalog for agents: every declared instruction, with executable vs documentation-only.
32
+ */
33
+ export declare function buildAgentInstructionSurface(allModules: WorkflowModule[], registry: ModuleRegistry): AgentInstructionSurfacePayload;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Classifies whether an instruction can be executed via the command router for the
3
+ * current enabled module set (owning module enabled + all requiresPeers enabled).
4
+ */
5
+ export function classifyInstructionExecution(mod, entry, registry) {
6
+ const moduleId = mod.registration.id;
7
+ if (!registry.isModuleEnabled(moduleId)) {
8
+ return { kind: "module_disabled" };
9
+ }
10
+ const requires = entry.requiresPeers ?? [];
11
+ const missing = requires.filter((peerId) => !registry.isModuleEnabled(peerId));
12
+ if (missing.length > 0) {
13
+ return { kind: "peer_disabled", missingPeers: missing };
14
+ }
15
+ return { kind: "executable" };
16
+ }
17
+ export function isInstructionExecutableForRegistry(mod, entry, registry) {
18
+ return classifyInstructionExecution(mod, entry, registry).kind === "executable";
19
+ }
20
+ /**
21
+ * Full catalog for agents: every declared instruction, with executable vs documentation-only.
22
+ */
23
+ export function buildAgentInstructionSurface(allModules, registry) {
24
+ const commands = [];
25
+ for (const mod of allModules) {
26
+ const moduleId = mod.registration.id;
27
+ const { directory, entries } = mod.registration.instructions;
28
+ for (const entry of entries) {
29
+ const degradation = classifyInstructionExecution(mod, entry, registry);
30
+ const instructionPath = `${directory}/${entry.file}`.replace(/\\/g, "/");
31
+ commands.push({
32
+ commandName: entry.name,
33
+ moduleId,
34
+ instructionPath,
35
+ executable: degradation.kind === "executable",
36
+ degradation
37
+ });
38
+ }
39
+ }
40
+ commands.sort((a, b) => a.commandName.localeCompare(b.commandName));
41
+ return {
42
+ schemaVersion: 1,
43
+ commands,
44
+ activationReport: registry.getActivationReport()
45
+ };
46
+ }
@@ -3,16 +3,12 @@ import { createInterface } from "node:readline/promises";
3
3
  import { stdin as processStdin, stdout as processStdout } from "node:process";
4
4
  import path from "node:path";
5
5
  import { ModuleRegistry } from "./module-registry.js";
6
+ import { pickModuleContractWorkspacePath, resolveRegistryAndConfig } from "./module-registry-resolve.js";
6
7
  import { appendPolicyTrace, parsePolicyApprovalFromEnv, resolveActorWithFallback } from "./policy.js";
7
8
  import { appendConfigMutation, summarizeForEvidence } from "./config-mutations.js";
8
9
  import { assertWritableKey, getConfigKeyMetadata, listConfigMetadata, validatePersistedConfigDocument, validateValueForMetadata } from "./config-metadata.js";
9
10
  import { explainConfigPath, getAtPath, getProjectConfigPath, getUserConfigFilePath, resolveWorkspaceConfigWithLayers, stableStringifyConfig } from "./workspace-kit-config.js";
10
- import { workspaceConfigModule } from "../modules/workspace-config/index.js";
11
- import { documentationModule } from "../modules/documentation/index.js";
12
- import { taskEngineModule } from "../modules/task-engine/index.js";
13
- import { approvalsModule } from "../modules/approvals/index.js";
14
- import { planningModule } from "../modules/planning/index.js";
15
- import { improvementModule } from "../modules/improvement/index.js";
11
+ import { defaultRegistryModules } from "../modules/index.js";
16
12
  const EXIT_SUCCESS = 0;
17
13
  const EXIT_VALIDATION_FAILURE = 1;
18
14
  const EXIT_USAGE_ERROR = 2;
@@ -90,16 +86,10 @@ async function writeConfigFileAtomic(fp, data) {
90
86
  await fs.writeFile(tmp, stableStringifyConfig(data), "utf8");
91
87
  await fs.rename(tmp, fp);
92
88
  }
93
- function buildRegistry() {
94
- const allModules = [
95
- workspaceConfigModule,
96
- documentationModule,
97
- taskEngineModule,
98
- approvalsModule,
99
- planningModule,
100
- improvementModule
101
- ];
102
- return new ModuleRegistry(allModules);
89
+ function buildRegistry(workspacePath) {
90
+ return new ModuleRegistry(defaultRegistryModules, {
91
+ workspacePath: pickModuleContractWorkspacePath(workspacePath)
92
+ });
103
93
  }
104
94
  function parseConfigArgs(argv) {
105
95
  const json = argv.includes("--json");
@@ -159,7 +149,13 @@ export async function runWorkspaceConfigCli(cwd, argv, io) {
159
149
  }
160
150
  let registry;
161
151
  try {
162
- registry = buildRegistry();
152
+ if (sub === "list") {
153
+ registry = buildRegistry(cwd);
154
+ }
155
+ else {
156
+ const resolved = await resolveRegistryAndConfig(cwd, defaultRegistryModules);
157
+ registry = resolved.registry;
158
+ }
163
159
  }
164
160
  catch (e) {
165
161
  writeError(e instanceof Error ? e.message : String(e));