@open-agent-toolkit/cli 0.3.9 → 0.3.11
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 +2 -1
- package/assets/bundle-metadata.json +1 -1
- package/assets/config/dispatch-matrix-recommendation.json +6 -6
- package/assets/docs/cli-utilities/configuration.md +12 -8
- package/assets/docs/cli-utilities/meta.json +13 -0
- package/assets/docs/cli-utilities/tool-packs.md +8 -2
- package/assets/docs/cli-utilities/workflow-gates.md +14 -1
- package/assets/docs/contributing/code.md +8 -2
- package/assets/docs/contributing/documentation.md +7 -1
- package/assets/docs/contributing/meta.json +15 -0
- package/assets/docs/contributing/updating-model-guidance.md +34 -6
- package/assets/docs/contributing/verifying-cursor-pins.md +38 -9
- package/assets/docs/docs-tooling/add-docs-to-a-repo.md +14 -5
- package/assets/docs/docs-tooling/commands.md +26 -8
- package/assets/docs/docs-tooling/meta.json +4 -0
- package/assets/docs/docs-tooling/workflows.md +2 -2
- package/assets/docs/guide/meta.json +4 -0
- package/assets/docs/meta.json +14 -0
- package/assets/docs/provider-sync/instruction-sync.md +8 -0
- package/assets/docs/provider-sync/meta.json +11 -0
- package/assets/docs/provider-sync/providers.md +4 -4
- package/assets/docs/provider-sync/scope-and-surface.md +3 -4
- package/assets/docs/reference/cli-reference.md +5 -2
- package/assets/docs/reference/docs-index-contract.md +22 -6
- package/assets/docs/reference/file-locations.md +7 -2
- package/assets/docs/reference/index.md +1 -1
- package/assets/docs/reference/meta.json +10 -0
- package/assets/docs/reference/troubleshooting.md +41 -6
- package/assets/docs/workflows/ideas/meta.json +4 -0
- package/assets/docs/workflows/meta.json +4 -0
- package/assets/docs/workflows/projects/cursor-cloud.md +8 -3
- package/assets/docs/workflows/projects/dispatch-ceiling.md +21 -14
- package/assets/docs/workflows/projects/evidence-layers.md +6 -8
- package/assets/docs/workflows/projects/implementation-execution.md +34 -5
- package/assets/docs/workflows/projects/lifecycle.md +7 -1
- package/assets/docs/workflows/projects/meta.json +25 -0
- package/assets/docs/workflows/projects/orchestration-model.md +5 -6
- package/assets/docs/workflows/skills/meta.json +10 -0
- package/assets/docs/workflows/skills/recon.md +28 -3
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-cursor-cloud-projects/SKILL.md +30 -16
- package/assets/skills/oat-dispatch-subagents/SKILL.md +4 -12
- package/assets/skills/oat-dispatch-subagents/references/managed-claude-example.json +1 -1
- package/assets/skills/oat-dispatch-subagents/references/provider-codex.md +51 -0
- package/assets/skills/oat-dispatch-subagents/references/provider-cursor.md +5 -2
- package/assets/skills/oat-dispatch-subagents/references/record-schema.md +8 -7
- package/assets/skills/oat-docs-analyze/SKILL.md +28 -3
- package/assets/skills/oat-docs-apply/SKILL.md +3 -3
- package/assets/skills/oat-docs-authoring/SKILL.md +1 -1
- package/assets/skills/oat-docs-authoring/references/oat-fumadocs-contract.md +5 -2
- package/assets/skills/oat-docs-bootstrap/SKILL.md +4 -3
- package/assets/skills/oat-docs-bootstrap/assets/AGENTS.md.template +3 -3
- package/assets/skills/oat-pjm-decision/SKILL.md +3 -2
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +4 -4
- package/assets/skills/oat-project-complete/SKILL.md +47 -2
- package/assets/skills/oat-project-design/SKILL.md +10 -6
- package/assets/skills/oat-project-discover/SKILL.md +3 -3
- package/assets/skills/oat-project-dispatch-subagents/SKILL.md +3 -10
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +4 -4
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +135 -3
- package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +8 -10
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +4 -4
- package/assets/skills/oat-project-implement/references/plan-and-resume.md +1 -1
- package/assets/skills/oat-project-import-plan/SKILL.md +3 -3
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +4 -4
- package/assets/skills/oat-project-new/SKILL.md +3 -3
- package/assets/skills/oat-project-next/SKILL.md +50 -7
- package/assets/skills/oat-project-plan/SKILL.md +4 -4
- package/assets/skills/oat-project-plan-writing/SKILL.md +4 -4
- package/assets/skills/oat-project-pr-final/SKILL.md +11 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +4 -4
- package/assets/skills/oat-project-promote-spec-driven/SKILL.md +2 -2
- package/assets/skills/oat-project-quick-start/SKILL.md +12 -8
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +4 -4
- package/assets/skills/oat-project-retro/SKILL.md +6 -3
- package/assets/skills/oat-project-review-provide/SKILL.md +2 -2
- package/assets/skills/oat-project-review-provide-remote/SKILL.md +2 -2
- package/assets/skills/oat-project-spec/SKILL.md +3 -3
- package/assets/skills/oat-project-summary/SKILL.md +22 -3
- package/assets/skills/oat-repo-improve/SKILL.md +2 -2
- package/assets/skills/recon/SKILL.md +24 -3
- package/assets/skills/recon/references/packet-contract.md +36 -6
- package/assets/skills/recon/references/profiles.md +3 -0
- package/assets/skills/recon/references/worker-contract.md +16 -3
- package/assets/skills/recon/scripts/create-review-brief.mjs +17 -86
- package/assets/skills/recon/scripts/lib/contracts.mjs +158 -41
- package/assets/skills/recon/scripts/lib/review-binding.mjs +123 -0
- package/assets/skills/recon/scripts/lib/routing.mjs +5 -2
- package/assets/skills/recon/scripts/reconcile-ledger.mjs +18 -7
- package/assets/skills/recon/scripts/render-packet.mjs +93 -1
- package/assets/skills/recon/scripts/validate-packet.mjs +119 -88
- package/assets/skills/subagent-orchestration/SKILL.md +1 -1
- package/assets/skills/subagent-orchestration/references/evidence-and-refresh.md +20 -8
- package/assets/skills/subagent-orchestration/references/provider-claude.md +25 -12
- package/assets/skills/subagent-orchestration/references/provider-codex.md +27 -18
- package/assets/skills/subagent-orchestration/references/provider-cursor.md +40 -10
- package/assets/templates/state.md +1 -0
- package/dist/commands/backlog/new.d.ts +2 -2
- package/dist/commands/backlog/new.d.ts.map +1 -1
- package/dist/commands/backlog/new.js +2 -2
- package/dist/commands/decision/new.d.ts +2 -2
- package/dist/commands/decision/new.d.ts.map +1 -1
- package/dist/commands/decision/new.js +2 -2
- package/dist/commands/docs/nav/contents.d.ts +9 -0
- package/dist/commands/docs/nav/contents.d.ts.map +1 -1
- package/dist/commands/docs/nav/contents.js +7 -2
- package/dist/commands/docs/nav/fumadocs.d.ts +51 -0
- package/dist/commands/docs/nav/fumadocs.d.ts.map +1 -0
- package/dist/commands/docs/nav/fumadocs.js +301 -0
- package/dist/commands/docs/nav/sync.d.ts +31 -1
- package/dist/commands/docs/nav/sync.d.ts.map +1 -1
- package/dist/commands/docs/nav/sync.js +163 -6
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/instructions/instructions.utils.d.ts +19 -0
- package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.js +89 -17
- package/dist/commands/instructions/sync/sync.d.ts.map +1 -1
- package/dist/commands/instructions/sync/sync.js +49 -2
- package/dist/commands/pjm/init.d.ts.map +1 -1
- package/dist/commands/pjm/init.js +2 -2
- package/dist/commands/project/closeout-check/closeout-invariant.d.ts +97 -0
- package/dist/commands/project/closeout-check/closeout-invariant.d.ts.map +1 -0
- package/dist/commands/project/closeout-check/closeout-invariant.js +301 -0
- package/dist/commands/project/closeout-check/index.d.ts +38 -0
- package/dist/commands/project/closeout-check/index.d.ts.map +1 -0
- package/dist/commands/project/closeout-check/index.js +117 -0
- package/dist/commands/project/complete-state/index.d.ts +4 -0
- package/dist/commands/project/complete-state/index.d.ts.map +1 -1
- package/dist/commands/project/complete-state/index.js +11 -13
- package/dist/commands/project/dispatch/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch/index.js +6 -30
- package/dist/commands/project/dispatch/record.d.ts +9 -18
- package/dist/commands/project/dispatch/record.d.ts.map +1 -1
- package/dist/commands/project/dispatch/record.js +15 -212
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +2 -0
- package/dist/commands/project/new/scaffold.d.ts +0 -1
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +19 -20
- package/dist/commands/project/promote/promote.d.ts +2 -2
- package/dist/commands/project/promote/promote.d.ts.map +1 -1
- package/dist/commands/project/promote/promote.js +13 -11
- package/dist/commands/shared/frontmatter.d.ts +21 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +70 -4
- package/dist/commands/shared/template-source.d.ts +29 -0
- package/dist/commands/shared/template-source.d.ts.map +1 -0
- package/dist/commands/{pjm → shared}/template-source.js +24 -7
- package/dist/commands/state/generate.js +2 -2
- package/dist/commands/template/index.d.ts +10 -0
- package/dist/commands/template/index.d.ts.map +1 -0
- package/dist/commands/template/index.js +87 -0
- package/dist/commands/template/resolve.d.ts +31 -0
- package/dist/commands/template/resolve.d.ts.map +1 -0
- package/dist/commands/template/resolve.js +86 -0
- package/dist/fs/io.d.ts +0 -41
- package/dist/fs/io.d.ts.map +1 -1
- package/dist/fs/io.js +2 -414
- package/dist/providers/claude/dispatch-envelope.d.ts.map +1 -1
- package/dist/providers/claude/dispatch-envelope.js +1 -0
- package/dist/providers/claude/targets.d.ts +1 -0
- package/dist/providers/claude/targets.d.ts.map +1 -1
- package/dist/providers/claude/targets.js +3 -1
- package/dist/providers/codex/codec/shared.d.ts +3 -0
- package/dist/providers/codex/codec/shared.d.ts.map +1 -1
- package/dist/providers/codex/codec/shared.js +4 -0
- package/dist/providers/cursor/codec/catalog.d.ts +2 -2
- package/dist/providers/cursor/codec/catalog.d.ts.map +1 -1
- package/dist/providers/cursor/codec/catalog.js +45 -0
- package/dist/providers/cursor/codec/mapping-validation.d.ts +4 -0
- package/dist/providers/cursor/codec/mapping-validation.d.ts.map +1 -0
- package/dist/providers/cursor/codec/mapping-validation.js +25 -0
- package/dist/providers/cursor/codec/materialize.d.ts.map +1 -1
- package/dist/providers/cursor/codec/materialize.js +2 -11
- package/dist/providers/cursor/codec/sync-extension.d.ts.map +1 -1
- package/dist/providers/cursor/codec/sync-extension.js +2 -11
- package/dist/providers/identity/absolute-paths.d.ts +4 -13
- package/dist/providers/identity/absolute-paths.d.ts.map +1 -1
- package/dist/providers/identity/absolute-paths.js +4 -17
- package/dist/providers/identity/generic-dispatch-record.d.ts +1 -1
- package/dist/providers/identity/generic-dispatch-record.js +2 -2
- package/dist/providers/identity/oat-dispatch-record.d.ts +4 -357
- package/dist/providers/identity/oat-dispatch-record.d.ts.map +1 -1
- package/dist/providers/identity/oat-dispatch-record.js +4 -236
- package/dist/release/public-package-contract.d.ts.map +1 -1
- package/dist/release/public-package-contract.js +12 -4
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +32 -6
- package/package.json +2 -2
- package/dist/commands/pjm/template-source.d.ts +0 -14
- package/dist/commands/pjm/template-source.d.ts.map +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFile as defaultReadFile } from 'node:fs/promises';
|
|
2
|
+
import { buildCommandContext, type CommandContext } from '../../../app/command-context.js';
|
|
3
|
+
import { resolveEffectiveConfig } from '../../../config/resolve.js';
|
|
4
|
+
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { type CloseoutResult } from './closeout-invariant.js';
|
|
7
|
+
export { evaluateCloseout, formatCloseoutRefusal, type CloseoutResult, } from './closeout-invariant.js';
|
|
8
|
+
export interface CloseoutCheckDependencies {
|
|
9
|
+
buildCommandContext: (options: Parameters<typeof buildCommandContext>[0]) => CommandContext;
|
|
10
|
+
resolveProjectRoot: (cwd: string) => Promise<string>;
|
|
11
|
+
resolveEffectiveConfig: typeof resolveEffectiveConfig;
|
|
12
|
+
readFile: typeof defaultReadFile;
|
|
13
|
+
dirExists: typeof dirExists;
|
|
14
|
+
fileExists: typeof fileExists;
|
|
15
|
+
/**
|
|
16
|
+
* Environment read for `OAT_AUTONOMOUS`. Injectable so a caller that forgets
|
|
17
|
+
* `--autonomous` under `OAT_AUTONOMOUS=1` still cannot fail open.
|
|
18
|
+
*/
|
|
19
|
+
env: NodeJS.ProcessEnv;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_CLOSEOUT_CHECK_DEPENDENCIES: CloseoutCheckDependencies;
|
|
22
|
+
export interface ProjectCloseoutCheck {
|
|
23
|
+
repoRoot: string;
|
|
24
|
+
targetProjectPath: string;
|
|
25
|
+
statePath: string;
|
|
26
|
+
stateContent: string;
|
|
27
|
+
result: CloseoutResult;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a project, read its `state.md` from disk, and evaluate the closeout
|
|
31
|
+
* invariant. Shared by `closeout-check` and `complete-state` so both read the
|
|
32
|
+
* same inputs and print the same refusal.
|
|
33
|
+
*/
|
|
34
|
+
export declare function checkProjectCloseout(projectPath: string, options: {
|
|
35
|
+
autonomous: boolean;
|
|
36
|
+
}, context: CommandContext, dependencies: Pick<CloseoutCheckDependencies, 'resolveProjectRoot' | 'resolveEffectiveConfig' | 'readFile' | 'dirExists' | 'fileExists' | 'env'>): Promise<ProjectCloseoutCheck>;
|
|
37
|
+
export declare function createProjectCloseoutCheckCommand(overrides?: Partial<CloseoutCheckDependencies>): Command;
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/closeout-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,yBAAyB;IACxC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,QAAQ,EAAE,OAAO,eAAe,CAAC;IACjC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,eAAO,MAAM,mCAAmC,EAAE,yBAQjD,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,EAChC,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,IAAI,CAChB,yBAAyB,EACvB,oBAAoB,GACpB,wBAAwB,GACxB,UAAU,GACV,WAAW,GACX,YAAY,GACZ,KAAK,CACR,GACA,OAAO,CAAC,oBAAoB,CAAC,CA+B/B;AAmED,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CA2BT"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { readFile as defaultReadFile } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, join } from 'node:path';
|
|
3
|
+
import { buildCommandContext } from '../../../app/command-context.js';
|
|
4
|
+
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
5
|
+
import { resolveEffectiveConfig } from '../../../config/resolve.js';
|
|
6
|
+
import { CliError } from '../../../errors/cli-error.js';
|
|
7
|
+
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
8
|
+
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { evaluateCloseout, formatCloseoutRefusal, } from './closeout-invariant.js';
|
|
11
|
+
export { evaluateCloseout, formatCloseoutRefusal, } from './closeout-invariant.js';
|
|
12
|
+
export const DEFAULT_CLOSEOUT_CHECK_DEPENDENCIES = {
|
|
13
|
+
buildCommandContext,
|
|
14
|
+
resolveProjectRoot,
|
|
15
|
+
resolveEffectiveConfig,
|
|
16
|
+
readFile: defaultReadFile,
|
|
17
|
+
dirExists,
|
|
18
|
+
fileExists,
|
|
19
|
+
env: process.env,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a project, read its `state.md` from disk, and evaluate the closeout
|
|
23
|
+
* invariant. Shared by `closeout-check` and `complete-state` so both read the
|
|
24
|
+
* same inputs and print the same refusal.
|
|
25
|
+
*/
|
|
26
|
+
export async function checkProjectCloseout(projectPath, options, context, dependencies) {
|
|
27
|
+
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
28
|
+
const targetProjectPath = isAbsolute(projectPath)
|
|
29
|
+
? projectPath
|
|
30
|
+
: join(repoRoot, projectPath);
|
|
31
|
+
if (!(await dependencies.dirExists(targetProjectPath))) {
|
|
32
|
+
throw new CliError(`Project not found: ${projectPath}`, 1);
|
|
33
|
+
}
|
|
34
|
+
const statePath = join(targetProjectPath, 'state.md');
|
|
35
|
+
if (!(await dependencies.fileExists(statePath))) {
|
|
36
|
+
throw new CliError(`Project state.md not found: ${statePath}`, 1);
|
|
37
|
+
}
|
|
38
|
+
const stateContent = await dependencies.readFile(statePath, 'utf8');
|
|
39
|
+
const result = await evaluateCloseout({
|
|
40
|
+
stateContent,
|
|
41
|
+
autonomousFlag: options.autonomous,
|
|
42
|
+
env: dependencies.env,
|
|
43
|
+
resolveConfigured: async () => {
|
|
44
|
+
const effective = await dependencies.resolveEffectiveConfig(repoRoot, join(context.home, '.oat'), dependencies.env);
|
|
45
|
+
const value = effective.resolved['workflow.postImplementSequence']?.value;
|
|
46
|
+
return value !== null && value !== undefined;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
return { repoRoot, targetProjectPath, statePath, stateContent, result };
|
|
50
|
+
}
|
|
51
|
+
async function runCloseoutCheck(projectPath, options, context, dependencies) {
|
|
52
|
+
try {
|
|
53
|
+
const { result } = await checkProjectCloseout(projectPath, { autonomous: options.autonomous ?? false }, context, dependencies);
|
|
54
|
+
if (result.status === 'incomplete') {
|
|
55
|
+
const message = formatCloseoutRefusal(projectPath, result);
|
|
56
|
+
if (context.json) {
|
|
57
|
+
context.logger.json({
|
|
58
|
+
status: 'incomplete',
|
|
59
|
+
projectPath,
|
|
60
|
+
invariant: result.invariant,
|
|
61
|
+
detail: result.detail,
|
|
62
|
+
route: result.route,
|
|
63
|
+
nextOwner: result.nextOwner,
|
|
64
|
+
inputs: result.inputs,
|
|
65
|
+
message,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
context.logger.info(message);
|
|
70
|
+
}
|
|
71
|
+
// Fail closed: a caller that ignores the JSON still stops.
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (context.json) {
|
|
76
|
+
context.logger.json({
|
|
77
|
+
status: result.status,
|
|
78
|
+
projectPath,
|
|
79
|
+
invariant: null,
|
|
80
|
+
route: null,
|
|
81
|
+
nextOwner: null,
|
|
82
|
+
inputs: result.inputs,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else if (result.status === 'complete') {
|
|
86
|
+
context.logger.info(`Closeout invariant satisfied for ${projectPath}: every stored step and the approval are recorded complete.`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
context.logger.info(`Closeout invariant not required for ${projectPath}: no snapshot, and the closeout is not configured, autonomous, or lite.`);
|
|
90
|
+
}
|
|
91
|
+
process.exitCode = 0;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
95
|
+
if (context.json) {
|
|
96
|
+
context.logger.json({ status: 'error', message });
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
context.logger.error(message);
|
|
100
|
+
}
|
|
101
|
+
process.exitCode = error instanceof CliError ? error.exitCode : 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export function createProjectCloseoutCheckCommand(overrides = {}) {
|
|
105
|
+
const dependencies = {
|
|
106
|
+
...DEFAULT_CLOSEOUT_CHECK_DEPENDENCIES,
|
|
107
|
+
...overrides,
|
|
108
|
+
};
|
|
109
|
+
return new Command('closeout-check')
|
|
110
|
+
.description('Report whether a project closeout snapshot permits terminal completion (read-only)')
|
|
111
|
+
.argument('<project-path>', 'Project path to check')
|
|
112
|
+
.option('--autonomous', 'Treat the closeout as autonomous (also implied by OAT_AUTONOMOUS=1)')
|
|
113
|
+
.action(async (projectPath, options, command) => {
|
|
114
|
+
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
115
|
+
await runCloseoutCheck(projectPath, options, context, dependencies);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile as defaultReadFile, writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
2
2
|
import { buildCommandContext, type CommandContext } from '../../../app/command-context.js';
|
|
3
|
+
import { resolveEffectiveConfig } from '../../../config/resolve.js';
|
|
3
4
|
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
4
5
|
import { Command } from 'commander';
|
|
5
6
|
interface ProjectCompleteStateDependencies {
|
|
@@ -9,6 +10,9 @@ interface ProjectCompleteStateDependencies {
|
|
|
9
10
|
writeFile: typeof defaultWriteFile;
|
|
10
11
|
dirExists: typeof dirExists;
|
|
11
12
|
fileExists: typeof fileExists;
|
|
13
|
+
resolveEffectiveConfig: typeof resolveEffectiveConfig;
|
|
14
|
+
/** Environment read for `OAT_AUTONOMOUS`; injectable for tests. */
|
|
15
|
+
env: NodeJS.ProcessEnv;
|
|
12
16
|
now: () => Date;
|
|
13
17
|
}
|
|
14
18
|
export declare function createProjectCompleteStateCommand(overrides?: Partial<ProjectCompleteStateDependencies>): Command;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/complete-state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,eAAe,EAC3B,SAAS,IAAI,gBAAgB,EAC9B,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/complete-state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,eAAe,EAC3B,SAAS,IAAI,gBAAgB,EAC9B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAMhF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAG/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,UAAU,gCAAgC;IACxC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,EAAE,OAAO,eAAe,CAAC;IACjC,SAAS,EAAE,OAAO,gBAAgB,CAAC;IACnC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AA4ED,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,gCAAgC,CAAM,GACxD,OAAO,CA+BT"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { readFile as defaultReadFile, writeFile as defaultWriteFile, } from 'node:fs/promises';
|
|
2
|
-
import { isAbsolute, join } from 'node:path';
|
|
3
2
|
import { buildCommandContext } from '../../../app/command-context.js';
|
|
3
|
+
import { checkProjectCloseout, formatCloseoutRefusal, } from '../../project/closeout-check/index.js';
|
|
4
4
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
5
|
+
import { resolveEffectiveConfig } from '../../../config/resolve.js';
|
|
5
6
|
import { CliError } from '../../../errors/cli-error.js';
|
|
6
7
|
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
7
8
|
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
@@ -15,24 +16,20 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
15
16
|
writeFile: defaultWriteFile,
|
|
16
17
|
dirExists,
|
|
17
18
|
fileExists,
|
|
19
|
+
resolveEffectiveConfig,
|
|
20
|
+
env: process.env,
|
|
18
21
|
now: () => new Date(),
|
|
19
22
|
};
|
|
20
|
-
function resolveTargetProjectPath(repoRoot, projectPath) {
|
|
21
|
-
return isAbsolute(projectPath) ? projectPath : join(repoRoot, projectPath);
|
|
22
|
-
}
|
|
23
23
|
async function runProjectCompleteState(projectPath, options, context, dependencies) {
|
|
24
24
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (!(await dependencies.fileExists(statePath))) {
|
|
32
|
-
throw new CliError(`Project state.md not found: ${statePath}`, 1);
|
|
25
|
+
// Refuse the same closeout invariant `oat project closeout-check` reports,
|
|
26
|
+
// before any write: a configured, autonomous, or lite closeout cannot
|
|
27
|
+
// reach terminal completion without its complete durable snapshot.
|
|
28
|
+
const { targetProjectPath, statePath, stateContent: content, result, } = await checkProjectCloseout(projectPath, { autonomous: options.autonomous ?? false }, context, dependencies);
|
|
29
|
+
if (result.status === 'incomplete') {
|
|
30
|
+
throw new CliError(formatCloseoutRefusal(projectPath, result), 1);
|
|
33
31
|
}
|
|
34
32
|
const now = dependencies.now();
|
|
35
|
-
const content = await dependencies.readFile(statePath, 'utf8');
|
|
36
33
|
const updatedContent = renderCompletedProjectState(content, {
|
|
37
34
|
archived: options.archived ?? false,
|
|
38
35
|
nowUtc: now.toISOString(),
|
|
@@ -78,6 +75,7 @@ export function createProjectCompleteStateCommand(overrides = {}) {
|
|
|
78
75
|
.description('Update a project state.md to the completed lifecycle shape')
|
|
79
76
|
.argument('<project-path>', 'Project path to update')
|
|
80
77
|
.option('--archived', 'Mark the completed project as archived locally')
|
|
78
|
+
.option('--autonomous', 'Treat the closeout as autonomous (also implied by OAT_AUTONOMOUS=1)')
|
|
81
79
|
.action(async (projectPath, options, command) => {
|
|
82
80
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
83
81
|
await runProjectCompleteState(projectPath, options, context, dependencies);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,MAAM,WAAW,kCAAkC;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AAiHD,wBAAgB,4BAA4B,CAC1C,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CA0BT"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { isAbsolute, join } from 'node:path';
|
|
3
2
|
import { buildCommandContext, } from '../../../app/command-context.js';
|
|
4
3
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
5
|
-
import {
|
|
6
|
-
import { resolveProjectRoot, validateRealPathWithinScope } from '../../../fs/paths.js';
|
|
4
|
+
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
7
5
|
import { Command } from 'commander';
|
|
8
6
|
import { createCanonicalRoleCommand } from './canonical-role.js';
|
|
9
7
|
import { recordProjectDispatch, redactDispatchMessage, } from './record.js';
|
|
@@ -19,16 +17,6 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
19
17
|
return Buffer.concat(chunks).toString('utf8');
|
|
20
18
|
},
|
|
21
19
|
};
|
|
22
|
-
async function resolveProjectPath(repoRoot, project) {
|
|
23
|
-
if (!project)
|
|
24
|
-
return null;
|
|
25
|
-
const candidate = isAbsolute(project) ? project : join(repoRoot, project);
|
|
26
|
-
const validated = await validateRealPathWithinScope(candidate, repoRoot);
|
|
27
|
-
if (!(await fileExists(join(validated.realPath, 'state.md')))) {
|
|
28
|
-
throw new Error('Project path must contain a readable state.md.');
|
|
29
|
-
}
|
|
30
|
-
return validated.realPath;
|
|
31
|
-
}
|
|
32
20
|
function axes(values) {
|
|
33
21
|
return values
|
|
34
22
|
.map(([name, value]) => `${name}=${value ?? 'not-reported'}`)
|
|
@@ -65,19 +53,14 @@ function runtimeIdentityLines(identity) {
|
|
|
65
53
|
}
|
|
66
54
|
async function runRecordCommand(options, context, dependencies) {
|
|
67
55
|
let repoRoot = null;
|
|
68
|
-
let projectPath = null;
|
|
69
56
|
try {
|
|
70
57
|
repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
71
|
-
projectPath = await resolveProjectPath(repoRoot, options.project);
|
|
72
58
|
const content = options.eventFile === '-'
|
|
73
59
|
? await dependencies.readStdin()
|
|
74
60
|
: await dependencies.readFile(options.eventFile);
|
|
75
61
|
// Hand the raw event to the recorder; it owns the single authoritative
|
|
76
62
|
// parse, and parsing twice would relabel the provenance of its own output.
|
|
77
|
-
const raw = await recordProjectDispatch({
|
|
78
|
-
projectPath,
|
|
79
|
-
input: JSON.parse(content),
|
|
80
|
-
});
|
|
63
|
+
const raw = await recordProjectDispatch({ input: JSON.parse(content) });
|
|
81
64
|
// The degradation reason is caller-influenced text on the success path, so
|
|
82
65
|
// it goes through the same single redaction boundary as every failure
|
|
83
66
|
// message. Producing a message that skips this boundary is exactly the
|
|
@@ -89,7 +72,6 @@ async function runRecordCommand(options, context, dependencies) {
|
|
|
89
72
|
reason: raw.runtimeIdentity.reason === null
|
|
90
73
|
? null
|
|
91
74
|
: redactDispatchMessage(raw.runtimeIdentity.reason, {
|
|
92
|
-
project: projectPath,
|
|
93
75
|
repo: repoRoot,
|
|
94
76
|
home: context.home,
|
|
95
77
|
}),
|
|
@@ -99,12 +81,7 @@ async function runRecordCommand(options, context, dependencies) {
|
|
|
99
81
|
context.logger.json(result);
|
|
100
82
|
}
|
|
101
83
|
else {
|
|
102
|
-
|
|
103
|
-
context.logger.success(`Recorded project dispatch: ${result.path}`);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
context.logger.info('Dispatch evidence is valid; no project path was supplied, so nothing was persisted.');
|
|
107
|
-
}
|
|
84
|
+
context.logger.info('Dispatch evidence is valid; nothing was written.');
|
|
108
85
|
for (const line of runtimeIdentityLines(result.runtimeIdentity)) {
|
|
109
86
|
context.logger.info(line);
|
|
110
87
|
}
|
|
@@ -113,7 +90,7 @@ async function runRecordCommand(options, context, dependencies) {
|
|
|
113
90
|
}
|
|
114
91
|
catch (error) {
|
|
115
92
|
// Single redaction boundary for every failure this command can surface.
|
|
116
|
-
const message = redactDispatchMessage(error instanceof Error ? error.message : String(error), {
|
|
93
|
+
const message = redactDispatchMessage(error instanceof Error ? error.message : String(error), { repo: repoRoot, home: context.home });
|
|
117
94
|
if (context.json) {
|
|
118
95
|
context.logger.json({ status: 'error', message });
|
|
119
96
|
}
|
|
@@ -126,10 +103,9 @@ async function runRecordCommand(options, context, dependencies) {
|
|
|
126
103
|
export function createProjectDispatchCommand(overrides = {}) {
|
|
127
104
|
const dependencies = { ...DEFAULT_DEPENDENCIES, ...overrides };
|
|
128
105
|
return new Command('dispatch')
|
|
129
|
-
.description('Validate
|
|
106
|
+
.description('Validate project dispatch provenance')
|
|
130
107
|
.addCommand(new Command('record')
|
|
131
|
-
.description('
|
|
132
|
-
.option('--project <project-path>', 'Project path; omit to validate without persistence')
|
|
108
|
+
.description('Validate one generic dispatch plus namespaced OAT evidence (writes nothing)')
|
|
133
109
|
.requiredOption('--event-file <json-file-or-dash>', 'Complete record and event JSON file, or - for standard input')
|
|
134
110
|
.action(async (options, command) => {
|
|
135
111
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { type GenericDispatchRecord } from '../../../providers/identity/generic-dispatch-record.js';
|
|
2
2
|
import { type OatDispatchEvidenceEvent, type PersistedOatDispatchRecordV1 } from '../../../providers/identity/oat-dispatch-record.js';
|
|
3
|
-
/**
|
|
4
|
-
* Test seam for deterministic concurrency coverage. `afterRead` fires after the
|
|
5
|
-
* caller has read the journal revision it will publish against and before the
|
|
6
|
-
* writer lock is acquired, which is exactly the window a stale concurrent
|
|
7
|
-
* writer occupies.
|
|
8
|
-
*/
|
|
9
|
-
export interface DispatchRecordRaceBarriers {
|
|
10
|
-
afterRead?: () => Promise<void>;
|
|
11
|
-
}
|
|
12
3
|
/**
|
|
13
4
|
* Hard redaction boundary. Producers redact their own messages, but this is the
|
|
14
5
|
* last stop before a message reaches `--json`, so a future call site that
|
|
@@ -17,10 +8,9 @@ export interface DispatchRecordRaceBarriers {
|
|
|
17
8
|
*
|
|
18
9
|
* The detector is shared with the record sanitizer. Two independent notions of
|
|
19
10
|
* "looks like a path" is how a path could be scrubbed from an error message and
|
|
20
|
-
*
|
|
11
|
+
* emitted verbatim in the validated record by the same command.
|
|
21
12
|
*/
|
|
22
13
|
export declare function redactDispatchMessage(message: string, roots?: {
|
|
23
|
-
project?: string | null;
|
|
24
14
|
repo?: string | null;
|
|
25
15
|
home?: string | null;
|
|
26
16
|
}): string;
|
|
@@ -68,24 +58,25 @@ export interface DispatchRecordRuntimeIdentity {
|
|
|
68
58
|
reason: string | null;
|
|
69
59
|
status: 'reported' | 'not-reported';
|
|
70
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* The command validates and never persists: nothing is written to disk, so
|
|
63
|
+
* `validated-only` is the only success status.
|
|
64
|
+
*/
|
|
71
65
|
export type ProjectDispatchRecordResult = {
|
|
72
|
-
status: '
|
|
73
|
-
path: string | null;
|
|
74
|
-
created: boolean;
|
|
66
|
+
status: 'validated-only';
|
|
75
67
|
record: PersistedOatDispatchRecordV1;
|
|
76
68
|
runtimeIdentity: DispatchRecordRuntimeIdentity;
|
|
77
69
|
};
|
|
78
70
|
export declare function parseDispatchRecordInput(value: unknown): DispatchRecordInput;
|
|
79
71
|
/**
|
|
80
|
-
*
|
|
81
|
-
* here
|
|
72
|
+
* Validate one dispatch record and event and return the augmented record. Parse
|
|
73
|
+
* once, here. An earlier revision parsed in the command layer and again here;
|
|
74
|
+
* because the metadata path resolves to a finished observation, the second
|
|
82
75
|
* parse saw its own output as caller-supplied and overwrote the parser source
|
|
83
76
|
* with `caller-asserted`. Parsing is not idempotent by design — provenance
|
|
84
77
|
* depends on which input form arrived — so it must happen exactly once.
|
|
85
78
|
*/
|
|
86
79
|
export declare function recordProjectDispatch(input: {
|
|
87
|
-
projectPath: string | null;
|
|
88
80
|
input: unknown;
|
|
89
|
-
raceBarriers?: DispatchRecordRaceBarriers;
|
|
90
81
|
}): Promise<ProjectDispatchRecordResult>;
|
|
91
82
|
//# sourceMappingURL=record.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/record.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/record.ts"],"names":[],"mappings":"AAYA,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAOL,KAAK,wBAAwB,EAE7B,KAAK,4BAA4B,EAElC,MAAM,yCAAyC,CAAC;AASjD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,GAAE;IACL,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjB,GACL,MAAM,CAgBR;AAeD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,wBAAwB,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,IAAI,CAAC;IACT,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC5D;;;OAGG;IACH,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,4BAA4B,CAAC;IACrC,eAAe,EAAE,6BAA6B,CAAC;CAChD,CAAC;AA8NF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CA6G5E;AAoCD;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAWvC"}
|