@workflow-cannon/workspace-kit 0.18.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 (140) 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 +61 -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 +8 -0
  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/index.js +384 -50
  81. package/dist/modules/planning/question-engine.d.ts +2 -0
  82. package/dist/modules/planning/question-engine.js +8 -1
  83. package/dist/modules/task-engine/doctor-planning-persistence.js +21 -13
  84. package/dist/modules/task-engine/index.d.ts +1 -2
  85. package/dist/modules/task-engine/index.js +1 -1143
  86. package/dist/modules/task-engine/migrate-task-persistence-runtime.js +31 -4
  87. package/dist/modules/task-engine/migrate-wishlist-intake-runtime.d.ts +2 -0
  88. package/dist/modules/task-engine/migrate-wishlist-intake-runtime.js +146 -0
  89. package/dist/modules/task-engine/planning-open.d.ts +2 -9
  90. package/dist/modules/task-engine/planning-open.js +4 -15
  91. package/dist/modules/task-engine/policy-sensitive-commands.d.ts +5 -0
  92. package/dist/modules/task-engine/policy-sensitive-commands.js +5 -0
  93. package/dist/modules/task-engine/sqlite-dual-planning.d.ts +11 -2
  94. package/dist/modules/task-engine/sqlite-dual-planning.js +134 -28
  95. package/dist/modules/task-engine/strict-task-validation.js +3 -0
  96. package/dist/modules/task-engine/suggestions.js +2 -1
  97. package/dist/modules/task-engine/task-engine-internal.d.ts +2 -0
  98. package/dist/modules/task-engine/task-engine-internal.js +1304 -0
  99. package/dist/modules/task-engine/task-type-validation.js +40 -0
  100. package/dist/modules/task-engine/wishlist-intake.d.ts +22 -0
  101. package/dist/modules/task-engine/wishlist-intake.js +180 -0
  102. package/dist/modules/task-engine/wishlist-validation.d.ts +4 -0
  103. package/dist/modules/task-engine/wishlist-validation.js +19 -0
  104. package/dist/modules/workspace-config/index.js +9 -11
  105. package/package.json +2 -2
  106. package/schemas/agent-behavior-profile.schema.json +52 -0
  107. package/schemas/task-engine-run-contracts.schema.json +80 -5
  108. package/src/modules/documentation/README.md +16 -25
  109. package/src/modules/documentation/RULES.md +9 -9
  110. package/src/modules/documentation/index.ts +54 -49
  111. package/src/modules/documentation/instructions/document-project.md +6 -6
  112. package/src/modules/documentation/instructions/generate-document.md +4 -4
  113. package/src/modules/documentation/normalizer.ts +187 -0
  114. package/src/modules/documentation/parser.ts +41 -0
  115. package/src/modules/documentation/policy-sensitive-commands.ts +8 -0
  116. package/src/modules/documentation/renderer.ts +121 -0
  117. package/src/modules/documentation/runtime-batch.ts +74 -0
  118. package/src/modules/documentation/runtime-config.ts +68 -0
  119. package/src/modules/documentation/runtime-render-support.ts +39 -0
  120. package/src/modules/documentation/runtime.ts +28 -600
  121. package/src/modules/documentation/schemas/documentation-schema.md +37 -54
  122. package/src/modules/documentation/types.ts +228 -0
  123. package/src/modules/documentation/validator.ts +247 -0
  124. package/src/modules/documentation/view-models.ts +132 -0
  125. package/src/modules/documentation/views/agents.view.yaml +18 -0
  126. package/src/modules/documentation/views/architecture.view.yaml +18 -0
  127. package/src/modules/documentation/views/principles.view.yaml +18 -0
  128. package/src/modules/documentation/views/readme.view.yaml +18 -0
  129. package/src/modules/documentation/views/releasing.view.yaml +18 -0
  130. package/src/modules/documentation/views/roadmap.view.yaml +18 -0
  131. package/src/modules/documentation/views/runbooks-consumer-cadence.view.yaml +18 -0
  132. package/src/modules/documentation/views/runbooks-parity-validation-flow.view.yaml +18 -0
  133. package/src/modules/documentation/views/runbooks-release-channels.view.yaml +18 -0
  134. package/src/modules/documentation/views/security.view.yaml +18 -0
  135. package/src/modules/documentation/views/support.view.yaml +18 -0
  136. package/src/modules/documentation/views/terms.view.yaml +18 -0
  137. package/src/modules/documentation/views/workbooks-phase2-config-policy-workbook.view.yaml +18 -0
  138. package/src/modules/documentation/views/workbooks-task-engine-workbook.view.yaml +18 -0
  139. package/src/modules/documentation/views/workbooks-transcript-automation-baseline.view.yaml +18 -0
  140. package/src/modules/documentation/state.md +0 -8
