agentplane 0.2.25 → 0.3.1

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 (221) hide show
  1. package/README.md +3 -1
  2. package/assets/AGENTS.md +123 -526
  3. package/assets/agents/UPGRADER.json +10 -9
  4. package/assets/framework.manifest.json +112 -7
  5. package/assets/policy/check-routing.mjs +180 -0
  6. package/assets/policy/dod.code.md +25 -0
  7. package/assets/policy/dod.core.md +32 -0
  8. package/assets/policy/dod.docs.md +32 -0
  9. package/assets/policy/examples/migration-note.md +6 -0
  10. package/assets/policy/examples/pr-note.md +16 -0
  11. package/assets/policy/examples/unit-test-pattern.md +19 -0
  12. package/assets/policy/governance.md +37 -0
  13. package/assets/policy/incidents.md +36 -0
  14. package/assets/policy/security.must.md +7 -0
  15. package/assets/policy/workflow.branch_pr.md +34 -0
  16. package/assets/policy/workflow.direct.md +46 -0
  17. package/assets/policy/workflow.md +9 -0
  18. package/assets/policy/workflow.release.md +31 -0
  19. package/assets/policy/workflow.upgrade.md +20 -0
  20. package/bin/agentplane.js +47 -57
  21. package/bin/dist-guard.js +124 -0
  22. package/dist/.build-manifest.json +11 -0
  23. package/dist/agents/agents-template.d.ts +7 -0
  24. package/dist/agents/agents-template.d.ts.map +1 -1
  25. package/dist/agents/agents-template.js +41 -2
  26. package/dist/backends/task-backend/local-backend.d.ts +2 -0
  27. package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
  28. package/dist/backends/task-backend/local-backend.js +12 -1
  29. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
  30. package/dist/backends/task-backend/redmine/mapping.js +26 -1
  31. package/dist/backends/task-backend/redmine-backend.d.ts +4 -0
  32. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
  33. package/dist/backends/task-backend/redmine-backend.js +92 -9
  34. package/dist/backends/task-backend/shared/types.d.ts +1 -0
  35. package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
  36. package/dist/backends/task-index.d.ts.map +1 -1
  37. package/dist/backends/task-index.js +8 -1
  38. package/dist/cli/command-guide.d.ts.map +1 -1
  39. package/dist/cli/command-guide.js +39 -17
  40. package/dist/cli/command-snippets.d.ts +24 -0
  41. package/dist/cli/command-snippets.d.ts.map +1 -0
  42. package/dist/cli/command-snippets.js +23 -0
  43. package/dist/cli/reason-codes.d.ts +9 -0
  44. package/dist/cli/reason-codes.d.ts.map +1 -0
  45. package/dist/cli/reason-codes.js +79 -0
  46. package/dist/cli/recipes-bundled.d.ts +1 -0
  47. package/dist/cli/recipes-bundled.d.ts.map +1 -1
  48. package/dist/cli/recipes-bundled.js +4 -1
  49. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  50. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  51. package/dist/cli/run-cli/command-catalog.js +40 -1
  52. package/dist/cli/run-cli/commands/config.d.ts +5 -0
  53. package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
  54. package/dist/cli/run-cli/commands/config.js +86 -1
  55. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  56. package/dist/cli/run-cli/commands/core.js +57 -2
  57. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
  58. package/dist/cli/run-cli/commands/ide.js +8 -3
  59. package/dist/cli/run-cli/commands/init/recipes.d.ts +5 -1
  60. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
  61. package/dist/cli/run-cli/commands/init/recipes.js +24 -4
  62. package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
  63. package/dist/cli/run-cli/commands/init/ui.js +1 -2
  64. package/dist/cli/run-cli/commands/init/write-agents.d.ts +2 -0
  65. package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
  66. package/dist/cli/run-cli/commands/init/write-agents.js +24 -5
  67. package/dist/cli/run-cli/commands/init/write-workflow.d.ts +12 -0
  68. package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -0
  69. package/dist/cli/run-cli/commands/init/write-workflow.js +58 -0
  70. package/dist/cli/run-cli/commands/init.d.ts +4 -1
  71. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  72. package/dist/cli/run-cli/commands/init.js +126 -48
  73. package/dist/cli/run-cli.d.ts.map +1 -1
  74. package/dist/cli/run-cli.js +195 -8
  75. package/dist/commands/backend/sync.command.d.ts.map +1 -1
  76. package/dist/commands/backend/sync.command.js +7 -6
  77. package/dist/commands/backend.d.ts.map +1 -1
  78. package/dist/commands/backend.js +2 -0
  79. package/dist/commands/doctor.run.d.ts.map +1 -1
  80. package/dist/commands/doctor.run.js +107 -16
  81. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  82. package/dist/commands/guard/impl/commands.js +12 -6
  83. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  84. package/dist/commands/recipes/impl/commands/install.js +36 -13
  85. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
  86. package/dist/commands/recipes/impl/scenario.js +25 -0
  87. package/dist/commands/recipes/impl/types.d.ts +4 -0
  88. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  89. package/dist/commands/release/apply.command.d.ts.map +1 -1
  90. package/dist/commands/release/apply.command.js +9 -4
  91. package/dist/commands/release/plan.command.d.ts.map +1 -1
  92. package/dist/commands/release/plan.command.js +9 -3
  93. package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
  94. package/dist/commands/scenario/impl/commands.js +74 -3
  95. package/dist/commands/scenario/impl/report.d.ts +8 -0
  96. package/dist/commands/scenario/impl/report.d.ts.map +1 -1
  97. package/dist/commands/scenario/impl/report.js +1 -0
  98. package/dist/commands/shared/reconcile-check.d.ts +7 -0
  99. package/dist/commands/shared/reconcile-check.d.ts.map +1 -0
  100. package/dist/commands/shared/reconcile-check.js +60 -0
  101. package/dist/commands/sync.command.d.ts.map +1 -1
  102. package/dist/commands/sync.command.js +9 -2
  103. package/dist/commands/task/add.d.ts.map +1 -1
  104. package/dist/commands/task/add.js +32 -0
  105. package/dist/commands/task/doc.command.d.ts.map +1 -1
  106. package/dist/commands/task/doc.command.js +1 -0
  107. package/dist/commands/task/finish.d.ts.map +1 -1
  108. package/dist/commands/task/finish.js +11 -1
  109. package/dist/commands/task/list.d.ts.map +1 -1
  110. package/dist/commands/task/list.js +2 -1
  111. package/dist/commands/task/list.spec.d.ts.map +1 -1
  112. package/dist/commands/task/list.spec.js +7 -0
  113. package/dist/commands/task/new.d.ts.map +1 -1
  114. package/dist/commands/task/new.js +41 -4
  115. package/dist/commands/task/next.d.ts.map +1 -1
  116. package/dist/commands/task/next.js +2 -1
  117. package/dist/commands/task/next.spec.d.ts.map +1 -1
  118. package/dist/commands/task/next.spec.js +7 -0
  119. package/dist/commands/task/plan.d.ts.map +1 -1
  120. package/dist/commands/task/plan.js +7 -1
  121. package/dist/commands/task/search.d.ts.map +1 -1
  122. package/dist/commands/task/search.js +2 -1
  123. package/dist/commands/task/search.spec.d.ts.map +1 -1
  124. package/dist/commands/task/search.spec.js +7 -0
  125. package/dist/commands/task/shared.d.ts +14 -0
  126. package/dist/commands/task/shared.d.ts.map +1 -1
  127. package/dist/commands/task/shared.js +58 -1
  128. package/dist/commands/task/start-ready.js +1 -1
  129. package/dist/commands/task/verify-record.d.ts.map +1 -1
  130. package/dist/commands/task/verify-record.js +2 -0
  131. package/dist/commands/upgrade.command.d.ts.map +1 -1
  132. package/dist/commands/upgrade.command.js +2 -2
  133. package/dist/commands/upgrade.d.ts.map +1 -1
  134. package/dist/commands/upgrade.js +263 -294
  135. package/dist/commands/workflow-build.command.d.ts +8 -0
  136. package/dist/commands/workflow-build.command.d.ts.map +1 -0
  137. package/dist/commands/workflow-build.command.js +103 -0
  138. package/dist/commands/workflow-playbook.command.d.ts +10 -0
  139. package/dist/commands/workflow-playbook.command.d.ts.map +1 -0
  140. package/dist/commands/workflow-playbook.command.js +173 -0
  141. package/dist/commands/workflow-restore.command.d.ts +5 -0
  142. package/dist/commands/workflow-restore.command.d.ts.map +1 -0
  143. package/dist/commands/workflow-restore.command.js +30 -0
  144. package/dist/commands/workflow.command.d.ts +6 -0
  145. package/dist/commands/workflow.command.d.ts.map +1 -0
  146. package/dist/commands/workflow.command.js +36 -0
  147. package/dist/harness/dynamic-tool-contract.d.ts +29 -0
  148. package/dist/harness/dynamic-tool-contract.d.ts.map +1 -0
  149. package/dist/harness/dynamic-tool-contract.js +86 -0
  150. package/dist/harness/hooks-lifecycle.d.ts +27 -0
  151. package/dist/harness/hooks-lifecycle.d.ts.map +1 -0
  152. package/dist/harness/hooks-lifecycle.js +67 -0
  153. package/dist/harness/index.d.ts +9 -0
  154. package/dist/harness/index.d.ts.map +1 -0
  155. package/dist/harness/index.js +8 -0
  156. package/dist/harness/reconcile.d.ts +37 -0
  157. package/dist/harness/reconcile.d.ts.map +1 -0
  158. package/dist/harness/reconcile.js +42 -0
  159. package/dist/harness/retry-policy.d.ts +31 -0
  160. package/dist/harness/retry-policy.d.ts.map +1 -0
  161. package/dist/harness/retry-policy.js +33 -0
  162. package/dist/harness/scheduler.d.ts +18 -0
  163. package/dist/harness/scheduler.d.ts.map +1 -0
  164. package/dist/harness/scheduler.js +55 -0
  165. package/dist/harness/state-machine.d.ts +17 -0
  166. package/dist/harness/state-machine.d.ts.map +1 -0
  167. package/dist/harness/state-machine.js +70 -0
  168. package/dist/harness/token-accounting.d.ts +19 -0
  169. package/dist/harness/token-accounting.d.ts.map +1 -0
  170. package/dist/harness/token-accounting.js +77 -0
  171. package/dist/harness/workspace-safety.d.ts +14 -0
  172. package/dist/harness/workspace-safety.d.ts.map +1 -0
  173. package/dist/harness/workspace-safety.js +62 -0
  174. package/dist/recipes/bundled-recipes.d.ts +4 -0
  175. package/dist/recipes/bundled-recipes.d.ts.map +1 -1
  176. package/dist/recipes/bundled-recipes.js +11 -0
  177. package/dist/shared/errors.d.ts +6 -0
  178. package/dist/shared/errors.d.ts.map +1 -1
  179. package/dist/shared/errors.js +1 -0
  180. package/dist/shared/policy-gateway.d.ts +15 -0
  181. package/dist/shared/policy-gateway.d.ts.map +1 -0
  182. package/dist/shared/policy-gateway.js +49 -0
  183. package/dist/shared/protected-paths.d.ts.map +1 -1
  184. package/dist/shared/protected-paths.js +1 -0
  185. package/dist/shared/runtime-artifacts.d.ts +2 -2
  186. package/dist/shared/runtime-artifacts.d.ts.map +1 -1
  187. package/dist/shared/runtime-artifacts.js +4 -0
  188. package/dist/workflow-runtime/build.d.ts +4 -0
  189. package/dist/workflow-runtime/build.d.ts.map +1 -0
  190. package/dist/workflow-runtime/build.js +126 -0
  191. package/dist/workflow-runtime/enforcement.d.ts +3 -0
  192. package/dist/workflow-runtime/enforcement.d.ts.map +1 -0
  193. package/dist/workflow-runtime/enforcement.js +10 -0
  194. package/dist/workflow-runtime/file-ops.d.ts +11 -0
  195. package/dist/workflow-runtime/file-ops.d.ts.map +1 -0
  196. package/dist/workflow-runtime/file-ops.js +248 -0
  197. package/dist/workflow-runtime/fix.d.ts +9 -0
  198. package/dist/workflow-runtime/fix.d.ts.map +1 -0
  199. package/dist/workflow-runtime/fix.js +107 -0
  200. package/dist/workflow-runtime/index.d.ts +11 -0
  201. package/dist/workflow-runtime/index.d.ts.map +1 -0
  202. package/dist/workflow-runtime/index.js +10 -0
  203. package/dist/workflow-runtime/markdown.d.ts +10 -0
  204. package/dist/workflow-runtime/markdown.d.ts.map +1 -0
  205. package/dist/workflow-runtime/markdown.js +147 -0
  206. package/dist/workflow-runtime/observability.d.ts +12 -0
  207. package/dist/workflow-runtime/observability.d.ts.map +1 -0
  208. package/dist/workflow-runtime/observability.js +14 -0
  209. package/dist/workflow-runtime/paths.d.ts +3 -0
  210. package/dist/workflow-runtime/paths.d.ts.map +1 -0
  211. package/dist/workflow-runtime/paths.js +11 -0
  212. package/dist/workflow-runtime/template.d.ts +7 -0
  213. package/dist/workflow-runtime/template.d.ts.map +1 -0
  214. package/dist/workflow-runtime/template.js +94 -0
  215. package/dist/workflow-runtime/types.d.ts +68 -0
  216. package/dist/workflow-runtime/types.d.ts.map +1 -0
  217. package/dist/workflow-runtime/types.js +1 -0
  218. package/dist/workflow-runtime/validate.d.ts +8 -0
  219. package/dist/workflow-runtime/validate.d.ts.map +1 -0
  220. package/dist/workflow-runtime/validate.js +331 -0
  221. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import { mkdir, mkdtemp, rm } from "node:fs/promises";
