@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.
- package/README.md +23 -9
- package/dist/cli/doctor-planning-issues.js +3 -22
- package/dist/cli/run-command.js +22 -38
- package/dist/cli.js +95 -4
- package/dist/contracts/command-manifest.d.ts +17 -0
- package/dist/contracts/command-manifest.js +1 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/module-contract.d.ts +12 -11
- package/dist/core/agent-instruction-surface.d.ts +33 -0
- package/dist/core/agent-instruction-surface.js +46 -0
- package/dist/core/config-cli.js +13 -17
- package/dist/core/config-metadata.js +61 -2
- package/dist/core/index.d.ts +4 -1
- package/dist/core/index.js +3 -0
- package/dist/core/module-command-router.js +19 -1
- package/dist/core/module-registry-resolve.d.ts +27 -0
- package/dist/core/module-registry-resolve.js +91 -0
- package/dist/core/module-registry.d.ts +14 -0
- package/dist/core/module-registry.js +57 -0
- package/dist/core/planning/build-plan-session-file.d.ts +29 -0
- package/dist/core/planning/build-plan-session-file.js +58 -0
- package/dist/core/planning/index.d.ts +17 -0
- package/dist/core/planning/index.js +15 -0
- package/dist/core/policy.js +18 -8
- package/dist/core/state/unified-state-db.d.ts +21 -0
- package/dist/core/state/unified-state-db.js +80 -0
- package/dist/core/workspace-kit-config.js +8 -0
- package/dist/modules/agent-behavior/builtins.d.ts +3 -0
- package/dist/modules/agent-behavior/builtins.js +71 -0
- package/dist/modules/agent-behavior/explain.d.ts +6 -0
- package/dist/modules/agent-behavior/explain.js +46 -0
- package/dist/modules/agent-behavior/index.d.ts +4 -0
- package/dist/modules/agent-behavior/index.js +461 -0
- package/dist/modules/agent-behavior/interview-session-file.d.ts +9 -0
- package/dist/modules/agent-behavior/interview-session-file.js +43 -0
- package/dist/modules/agent-behavior/interview.d.ts +13 -0
- package/dist/modules/agent-behavior/interview.js +88 -0
- package/dist/modules/agent-behavior/persistence.d.ts +6 -0
- package/dist/modules/agent-behavior/persistence.js +89 -0
- package/dist/modules/agent-behavior/store.d.ts +34 -0
- package/dist/modules/agent-behavior/store.js +119 -0
- package/dist/modules/agent-behavior/types.d.ts +28 -0
- package/dist/modules/agent-behavior/types.js +1 -0
- package/dist/modules/agent-behavior/validate.d.ts +11 -0
- package/dist/modules/agent-behavior/validate.js +123 -0
- package/dist/modules/approvals/index.js +54 -51
- package/dist/modules/approvals/policy-sensitive-commands.d.ts +4 -0
- package/dist/modules/approvals/policy-sensitive-commands.js +4 -0
- package/dist/modules/approvals/review-runtime.js +1 -2
- package/dist/modules/documentation/index.js +47 -45
- package/dist/modules/documentation/normalizer.d.ts +3 -0
- package/dist/modules/documentation/normalizer.js +171 -0
- package/dist/modules/documentation/parser.d.ts +7 -0
- package/dist/modules/documentation/parser.js +39 -0
- package/dist/modules/documentation/policy-sensitive-commands.d.ts +5 -0
- package/dist/modules/documentation/policy-sensitive-commands.js +8 -0
- package/dist/modules/documentation/renderer.d.ts +23 -0
- package/dist/modules/documentation/renderer.js +105 -0
- package/dist/modules/documentation/runtime-batch.d.ts +10 -0
- package/dist/modules/documentation/runtime-batch.js +67 -0
- package/dist/modules/documentation/runtime-config.d.ts +11 -0
- package/dist/modules/documentation/runtime-config.js +54 -0
- package/dist/modules/documentation/runtime-render-support.d.ts +8 -0
- package/dist/modules/documentation/runtime-render-support.js +36 -0
- package/dist/modules/documentation/runtime.js +22 -510
- package/dist/modules/documentation/types.d.ts +182 -0
- package/dist/modules/documentation/validator.d.ts +8 -0
- package/dist/modules/documentation/validator.js +234 -0
- package/dist/modules/documentation/view-models.d.ts +3 -0
- package/dist/modules/documentation/view-models.js +124 -0
- package/dist/modules/improvement/generate-recommendations-runtime.js +3 -3
- package/dist/modules/improvement/improvement-state.d.ts +2 -2
- package/dist/modules/improvement/improvement-state.js +52 -23
- package/dist/modules/improvement/index.js +140 -138
- package/dist/modules/improvement/ingest.d.ts +1 -1
- package/dist/modules/improvement/policy-sensitive-commands.d.ts +4 -0
- package/dist/modules/improvement/policy-sensitive-commands.js +7 -0
- package/dist/modules/index.d.ts +6 -0
- package/dist/modules/index.js +17 -0
- package/dist/modules/planning/index.js +384 -50
- package/dist/modules/planning/question-engine.d.ts +2 -0
- package/dist/modules/planning/question-engine.js +8 -1
- package/dist/modules/task-engine/doctor-planning-persistence.js +21 -13
- package/dist/modules/task-engine/index.d.ts +1 -2
- package/dist/modules/task-engine/index.js +1 -1143
- package/dist/modules/task-engine/migrate-task-persistence-runtime.js +31 -4
- package/dist/modules/task-engine/migrate-wishlist-intake-runtime.d.ts +2 -0
- package/dist/modules/task-engine/migrate-wishlist-intake-runtime.js +146 -0
- package/dist/modules/task-engine/planning-open.d.ts +2 -9
- package/dist/modules/task-engine/planning-open.js +4 -15
- package/dist/modules/task-engine/policy-sensitive-commands.d.ts +5 -0
- package/dist/modules/task-engine/policy-sensitive-commands.js +5 -0
- package/dist/modules/task-engine/sqlite-dual-planning.d.ts +11 -2
- package/dist/modules/task-engine/sqlite-dual-planning.js +134 -28
- package/dist/modules/task-engine/strict-task-validation.js +3 -0
- package/dist/modules/task-engine/suggestions.js +2 -1
- package/dist/modules/task-engine/task-engine-internal.d.ts +2 -0
- package/dist/modules/task-engine/task-engine-internal.js +1304 -0
- package/dist/modules/task-engine/task-type-validation.js +40 -0
- package/dist/modules/task-engine/wishlist-intake.d.ts +22 -0
- package/dist/modules/task-engine/wishlist-intake.js +180 -0
- package/dist/modules/task-engine/wishlist-validation.d.ts +4 -0
- package/dist/modules/task-engine/wishlist-validation.js +19 -0
- package/dist/modules/workspace-config/index.js +9 -11
- package/package.json +2 -2
- package/schemas/agent-behavior-profile.schema.json +52 -0
- package/schemas/task-engine-run-contracts.schema.json +80 -5
- package/src/modules/documentation/README.md +16 -25
- package/src/modules/documentation/RULES.md +9 -9
- package/src/modules/documentation/index.ts +54 -49
- package/src/modules/documentation/instructions/document-project.md +6 -6
- package/src/modules/documentation/instructions/generate-document.md +4 -4
- package/src/modules/documentation/normalizer.ts +187 -0
- package/src/modules/documentation/parser.ts +41 -0
- package/src/modules/documentation/policy-sensitive-commands.ts +8 -0
- package/src/modules/documentation/renderer.ts +121 -0
- package/src/modules/documentation/runtime-batch.ts +74 -0
- package/src/modules/documentation/runtime-config.ts +68 -0
- package/src/modules/documentation/runtime-render-support.ts +39 -0
- package/src/modules/documentation/runtime.ts +28 -600
- package/src/modules/documentation/schemas/documentation-schema.md +37 -54
- package/src/modules/documentation/types.ts +228 -0
- package/src/modules/documentation/validator.ts +247 -0
- package/src/modules/documentation/view-models.ts +132 -0
- package/src/modules/documentation/views/agents.view.yaml +18 -0
- package/src/modules/documentation/views/architecture.view.yaml +18 -0
- package/src/modules/documentation/views/principles.view.yaml +18 -0
- package/src/modules/documentation/views/readme.view.yaml +18 -0
- package/src/modules/documentation/views/releasing.view.yaml +18 -0
- package/src/modules/documentation/views/roadmap.view.yaml +18 -0
- package/src/modules/documentation/views/runbooks-consumer-cadence.view.yaml +18 -0
- package/src/modules/documentation/views/runbooks-parity-validation-flow.view.yaml +18 -0
- package/src/modules/documentation/views/runbooks-release-channels.view.yaml +18 -0
- package/src/modules/documentation/views/security.view.yaml +18 -0
- package/src/modules/documentation/views/support.view.yaml +18 -0
- package/src/modules/documentation/views/terms.view.yaml +18 -0
- package/src/modules/documentation/views/workbooks-phase2-config-policy-workbook.view.yaml +18 -0
- package/src/modules/documentation/views/workbooks-task-engine-workbook.view.yaml +18 -0
- package/src/modules/documentation/views/workbooks-transcript-automation-baseline.view.yaml +18 -0
- 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.
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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,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,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[];
|