@@ -13,21 +13,18 @@ function parseOptions(raw) {
13
13
  export const documentationModule = {
14
14
  registration: {
15
15
  id: "documentation",
16
- version: "0.2.0",
16
+ version: "0.3.0",
17
17
  contractVersion: "1",
18
+ stateSchema: 1,
18
19
  capabilities: ["documentation"],
19
20
  dependsOn: [],
21
+ optionalPeers: [],
20
22
  enabledByDefault: true,
21
23
  config: {
22
24
  path: "src/modules/documentation/config.md",
23
25
  format: "md",
24
26
  description: "Documentation module configuration contract."
25
27
  },
26
- state: {
27
- path: "src/modules/documentation/state.md",
28
- format: "md",
29
- description: "Documentation module generation/runtime state contract."
30
- },
31
28
  instructions: {
32
29
  directory: "src/modules/documentation/instructions",
33
30
  entries: [
@@ -50,45 +47,50 @@ export const documentationModule = {
50
47
  ? args.options
51
48
  : {};
52
49
  const options = parseOptions(rawOptions);
53
- if (command.name === "document-project") {
54
- const batchResult = await generateAllDocuments({ options }, ctx);
55
- return {
56
- ok: batchResult.ok,
57
- code: batchResult.ok ? "documented-project" : "documentation-batch-failed",
58
- message: batchResult.ok
59
- ? `Generated ${batchResult.summary.succeeded} documents (${batchResult.summary.skipped} skipped)`
60
- : `Batch failed: ${batchResult.summary.failed} of ${batchResult.summary.total} documents failed`,
61
- data: {
62
- summary: batchResult.summary,
63
- results: batchResult.results.map((r) => ({
64
- documentType: r.evidence.documentType,
65
- ok: r.ok,
66
- aiOutputPath: r.aiOutputPath,
67
- humanOutputPath: r.humanOutputPath,
68
- filesWritten: r.evidence.filesWritten,
69
- filesSkipped: r.evidence.filesSkipped,
70
- }))
71
- }
72
- };
73
- }
74
- if (command.name === "generate-document") {
75
- const result = await generateDocument({
76
- documentType: typeof args.documentType === "string" ? args.documentType : undefined,
77
- options
78
- }, ctx);
79
- return {
80
- ok: result.ok,
81
- code: result.ok ? "generated-document" : "generation-failed",
82
- message: result.ok
83
- ? `Generated document '${args.documentType ?? "unknown"}'`
84
- : `Failed to generate document '${args.documentType ?? "unknown"}'`,
85
- data: {
86
- aiOutputPath: result.aiOutputPath,
87
- humanOutputPath: result.humanOutputPath,
88
- evidence: result.evidence
89
- }
90
- };
91
- }
50
+ const handlers = {
51
+ "document-project": async () => {
52
+ const batchResult = await generateAllDocuments({ options }, ctx);
53
+ return {
54
+ ok: batchResult.ok,
55
+ code: batchResult.ok ? "documented-project" : "documentation-batch-failed",
56
+ message: batchResult.ok
57
+ ? `Generated ${batchResult.summary.succeeded} documents (${batchResult.summary.skipped} skipped)`
58
+ : `Batch failed: ${batchResult.summary.failed} of ${batchResult.summary.total} documents failed`,
59
+ data: {
60
+ summary: batchResult.summary,
61
+ results: batchResult.results.map((r) => ({
62
+ documentType: r.evidence.documentType,
63
+ ok: r.ok,
64
+ aiOutputPath: r.aiOutputPath,
65
+ humanOutputPath: r.humanOutputPath,
66
+ filesWritten: r.evidence.filesWritten,
67
+ filesSkipped: r.evidence.filesSkipped
68
+ }))
69
+ }
70
+ };
71
+ },
72
+ "generate-document": async () => {
73
+ const result = await generateDocument({
74
+ documentType: typeof args.documentType === "string" ? args.documentType : undefined,
75
+ options
76
+ }, ctx);
77
+ return {
78
+ ok: result.ok,
79
+ code: result.ok ? "generated-document" : "generation-failed",
80
+ message: result.ok
81
+ ? `Generated document '${args.documentType ?? "unknown"}'`
82
+ : `Failed to generate document '${args.documentType ?? "unknown"}'`,
83
+ data: {
84
+ aiOutputPath: result.aiOutputPath,
85
+ humanOutputPath: result.humanOutputPath,
86
+ evidence: result.evidence
87
+ }
88
+ };
89
+ }
90
+ };
91
+ const handler = handlers[command.name];
92
+ if (handler)
93
+ return handler();
92
94
  return {
93
95
  ok: false,
94
96
  code: "unsupported-command",
@@ -0,0 +1,3 @@
1
+ import type { AiRecord } from "./parser.js";
2
+ import type { NormalizedDocument } from "./types.js";
3
+ export declare function normalizeDocument(records: AiRecord[]): NormalizedDocument;
@@ -0,0 +1,171 @@
1
+ function asStatus(v) {
2
+ if (v === "active" || v === "deprecated" || v === "draft" || v === "observed" || v === "planned")
3
+ return v;
4
+ return undefined;
5
+ }
6
+ function asList(v) {
7
+ if (!v)
8
+ return [];
9
+ return v
10
+ .split(",")
11
+ .map((x) => x.trim())
12
+ .filter(Boolean);
13
+ }
14
+ export function normalizeDocument(records) {
15
+ const refs = [];
16
+ const rules = [];
17
+ const checks = [];
18
+ const decisions = [];
19
+ const examples = [];
20
+ const terms = [];
21
+ const commands = [];
22
+ const workflows = [];
23
+ const runbooks = [];
24
+ const workbooks = [];
25
+ const chains = [];
26
+ const states = [];
27
+ const transitions = [];
28
+ const promotions = [];
29
+ const rollbacks = [];
30
+ const artifacts = [];
31
+ const configs = [];
32
+ const cadences = [];
33
+ const guardrails = [];
34
+ const refsById = new Map();
35
+ const examplesByParent = new Map();
36
+ const profileRecords = new Map([
37
+ ["core", []],
38
+ ["runbook", []],
39
+ ["workbook", []]
40
+ ]);
41
+ let meta = null;
42
+ for (const rec of records) {
43
+ const status = asStatus(rec.kv["status"] ?? rec.kv["st"]);
44
+ if (rec.type === "meta") {
45
+ meta = {
46
+ schema: "base.v2",
47
+ doc: rec.kv["doc"] ?? "rules",
48
+ truth: rec.kv["truth"] ?? "canonical",
49
+ profile: rec.kv["profile"],
50
+ status,
51
+ title: rec.kv["title"],
52
+ owner: rec.kv["owner"],
53
+ tags: asList(rec.kv["tags"]),
54
+ refs: asList(rec.kv["refs"])
55
+ };
56
+ continue;
57
+ }
58
+ if (rec.type === "ref") {
59
+ const ref = {
60
+ id: rec.kv["id"] ?? rec.kv["name"] ?? "",
61
+ type: rec.kv["type"] ?? "doc",
62
+ target: rec.kv["target"] ?? rec.kv["path"] ?? "",
63
+ anchor: rec.kv["anchor"],
64
+ label: rec.kv["label"] ?? rec.kv["name"],
65
+ note: rec.kv["note"],
66
+ status
67
+ };
68
+ refs.push(ref);
69
+ if (ref.id)
70
+ refsById.set(ref.id, ref);
71
+ continue;
72
+ }
73
+ if (rec.type === "rule") {
74
+ rules.push({
75
+ id: rec.kv["id"] ?? rec.kv["slot1"] ?? "",
76
+ level: rec.kv["level"] ?? "should",
77
+ scope: rec.kv["scope"] ?? "",
78
+ scope_kind: rec.kv["scope_kind"],
79
+ kind: rec.kv["kind"],
80
+ directive: rec.kv["directive"] ?? rec.kv["slot3"] ?? "",
81
+ why: rec.kv["why"] ?? "",
82
+ unless: rec.kv["unless"],
83
+ also: asList(rec.kv["also"]),
84
+ risk: rec.kv["risk"],
85
+ approval: rec.kv["approval"],
86
+ override: rec.kv["override"],
87
+ status,
88
+ refs: asList(rec.kv["refs"])
89
+ });
90
+ continue;
91
+ }
92
+ if (rec.type === "example") {
93
+ const ex = {
94
+ id: rec.kv["id"] ?? "",
95
+ for: rec.kv["for"] ?? "",
96
+ kind: rec.kv["kind"] ?? "edge",
97
+ text: rec.kv["text"] ?? "",
98
+ status,
99
+ refs: asList(rec.kv["refs"])
100
+ };
101
+ examples.push(ex);
102
+ const list = examplesByParent.get(ex.for) ?? [];
103
+ list.push(ex);
104
+ examplesByParent.set(ex.for, list);
105
+ continue;
106
+ }
107
+ if (rec.type === "check")
108
+ checks.push({ id: rec.kv["id"] ?? "", scope: rec.kv["scope"] ?? "", assertion: rec.kv["assertion"] ?? rec.kv["assert"] ?? "", when: rec.kv["when"], onFail: rec.kv["onFail"], status, refs: asList(rec.kv["refs"]) });
109
+ if (rec.type === "decision")
110
+ decisions.push({ id: rec.kv["id"] ?? "", topic: rec.kv["topic"] ?? "", choice: rec.kv["choice"] ?? "", why: rec.kv["why"] ?? "", consequence: rec.kv["consequence"] ?? rec.kv["then"], status, refs: asList(rec.kv["refs"]) });
111
+ if (rec.type === "term")
112
+ terms.push({ name: rec.kv["name"] ?? "", definition: rec.kv["definition"] ?? rec.kv["def"] ?? "", status, refs: asList(rec.kv["refs"]) });
113
+ if (rec.type === "command" || rec.type === "cmd")
114
+ commands.push({ id: rec.kv["id"] ?? rec.kv["slot1"] ?? "", name: rec.kv["name"] ?? "", use: rec.kv["use"] ?? "", scope: rec.kv["scope"] ?? "", expectation: rec.kv["expectation"] ?? rec.kv["expect"] ?? "", risk: rec.kv["risk"], sensitivity: rec.kv["sensitivity"], status, refs: asList(rec.kv["refs"]) });
115
+ if (rec.type === "workflow" || rec.type === "wf")
116
+ workflows.push({ id: rec.kv["id"] ?? rec.kv["slot1"] ?? "", name: rec.kv["name"] ?? "", when: rec.kv["when"] ?? "", steps: asList(rec.kv["steps"] ?? rec.kv["do"]), done: asList(rec.kv["done"]), forbid: asList(rec.kv["forbid"]), askIf: rec.kv["askIf"] ?? rec.kv["ask_if"], haltIf: rec.kv["haltIf"] ?? rec.kv["halt_if"], approval: rec.kv["approval"], risk: rec.kv["risk"], status, refs: asList(rec.kv["refs"]) });
117
+ if (rec.type === "runbook")
118
+ runbooks.push({ name: rec.kv["name"] ?? "", scope: rec.kv["scope"] ?? "", owner: rec.kv["owner"] ?? "", status, refs: asList(rec.kv["refs"]) });
119
+ if (rec.type === "workbook")
120
+ workbooks.push({ name: rec.kv["name"] ?? "", phase: rec.kv["phase"] ?? "", state: rec.kv["state"] ?? "", status, refs: asList(rec.kv["refs"]) });
121
+ if (rec.type === "chain")
122
+ chains.push({ step: rec.kv["step"] ?? "", command: rec.kv["command"] ?? "", expectExit: Number.parseInt(rec.kv["expectExit"] ?? rec.kv["expect_exit"] ?? "0", 10), status, refs: asList(rec.kv["refs"]) });
123
+ if (rec.type === "state")
124
+ states.push({ name: rec.kv["name"] ?? "", distTag: rec.kv["distTag"] ?? rec.kv["dist_tag"] ?? "", intent: rec.kv["intent"] ?? "", status, refs: asList(rec.kv["refs"]) });
125
+ if (rec.type === "transition")
126
+ transitions.push({ from: rec.kv["from"] ?? "", to: rec.kv["to"] ?? "", requires: asList(rec.kv["requires"]), status, refs: asList(rec.kv["refs"]) });
127
+ if (rec.type === "promotion")
128
+ promotions.push({ from: rec.kv["from"] ?? "", to: rec.kv["to"] ?? "", requires: asList(rec.kv["requires"]), status, refs: asList(rec.kv["refs"]) });
129
+ if (rec.type === "rollback")
130
+ rollbacks.push({ strategy: rec.kv["strategy"] ?? "", note: rec.kv["note"] ?? "", status, refs: asList(rec.kv["refs"]) });
131
+ if (rec.type === "artifact")
132
+ artifacts.push({ path: rec.kv["path"] ?? "", schema: rec.kv["schema"] ?? "", status, refs: asList(rec.kv["refs"]) });
133
+ if (rec.type === "config")
134
+ configs.push({ key: rec.kv["key"] ?? "", default: rec.kv["default"] ?? "", status, refs: asList(rec.kv["refs"]) });
135
+ if (rec.type === "cadence")
136
+ cadences.push({ rule: rec.kv["rule"] ?? "", status, refs: asList(rec.kv["refs"]) });
137
+ if (rec.type === "guardrail")
138
+ guardrails.push({ id: rec.kv["id"] ?? "", level: rec.kv["level"] ?? "should", directive: rec.kv["directive"] ?? "", why: rec.kv["why"] ?? "", status, refs: asList(rec.kv["refs"]) });
139
+ }
140
+ const core = [...refs, ...rules, ...checks, ...decisions, ...examples, ...terms, ...commands, ...workflows];
141
+ const runbook = [...runbooks, ...chains, ...states, ...transitions, ...promotions, ...rollbacks, ...artifacts, ...configs, ...cadences, ...guardrails];
142
+ const workbook = [...workbooks, ...states, ...transitions, ...artifacts, ...guardrails];
143
+ profileRecords.set("core", core);
144
+ profileRecords.set("runbook", runbook);
145
+ profileRecords.set("workbook", workbook);
146
+ return {
147
+ meta,
148
+ refs,
149
+ rules,
150
+ checks,
151
+ decisions,
152
+ examples,
153
+ terms,
154
+ commands,
155
+ workflows,
156
+ runbooks,
157
+ workbooks,
158
+ chains,
159
+ states,
160
+ transitions,
161
+ promotions,
162
+ rollbacks,
163
+ artifacts,
164
+ configs,
165
+ cadences,
166
+ guardrails,
167
+ refsById,
168
+ examplesByParent,
169
+ profileRecords
170
+ };
171
+ }
@@ -0,0 +1,7 @@
1
+ export type AiRecord = {
2
+ type: string;
3
+ kv: Record<string, string>;
4
+ raw: string;
5
+ };
6
+ export declare function parseAiRecordLine(line: string): AiRecord | null;
7
+ export declare function parseAiDocument(text: string): AiRecord[];
@@ -0,0 +1,39 @@
1
+ export function parseAiRecordLine(line) {
2
+ const trimmed = line.trim();
3
+ if (!trimmed || trimmed.startsWith("#"))
4
+ return null;
5
+ const parts = trimmed.split("|");
6
+ if (parts.length < 2)
7
+ return null;
8
+ const type = parts[0]?.trim() ?? "";
9
+ if (!type)
10
+ return null;
11
+ const kv = {};
12
+ let slotIndex = 1;
13
+ for (const token of parts.slice(1)) {
14
+ const piece = token.trim();
15
+ if (!piece)
16
+ continue;
17
+ const idx = piece.indexOf("=");
18
+ if (idx >= 0) {
19
+ const key = piece.slice(0, idx).trim();
20
+ const value = piece.slice(idx + 1).trim();
21
+ if (key)
22
+ kv[key] = value;
23
+ continue;
24
+ }
25
+ // Transitional support: retain unkeyed tokens as synthetic slots.
26
+ kv[`slot${slotIndex}`] = piece;
27
+ slotIndex += 1;
28
+ }
29
+ return { type, kv, raw: line };
30
+ }
31
+ export function parseAiDocument(text) {
32
+ const records = [];
33
+ for (const line of text.split("\n")) {
34
+ const rec = parseAiRecordLine(line);
35
+ if (rec)
36
+ records.push(rec);
37
+ }
38
+ return records;
39
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Policy-gated `workspace-kit run` commands owned by the documentation module.
3
+ * Keep in sync with instruction names in `documentation/index.ts`.
4
+ */
5
+ export declare const DOCUMENTATION_POLICY_COMMAND_NAMES: readonly [readonly ["document-project", "doc.document-project"], readonly ["generate-document", "doc.generate-document"]];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Policy-gated `workspace-kit run` commands owned by the documentation module.
3
+ * Keep in sync with instruction names in `documentation/index.ts`.
4
+ */
5
+ export const DOCUMENTATION_POLICY_COMMAND_NAMES = [
6
+ ["document-project", "doc.document-project"],
7
+ ["generate-document", "doc.generate-document"]
8
+ ];
@@ -0,0 +1,23 @@
1
+ import type { NormalizedCheck, NormalizedCommand, NormalizedDecision, NormalizedDocument, NormalizedRule, NormalizedTerm, NormalizedWorkflow, ViewModelDefinition } from "./types.js";
2
+ export declare function brief_summary(input: string[]): string;
3
+ export declare function ordered_list(input: string[]): string;
4
+ export declare function rule_table(rules: NormalizedRule[]): string;
5
+ export declare function check_table(checks: NormalizedCheck[]): string;
6
+ export declare function command_reference(commands: NormalizedCommand[]): string;
7
+ export declare function decision_section(decisions: NormalizedDecision[]): string;
8
+ export declare function term_list(terms: NormalizedTerm[]): string;
9
+ export declare function workflow_steps(workflows: NormalizedWorkflow[]): string;
10
+ export declare function chain_steps(chains: Array<{
11
+ step: string;
12
+ command: string;
13
+ expectExit: number;
14
+ }>): string;
15
+ export declare function ref_table(refs: Array<{
16
+ id: string;
17
+ type: string;
18
+ target: string;
19
+ }>): string;
20
+ export declare const renderMetaSection: (doc: NormalizedDocument) => string;
21
+ export declare const renderRuleSection: (doc: NormalizedDocument) => string;
22
+ export declare const renderDecisionSection: (doc: NormalizedDocument) => string;
23
+ export declare function renderDocument(doc: NormalizedDocument, view: ViewModelDefinition): string;
@@ -0,0 +1,105 @@
1
+ function stableSort(values) {
2
+ return [...values].sort((a, b) => a.localeCompare(b));
3
+ }
4
+ export function brief_summary(input) {
5
+ if (input.length === 0)
6
+ return "No summary records.";
7
+ return input.map((line) => `- ${line}`).join("\n");
8
+ }
9
+ export function ordered_list(input) {
10
+ if (input.length === 0)
11
+ return "1. No entries";
12
+ return input.map((line, idx) => `${idx + 1}. ${line}`).join("\n");
13
+ }
14
+ export function rule_table(rules) {
15
+ if (rules.length === 0)
16
+ return "_No rules_";
17
+ const rows = [...rules].sort((a, b) => a.id.localeCompare(b.id));
18
+ const body = rows
19
+ .map((r) => `| ${r.id} | ${r.level} | ${r.scope || "-"} | ${r.directive || "-"} | ${r.why || "-"} |`)
20
+ .join("\n");
21
+ return `| ID | Level | Scope | Directive | Why |\n|---|---|---|---|---|\n${body}`;
22
+ }
23
+ export function check_table(checks) {
24
+ if (checks.length === 0)
25
+ return "_No checks_";
26
+ const rows = [...checks].sort((a, b) => a.id.localeCompare(b.id));
27
+ const body = rows
28
+ .map((c) => `| ${c.id} | ${c.scope || "-"} | ${c.assertion || "-"} | ${c.onFail || "-"} |`)
29
+ .join("\n");
30
+ return `| ID | Scope | Assertion | On Fail |\n|---|---|---|---|\n${body}`;
31
+ }
32
+ export function command_reference(commands) {
33
+ if (commands.length === 0)
34
+ return "_No commands_";
35
+ const rows = [...commands].sort((a, b) => a.name.localeCompare(b.name));
36
+ return rows.map((c) => `- \`${c.name}\`: ${c.expectation || c.use || "No expectation"}`).join("\n");
37
+ }
38
+ export function decision_section(decisions) {
39
+ if (decisions.length === 0)
40
+ return "_No decisions_";
41
+ const rows = [...decisions].sort((a, b) => a.id.localeCompare(b.id));
42
+ return rows.map((d) => `### ${d.id}: ${d.topic}\n- Choice: ${d.choice}\n- Why: ${d.why}`).join("\n\n");
43
+ }
44
+ export function term_list(terms) {
45
+ if (terms.length === 0)
46
+ return "_No terms_";
47
+ return [...terms]
48
+ .sort((a, b) => a.name.localeCompare(b.name))
49
+ .map((t) => `- **${t.name}**: ${t.definition}`)
50
+ .join("\n");
51
+ }
52
+ export function workflow_steps(workflows) {
53
+ if (workflows.length === 0)
54
+ return "_No workflows_";
55
+ return workflows
56
+ .sort((a, b) => a.id.localeCompare(b.id))
57
+ .map((wf) => `### ${wf.id}: ${wf.name}\n${ordered_list(stableSort(wf.steps))}`)
58
+ .join("\n\n");
59
+ }
60
+ export function chain_steps(chains) {
61
+ if (chains.length === 0)
62
+ return "_No chain steps_";
63
+ return chains
64
+ .map((c, idx) => `${idx + 1}. ${c.step} -> \`${c.command}\` (expect ${c.expectExit})`)
65
+ .join("\n");
66
+ }
67
+ export function ref_table(refs) {
68
+ if (refs.length === 0)
69
+ return "_No refs_";
70
+ const body = [...refs]
71
+ .sort((a, b) => a.id.localeCompare(b.id))
72
+ .map((r) => `| ${r.id} | ${r.type} | ${r.target} |`)
73
+ .join("\n");
74
+ return `| ID | Type | Target |\n|---|---|---|\n${body}`;
75
+ }
76
+ export const renderMetaSection = (doc) => brief_summary([
77
+ `doc=${doc.meta?.doc ?? "unknown"}`,
78
+ `truth=${doc.meta?.truth ?? "unknown"}`,
79
+ `profile=${doc.meta?.profile ?? "core"}`
80
+ ]);
81
+ export const renderRuleSection = (doc) => rule_table(doc.rules);
82
+ export const renderDecisionSection = (doc) => decision_section(doc.decisions);
83
+ function renderSection(doc, section) {
84
+ const byName = {
85
+ renderMetaSection,
86
+ renderRuleSection,
87
+ renderDecisionSection,
88
+ brief_summary: (d) => brief_summary(d.examples.map((e) => e.text)),
89
+ ordered_list: (d) => ordered_list(d.commands.map((c) => c.name)),
90
+ rule_table: (d) => rule_table(d.rules),
91
+ check_table: (d) => check_table(d.checks),
92
+ command_reference: (d) => command_reference(d.commands),
93
+ decision_section: (d) => decision_section(d.decisions),
94
+ term_list: (d) => term_list(d.terms),
95
+ workflow_steps: (d) => workflow_steps(d.workflows),
96
+ chain_steps: (d) => chain_steps(d.chains),
97
+ ref_table: (d) => ref_table(d.refs)
98
+ };
99
+ const fn = byName[section.renderer] ?? (() => "_No renderer_");
100
+ const title = section.title ?? section.id;
101
+ return `## ${title}\n\n${fn(doc)}`;
102
+ }
103
+ export function renderDocument(doc, view) {
104
+ return view.sections.map((s) => renderSection(doc, s)).join("\n\n").trim() + "\n";
105
+ }
@@ -0,0 +1,10 @@
1
+ import type { ModuleLifecycleContext } from "../../contracts/module-contract.js";
2
+ import type { DocumentationBatchResult, DocumentationGenerateOptions, DocumentationGenerateResult } from "./types.js";
3
+ type GenerateAllDocumentsArgs = {
4
+ options?: DocumentationGenerateOptions;
5
+ };
6
+ export declare function runGenerateAllDocuments(args: GenerateAllDocumentsArgs, ctx: ModuleLifecycleContext, generateOne: (args: {
7
+ documentType?: string;
8
+ options?: DocumentationGenerateOptions;
9
+ }, ctx: ModuleLifecycleContext) => Promise<DocumentationGenerateResult>): Promise<DocumentationBatchResult>;
10
+ export {};
@@ -0,0 +1,67 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readdir } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ import { listViewModels, loadViewModel } from "./view-models.js";
5
+ import { loadRuntimeConfig } from "./runtime-config.js";
6
+ export async function runGenerateAllDocuments(args, ctx, generateOne) {
7
+ const config = await loadRuntimeConfig(ctx.workspacePath);
8
+ const workspaceViewsRoot = resolve(ctx.workspacePath, "src/modules/documentation/views");
9
+ const useWorkspaceViews = existsSync(workspaceViewsRoot);
10
+ const workItems = [];
11
+ if (useWorkspaceViews) {
12
+ const viewFiles = await listViewModels(ctx.workspacePath);
13
+ for (const viewFile of viewFiles) {
14
+ const view = await loadViewModel(ctx.workspacePath, viewFile);
15
+ workItems.push({ documentType: view.target });
16
+ }
17
+ }
18
+ else {
19
+ const templatesDir = resolve(config.sourceRoot, config.templatesRoot);
20
+ const listTemplateFiles = async (dir, baseDir) => {
21
+ const entries = await readdir(dir, { withFileTypes: true });
22
+ const files = [];
23
+ for (const entry of entries) {
24
+ const absPath = resolve(dir, entry.name);
25
+ if (entry.isDirectory())
26
+ files.push(...(await listTemplateFiles(absPath, baseDir)));
27
+ if (entry.isFile() && entry.name.endsWith(".md"))
28
+ files.push(absPath.slice(baseDir.length + 1).split("\\").join("/"));
29
+ }
30
+ return files;
31
+ };
32
+ for (const templateFile of (await listTemplateFiles(templatesDir, templatesDir)).sort()) {
33
+ workItems.push({ documentType: templateFile });
34
+ }
35
+ }
36
+ const results = [];
37
+ let succeeded = 0;
38
+ let failed = 0;
39
+ let skipped = 0;
40
+ const batchOptions = {
41
+ ...args.options,
42
+ overwriteAi: args.options?.overwriteAi ?? false,
43
+ overwriteHuman: args.options?.overwriteHuman ?? true,
44
+ strict: args.options?.strict ?? false
45
+ };
46
+ for (const item of workItems) {
47
+ const result = await generateOne({ documentType: item.documentType, options: batchOptions }, ctx);
48
+ results.push(result);
49
+ if (!result.ok)
50
+ failed += 1;
51
+ else if (result.evidence.filesWritten.length > 0)
52
+ succeeded += 1;
53
+ else
54
+ skipped += 1;
55
+ }
56
+ return {
57
+ ok: failed === 0,
58
+ results,
59
+ summary: {
60
+ total: workItems.length,
61
+ succeeded,
62
+ failed,
63
+ skipped,
64
+ timestamp: new Date().toISOString()
65
+ }
66
+ };
67
+ }
@@ -0,0 +1,11 @@
1
+ export type DocumentationRuntimeConfig = {
2
+ aiRoot: string;
3
+ humanRoot: string;
4
+ templatesRoot: string;
5
+ instructionsRoot: string;
6
+ schemasRoot: string;
7
+ maxValidationAttempts: number;
8
+ sourceRoot: string;
9
+ };
10
+ export declare function isPathWithinRoot(path: string, root: string): boolean;
11
+ export declare function loadRuntimeConfig(workspacePath: string): Promise<DocumentationRuntimeConfig>;
@@ -0,0 +1,54 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { dirname, resolve, sep } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ export function isPathWithinRoot(path, root) {
6
+ return path === root || path.startsWith(`${root}${sep}`);
7
+ }
8
+ function parseDefaultValue(fileContent, key, fallback) {
9
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10
+ const regex = new RegExp(`\\\`${escaped}\\\`[^\\n]*default:\\s*\\\`([^\\\`]+)\\\``);
11
+ const match = fileContent.match(regex);
12
+ return match?.[1] ?? fallback;
13
+ }
14
+ export async function loadRuntimeConfig(workspacePath) {
15
+ const runtimeSourceRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
16
+ const sourceRoots = [workspacePath, runtimeSourceRoot];
17
+ let sourceRoot = workspacePath;
18
+ let configContent;
19
+ for (const candidateRoot of sourceRoots) {
20
+ const candidate = resolve(candidateRoot, "src/modules/documentation/config.md");
21
+ if (!existsSync(candidate))
22
+ continue;
23
+ configContent = await readFile(candidate, "utf8");
24
+ sourceRoot = candidateRoot;
25
+ break;
26
+ }
27
+ if (!configContent) {
28
+ return {
29
+ aiRoot: "/.ai",
30
+ humanRoot: "docs/maintainers",
31
+ templatesRoot: "src/modules/documentation/templates",
32
+ instructionsRoot: "src/modules/documentation/instructions",
33
+ schemasRoot: "src/modules/documentation/schemas",
34
+ maxValidationAttempts: 3,
35
+ sourceRoot
36
+ };
37
+ }
38
+ const aiRoot = parseDefaultValue(configContent, "sources.aiRoot", "/.ai");
39
+ const humanRoot = parseDefaultValue(configContent, "sources.humanRoot", "docs/maintainers");
40
+ const templatesRoot = parseDefaultValue(configContent, "sources.templatesRoot", "src/modules/documentation/templates");
41
+ const instructionsRoot = parseDefaultValue(configContent, "sources.instructionsRoot", "src/modules/documentation/instructions");
42
+ const schemasRoot = parseDefaultValue(configContent, "sources.schemasRoot", "src/modules/documentation/schemas");
43
+ const maxValidationAttemptsRaw = parseDefaultValue(configContent, "generation.maxValidationAttempts", "3");
44
+ const maxValidationAttempts = Number.parseInt(maxValidationAttemptsRaw, 10);
45
+ return {
46
+ aiRoot,
47
+ humanRoot,
48
+ templatesRoot,
49
+ instructionsRoot,
50
+ schemasRoot,
51
+ maxValidationAttempts: Number.isFinite(maxValidationAttempts) ? maxValidationAttempts : 3,
52
+ sourceRoot
53
+ };
54
+ }
@@ -0,0 +1,8 @@
1
+ import type { DocumentationConflict, DocumentationValidationIssue } from "./types.js";
2
+ export declare function resolveExpectedDocFamily(docType: string): "rules" | "runbook" | "workbook";
3
+ export declare function renderTemplate(templateContent: string): {
4
+ output: string;
5
+ unresolvedBlocks: boolean;
6
+ };
7
+ export declare function validateSectionCoverage(templateContent: string, output: string): DocumentationValidationIssue[];
8
+ export declare function detectConflicts(aiOutput: string, humanOutput: string): DocumentationConflict[];