1
+ import { cp, mkdir, mkdtemp, rm } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { defaultConfig, loadConfig } from "@agentplaneorg/core";
@@ -8,6 +8,7 @@ import { mapCoreError } from "../../../../cli/error-map.js";
8
8
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
9
9
  import { fileExists, getPathKind } from "../../../../cli/fs-utils.js";
10
10
  import { downloadToFile } from "../../../../cli/http.js";
11
+ import { getBundledRecipeEntry, resolveBundledRecipeSourcePath, } from "../../../../recipes/bundled-recipes.js";
11
12
  import { CliError } from "../../../../shared/errors.js";
12
13
  import { ensureNetworkApproved } from "../../../shared/network-approval.js";
13
14
  import { resolvePathFallback } from "../../../shared/path.js";
@@ -86,7 +87,7 @@ export async function cmdRecipeInstall(opts) {
86
87
  const filename = path.basename(url.pathname) || "recipe.tar.gz";
87
88
  const target = path.join(tempRoot, filename);
88
89
  await downloadToFile(latest.url, target);
89
- return target;
90
+ return { kind: "archive", path: target };
90
91
  }
91
92
  const resolved = path.resolve(opts.cwd, latest.url);
92
93
  if (!(await fileExists(resolved))) {
@@ -96,11 +97,19 @@ export async function cmdRecipeInstall(opts) {
96
97
  message: `Recipe archive not found: ${latest.url}`,
97
98
  });
