agentplane 0.3.5 → 0.3.6
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 +103 -75
- package/assets/AGENTS.md +4 -2
- package/bin/dist-guard.js +13 -3
- package/bin/runtime-watch.d.ts +1 -0
- package/bin/runtime-watch.js +22 -5
- package/bin/stale-dist-policy.js +9 -2
- package/dist/.build-manifest.json +196 -776
- package/dist/backends/task-backend.test-helpers.d.ts +4 -0
- package/dist/backends/task-backend.test-helpers.d.ts.map +1 -0
- package/dist/backends/task-backend.test-helpers.js +33 -0
- package/dist/cli/bootstrap-guide.d.ts.map +1 -1
- package/dist/cli/bootstrap-guide.js +1 -0
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +3 -2
- package/dist/cli/reason-codes.d.ts.map +1 -1
- package/dist/cli/reason-codes.js +30 -0
- package/dist/cli/run-cli/command-catalog/core.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/core.js +137 -0
- package/dist/cli/run-cli/command-catalog/lifecycle.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/lifecycle.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/lifecycle.js +52 -0
- package/dist/cli/run-cli/command-catalog/project.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/project.js +78 -0
- package/dist/cli/run-cli/command-catalog/shared.d.ts +19 -0
- package/dist/cli/run-cli/command-catalog/shared.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/shared.js +9 -0
- package/dist/cli/run-cli/command-catalog/task.d.ts +3 -0
- package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -0
- package/dist/cli/run-cli/command-catalog/task.js +85 -0
- package/dist/cli/run-cli/command-catalog.d.ts +3 -18
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +8 -337
- package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/ide.js +64 -2
- package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/ui.js +33 -13
- package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts +3 -0
- package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts.map +1 -0
- package/dist/cli/run-cli.core.pr-flow.test-helpers.js +41 -0
- package/dist/cli/run-cli.core.tasks.test-helpers.d.ts +2 -0
- package/dist/cli/run-cli.core.tasks.test-helpers.d.ts.map +1 -0
- package/dist/cli/run-cli.core.tasks.test-helpers.js +6 -0
- package/dist/cli/run-cli.test-helpers.d.ts +3 -0
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +138 -6
- package/dist/commands/commit.spec.d.ts.map +1 -1
- package/dist/commands/commit.spec.js +2 -2
- package/dist/commands/doctor/runtime.d.ts.map +1 -1
- package/dist/commands/doctor/runtime.js +3 -6
- package/dist/commands/guard/commit.command.js +1 -1
- package/dist/commands/guard/impl/allow.d.ts +5 -0
- package/dist/commands/guard/impl/allow.d.ts.map +1 -1
- package/dist/commands/guard/impl/allow.js +15 -10
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +137 -18
- package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -1
- package/dist/commands/guard/impl/comment-commit.js +2 -0
- package/dist/commands/hooks/index.d.ts.map +1 -1
- package/dist/commands/hooks/index.js +8 -35
- package/dist/commands/recipes/impl/apply.d.ts +4 -0
- package/dist/commands/recipes/impl/apply.d.ts.map +1 -1
- package/dist/commands/recipes/impl/apply.js +34 -0
- package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/explain.js +70 -11
- package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/info.js +24 -12
- package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/install.js +32 -36
- package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/list.js +7 -4
- package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
- package/dist/commands/recipes/impl/commands/remove.js +9 -11
- package/dist/commands/recipes/impl/constants.d.ts +2 -0
- package/dist/commands/recipes/impl/constants.d.ts.map +1 -1
- package/dist/commands/recipes/impl/constants.js +2 -0
- package/dist/commands/recipes/impl/manifest.d.ts.map +1 -1
- package/dist/commands/recipes/impl/manifest.js +219 -23
- package/dist/commands/recipes/impl/normalize.d.ts +3 -0
- package/dist/commands/recipes/impl/normalize.d.ts.map +1 -1
- package/dist/commands/recipes/impl/normalize.js +28 -24
- package/dist/commands/recipes/impl/paths.d.ts +9 -0
- package/dist/commands/recipes/impl/paths.d.ts.map +1 -1
- package/dist/commands/recipes/impl/paths.js +10 -1
- package/dist/commands/recipes/impl/project-installed-recipes.d.ts +7 -0
- package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -0
- package/dist/commands/recipes/impl/project-installed-recipes.js +102 -0
- package/dist/commands/recipes/impl/resolver.d.ts +20 -0
- package/dist/commands/recipes/impl/resolver.d.ts.map +1 -0
- package/dist/commands/recipes/impl/resolver.js +220 -0
- package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
- package/dist/commands/recipes/impl/scenario.js +40 -11
- package/dist/commands/recipes/impl/types.d.ts +145 -16
- package/dist/commands/recipes/impl/types.d.ts.map +1 -1
- package/dist/commands/recipes/install.spec.d.ts.map +1 -1
- package/dist/commands/recipes/install.spec.js +3 -2
- package/dist/commands/recipes.d.ts +6 -4
- package/dist/commands/recipes.d.ts.map +1 -1
- package/dist/commands/recipes.js +5 -3
- package/dist/commands/recipes.test-helpers.d.ts +185 -0
- package/dist/commands/recipes.test-helpers.d.ts.map +1 -0
- package/dist/commands/recipes.test-helpers.js +339 -0
- package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
- package/dist/commands/scenario/impl/commands.js +192 -336
- package/dist/commands/scenario/info.command.d.ts.map +1 -1
- package/dist/commands/scenario/info.command.js +7 -2
- package/dist/commands/scenario/list.command.js +2 -2
- package/dist/commands/scenario/run.command.d.ts.map +1 -1
- package/dist/commands/scenario/run.command.js +7 -2
- package/dist/commands/shared/reconcile-check.d.ts.map +1 -1
- package/dist/commands/shared/reconcile-check.js +77 -2
- package/dist/commands/shared/task-store.d.ts +32 -1
- package/dist/commands/shared/task-store.d.ts.map +1 -1
- package/dist/commands/shared/task-store.js +166 -42
- package/dist/commands/task/block.d.ts.map +1 -1
- package/dist/commands/task/block.js +46 -29
- package/dist/commands/task/close-duplicate.d.ts.map +1 -1
- package/dist/commands/task/close-duplicate.js +12 -37
- package/dist/commands/task/close-noop.d.ts.map +1 -1
- package/dist/commands/task/close-noop.js +12 -30
- package/dist/commands/task/close-shared.d.ts +14 -0
- package/dist/commands/task/close-shared.d.ts.map +1 -0
- package/dist/commands/task/close-shared.js +76 -0
- package/dist/commands/task/comment.d.ts.map +1 -1
- package/dist/commands/task/comment.js +35 -17
- package/dist/commands/task/doc-set.command.d.ts +2 -1
- package/dist/commands/task/doc-set.command.d.ts.map +1 -1
- package/dist/commands/task/doc-set.command.js +36 -4
- package/dist/commands/task/doc-template.d.ts.map +1 -1
- package/dist/commands/task/doc-template.js +2 -7
- package/dist/commands/task/doc.command.js +1 -1
- package/dist/commands/task/doc.d.ts +2 -1
- package/dist/commands/task/doc.d.ts.map +1 -1
- package/dist/commands/task/doc.js +123 -71
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +138 -76
- package/dist/commands/task/migrate-doc.d.ts.map +1 -1
- package/dist/commands/task/migrate-doc.js +2 -8
- package/dist/commands/task/plan-set.command.js +1 -1
- package/dist/commands/task/plan.command.d.ts +8 -0
- package/dist/commands/task/plan.command.d.ts.map +1 -0
- package/dist/commands/task/plan.command.js +37 -0
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +190 -93
- package/dist/commands/task/set-status.command.d.ts.map +1 -1
- package/dist/commands/task/set-status.command.js +1 -1
- package/dist/commands/task/set-status.d.ts.map +1 -1
- package/dist/commands/task/set-status.js +40 -3
- package/dist/commands/task/shared/docs.d.ts +1 -0
- package/dist/commands/task/shared/docs.d.ts.map +1 -1
- package/dist/commands/task/shared/docs.js +7 -0
- package/dist/commands/task/shared/transitions.d.ts +0 -2
- package/dist/commands/task/shared/transitions.d.ts.map +1 -1
- package/dist/commands/task/shared/transitions.js +0 -6
- package/dist/commands/task/shared.d.ts +2 -2
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +2 -2
- package/dist/commands/task/start.d.ts.map +1 -1
- package/dist/commands/task/start.js +88 -63
- package/dist/commands/task/task.command.d.ts +8 -0
- package/dist/commands/task/task.command.d.ts.map +1 -0
- package/dist/commands/task/task.command.js +71 -0
- package/dist/commands/task/verify-command-shared.d.ts +16 -0
- package/dist/commands/task/verify-command-shared.d.ts.map +1 -0
- package/dist/commands/task/verify-command-shared.js +53 -0
- package/dist/commands/task/verify-ok.command.d.ts +2 -6
- package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
- package/dist/commands/task/verify-ok.command.js +8 -50
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +119 -140
- package/dist/commands/task/verify-rework.command.d.ts +2 -6
- package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
- package/dist/commands/task/verify-rework.command.js +8 -50
- package/dist/commands/verify.spec.d.ts.map +1 -1
- package/dist/commands/verify.spec.js +3 -12
- package/dist/policy/rules/allowlist.d.ts.map +1 -1
- package/dist/policy/rules/allowlist.js +13 -4
- package/dist/policy/rules/protected-paths.d.ts.map +1 -1
- package/dist/policy/rules/protected-paths.js +6 -1
- package/dist/shared/agent-emoji.d.ts.map +1 -1
- package/dist/shared/protected-paths.d.ts +7 -0
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +26 -10
- package/dist/shared/repo-cli-version.d.ts.map +1 -1
- package/dist/shared/repo-cli-version.js +9 -3
- package/package.json +2 -2
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { promisify } from "node:util";
|
|
8
8
|
import { gzipSync } from "node:zlib";
|
|
9
|
-
import { afterAll, afterEach, beforeAll } from "vitest";
|
|
9
|
+
import { afterAll, afterEach, beforeAll, beforeEach, vi } from "vitest";
|
|
10
10
|
import { defaultConfig } from "@agentplaneorg/core";
|
|
11
11
|
import { runCli } from "./run-cli.js";
|
|
12
12
|
const execFileAsync = promisify(execFile);
|
|
@@ -98,6 +98,17 @@ export function registerAgentplaneHome() {
|
|
|
98
98
|
}));
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
|
+
export function installRunCliIntegrationHarness() {
|
|
102
|
+
registerAgentplaneHome();
|
|
103
|
+
let restoreStdIO = null;
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
restoreStdIO = silenceStdIO();
|
|
106
|
+
});
|
|
107
|
+
afterEach(() => {
|
|
108
|
+
restoreStdIO?.();
|
|
109
|
+
restoreStdIO = null;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
101
112
|
export function getAgentplaneHome() {
|
|
102
113
|
return agentplaneHome;
|
|
103
114
|
}
|
|
@@ -150,6 +161,26 @@ export function silenceStdIO() {
|
|
|
150
161
|
}
|
|
151
162
|
};
|
|
152
163
|
}
|
|
164
|
+
export function stubTaskBackend(overrides = {}) {
|
|
165
|
+
return {
|
|
166
|
+
id: "local",
|
|
167
|
+
capabilities: {
|
|
168
|
+
canonical_source: "local",
|
|
169
|
+
projection: "canonical",
|
|
170
|
+
reads_from_projection_by_default: false,
|
|
171
|
+
writes_task_readmes: true,
|
|
172
|
+
may_access_network_on_read: false,
|
|
173
|
+
may_access_network_on_write: false,
|
|
174
|
+
supports_projection_refresh: false,
|
|
175
|
+
supports_push_sync: false,
|
|
176
|
+
supports_snapshot_export: false,
|
|
177
|
+
},
|
|
178
|
+
listTasks: vi.fn().mockResolvedValue([]),
|
|
179
|
+
getTask: vi.fn().mockResolvedValue(null),
|
|
180
|
+
writeTask: vi.fn().mockImplementation(() => Promise.resolve()),
|
|
181
|
+
...overrides,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
153
184
|
export async function runCliSilent(args) {
|
|
154
185
|
const io = captureStdIO();
|
|
155
186
|
try {
|
|
@@ -215,11 +246,60 @@ export async function createRecipeArchive(opts) {
|
|
|
215
246
|
name: opts?.name ?? "Viewer",
|
|
216
247
|
summary: opts?.summary ?? "Preview task artifacts",
|
|
217
248
|
description: opts?.description ?? "Provides a local viewer for task artifacts.",
|
|
218
|
-
|
|
249
|
+
compatibility: {
|
|
250
|
+
min_agentplane_version: "0.3.5",
|
|
251
|
+
manifest_api_version: "1",
|
|
252
|
+
scenario_api_version: "1",
|
|
253
|
+
runtime_api_version: "1",
|
|
254
|
+
platforms: ["darwin", "linux"],
|
|
255
|
+
repo_types: ["generic"],
|
|
256
|
+
},
|
|
257
|
+
skills: [
|
|
258
|
+
{
|
|
259
|
+
id: "RECIPE_SKILL",
|
|
260
|
+
summary: "Recipe analysis skill",
|
|
261
|
+
kind: "agent-skill",
|
|
262
|
+
file: "skills/analysis.json",
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
agents: [
|
|
266
|
+
{
|
|
267
|
+
id: "RECIPE_AGENT",
|
|
268
|
+
display_name: "Recipe Agent",
|
|
269
|
+
role: "executor",
|
|
270
|
+
summary: "Recipe agent",
|
|
271
|
+
skills: ["RECIPE_SKILL"],
|
|
272
|
+
tools: ["RECIPE_TOOL"],
|
|
273
|
+
file: "agents/recipe.json",
|
|
274
|
+
},
|
|
275
|
+
],
|
|
219
276
|
tools: [
|
|
220
277
|
{ id: "RECIPE_TOOL", summary: "Recipe tool", runtime: "node", entrypoint: "tools/run.js" },
|
|
221
278
|
],
|
|
222
|
-
scenarios: [
|
|
279
|
+
scenarios: [
|
|
280
|
+
{
|
|
281
|
+
id: "RECIPE_SCENARIO",
|
|
282
|
+
name: "Recipe Scenario",
|
|
283
|
+
summary: "Recipe scenario",
|
|
284
|
+
use_when: ["Task artifacts need local preview"],
|
|
285
|
+
required_inputs: ["task_id"],
|
|
286
|
+
outputs: ["report"],
|
|
287
|
+
permissions: ["filesystem-write"],
|
|
288
|
+
artifacts: ["artifact.txt"],
|
|
289
|
+
agents_involved: ["RECIPE_AGENT"],
|
|
290
|
+
skills_used: ["RECIPE_SKILL"],
|
|
291
|
+
tools_used: ["RECIPE_TOOL"],
|
|
292
|
+
run_profile: {
|
|
293
|
+
mode: "analysis",
|
|
294
|
+
sandbox: "workspace-write",
|
|
295
|
+
network: false,
|
|
296
|
+
requires_human_approval: false,
|
|
297
|
+
writes_artifacts_to: ["logs/", "reports/"],
|
|
298
|
+
expected_exit_contract: "report",
|
|
299
|
+
},
|
|
300
|
+
file: "scenarios/recipe-scenario.json",
|
|
301
|
+
},
|
|
302
|
+
],
|
|
223
303
|
};
|
|
224
304
|
if (normalizedTags) {
|
|
225
305
|
manifest.tags = normalizedTags;
|
|
@@ -232,6 +312,13 @@ export async function createRecipeArchive(opts) {
|
|
|
232
312
|
role: "Recipe agent",
|
|
233
313
|
description: "Example agent installed from a recipe.",
|
|
234
314
|
}, null, 2), "utf8");
|
|
315
|
+
const skillsDir = path.join(recipeDir, "skills");
|
|
316
|
+
await mkdir(skillsDir, { recursive: true });
|
|
317
|
+
await writeFile(path.join(skillsDir, "analysis.json"), JSON.stringify({
|
|
318
|
+
id: "RECIPE_SKILL",
|
|
319
|
+
summary: "Recipe analysis skill",
|
|
320
|
+
kind: "agent-skill",
|
|
321
|
+
}, null, 2), "utf8");
|
|
235
322
|
const toolsDir = path.join(recipeDir, "tools");
|
|
236
323
|
await mkdir(toolsDir, { recursive: true });
|
|
237
324
|
await writeFile(path.join(toolsDir, "run.js"), [
|
|
@@ -302,22 +389,67 @@ export async function createUnsafeRecipeArchive(opts) {
|
|
|
302
389
|
name: "Unsafe",
|
|
303
390
|
summary: "Unsafe recipe",
|
|
304
391
|
description: "Used for archive validation tests.",
|
|
305
|
-
|
|
392
|
+
skills: [
|
|
393
|
+
{
|
|
394
|
+
id: "RECIPE_SKILL",
|
|
395
|
+
summary: "Recipe skill",
|
|
396
|
+
kind: "agent-skill",
|
|
397
|
+
file: "skills/recipe.json",
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
agents: [
|
|
401
|
+
{
|
|
402
|
+
id: "RECIPE_AGENT",
|
|
403
|
+
display_name: "Recipe Agent",
|
|
404
|
+
role: "executor",
|
|
405
|
+
summary: "Recipe agent",
|
|
406
|
+
skills: ["RECIPE_SKILL"],
|
|
407
|
+
tools: ["RECIPE_TOOL"],
|
|
408
|
+
file: "agents/recipe.json",
|
|
409
|
+
},
|
|
410
|
+
],
|
|
306
411
|
tools: [
|
|
307
412
|
{ id: "RECIPE_TOOL", summary: "Recipe tool", runtime: "bash", entrypoint: "tools/run.sh" },
|
|
308
413
|
],
|
|
309
|
-
scenarios: [
|
|
414
|
+
scenarios: [
|
|
415
|
+
{
|
|
416
|
+
id: "RECIPE_SCENARIO",
|
|
417
|
+
name: "Recipe Scenario",
|
|
418
|
+
summary: "Recipe scenario",
|
|
419
|
+
use_when: ["Unsafe validation fixture"],
|
|
420
|
+
required_inputs: [],
|
|
421
|
+
outputs: [],
|
|
422
|
+
permissions: [],
|
|
423
|
+
artifacts: [],
|
|
424
|
+
agents_involved: ["RECIPE_AGENT"],
|
|
425
|
+
skills_used: ["RECIPE_SKILL"],
|
|
426
|
+
tools_used: ["RECIPE_TOOL"],
|
|
427
|
+
run_profile: { mode: "analysis" },
|
|
428
|
+
file: "scenarios/recipe-scenario.json",
|
|
429
|
+
},
|
|
430
|
+
],
|
|
310
431
|
};
|
|
311
432
|
await writeFile(path.join(recipeDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
|
|
312
433
|
const agentsDir = path.join(recipeDir, "agents");
|
|
313
434
|
await mkdir(agentsDir, { recursive: true });
|
|
314
435
|
await writeFile(path.join(agentsDir, "recipe.json"), JSON.stringify({ id: "RECIPE_AGENT", role: "Recipe agent" }, null, 2), "utf8");
|
|
436
|
+
const skillsDir = path.join(recipeDir, "skills");
|
|
437
|
+
await mkdir(skillsDir, { recursive: true });
|
|
438
|
+
await writeFile(path.join(skillsDir, "recipe.json"), JSON.stringify({ id: "RECIPE_SKILL" }), "utf8");
|
|
315
439
|
const toolsDir = path.join(recipeDir, "tools");
|
|
316
440
|
await mkdir(toolsDir, { recursive: true });
|
|
317
441
|
await writeFile(path.join(toolsDir, "run.sh"), "#!/usr/bin/env bash\n", "utf8");
|
|
318
442
|
const scenariosDir = path.join(recipeDir, "scenarios");
|
|
319
443
|
await mkdir(scenariosDir, { recursive: true });
|
|
320
|
-
await writeFile(path.join(scenariosDir, "recipe-scenario.json"), JSON.stringify({
|
|
444
|
+
await writeFile(path.join(scenariosDir, "recipe-scenario.json"), JSON.stringify({
|
|
445
|
+
schema_version: "1",
|
|
446
|
+
id: "RECIPE_SCENARIO",
|
|
447
|
+
summary: "Recipe scenario",
|
|
448
|
+
goal: "Exercise unsafe archive validation.",
|
|
449
|
+
inputs: [],
|
|
450
|
+
outputs: [],
|
|
451
|
+
steps: [{ tool: "RECIPE_TOOL" }],
|
|
452
|
+
}, null, 2), "utf8");
|
|
321
453
|
const entryPath = opts.entryPath ?? "../evil.txt";
|
|
322
454
|
await writeFile(path.join(baseDir, "evil.txt"), "evil", "utf8");
|
|
323
455
|
const archivePath = opts.format === "zip" ? path.join(baseDir, "unsafe.zip") : path.join(baseDir, "unsafe.tar.gz");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commit.spec.d.ts","sourceRoot":"","sources":["../../src/commands/commit.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,
|
|
1
|
+
{"version":3,"file":"commit.spec.d.ts","sourceRoot":"","sources":["../../src/commands/commit.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CA+JhD,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../share
|
|
|
3
3
|
export const commitSpec = {
|
|
4
4
|
id: ["commit"],
|
|
5
5
|
group: "Guard",
|
|
6
|
-
summary: "Create a git commit after validating policy and allowlist
|
|
6
|
+
summary: "Create a git commit after validating policy and allowlist; if the index is empty, stage matching allowlist paths first.",
|
|
7
7
|
args: [{ name: "task-id", required: true, valueHint: "<task-id>" }],
|
|
8
8
|
options: [
|
|
9
9
|
{
|
|
@@ -49,7 +49,7 @@ export const commitSpec = {
|
|
|
49
49
|
kind: "boolean",
|
|
50
50
|
name: "allow-tasks",
|
|
51
51
|
default: false,
|
|
52
|
-
description: "Allow
|
|
52
|
+
description: "Allow the tasks export snapshot plus artifacts under the active task subtree.",
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
kind: "boolean",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAsB5D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,CA+BxF;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAM1E"}
|
|
@@ -10,10 +10,7 @@ function renderCliVersionFacts(expectation) {
|
|
|
10
10
|
...(expectation.recovery ? [`[WARN] Recovery: ${expectation.recovery}`] : []),
|
|
11
11
|
];
|
|
12
12
|
}
|
|
13
|
-
return [
|
|
14
|
-
`[INFO] Repository expected agentplane CLI: ${expectation.expectedVersion}`,
|
|
15
|
-
...(expectation.summary ? [`[INFO] ${expectation.summary}`] : []),
|
|
16
|
-
];
|
|
13
|
+
return [];
|
|
17
14
|
}
|
|
18
15
|
export function checkRuntimeSourceFacts(cwd, config) {
|
|
19
16
|
const report = resolveRuntimeSourceInfo({ cwd, entryModuleUrl: import.meta.url });
|
|
@@ -25,9 +22,9 @@ export function checkRuntimeSourceFacts(cwd, config) {
|
|
|
25
22
|
}
|
|
26
23
|
const warning = report.mode === "global-in-framework"
|
|
27
24
|
? "[WARN] Framework checkout detected but the active runtime is still a global installed binary. " +
|
|
28
|
-
"
|
|
25
|
+
"Run scripts/reinstall-global-agentplane.sh to refresh the wrapper, or run the repo-local binary directly."
|
|
29
26
|
: report.mode === "global-forced-in-framework"
|
|
30
|
-
? "[WARN] Framework checkout is forcing the global installed binary via AGENTPLANE_USE_GLOBAL_IN_FRAMEWORK=1."
|
|
27
|
+
? "[WARN] Framework checkout is forcing the global installed binary via AGENTPLANE_USE_GLOBAL_IN_FRAMEWORK=1. Unset it unless that override is intentional."
|
|
31
28
|
: null;
|
|
32
29
|
return [
|
|
33
30
|
...(warning ? [warning] : []),
|
|
@@ -34,7 +34,7 @@ export const guardCommitSpec = {
|
|
|
34
34
|
kind: "boolean",
|
|
35
35
|
name: "allow-tasks",
|
|
36
36
|
default: false,
|
|
37
|
-
description: "Allow
|
|
37
|
+
description: "Allow the tasks export snapshot plus artifacts under the active task subtree.",
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
kind: "boolean",
|
|
@@ -14,5 +14,10 @@ export declare function stageAllowlist(opts: {
|
|
|
14
14
|
allow: string[];
|
|
15
15
|
allowTasks: boolean;
|
|
16
16
|
tasksPath: string;
|
|
17
|
+
workflowDir?: string;
|
|
18
|
+
taskId?: string;
|
|
19
|
+
allowTaskOnly?: boolean;
|
|
20
|
+
emptyAllowMessage?: string;
|
|
21
|
+
noMatchMessage?: string;
|
|
17
22
|
}): Promise<string[]>;
|
|
18
23
|
//# sourceMappingURL=allow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allow.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/allow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"allow.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/allow.ts"],"names":[],"mappings":"AAOA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAkBvF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAe9D;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOpB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,cAAc,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuDpB"}
|
|
@@ -2,6 +2,7 @@ import { resolveProject } from "@agentplaneorg/core";
|
|
|
2
2
|
import { exitCodeForError } from "../../../cli/exit-codes.js";
|
|
3
3
|
import { gitPathIsUnderPrefix, normalizeGitPathPrefix } from "../../../shared/git-path.js";
|
|
4
4
|
import { CliError } from "../../../shared/errors.js";
|
|
5
|
+
import { taskArtifactPrefixes } from "../../../shared/protected-paths.js";
|
|
5
6
|
import { GitContext } from "../../shared/git-context.js";
|
|
6
7
|
import { loadCommandContext } from "../../shared/task-backend.js";
|
|
7
8
|
function normalizeAllowPrefixes(prefixes) {
|
|
@@ -75,28 +76,32 @@ export async function stageAllowlist(opts) {
|
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
const allow = normalizeAllowPrefixes(opts.allow);
|
|
78
|
-
if (allow.
|
|
79
|
+
if (allow.includes(".")) {
|
|
79
80
|
throw new CliError({
|
|
80
81
|
exitCode: 2,
|
|
81
82
|
code: "E_USAGE",
|
|
82
|
-
message: "
|
|
83
|
+
message: "Repo-wide allowlist ('.') is not allowed; choose minimal prefixes (tip: `agentplane guard suggest-allow --format args`).",
|
|
83
84
|
});
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
+
const taskAllow = taskArtifactPrefixes({
|
|
87
|
+
tasksPath: opts.tasksPath,
|
|
88
|
+
workflowDir: opts.workflowDir,
|
|
89
|
+
taskId: opts.taskId,
|
|
90
|
+
});
|
|
91
|
+
const effectiveAllow = normalizeAllowPrefixes(opts.allowTasks ? [...allow, ...taskAllow] : allow);
|
|
92
|
+
if (effectiveAllow.length === 0 || (allow.length === 0 && opts.allowTaskOnly !== true)) {
|
|
86
93
|
throw new CliError({
|
|
87
94
|
exitCode: 2,
|
|
88
95
|
code: "E_USAGE",
|
|
89
|
-
message:
|
|
96
|
+
message: opts.emptyAllowMessage ?? "Provide at least one allowed prefix",
|
|
90
97
|
});
|
|
91
98
|
}
|
|
92
|
-
const denied =
|
|
93
|
-
if (!opts.allowTasks)
|
|
94
|
-
denied.add(opts.tasksPath);
|
|
99
|
+
const denied = opts.allowTasks ? [] : taskAllow;
|
|
95
100
|
const staged = [];
|
|
96
101
|
for (const filePath of changed) {
|
|
97
|
-
if (denied.
|
|
102
|
+
if (denied.some((prefix) => gitPathIsUnderPrefix(filePath, prefix)))
|
|
98
103
|
continue;
|
|
99
|
-
if (
|
|
104
|
+
if (effectiveAllow.some((prefix) => gitPathIsUnderPrefix(filePath, prefix))) {
|
|
100
105
|
staged.push(filePath);
|
|
101
106
|
}
|
|
102
107
|
}
|
|
@@ -105,7 +110,7 @@ export async function stageAllowlist(opts) {
|
|
|
105
110
|
throw new CliError({
|
|
106
111
|
exitCode: 2,
|
|
107
112
|
code: "E_USAGE",
|
|
108
|
-
message: "No changes matched allowed prefixes (update --commit-allow)",
|
|
113
|
+
message: opts.noMatchMessage ?? "No changes matched allowed prefixes (update --commit-allow)",
|
|
109
114
|
});
|
|
110
115
|
}
|
|
111
116
|
// `git add <pathspec>` is not reliable for staging deletes/renames across versions/configs.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commands.ts"],"names":[],"mappings":"AAKA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAQvF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAyLxE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAa9E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmMlB"}
|
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { mapCoreError } from "../../../cli/error-map.js";
|
|
2
|
-
import { successMessage } from "../../../cli/output.js";
|
|
2
|
+
import { infoMessage, successMessage } from "../../../cli/output.js";
|
|
3
|
+
import { stripAnsi } from "../../../cli/shared/ansi.js";
|
|
3
4
|
import { withDiagnosticContext } from "../../../shared/diagnostics.js";
|
|
4
5
|
import { CliError } from "../../../shared/errors.js";
|
|
5
6
|
import { loadCommandContext } from "../../shared/task-backend.js";
|
|
6
7
|
import { loadTaskFromContext } from "../../shared/task-backend.js";
|
|
7
8
|
import { execFileAsync, gitEnv } from "../../shared/git.js";
|
|
8
9
|
import { ensureReconciledBeforeMutation } from "../../shared/reconcile-check.js";
|
|
9
|
-
import { suggestAllowPrefixes } from "./allow.js";
|
|
10
|
+
import { stageAllowlist, suggestAllowPrefixes } from "./allow.js";
|
|
10
11
|
import { buildCloseCommitMessage, taskReadmePathForTask } from "./close-message.js";
|
|
11
12
|
import { buildGitCommitEnv } from "./env.js";
|
|
12
13
|
import { guardCommitCheck } from "./policy.js";
|
|
14
|
+
const COMMIT_FAILURE_SIGNAL_PATTERNS = [
|
|
15
|
+
/Code style issues found/i,
|
|
16
|
+
/Run Prettier with --write/i,
|
|
17
|
+
/\bESLint\b/i,
|
|
18
|
+
/\b[0-9]+\s+problems?\b/i,
|
|
19
|
+
/\berror\b/i,
|
|
20
|
+
/\bfailed\b/i,
|
|
21
|
+
/✖/,
|
|
22
|
+
];
|
|
23
|
+
const FORMATTER_SIGNAL_PATTERNS = [
|
|
24
|
+
/Code style issues found/i,
|
|
25
|
+
/Run Prettier with --write/i,
|
|
26
|
+
];
|
|
27
|
+
const ESLINT_SIGNAL_PATTERNS = [/\bESLint\b/i, /\b[0-9]+\s+problems?\b/i];
|
|
13
28
|
function readText(value) {
|
|
14
29
|
if (typeof value === "string")
|
|
15
30
|
return value;
|
|
@@ -21,16 +36,103 @@ function summarizeOutput(raw) {
|
|
|
21
36
|
const lines = raw
|
|
22
37
|
.replaceAll("\r\n", "\n")
|
|
23
38
|
.split("\n")
|
|
24
|
-
.map((line) => line.trimEnd())
|
|
39
|
+
.map((line) => stripAnsi(line).trimEnd())
|
|
25
40
|
.filter((line) => line.trim().length > 0)
|
|
26
41
|
.map((line) => (line.length > 180 ? `${line.slice(0, 180)} [truncated]` : line));
|
|
27
42
|
if (lines.length <= 12)
|
|
28
43
|
return lines;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
44
|
+
const selected = new Set();
|
|
45
|
+
for (let index = 0; index < Math.min(6, lines.length); index += 1) {
|
|
46
|
+
selected.add(index);
|
|
47
|
+
}
|
|
48
|
+
for (let index = Math.max(lines.length - 6, 0); index < lines.length; index += 1) {
|
|
49
|
+
selected.add(index);
|
|
50
|
+
}
|
|
51
|
+
for (const [index, line] of lines.entries()) {
|
|
52
|
+
if (selected.has(index))
|
|
53
|
+
continue;
|
|
54
|
+
if (COMMIT_FAILURE_SIGNAL_PATTERNS.some((pattern) => pattern.test(line))) {
|
|
55
|
+
selected.add(index);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const ordered = [...selected].toSorted((a, b) => a - b);
|
|
59
|
+
const summary = [];
|
|
60
|
+
let previous = -1;
|
|
61
|
+
for (const index of ordered) {
|
|
62
|
+
if (previous >= 0 && index - previous > 1) {
|
|
63
|
+
summary.push(`[${index - previous - 1} lines omitted]`);
|
|
64
|
+
}
|
|
65
|
+
summary.push(lines[index] ?? "");
|
|
66
|
+
previous = index;
|
|
67
|
+
}
|
|
68
|
+
return summary;
|
|
69
|
+
}
|
|
70
|
+
function detectCommitFailureSignal(output) {
|
|
71
|
+
if (FORMATTER_SIGNAL_PATTERNS.some((pattern) => pattern.test(output))) {
|
|
72
|
+
return "formatter";
|
|
73
|
+
}
|
|
74
|
+
if (ESLINT_SIGNAL_PATTERNS.some((pattern) => pattern.test(output))) {
|
|
75
|
+
return "eslint";
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function commitFailureDiagnostic(phase, output) {
|
|
80
|
+
const signal = detectCommitFailureSignal(output);
|
|
81
|
+
if (signal === "formatter") {
|
|
82
|
+
return {
|
|
83
|
+
state: phase === "close_commit"
|
|
84
|
+
? "git rejected the generated close commit"
|
|
85
|
+
: "git rejected the requested task-scoped commit",
|
|
86
|
+
likelyCause: phase === "close_commit"
|
|
87
|
+
? "a formatting check in the pre-commit path rejected the deterministic close commit after the task README was staged"
|
|
88
|
+
: "a formatting check in the pre-commit path rejected the staged task-scoped commit",
|
|
89
|
+
nextAction: {
|
|
90
|
+
command: "bun run format",
|
|
91
|
+
reason: "apply formatter fixes before retrying the commit flow",
|
|
92
|
+
reasonCode: "git_pre_commit_format",
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (signal === "eslint") {
|
|
97
|
+
return {
|
|
98
|
+
state: phase === "close_commit"
|
|
99
|
+
? "git rejected the generated close commit"
|
|
100
|
+
: "git rejected the requested task-scoped commit",
|
|
101
|
+
likelyCause: phase === "close_commit"
|
|
102
|
+
? "a lint check in the pre-commit path rejected the deterministic close commit after the task README was staged"
|
|
103
|
+
: "a lint check in the pre-commit path rejected the staged task-scoped commit",
|
|
104
|
+
nextAction: {
|
|
105
|
+
command: "bun run lint:core",
|
|
106
|
+
reason: "rerun lint and fix the reported error before retrying the commit flow",
|
|
107
|
+
reasonCode: "git_pre_commit_lint",
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (phase === "close_commit") {
|
|
112
|
+
return {
|
|
113
|
+
state: "git rejected the generated close commit",
|
|
114
|
+
likelyCause: "a hook or commit policy blocked the deterministic task close commit after the task README was staged",
|
|
115
|
+
nextAction: {
|
|
116
|
+
command: "git status --short --untracked-files=no",
|
|
117
|
+
reason: "inspect the staged close-commit payload before fixing the hook or policy failure",
|
|
118
|
+
reasonCode: "git_close_commit_blocked",
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
state: "git rejected the requested task-scoped commit",
|
|
124
|
+
likelyCause: "a hook or commit policy blocked the staged changes after guard validation passed",
|
|
125
|
+
nextAction: {
|
|
126
|
+
command: "git status --short --untracked-files=no",
|
|
127
|
+
reason: "inspect the staged task-scoped payload before fixing the hook or policy failure",
|
|
128
|
+
reasonCode: "git_task_commit_blocked",
|
|
129
|
+
},
|
|
130
|
+
};
|
|
32
131
|
}
|
|
33
|
-
function
|
|
132
|
+
function hasExplicitCommitScope(opts) {
|
|
133
|
+
return opts.allow.some((prefix) => prefix.trim().length > 0) || opts.allowTasks;
|
|
134
|
+
}
|
|
135
|
+
function asCommitFailure(err, phase) {
|
|
34
136
|
if (err instanceof Error) {
|
|
35
137
|
const e = err;
|
|
36
138
|
const cmd = typeof e.cmd === "string" ? e.cmd : "";
|
|
@@ -51,15 +153,7 @@ function asCommitFailure(err) {
|
|
|
51
153
|
exitCode: 5,
|
|
52
154
|
code: "E_GIT",
|
|
53
155
|
message: lines.join("\n"),
|
|
54
|
-
context: withDiagnosticContext({ command: "commit" },
|
|
55
|
-
state: "git rejected the generated close commit",
|
|
56
|
-
likelyCause: "a hook or commit policy blocked the deterministic task close commit after the task README was staged",
|
|
57
|
-
nextAction: {
|
|
58
|
-
command: "git status --short --untracked-files=no",
|
|
59
|
-
reason: "inspect the staged close-commit payload before fixing the hook or policy failure",
|
|
60
|
-
reasonCode: "git_close_commit_blocked",
|
|
61
|
-
},
|
|
62
|
-
}),
|
|
156
|
+
context: withDiagnosticContext({ command: "commit" }, commitFailureDiagnostic(phase, output)),
|
|
63
157
|
});
|
|
64
158
|
}
|
|
65
159
|
return null;
|
|
@@ -235,6 +329,31 @@ export async function cmdCommit(opts) {
|
|
|
235
329
|
});
|
|
236
330
|
}
|
|
237
331
|
await ensureReconciledBeforeMutation({ ctx, command: "commit" });
|
|
332
|
+
let autoStaged = [];
|
|
333
|
+
const staged = await ctx.git.statusStagedPaths();
|
|
334
|
+
if (staged.length === 0) {
|
|
335
|
+
if (!hasExplicitCommitScope(opts)) {
|
|
336
|
+
throw new CliError({
|
|
337
|
+
exitCode: 2,
|
|
338
|
+
code: "E_USAGE",
|
|
339
|
+
message: "No staged files and no commit allowlist. Pass --allow <path-prefix>, use --allow-tasks for active task artifacts, or stage files manually.",
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
autoStaged = await stageAllowlist({
|
|
343
|
+
ctx,
|
|
344
|
+
allow: opts.allow,
|
|
345
|
+
allowTasks: opts.allowTasks,
|
|
346
|
+
tasksPath: ctx.config.paths.tasks_path,
|
|
347
|
+
workflowDir: ctx.config.paths.workflow_dir,
|
|
348
|
+
taskId: opts.taskId,
|
|
349
|
+
allowTaskOnly: true,
|
|
350
|
+
emptyAllowMessage: "No staged files and no commit allowlist. Pass --allow <path-prefix>, use --allow-tasks for active task artifacts, or stage files manually.",
|
|
351
|
+
noMatchMessage: "No changed files matched the commit allowlist (adjust --allow / --allow-tasks or stage files manually).",
|
|
352
|
+
});
|
|
353
|
+
if (!opts.quiet) {
|
|
354
|
+
process.stdout.write(`${infoMessage(`commit auto-staged ${autoStaged.length} path(s) from allowlist`)}\n`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
238
357
|
await guardCommitCheck({
|
|
239
358
|
ctx,
|
|
240
359
|
cwd: opts.cwd,
|
|
@@ -263,14 +382,14 @@ export async function cmdCommit(opts) {
|
|
|
263
382
|
await ctx.git.commit({ message: opts.message, env });
|
|
264
383
|
if (!opts.quiet) {
|
|
265
384
|
const { hash, subject } = await ctx.git.headHashSubject();
|
|
266
|
-
process.stdout.write(`${successMessage("committed", `${hash?.slice(0, 12) ?? ""} ${subject ?? ""}`.trim())}\n`);
|
|
385
|
+
process.stdout.write(`${successMessage("committed", `${hash?.slice(0, 12) ?? ""} ${subject ?? ""}`.trim(), autoStaged.length > 0 ? `staged=${autoStaged.join(", ")}` : undefined)}\n`);
|
|
267
386
|
}
|
|
268
387
|
return 0;
|
|
269
388
|
}
|
|
270
389
|
catch (err) {
|
|
271
390
|
if (err instanceof CliError)
|
|
272
391
|
throw err;
|
|
273
|
-
const commitFailure = asCommitFailure(err);
|
|
392
|
+
const commitFailure = asCommitFailure(err, opts.close ? "close_commit" : "task_commit");
|
|
274
393
|
if (commitFailure)
|
|
275
394
|
throw commitFailure;
|
|
276
395
|
throw mapCoreError(err, { command: "commit", root: opts.rootOverride ?? null });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/comment-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAQ/E,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAiEvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"comment-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/comment-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAQ/E,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAiEvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA2F/D"}
|
|
@@ -68,6 +68,8 @@ export async function commitFromComment(opts) {
|
|
|
68
68
|
allow: allowPrefixes,
|
|
69
69
|
allowTasks: opts.allowTasks,
|
|
70
70
|
tasksPath: opts.config.paths.tasks_path,
|
|
71
|
+
workflowDir: opts.config.paths.workflow_dir,
|
|
72
|
+
taskId: opts.taskId,
|
|
71
73
|
});
|
|
72
74
|
const message = deriveCommitMessageFromComment({
|
|
73
75
|
taskId: opts.taskId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/hooks/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/hooks/index.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,UAAU,mDAAoD,CAAC;AA8G5E,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BlB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsGlB"}
|
|
@@ -5,13 +5,11 @@ import { evaluatePolicy } from "../../policy/evaluate.js";
|
|
|
5
5
|
import { mapBackendError, mapCoreError } from "../../cli/error-map.js";
|
|
6
6
|
import { fileExists } from "../../cli/fs-utils.js";
|
|
7
7
|
import { infoMessage, successMessage } from "../../cli/output.js";
|
|
8
|
-
import { resolveCommitEmojiForAgent } from "../../shared/agent-emoji.js";
|
|
9
8
|
import { CliError } from "../../shared/errors.js";
|
|
10
9
|
import { GitContext } from "../shared/git-context.js";
|
|
11
10
|
import { throwIfPolicyDenied } from "../shared/policy-deny.js";
|
|
12
11
|
import { gitCurrentBranch, gitRevParse } from "../shared/git-ops.js";
|
|
13
12
|
import { isPathWithin } from "../shared/path.js";
|
|
14
|
-
import { readDirectWorkLock } from "../../shared/direct-work-lock.js";
|
|
15
13
|
const HOOK_MARKER = "agentplane-hook";
|
|
16
14
|
const SHIM_MARKER = "agentplane-hook-shim";
|
|
17
15
|
export const HOOK_NAMES = ["commit-msg", "pre-commit", "pre-push"];
|
|
@@ -201,40 +199,15 @@ export async function cmdHooksRun(opts) {
|
|
|
201
199
|
const loaded = await loadConfig(resolved.agentplaneDir);
|
|
202
200
|
const taskId = (process.env.AGENTPLANE_TASK_ID ?? "").trim();
|
|
203
201
|
const statusTo = (process.env.AGENTPLANE_STATUS_TO ?? "").trim().toUpperCase();
|
|
204
|
-
const agentsDirAbs = path.join(resolved.gitRoot, loaded.config.paths.agents_dir);
|
|
205
|
-
let agentId = (process.env.AGENTPLANE_AGENT_ID ?? "").trim();
|
|
206
|
-
if (!agentId && loaded.config.workflow_mode === "direct" && taskId) {
|
|
207
|
-
const lock = await readDirectWorkLock(resolved.agentplaneDir);
|
|
208
|
-
const lockAgent = lock?.agent?.trim() ?? "";
|
|
209
|
-
if (lock?.task_id === taskId && lockAgent)
|
|
210
|
-
agentId = lockAgent;
|
|
211
|
-
}
|
|
212
202
|
const emoji = subject.split(/\s+/).find(Boolean) ?? "";
|
|
213
|
-
if (taskId) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
" ✅ <TASK_SUFFIX> <scope>: <summary>",
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
else if (agentId) {
|
|
226
|
-
const expectedEmoji = await resolveCommitEmojiForAgent({ agentsDirAbs, agentId });
|
|
227
|
-
if (emoji !== expectedEmoji) {
|
|
228
|
-
throw new CliError({
|
|
229
|
-
exitCode: 5,
|
|
230
|
-
code: "E_GIT",
|
|
231
|
-
message: "Commit emoji does not match the executor agent policy.\n" +
|
|
232
|
-
`executor_agent=${agentId}\n` +
|
|
233
|
-
"Expected:\n" +
|
|
234
|
-
` ${expectedEmoji} <TASK_SUFFIX> <scope>: <summary>`,
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
}
|
|
203
|
+
if (taskId && statusTo === "DONE" && emoji !== "✅") {
|
|
204
|
+
throw new CliError({
|
|
205
|
+
exitCode: 5,
|
|
206
|
+
code: "E_GIT",
|
|
207
|
+
message: "Finish commits must use a checkmark emoji.\n" +
|
|
208
|
+
"Expected:\n" +
|
|
209
|
+
" ✅ <TASK_SUFFIX> <scope>: <summary>",
|
|
210
|
+
});
|
|
238
211
|
}
|
|
239
212
|
const res = evaluatePolicy({
|
|
240
213
|
action: "hook_commit_msg",
|