@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
@@ -1,7 +1,10 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { UnifiedStateDb } from "../../core/state/unified-state-db.js";
4
+ import { getTaskPersistenceBackend, planningSqliteDatabaseRelativePath } from "../task-engine/planning-config.js";
3
5
  export const IMPROVEMENT_STATE_SCHEMA_VERSION = 2;
4
6
  const DEFAULT_REL = ".workspace-kit/improvement/state.json";
7
+ const IMPROVEMENT_MODULE_STATE_ID = "improvement";
5
8
  function statePath(workspacePath) {
6
9
  return path.join(workspacePath, DEFAULT_REL);
7
10
  }
@@ -31,43 +34,69 @@ function migrateFromV1(raw) {
31
34
  lastIngestRunAt: typeof raw.lastIngestRunAt === "string" ? raw.lastIngestRunAt : null
32
35
  };
33
36
  }
34
- export async function loadImprovementState(workspacePath) {
37
+ function normalizeLoadedDoc(raw) {
38
+ const ver = raw.schemaVersion;
39
+ if (ver === 1) {
40
+ return migrateFromV1(raw);
41
+ }
42
+ if (ver !== IMPROVEMENT_STATE_SCHEMA_VERSION) {
43
+ return emptyImprovementState();
44
+ }
45
+ const doc = raw;
46
+ return {
47
+ ...emptyImprovementState(),
48
+ ...doc,
49
+ transcriptLineCursors: doc.transcriptLineCursors ?? {},
50
+ transcriptRetryQueue: Array.isArray(doc.transcriptRetryQueue)
51
+ ? doc.transcriptRetryQueue.filter((e) => e !== null &&
52
+ typeof e === "object" &&
53
+ typeof e.relativePath === "string")
54
+ : []
55
+ };
56
+ }
57
+ async function loadImprovementStateFromFile(workspacePath) {
35
58
  const fp = statePath(workspacePath);
36
59
  try {
37
60
  const rawText = await fs.readFile(fp, "utf8");
38
61
  const raw = JSON.parse(rawText);
39
- const ver = raw.schemaVersion;
40
- if (ver === 1) {
41
- return migrateFromV1(raw);
42
- }
43
- if (ver !== IMPROVEMENT_STATE_SCHEMA_VERSION) {
44
- return emptyImprovementState();
45
- }
46
- const doc = raw;
47
- return {
48
- ...emptyImprovementState(),
49
- ...doc,
50
- transcriptLineCursors: doc.transcriptLineCursors ?? {},
51
- transcriptRetryQueue: Array.isArray(doc.transcriptRetryQueue)
52
- ? doc.transcriptRetryQueue.filter((e) => e !== null &&
53
- typeof e === "object" &&
54
- typeof e.relativePath === "string")
55
- : []
56
- };
62
+ return normalizeLoadedDoc(raw);
57
63
  }
58
64
  catch (e) {
59
65
  if (e.code === "ENOENT") {
60
- return emptyImprovementState();
66
+ return null;
61
67
  }
62
68
  throw e;
63
69
  }
64
70
  }
65
- export async function saveImprovementState(workspacePath, doc) {
66
- const fp = statePath(workspacePath);
67
- await fs.mkdir(path.dirname(fp), { recursive: true });
71
+ export async function loadImprovementState(workspacePath, effectiveConfig) {
72
+ if (getTaskPersistenceBackend(effectiveConfig) === "sqlite") {
73
+ const ctx = { workspacePath, effectiveConfig };
74
+ const unified = new UnifiedStateDb(workspacePath, planningSqliteDatabaseRelativePath(ctx));
75
+ const row = unified.getModuleState(IMPROVEMENT_MODULE_STATE_ID);
76
+ if (row?.state) {
77
+ return normalizeLoadedDoc(row.state);
78
+ }
79
+ const fromFile = await loadImprovementStateFromFile(workspacePath);
80
+ if (fromFile) {
81
+ return fromFile;
82
+ }
83
+ return emptyImprovementState();
84
+ }
85
+ const fromFile = await loadImprovementStateFromFile(workspacePath);
86
+ return fromFile ?? emptyImprovementState();
87
+ }
88
+ export async function saveImprovementState(workspacePath, doc, effectiveConfig) {
68
89
  const out = {
69
90
  ...doc,
70
91
  schemaVersion: IMPROVEMENT_STATE_SCHEMA_VERSION
71
92
  };
93
+ if (getTaskPersistenceBackend(effectiveConfig) === "sqlite") {
94
+ const ctx = { workspacePath, effectiveConfig };
95
+ const unified = new UnifiedStateDb(workspacePath, planningSqliteDatabaseRelativePath(ctx));
96
+ unified.setModuleState(IMPROVEMENT_MODULE_STATE_ID, out.schemaVersion, out);
97
+ return;
98
+ }
99
+ const fp = statePath(workspacePath);
100
+ await fs.mkdir(path.dirname(fp), { recursive: true });
72
101
  await fs.writeFile(fp, `${JSON.stringify(out, null, 2)}\n`, "utf8");
73
102
  }
@@ -8,19 +8,16 @@ export const improvementModule = {
8
8
  id: "improvement",
9
9
  version: "0.8.0",
10
10
  contractVersion: "1",
11
+ stateSchema: 1,
11
12
  capabilities: ["improvement"],
12
13
  dependsOn: ["task-engine", "planning"],
14
+ optionalPeers: ["documentation"],
13
15
  enabledByDefault: true,
14
16
  config: {
15
17
  path: "src/modules/improvement/config.md",
16
18
  format: "md",
17
19
  description: "Improvement module configuration contract."
18
20
  },
19
- state: {
20
- path: "src/modules/improvement/state.md",
21
- format: "md",
22
- description: "Improvement module recommendation state contract."
23
- },
24
21
  instructions: {
25
22
  directory: "src/modules/improvement/instructions",
26
23
  entries: [
@@ -54,153 +51,158 @@ export const improvementModule = {
54
51
  },
55
52
  async onCommand(command, ctx) {
56
53
  const args = command.args ?? {};
57
- if (command.name === "generate-recommendations") {
58
- const transcriptsRoot = typeof args.transcriptsRoot === "string" ? args.transcriptsRoot : undefined;
59
- const fromTag = typeof args.fromTag === "string" ? args.fromTag : undefined;
60
- const toTag = typeof args.toTag === "string" ? args.toTag : undefined;
61
- const syncArgs = {
62
- sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
63
- archivePath: transcriptsRoot
64
- };
65
- try {
66
- const state = await loadImprovementState(ctx.workspacePath);
67
- const sync = await runSyncTranscripts(ctx, syncArgs, state);
68
- state.lastSyncRunAt = new Date().toISOString();
69
- await saveImprovementState(ctx.workspacePath, state);
70
- const result = await runGenerateRecommendations(ctx, {
71
- transcriptsRoot: sync.archivePath,
72
- fromTag,
73
- toTag
74
- });
75
- return {
76
- ok: true,
77
- code: "recommendations-generated",
78
- message: `After sync (${sync.copied} copied): created ${result.created.length} improvement task(s); skipped ${result.skipped} duplicate(s)`,
79
- data: { sync, ...result }
80
- };
81
- }
82
- catch (e) {
83
- const msg = e instanceof Error ? e.message : String(e);
84
- return { ok: false, code: "generate-failed", message: msg };
85
- }
86
- }
87
- if (command.name === "sync-transcripts") {
88
- const syncArgs = {
89
- sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
90
- archivePath: typeof args.archivePath === "string" ? args.archivePath : undefined
91
- };
92
- try {
93
- const state = await loadImprovementState(ctx.workspacePath);
94
- const sync = await runSyncTranscripts(ctx, syncArgs, state);
95
- state.lastSyncRunAt = new Date().toISOString();
96
- await saveImprovementState(ctx.workspacePath, state);
97
- return {
98
- ok: true,
99
- code: "transcripts-synced",
100
- message: `Copied ${sync.copied} transcript file(s); skipped ${sync.skippedExisting} existing`,
101
- data: sync
54
+ const handlers = {
55
+ "generate-recommendations": async () => {
56
+ const transcriptsRoot = typeof args.transcriptsRoot === "string" ? args.transcriptsRoot : undefined;
57
+ const fromTag = typeof args.fromTag === "string" ? args.fromTag : undefined;
58
+ const toTag = typeof args.toTag === "string" ? args.toTag : undefined;
59
+ const syncArgs = {
60
+ sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
61
+ archivePath: transcriptsRoot
102
62
  };
103
- }
104
- catch (e) {
105
- const msg = e instanceof Error ? e.message : String(e);
106
- return { ok: false, code: "sync-failed", message: msg };
107
- }
108
- }
109
- if (command.name === "ingest-transcripts") {
110
- const syncArgs = {
111
- sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
112
- archivePath: typeof args.archivePath === "string" ? args.archivePath : undefined
113
- };
114
- const now = new Date();
115
- try {
116
- const state = await loadImprovementState(ctx.workspacePath);
117
- const sync = await runSyncTranscripts(ctx, syncArgs, state);
118
- const cfg = resolveImprovementTranscriptConfig(ctx, syncArgs);
119
- const cadenceDecision = resolveCadenceDecision(now, state.lastIngestRunAt, cfg.minIntervalMinutes, sync.copied, cfg.skipIfNoNewTranscripts);
120
- state.lastSyncRunAt = now.toISOString();
121
- const generate = cadenceDecision.shouldRunGenerate || args.forceGenerate === true || args.runGenerate === true;
122
- let recommendations = null;
123
- if (generate) {
124
- recommendations = await runGenerateRecommendations(ctx, {
125
- transcriptsRoot: sync.archivePath
63
+ try {
64
+ const state = await loadImprovementState(ctx.workspacePath, ctx.effectiveConfig);
65
+ const sync = await runSyncTranscripts(ctx, syncArgs, state);
66
+ state.lastSyncRunAt = new Date().toISOString();
67
+ await saveImprovementState(ctx.workspacePath, state, ctx.effectiveConfig);
68
+ const result = await runGenerateRecommendations(ctx, {
69
+ transcriptsRoot: sync.archivePath,
70
+ fromTag,
71
+ toTag
126
72
  });
127
- state.lastIngestRunAt = now.toISOString();
73
+ return {
74
+ ok: true,
75
+ code: "recommendations-generated",
76
+ message: `After sync (${sync.copied} copied): created ${result.created.length} improvement task(s); skipped ${result.skipped} duplicate(s)`,
77
+ data: { sync, ...result }
78
+ };
79
+ }
80
+ catch (e) {
81
+ const msg = e instanceof Error ? e.message : String(e);
82
+ return { ok: false, code: "generate-failed", message: msg };
128
83
  }
129
- await saveImprovementState(ctx.workspacePath, state);
130
- const status = generate ? "generated" : "skipped";
84
+ },
85
+ "sync-transcripts": async () => {
86
+ const syncArgs = {
87
+ sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
88
+ archivePath: typeof args.archivePath === "string" ? args.archivePath : undefined
89
+ };
90
+ try {
91
+ const state = await loadImprovementState(ctx.workspacePath, ctx.effectiveConfig);
92
+ const sync = await runSyncTranscripts(ctx, syncArgs, state);
93
+ state.lastSyncRunAt = new Date().toISOString();
94
+ await saveImprovementState(ctx.workspacePath, state, ctx.effectiveConfig);
95
+ return {
96
+ ok: true,
97
+ code: "transcripts-synced",
98
+ message: `Copied ${sync.copied} transcript file(s); skipped ${sync.skippedExisting} existing`,
99
+ data: sync
100
+ };
101
+ }
102
+ catch (e) {
103
+ const msg = e instanceof Error ? e.message : String(e);
104
+ return { ok: false, code: "sync-failed", message: msg };
105
+ }
106
+ },
107
+ "ingest-transcripts": async () => {
108
+ const syncArgs = {
109
+ sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
110
+ archivePath: typeof args.archivePath === "string" ? args.archivePath : undefined
111
+ };
112
+ const now = new Date();
113
+ try {
114
+ const state = await loadImprovementState(ctx.workspacePath, ctx.effectiveConfig);
115
+ const sync = await runSyncTranscripts(ctx, syncArgs, state);
116
+ const cfg = resolveImprovementTranscriptConfig(ctx, syncArgs);
117
+ const cadenceDecision = resolveCadenceDecision(now, state.lastIngestRunAt, cfg.minIntervalMinutes, sync.copied, cfg.skipIfNoNewTranscripts);
118
+ state.lastSyncRunAt = now.toISOString();
119
+ const generate = cadenceDecision.shouldRunGenerate || args.forceGenerate === true || args.runGenerate === true;
120
+ let recommendations = null;
121
+ if (generate) {
122
+ recommendations = await runGenerateRecommendations(ctx, {
123
+ transcriptsRoot: sync.archivePath
124
+ });
125
+ state.lastIngestRunAt = now.toISOString();
126
+ }
127
+ await saveImprovementState(ctx.workspacePath, state, ctx.effectiveConfig);
128
+ const status = generate ? "generated" : "skipped";
129
+ return {
130
+ ok: true,
131
+ code: "transcripts-ingested",
132
+ message: `Ingest ${status}; sync copied ${sync.copied} file(s)`,
133
+ data: {
134
+ sync,
135
+ cadence: {
136
+ minIntervalMinutes: cfg.minIntervalMinutes,
137
+ skipIfNoNewTranscripts: cfg.skipIfNoNewTranscripts,
138
+ decision: cadenceDecision.reason
139
+ },
140
+ generatedRecommendations: recommendations
141
+ }
142
+ };
143
+ }
144
+ catch (e) {
145
+ const msg = e instanceof Error ? e.message : String(e);
146
+ return { ok: false, code: "ingest-failed", message: msg };
147
+ }
148
+ },
149
+ "transcript-automation-status": async () => {
150
+ const syncArgs = {
151
+ sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
152
+ archivePath: typeof args.archivePath === "string" ? args.archivePath : undefined
153
+ };
154
+ const state = await loadImprovementState(ctx.workspacePath, ctx.effectiveConfig);
155
+ const cfg = resolveImprovementTranscriptConfig(ctx, syncArgs);
131
156
  return {
132
157
  ok: true,
133
- code: "transcripts-ingested",
134
- message: `Ingest ${status}; sync copied ${sync.copied} file(s)`,
158
+ code: "transcript-automation-status",
159
+ message: "Transcript automation status",
135
160
  data: {
136
- sync,
161
+ schemaVersion: 1,
162
+ lastSyncRunAt: state.lastSyncRunAt,
163
+ lastIngestRunAt: state.lastIngestRunAt,
137
164
  cadence: {
138
165
  minIntervalMinutes: cfg.minIntervalMinutes,
139
166
  skipIfNoNewTranscripts: cfg.skipIfNoNewTranscripts,
140
- decision: cadenceDecision.reason
167
+ maxRecommendationCandidatesPerRun: getMaxRecommendationCandidatesPerRun(ctx)
141
168
  },
142
- generatedRecommendations: recommendations
143
- }
144
- };
145
- }
146
- catch (e) {
147
- const msg = e instanceof Error ? e.message : String(e);
148
- return { ok: false, code: "ingest-failed", message: msg };
149
- }
150
- }
151
- if (command.name === "transcript-automation-status") {
152
- const syncArgs = {
153
- sourcePath: typeof args.sourcePath === "string" ? args.sourcePath : undefined,
154
- archivePath: typeof args.archivePath === "string" ? args.archivePath : undefined
155
- };
156
- const state = await loadImprovementState(ctx.workspacePath);
157
- const cfg = resolveImprovementTranscriptConfig(ctx, syncArgs);
158
- return {
159
- ok: true,
160
- code: "transcript-automation-status",
161
- message: "Transcript automation status",
162
- data: {
163
- schemaVersion: 1,
164
- lastSyncRunAt: state.lastSyncRunAt,
165
- lastIngestRunAt: state.lastIngestRunAt,
166
- cadence: {
167
- minIntervalMinutes: cfg.minIntervalMinutes,
168
- skipIfNoNewTranscripts: cfg.skipIfNoNewTranscripts,
169
- maxRecommendationCandidatesPerRun: getMaxRecommendationCandidatesPerRun(ctx)
170
- },
171
- transcripts: {
172
- sourcePath: cfg.sourcePath || null,
173
- archivePath: cfg.archivePath,
174
- discoveryPaths: cfg.discoveryPaths,
175
- budgets: {
176
- maxFilesPerSync: cfg.maxFilesPerSync,
177
- maxBytesPerFile: cfg.maxBytesPerFile,
178
- maxTotalScanBytes: cfg.maxTotalScanBytes
169
+ transcripts: {
170
+ sourcePath: cfg.sourcePath || null,
171
+ archivePath: cfg.archivePath,
172
+ discoveryPaths: cfg.discoveryPaths,
173
+ budgets: {
174
+ maxFilesPerSync: cfg.maxFilesPerSync,
175
+ maxBytesPerFile: cfg.maxBytesPerFile,
176
+ maxTotalScanBytes: cfg.maxTotalScanBytes
177
+ }
178
+ },
179
+ retryQueue: {
180
+ pending: state.transcriptRetryQueue?.length ?? 0,
181
+ entries: state.transcriptRetryQueue ?? []
182
+ },
183
+ policySession: {
184
+ sessionId: resolveSessionId(process.env)
179
185
  }
180
- },
181
- retryQueue: {
182
- pending: state.transcriptRetryQueue?.length ?? 0,
183
- entries: state.transcriptRetryQueue ?? []
184
- },
185
- policySession: {
186
- sessionId: resolveSessionId(process.env)
187
186
  }
187
+ };
188
+ },
189
+ "query-lineage": async () => {
190
+ const taskId = typeof args.taskId === "string" ? args.taskId.trim() : "";
191
+ if (!taskId) {
192
+ return { ok: false, code: "invalid-args", message: "query-lineage requires taskId" };
188
193
  }
189
- };
190
- }
191
- if (command.name === "query-lineage") {
192
- const taskId = typeof args.taskId === "string" ? args.taskId.trim() : "";
193
- if (!taskId) {
194
- return { ok: false, code: "invalid-args", message: "query-lineage requires taskId" };
194
+ const chain = await queryLineageChain(ctx.workspacePath, taskId);
195
+ return {
196
+ ok: true,
197
+ code: "lineage-queried",
198
+ message: `${chain.events.length} lineage event(s) for ${taskId}`,
199
+ data: chain
200
+ };
195
201
  }
196
- const chain = await queryLineageChain(ctx.workspacePath, taskId);
197
- return {
198
- ok: true,
199
- code: "lineage-queried",
200
- message: `${chain.events.length} lineage event(s) for ${taskId}`,
201
- data: chain
202
- };
203
- }
202
+ };
203
+ const handler = handlers[command.name];
204
+ if (handler)
205
+ return handler();
204
206
  return {
205
207
  ok: false,
206
208
  code: "unsupported-command",
@@ -1,4 +1,4 @@
1
- import type { TransitionEvidence } from "../task-engine/types.js";
1
+ import type { TransitionEvidence } from "../../core/planning/index.js";
2
2
  import type { EvidenceKind, ConfidenceSignals } from "./confidence.js";
3
3
  import { computeHeuristicConfidence } from "./confidence.js";
4
4
  import type { ImprovementStateDocument } from "./improvement-state.js";
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Policy-gated `workspace-kit run` commands owned by the improvement module.
3
+ */
4
+ export declare const IMPROVEMENT_POLICY_COMMAND_NAMES: readonly [readonly ["generate-recommendations", "improvement.generate-recommendations"], readonly ["ingest-transcripts", "improvement.ingest-transcripts"]];
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Policy-gated `workspace-kit run` commands owned by the improvement module.
3
+ */
4
+ export const IMPROVEMENT_POLICY_COMMAND_NAMES = [
5
+ ["generate-recommendations", "improvement.generate-recommendations"],
6
+ ["ingest-transcripts", "improvement.ingest-transcripts"]
7
+ ];
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Default module bundle + selective re-exports. Policy: see `docs/maintainers/module-build-guide.md` (Barrel export policy).
3
+ */
4
+ import type { WorkflowModule } from "../contracts/module-contract.js";
5
+ export declare const defaultRegistryModules: WorkflowModule[];
6
+ export { agentBehaviorModule, BUILTIN_PROFILES, DEFAULT_BUILTIN_PROFILE_ID, mergeDimensions, validateBehaviorProfile } from "./agent-behavior/index.js";
1
7
  export { approvalsModule } from "./approvals/index.js";
2
8
  export { documentationModule } from "./documentation/index.js";
3
9
  export type { DocumentationConflict, DocumentationGenerateOptions, DocumentationGenerateResult, DocumentationGenerationEvidence, DocumentationValidationIssue } from "./documentation/types.js";
@@ -1,3 +1,20 @@
1
+ import { agentBehaviorModule } from "./agent-behavior/index.js";
2
+ import { approvalsModule } from "./approvals/index.js";
3
+ import { documentationModule } from "./documentation/index.js";
4
+ import { improvementModule } from "./improvement/index.js";
5
+ import { planningModule } from "./planning/index.js";
6
+ import { taskEngineModule } from "./task-engine/index.js";
7
+ import { workspaceConfigModule } from "./workspace-config/index.js";
8
+ export const defaultRegistryModules = [
9
+ workspaceConfigModule,
10
+ documentationModule,
11
+ agentBehaviorModule,
12
+ taskEngineModule,
13
+ approvalsModule,
14
+ planningModule,
15
+ improvementModule
16
+ ];
17
+ export { agentBehaviorModule, BUILTIN_PROFILES, DEFAULT_BUILTIN_PROFILE_ID, mergeDimensions, validateBehaviorProfile } from "./agent-behavior/index.js";
1
18
  export { approvalsModule } from "./approvals/index.js";
2
19
  export { documentationModule } from "./documentation/index.js";
3
20
  export { improvementModule } from "./improvement/index.js";
@@ -0,0 +1,19 @@
1
+ import type { PlanningWorkflowType } from "./types.js";
2
+ export type PlanningWishlistArtifact = {
3
+ schemaVersion: 1;
4
+ planningType: PlanningWorkflowType;
5
+ generatedAt: string;
6
+ goals: string[];
7
+ approach: string;
8
+ majorTechnicalDecisions: string[];
9
+ candidateFeaturesOrChanges: string[];
10
+ assumptions: string[];
11
+ openQuestions: string[];
12
+ risksAndConstraints: string[];
13
+ sourceAnswers: Record<string, string>;
14
+ };
15
+ export declare function composePlanningWishlistArtifact(args: {
16
+ planningType: PlanningWorkflowType;
17
+ answers: Record<string, unknown>;
18
+ unresolvedCriticalQuestionIds: string[];
19
+ }): PlanningWishlistArtifact;
@@ -0,0 +1,72 @@
1
+ function answer(answers, key, fallback) {
2
+ const value = answers[key];
3
+ if (typeof value !== "string" || value.trim().length === 0) {
4
+ return fallback;
5
+ }
6
+ return value.trim();
7
+ }
8
+ function list(answers, key) {
9
+ const value = answers[key];
10
+ if (Array.isArray(value)) {
11
+ return value.filter((x) => typeof x === "string" && x.trim().length > 0).map((x) => x.trim());
12
+ }
13
+ if (typeof value === "string" && value.trim().length > 0) {
14
+ return [value.trim()];
15
+ }
16
+ return [];
17
+ }
18
+ export function composePlanningWishlistArtifact(args) {
19
+ const { planningType, answers, unresolvedCriticalQuestionIds } = args;
20
+ const sourceAnswers = {};
21
+ for (const [key, value] of Object.entries(answers)) {
22
+ if (typeof value === "string" && value.trim().length > 0) {
23
+ sourceAnswers[key] = value.trim();
24
+ }
25
+ }
26
+ const goals = list(answers, "goals");
27
+ if (goals.length === 0) {
28
+ const inferredGoal = answer(answers, "goal", "") ||
29
+ answer(answers, "featureGoal", "") ||
30
+ answer(answers, "changeGoal", "");
31
+ if (inferredGoal)
32
+ goals.push(inferredGoal);
33
+ }
34
+ const candidate = list(answers, "candidateFeaturesOrChanges");
35
+ if (candidate.length === 0) {
36
+ const inferred = answer(answers, "scope", "");
37
+ if (inferred)
38
+ candidate.push(inferred);
39
+ }
40
+ const majorTechnicalDecisions = list(answers, "majorTechnicalDecisions");
41
+ const decisionRationale = answer(answers, "decisionRationale", "");
42
+ if (decisionRationale && majorTechnicalDecisions.length === 0) {
43
+ majorTechnicalDecisions.push(decisionRationale);
44
+ }
45
+ const assumptions = list(answers, "assumptions");
46
+ const openQuestions = [
47
+ ...list(answers, "openQuestions"),
48
+ ...unresolvedCriticalQuestionIds.map((id) => `Unresolved critical question: ${id}`)
49
+ ];
50
+ const risksAndConstraints = list(answers, "risksAndConstraints");
51
+ const constraints = answer(answers, "constraints", "");
52
+ if (constraints) {
53
+ risksAndConstraints.push(`Constraint: ${constraints}`);
54
+ }
55
+ const riskPriority = answer(answers, "riskPriority", "");
56
+ if (riskPriority) {
57
+ risksAndConstraints.push(`Risk priority: ${riskPriority}`);
58
+ }
59
+ return {
60
+ schemaVersion: 1,
61
+ planningType,
62
+ generatedAt: new Date().toISOString(),
63
+ goals,
64
+ approach: answer(answers, "approach", "Context-driven workflow guided by planning rules."),
65
+ majorTechnicalDecisions,
66
+ candidateFeaturesOrChanges: candidate,
67
+ assumptions,
68
+ openQuestions,
69
+ risksAndConstraints,
70
+ sourceAnswers
71
+ };
72
+ }