98
99
  }
99
- return resolved;
100
+ return { kind: "archive", path: resolved };
100
101
  };
101
102
  const resolveSourcePath = async (source) => {
102
- if (source.type === "name")
103
+ if (source.type === "name") {
104
+ const bundledPath = resolveBundledRecipeSourcePath(source.value);
105
+ if (bundledPath && (await fileExists(path.join(bundledPath, "manifest.json")))) {
106
+ const bundledEntry = getBundledRecipeEntry(source.value);
107
+ const bundledVersion = bundledEntry?.versions.at(-1)?.version ?? "unknown";
108
+ sourceLabel = `bundled:${source.value}@${bundledVersion}`;
109
+ return { kind: "directory", path: bundledPath };
110
+ }
103
111
  return await resolveFromIndex(source.value);
112
+ }
104
113
  if (source.type === "url") {
105
114
  await ensureApproved("recipes install downloads a recipe archive");
106
115
  const url = new URL(source.value);
@@ -108,7 +117,7 @@ export async function cmdRecipeInstall(opts) {
108
117
  const target = path.join(tempRoot, filename);
109
118
  sourceLabel = source.value;
110
119
  await downloadToFile(source.value, target);
111
- return target;
120
+ return { kind: "archive", path: target };
112
121
  }
113
122
  if (source.type === "path") {
114
123
  const candidate = await resolvePathFallback(source.value);
@@ -119,8 +128,13 @@ export async function cmdRecipeInstall(opts) {
119
128
  message: `Recipe archive not found: ${source.value}`,
120
129
  });
121
130
  }
131
+ const kind = await getPathKind(candidate);
132
+ if (kind === "dir") {
133
+ sourceLabel = candidate;
134
+ return { kind: "directory", path: candidate };
135
+ }
122
136
  sourceLabel = candidate;
123
- return candidate;
137
+ return { kind: "archive", path: candidate };
124
138
  }
125
139
  if (isHttpUrl(source.value)) {
126
140
  return await resolveSourcePath({ type: "url", value: source.value });
@@ -131,10 +145,11 @@ export async function cmdRecipeInstall(opts) {
131
145
  }
132
146
  return await resolveSourcePath({ type: "name", value: source.value });
133
147
  };
134
- const sourcePath = await resolveSourcePath(opts.source);
148
+ const sourceInput = await resolveSourcePath(opts.source);
149
+ const sourcePath = sourceInput.path;
135
150
  if (!sourceLabel)
