cohorte 3.0.0-dev.0 → 3.0.0-dev.2
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/assets/manifest.json +4 -4
- package/assets/schemas/reconcile-plan.schema.json +1 -2
- package/dist/agent-host.mjs +2142 -5
- package/dist/agent-host.mjs.map +1 -1
- package/dist/bundle-manifest.json +38 -36
- package/dist/chunks/{auth-D8rCVY33.mjs → auth-ybswxUPK.mjs} +54 -2
- package/dist/chunks/auth-ybswxUPK.mjs.map +1 -0
- package/dist/chunks/{brainstorm-CU10T1tm.mjs → brainstorm-BwKA6yZP.mjs} +2 -2
- package/dist/chunks/{brainstorm-CU10T1tm.mjs.map → brainstorm-BwKA6yZP.mjs.map} +1 -1
- package/dist/chunks/{catalogue-BvwSrM_j.mjs → catalogue-B5uFqfzJ.mjs} +2 -2
- package/dist/chunks/{catalogue-BvwSrM_j.mjs.map → catalogue-B5uFqfzJ.mjs.map} +1 -1
- package/dist/chunks/{compose-Cr0hP0qm.mjs → compose-C0rEh5wB.mjs} +3354 -3343
- package/dist/chunks/compose-C0rEh5wB.mjs.map +1 -0
- package/dist/chunks/{contract-B0ra2-bm.mjs → contract-BkMjU1kR.mjs} +2 -2
- package/dist/chunks/{contract-B0ra2-bm.mjs.map → contract-BkMjU1kR.mjs.map} +1 -1
- package/dist/chunks/{contract-vYbwYr0Y.mjs → contract-bQ9FJl4N.mjs} +2 -2
- package/dist/chunks/contract-bQ9FJl4N.mjs.map +1 -0
- package/dist/chunks/{diff-Qw0II0sj.mjs → diff-D_0hBwHl.mjs} +2 -2
- package/dist/chunks/{diff-Qw0II0sj.mjs.map → diff-D_0hBwHl.mjs.map} +1 -1
- package/dist/chunks/{discover-30Ciya_0.mjs → discover-eS01-me1.mjs} +3 -2
- package/dist/chunks/{discover-30Ciya_0.mjs.map → discover-eS01-me1.mjs.map} +1 -1
- package/dist/chunks/{doctor-DfCrKpfT.mjs → doctor-CginW8y8.mjs} +5 -5
- package/dist/chunks/{doctor-DfCrKpfT.mjs.map → doctor-CginW8y8.mjs.map} +1 -1
- package/dist/chunks/init-BUnzIkeE.mjs +63 -0
- package/dist/chunks/init-BUnzIkeE.mjs.map +1 -0
- package/dist/chunks/migrate-DybihKzZ.mjs +33 -0
- package/dist/chunks/migrate-DybihKzZ.mjs.map +1 -0
- package/dist/chunks/{policy-DUIgzF3W.mjs → policy-Clypo20s.mjs} +3 -3
- package/dist/chunks/{policy-DUIgzF3W.mjs.map → policy-Clypo20s.mjs.map} +1 -1
- package/dist/chunks/reconcile-Bhy3IIYo.mjs +50 -0
- package/dist/chunks/reconcile-Bhy3IIYo.mjs.map +1 -0
- package/dist/chunks/scan-8Gy_B6kI.mjs +122 -0
- package/dist/chunks/scan-8Gy_B6kI.mjs.map +1 -0
- package/dist/chunks/src-CmFjh4M0.mjs +928 -0
- package/dist/chunks/src-CmFjh4M0.mjs.map +1 -0
- package/dist/chunks/{src-CfAOde7C.mjs → src-DZazJCp1.mjs} +2 -2
- package/dist/chunks/{src-CfAOde7C.mjs.map → src-DZazJCp1.mjs.map} +1 -1
- package/dist/chunks/{src-CId6kMsY.mjs → src-r0ECB1UJ.mjs} +2 -2
- package/dist/chunks/{src-CId6kMsY.mjs.map → src-r0ECB1UJ.mjs.map} +1 -1
- package/dist/cli.mjs +12 -12
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/auth-D8rCVY33.mjs.map +0 -1
- package/dist/chunks/compose-Cr0hP0qm.mjs.map +0 -1
- package/dist/chunks/contract-vYbwYr0Y.mjs.map +0 -1
- package/dist/chunks/init-Okz4mlhW.mjs +0 -30
- package/dist/chunks/init-Okz4mlhW.mjs.map +0 -1
- package/dist/chunks/migrate-DRoFUg53.mjs +0 -19
- package/dist/chunks/migrate-DRoFUg53.mjs.map +0 -1
- package/dist/chunks/reconcile-BfD785gd.mjs +0 -26
- package/dist/chunks/reconcile-BfD785gd.mjs.map +0 -1
- package/dist/chunks/src-JxawBQBn.mjs +0 -446
- package/dist/chunks/src-JxawBQBn.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { F as EXIT_CODE_BY_CLASS, L as ERROR_CLASSES, N as errorOf, j as CohorteError } from "./src-Cu3TxNob.mjs";
|
|
2
|
-
import "./contract-
|
|
2
|
+
import "./contract-bQ9FJl4N.mjs";
|
|
3
3
|
import { f as HALTED_STATES, m as SUSPENDED_STATES, r as CONTROLLER_EXIT_CODES } from "./src-s7YRvk0t.mjs";
|
|
4
4
|
//#region src/contract/command-module.ts
|
|
5
5
|
/**
|
|
@@ -292,4 +292,4 @@ Object.freeze(Object.fromEntries(VERBS.filter((verb) => verb.commandType !== voi
|
|
|
292
292
|
//#endregion
|
|
293
293
|
export { formatExitCodesHelp as n, notImplementedCommand as r, VERBS as t };
|
|
294
294
|
|
|
295
|
-
//# sourceMappingURL=contract-
|
|
295
|
+
//# sourceMappingURL=contract-BkMjU1kR.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-B0ra2-bm.mjs","names":[],"sources":["../../../../apps/cli/src/contract/command-module.ts","../../../../apps/cli/src/contract/documents.ts","../../../../apps/cli/src/contract/exit-codes.ts","../../../../apps/cli/src/contract/verbs.ts"],"sourcesContent":["// apps/cli/src/contract/command-module.ts — DESIGN 10.1 rule 3 \"every barrel entry is a live export\": each verb's\n// `commands/<verb>/index.ts` implements `CommandModule`. Wave 0 fills every one with `notImplementedCommand` (the\n// documented not-available error, spec 24 `configuration/phase-not-available`); later waves replace the body,\n// never the shape — `cli.ts` and `lazy.ts` never change to accommodate a filled-in verb.\nimport { CohorteError, errorOf } from '@cohorte/base';\nimport type { CliContext } from './context.ts';\n\n/** What `cli.ts` hands a module after commander parsed the line: positionals, options, and the JSON flag. */\nexport interface CommandArgs {\n /**\n * Every token commander did not consume, IN ORDER — which in V3.0 means every flag a verb defines for itself:\n * `cohorte run spec-1 --wait 8 --detach` arrives as `['spec-1', '--wait', '8', '--detach']`. A verb module parses\n * its own flags from here.\n */\n readonly positionals: readonly string[];\n /**\n * In V3.0 this carries ONLY `json`. The registry is frozen (PLAN §3 rule 3) and `cli.ts` registers no option but\n * `--json`, on the verbs that publish a document; with `allowUnknownOption(true)` every other flag is left\n * unparsed in `positionals`. So `args.options.wait` / `args.options.check` are ALWAYS `undefined` — read\n * `positionals`. The map is kept open (rather than typed `{ json?: boolean }`) because a post-3.0 registry\n * amendment that declares a real option is a MINOR, not a breaking change to this contract.\n */\n readonly options: Readonly<Record<string, unknown>>;\n /** Set when the verb has DESIGN §9 sub-verbs (`config get`, `auth login`, ...): the one commander matched. */\n readonly subVerb?: string;\n readonly json: boolean;\n}\n\nexport interface CommandModule {\n readonly verb: string;\n /**\n * Runs the verb; returns the process exit code (DESIGN 2.8 / 2.3.4). Throwing is equivalent to returning the\n * class exit code of `toErrorInfo(thrown, …)`: `cli.ts` converts every throw at the boundary, so a module is\n * free to throw a `CohorteError`, a `NotImplemented`, or let an unexpected error surface — nothing here writes to\n * `ctx.stdio` on error, `cli.ts` alone owns the spec-21 `cause / impact / run / next action / exit code` format.\n */\n run(ctx: CliContext, args: CommandArgs): Promise<number>;\n}\n\n/**\n * The Wave-0 body of every verb (DESIGN §9 \"stubbed with a seam\" and the plain \"not yet built\" ones alike): a verb\n * a later wave fills replaces this factory call with a real implementation, never the module's shape.\n *\n * It throws a CLASSIFIED `CohorteError`, not a bare `NotImplemented`: `toErrorInfo` keeps a `CohorteError`'s own\n * code, so the documented `configuration/phase-not-available` (DESIGN §9, exit 10) is what the stub MEANS rather\n * than what `cli.ts`'s unknown-throwable fallback happens to be. `cli.ts`'s fallback is `configuration/unexpected`\n * (DESIGN 2.8 \"Unknown throwables -> `<nearest class>/unexpected`\"), so a real defect in a filled-in verb can never\n * masquerade as \"this phase is not available in this build\".\n */\nexport function notImplementedCommand(verb: string): CommandModule {\n return {\n verb,\n // `ctx`/`args` intentionally unused: the Wave-0 stub never touches a port (DESIGN 1.3).\n async run(_ctx, _args): Promise<number> {\n throw new CohorteError(\n errorOf('configuration/phase-not-available', `the verb \\`${verb}\\` is not available in this build`),\n );\n },\n };\n}\n","// apps/cli/src/contract/documents.ts — DESIGN 2.3.5 \"one [S] document per --json output\". `JSON_OUTPUTS` is the\n// map a Wave-4 command unit's `--json validates` test reads: verb -> the published document(s) that verb's\n// `--json` can print, each resolvable to a real schema in the protocol, project-model or security contract (PLAN\n// U0.10 test list, 6th row).\n\nimport { ProjectModel, ReconcilePlan } from '@cohorte/project-model/contract';\nimport { DOCUMENTS, type DocumentName } from '@cohorte/protocol';\nimport type { TSchema } from 'typebox';\n\n/** The two project-model documents a `--json` verb may print (DESIGN §9: `reconcile --plan`, `discover`). */\nexport const PROJECT_MODEL_DOCUMENT_NAMES = ['reconcile-plan', 'project-model'] as const;\nexport type ProjectModelDocumentName = (typeof PROJECT_MODEL_DOCUMENT_NAMES)[number];\n\nexport type DocumentRef =\n | { readonly source: 'protocol'; readonly name: DocumentName }\n | { readonly source: 'project-model'; readonly name: ProjectModelDocumentName };\n\n/** Resolves a `DocumentRef` to its real schema; throws when the referenced contract has no such entry (a drift\n * guard, not a runtime path: every entry of `JSON_OUTPUTS` below is checked against this at test time). */\nexport function resolveDocumentSchema(ref: DocumentRef): TSchema {\n if (ref.source === 'protocol') {\n const schema = DOCUMENTS[ref.name];\n if (!schema) throw new RangeError(`resolveDocumentSchema: no protocol document named ${ref.name}`);\n return schema;\n }\n // A plain lookup, not a `switch` with an unreachable default: the ref may come from a Wave-4 unit's data, so an\n // unknown name must throw at run time and not only fail to typecheck.\n // No cast: `TUnsafe<T> extends TSchema`, and there is exactly one typebox install (the `pnpm-workspace.yaml`\n // override pins 1.3.7), so `@cohorte/project-model/contract`'s schemas ARE `TSchema`s here. If this ever stops\n // compiling, the cause is a second typebox identity in the graph — a real defect to report, not to cast away.\n const projectModelSchemas: Record<ProjectModelDocumentName, TSchema> = {\n 'reconcile-plan': ReconcilePlan,\n 'project-model': ProjectModel,\n };\n const schema = projectModelSchemas[ref.name];\n if (!schema) throw new RangeError(`resolveDocumentSchema: no project-model document named ${String(ref.name)}`);\n return schema;\n}\n\nconst protocolDoc = (name: DocumentName): DocumentRef => ({ source: 'protocol', name });\nconst reconcilePlanDoc: DocumentRef = { source: 'project-model', name: 'reconcile-plan' };\n/** DESIGN §9 verb semantics: \"`cohorte discover` prints the deterministic scan as a Project Model document\". */\nconst projectModelDoc: DocumentRef = { source: 'project-model', name: 'project-model' };\n/** DESIGN 2.3.4's inbox route: every mutating command answers with a `CommandResultDocument`. */\nconst commandResult: readonly DocumentRef[] = [protocolDoc('command-result')];\n\n/**\n * Keyed by CLI verb (not by `CommandType`: read-only verbs publish a document with no command behind them).\n *\n * The key set is exactly `{ verb.name | verb.json }` of `contract/verbs.ts`, and `cli.ts` registers `--json` only\n * for those verbs — `apps/cli/test/registry/json-outputs.test.ts` pins both directions. `logs` and `tail` are\n * deliberately absent: DESIGN 4.7 gives an observer `--format=line|json` over an NDJSON *stream* of event\n * envelopes, not a single `--json` document (request U0.10 R1 asks U0.G to confirm that reading).\n */\nexport const JSON_OUTPUTS: Readonly<Record<string, readonly DocumentRef[]>> = Object.freeze({\n // `status <run>` -> run-state; `status` (no run) -> project-status (DESIGN 2.3.4 \"no runId => ProjectStatusDocument\")\n status: [protocolDoc('project-status'), protocolDoc('run-state')],\n inspect: [protocolDoc('inspect')],\n diff: [protocolDoc('run-diff')],\n doctor: [protocolDoc('doctor-report')],\n auth: [protocolDoc('auth-status')],\n reconcile: [reconcilePlanDoc],\n discover: [projectModelDoc],\n // `run` drives `start`; its `--wait`/`--json` prints the same run-state an observer would (DESIGN 4.7).\n run: [protocolDoc('command-result'), protocolDoc('run-state')],\n resume: commandResult,\n pause: commandResult,\n cancel: commandResult,\n approve: commandResult,\n deny: commandResult,\n retry: commandResult,\n skip: commandResult,\n shutdown: commandResult,\n send: commandResult,\n 'run-tool': commandResult,\n});\n","// apps/cli/src/contract/exit-codes.ts — DESIGN 2.8 \"Exit codes of a process that waits for a run\" + DESIGN 4.7 +\n// the controller codes of DESIGN 2.3.4 (`CONTROLLER_EXIT_CODES`). Total over `ErrorClass` because it is built\n// directly from `@cohorte/base`'s `EXIT_CODE_BY_CLASS`, which is itself total (a `satisfies Record<ErrorClass, …>`\n// literal): the totality test in `apps/cli/test/registry` checks that equality holds, it does not re-derive it.\nimport { ERROR_CLASSES, type ErrorClass, EXIT_CODE_BY_CLASS } from '@cohorte/base';\nimport { CONTROLLER_EXIT_CODES, HALTED_STATES, type PipelineState, SUSPENDED_STATES } from '@cohorte/protocol';\n\nexport { CONTROLLER_EXIT_CODES, EXIT_CODE_BY_CLASS };\n\n/** DESIGN 4.7 \"4 on a suspended state\" / DESIGN 2.3.4 \"4 accepted-but-pending at --wait expiry (not an error)\". */\nexport const SUSPENDED_EXIT_CODE = 4;\n/** DESIGN 2.8 \"16 on CANCELLED\" (shares the `conflict` class code, but CANCELLED is not itself an error). */\nexport const CANCELLED_EXIT_CODE = 16;\nexport const COMPLETED_EXIT_CODE = 0;\n\nconst SUSPENDED = new Set<string>(SUSPENDED_STATES);\nconst HALTED = new Set<string>(HALTED_STATES);\n\n/**\n * DESIGN 2.8 / 4.7: \"an observer started by `run`, or any `--wait`, exits 0 on COMPLETED, the class code of\n * `run.lastError` on FAILED/BLOCKED, 4 on a suspended state, 16 on CANCELLED.\" `lastErrorClass` is required\n * exactly when `state` is FAILED or BLOCKED (DESIGN 2.8: every halted run carries a `lastError`).\n */\nexport function waitExitCode(state: PipelineState, lastErrorClass?: ErrorClass): number {\n if (state === 'COMPLETED') return COMPLETED_EXIT_CODE;\n if (state === 'CANCELLED') return CANCELLED_EXIT_CODE;\n if (SUSPENDED.has(state)) return SUSPENDED_EXIT_CODE;\n if (HALTED.has(state)) {\n if (!lastErrorClass) throw new RangeError(`waitExitCode: ${state} requires lastErrorClass (DESIGN 2.8)`);\n return EXIT_CODE_BY_CLASS[lastErrorClass];\n }\n // IDLE and every ACTIVE_PIPELINE_STATE are not terminal/suspended: a waiter never observes them as a final state.\n throw new RangeError(`waitExitCode: ${state} is not a terminal or suspended state (DESIGN 2.8)`);\n}\n\nexport interface ExitCodeHelpRow {\n readonly code: number;\n readonly meaning: string;\n}\n\n/** DESIGN 2.3.4 \"Controller exit codes: 0 completed · 3 rejected · 4 accepted-but-pending · 2 usage.\" */\nexport const CONTROLLER_EXIT_HELP: readonly ExitCodeHelpRow[] = [\n { code: CONTROLLER_EXIT_CODES.completed, meaning: 'completed' },\n { code: CONTROLLER_EXIT_CODES.usage, meaning: 'usage error' },\n { code: CONTROLLER_EXIT_CODES.rejected, meaning: 'rejected' },\n { code: CONTROLLER_EXIT_CODES.pending, meaning: 'accepted, pending at --wait expiry (not an error: durable inbox)' },\n];\n\n/** DESIGN 2.8's table, class by class, in spec order. */\nexport const ERROR_CLASS_EXIT_HELP: readonly ExitCodeHelpRow[] = ERROR_CLASSES.map((errorClass) => ({\n code: EXIT_CODE_BY_CLASS[errorClass],\n meaning: `${errorClass} error`,\n}));\n\nexport const CANCELLED_EXIT_HELP: ExitCodeHelpRow = { code: CANCELLED_EXIT_CODE, meaning: 'cancelled' };\n\n/** Rendered into `--help` (PLAN U0.10 test: \"controller codes 0/2/3/4 documented in --help\"). */\nexport function formatExitCodesHelp(): string {\n const rows = [...CONTROLLER_EXIT_HELP, ...ERROR_CLASS_EXIT_HELP, CANCELLED_EXIT_HELP];\n const width = Math.max(...rows.map((row) => String(row.code).length));\n const lines = rows.map((row) => ` ${String(row.code).padStart(width)} ${row.meaning}`);\n return ['Exit codes:', ...lines].join('\\n');\n}\n","// apps/cli/src/contract/verbs.ts — DESIGN §9 \"V3.0 scope cut\" CLI row + the verb-semantics paragraph, and DESIGN\n// 2.3.4 \"every command type has a CLI verb, because one-shot CLI spawns are the only V3.0 transport\". `cli.ts`\n// builds the whole commander tree from this table and NOTHING ELSE (PLAN §3 rule 3: \"cli.ts pre-registers every\n// verb against commands/<verb>/index.ts\"); a later wave fills a verb's module, never this table's shape.\nimport type { CommandType } from '@cohorte/protocol';\n\nexport interface VerbSpec {\n readonly name: string;\n readonly summary: string;\n /** DESIGN §9: `config get|set|validate|trust`, `auth login|status|logout`, `providers list|test`, ... */\n readonly subVerbs?: readonly string[];\n /** Not listed in `cohorte --help` (the `__host` internal entry point, DESIGN 4.7). */\n readonly hidden?: boolean;\n /**\n * This verb accepts `--json` and publishes a document for it (DESIGN 2.3.5). Set exactly on the verbs that have\n * a `JSON_OUTPUTS` entry — `cli.ts` registers the `--json` option only for those, and\n * `apps/cli/test/registry/json-outputs.test.ts` pins the two sides equal in BOTH directions, so a verb can never\n * be silently flagged `--json` with no document behind it.\n */\n readonly json?: boolean;\n /** The `@cohorte/protocol` `CommandType` this verb drives 1:1, when it drives exactly one (DESIGN 2.3.4). */\n readonly commandType?: CommandType;\n}\n\nexport const VERBS: readonly VerbSpec[] = [\n { name: 'init', summary: 'Scaffold .cohorte/ for this repository' },\n { name: 'doctor', summary: 'Diagnose the installation, configuration and toolchain', json: true },\n { name: 'discover', summary: 'Print the deterministic project scan (no write)', json: true },\n { name: 'run', summary: 'Start a pipeline run', commandType: 'start', json: true },\n { name: 'status', summary: 'Show a run, or the project, status', commandType: 'status', json: true },\n {\n name: 'inspect',\n summary: 'Inspect one agent, context, approval, effect, snapshot, lock, diff or artifact',\n commandType: 'inspect',\n json: true,\n },\n { name: 'resume', summary: 'Resume a suspended run', commandType: 'resume', json: true },\n { name: 'pause', summary: 'Pause an active run', commandType: 'pause', json: true },\n { name: 'cancel', summary: 'Cancel a run', commandType: 'cancel', json: true },\n { name: 'shutdown', summary: 'Ask the detached host to shut down gracefully', commandType: 'shutdown', json: true },\n { name: 'approve', summary: 'Approve a pending approval request', commandType: 'approve', json: true },\n { name: 'deny', summary: 'Deny a pending approval request', commandType: 'deny', json: true },\n { name: 'retry', summary: 'Retry a phase or an agent', commandType: 'retry', json: true },\n { name: 'skip', summary: 'Skip a phase (only if policy.skip lists it)', commandType: 'skip', json: true },\n { name: 'logs', summary: 'Print durable run events' },\n { name: 'tail', summary: 'Follow a run (durable + ephemeral events)', commandType: 'tail' },\n { name: 'diff', summary: 'Show the run diff for a surface', json: true },\n { name: 'review', summary: 'Start a review-profile run over a ref range or a prior run' },\n { name: 'fix', summary: \"Retry a run's FIX phase\" },\n { name: 'ship', summary: 'Show and resolve the pending ship approval' },\n { name: 'auth', summary: 'Manage provider authentication', subVerbs: ['login', 'status', 'logout'], json: true },\n { name: 'providers', summary: 'List or test configured providers', subVerbs: ['list', 'test'] },\n { name: 'models', summary: 'List available models', subVerbs: ['list'] },\n {\n name: 'config',\n summary: 'Read, write, validate or trust the project configuration',\n subVerbs: ['get', 'set', 'validate', 'trust'],\n },\n { name: 'migrate', summary: 'Check or apply state-store migrations' },\n {\n name: 'reconcile',\n summary: 'Plan the project configuration against the discovered state',\n commandType: 'reconcile',\n json: true,\n },\n { name: 'spec', summary: 'Validate or freeze a human-written spec', subVerbs: ['validate', 'freeze'] },\n { name: 'policy', summary: 'Explain the effective security policy', subVerbs: ['explain'] },\n { name: 'gc', summary: 'Garbage-collect worktrees, spools and old runs' },\n {\n name: 'update',\n // DESIGN §9 spells it as a FLAG, `update --check`, not a sub-verb: the Wave-5 unit that fills\n // `commands/update/index.ts` reads `--check` from `args.options`/`args.positionals` like every other verb flag.\n summary: 'Check for a newer pinned install (offline, --check only in V3.0)',\n },\n { name: 'brainstorm', summary: 'Not available in V3.0 (reserved verb id, DESIGN §9)' },\n {\n name: 'run-tool',\n summary: 'Run one tool directly (admin; policy.admin.runTool)',\n commandType: 'run-tool',\n json: true,\n },\n {\n name: 'send',\n summary: 'Send text to a running agent (policy.steer.enabled)',\n commandType: 'agent.send',\n json: true,\n },\n { name: '__host', summary: 'Internal: run the detached host in-process', hidden: true },\n];\n\nconst BY_NAME = new Map(VERBS.map((verb) => [verb.name, verb]));\n\nexport function findVerb(name: string): VerbSpec | undefined {\n return BY_NAME.get(name);\n}\n\nexport const VERB_NAMES: readonly string[] = VERBS.map((verb) => verb.name);\n\n/** DESIGN 2.3.4: every `CommandType` has exactly one driving verb. Built from `VERBS`, so it can never drift. */\nexport const COMMAND_TYPE_TO_VERB: Readonly<Record<CommandType, string>> = Object.freeze(\n Object.fromEntries(\n VERBS.filter((verb): verb is VerbSpec & { commandType: CommandType } => verb.commandType !== undefined).map(\n (verb) => [verb.commandType, verb.name],\n ),\n ) as Record<CommandType, string>,\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"contract-BkMjU1kR.mjs","names":[],"sources":["../../../../apps/cli/src/contract/command-module.ts","../../../../apps/cli/src/contract/documents.ts","../../../../apps/cli/src/contract/exit-codes.ts","../../../../apps/cli/src/contract/verbs.ts"],"sourcesContent":["// apps/cli/src/contract/command-module.ts — DESIGN 10.1 rule 3 \"every barrel entry is a live export\": each verb's\n// `commands/<verb>/index.ts` implements `CommandModule`. Wave 0 fills every one with `notImplementedCommand` (the\n// documented not-available error, spec 24 `configuration/phase-not-available`); later waves replace the body,\n// never the shape — `cli.ts` and `lazy.ts` never change to accommodate a filled-in verb.\nimport { CohorteError, errorOf } from '@cohorte/base';\nimport type { CliContext } from './context.ts';\n\n/** What `cli.ts` hands a module after commander parsed the line: positionals, options, and the JSON flag. */\nexport interface CommandArgs {\n /**\n * Every token commander did not consume, IN ORDER — which in V3.0 means every flag a verb defines for itself:\n * `cohorte run spec-1 --wait 8 --detach` arrives as `['spec-1', '--wait', '8', '--detach']`. A verb module parses\n * its own flags from here.\n */\n readonly positionals: readonly string[];\n /**\n * In V3.0 this carries ONLY `json`. The registry is frozen (PLAN §3 rule 3) and `cli.ts` registers no option but\n * `--json`, on the verbs that publish a document; with `allowUnknownOption(true)` every other flag is left\n * unparsed in `positionals`. So `args.options.wait` / `args.options.check` are ALWAYS `undefined` — read\n * `positionals`. The map is kept open (rather than typed `{ json?: boolean }`) because a post-3.0 registry\n * amendment that declares a real option is a MINOR, not a breaking change to this contract.\n */\n readonly options: Readonly<Record<string, unknown>>;\n /** Set when the verb has DESIGN §9 sub-verbs (`config get`, `auth login`, ...): the one commander matched. */\n readonly subVerb?: string;\n readonly json: boolean;\n}\n\nexport interface CommandModule {\n readonly verb: string;\n /**\n * Runs the verb; returns the process exit code (DESIGN 2.8 / 2.3.4). Throwing is equivalent to returning the\n * class exit code of `toErrorInfo(thrown, …)`: `cli.ts` converts every throw at the boundary, so a module is\n * free to throw a `CohorteError`, a `NotImplemented`, or let an unexpected error surface — nothing here writes to\n * `ctx.stdio` on error, `cli.ts` alone owns the spec-21 `cause / impact / run / next action / exit code` format.\n */\n run(ctx: CliContext, args: CommandArgs): Promise<number>;\n}\n\n/**\n * The Wave-0 body of every verb (DESIGN §9 \"stubbed with a seam\" and the plain \"not yet built\" ones alike): a verb\n * a later wave fills replaces this factory call with a real implementation, never the module's shape.\n *\n * It throws a CLASSIFIED `CohorteError`, not a bare `NotImplemented`: `toErrorInfo` keeps a `CohorteError`'s own\n * code, so the documented `configuration/phase-not-available` (DESIGN §9, exit 10) is what the stub MEANS rather\n * than what `cli.ts`'s unknown-throwable fallback happens to be. `cli.ts`'s fallback is `configuration/unexpected`\n * (DESIGN 2.8 \"Unknown throwables -> `<nearest class>/unexpected`\"), so a real defect in a filled-in verb can never\n * masquerade as \"this phase is not available in this build\".\n */\nexport function notImplementedCommand(verb: string): CommandModule {\n return {\n verb,\n // `ctx`/`args` intentionally unused: the Wave-0 stub never touches a port (DESIGN 1.3).\n async run(_ctx, _args): Promise<number> {\n throw new CohorteError(\n errorOf('configuration/phase-not-available', `the verb \\`${verb}\\` is not available in this build`),\n );\n },\n };\n}\n","// apps/cli/src/contract/documents.ts — DESIGN 2.3.5 \"one [S] document per --json output\". `JSON_OUTPUTS` is the\n// map a Wave-4 command unit's `--json validates` test reads: verb -> the published document(s) that verb's\n// `--json` can print, each resolvable to a real schema in the protocol, project-model or security contract (PLAN\n// U0.10 test list, 6th row).\n\nimport { ProjectModel, ReconcilePlan } from '@cohorte/project-model/contract';\nimport { DOCUMENTS, type DocumentName } from '@cohorte/protocol';\nimport type { TSchema } from 'typebox';\n\n/** The two project-model documents a `--json` verb may print (DESIGN §9: `reconcile --plan`, `discover`). */\nexport const PROJECT_MODEL_DOCUMENT_NAMES = ['reconcile-plan', 'project-model'] as const;\nexport type ProjectModelDocumentName = (typeof PROJECT_MODEL_DOCUMENT_NAMES)[number];\n\nexport type DocumentRef =\n | { readonly source: 'protocol'; readonly name: DocumentName }\n | { readonly source: 'project-model'; readonly name: ProjectModelDocumentName };\n\n/** Resolves a `DocumentRef` to its real schema; throws when the referenced contract has no such entry (a drift\n * guard, not a runtime path: every entry of `JSON_OUTPUTS` below is checked against this at test time). */\nexport function resolveDocumentSchema(ref: DocumentRef): TSchema {\n if (ref.source === 'protocol') {\n const schema = DOCUMENTS[ref.name];\n if (!schema) throw new RangeError(`resolveDocumentSchema: no protocol document named ${ref.name}`);\n return schema;\n }\n // A plain lookup, not a `switch` with an unreachable default: the ref may come from a Wave-4 unit's data, so an\n // unknown name must throw at run time and not only fail to typecheck.\n // No cast: `TUnsafe<T> extends TSchema`, and there is exactly one typebox install (the `pnpm-workspace.yaml`\n // override pins 1.3.7), so `@cohorte/project-model/contract`'s schemas ARE `TSchema`s here. If this ever stops\n // compiling, the cause is a second typebox identity in the graph — a real defect to report, not to cast away.\n const projectModelSchemas: Record<ProjectModelDocumentName, TSchema> = {\n 'reconcile-plan': ReconcilePlan,\n 'project-model': ProjectModel,\n };\n const schema = projectModelSchemas[ref.name];\n if (!schema) throw new RangeError(`resolveDocumentSchema: no project-model document named ${String(ref.name)}`);\n return schema;\n}\n\nconst protocolDoc = (name: DocumentName): DocumentRef => ({ source: 'protocol', name });\nconst reconcilePlanDoc: DocumentRef = { source: 'project-model', name: 'reconcile-plan' };\n/** DESIGN §9 verb semantics: \"`cohorte discover` prints the deterministic scan as a Project Model document\". */\nconst projectModelDoc: DocumentRef = { source: 'project-model', name: 'project-model' };\n/** DESIGN 2.3.4's inbox route: every mutating command answers with a `CommandResultDocument`. */\nconst commandResult: readonly DocumentRef[] = [protocolDoc('command-result')];\n\n/**\n * Keyed by CLI verb (not by `CommandType`: read-only verbs publish a document with no command behind them).\n *\n * The key set is exactly `{ verb.name | verb.json }` of `contract/verbs.ts`, and `cli.ts` registers `--json` only\n * for those verbs — `apps/cli/test/registry/json-outputs.test.ts` pins both directions. `logs` and `tail` are\n * deliberately absent: DESIGN 4.7 gives an observer `--format=line|json` over an NDJSON *stream* of event\n * envelopes, not a single `--json` document (request U0.10 R1 asks U0.G to confirm that reading).\n */\nexport const JSON_OUTPUTS: Readonly<Record<string, readonly DocumentRef[]>> = Object.freeze({\n // `status <run>` -> run-state; `status` (no run) -> project-status (DESIGN 2.3.4 \"no runId => ProjectStatusDocument\")\n status: [protocolDoc('project-status'), protocolDoc('run-state')],\n inspect: [protocolDoc('inspect')],\n diff: [protocolDoc('run-diff')],\n doctor: [protocolDoc('doctor-report')],\n auth: [protocolDoc('auth-status')],\n reconcile: [reconcilePlanDoc],\n discover: [projectModelDoc],\n // `run` drives `start`; its `--wait`/`--json` prints the same run-state an observer would (DESIGN 4.7).\n run: [protocolDoc('command-result'), protocolDoc('run-state')],\n resume: commandResult,\n pause: commandResult,\n cancel: commandResult,\n approve: commandResult,\n deny: commandResult,\n retry: commandResult,\n skip: commandResult,\n shutdown: commandResult,\n send: commandResult,\n 'run-tool': commandResult,\n});\n","// apps/cli/src/contract/exit-codes.ts — DESIGN 2.8 \"Exit codes of a process that waits for a run\" + DESIGN 4.7 +\n// the controller codes of DESIGN 2.3.4 (`CONTROLLER_EXIT_CODES`). Total over `ErrorClass` because it is built\n// directly from `@cohorte/base`'s `EXIT_CODE_BY_CLASS`, which is itself total (a `satisfies Record<ErrorClass, …>`\n// literal): the totality test in `apps/cli/test/registry` checks that equality holds, it does not re-derive it.\nimport { ERROR_CLASSES, type ErrorClass, EXIT_CODE_BY_CLASS } from '@cohorte/base';\nimport { CONTROLLER_EXIT_CODES, HALTED_STATES, type PipelineState, SUSPENDED_STATES } from '@cohorte/protocol';\n\nexport { CONTROLLER_EXIT_CODES, EXIT_CODE_BY_CLASS };\n\n/** DESIGN 4.7 \"4 on a suspended state\" / DESIGN 2.3.4 \"4 accepted-but-pending at --wait expiry (not an error)\". */\nexport const SUSPENDED_EXIT_CODE = 4;\n/** DESIGN 2.8 \"16 on CANCELLED\" (shares the `conflict` class code, but CANCELLED is not itself an error). */\nexport const CANCELLED_EXIT_CODE = 16;\nexport const COMPLETED_EXIT_CODE = 0;\n\nconst SUSPENDED = new Set<string>(SUSPENDED_STATES);\nconst HALTED = new Set<string>(HALTED_STATES);\n\n/**\n * DESIGN 2.8 / 4.7: \"an observer started by `run`, or any `--wait`, exits 0 on COMPLETED, the class code of\n * `run.lastError` on FAILED/BLOCKED, 4 on a suspended state, 16 on CANCELLED.\" `lastErrorClass` is required\n * exactly when `state` is FAILED or BLOCKED (DESIGN 2.8: every halted run carries a `lastError`).\n */\nexport function waitExitCode(state: PipelineState, lastErrorClass?: ErrorClass): number {\n if (state === 'COMPLETED') return COMPLETED_EXIT_CODE;\n if (state === 'CANCELLED') return CANCELLED_EXIT_CODE;\n if (SUSPENDED.has(state)) return SUSPENDED_EXIT_CODE;\n if (HALTED.has(state)) {\n if (!lastErrorClass) throw new RangeError(`waitExitCode: ${state} requires lastErrorClass (DESIGN 2.8)`);\n return EXIT_CODE_BY_CLASS[lastErrorClass];\n }\n // IDLE and every ACTIVE_PIPELINE_STATE are not terminal/suspended: a waiter never observes them as a final state.\n throw new RangeError(`waitExitCode: ${state} is not a terminal or suspended state (DESIGN 2.8)`);\n}\n\nexport interface ExitCodeHelpRow {\n readonly code: number;\n readonly meaning: string;\n}\n\n/** DESIGN 2.3.4 \"Controller exit codes: 0 completed · 3 rejected · 4 accepted-but-pending · 2 usage.\" */\nexport const CONTROLLER_EXIT_HELP: readonly ExitCodeHelpRow[] = [\n { code: CONTROLLER_EXIT_CODES.completed, meaning: 'completed' },\n { code: CONTROLLER_EXIT_CODES.usage, meaning: 'usage error' },\n { code: CONTROLLER_EXIT_CODES.rejected, meaning: 'rejected' },\n { code: CONTROLLER_EXIT_CODES.pending, meaning: 'accepted, pending at --wait expiry (not an error: durable inbox)' },\n];\n\n/** DESIGN 2.8's table, class by class, in spec order. */\nexport const ERROR_CLASS_EXIT_HELP: readonly ExitCodeHelpRow[] = ERROR_CLASSES.map((errorClass) => ({\n code: EXIT_CODE_BY_CLASS[errorClass],\n meaning: `${errorClass} error`,\n}));\n\nexport const CANCELLED_EXIT_HELP: ExitCodeHelpRow = { code: CANCELLED_EXIT_CODE, meaning: 'cancelled' };\n\n/** Rendered into `--help` (PLAN U0.10 test: \"controller codes 0/2/3/4 documented in --help\"). */\nexport function formatExitCodesHelp(): string {\n const rows = [...CONTROLLER_EXIT_HELP, ...ERROR_CLASS_EXIT_HELP, CANCELLED_EXIT_HELP];\n const width = Math.max(...rows.map((row) => String(row.code).length));\n const lines = rows.map((row) => ` ${String(row.code).padStart(width)} ${row.meaning}`);\n return ['Exit codes:', ...lines].join('\\n');\n}\n","// apps/cli/src/contract/verbs.ts — DESIGN §9 \"V3.0 scope cut\" CLI row + the verb-semantics paragraph, and DESIGN\n// 2.3.4 \"every command type has a CLI verb, because one-shot CLI spawns are the only V3.0 transport\". `cli.ts`\n// builds the whole commander tree from this table and NOTHING ELSE (PLAN §3 rule 3: \"cli.ts pre-registers every\n// verb against commands/<verb>/index.ts\"); a later wave fills a verb's module, never this table's shape.\nimport type { CommandType } from '@cohorte/protocol';\n\nexport interface VerbSpec {\n readonly name: string;\n readonly summary: string;\n /** DESIGN §9: `config get|set|validate|trust`, `auth login|status|logout`, `providers list|test`, ... */\n readonly subVerbs?: readonly string[];\n /** Not listed in `cohorte --help` (the `__host` internal entry point, DESIGN 4.7). */\n readonly hidden?: boolean;\n /**\n * This verb accepts `--json` and publishes a document for it (DESIGN 2.3.5). Set exactly on the verbs that have\n * a `JSON_OUTPUTS` entry — `cli.ts` registers the `--json` option only for those, and\n * `apps/cli/test/registry/json-outputs.test.ts` pins the two sides equal in BOTH directions, so a verb can never\n * be silently flagged `--json` with no document behind it.\n */\n readonly json?: boolean;\n /** The `@cohorte/protocol` `CommandType` this verb drives 1:1, when it drives exactly one (DESIGN 2.3.4). */\n readonly commandType?: CommandType;\n}\n\nexport const VERBS: readonly VerbSpec[] = [\n { name: 'init', summary: 'Scaffold .cohorte/ for this repository' },\n { name: 'doctor', summary: 'Diagnose the installation, configuration and toolchain', json: true },\n { name: 'discover', summary: 'Print the deterministic project scan (no write)', json: true },\n { name: 'run', summary: 'Start a pipeline run', commandType: 'start', json: true },\n { name: 'status', summary: 'Show a run, or the project, status', commandType: 'status', json: true },\n {\n name: 'inspect',\n summary: 'Inspect one agent, context, approval, effect, snapshot, lock, diff or artifact',\n commandType: 'inspect',\n json: true,\n },\n { name: 'resume', summary: 'Resume a suspended run', commandType: 'resume', json: true },\n { name: 'pause', summary: 'Pause an active run', commandType: 'pause', json: true },\n { name: 'cancel', summary: 'Cancel a run', commandType: 'cancel', json: true },\n { name: 'shutdown', summary: 'Ask the detached host to shut down gracefully', commandType: 'shutdown', json: true },\n { name: 'approve', summary: 'Approve a pending approval request', commandType: 'approve', json: true },\n { name: 'deny', summary: 'Deny a pending approval request', commandType: 'deny', json: true },\n { name: 'retry', summary: 'Retry a phase or an agent', commandType: 'retry', json: true },\n { name: 'skip', summary: 'Skip a phase (only if policy.skip lists it)', commandType: 'skip', json: true },\n { name: 'logs', summary: 'Print durable run events' },\n { name: 'tail', summary: 'Follow a run (durable + ephemeral events)', commandType: 'tail' },\n { name: 'diff', summary: 'Show the run diff for a surface', json: true },\n { name: 'review', summary: 'Start a review-profile run over a ref range or a prior run' },\n { name: 'fix', summary: \"Retry a run's FIX phase\" },\n { name: 'ship', summary: 'Show and resolve the pending ship approval' },\n { name: 'auth', summary: 'Manage provider authentication', subVerbs: ['login', 'status', 'logout'], json: true },\n { name: 'providers', summary: 'List or test configured providers', subVerbs: ['list', 'test'] },\n { name: 'models', summary: 'List available models', subVerbs: ['list'] },\n {\n name: 'config',\n summary: 'Read, write, validate or trust the project configuration',\n subVerbs: ['get', 'set', 'validate', 'trust'],\n },\n { name: 'migrate', summary: 'Check or apply state-store migrations' },\n {\n name: 'reconcile',\n summary: 'Plan the project configuration against the discovered state',\n commandType: 'reconcile',\n json: true,\n },\n { name: 'spec', summary: 'Validate or freeze a human-written spec', subVerbs: ['validate', 'freeze'] },\n { name: 'policy', summary: 'Explain the effective security policy', subVerbs: ['explain'] },\n { name: 'gc', summary: 'Garbage-collect worktrees, spools and old runs' },\n {\n name: 'update',\n // DESIGN §9 spells it as a FLAG, `update --check`, not a sub-verb: the Wave-5 unit that fills\n // `commands/update/index.ts` reads `--check` from `args.options`/`args.positionals` like every other verb flag.\n summary: 'Check for a newer pinned install (offline, --check only in V3.0)',\n },\n { name: 'brainstorm', summary: 'Not available in V3.0 (reserved verb id, DESIGN §9)' },\n {\n name: 'run-tool',\n summary: 'Run one tool directly (admin; policy.admin.runTool)',\n commandType: 'run-tool',\n json: true,\n },\n {\n name: 'send',\n summary: 'Send text to a running agent (policy.steer.enabled)',\n commandType: 'agent.send',\n json: true,\n },\n { name: '__host', summary: 'Internal: run the detached host in-process', hidden: true },\n];\n\nconst BY_NAME = new Map(VERBS.map((verb) => [verb.name, verb]));\n\nexport function findVerb(name: string): VerbSpec | undefined {\n return BY_NAME.get(name);\n}\n\nexport const VERB_NAMES: readonly string[] = VERBS.map((verb) => verb.name);\n\n/** DESIGN 2.3.4: every `CommandType` has exactly one driving verb. Built from `VERBS`, so it can never drift. */\nexport const COMMAND_TYPE_TO_VERB: Readonly<Record<CommandType, string>> = Object.freeze(\n Object.fromEntries(\n VERBS.filter((verb): verb is VerbSpec & { commandType: CommandType } => verb.commandType !== undefined).map(\n (verb) => [verb.commandType, verb.name],\n ),\n ) as Record<CommandType, string>,\n);\n"],"mappings":"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"}
|
|
@@ -115,9 +115,9 @@ Type.Unsafe(Type.Object({
|
|
|
115
115
|
reason: Type.String()
|
|
116
116
|
}, closed)),
|
|
117
117
|
conflicts: Type.Array(Type.String()),
|
|
118
|
-
applyAvailable: Type.
|
|
118
|
+
applyAvailable: Type.Boolean()
|
|
119
119
|
}, closed));
|
|
120
120
|
//#endregion
|
|
121
121
|
export {};
|
|
122
122
|
|
|
123
|
-
//# sourceMappingURL=contract-
|
|
123
|
+
//# sourceMappingURL=contract-bQ9FJl4N.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-bQ9FJl4N.mjs","names":[],"sources":["../../../../packages/project-model/src/contract.ts"],"sourcesContent":["// @cohorte/project-model/contract (PLAN PC-4, spec 12-13): frozen in Wave 0 so that the scan unit and the drift unit\n// never import each other. Types are written by hand and the schema consts annotated: see docs/v3/requests/U0.02.md R1.\nimport { ID_PATTERN, IsoInstant, Sha256 } from '@cohorte/base';\nimport type { Manifest } from '@cohorte/config/schema';\nimport { type TSchema, type TUnsafe, Type } from 'typebox';\n\nconst closed = { additionalProperties: false } as const;\nconst oneOf = <const V extends readonly string[]>(values: V): TUnsafe<V[number]> =>\n Type.Unsafe<V[number]>({ type: 'string', enum: [...values] });\n\n/** Spec 13: every field of the model, and every file of `.cohorte/`, has exactly one class. */\nexport const FIELD_CLASSES = ['human', 'generated', 'derived', 'observed', 'mixed'] as const;\nexport type FieldClass = (typeof FIELD_CLASSES)[number];\n\n/** Spec 13: what the diff engine must tell apart. */\nexport const DIFF_CLASSES = [\n 'absent',\n 'expected-change',\n 'human-change',\n 'conflict',\n 'potential-deletion',\n 'unknown',\n] as const;\nexport type DiffClass = (typeof DIFF_CLASSES)[number];\n\nexport interface Provenance {\n /** which deterministic detector produced the value, e.g. 'package-json', 'lockfile', 'git', 'human-config' */\n detector: string;\n /** repo-relative POSIX paths the value was read from */\n sources: string[];\n /** 0..1; only a SEMANTIC inference carries one (spec 12), and V3.0 has none */\n confidence?: number;\n}\n\nexport interface ModelField<T> {\n value: T;\n class: FieldClass;\n provenance: Provenance;\n}\n\n/** Ambiguity is recorded, NEVER resolved by inventing a value (a command least of all). */\nexport interface Unknown {\n id: string;\n question: string;\n candidates: string[];\n sources: string[];\n}\n\nexport interface Risk {\n id: string;\n severity: 'high' | 'medium' | 'low';\n message: string;\n sources: string[];\n}\n\n/** Spec 12. `commands` are argv arrays, not the shell strings of the spec's example: the product is argv-only (I3, D-25). */\nexport interface ProjectModel {\n schemaVersion: 1;\n project: { id: ModelField<string>; root: ModelField<string> };\n stack: {\n languages: ModelField<string[]>;\n packageManager: ModelField<string | null>;\n frameworks: ModelField<string[]>;\n };\n surfaces: Record<string, { paths: ModelField<string[]> }>;\n commands: Record<string, ModelField<string[]>>;\n testStrategy: ModelField<{ runner: string | null; locations: string[] }>;\n deploymentHints: ModelField<string[]>;\n ownership: ModelField<{ codeowners: string | null }>;\n risks: Risk[];\n conventions: ModelField<string[]>;\n generatedArtifacts: ModelField<string[]>;\n unknowns: Unknown[];\n provenance: { generatedAt: IsoInstant; toolVersion: string; analysis: 'deterministic' };\n}\n\nconst strings = () => Type.Array(Type.String());\nconst ProvenanceSchema = Type.Object(\n {\n detector: Type.String({ minLength: 1 }),\n sources: strings(),\n confidence: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })),\n },\n closed,\n);\nconst field = (value: TSchema) =>\n Type.Object({ value, class: oneOf(FIELD_CLASSES), provenance: ProvenanceSchema }, closed);\nconst nullableString = () => Type.Union([Type.String(), Type.Null()]);\n\n/** [S] `.cohorte/project.yaml`, and the document `cohorte discover` prints. */\nexport const ProjectModel: TUnsafe<ProjectModel> = Type.Unsafe<ProjectModel>(\n Type.Object(\n {\n schemaVersion: Type.Literal(1),\n project: Type.Object({ id: field(Type.String({ pattern: ID_PATTERN })), root: field(Type.String()) }, closed),\n stack: Type.Object(\n { languages: field(strings()), packageManager: field(nullableString()), frameworks: field(strings()) },\n closed,\n ),\n surfaces: Type.Record(Type.String({ pattern: ID_PATTERN }), Type.Object({ paths: field(strings()) }, closed)),\n commands: Type.Record(Type.String(), field(Type.Array(Type.String(), { minItems: 1 }))),\n testStrategy: field(Type.Object({ runner: nullableString(), locations: strings() }, closed)),\n deploymentHints: field(strings()),\n ownership: field(Type.Object({ codeowners: nullableString() }, closed)),\n risks: Type.Array(\n Type.Object(\n {\n id: Type.String(),\n severity: oneOf(['high', 'medium', 'low']),\n message: Type.String(),\n sources: strings(),\n },\n closed,\n ),\n ),\n conventions: field(strings()),\n generatedArtifacts: field(strings()),\n unknowns: Type.Array(\n Type.Object({ id: Type.String(), question: Type.String(), candidates: strings(), sources: strings() }, closed),\n ),\n provenance: Type.Object(\n { generatedAt: IsoInstant, toolVersion: Type.String(), analysis: Type.Literal('deterministic') },\n closed,\n ),\n },\n closed,\n ),\n);\n\n/** One file Cohorte wants to exist under `.cohorte/` (desired) or found there (actual). */\nexport interface StateFile {\n /** `.cohorte`-relative POSIX path */\n path: string;\n class: FieldClass;\n sha256: Sha256;\n templateId?: string;\n /** Rendered content, kept in-memory for an authorized reconcile apply. */\n content?: string;\n}\nexport interface DesiredState {\n cohorteVersion: string;\n files: StateFile[];\n}\nexport interface ActualState {\n /** the manifest found on disk; null = not initialised */\n manifest: Manifest | null;\n files: StateFile[];\n}\n\nexport interface DriftEntry {\n /** `.cohorte`-relative POSIX path, or a JSON pointer into project.yaml prefixed with `project.yaml#` */\n target: string;\n class: FieldClass;\n diff: DiffClass;\n /** what the desired state renders to */\n desiredSha256?: Sha256;\n /** what is on disk */\n actualSha256?: Sha256;\n /** `renderedSha256` of the manifest: the previous-hash guard of spec 14 */\n recordedSha256?: Sha256;\n detail: string;\n}\n\nexport interface DriftReport {\n schemaVersion: 1;\n generatedAt: IsoInstant;\n entries: DriftEntry[];\n}\n\nexport const RECONCILE_OPS = ['create', 'replace', 'delete', 'keep', 'ask'] as const;\n\nexport interface ReconcileOperation {\n op: (typeof RECONCILE_OPS)[number];\n target: string;\n diff: DiffClass;\n reason: string;\n}\n\n/** The `--json` document of `cohorte reconcile --plan`. */\nexport interface ReconcilePlan {\n schemaVersion: 1;\n cohorteVersion: string;\n generatedAt: IsoInstant;\n drift: DriftReport;\n /** a human override is never in here as `replace` or `delete`: a collision is a `conflict` */\n operations: ReconcileOperation[];\n /** targets whose diff class is `conflict` */\n conflicts: string[];\n applyAvailable: boolean;\n}\n\nconst sha = () => Type.Optional(Sha256);\nconst DriftReportSchema = Type.Object(\n {\n schemaVersion: Type.Literal(1),\n generatedAt: IsoInstant,\n entries: Type.Array(\n Type.Object(\n {\n target: Type.String({ minLength: 1 }),\n class: oneOf(FIELD_CLASSES),\n diff: oneOf(DIFF_CLASSES),\n desiredSha256: sha(),\n actualSha256: sha(),\n recordedSha256: sha(),\n detail: Type.String(),\n },\n closed,\n ),\n ),\n },\n closed,\n);\n\n/** [S] */\nexport const DriftReport: TUnsafe<DriftReport> = Type.Unsafe<DriftReport>(DriftReportSchema);\n\n/** [S] published by `gen-schemas` */\nexport const ReconcilePlan: TUnsafe<ReconcilePlan> = Type.Unsafe<ReconcilePlan>(\n Type.Object(\n {\n schemaVersion: Type.Literal(1),\n cohorteVersion: Type.String({ minLength: 1 }),\n generatedAt: IsoInstant,\n drift: DriftReportSchema,\n operations: Type.Array(\n Type.Object(\n {\n op: oneOf(RECONCILE_OPS),\n target: Type.String({ minLength: 1 }),\n diff: oneOf(DIFF_CLASSES),\n reason: Type.String(),\n },\n closed,\n ),\n ),\n conflicts: Type.Array(Type.String()),\n applyAvailable: Type.Boolean(),\n },\n closed,\n ),\n);\n\nexport interface InitFile {\n /** `.cohorte`-relative POSIX path */\n path: string;\n /** an existing human file is NEVER overwritten */\n action: 'create' | 'keep-existing';\n class: FieldClass;\n content: string;\n templateId?: string;\n templateSha256?: Sha256;\n renderedSha256?: Sha256;\n}\n\n/** What `cohorte init` will do, computed without writing anything. Idempotent: planning twice yields the same plan. */\nexport interface InitPlan {\n projectRoot: string;\n model: ProjectModel;\n files: InitFile[];\n manifest: Manifest;\n warnings: string[];\n}\n\n/** INJECTED into `planReconcile`, so the drift unit never imports the scan unit. */\nexport type RepositoryScanner = (root: string) => Promise<ProjectModel>;\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as sha256Hex } from "./canonical-C8UxeEmB.mjs";
|
|
2
2
|
import "./src-Cu3TxNob.mjs";
|
|
3
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
3
|
import { execFile } from "node:child_process";
|
|
4
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
//#region src/commands/diff/index.ts
|
|
7
7
|
const exec = promisify(execFile);
|
|
@@ -98,4 +98,4 @@ const diff = {
|
|
|
98
98
|
//#endregion
|
|
99
99
|
export { diff as default };
|
|
100
100
|
|
|
101
|
-
//# sourceMappingURL=diff-
|
|
101
|
+
//# sourceMappingURL=diff-D_0hBwHl.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-
|
|
1
|
+
{"version":3,"file":"diff-D_0hBwHl.mjs","names":[],"sources":["../../../../apps/cli/src/commands/diff/index.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { promisify } from 'node:util';\nimport { sha256Hex } from '@cohorte/base';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst exec = promisify(execFile);\ntype GitRow = { path: string; op: 'create' | 'modify' | 'delete'; added: number; removed: number };\n\nasync function git(cwd: string, args: string[]): Promise<string> {\n const result = await exec('git', args, { cwd, maxBuffer: 4 * 1024 * 1024 });\n return result.stdout;\n}\n\nfunction parseNumstat(text: string): GitRow[] {\n return text\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const [addedText, removedText, ...pathParts] = line.split('\\t');\n const path = pathParts.join('\\t');\n const added = addedText === '-' ? 0 : Number(addedText);\n const removed = removedText === '-' ? 0 : Number(removedText);\n return {\n path,\n op: added === 0 && removed > 0 ? 'delete' : added > 0 && removed === 0 ? 'create' : 'modify',\n added,\n removed,\n };\n });\n}\n\nconst diff: CommandModule = {\n verb: 'diff',\n async run(ctx, args) {\n const runId = args.positionals[0];\n if (!runId) return 2;\n const store = await ctx.openStore();\n try {\n const tree = await store.readRunTree(runId as never);\n const run = tree.run;\n const worktree =\n tree.worktrees.find((item) => item.slot === (args.positionals[1] ?? '_integration')) ?? tree.worktrees[0];\n if (!worktree || !run.baseSha) return 3;\n const base = run.baseSha;\n const head = run.integrationHead ?? (await git(worktree.path, ['rev-parse', 'HEAD'])).trim();\n const rows = parseNumstat(await git(worktree.path, ['diff', '--numstat', `${base}..${head}`]));\n const patch = await git(worktree.path, ['diff', '--binary', `${base}..${head}`]);\n const artifactId = ctx.ids.next<'ArtifactId'>('art');\n const artifactDir = `${ctx.cwd}/.cohorte/runs/${runId}/artifacts`;\n const relativePatch = `.cohorte/runs/${runId}/artifacts/${artifactId}.patch`;\n await mkdir(artifactDir, { recursive: true, mode: 0o700 });\n await writeFile(`${ctx.cwd}/${relativePatch}`, patch, 'utf8');\n const document = {\n documentVersion: 1,\n runId,\n base: { branch: run.baseBranch, sha: base },\n head: {\n branch: run.integrationBranch ?? worktree.branch ?? 'HEAD',\n sha: head,\n treeDigest: (await git(worktree.path, ['rev-parse', `${head}^{tree}`])).trim(),\n },\n surfaces: [\n {\n surface: args.positionals[1] ?? 'shared',\n files: rows.map((row) => ({ path: row.path, op: row.op })),\n stat: {\n added: rows.reduce((sum, row) => sum + row.added, 0),\n removed: rows.reduce((sum, row) => sum + row.removed, 0),\n },\n patch: {\n artifactId,\n kind: 'patch',\n path: relativePatch,\n sha256: sha256Hex(patch),\n bytes: Buffer.byteLength(patch),\n },\n },\n ],\n };\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify(document)}\\n`);\n else ctx.stdio.stdout.write(patch);\n return 0;\n } finally {\n await store.close();\n }\n },\n};\n\nexport default diff;\n"],"mappings":";;;;;;AAMA,MAAM,OAAO,UAAU,QAAQ;AAG/B,eAAe,IAAI,KAAa,MAAiC;CAE/D,QAAO,MADc,KAAK,OAAO,MAAM;EAAE;EAAK,WAAW;CAAgB,CAAC,EAAA,CAC5D;AAChB;AAEA,SAAS,aAAa,MAAwB;CAC5C,OAAO,KACJ,MAAM,IAAI,CAAC,CACX,OAAO,OAAO,CAAC,CACf,KAAK,SAAS;EACb,MAAM,CAAC,WAAW,aAAa,GAAG,aAAa,KAAK,MAAM,GAAI;EAC9D,MAAM,OAAO,UAAU,KAAK,GAAI;EAChC,MAAM,QAAQ,cAAc,MAAM,IAAI,OAAO,SAAS;EACtD,MAAM,UAAU,gBAAgB,MAAM,IAAI,OAAO,WAAW;EAC5D,OAAO;GACL;GACA,IAAI,UAAU,KAAK,UAAU,IAAI,WAAW,QAAQ,KAAK,YAAY,IAAI,WAAW;GACpF;GACA;EACF;CACF,CAAC;AACL;AAEA,MAAM,OAAsB;CAC1B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,QAAQ,KAAK,YAAY;EAC/B,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,QAAQ,MAAM,IAAI,UAAU;EAClC,IAAI;GACF,MAAM,OAAO,MAAM,MAAM,YAAY,KAAc;GACnD,MAAM,MAAM,KAAK;GACjB,MAAM,WACJ,KAAK,UAAU,MAAM,SAAS,KAAK,UAAU,KAAK,YAAY,MAAM,eAAe,KAAK,KAAK,UAAU;GACzG,IAAI,CAAC,YAAY,CAAC,IAAI,SAAS,OAAO;GACtC,MAAM,OAAO,IAAI;GACjB,MAAM,OAAO,IAAI,oBAAoB,MAAM,IAAI,SAAS,MAAM,CAAC,aAAa,MAAM,CAAC,EAAA,CAAG,KAAK;GAC3F,MAAM,OAAO,aAAa,MAAM,IAAI,SAAS,MAAM;IAAC;IAAQ;IAAa,GAAG,KAAK,IAAI;GAAM,CAAC,CAAC;GAC7F,MAAM,QAAQ,MAAM,IAAI,SAAS,MAAM;IAAC;IAAQ;IAAY,GAAG,KAAK,IAAI;GAAM,CAAC;GAC/E,MAAM,aAAa,IAAI,IAAI,KAAmB,KAAK;GACnD,MAAM,cAAc,GAAG,IAAI,IAAI,iBAAiB,MAAM;GACtD,MAAM,gBAAgB,iBAAiB,MAAM,aAAa,WAAW;GACrE,MAAM,MAAM,aAAa;IAAE,WAAW;IAAM,MAAM;GAAM,CAAC;GACzD,MAAM,UAAU,GAAG,IAAI,IAAI,GAAG,iBAAiB,OAAO,MAAM;GAC5D,MAAM,WAAW;IACf,iBAAiB;IACjB;IACA,MAAM;KAAE,QAAQ,IAAI;KAAY,KAAK;IAAK;IAC1C,MAAM;KACJ,QAAQ,IAAI,qBAAqB,SAAS,UAAU;KACpD,KAAK;KACL,aAAa,MAAM,IAAI,SAAS,MAAM,CAAC,aAAa,GAAG,KAAK,QAAQ,CAAC,EAAA,CAAG,KAAK;IAC/E;IACA,UAAU,CACR;KACE,SAAS,KAAK,YAAY,MAAM;KAChC,OAAO,KAAK,KAAK,SAAS;MAAE,MAAM,IAAI;MAAM,IAAI,IAAI;KAAG,EAAE;KACzD,MAAM;MACJ,OAAO,KAAK,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,CAAC;MACnD,SAAS,KAAK,QAAQ,KAAK,QAAQ,MAAM,IAAI,SAAS,CAAC;KACzD;KACA,OAAO;MACL;MACA,MAAM;MACN,MAAM;MACN,QAAQ,UAAU,KAAK;MACvB,OAAO,OAAO,WAAW,KAAK;KAChC;IACF,CACF;GACF;GACA,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,EAAE,GAAG;QAChE,IAAI,MAAM,OAAO,MAAM,KAAK;GACjC,OAAO;EACT,UAAU;GACR,MAAM,MAAM,MAAM;EACpB;CACF;AACF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { N as errorOf, j as CohorteError } from "./src-Cu3TxNob.mjs";
|
|
2
|
-
import
|
|
2
|
+
import "./src-CmFjh4M0.mjs";
|
|
3
|
+
import { t as scanRepository } from "./scan-8Gy_B6kI.mjs";
|
|
3
4
|
//#region src/commands/discover/index.ts
|
|
4
5
|
const discover = {
|
|
5
6
|
verb: "discover",
|
|
@@ -17,4 +18,4 @@ const discover = {
|
|
|
17
18
|
//#endregion
|
|
18
19
|
export { discover as default };
|
|
19
20
|
|
|
20
|
-
//# sourceMappingURL=discover-
|
|
21
|
+
//# sourceMappingURL=discover-eS01-me1.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover-
|
|
1
|
+
{"version":3,"file":"discover-eS01-me1.mjs","names":[],"sources":["../../../../apps/cli/src/commands/discover/index.ts"],"sourcesContent":["import { CohorteError, errorOf } from '@cohorte/base';\nimport { scanRepository } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst discover: CommandModule = {\n verb: 'discover',\n async run(ctx, args) {\n if (args.positionals.includes('--semantic')) {\n throw new CohorteError(\n errorOf('configuration/phase-not-available', 'semantic discovery is not available in V3.0'),\n );\n }\n const model = await scanRepository(ctx.cwd, { clock: ctx.clock, toolVersion: '3.0.0' });\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify(model)}\\n`);\n else ctx.stdio.stdout.write(`${JSON.stringify(model, null, 2)}\\n`);\n return 0;\n },\n};\n\nexport default discover;\n"],"mappings":";;;;AAIA,MAAM,WAA0B;CAC9B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,IAAI,KAAK,YAAY,SAAS,YAAY,GACxC,MAAM,IAAI,aACR,QAAQ,qCAAqC,6CAA6C,CAC5F;EAEF,MAAM,QAAQ,MAAM,eAAe,IAAI,KAAK;GAAE,OAAO,IAAI;GAAO,aAAa;EAAQ,CAAC;EACtF,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;OAC7D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,GAAG;EACjE,OAAO;CACT;AACF"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { n as sha256Hex } from "./canonical-C8UxeEmB.mjs";
|
|
2
2
|
import "./src-Cu3TxNob.mjs";
|
|
3
3
|
import { n as createKeyStore, r as createTrustStore } from "./auth-BT5oVp76.mjs";
|
|
4
|
-
import "./contract-
|
|
4
|
+
import "./contract-BkMjU1kR.mjs";
|
|
5
5
|
import { i as resolveConfig, n as loadConfig } from "./src-DcU4IXMe.mjs";
|
|
6
|
-
import { _ as probeSandbox } from "./src-
|
|
7
|
-
import { l as verifyProjectionAgainstEvents } from "./src-
|
|
8
|
-
import { join } from "node:path";
|
|
6
|
+
import { _ as probeSandbox } from "./src-r0ECB1UJ.mjs";
|
|
7
|
+
import { l as verifyProjectionAgainstEvents } from "./src-DZazJCp1.mjs";
|
|
9
8
|
import { execFile } from "node:child_process";
|
|
9
|
+
import { join } from "node:path";
|
|
10
10
|
import { promisify } from "node:util";
|
|
11
11
|
//#region src/contract/doctor.ts
|
|
12
12
|
/** DESIGN §9 doctor capabilities + F-1 (ripgrep backend) + F-3 (sandbox availability) + 6.3 (protected roots). */
|
|
@@ -219,4 +219,4 @@ const doctor = {
|
|
|
219
219
|
//#endregion
|
|
220
220
|
export { doctor as default };
|
|
221
221
|
|
|
222
|
-
//# sourceMappingURL=doctor-
|
|
222
|
+
//# sourceMappingURL=doctor-CginW8y8.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-DfCrKpfT.mjs","names":[],"sources":["../../../../apps/cli/src/contract/doctor.ts","../../../../apps/cli/src/doctor/checks/auth/index.ts","../../../../apps/cli/src/doctor/index.ts","../../../../apps/cli/src/commands/doctor/index.ts"],"sourcesContent":["// apps/cli/src/contract/doctor.ts — the frozen list of doctor check modules (PLAN PC-4 \"DoctorCheck + the frozen\n// list of doctor check modules\"). `doctor/index.ts` (area barrel, U4.05) runs every id of `DOCTOR_CHECK_IDS`\n// through `doctor/checks/<id>/index.ts`; only `auth` is a Wave-0 owned stub (`apps/cli/src/doctor/checks/auth`,\n// filled by U5.05) — the rest are created, under the same shape, by U4.05.\nimport type { DOCTOR_CHECK_STATUSES } from '@cohorte/protocol';\nimport type { CliContext } from './context.ts';\n\nexport type DoctorCheckStatus = (typeof DOCTOR_CHECK_STATUSES)[number];\n\nexport interface DoctorCheckResult {\n readonly id: string;\n readonly status: DoctorCheckStatus;\n readonly summary: string;\n readonly remediation?: string;\n}\n\nexport interface DoctorCheck {\n readonly id: string;\n readonly description: string;\n run(ctx: CliContext): Promise<DoctorCheckResult>;\n}\n\n/** DESIGN §9 doctor capabilities + F-1 (ripgrep backend) + F-3 (sandbox availability) + 6.3 (protected roots). */\nexport const DOCTOR_CHECK_IDS = [\n 'node-version',\n 'git',\n 'sqlite',\n 'search-backend',\n 'sandbox',\n 'auth',\n 'install',\n 'config',\n 'worktree-root',\n] as const;\nexport type DoctorCheckId = (typeof DOCTOR_CHECK_IDS)[number];\n","// apps/cli/src/doctor/checks/auth/index.ts — the `auth` doctor check (spec 10 \"auth status\"). Wave-0 typed stub:\n// filled by `U5.05`, which owns `apps/cli/src/doctor/checks/auth/**`.\nimport type { DoctorCheck } from '../../../contract/index.ts';\n\nconst authDoctorCheck: DoctorCheck = {\n id: 'auth',\n description: \"Checks that the configured provider's authentication is usable, without reading the token.\",\n async run(ctx) {\n try {\n const statuses = await ctx.runtime.resolve().authStatus([]);\n const usable = statuses.every((status) => status.state !== 'absent' && status.state !== 'unknown-transient');\n const accountNote = statuses.some((status) => status.accountLabel === undefined)\n ? '; account: not exposed by the engine'\n : '';\n return {\n id: 'auth',\n status: usable ? 'ok' : 'warning',\n summary: `${usable ? 'runtime authentication is available' : 'runtime authentication needs attention'}${accountNote}`,\n };\n } catch (error) {\n return { id: 'auth', status: 'error', summary: `authentication status unavailable: ${String(error)}` };\n }\n },\n};\n\nexport default authDoctorCheck;\n","// apps/cli/src/doctor/index.ts — AREA barrel: runs every `DOCTOR_CHECK_IDS` entry (contract/doctor.ts) through\n// `doctor/checks/<id>/index.ts` and assembles a `DoctorReport`. Wave-0 stub: filled by `U4.05`, which owns\n// `apps/cli/src/doctor/**` (this file included); only `checks/auth/**` is carved out to `U5.05`.\nimport { execFile } from 'node:child_process';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { sha256Hex } from '@cohorte/base';\nimport { loadConfig, resolveConfig } from '@cohorte/config';\nimport { verifyProjectionAgainstEvents } from '@cohorte/core';\nimport { createKeyStore, createTrustStore } from '@cohorte/security/auth';\nimport { probeSandbox } from '@cohorte/security/exec';\nimport { type CliContext, DOCTOR_CHECK_IDS, type DoctorCheck, type DoctorCheckResult } from '../contract/index.ts';\nimport authDoctorCheck from './checks/auth/index.ts';\n\nconst exec = promisify(execFile);\nconst result = (id: string, summary: string, status: DoctorCheckResult['status'] = 'ok'): DoctorCheckResult => ({\n id,\n summary,\n status,\n});\n\nfunction versionAtLeast(value: string, required: [number, number]): boolean {\n const [major = 0, minor = 0] = value.split('.').map((part) => Number.parseInt(part, 10));\n return major > required[0] || (major === required[0] && minor >= required[1]);\n}\n\nexport async function runDoctor(\n ctx: CliContext,\n options: { readonly verifyState?: boolean } = {},\n): Promise<readonly DoctorCheckResult[]> {\n const checks: DoctorCheck[] = [\n {\n id: 'node-version',\n description: 'Node',\n run: async () =>\n versionAtLeast(process.versions.node, [24, 16])\n ? result('node-version', `Node ${process.versions.node}`)\n : result('node-version', `Node ${process.versions.node} is below 24.16`, 'error'),\n },\n {\n id: 'git',\n description: 'Git',\n run: async () => {\n try {\n const { stdout } = await exec('git', ['--version']);\n const version = stdout.match(/(\\d+\\.\\d+(?:\\.\\d+)?)/)?.[1] ?? '0.0.0';\n return versionAtLeast(version, [2, 38])\n ? result('git', `Git ${version}`)\n : result('git', `Git ${version} is below 2.38`, 'error');\n } catch (error) {\n return result('git', `git unavailable: ${String(error)}`, 'error');\n }\n },\n },\n {\n id: 'sqlite',\n description: 'SQLite',\n run: async () => {\n try {\n const store = await ctx.openStore();\n const info = await store.open();\n const migration = await store.migrate('check');\n await store.close();\n return migration.pending.length === 0\n ? result('sqlite', `${info.kind} schema ${info.schemaVersion}`)\n : result('sqlite', `${migration.pending.length} migration(s) pending`, 'warning');\n } catch (error) {\n return result('sqlite', `state store unavailable: ${String(error)}`, 'error');\n }\n },\n },\n {\n id: 'search-backend',\n description: 'Search',\n run: async () => {\n try {\n const { stdout } = await exec('rg', ['--version']);\n return result('search-backend', `ripgrep ${stdout.split(/\\s+/u)[1] ?? 'available'}`);\n } catch {\n try {\n await exec('git', ['grep', '--version']);\n return result('search-backend', 'git grep fallback');\n } catch {\n return result('search-backend', 'neither rg nor git grep is available', 'error');\n }\n }\n },\n },\n {\n id: 'sandbox',\n description: 'Sandbox',\n run: async () => {\n const capabilities = await probeSandbox();\n return result(\n 'sandbox',\n `level=${capabilities.level}, backend=${capabilities.backend}, filesystem=${capabilities.filesystem}, network=${capabilities.network}`,\n capabilities.level === 'L0-process' ? 'warning' : 'ok',\n );\n },\n },\n authDoctorCheck,\n {\n id: 'install',\n description: 'Install',\n run: async () => {\n try {\n const verified = await ctx.assets.verify();\n return verified.ok\n ? result('install', `${ctx.install.installDir()} (assets verified)`)\n : result('install', `asset verification failed: ${verified.error.message}`, 'error');\n } catch (error) {\n return result('install', `asset verification unavailable: ${String(error)}`, 'warning');\n }\n },\n },\n {\n id: 'config',\n description: 'Config',\n run: async () => {\n try {\n const home = ctx.env.HOME ?? ctx.cwd;\n const keys = createKeyStore({ directory: join(home, '.cohorte', 'keys') });\n const trustStore = createTrustStore({ directory: join(home, '.cohorte', 'trust'), keys });\n const loaded = await loadConfig({ cwd: ctx.cwd, home });\n const resolved = await resolveConfig(loaded, {\n trustStore,\n projectKeyId: sha256Hex(loaded.projectRoot).slice(0, 24),\n });\n return resolved.status === 'resolved'\n ? result('config', `project configuration resolved at ${loaded.projectRoot}`)\n : result('config', `project policy requires trust: ${resolved.loosenedKeys.join(', ')}`, 'warning');\n } catch (error) {\n return result('config', `configuration unavailable: ${String(error)}`, 'error');\n }\n },\n },\n {\n id: 'worktree-root',\n description: 'Worktree',\n run: async () =>\n typeof process.getuid === 'function' && process.getuid() === 0\n ? result('worktree-root', 'refusing to operate as uid 0', 'error')\n : result('worktree-root', ctx.cwd),\n },\n ];\n if (options.verifyState) {\n checks.push({\n id: 'verify-state',\n description: 'State verification',\n run: async () => {\n const store = await ctx.openStore();\n try {\n const runs = await store.listRuns({ limit: 100_000, offset: 0 });\n for (const run of runs) {\n const chain = await store.verifyChain(run.runId);\n if (!chain.ok) return result('verify-state', `run ${run.runId}: event chain is broken`, 'error');\n try {\n await verifyProjectionAgainstEvents(store, run);\n } catch (error) {\n return result('verify-state', `run ${run.runId}: projection mismatch (${String(error)})`, 'error');\n }\n }\n return result('verify-state', `verified ${runs.length} run(s)`);\n } finally {\n await store.close();\n }\n },\n });\n }\n const byId = new Map(checks.map((check) => [check.id, check]));\n return Promise.all(\n DOCTOR_CHECK_IDS.map(async (id) => byId.get(id)?.run(ctx) ?? result(id, 'check unavailable', 'skipped')),\n );\n}\n","// apps/cli/src/commands/doctor/index.ts — DESIGN §9 verb `doctor` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/doctor/**`.\nimport { probeSandbox } from '@cohorte/security/exec';\nimport type { CommandModule } from '../../contract/index.ts';\nimport { runDoctor } from '../../doctor/index.ts';\n\nconst doctor: CommandModule = {\n verb: 'doctor',\n async run(ctx, args) {\n const checks = await runDoctor(ctx, { verifyState: args.positionals.includes('--verify-state') });\n if (args.json) {\n let sandbox: unknown = {};\n let runtimeCapabilities: unknown = {};\n try {\n sandbox = await probeSandbox();\n } catch {\n // The corresponding check already reports the diagnostic; keep JSON stable.\n }\n try {\n runtimeCapabilities = ctx.runtime.capabilities?.() ?? { provider: ctx.runtime.resolve().id };\n } catch {\n // A provider may be unavailable while the rest of doctor remains useful.\n }\n ctx.stdio.stdout.write(\n `${JSON.stringify({ documentVersion: 1, cohorteVersion: '3.0.0', generatedAt: ctx.clock.now(), ok: checks.every((check) => check.status === 'ok' || check.status === 'skipped'), checks, sandbox, runtimeCapabilities })}\\n`,\n );\n } else\n for (const check of checks) ctx.stdio.stdout.write(`${check.status.padEnd(7)} ${check.id}: ${check.summary}\\n`);\n return checks.some((check) => check.status === 'error') ? 1 : 0;\n },\n};\n\nexport default doctor;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"doctor-CginW8y8.mjs","names":[],"sources":["../../../../apps/cli/src/contract/doctor.ts","../../../../apps/cli/src/doctor/checks/auth/index.ts","../../../../apps/cli/src/doctor/index.ts","../../../../apps/cli/src/commands/doctor/index.ts"],"sourcesContent":["// apps/cli/src/contract/doctor.ts — the frozen list of doctor check modules (PLAN PC-4 \"DoctorCheck + the frozen\n// list of doctor check modules\"). `doctor/index.ts` (area barrel, U4.05) runs every id of `DOCTOR_CHECK_IDS`\n// through `doctor/checks/<id>/index.ts`; only `auth` is a Wave-0 owned stub (`apps/cli/src/doctor/checks/auth`,\n// filled by U5.05) — the rest are created, under the same shape, by U4.05.\nimport type { DOCTOR_CHECK_STATUSES } from '@cohorte/protocol';\nimport type { CliContext } from './context.ts';\n\nexport type DoctorCheckStatus = (typeof DOCTOR_CHECK_STATUSES)[number];\n\nexport interface DoctorCheckResult {\n readonly id: string;\n readonly status: DoctorCheckStatus;\n readonly summary: string;\n readonly remediation?: string;\n}\n\nexport interface DoctorCheck {\n readonly id: string;\n readonly description: string;\n run(ctx: CliContext): Promise<DoctorCheckResult>;\n}\n\n/** DESIGN §9 doctor capabilities + F-1 (ripgrep backend) + F-3 (sandbox availability) + 6.3 (protected roots). */\nexport const DOCTOR_CHECK_IDS = [\n 'node-version',\n 'git',\n 'sqlite',\n 'search-backend',\n 'sandbox',\n 'auth',\n 'install',\n 'config',\n 'worktree-root',\n] as const;\nexport type DoctorCheckId = (typeof DOCTOR_CHECK_IDS)[number];\n","// apps/cli/src/doctor/checks/auth/index.ts — the `auth` doctor check (spec 10 \"auth status\"). Wave-0 typed stub:\n// filled by `U5.05`, which owns `apps/cli/src/doctor/checks/auth/**`.\nimport type { DoctorCheck } from '../../../contract/index.ts';\n\nconst authDoctorCheck: DoctorCheck = {\n id: 'auth',\n description: \"Checks that the configured provider's authentication is usable, without reading the token.\",\n async run(ctx) {\n try {\n const statuses = await ctx.runtime.resolve().authStatus([]);\n const usable = statuses.every((status) => status.state !== 'absent' && status.state !== 'unknown-transient');\n const accountNote = statuses.some((status) => status.accountLabel === undefined)\n ? '; account: not exposed by the engine'\n : '';\n return {\n id: 'auth',\n status: usable ? 'ok' : 'warning',\n summary: `${usable ? 'runtime authentication is available' : 'runtime authentication needs attention'}${accountNote}`,\n };\n } catch (error) {\n return { id: 'auth', status: 'error', summary: `authentication status unavailable: ${String(error)}` };\n }\n },\n};\n\nexport default authDoctorCheck;\n","// apps/cli/src/doctor/index.ts — AREA barrel: runs every `DOCTOR_CHECK_IDS` entry (contract/doctor.ts) through\n// `doctor/checks/<id>/index.ts` and assembles a `DoctorReport`. Wave-0 stub: filled by `U4.05`, which owns\n// `apps/cli/src/doctor/**` (this file included); only `checks/auth/**` is carved out to `U5.05`.\nimport { execFile } from 'node:child_process';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { sha256Hex } from '@cohorte/base';\nimport { loadConfig, resolveConfig } from '@cohorte/config';\nimport { verifyProjectionAgainstEvents } from '@cohorte/core';\nimport { createKeyStore, createTrustStore } from '@cohorte/security/auth';\nimport { probeSandbox } from '@cohorte/security/exec';\nimport { type CliContext, DOCTOR_CHECK_IDS, type DoctorCheck, type DoctorCheckResult } from '../contract/index.ts';\nimport authDoctorCheck from './checks/auth/index.ts';\n\nconst exec = promisify(execFile);\nconst result = (id: string, summary: string, status: DoctorCheckResult['status'] = 'ok'): DoctorCheckResult => ({\n id,\n summary,\n status,\n});\n\nfunction versionAtLeast(value: string, required: [number, number]): boolean {\n const [major = 0, minor = 0] = value.split('.').map((part) => Number.parseInt(part, 10));\n return major > required[0] || (major === required[0] && minor >= required[1]);\n}\n\nexport async function runDoctor(\n ctx: CliContext,\n options: { readonly verifyState?: boolean } = {},\n): Promise<readonly DoctorCheckResult[]> {\n const checks: DoctorCheck[] = [\n {\n id: 'node-version',\n description: 'Node',\n run: async () =>\n versionAtLeast(process.versions.node, [24, 16])\n ? result('node-version', `Node ${process.versions.node}`)\n : result('node-version', `Node ${process.versions.node} is below 24.16`, 'error'),\n },\n {\n id: 'git',\n description: 'Git',\n run: async () => {\n try {\n const { stdout } = await exec('git', ['--version']);\n const version = stdout.match(/(\\d+\\.\\d+(?:\\.\\d+)?)/)?.[1] ?? '0.0.0';\n return versionAtLeast(version, [2, 38])\n ? result('git', `Git ${version}`)\n : result('git', `Git ${version} is below 2.38`, 'error');\n } catch (error) {\n return result('git', `git unavailable: ${String(error)}`, 'error');\n }\n },\n },\n {\n id: 'sqlite',\n description: 'SQLite',\n run: async () => {\n try {\n const store = await ctx.openStore();\n const info = await store.open();\n const migration = await store.migrate('check');\n await store.close();\n return migration.pending.length === 0\n ? result('sqlite', `${info.kind} schema ${info.schemaVersion}`)\n : result('sqlite', `${migration.pending.length} migration(s) pending`, 'warning');\n } catch (error) {\n return result('sqlite', `state store unavailable: ${String(error)}`, 'error');\n }\n },\n },\n {\n id: 'search-backend',\n description: 'Search',\n run: async () => {\n try {\n const { stdout } = await exec('rg', ['--version']);\n return result('search-backend', `ripgrep ${stdout.split(/\\s+/u)[1] ?? 'available'}`);\n } catch {\n try {\n await exec('git', ['grep', '--version']);\n return result('search-backend', 'git grep fallback');\n } catch {\n return result('search-backend', 'neither rg nor git grep is available', 'error');\n }\n }\n },\n },\n {\n id: 'sandbox',\n description: 'Sandbox',\n run: async () => {\n const capabilities = await probeSandbox();\n return result(\n 'sandbox',\n `level=${capabilities.level}, backend=${capabilities.backend}, filesystem=${capabilities.filesystem}, network=${capabilities.network}`,\n capabilities.level === 'L0-process' ? 'warning' : 'ok',\n );\n },\n },\n authDoctorCheck,\n {\n id: 'install',\n description: 'Install',\n run: async () => {\n try {\n const verified = await ctx.assets.verify();\n return verified.ok\n ? result('install', `${ctx.install.installDir()} (assets verified)`)\n : result('install', `asset verification failed: ${verified.error.message}`, 'error');\n } catch (error) {\n return result('install', `asset verification unavailable: ${String(error)}`, 'warning');\n }\n },\n },\n {\n id: 'config',\n description: 'Config',\n run: async () => {\n try {\n const home = ctx.env.HOME ?? ctx.cwd;\n const keys = createKeyStore({ directory: join(home, '.cohorte', 'keys') });\n const trustStore = createTrustStore({ directory: join(home, '.cohorte', 'trust'), keys });\n const loaded = await loadConfig({ cwd: ctx.cwd, home });\n const resolved = await resolveConfig(loaded, {\n trustStore,\n projectKeyId: sha256Hex(loaded.projectRoot).slice(0, 24),\n });\n return resolved.status === 'resolved'\n ? result('config', `project configuration resolved at ${loaded.projectRoot}`)\n : result('config', `project policy requires trust: ${resolved.loosenedKeys.join(', ')}`, 'warning');\n } catch (error) {\n return result('config', `configuration unavailable: ${String(error)}`, 'error');\n }\n },\n },\n {\n id: 'worktree-root',\n description: 'Worktree',\n run: async () =>\n typeof process.getuid === 'function' && process.getuid() === 0\n ? result('worktree-root', 'refusing to operate as uid 0', 'error')\n : result('worktree-root', ctx.cwd),\n },\n ];\n if (options.verifyState) {\n checks.push({\n id: 'verify-state',\n description: 'State verification',\n run: async () => {\n const store = await ctx.openStore();\n try {\n const runs = await store.listRuns({ limit: 100_000, offset: 0 });\n for (const run of runs) {\n const chain = await store.verifyChain(run.runId);\n if (!chain.ok) return result('verify-state', `run ${run.runId}: event chain is broken`, 'error');\n try {\n await verifyProjectionAgainstEvents(store, run);\n } catch (error) {\n return result('verify-state', `run ${run.runId}: projection mismatch (${String(error)})`, 'error');\n }\n }\n return result('verify-state', `verified ${runs.length} run(s)`);\n } finally {\n await store.close();\n }\n },\n });\n }\n const byId = new Map(checks.map((check) => [check.id, check]));\n return Promise.all(\n DOCTOR_CHECK_IDS.map(async (id) => byId.get(id)?.run(ctx) ?? result(id, 'check unavailable', 'skipped')),\n );\n}\n","// apps/cli/src/commands/doctor/index.ts — DESIGN §9 verb `doctor` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/doctor/**`.\nimport { probeSandbox } from '@cohorte/security/exec';\nimport type { CommandModule } from '../../contract/index.ts';\nimport { runDoctor } from '../../doctor/index.ts';\n\nconst doctor: CommandModule = {\n verb: 'doctor',\n async run(ctx, args) {\n const checks = await runDoctor(ctx, { verifyState: args.positionals.includes('--verify-state') });\n if (args.json) {\n let sandbox: unknown = {};\n let runtimeCapabilities: unknown = {};\n try {\n sandbox = await probeSandbox();\n } catch {\n // The corresponding check already reports the diagnostic; keep JSON stable.\n }\n try {\n runtimeCapabilities = ctx.runtime.capabilities?.() ?? { provider: ctx.runtime.resolve().id };\n } catch {\n // A provider may be unavailable while the rest of doctor remains useful.\n }\n ctx.stdio.stdout.write(\n `${JSON.stringify({ documentVersion: 1, cohorteVersion: '3.0.0', generatedAt: ctx.clock.now(), ok: checks.every((check) => check.status === 'ok' || check.status === 'skipped'), checks, sandbox, runtimeCapabilities })}\\n`,\n );\n } else\n for (const check of checks) ctx.stdio.stdout.write(`${check.status.padEnd(7)} ${check.id}: ${check.summary}\\n`);\n return checks.some((check) => check.status === 'error') ? 1 : 0;\n },\n};\n\nexport default doctor;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { a as applyV2Import, i as planInit, o as exportV2, r as applyInit, s as planV2Import } from "./src-CmFjh4M0.mjs";
|
|
2
|
+
import { t as scanRepository } from "./scan-8Gy_B6kI.mjs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
//#region src/commands/init/index.ts
|
|
5
|
+
const init = {
|
|
6
|
+
verb: "init",
|
|
7
|
+
async run(ctx, args) {
|
|
8
|
+
const fromV2 = args.positionals.indexOf("--from-v2");
|
|
9
|
+
const exportV2At = args.positionals.indexOf("--export-v2");
|
|
10
|
+
const optionValues = new Set([fromV2, exportV2At].filter((index) => index !== -1).map((index) => args.positionals[index + 1]).filter((value) => value !== void 0));
|
|
11
|
+
const requestedRoot = args.positionals.find((value) => !value.startsWith("--") && !optionValues.has(value));
|
|
12
|
+
const root = requestedRoot === void 0 ? ctx.cwd : resolve(ctx.cwd, requestedRoot);
|
|
13
|
+
if (fromV2 !== -1) {
|
|
14
|
+
const bundle = args.positionals[fromV2 + 1];
|
|
15
|
+
if (!bundle) throw new Error("configuration/import-invalid: init --from-v2 requires a bundle directory");
|
|
16
|
+
const model = await scanRepository(root, {
|
|
17
|
+
clock: ctx.clock,
|
|
18
|
+
toolVersion: "3.0.0-v2-import"
|
|
19
|
+
});
|
|
20
|
+
const plan = await planV2Import(resolve(ctx.cwd, bundle), root, { model });
|
|
21
|
+
if (!args.positionals.includes("--yes")) {
|
|
22
|
+
ctx.stdio.stdout.write(`${JSON.stringify(plan, null, 2)}\n`);
|
|
23
|
+
return plan.conflicts.length ? 3 : 0;
|
|
24
|
+
}
|
|
25
|
+
const result = await applyV2Import(plan, {
|
|
26
|
+
confirm: args.positionals.includes("--yes"),
|
|
27
|
+
backupRoot: resolve(root, "..", ".cohorte-migration-backups")
|
|
28
|
+
});
|
|
29
|
+
ctx.stdio.stdout.write(`${JSON.stringify(result)}\n`);
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
if (exportV2At !== -1) {
|
|
33
|
+
const destination = args.positionals[exportV2At + 1];
|
|
34
|
+
if (!destination) throw new Error("configuration/import-invalid: init --export-v2 requires a destination");
|
|
35
|
+
const result = await exportV2({
|
|
36
|
+
root,
|
|
37
|
+
destination: resolve(ctx.cwd, destination)
|
|
38
|
+
});
|
|
39
|
+
ctx.stdio.stdout.write(`${JSON.stringify(result)}\n`);
|
|
40
|
+
return result.manifest.warnings.some((item) => item.blocking) ? 3 : 0;
|
|
41
|
+
}
|
|
42
|
+
const model = await scanRepository(root, {
|
|
43
|
+
clock: ctx.clock,
|
|
44
|
+
toolVersion: "3.0.0"
|
|
45
|
+
});
|
|
46
|
+
const plan = await planInit({
|
|
47
|
+
root,
|
|
48
|
+
model,
|
|
49
|
+
cohorteVersion: "3.0.0"
|
|
50
|
+
});
|
|
51
|
+
if (args.positionals.includes("--plan") || args.json) {
|
|
52
|
+
ctx.stdio.stdout.write(`${JSON.stringify(plan)}\n`);
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
const result = await applyInit(plan);
|
|
56
|
+
ctx.stdio.stdout.write(`written: ${result.written.join(", ") || "none"}\n`);
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { init as default };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=init-BUnzIkeE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-BUnzIkeE.mjs","names":[],"sources":["../../../../apps/cli/src/commands/init/index.ts"],"sourcesContent":["// apps/cli/src/commands/init/index.ts — DESIGN §9 verb `init` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/init/**`.\nimport { resolve } from 'node:path';\nimport { applyInit, applyV2Import, exportV2, planInit, planV2Import, scanRepository } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst init: CommandModule = {\n verb: 'init',\n async run(ctx, args) {\n const fromV2 = args.positionals.indexOf('--from-v2');\n const exportV2At = args.positionals.indexOf('--export-v2');\n const optionValues = new Set(\n [fromV2, exportV2At]\n .filter((index) => index !== -1)\n .map((index) => args.positionals[index + 1])\n .filter((value): value is string => value !== undefined),\n );\n const requestedRoot = args.positionals.find((value) => !value.startsWith('--') && !optionValues.has(value));\n const root = requestedRoot === undefined ? ctx.cwd : resolve(ctx.cwd, requestedRoot);\n if (fromV2 !== -1) {\n const bundle = args.positionals[fromV2 + 1];\n if (!bundle) throw new Error('configuration/import-invalid: init --from-v2 requires a bundle directory');\n const model = await scanRepository(root, { clock: ctx.clock, toolVersion: '3.0.0-v2-import' });\n const plan = await planV2Import(resolve(ctx.cwd, bundle), root, { model });\n if (!args.positionals.includes('--yes')) {\n ctx.stdio.stdout.write(`${JSON.stringify(plan, null, 2)}\\n`);\n return plan.conflicts.length ? 3 : 0;\n }\n const result = await applyV2Import(plan, {\n confirm: args.positionals.includes('--yes'),\n backupRoot: resolve(root, '..', '.cohorte-migration-backups'),\n });\n ctx.stdio.stdout.write(`${JSON.stringify(result)}\\n`);\n return 0;\n }\n if (exportV2At !== -1) {\n const destination = args.positionals[exportV2At + 1];\n if (!destination) throw new Error('configuration/import-invalid: init --export-v2 requires a destination');\n const result = await exportV2({ root, destination: resolve(ctx.cwd, destination) });\n ctx.stdio.stdout.write(`${JSON.stringify(result)}\\n`);\n return result.manifest.warnings.some((item) => item.blocking) ? 3 : 0;\n }\n const model = await scanRepository(root, { clock: ctx.clock, toolVersion: '3.0.0' });\n const plan = await planInit({ root, model, cohorteVersion: '3.0.0' });\n if (args.positionals.includes('--plan') || args.json) {\n ctx.stdio.stdout.write(`${JSON.stringify(plan)}\\n`);\n return 0;\n }\n const result = await applyInit(plan);\n ctx.stdio.stdout.write(`written: ${result.written.join(', ') || 'none'}\\n`);\n return 0;\n },\n};\n\nexport default init;\n"],"mappings":";;;;AAQA,MAAM,OAAsB;CAC1B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,SAAS,KAAK,YAAY,QAAQ,WAAW;EACnD,MAAM,aAAa,KAAK,YAAY,QAAQ,aAAa;EACzD,MAAM,eAAe,IAAI,IACvB,CAAC,QAAQ,UAAU,CAAC,CACjB,QAAQ,UAAU,UAAU,EAAE,CAAC,CAC/B,KAAK,UAAU,KAAK,YAAY,QAAQ,EAAE,CAAC,CAC3C,QAAQ,UAA2B,UAAU,KAAA,CAAS,CAC3D;EACA,MAAM,gBAAgB,KAAK,YAAY,MAAM,UAAU,CAAC,MAAM,WAAW,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC;EAC1G,MAAM,OAAO,kBAAkB,KAAA,IAAY,IAAI,MAAM,QAAQ,IAAI,KAAK,aAAa;EACnF,IAAI,WAAW,IAAI;GACjB,MAAM,SAAS,KAAK,YAAY,SAAS;GACzC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,0EAA0E;GACvG,MAAM,QAAQ,MAAM,eAAe,MAAM;IAAE,OAAO,IAAI;IAAO,aAAa;GAAkB,CAAC;GAC7F,MAAM,OAAO,MAAM,aAAa,QAAQ,IAAI,KAAK,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC;GACzE,IAAI,CAAC,KAAK,YAAY,SAAS,OAAO,GAAG;IACvC,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;IAC3D,OAAO,KAAK,UAAU,SAAS,IAAI;GACrC;GACA,MAAM,SAAS,MAAM,cAAc,MAAM;IACvC,SAAS,KAAK,YAAY,SAAS,OAAO;IAC1C,YAAY,QAAQ,MAAM,MAAM,4BAA4B;GAC9D,CAAC;GACD,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;GACpD,OAAO;EACT;EACA,IAAI,eAAe,IAAI;GACrB,MAAM,cAAc,KAAK,YAAY,aAAa;GAClD,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,uEAAuE;GACzG,MAAM,SAAS,MAAM,SAAS;IAAE;IAAM,aAAa,QAAQ,IAAI,KAAK,WAAW;GAAE,CAAC;GAClF,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;GACpD,OAAO,OAAO,SAAS,SAAS,MAAM,SAAS,KAAK,QAAQ,IAAI,IAAI;EACtE;EACA,MAAM,QAAQ,MAAM,eAAe,MAAM;GAAE,OAAO,IAAI;GAAO,aAAa;EAAQ,CAAC;EACnF,MAAM,OAAO,MAAM,SAAS;GAAE;GAAM;GAAO,gBAAgB;EAAQ,CAAC;EACpE,IAAI,KAAK,YAAY,SAAS,QAAQ,KAAK,KAAK,MAAM;GACpD,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,GAAG;GAClD,OAAO;EACT;EACA,MAAM,SAAS,MAAM,UAAU,IAAI;EACnC,IAAI,MAAM,OAAO,MAAM,YAAY,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,GAAG;EAC1E,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { c as rollbackV2Import } from "./src-CmFjh4M0.mjs";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
//#region src/commands/migrate/index.ts
|
|
5
|
+
const migrate = {
|
|
6
|
+
verb: "migrate",
|
|
7
|
+
async run(ctx, args) {
|
|
8
|
+
const rollback = args.positionals.indexOf("--rollback");
|
|
9
|
+
if (rollback !== -1) {
|
|
10
|
+
const reportId = args.positionals[rollback + 1];
|
|
11
|
+
if (!reportId) throw new Error("configuration/import-invalid: migrate --rollback requires a report id");
|
|
12
|
+
const reportPath = join(resolve(ctx.cwd), ".cohorte", "import-reports", `${reportId}.json`);
|
|
13
|
+
const report = JSON.parse(await readFile(reportPath, "utf8"));
|
|
14
|
+
const rolledBack = await rollbackV2Import(report);
|
|
15
|
+
await writeFile(reportPath, `${JSON.stringify(rolledBack, null, 2)}\n`, { mode: 384 });
|
|
16
|
+
ctx.stdio.stdout.write(`${JSON.stringify(rolledBack)}\n`);
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
const store = await (ctx.openMigrationStore ?? ctx.openStore)();
|
|
20
|
+
try {
|
|
21
|
+
const apply = args.positionals.includes("--apply");
|
|
22
|
+
const report = await store.migrate(apply ? "apply" : "check");
|
|
23
|
+
ctx.stdio.stdout.write(`${JSON.stringify(report)}\n`);
|
|
24
|
+
return !apply && report.pending.length > 0 ? 3 : 0;
|
|
25
|
+
} finally {
|
|
26
|
+
await store.close();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { migrate as default };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=migrate-DybihKzZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-DybihKzZ.mjs","names":[],"sources":["../../../../apps/cli/src/commands/migrate/index.ts"],"sourcesContent":["// apps/cli/src/commands/migrate/index.ts — DESIGN §9 verb `migrate` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/migrate/**`.\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { rollbackV2Import, type V2ImportReport } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst migrate: CommandModule = {\n verb: 'migrate',\n async run(ctx, args) {\n const rollback = args.positionals.indexOf('--rollback');\n if (rollback !== -1) {\n const reportId = args.positionals[rollback + 1];\n if (!reportId) throw new Error('configuration/import-invalid: migrate --rollback requires a report id');\n const reportPath = join(resolve(ctx.cwd), '.cohorte', 'import-reports', `${reportId}.json`);\n const report = JSON.parse(await readFile(reportPath, 'utf8')) as V2ImportReport;\n const rolledBack = await rollbackV2Import(report);\n await writeFile(reportPath, `${JSON.stringify(rolledBack, null, 2)}\\n`, { mode: 0o600 });\n ctx.stdio.stdout.write(`${JSON.stringify(rolledBack)}\\n`);\n return 0;\n }\n const store = await (ctx.openMigrationStore ?? ctx.openStore)();\n try {\n const apply = args.positionals.includes('--apply');\n const report = await store.migrate(apply ? 'apply' : 'check');\n ctx.stdio.stdout.write(`${JSON.stringify(report)}\\n`);\n return !apply && report.pending.length > 0 ? 3 : 0;\n } finally {\n await store.close();\n }\n },\n};\n\nexport default migrate;\n"],"mappings":";;;;AASA,MAAM,UAAyB;CAC7B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,WAAW,KAAK,YAAY,QAAQ,YAAY;EACtD,IAAI,aAAa,IAAI;GACnB,MAAM,WAAW,KAAK,YAAY,WAAW;GAC7C,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,uEAAuE;GACtG,MAAM,aAAa,KAAK,QAAQ,IAAI,GAAG,GAAG,YAAY,kBAAkB,GAAG,SAAS,MAAM;GAC1F,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,YAAY,MAAM,CAAC;GAC5D,MAAM,aAAa,MAAM,iBAAiB,MAAM;GAChD,MAAM,UAAU,YAAY,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,IAAM,CAAC;GACvF,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,UAAU,EAAE,GAAG;GACxD,OAAO;EACT;EACA,MAAM,QAAQ,OAAO,IAAI,sBAAsB,IAAI,UAAA,CAAW;EAC9D,IAAI;GACF,MAAM,QAAQ,KAAK,YAAY,SAAS,SAAS;GACjD,MAAM,SAAS,MAAM,MAAM,QAAQ,QAAQ,UAAU,OAAO;GAC5D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;GACpD,OAAO,CAAC,SAAS,OAAO,QAAQ,SAAS,IAAI,IAAI;EACnD,UAAU;GACR,MAAM,MAAM,MAAM;EACpB;CACF;AACF"}
|
|
@@ -2,8 +2,8 @@ import { n as sha256Hex, t as canonicalJson } from "./canonical-C8UxeEmB.mjs";
|
|
|
2
2
|
import { N as errorOf, j as CohorteError } from "./src-Cu3TxNob.mjs";
|
|
3
3
|
import { n as createKeyStore, r as createTrustStore } from "./auth-BT5oVp76.mjs";
|
|
4
4
|
import { i as resolveConfig, n as loadConfig } from "./src-DcU4IXMe.mjs";
|
|
5
|
-
import "./src-
|
|
6
|
-
import { a as buildPolicySnapshot, c as createCommandPolicy, i as createGlobMatcher, l as createProgramResolver, n as toolIntrospection, o as createPolicyEngine, r as createPathResolver, s as explainPolicy } from "./catalogue-
|
|
5
|
+
import "./src-r0ECB1UJ.mjs";
|
|
6
|
+
import { a as buildPolicySnapshot, c as createCommandPolicy, i as createGlobMatcher, l as createProgramResolver, n as toolIntrospection, o as createPolicyEngine, r as createPathResolver, s as explainPolicy } from "./catalogue-B5uFqfzJ.mjs";
|
|
7
7
|
import { join, resolve } from "node:path";
|
|
8
8
|
import { realpathSync } from "node:fs";
|
|
9
9
|
//#region src/commands/policy/index.ts
|
|
@@ -136,4 +136,4 @@ const policy = {
|
|
|
136
136
|
//#endregion
|
|
137
137
|
export { policy as default };
|
|
138
138
|
|
|
139
|
-
//# sourceMappingURL=policy-
|
|
139
|
+
//# sourceMappingURL=policy-Clypo20s.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-
|
|
1
|
+
{"version":3,"file":"policy-Clypo20s.mjs","names":[],"sources":["../../../../apps/cli/src/commands/policy/index.ts"],"sourcesContent":["// apps/cli/src/commands/policy/index.ts — DESIGN §9 verb `policy` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/policy/**`.\nimport { realpathSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { CohorteError, canonicalJson, errorOf, sha256Hex } from '@cohorte/base';\nimport { loadConfig, resolveConfig } from '@cohorte/config';\nimport {\n buildPolicySnapshot,\n createCommandPolicy,\n createGlobMatcher,\n createPathResolver,\n createPolicyEngine,\n createProgramResolver,\n explainPolicy,\n} from '@cohorte/security';\nimport { createKeyStore, createTrustStore } from '@cohorte/security/auth';\nimport type { AgentGrant, GateCall, PolicyPorts } from '@cohorte/security/contract';\nimport { toolIntrospection } from '@cohorte/tools/catalogue';\nimport type { CommandModule } from '../../contract/index.ts';\n\nfunction canonical(path: string): string {\n const absolute = resolve(path);\n try {\n return realpathSync.native(absolute);\n } catch {\n return absolute;\n }\n}\n\nfunction grantFor(root: string, argv: readonly string[]): AgentGrant {\n const tools = ['run_command'];\n const digest = sha256Hex(canonicalJson({ root, argv: [...argv] }));\n return {\n agentId: 'agt_policy_explain' as AgentGrant['agentId'],\n role: 'policy-explain',\n digest,\n tools,\n roots: { workspace: root as AgentGrant['roots']['workspace'], readOnly: [] },\n read: { include: ['**'], exclude: [] },\n write: { include: ['**'], exclude: [] },\n denyRead: { include: ['**/.cohorte/**', '**/.git/**'], exclude: [] },\n denyWrite: { include: ['**/.cohorte/**', '**/.git/**'], exclude: [] },\n commands: { default: 'deny', rules: [] },\n secrets: [],\n temporary: [],\n limits: {\n maxToolCalls: 1,\n maxCallsPerMinute: 1,\n perTool: { run_command: { timeoutMs: 120_000, maxOutputBytes: 1024 * 1024 } },\n },\n };\n}\n\nconst policy: CommandModule = {\n verb: 'policy',\n async run(ctx, args) {\n if (args.subVerb !== 'explain') return 2;\n const argv = args.positionals.filter((value) => value !== '--');\n if (argv.length === 0) return 2;\n\n const home = ctx.env.HOME ?? ctx.cwd;\n const projectKeyId = sha256Hex(ctx.cwd).slice(0, 24);\n const keys = createKeyStore({ directory: join(home, '.cohorte', 'keys') });\n const trustStore = createTrustStore({ directory: join(home, '.cohorte', 'trust'), keys });\n const loaded = await loadConfig({ cwd: ctx.cwd, home });\n const resolved = await resolveConfig(loaded, { trustStore, projectKeyId });\n if (resolved.status === 'untrusted') {\n throw new CohorteError(\n errorOf(\n 'security/project-policy-untrusted',\n `project policy is untrusted (${resolved.loosenedKeys.join(', ') || 'unknown key'})`,\n ),\n );\n }\n\n const root = canonical(loaded.projectRoot);\n const pathResolver = createPathResolver({\n roots: [root as never],\n protectedRoots: [canonical(join(root, '.cohorte')) as never],\n symlinks: resolved.config.policy.symlinks,\n });\n const pathDirs = (ctx.env.PATH ?? '').split(':').filter(Boolean).map(canonical);\n const programs = createProgramResolver({ pathDirs });\n const branches: PolicyPorts['branches'] = {\n branchOf: () => ({ kind: 'detached-or-unknown', protected: true }),\n };\n const commands = createCommandPolicy({ programs, branches });\n const engine = createPolicyEngine({ tools: toolIntrospection, globs: createGlobMatcher(), commands });\n const policySnapshot = buildPolicySnapshot(resolved.config, loaded.ownership, { sandboxLevel: 'L0-process' });\n const ports: PolicyPorts = {\n paths: pathResolver,\n branches,\n budgets: { remaining: () => ({}), callsInLastMinute: () => 0 },\n programs,\n clock: ctx.clock,\n };\n const call: GateCall = {\n runId: 'run_policy_explain' as GateCall['runId'],\n agentId: 'agt_policy_explain' as GateCall['agentId'],\n incarnation: 1,\n toolCallId: 'tool_policy_explain' as GateCall['toolCallId'],\n tool: 'run_command',\n input: { argv, cwd: root, timeoutMs: 120_000 },\n phase: 'PREFLIGHT',\n role: 'policy-explain',\n };\n const verdict = explainPolicy(engine, call, grantFor(root, argv), policySnapshot, ports);\n ctx.stdio.stdout.write(`${JSON.stringify(verdict)}\\n`);\n return 0;\n },\n};\n\nexport default policy;\n"],"mappings":";;;;;;;;;AAsBA,SAAS,UAAU,MAAsB;CACvC,MAAM,WAAW,QAAQ,IAAI;CAC7B,IAAI;EACF,OAAO,aAAa,OAAO,QAAQ;CACrC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,SAAS,MAAc,MAAqC;CACnE,MAAM,QAAQ,CAAC,aAAa;CAE5B,OAAO;EACL,SAAS;EACT,MAAM;EACN,QAJa,UAAU,cAAc;GAAE;GAAM,MAAM,CAAC,GAAG,IAAI;EAAE,CAAC,CAIzD;EACL;EACA,OAAO;GAAE,WAAW;GAA0C,UAAU,CAAC;EAAE;EAC3E,MAAM;GAAE,SAAS,CAAC,IAAI;GAAG,SAAS,CAAC;EAAE;EACrC,OAAO;GAAE,SAAS,CAAC,IAAI;GAAG,SAAS,CAAC;EAAE;EACtC,UAAU;GAAE,SAAS,CAAC,kBAAkB,YAAY;GAAG,SAAS,CAAC;EAAE;EACnE,WAAW;GAAE,SAAS,CAAC,kBAAkB,YAAY;GAAG,SAAS,CAAC;EAAE;EACpE,UAAU;GAAE,SAAS;GAAQ,OAAO,CAAC;EAAE;EACvC,SAAS,CAAC;EACV,WAAW,CAAC;EACZ,QAAQ;GACN,cAAc;GACd,mBAAmB;GACnB,SAAS,EAAE,aAAa;IAAE,WAAW;IAAS,gBAAgB;GAAY,EAAE;EAC9E;CACF;AACF;AAEA,MAAM,SAAwB;CAC5B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,IAAI,KAAK,YAAY,WAAW,OAAO;EACvC,MAAM,OAAO,KAAK,YAAY,QAAQ,UAAU,UAAU,IAAI;EAC9D,IAAI,KAAK,WAAW,GAAG,OAAO;EAE9B,MAAM,OAAO,IAAI,IAAI,QAAQ,IAAI;EACjC,MAAM,eAAe,UAAU,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,EAAE;EACnD,MAAM,OAAO,eAAe,EAAE,WAAW,KAAK,MAAM,YAAY,MAAM,EAAE,CAAC;EACzE,MAAM,aAAa,iBAAiB;GAAE,WAAW,KAAK,MAAM,YAAY,OAAO;GAAG;EAAK,CAAC;EACxF,MAAM,SAAS,MAAM,WAAW;GAAE,KAAK,IAAI;GAAK;EAAK,CAAC;EACtD,MAAM,WAAW,MAAM,cAAc,QAAQ;GAAE;GAAY;EAAa,CAAC;EACzE,IAAI,SAAS,WAAW,aACtB,MAAM,IAAI,aACR,QACE,qCACA,gCAAgC,SAAS,aAAa,KAAK,IAAI,KAAK,cAAc,EACpF,CACF;EAGF,MAAM,OAAO,UAAU,OAAO,WAAW;EACzC,MAAM,eAAe,mBAAmB;GACtC,OAAO,CAAC,IAAa;GACrB,gBAAgB,CAAC,UAAU,KAAK,MAAM,UAAU,CAAC,CAAU;GAC3D,UAAU,SAAS,OAAO,OAAO;EACnC,CAAC;EACD,MAAM,YAAY,IAAI,IAAI,QAAQ,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,IAAI,SAAS;EAC9E,MAAM,WAAW,sBAAsB,EAAE,SAAS,CAAC;EACnD,MAAM,WAAoC,EACxC,iBAAiB;GAAE,MAAM;GAAuB,WAAW;EAAK,GAClE;EACA,MAAM,WAAW,oBAAoB;GAAE;GAAU;EAAS,CAAC;EAC3D,MAAM,SAAS,mBAAmB;GAAE,OAAO;GAAmB,OAAO,kBAAkB;GAAG;EAAS,CAAC;EACpG,MAAM,iBAAiB,oBAAoB,SAAS,QAAQ,OAAO,WAAW,EAAE,cAAc,aAAa,CAAC;EAC5G,MAAM,QAAqB;GACzB,OAAO;GACP;GACA,SAAS;IAAE,kBAAkB,CAAC;IAAI,yBAAyB;GAAE;GAC7D;GACA,OAAO,IAAI;EACb;EAWA,MAAM,UAAU,cAAc,QAAQ;GATpC,OAAO;GACP,SAAS;GACT,aAAa;GACb,YAAY;GACZ,MAAM;GACN,OAAO;IAAE;IAAM,KAAK;IAAM,WAAW;GAAQ;GAC7C,OAAO;GACP,MAAM;EAEiC,GAAG,SAAS,MAAM,IAAI,GAAG,gBAAgB,KAAK;EACvF,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,EAAE,GAAG;EACrD,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { s as DEFAULT_CONFIG } from "./schema-C9QbUW4H.mjs";
|
|
2
|
+
import { l as deriveDesiredState, n as planReconcile, t as applyReconcile } from "./src-CmFjh4M0.mjs";
|
|
3
|
+
import { t as scanRepository } from "./scan-8Gy_B6kI.mjs";
|
|
4
|
+
//#region src/commands/reconcile/index.ts
|
|
5
|
+
const reconcile = {
|
|
6
|
+
verb: "reconcile",
|
|
7
|
+
async run(ctx, args) {
|
|
8
|
+
const model = await scanRepository(ctx.cwd, {
|
|
9
|
+
clock: ctx.clock,
|
|
10
|
+
toolVersion: "3.0.0"
|
|
11
|
+
});
|
|
12
|
+
const plan = await planReconcile({
|
|
13
|
+
root: ctx.cwd,
|
|
14
|
+
scan: (root) => scanRepository(root, {
|
|
15
|
+
clock: ctx.clock,
|
|
16
|
+
toolVersion: "3.0.0"
|
|
17
|
+
}),
|
|
18
|
+
cohorteVersion: "3.0.0",
|
|
19
|
+
clock: ctx.clock
|
|
20
|
+
});
|
|
21
|
+
if (args.positionals.includes("--apply")) {
|
|
22
|
+
const result = await applyReconcile({
|
|
23
|
+
root: ctx.cwd,
|
|
24
|
+
plan,
|
|
25
|
+
desired: deriveDesiredState({
|
|
26
|
+
model,
|
|
27
|
+
config: DEFAULT_CONFIG,
|
|
28
|
+
cohorteVersion: "3.0.0",
|
|
29
|
+
skills: {}
|
|
30
|
+
}),
|
|
31
|
+
backup: !args.positionals.includes("--no-backup"),
|
|
32
|
+
clock: ctx.clock
|
|
33
|
+
});
|
|
34
|
+
if (args.json) ctx.stdio.stdout.write(`${JSON.stringify({
|
|
35
|
+
plan,
|
|
36
|
+
result
|
|
37
|
+
})}\n`);
|
|
38
|
+
else ctx.stdio.stdout.write(`applied: ${result.applied.join(", ") || "none"}\n`);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
if (!args.positionals.includes("--plan")) return 2;
|
|
42
|
+
if (args.json) ctx.stdio.stdout.write(`${JSON.stringify(plan)}\n`);
|
|
43
|
+
else ctx.stdio.stdout.write(`${plan.operations.length} operation(s) planned\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
//#endregion
|
|
48
|
+
export { reconcile as default };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=reconcile-Bhy3IIYo.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile-Bhy3IIYo.mjs","names":[],"sources":["../../../../apps/cli/src/commands/reconcile/index.ts"],"sourcesContent":["import { DEFAULT_CONFIG } from '@cohorte/config/schema';\nimport { applyReconcile, deriveDesiredState, planReconcile, scanRepository } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst reconcile: CommandModule = {\n verb: 'reconcile',\n async run(ctx, args) {\n const model = await scanRepository(ctx.cwd, { clock: ctx.clock, toolVersion: '3.0.0' });\n const plan = await planReconcile({\n root: ctx.cwd,\n scan: (root) => scanRepository(root, { clock: ctx.clock, toolVersion: '3.0.0' }),\n cohorteVersion: '3.0.0',\n clock: ctx.clock,\n });\n if (args.positionals.includes('--apply')) {\n const result = await applyReconcile({\n root: ctx.cwd,\n plan,\n desired: deriveDesiredState({ model, config: DEFAULT_CONFIG, cohorteVersion: '3.0.0', skills: {} }),\n backup: !args.positionals.includes('--no-backup'),\n clock: ctx.clock,\n });\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify({ plan, result })}\\n`);\n else ctx.stdio.stdout.write(`applied: ${result.applied.join(', ') || 'none'}\\n`);\n return 0;\n }\n if (!args.positionals.includes('--plan')) return 2;\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify(plan)}\\n`);\n else ctx.stdio.stdout.write(`${plan.operations.length} operation(s) planned\\n`);\n return 0;\n },\n};\n\nexport default reconcile;\n"],"mappings":";;;;AAIA,MAAM,YAA2B;CAC/B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,QAAQ,MAAM,eAAe,IAAI,KAAK;GAAE,OAAO,IAAI;GAAO,aAAa;EAAQ,CAAC;EACtF,MAAM,OAAO,MAAM,cAAc;GAC/B,MAAM,IAAI;GACV,OAAO,SAAS,eAAe,MAAM;IAAE,OAAO,IAAI;IAAO,aAAa;GAAQ,CAAC;GAC/E,gBAAgB;GAChB,OAAO,IAAI;EACb,CAAC;EACD,IAAI,KAAK,YAAY,SAAS,SAAS,GAAG;GACxC,MAAM,SAAS,MAAM,eAAe;IAClC,MAAM,IAAI;IACV;IACA,SAAS,mBAAmB;KAAE;KAAO,QAAQ;KAAgB,gBAAgB;KAAS,QAAQ,CAAC;IAAE,CAAC;IAClG,QAAQ,CAAC,KAAK,YAAY,SAAS,aAAa;IAChD,OAAO,IAAI;GACb,CAAC;GACD,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU;IAAE;IAAM;GAAO,CAAC,EAAE,GAAG;QACxE,IAAI,MAAM,OAAO,MAAM,YAAY,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,GAAG;GAC/E,OAAO;EACT;EACA,IAAI,CAAC,KAAK,YAAY,SAAS,QAAQ,GAAG,OAAO;EACjD,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,GAAG;OAC5D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,WAAW,OAAO,wBAAwB;EAC9E,OAAO;CACT;AACF"}
|