136
151
  sourceLabel = opts.source.value;
137
- const actualSha = expectedSha ? await sha256File(sourcePath) : "";
152
+ const actualSha = expectedSha && sourceInput.kind === "archive" ? await sha256File(sourcePath) : "";
138
153
  if (expectedSha && actualSha !== expectedSha) {
139
154
  throw new CliError({
140
155
  exitCode: 3,
@@ -142,11 +157,19 @@ export async function cmdRecipeInstall(opts) {
142
157
  message: `Recipe checksum mismatch for ${sourceLabel}`,
143
158
  });
144
159
  }
145
- await extractArchive({
146
- archivePath: sourcePath,
147
- destDir: tempRoot,
148
- });
149
- const recipeRoot = await resolveRecipeRoot(tempRoot);
160
+ let recipeRoot;
161
+ if (sourceInput.kind === "archive") {
162
+ await extractArchive({
163
+ archivePath: sourcePath,
164
+ destDir: tempRoot,
165
+ });
166
+ recipeRoot = await resolveRecipeRoot(tempRoot);
167
+ }
168
+ else {
169
+ const stagedRecipeRoot = path.join(tempRoot, "recipe");
170
+ await cp(sourcePath, stagedRecipeRoot, { recursive: true });
171
+ recipeRoot = stagedRecipeRoot;
172
+ }
150
173
  const manifest = await readRecipeManifest(path.join(recipeRoot, "manifest.json"));
151
174
  const resolvedTags = manifest.tags && manifest.tags.length > 0 ? manifest.tags : normalizeRecipeTags(indexTags);
152
175
  const manifestWithTags = resolvedTags.length > 0 ? { ...manifest, tags: resolvedTags } : manifest;
@@ -1 +1 @@
1
- {"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../../../src/commands/recipes/impl/scenario.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA4B3F,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAG1F;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACjE,cAAc,EAAE,CAAC,CAAC;IAClB,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC/C,CAAC,CAeD;AAED,wBAAsB,4BAA4B,CAChD,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA+CjC;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,MAAM,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAyB/D"}
1
+ {"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../../../src/commands/recipes/impl/scenario.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAwD3F,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAG1F;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACjE,cAAc,EAAE,CAAC,CAAC;IAClB,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC/C,CAAC,CAeD;AAED,wBAAsB,4BAA4B,CAChD,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA+CjC;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,MAAM,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAyB/D"}
@@ -5,6 +5,30 @@ import { invalidFieldMessage, requiredFieldMessage } from "../../../cli/output.j
5
5
  import { isRecord } from "../../../shared/guards.js";
6
6
  import { RECIPES_SCENARIOS_DIR_NAME, RECIPES_SCENARIOS_INDEX_NAME } from "./constants.js";
7
7
  import { normalizeScenarioId } from "./normalize.js";
8
+ function normalizeScenarioEvidence(raw, sourcePath) {
9
+ if (raw === undefined)
10
+ return undefined;
11
+ if (!isRecord(raw)) {
12
+ throw new Error(invalidFieldMessage("scenario.evidence", "object", sourcePath));
13
+ }
14
+ const required = raw.required === true;
15
+ let files = [];
16
+ if (raw.files !== undefined) {
17
+ if (!Array.isArray(raw.files)) {
18
+ throw new Error(invalidFieldMessage("scenario.evidence.files", "string[]", sourcePath));
19
+ }
20
+ files = raw.files
21
+ .map((value) => (typeof value === "string" ? value.trim() : ""))
22
+ .filter(Boolean);
23
+ if (files.length !== raw.files.length) {
24
+ throw new Error(invalidFieldMessage("scenario.evidence.files", "string[]", sourcePath));
25
+ }
26
+ }
27
+ if (required && files.length === 0) {
28
+ files = ["evidence.json"];
29
+ }
30
+ return { required, files };
31
+ }
8
32
  function validateScenarioDefinition(raw, sourcePath) {
9
33
  if (!isRecord(raw))
10
34
  throw new Error(invalidFieldMessage("scenario", "object", sourcePath));
@@ -31,6 +55,7 @@ function validateScenarioDefinition(raw, sourcePath) {
31
55
  goal,
32
56
  inputs: raw.inputs,
33
57
  outputs: raw.outputs,
58
+ evidence: normalizeScenarioEvidence(raw.evidence, sourcePath),
34
59
  steps: raw.steps,
35
60
  };
36
61
  }
@@ -45,6 +45,10 @@ export type ScenarioDefinition = {
45
45
  goal: string;
46
46
  inputs: unknown;
47
47
  outputs: unknown;
48
+ evidence?: {
49
+ required: boolean;
50
+ files: string[];
51
+ };
48
52
  steps: unknown[];
49
53
  };
50
54
  export type RecipeScenarioDetail = {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/commands/recipes/impl/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/commands/recipes/impl/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,cAAc,EAAE,GAAG,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5D,KAAK,CAAC,EAAE;QACN,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KACxB,EAAE,CAAC;IACJ,SAAS,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEjE,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,CAAC,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,EAAE,GAAG,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,YAAY,GAAG,OAAO,GAAG,UAAU,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,cAAc,EAAE,CAAC,CAAC;IAClB,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC;YACZ,MAAM,EAAE,MAAM,CAAC;YACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;YAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;SACjB,EAAE,CAAC;KACL,EAAE,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,CAAC,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAU1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAsVnD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAiF5D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,kBAAkB,CA+K9D,CAAC"}
1
+ {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAU1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AA4VnD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAiF5D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,kBAAkB,CAoL9D,CAAC"}
@@ -136,7 +136,7 @@ function cleanHookEnv() {
136
136
  delete env.AGENTPLANE_AGENT_ID;
137
137
  return env;
138
138
  }
139
- async function validateReleaseNotes(notesPath) {
139
+ async function validateReleaseNotes(notesPath, minBullets) {
140
140
  const content = await readFile(notesPath, "utf8");
141
141
  if (!/release\s+notes/i.test(content)) {
142
142
  throw new CliError({
@@ -146,11 +146,11 @@ async function validateReleaseNotes(notesPath) {
146
146
  });
147
147
  }
148
148
  const bulletCount = content.split(/\r?\n/u).filter((line) => /^\s*[-*]\s+\S+/u.test(line)).length;
149
- if (bulletCount < 1) {
149
+ if (bulletCount < minBullets) {
150
150
  throw new CliError({
151
151
  exitCode: exitCodeForError("E_VALIDATION"),
152
152
  code: "E_VALIDATION",
153
- message: `Release notes must include at least one bullet point in ${notesPath}.`,
153
+ message: `Release notes must include at least ${minBullets} bullet points in ${notesPath}.`,
154
154
  });
155
155
  }
156
156
  if (/[\u0400-\u04FF]/u.test(content)) {
@@ -383,6 +383,11 @@ export const runReleaseApply = async (ctx, flags) => {
383
383
  });
384
384
  }
385
385
  const plan = parseVersionPlan(await readJsonFile(versionJsonPath));
386
+ const changesJsonPath = path.join(planDir, "changes.json");
387
+ const changes = (await fileExists(changesJsonPath))
388
+ ? await readJsonFile(changesJsonPath)
389
+ : [];
390
+ const minBullets = Math.max(1, Array.isArray(changes) ? changes.length : 0);
386
391
  if ((plan.bump === "minor" || plan.bump === "major") && flags.yes !== true) {
387
392
  throw usageError({
388
393
  spec: releaseApplySpec,
@@ -406,7 +411,7 @@ export const runReleaseApply = async (ctx, flags) => {
406
411
  "Write this file using a DOCS agent before applying the release.",
407
412
  });
408
413
  }
409
- await validateReleaseNotes(notesPath);
414
+ await validateReleaseNotes(notesPath, minBullets);
410
415
  const corePkgPath = path.join(gitRoot, "packages", "core", "package.json");
411
416
  const agentplanePkgPath = path.join(gitRoot, "packages", "agentplane", "package.json");
412
417
  const [coreVersion, agentplaneVersion, coreDependencyVersion] = await Promise.all([
@@ -1 +1 @@
1
- {"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/plan.command.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1E,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAqIjD,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,iBAAiB,CA4E1D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,iBAAiB,CAoE5D,CAAC"}
1
+ {"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/plan.command.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1E,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AA4IjD,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,iBAAiB,CA4E1D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,iBAAiB,CAqE5D,CAAC"}
@@ -92,6 +92,9 @@ function changesMarkdown(changes) {
92
92
  .join("\n")
93
93
  .trim() + "\n");
94
94
  }
95
+ function requiredBulletCount(changeCount) {
96
+ return Math.max(1, changeCount);
97
+ }
95
98
  function releaseInstructions(opts) {
96
99
  return (`# Release plan\n\n` +
97
100
  `## Target\n\n` +
@@ -103,8 +106,10 @@ function releaseInstructions(opts) {
103
106
  `## Agent task: write release notes\n\n` +
104
107
  `Write English release notes as \`docs/releases/${opts.nextTag}.md\`.\n\n` +
105
108
  `Rules:\n` +
106
- `- Use human-readable bullets focused on outcomes and user-facing improvements.\n` +
107
- `- Include as many bullets as needed; do not enforce a fixed bullet count.\n` +
109
+ `- Use detailed, human-readable bullets focused on outcomes and user-facing improvements.\n` +
110
+ `- Cover all listed differences from \`changes.md\`; do not omit commits.\n` +
111
+ `- Keep one concrete bullet per listed change in plain language.\n` +
112
+ `- Write at least ${opts.minBullets} bullet points.\n` +
108
113
  `- Do not include Cyrillic.\n` +
109
114
  `- Use \`docs/releases/TEMPLATE.md\` as the structure.\n\n` +
110
115
  `Inputs:\n` +
@@ -216,13 +221,14 @@ export const runReleasePlan = async (ctx, flags) => {
216
221
  const nextVersion = bumpVersion(coreVersion, flags.bump);
217
222
  const nextTag = `v${nextVersion}`;
218
223
  const changes = await listChanges(gitRoot, prevTag);
224
+ const minBullets = requiredBulletCount(changes.length);
219
225
  const runId = new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-");
220
226
  const baseDir = path.join(gitRoot, ".agentplane", ".release", "plan", runId);
221
227
  await mkdir(baseDir, { recursive: true });
222
228
  await writeFile(path.join(baseDir, "version.json"), JSON.stringify({ prevTag, prevVersion: coreVersion, nextTag, nextVersion, bump: flags.bump }, null, 2) + "\n", "utf8");
223
229
  await writeFile(path.join(baseDir, "changes.json"), JSON.stringify(changes, null, 2) + "\n", "utf8");
224
230
  await writeFile(path.join(baseDir, "changes.md"), changesMarkdown(changes), "utf8");
225
- await writeFile(path.join(baseDir, "instructions.md"), releaseInstructions({ nextTag, prevTag, bump: flags.bump }), "utf8");
231
+ await writeFile(path.join(baseDir, "instructions.md"), releaseInstructions({ nextTag, prevTag, bump: flags.bump, minBullets }), "utf8");
226
232
  process.stdout.write(`Release plan written: ${path.relative(gitRoot, baseDir)}\n`);
227
233
  process.stdout.write(`Next tag: ${nextTag}\n`);
228
234
  process.stdout.write(`Hint: Create a DOCS task to write docs/releases/${nextTag}.md based on this plan.\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/scenario/impl/commands.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAgCtE,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,GACb,oBAAoB,CAQtB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDlB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoElB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,iBAAiB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA2ChE;AAMD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC;CACvD,GAAG,OAAO,CAAC,MAAM,CAAC,CAuNlB"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/scenario/impl/commands.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAgCtE,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,GACb,oBAAoB,CAQtB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDlB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ElB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,iBAAiB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA2ChE;AAkCD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC;CACvD,GAAG,OAAO,CAAC,MAAM,CAAC,CAiQlB"}
@@ -125,6 +125,12 @@ export async function cmdScenarioInfoParsed(opts) {
125
125
  process.stdout.write(`Goal: ${scenario.goal}\n`);
126
126
  process.stdout.write(`Inputs: ${JSON.stringify(scenario.inputs, null, 2)}\n`);
127
127
  process.stdout.write(`Outputs: ${JSON.stringify(scenario.outputs, null, 2)}\n`);
128
+ if (scenario.evidence?.required) {
129
+ process.stdout.write(`Evidence: required (${normalizeExpectedEvidenceFiles(scenario.evidence.files).join(", ")})\n`);
130
+ }
131
+ else if (scenario.evidence?.files && scenario.evidence.files.length > 0) {
132
+ process.stdout.write(`Evidence: optional (${scenario.evidence.files.join(", ")})\n`);
133
+ }
128
134
  process.stdout.write("Steps:\n");
129
135
  let stepIndex = 1;
130
136
  for (const step of scenario.steps) {
@@ -185,6 +191,33 @@ export async function executeRecipeTool(opts) {
185
191
  function sanitizeRunId(value) {
186
192
  return value.replaceAll(/[^a-zA-Z0-9._-]/g, "_");
187
193
  }
194
+ function normalizeExpectedEvidenceFiles(raw) {
195
+ if (!raw || raw.length === 0)
196
+ return ["evidence.json"];
197
+ const unique = [];
198
+ for (const value of raw) {
199
+ const file = value.trim();
200
+ if (!file)
201
+ continue;
202
+ if (unique.includes(file))
203
+ continue;
204
+ unique.push(file);
205
+ }
206
+ return unique.length > 0 ? unique : ["evidence.json"];
207
+ }
208
+ async function collectStepEvidenceFiles(stepDir, expectedFiles) {
209
+ const present = [];
210
+ const missing = [];
211
+ for (const file of expectedFiles) {
212
+ if (await fileExists(path.join(stepDir, file))) {
213
+ present.push(file);
214
+ }
215
+ else {
216
+ missing.push(file);
217
+ }
218
+ }
219
+ return { present, missing };
220
+ }
188
221
  export async function cmdScenarioRunParsed(opts) {
189
222
  const resolved = opts.resolved ??
190
223
  (await resolveProject({
@@ -241,6 +274,13 @@ export async function cmdScenarioRunParsed(opts) {
241
274
  .replaceAll(".", "-")}-${sanitizeRunId(scenarioId)}`;
242
275
  const runDir = path.join(runsRoot, runId);
243
276
  await mkdir(runDir, { recursive: true });
277
+ const evidenceRequired = scenario.evidence?.required === true;
278
+ const expectedEvidenceFiles = evidenceRequired
279
+ ? normalizeExpectedEvidenceFiles(scenario.evidence?.files)
280
+ : normalizeExpectedEvidenceFiles(scenario.evidence?.files && scenario.evidence.files.length > 0
281
+ ? scenario.evidence.files
282
+ : undefined);
283
+ const missingEvidenceSteps = [];
244
284
  const stepsMeta = [];
245
285
  const stepsReport = [];
246
286
  for (let index = 0; index < scenario.steps.length; index++) {
@@ -299,6 +339,11 @@ export async function cmdScenarioRunParsed(opts) {
299
339
  const durationMs = Date.now() - startedAt;
300
340
  await atomicWriteFile(path.join(stepDir, "stdout.log"), result.stdout, "utf8");
301
341
  await atomicWriteFile(path.join(stepDir, "stderr.log"), result.stderr, "utf8");
342
+ const stepEvidence = await collectStepEvidenceFiles(stepDir, expectedEvidenceFiles);
343
+ const missingRequiredEvidence = evidenceRequired ? stepEvidence.missing : [];
344
+ if (missingRequiredEvidence.length > 0) {
345
+ missingEvidenceSteps.push(index + 1);
346
+ }
302
347
  stepsMeta.push({
303
348
  tool: step.tool,
304
349
  runtime,
@@ -313,10 +358,12 @@ export async function cmdScenarioRunParsed(opts) {
313
358
  entrypoint,
314
359
  args: redactArgs(step.args),
315
360
  env_keys: stepEnvKeys,
361
+ evidence_files: stepEvidence.present,
362
+ missing_evidence_files: missingRequiredEvidence.length > 0 ? missingRequiredEvidence : undefined,
316
363
  exit_code: result.exitCode,
317
364
  duration_ms: durationMs,
318
365
  });
319
- if (result.exitCode !== 0) {
366
+ if (result.exitCode !== 0 || missingRequiredEvidence.length > 0) {
320
367
  const gitSummary = await getGitDiffSummary(resolved.gitRoot);
321
368
  await writeScenarioReport({
322
369
  runDir,
@@ -326,18 +373,32 @@ export async function cmdScenarioRunParsed(opts) {
326
373
  startedAt: runStartedAt,
327
374
  status: "failed",
328
375
  steps: stepsReport,
376
+ evidence: {
377
+ required: evidenceRequired,
378
+ expected_files: expectedEvidenceFiles,
379
+ missing_steps: missingEvidenceSteps,
380
+ },
329
381
  gitSummary,
330
382
  });
331
383
  await atomicWriteFile(path.join(runDir, "meta.json"), `${JSON.stringify({
332
384
  recipe: recipeId,
333
385
  scenario: scenarioId,
334
386
  run_id: runId,
387
+ evidence: {
388
+ required: evidenceRequired,
389
+ expected_files: expectedEvidenceFiles,
390
+ missing_steps: missingEvidenceSteps,
391
+ },
335
392
  steps: stepsMeta,
336
393
  }, null, 2)}\n`, "utf8");
394
+ const reason = missingRequiredEvidence.length > 0
395
+ ? `Scenario step missing required evidence: ${step.tool} (${missingRequiredEvidence.join(", ")})`
396
+ : `Scenario step failed: ${step.tool}`;
397
+ const stepExitCode = result.exitCode === 0 ? 1 : result.exitCode;
337
398
  throw new CliError({
338
- exitCode: result.exitCode,
399
+ exitCode: stepExitCode,
339
400
  code: "E_INTERNAL",
340
- message: `Scenario step failed: ${step.tool}`,
401
+ message: reason,
341
402
  });
342
403
  }
343
404
  }
@@ -350,12 +411,22 @@ export async function cmdScenarioRunParsed(opts) {
350
411
  startedAt: runStartedAt,
351
412
  status: "success",
352
413
  steps: stepsReport,
414
+ evidence: {
415
+ required: evidenceRequired,
416
+ expected_files: expectedEvidenceFiles,
417
+ missing_steps: missingEvidenceSteps,
418
+ },
353
419
  gitSummary,
354
420
  });
355
421
  await atomicWriteFile(path.join(runDir, "meta.json"), `${JSON.stringify({
356
422
  recipe: recipeId,
357
423
  scenario: scenarioId,
358
424
  run_id: runId,
425
+ evidence: {
426
+ required: evidenceRequired,
427
+ expected_files: expectedEvidenceFiles,
428
+ missing_steps: missingEvidenceSteps,
429
+ },
359
430
  steps: stepsMeta,
360
431
  }, null, 2)}\n`, "utf8");
361
432
  process.stdout.write(`Run artifacts: ${path.relative(resolved.gitRoot, runDir)}\n`);
@@ -10,9 +10,16 @@ export type ScenarioRunReportStep = {
10
10
  entrypoint: string;
11
11
  args: string[];
12
12
  env_keys: string[];
13
+ evidence_files: string[];
14
+ missing_evidence_files?: string[];
13
15
  exit_code: number;
14
16
  duration_ms: number;
15
17
  };
18
+ type ScenarioRunEvidenceSummary = {
19
+ required: boolean;
20
+ expected_files: string[];
21
+ missing_steps: number[];
22
+ };
16
23
  export declare function redactArgs(args: string[]): string[];
17
24
  export declare function getGitDiffSummary(cwd: string): Promise<ScenarioRunGitSummary | undefined>;
18
25
  export declare function collectScenarioEnvKeys(stepEnv: Record<string, string> | undefined): string[];
@@ -24,6 +31,7 @@ export declare function writeScenarioReport(opts: {
24
31
  startedAt: string;
25
32
  status: "success" | "failed";
26
33
  steps: ScenarioRunReportStep[];
34
+ evidence: ScenarioRunEvidenceSummary;
27
35
  gitSummary?: ScenarioRunGitSummary;
28
36
  }): Promise<void>;
29
37
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../../src/commands/scenario/impl/report.ts"],"names":[],"mappings":"AAYA,KAAK,qBAAqB,GAAG;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AA2BF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBnD;AASD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAwB/F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CAU5F;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../../src/commands/scenario/impl/report.ts"],"names":[],"mappings":"AAYA,KAAK,qBAAqB,GAAG;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AA4BF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBnD;AASD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAwB/F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CAU5F;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,QAAQ,EAAE,0BAA0B,CAAC;IACrC,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB"}
@@ -93,6 +93,7 @@ export async function writeScenarioReport(opts) {
93
93
  ended_at: new Date().toISOString(),
94
94
  status: opts.status,
95
95
  steps: opts.steps,
96
+ evidence: opts.evidence,
96
97
  git: opts.gitSummary,
97
98
  };
98
99
  await atomicWriteFile(path.join(opts.runDir, SCENARIO_REPORT_NAME), `${JSON.stringify(report, null, 2)}\n`, "utf8");
@@ -0,0 +1,7 @@
1
+ import { type CommandContext } from "./task-backend.js";
2
+ export declare function ensureReconciledBeforeMutation(opts: {
3
+ ctx: CommandContext;
4
+ command: string;
5
+ strictTaskScan?: boolean;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=reconcile-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile-check.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/reconcile-check.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgBvE,wBAAsB,8BAA8B,CAAC,IAAI,EAAE;IACzD,GAAG,EAAE,cAAc,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,IAAI,CAAC,CA4ChB"}
@@ -0,0 +1,60 @@
1
+ import { exitCodeForError } from "../../cli/exit-codes.js";
2
+ import { CliError } from "../../shared/errors.js";
3
+ import { listTasksMemo } from "./task-backend.js";
4
+ function compactError(err) {
5
+ if (err instanceof Error) {
6
+ const text = err.message.trim();
7
+ return text.length > 0 ? text : err.name;
8
+ }
9
+ return String(err);
10
+ }
11
+ function summarizeWarnings(warnings) {
12
+ const preview = warnings.slice(0, 3).join("; ");
13
+ const suffix = warnings.length > 3 ? `; +${warnings.length - 3} more` : "";
14
+ return `skipped ${warnings.length} task files during scan (${preview}${suffix})`;
15
+ }
16
+ export async function ensureReconciledBeforeMutation(opts) {
17
+ try {
18
+ await opts.ctx.git.statusChangedPaths();
19
+ }
20
+ catch (err) {
21
+ throw new CliError({
22
+ exitCode: exitCodeForError("E_GIT"),
23
+ code: "E_GIT",
24
+ message: `reconcile check failed: cannot inspect git status (${compactError(err)})`,
25
+ context: {
26
+ command: opts.command,
27
+ reason_code: "reconcile_git_state_unreadable",
28
+ },
29
+ });
30
+ }
31
+ if (opts.strictTaskScan === false)
32
+ return;
33
+ try {
34
+ await listTasksMemo(opts.ctx);
35
+ }
36
+ catch (err) {
37
+ throw new CliError({
38
+ exitCode: exitCodeForError("E_VALIDATION"),
39
+ code: "E_VALIDATION",
40
+ message: `reconcile check failed: task scan error (${compactError(err)})`,
41
+ context: {
42
+ command: opts.command,
43
+ reason_code: "reconcile_task_scan_failed",
44
+ },
45
+ });
46
+ }
47
+ const warnings = opts.ctx.taskBackend.getLastListWarnings?.() ?? [];
48
+ if (warnings.length === 0)
49
+ return;
50
+ throw new CliError({
51
+ exitCode: exitCodeForError("E_VALIDATION"),
52
+ code: "E_VALIDATION",
53
+ message: `reconcile check failed: ${summarizeWarnings(warnings)}`,
54
+ context: {
55
+ command: opts.command,
56
+ reason_code: "reconcile_task_scan_incomplete",
57
+ warning_count: warnings.length,
58
+ },
59
+ });
60
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"sync.command.d.ts","sourceRoot":"","sources":["../../src/commands/sync.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE9D,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CA6C5C,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACnE,KAAK,UAAU,EAAE,GAAG,UAAU,KAAG,OAAO,CAAC,MAAM,CAAC,CAS/D"}
1
+ {"version":3,"file":"sync.command.d.ts","sourceRoot":"","sources":["../../src/commands/sync.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE9D,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CAmD5C,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACnE,KAAK,UAAU,EAAE,GAAG,UAAU,KAAG,OAAO,CAAC,MAAM,CAAC,CAS/D"}
@@ -1,3 +1,4 @@
1
+ import { COMMAND_SNIPPETS } from "../cli/command-snippets.js";
1
2
  import { cmdSyncParsed } from "./backend.js";
2
3
  export const syncSpec = {
3
4
  id: ["sync"],
@@ -33,8 +34,14 @@ export const syncSpec = {
33
34
  { kind: "boolean", name: "quiet", default: false, description: "Reduce output noise." },
34
35
  ],
35
36
  examples: [
36
- { cmd: "agentplane sync --direction pull", why: "Pull from backend (configured backend id)." },
37
- { cmd: "agentplane sync redmine --direction push --yes", why: "Push to redmine backend." },
37
+ {
38
+ cmd: COMMAND_SNIPPETS.sync.pullConfigured,
39
+ why: "Pull from backend (configured backend id).",
40
+ },
41
+ {
42
+ cmd: COMMAND_SNIPPETS.sync.pushRedmineExplicitWithYes,
43
+ why: "Push to redmine backend.",
44
+ },
38
45
  ],
39
46
  parse: (raw) => ({
40
47
  backendId: raw.args.id ? String(raw.args.id) : null,
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/commands/task/add.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGpF,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG,OAAO,CAAC,MAAM,CAAC,CAwDlB"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/commands/task/add.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAoCpF,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG,OAAO,CAAC,MAAM,CAAC,CA6DlB"}
@@ -2,6 +2,33 @@ import { mapBackendError } from "../../cli/error-map.js";
2
2
  import { CliError } from "../../shared/errors.js";
3
3
  import { loadCommandContext } from "../shared/task-backend.js";
4
4
  import { dedupeStrings, normalizeTaskStatus, nowIso } from "./shared.js";
5
+ import { ensureDocSections, setMarkdownSection } from "@agentplaneorg/core";
6
+ function defaultTaskDoc(opts) {
7
+ const baseDoc = ensureDocSections("", opts.requiredSections);
8
+ const summary = `${opts.title}\n\n${opts.description}`;
9
+ const scope = [
10
+ `- In scope: ${opts.description}.`,
11
+ `- Out of scope: unrelated refactors not required for "${opts.title}".`,
12
+ ].join("\n");
13
+ const plan = [
14
+ `1. Implement the change for "${opts.title}".`,
15
+ "2. Run required checks and capture verification evidence.",
16
+ "3. Finalize task notes and finish with traceable commit metadata.",
17
+ ].join("\n");
18
+ const risks = [
19
+ "- Risk: hidden regressions in touched paths.",
20
+ "- Mitigation: run required checks before finish and record evidence.",
21
+ ].join("\n");
22
+ const rollback = [
23
+ "- Revert task-related commit(s).",
24
+ "- Re-run required checks to confirm rollback safety.",
25
+ ].join("\n");
26
+ const withSummary = setMarkdownSection(baseDoc, "Summary", summary);
27
+ const withScope = setMarkdownSection(withSummary, "Scope", scope);
28
+ const withPlan = setMarkdownSection(withScope, "Plan", plan);
29
+ const withRisks = setMarkdownSection(withPlan, "Risks", risks);
30
+ return setMarkdownSection(withRisks, "Rollback Plan", rollback);
31
+ }
5
32
  export async function cmdTaskAdd(opts) {
6
33
  try {
7
34
  const ctx = opts.ctx ??
@@ -39,6 +66,11 @@ export async function cmdTaskAdd(opts) {
39
66
  doc_updated_at: nowIso(),
40
67
  doc_updated_by: docUpdatedBy,
41
68
  id_source: "explicit",
69
+ doc: defaultTaskDoc({
70
+ requiredSections: ctx.config.tasks.doc.required_sections,
71
+ title: opts.title,
72
+ description: opts.description,
73
+ }),
42
74
  }));
43
75
  if (ctx.taskBackend.writeTasks) {
44
76
  await ctx.taskBackend.writeTasks(tasks);
@@ -1 +1 @@
1
- {"version":3,"file":"doc.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtE,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAclD,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9E"}
1
+ {"version":3,"file":"doc.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtE,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,aAAa,CAelD,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9E"}
@@ -6,6 +6,7 @@ export const taskDocSpec = {
6
6
  synopsis: [
7
7
  "agentplane task doc show <task-id> [--section <name>] [--quiet]",
8
8
  "agentplane task doc set <task-id> --section <name> (--text <text> | --file <path>) [--updated-by <id>]",
9
+ "agentplane task doc set <task-id> --section Summary --file ./task-readme.md # if payload contains multiple known ## headings, apply as full-doc update",
9
10
  ],
10
11
  args: [{ name: "subcommand", required: false, valueHint: "<show|set>" }],
11
12
  parse: (raw) => {