@deftai/directive 0.118.0 → 0.119.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authz.js +30 -0
- package/dist/cli-router/route-argv.js +6 -0
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +12 -0
- package/dist/release-wait-npm.d.ts +3 -0
- package/dist/release-wait-npm.js +10 -0
- package/dist/scope-record-intent-constraint.d.ts +15 -0
- package/dist/scope-record-intent-constraint.js +178 -0
- package/dist/scope-record-observable-scope.d.ts +15 -0
- package/dist/scope-record-observable-scope.js +180 -0
- package/dist/session-start.d.ts +3 -1
- package/dist/session-start.js +51 -3
- package/dist/verify-intent-constraint.d.ts +15 -0
- package/dist/verify-intent-constraint.js +86 -0
- package/dist/verify-observable-scope.d.ts +15 -0
- package/dist/verify-observable-scope.js +86 -0
- package/dist/verify-pr-closeout-attestable.d.ts +1 -0
- package/dist/verify-pr-closeout-attestable.js +19 -1
- package/dist/verify-source-cli/verify-closing-keywords.js +2 -2
- package/dist/verify-story-ready.js +2 -1
- package/package.json +3 -3
package/dist/authz.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { existsSync } from "node:fs";
|
|
26
26
|
import { isAbsolute, resolve } from "node:path";
|
|
27
|
+
import { onePrUnit } from "@deftai/directive-core";
|
|
27
28
|
import { AFK_TEMPLATE_NAMES, AUTHZ_OPERATIONS, CLOSED_VERB_TEMPLATE_NAMES, FINISH_LOOP_TEMPLATE_NAME, formatDecomposeStructuralMintCommand, isAfkTemplateName, isClosedVerbTemplateName, isFinishLoopTemplateName, mintAfkTemplateGrant, mintDecomposeStructuralApplyGrant, mintHumanOriginGrant, revokeGrant, showAuthzSnapshot, startUatLease, suspendUatLease, toProjectRelativePosix, } from "@deftai/directive-core/authz";
|
|
28
29
|
import { refuseMintWhileUatActive, refuseNonInteractiveMint, resolveHumanPresenceMintSeams, } from "./human-presence-mint.js";
|
|
29
30
|
export { AUTHZ_AGENT_SHELL_ENV_MARKERS, AUTHZ_INTERACTIVE_CONFIRM_PHRASE, } from "./human-presence-mint.js";
|
|
@@ -416,6 +417,35 @@ export function main(argv = process.argv.slice(2), seams = {}) {
|
|
|
416
417
|
" Authorization SoT: Wave 1 grant store (.deft/authz/grants) — not session-auth.\n");
|
|
417
418
|
return 0;
|
|
418
419
|
}
|
|
420
|
+
if (args.template !== null && args.template.trim().toLowerCase() === "one-pr-unit") {
|
|
421
|
+
if (args.repo === null || args.repo.trim().length === 0) {
|
|
422
|
+
process.stderr.write("authz:grant --template one-pr-unit requires --repo owner/name\n");
|
|
423
|
+
return 2;
|
|
424
|
+
}
|
|
425
|
+
if (args.issueIds.length < 2) {
|
|
426
|
+
process.stderr.write("authz:grant --template one-pr-unit requires --issue-ids with at least two origins\n");
|
|
427
|
+
return 2;
|
|
428
|
+
}
|
|
429
|
+
const blocked = gateConfirm();
|
|
430
|
+
if (blocked !== null)
|
|
431
|
+
return blocked;
|
|
432
|
+
if ((process.env.DEFT_ONE_PR_UNIT_APP ?? "").trim().length === 0) {
|
|
433
|
+
process.stderr.write("authz:grant --template one-pr-unit requires DEFT_ONE_PR_UNIT_APP (durable Directive App store). " +
|
|
434
|
+
"The in-process simulator is test-only and is discarded on process exit.\n");
|
|
435
|
+
return 2;
|
|
436
|
+
}
|
|
437
|
+
const claim = onePrUnit.mintOnePrUnitGrant({
|
|
438
|
+
actor: args.actor,
|
|
439
|
+
approvalRef: args.note ?? "authz:grant --template one-pr-unit",
|
|
440
|
+
rationale: args.note ?? "one-PR-unit",
|
|
441
|
+
origins: args.issueIds.map((issueId) => ({ repo: args.repo, issueId })),
|
|
442
|
+
repo: args.repo,
|
|
443
|
+
});
|
|
444
|
+
process.stdout.write(`✓ one-PR-unit claim minted id=${claim.id} state=${claim.state} (reserved unbound)\n`);
|
|
445
|
+
process.stdout.write(" Opaque id is not a bearer. Only the App store plus the bound PR node id authorizes.\n");
|
|
446
|
+
process.stdout.write(` origins=${claim.origins.map((o) => `${o.repo}#${o.issueId}`).join(",")}\n`);
|
|
447
|
+
return 0;
|
|
448
|
+
}
|
|
419
449
|
// AFK template path (#1095 / #871): presets only — still mintHumanOriginGrant.
|
|
420
450
|
if (args.template !== null && args.template.trim().length > 0) {
|
|
421
451
|
if (!isAfkTemplateName(args.template)) {
|
|
@@ -190,6 +190,12 @@ function routeNamespaceVerb(ns, verb, rest) {
|
|
|
190
190
|
if (verb === "record-approved-scope") {
|
|
191
191
|
return { kind: "dispatch", argv: ["scope-record-approved-scope", ...rest] };
|
|
192
192
|
}
|
|
193
|
+
if (verb === "record-observable-scope") {
|
|
194
|
+
return { kind: "dispatch", argv: ["scope-record-observable-scope", ...rest] };
|
|
195
|
+
}
|
|
196
|
+
if (verb === "record-intent-constraint") {
|
|
197
|
+
return { kind: "dispatch", argv: ["scope-record-intent-constraint", ...rest] };
|
|
198
|
+
}
|
|
193
199
|
}
|
|
194
200
|
if (ns === "verify") {
|
|
195
201
|
const verifyStem = VERIFY_VERB_MAP[verb];
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface DispatchIo {
|
|
|
10
10
|
writeErr: (text: string) => void;
|
|
11
11
|
}
|
|
12
12
|
/** CLI modules in packages/cli/src (excluding parity harnesses and bin/index). */
|
|
13
|
-
export declare const CLI_MODULE_VERBS: readonly ["agents-refresh", "cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "install-upgrade", "install-uninstall", "migrate-preflight", "migrate-xbrief", "migrate-category-b", "framework-check-updates", "hook-dispatch", "umbrella-current-shape", "changelog-check", "change-init", "commit-lint", "coverage-hotspots", "policy", "authz", "escalation-cli", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "pr-finish-loop", "directive-finish-loop", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "scope-record-approved-scope", "scm-sync-default", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "occupancy-steal", "occupancy-release", "occupancy-heartbeat", "occupancy-grant", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-strip-withdrawn", "triage-evaluate", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "xbrief-create", "xbrief-verify", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "verify-scope-provenance", "verify-consumer-check-contract", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-biome-config", "verify-bridge-drift", "verify-capacity", "verify-contained-writes", "verify-telemetry-coverage", "verify-content-manifest", "verify-deposit-closure", "verify-consumer-hard-stops", "verify-closing-keywords", "verify-skill-external-fetch-gate", "verify-semantic-single-source", "verify-contract-drift", "verify-cursor-tier1", "verify-openclaw-tier1", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-plan-sequence", "verify-stubs", "verify-xbrief-drift", "verify-spec-prd-fresh", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "verify-subagent-steer", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "verify-pr-closeout-attestable", "verify-lifecycle-visible", "verify-completed-tracked", "verify-completed-write-guard", "verify-literal-ac", "verify-ac", "verify-agents-md-budget", "verify-agents-md-advisory", "verify-eval-health-relocation", "verify-eval-triggers-relocation", "verify-evaluator-surface", "verify-consumer-test-lane", "eval-health", "eval-run", "eval-report", "eval-triggers"];
|
|
13
|
+
export declare const CLI_MODULE_VERBS: readonly ["agents-refresh", "cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "install-upgrade", "install-uninstall", "migrate-preflight", "migrate-xbrief", "migrate-category-b", "framework-check-updates", "hook-dispatch", "umbrella-current-shape", "changelog-check", "change-init", "commit-lint", "coverage-hotspots", "policy", "authz", "escalation-cli", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "pr-finish-loop", "directive-finish-loop", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "release-wait-npm", "scope-lifecycle", "scope-record-approved-scope", "scope-record-observable-scope", "scope-record-intent-constraint", "scm-sync-default", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "occupancy-steal", "occupancy-release", "occupancy-heartbeat", "occupancy-grant", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-strip-withdrawn", "triage-evaluate", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "xbrief-create", "xbrief-verify", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "verify-scope-provenance", "verify-consumer-check-contract", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-biome-config", "verify-bridge-drift", "verify-capacity", "verify-contained-writes", "verify-telemetry-coverage", "verify-content-manifest", "verify-deposit-closure", "verify-consumer-hard-stops", "verify-closing-keywords", "verify-skill-external-fetch-gate", "verify-semantic-single-source", "verify-contract-drift", "verify-cursor-tier1", "verify-openclaw-tier1", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-plan-sequence", "verify-stubs", "verify-xbrief-drift", "verify-spec-prd-fresh", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "verify-subagent-steer", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "verify-pr-closeout-attestable", "verify-lifecycle-visible", "verify-completed-tracked", "verify-completed-write-guard", "verify-literal-ac", "verify-ac", "verify-agents-md-budget", "verify-agents-md-advisory", "verify-eval-health-relocation", "verify-eval-triggers-relocation", "verify-evaluator-surface", "verify-observable-scope", "verify-intent-constraint", "verify-consumer-test-lane", "eval-health", "eval-run", "eval-report", "eval-triggers"];
|
|
14
14
|
/** Core-only CLI entrypoints without a packages/cli wrapper. */
|
|
15
15
|
export declare const CORE_MODULE_VERBS: readonly ["scm", "scm-readiness", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "issue-sync-from-xbrief", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-finalize-cohort", "swarm-pre-dispatch", "swarm-readiness", "swarm-routing-verify", "swarm-routing-set", "swarm-verify-review-clean", "swarm-worktrees", "framework-commands", "pack-render", "packs-slice", "prd-render", "export-spec", "project-render", "roadmap-render", "rule-map", "spec-render", "spec-validate", "code-structure-validate", "pack-migrate-skills", "pack-migrate-rules", "pack-migrate-strategies", "pack-migrate-patterns", "pack-migrate-swarm-spec", "policy-set", "setup-ghx", "scope-undo", "scope-demote", "scope-decompose", "changelog-resolve-unreleased", "architecture-preflight-sor", "feedback-file", "value-readback", "product-signal", "freshness-report", "decision-write", "decision-list", "docs-impact"];
|
|
16
16
|
/** Colon aliases for triage-actions (mirrors cli-router SUBCOMMAND_ROUTES). */
|
package/dist/dispatch.js
CHANGED
|
@@ -67,8 +67,11 @@ export const CLI_MODULE_VERBS = [
|
|
|
67
67
|
"release-e2e",
|
|
68
68
|
"release-publish",
|
|
69
69
|
"release-rollback",
|
|
70
|
+
"release-wait-npm",
|
|
70
71
|
"scope-lifecycle",
|
|
71
72
|
"scope-record-approved-scope",
|
|
73
|
+
"scope-record-observable-scope",
|
|
74
|
+
"scope-record-intent-constraint",
|
|
72
75
|
"scm-sync-default",
|
|
73
76
|
"lifecycle-event",
|
|
74
77
|
"lifecycle-stats",
|
|
@@ -162,6 +165,8 @@ export const CLI_MODULE_VERBS = [
|
|
|
162
165
|
"verify-eval-health-relocation",
|
|
163
166
|
"verify-eval-triggers-relocation",
|
|
164
167
|
"verify-evaluator-surface",
|
|
168
|
+
"verify-observable-scope",
|
|
169
|
+
"verify-intent-constraint",
|
|
165
170
|
"verify-consumer-test-lane",
|
|
166
171
|
"eval-health",
|
|
167
172
|
"eval-run",
|
|
@@ -294,6 +299,8 @@ export const VERB_ALIASES = {
|
|
|
294
299
|
"verify:test-boundary": "verify-test-boundary",
|
|
295
300
|
"verify:scope-provenance": "verify-scope-provenance",
|
|
296
301
|
"scope:record-approved-scope": "scope-record-approved-scope",
|
|
302
|
+
"scope:record-observable-scope": "scope-record-observable-scope",
|
|
303
|
+
"scope:record-intent-constraint": "scope-record-intent-constraint",
|
|
297
304
|
"verify:consumer-check-contract": "verify-consumer-check-contract",
|
|
298
305
|
"coverage:hotspots": "coverage-hotspots",
|
|
299
306
|
"verify:branch": "verify-branch",
|
|
@@ -313,6 +320,8 @@ export const VERB_ALIASES = {
|
|
|
313
320
|
"verify:eval-health-relocation": "verify-eval-health-relocation",
|
|
314
321
|
"verify:eval-triggers-relocation": "verify-eval-triggers-relocation",
|
|
315
322
|
"verify:evaluator-surface": "verify-evaluator-surface",
|
|
323
|
+
"verify:observable-scope": "verify-observable-scope",
|
|
324
|
+
"verify:intent-constraint": "verify-intent-constraint",
|
|
316
325
|
"verify:consumer-test-lane": "verify-consumer-test-lane",
|
|
317
326
|
"verify:hooks-installed": "verify-hooks-installed",
|
|
318
327
|
"verify:no-task-runtime": "verify-no-task-runtime",
|
|
@@ -424,6 +433,7 @@ export const VERB_ALIASES = {
|
|
|
424
433
|
"scm:status": "scm-readiness",
|
|
425
434
|
"scm:readiness": "scm-readiness",
|
|
426
435
|
"scm:sync-default": "scm-sync-default",
|
|
436
|
+
"release:wait-npm": "release-wait-npm",
|
|
427
437
|
};
|
|
428
438
|
/** CLI modules living under verify-source-cli/ or content-validate-cli/ subdirs. */
|
|
429
439
|
const SUBDIR_CLI_STEMS = {
|
|
@@ -2640,6 +2650,8 @@ const SCOPE_COMMAND_NAMES = [
|
|
|
2640
2650
|
"scope:demote",
|
|
2641
2651
|
"scope:undo",
|
|
2642
2652
|
"scope:record-approved-scope",
|
|
2653
|
+
"scope:record-observable-scope",
|
|
2654
|
+
"scope:record-intent-constraint",
|
|
2643
2655
|
];
|
|
2644
2656
|
/**
|
|
2645
2657
|
* Deduplicated command names for `directive commands`, preferring colon-style
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { cmdReleaseWaitNpm } from "@deftai/directive-core/dist/release/cli-drift-report.js";
|
|
4
|
+
export function run(argv) {
|
|
5
|
+
return cmdReleaseWaitNpm(argv);
|
|
6
|
+
}
|
|
7
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
8
|
+
process.exit(run(process.argv.slice(2)));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=release-wait-npm.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type HumanPresenceMintSeams } from "./human-presence-mint.js";
|
|
3
|
+
export interface ParsedArgs {
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
xbriefPath: string;
|
|
6
|
+
actor: string;
|
|
7
|
+
kind: string;
|
|
8
|
+
quiet: boolean;
|
|
9
|
+
confirm: boolean;
|
|
10
|
+
help?: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
14
|
+
export declare function run(argv: string[], seams?: HumanPresenceMintSeams): number;
|
|
15
|
+
//# sourceMappingURL=scope-record-intent-constraint.d.ts.map
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for scope:record-intent-constraint (#4541).
|
|
4
|
+
*
|
|
5
|
+
* Human-presence mint of `.deft/intent-constraint/<plan-id>.json` from
|
|
6
|
+
* `plan["x-directive/intentConstraint"]`. --actor is display-only.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { basename, relative, resolve } from "node:path";
|
|
10
|
+
import { buildIntentConstraintRecord, extractIntentConstraintFromPlan, parseIntentConstraintContract, writeIntentConstraintRecord, } from "@deftai/directive-core/intent-constraint";
|
|
11
|
+
import { isDirectEntrypoint } from "./entrypoint.js";
|
|
12
|
+
import { refuseMintWhileUatActive, refuseNonInteractiveMint, resolveHumanPresenceMintSeams, } from "./human-presence-mint.js";
|
|
13
|
+
import { isPathInsideRoot } from "./scope-record-approved-scope.js";
|
|
14
|
+
function usage() {
|
|
15
|
+
return ("usage: scope:record-intent-constraint -- <xbrief-path> --actor <name> --confirm " +
|
|
16
|
+
"[--kind operator] [--project-root <dir>] [--quiet]\n" +
|
|
17
|
+
' Writes .deft/intent-constraint/<plan-id>.json from plan["x-directive/intentConstraint"].\n' +
|
|
18
|
+
" --actor is display only and never authorizes mint. Mint requires a real TTY, " +
|
|
19
|
+
"controlling terminal, --confirm, and typed phrase mint (#3110). Agent/CI shells refuse.");
|
|
20
|
+
}
|
|
21
|
+
function extractPlanId(payload) {
|
|
22
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload))
|
|
23
|
+
return null;
|
|
24
|
+
const plan = payload.plan;
|
|
25
|
+
if (plan === null || typeof plan !== "object" || Array.isArray(plan))
|
|
26
|
+
return null;
|
|
27
|
+
const id = plan.id;
|
|
28
|
+
return typeof id === "string" && id.trim().length > 0 ? id.trim() : null;
|
|
29
|
+
}
|
|
30
|
+
export function parseArgs(argv) {
|
|
31
|
+
const parsed = {
|
|
32
|
+
projectRoot: ".",
|
|
33
|
+
xbriefPath: "",
|
|
34
|
+
actor: "",
|
|
35
|
+
kind: "operator",
|
|
36
|
+
quiet: false,
|
|
37
|
+
confirm: false,
|
|
38
|
+
};
|
|
39
|
+
const positionals = [];
|
|
40
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
41
|
+
const arg = argv[i];
|
|
42
|
+
if (arg === "--")
|
|
43
|
+
continue;
|
|
44
|
+
if (arg === "--help" || arg === "-h")
|
|
45
|
+
return { ...parsed, help: true };
|
|
46
|
+
if (arg === "--quiet")
|
|
47
|
+
parsed.quiet = true;
|
|
48
|
+
else if (arg === "--confirm")
|
|
49
|
+
parsed.confirm = true;
|
|
50
|
+
else if (arg === "--project-root") {
|
|
51
|
+
const value = argv[i + 1];
|
|
52
|
+
if (value === undefined)
|
|
53
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
54
|
+
parsed.projectRoot = value;
|
|
55
|
+
i += 1;
|
|
56
|
+
}
|
|
57
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
58
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
59
|
+
}
|
|
60
|
+
else if (arg === "--actor") {
|
|
61
|
+
const value = argv[i + 1];
|
|
62
|
+
if (value === undefined)
|
|
63
|
+
return { ...parsed, error: "argument --actor: expected one argument" };
|
|
64
|
+
parsed.actor = value;
|
|
65
|
+
i += 1;
|
|
66
|
+
}
|
|
67
|
+
else if (arg?.startsWith("--actor=")) {
|
|
68
|
+
parsed.actor = arg.slice("--actor=".length);
|
|
69
|
+
}
|
|
70
|
+
else if (arg === "--kind") {
|
|
71
|
+
const value = argv[i + 1];
|
|
72
|
+
if (value === undefined)
|
|
73
|
+
return { ...parsed, error: "argument --kind: expected one argument" };
|
|
74
|
+
parsed.kind = value;
|
|
75
|
+
i += 1;
|
|
76
|
+
}
|
|
77
|
+
else if (arg?.startsWith("--kind=")) {
|
|
78
|
+
parsed.kind = arg.slice("--kind=".length);
|
|
79
|
+
}
|
|
80
|
+
else if (arg?.startsWith("-")) {
|
|
81
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
82
|
+
}
|
|
83
|
+
else if (arg !== undefined) {
|
|
84
|
+
positionals.push(arg);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (parsed.help)
|
|
88
|
+
return parsed;
|
|
89
|
+
if (positionals.length === 0)
|
|
90
|
+
return { ...parsed, error: `missing xBRIEF path\n${usage()}` };
|
|
91
|
+
if (positionals.length > 1) {
|
|
92
|
+
return { ...parsed, error: `unexpected extra args: ${positionals.slice(1).join(" ")}` };
|
|
93
|
+
}
|
|
94
|
+
parsed.xbriefPath = positionals[0] ?? "";
|
|
95
|
+
if (parsed.actor.trim().length === 0) {
|
|
96
|
+
return {
|
|
97
|
+
...parsed,
|
|
98
|
+
error: `argument --actor is required (human operator identity)\n${usage()}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return parsed;
|
|
102
|
+
}
|
|
103
|
+
export function run(argv, seams = {}) {
|
|
104
|
+
const args = parseArgs(argv);
|
|
105
|
+
if (args.help) {
|
|
106
|
+
process.stdout.write(`${usage()}\n`);
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
if (args.error !== undefined) {
|
|
110
|
+
process.stderr.write(`scope_record_intent_constraint: ${args.error}\n`);
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
const projectRoot = resolve(args.projectRoot);
|
|
114
|
+
const uat = refuseMintWhileUatActive("scope:record-intent-constraint", projectRoot);
|
|
115
|
+
if (uat !== null)
|
|
116
|
+
return uat;
|
|
117
|
+
const resolved = resolveHumanPresenceMintSeams(seams);
|
|
118
|
+
const refused = refuseNonInteractiveMint({
|
|
119
|
+
verb: "scope:record-intent-constraint",
|
|
120
|
+
confirm: args.confirm,
|
|
121
|
+
isTty: resolved.isTty,
|
|
122
|
+
environ: resolved.environ,
|
|
123
|
+
hasControllingTerminal: resolved.hasControllingTerminal,
|
|
124
|
+
readInteractiveConfirm: resolved.readInteractiveConfirm,
|
|
125
|
+
});
|
|
126
|
+
if (refused !== null)
|
|
127
|
+
return refused;
|
|
128
|
+
const xbriefAbs = resolve(projectRoot, args.xbriefPath);
|
|
129
|
+
const fullPath = existsSync(xbriefAbs) ? xbriefAbs : resolve(args.xbriefPath);
|
|
130
|
+
if (!existsSync(fullPath)) {
|
|
131
|
+
process.stderr.write(`scope_record_intent_constraint: xBRIEF not found: ${args.xbriefPath}\n`);
|
|
132
|
+
return 2;
|
|
133
|
+
}
|
|
134
|
+
if (!isPathInsideRoot(projectRoot, fullPath)) {
|
|
135
|
+
process.stderr.write("scope_record_intent_constraint: xBRIEF path escapes --project-root.\n");
|
|
136
|
+
return 2;
|
|
137
|
+
}
|
|
138
|
+
let payload;
|
|
139
|
+
const rawText = readFileSync(fullPath, "utf8");
|
|
140
|
+
try {
|
|
141
|
+
payload = JSON.parse(rawText);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
process.stderr.write(`scope_record_intent_constraint: invalid JSON: ${String(err)}\n`);
|
|
145
|
+
return 2;
|
|
146
|
+
}
|
|
147
|
+
const planId = extractPlanId(payload) ?? basename(fullPath, ".xbrief.json");
|
|
148
|
+
const contract = parseIntentConstraintContract(extractIntentConstraintFromPlan(payload));
|
|
149
|
+
if ("error" in contract) {
|
|
150
|
+
process.stderr.write(`scope_record_intent_constraint: ${contract.error}\n`);
|
|
151
|
+
return 2;
|
|
152
|
+
}
|
|
153
|
+
const rel = relative(projectRoot, fullPath).replace(/\\/g, "/");
|
|
154
|
+
const rec = buildIntentConstraintRecord({
|
|
155
|
+
planId,
|
|
156
|
+
xbriefRelPath: rel.startsWith("xbrief/pending/") ? `xbrief/active/${basename(rel)}` : rel,
|
|
157
|
+
constraints: contract.constraints,
|
|
158
|
+
humanApproval: {
|
|
159
|
+
kind: args.kind,
|
|
160
|
+
actor: args.actor,
|
|
161
|
+
mintedAt: new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
162
|
+
mintedVia: "scope:record-intent-constraint",
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
if ("error" in rec) {
|
|
166
|
+
process.stderr.write(`scope_record_intent_constraint: ${rec.error}\n`);
|
|
167
|
+
return 2;
|
|
168
|
+
}
|
|
169
|
+
const path = writeIntentConstraintRecord(projectRoot, rec);
|
|
170
|
+
if (!args.quiet) {
|
|
171
|
+
process.stdout.write(`Wrote ${path}\nCommit this record on the merge base before the implementation change PR.\n`);
|
|
172
|
+
}
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
if (isDirectEntrypoint(import.meta.url)) {
|
|
176
|
+
process.exit(run(process.argv.slice(2)));
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=scope-record-intent-constraint.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type HumanPresenceMintSeams } from "./human-presence-mint.js";
|
|
3
|
+
export interface ParsedArgs {
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
xbriefPath: string;
|
|
6
|
+
actor: string;
|
|
7
|
+
kind: string;
|
|
8
|
+
quiet: boolean;
|
|
9
|
+
confirm: boolean;
|
|
10
|
+
help?: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
14
|
+
export declare function run(argv: string[], seams?: HumanPresenceMintSeams): number;
|
|
15
|
+
//# sourceMappingURL=scope-record-observable-scope.d.ts.map
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for scope:record-observable-scope (#4495).
|
|
4
|
+
*
|
|
5
|
+
* Human-presence mint of `.deft/observable-scope/<plan-id>.json` from
|
|
6
|
+
* `plan["x-directive/observableChange"]`. --actor is display-only.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { basename, relative, resolve } from "node:path";
|
|
10
|
+
import { buildObservableScopeRecord, extractObservableChangeFromPlan, parseObservableChangeContract, writeObservableScopeRecord, } from "@deftai/directive-core/observable-scope";
|
|
11
|
+
import { isDirectEntrypoint } from "./entrypoint.js";
|
|
12
|
+
import { refuseMintWhileUatActive, refuseNonInteractiveMint, resolveHumanPresenceMintSeams, } from "./human-presence-mint.js";
|
|
13
|
+
import { isPathInsideRoot } from "./scope-record-approved-scope.js";
|
|
14
|
+
function usage() {
|
|
15
|
+
return ("usage: scope:record-observable-scope -- <xbrief-path> --actor <name> --confirm " +
|
|
16
|
+
"[--kind operator] [--project-root <dir>] [--quiet]\n" +
|
|
17
|
+
' Writes .deft/observable-scope/<plan-id>.json from plan["x-directive/observableChange"].\n' +
|
|
18
|
+
" --actor is display only and never authorizes mint. Mint requires a real TTY, " +
|
|
19
|
+
"controlling terminal, --confirm, and typed phrase mint (#3110). Agent/CI shells refuse.");
|
|
20
|
+
}
|
|
21
|
+
function extractPlanId(payload) {
|
|
22
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload))
|
|
23
|
+
return null;
|
|
24
|
+
const plan = payload.plan;
|
|
25
|
+
if (plan === null || typeof plan !== "object" || Array.isArray(plan))
|
|
26
|
+
return null;
|
|
27
|
+
const id = plan.id;
|
|
28
|
+
return typeof id === "string" && id.trim().length > 0 ? id.trim() : null;
|
|
29
|
+
}
|
|
30
|
+
export function parseArgs(argv) {
|
|
31
|
+
const parsed = {
|
|
32
|
+
projectRoot: ".",
|
|
33
|
+
xbriefPath: "",
|
|
34
|
+
actor: "",
|
|
35
|
+
kind: "operator",
|
|
36
|
+
quiet: false,
|
|
37
|
+
confirm: false,
|
|
38
|
+
};
|
|
39
|
+
const positionals = [];
|
|
40
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
41
|
+
const arg = argv[i];
|
|
42
|
+
if (arg === "--")
|
|
43
|
+
continue;
|
|
44
|
+
if (arg === "--help" || arg === "-h")
|
|
45
|
+
return { ...parsed, help: true };
|
|
46
|
+
if (arg === "--quiet")
|
|
47
|
+
parsed.quiet = true;
|
|
48
|
+
else if (arg === "--confirm")
|
|
49
|
+
parsed.confirm = true;
|
|
50
|
+
else if (arg === "--project-root") {
|
|
51
|
+
const value = argv[i + 1];
|
|
52
|
+
if (value === undefined)
|
|
53
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
54
|
+
parsed.projectRoot = value;
|
|
55
|
+
i += 1;
|
|
56
|
+
}
|
|
57
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
58
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
59
|
+
}
|
|
60
|
+
else if (arg === "--actor") {
|
|
61
|
+
const value = argv[i + 1];
|
|
62
|
+
if (value === undefined)
|
|
63
|
+
return { ...parsed, error: "argument --actor: expected one argument" };
|
|
64
|
+
parsed.actor = value;
|
|
65
|
+
i += 1;
|
|
66
|
+
}
|
|
67
|
+
else if (arg?.startsWith("--actor=")) {
|
|
68
|
+
parsed.actor = arg.slice("--actor=".length);
|
|
69
|
+
}
|
|
70
|
+
else if (arg === "--kind") {
|
|
71
|
+
const value = argv[i + 1];
|
|
72
|
+
if (value === undefined)
|
|
73
|
+
return { ...parsed, error: "argument --kind: expected one argument" };
|
|
74
|
+
parsed.kind = value;
|
|
75
|
+
i += 1;
|
|
76
|
+
}
|
|
77
|
+
else if (arg?.startsWith("--kind=")) {
|
|
78
|
+
parsed.kind = arg.slice("--kind=".length);
|
|
79
|
+
}
|
|
80
|
+
else if (arg?.startsWith("-")) {
|
|
81
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
82
|
+
}
|
|
83
|
+
else if (arg !== undefined) {
|
|
84
|
+
positionals.push(arg);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (parsed.help)
|
|
88
|
+
return parsed;
|
|
89
|
+
if (positionals.length === 0)
|
|
90
|
+
return { ...parsed, error: `missing xBRIEF path\n${usage()}` };
|
|
91
|
+
if (positionals.length > 1) {
|
|
92
|
+
return { ...parsed, error: `unexpected extra args: ${positionals.slice(1).join(" ")}` };
|
|
93
|
+
}
|
|
94
|
+
parsed.xbriefPath = positionals[0] ?? "";
|
|
95
|
+
if (parsed.actor.trim().length === 0) {
|
|
96
|
+
return {
|
|
97
|
+
...parsed,
|
|
98
|
+
error: `argument --actor is required (human operator identity)\n${usage()}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return parsed;
|
|
102
|
+
}
|
|
103
|
+
export function run(argv, seams = {}) {
|
|
104
|
+
const args = parseArgs(argv);
|
|
105
|
+
if (args.help) {
|
|
106
|
+
process.stdout.write(`${usage()}\n`);
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
if (args.error !== undefined) {
|
|
110
|
+
process.stderr.write(`scope_record_observable_scope: ${args.error}\n`);
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
const projectRoot = resolve(args.projectRoot);
|
|
114
|
+
const uat = refuseMintWhileUatActive("scope:record-observable-scope", projectRoot);
|
|
115
|
+
if (uat !== null)
|
|
116
|
+
return uat;
|
|
117
|
+
const resolved = resolveHumanPresenceMintSeams(seams);
|
|
118
|
+
const refused = refuseNonInteractiveMint({
|
|
119
|
+
verb: "scope:record-observable-scope",
|
|
120
|
+
confirm: args.confirm,
|
|
121
|
+
isTty: resolved.isTty,
|
|
122
|
+
environ: resolved.environ,
|
|
123
|
+
hasControllingTerminal: resolved.hasControllingTerminal,
|
|
124
|
+
readInteractiveConfirm: resolved.readInteractiveConfirm,
|
|
125
|
+
});
|
|
126
|
+
if (refused !== null)
|
|
127
|
+
return refused;
|
|
128
|
+
const xbriefAbs = resolve(projectRoot, args.xbriefPath);
|
|
129
|
+
const fullPath = existsSync(xbriefAbs) ? xbriefAbs : resolve(args.xbriefPath);
|
|
130
|
+
if (!existsSync(fullPath)) {
|
|
131
|
+
process.stderr.write(`scope_record_observable_scope: xBRIEF not found: ${args.xbriefPath}\n`);
|
|
132
|
+
return 2;
|
|
133
|
+
}
|
|
134
|
+
if (!isPathInsideRoot(projectRoot, fullPath)) {
|
|
135
|
+
process.stderr.write("scope_record_observable_scope: xBRIEF path escapes --project-root.\n");
|
|
136
|
+
return 2;
|
|
137
|
+
}
|
|
138
|
+
let payload;
|
|
139
|
+
const rawText = readFileSync(fullPath, "utf8");
|
|
140
|
+
try {
|
|
141
|
+
payload = JSON.parse(rawText);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
process.stderr.write(`scope_record_observable_scope: invalid JSON: ${String(err)}\n`);
|
|
145
|
+
return 2;
|
|
146
|
+
}
|
|
147
|
+
const planId = extractPlanId(payload) ?? basename(fullPath, ".xbrief.json");
|
|
148
|
+
const contract = parseObservableChangeContract(extractObservableChangeFromPlan(payload));
|
|
149
|
+
if ("error" in contract) {
|
|
150
|
+
process.stderr.write(`scope_record_observable_scope: ${contract.error}\n`);
|
|
151
|
+
return 2;
|
|
152
|
+
}
|
|
153
|
+
const rel = relative(projectRoot, fullPath).replace(/\\/g, "/");
|
|
154
|
+
const rec = buildObservableScopeRecord({
|
|
155
|
+
planId,
|
|
156
|
+
xbriefRelPath: rel.startsWith("xbrief/pending/") ? `xbrief/active/${basename(rel)}` : rel,
|
|
157
|
+
allowedChanges: contract.allowedChanges,
|
|
158
|
+
mustPreserve: contract.mustPreserve,
|
|
159
|
+
changeKind: contract.changeKind,
|
|
160
|
+
humanApproval: {
|
|
161
|
+
kind: args.kind,
|
|
162
|
+
actor: args.actor,
|
|
163
|
+
mintedAt: new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
164
|
+
mintedVia: "scope:record-observable-scope",
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
if ("error" in rec) {
|
|
168
|
+
process.stderr.write(`scope_record_observable_scope: ${rec.error}\n`);
|
|
169
|
+
return 2;
|
|
170
|
+
}
|
|
171
|
+
const path = writeObservableScopeRecord(projectRoot, rec);
|
|
172
|
+
if (!args.quiet) {
|
|
173
|
+
process.stdout.write(`Wrote ${path}\nCommit this record on the merge base before the UI change PR.\n`);
|
|
174
|
+
}
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
if (isDirectEntrypoint(import.meta.url)) {
|
|
178
|
+
process.exit(run(process.argv.slice(2)));
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=scope-record-observable-scope.js.map
|
package/dist/session-start.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { type CeremonyDepth, type CeremonyDialInputs } from "@deftai/directive-core/policy";
|
|
3
|
-
import { type PrimaryClaimException, type SessionCeremonyTier } from "@deftai/directive-core/session";
|
|
3
|
+
import { type PrimaryClaimException, type SessionCeremonyTier, type SessionPosture } from "@deftai/directive-core/session";
|
|
4
4
|
export interface ParsedSessionStartArgs {
|
|
5
5
|
projectRoot: string;
|
|
6
6
|
deferValues: string[];
|
|
@@ -43,6 +43,8 @@ export interface ParsedSessionStartArgs {
|
|
|
43
43
|
primaryClaimException: PrimaryClaimException | null;
|
|
44
44
|
/** #3611: explicit lifecycle owner injected by a host hook bridge. */
|
|
45
45
|
sessionId: string | null;
|
|
46
|
+
/** Trusted --posture argv (#4444). */
|
|
47
|
+
posture: SessionPosture | null;
|
|
46
48
|
error?: string;
|
|
47
49
|
}
|
|
48
50
|
/** Parse session:start CLI args, mirroring scripts/session_start.py. */
|
package/dist/session-start.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { CEREMONY_DEPTHS, normalizeCeremonyModelTier, normalizeCeremonyProjectShape, normalizeCeremonyTaskSize, selectCeremonyDepth, } from "@deftai/directive-core/policy";
|
|
5
|
-
import { COLD_CEREMONY_TIER, PRIMARY_CLAIM_EXCEPTIONS, parseDeferrals, READ_ONLY_POSTURE, REARM_CEREMONY_TIER, resolveProductionHostEffortDescriptor, ritualStatePath, runSessionStart, SESSION_CEREMONY_TIERS, } from "@deftai/directive-core/session";
|
|
5
|
+
import { COLD_CEREMONY_TIER, PRIMARY_CLAIM_EXCEPTIONS, parseDeferrals, parseSessionPostureToken, READ_ONLY_POSTURE, REARM_CEREMONY_TIER, REQUIREMENTS_POSTURE, resolveProductionHostEffortDescriptor, ritualStatePath, runSessionStart, SESSION_CEREMONY_TIERS, } from "@deftai/directive-core/session";
|
|
6
6
|
function parseCeremonyDepth(raw) {
|
|
7
7
|
const value = raw.trim().toLowerCase();
|
|
8
8
|
if (CEREMONY_DEPTHS.includes(value)) {
|
|
@@ -44,6 +44,7 @@ export function parseArgs(argv) {
|
|
|
44
44
|
occupant: null,
|
|
45
45
|
primaryClaimException: null,
|
|
46
46
|
sessionId: null,
|
|
47
|
+
posture: null,
|
|
47
48
|
};
|
|
48
49
|
const dialInputs = {};
|
|
49
50
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -372,6 +373,53 @@ export function parseArgs(argv) {
|
|
|
372
373
|
}
|
|
373
374
|
parsed.occupant = value;
|
|
374
375
|
}
|
|
376
|
+
else if (arg === "--posture") {
|
|
377
|
+
const value = argv[i + 1];
|
|
378
|
+
if (value === undefined || value.startsWith("--")) {
|
|
379
|
+
return {
|
|
380
|
+
...parsed,
|
|
381
|
+
error: "argument --posture: expected one argument (read-only|mutation|requirements)",
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
const parsedPosture = parseSessionPostureToken(value);
|
|
385
|
+
if (parsedPosture.error !== null) {
|
|
386
|
+
return { ...parsed, error: parsedPosture.error };
|
|
387
|
+
}
|
|
388
|
+
if (parsedPosture.token === "assist") {
|
|
389
|
+
return {
|
|
390
|
+
...parsed,
|
|
391
|
+
error: "argument --posture=docs|assist is scratch-only; set DEFT_SESSION_POSTURE=assist. Tracked docs use --posture=requirements",
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (parsedPosture.token === null) {
|
|
395
|
+
return {
|
|
396
|
+
...parsed,
|
|
397
|
+
error: "argument --posture: expected one argument (read-only|mutation|requirements)",
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
parsed.posture = parsedPosture.token;
|
|
401
|
+
i += 1;
|
|
402
|
+
}
|
|
403
|
+
else if (arg?.startsWith("--posture=")) {
|
|
404
|
+
const value = arg.slice("--posture=".length);
|
|
405
|
+
const parsedPosture = parseSessionPostureToken(value);
|
|
406
|
+
if (parsedPosture.error !== null) {
|
|
407
|
+
return { ...parsed, error: parsedPosture.error };
|
|
408
|
+
}
|
|
409
|
+
if (parsedPosture.token === "assist") {
|
|
410
|
+
return {
|
|
411
|
+
...parsed,
|
|
412
|
+
error: "argument --posture=docs|assist is scratch-only; set DEFT_SESSION_POSTURE=assist. Tracked docs use --posture=requirements",
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
if (parsedPosture.token === null) {
|
|
416
|
+
return {
|
|
417
|
+
...parsed,
|
|
418
|
+
error: "argument --posture: expected one argument (read-only|mutation|requirements)",
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
parsed.posture = parsedPosture.token;
|
|
422
|
+
}
|
|
375
423
|
else {
|
|
376
424
|
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
377
425
|
}
|
|
@@ -427,7 +475,7 @@ export function run(argv) {
|
|
|
427
475
|
result = runSessionStart(projectRoot, {
|
|
428
476
|
deferrals,
|
|
429
477
|
writeHistory: !args.noHistory,
|
|
430
|
-
posture: args.readOnly ? READ_ONLY_POSTURE : undefined,
|
|
478
|
+
posture: args.readOnly ? READ_ONLY_POSTURE : (args.posture ?? undefined),
|
|
431
479
|
allowOptionalNetwork: args.withNetwork ? true : undefined,
|
|
432
480
|
ceremonyTier: args.ceremonyTier,
|
|
433
481
|
ceremonyDialInputs: args.ceremonyDialInputs,
|
|
@@ -474,7 +522,7 @@ export function run(argv) {
|
|
|
474
522
|
}
|
|
475
523
|
if (result.code === 0) {
|
|
476
524
|
const posture = result.payload.posture;
|
|
477
|
-
if (posture === READ_ONLY_POSTURE) {
|
|
525
|
+
if (posture === READ_ONLY_POSTURE || posture === REQUIREMENTS_POSTURE) {
|
|
478
526
|
process.stdout.write(`[deft] ${String(result.payload.message)}\n`);
|
|
479
527
|
}
|
|
480
528
|
else {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
originRef?: string;
|
|
5
|
+
staged: boolean;
|
|
6
|
+
quiet: boolean;
|
|
7
|
+
planId?: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Parse verify-intent-constraint CLI args. */
|
|
11
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
12
|
+
/** Run the gate and return the process exit code. */
|
|
13
|
+
export declare function run(argv: string[]): number;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=verify-intent-constraint.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { evaluateIntentConstraint } from "@deftai/directive-core/intent-constraint";
|
|
5
|
+
/** Parse verify-intent-constraint CLI args. */
|
|
6
|
+
export function parseArgs(argv) {
|
|
7
|
+
const parsed = { projectRoot: ".", staged: false, quiet: false };
|
|
8
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
9
|
+
const arg = argv[i];
|
|
10
|
+
if (arg === "--quiet") {
|
|
11
|
+
parsed.quiet = true;
|
|
12
|
+
}
|
|
13
|
+
else if (arg === "--staged") {
|
|
14
|
+
parsed.staged = true;
|
|
15
|
+
}
|
|
16
|
+
else if (arg === "--project-root") {
|
|
17
|
+
const value = argv[i + 1];
|
|
18
|
+
if (value === undefined) {
|
|
19
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
20
|
+
}
|
|
21
|
+
parsed.projectRoot = value;
|
|
22
|
+
i += 1;
|
|
23
|
+
}
|
|
24
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
25
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
26
|
+
}
|
|
27
|
+
else if (arg === "--origin-ref") {
|
|
28
|
+
const value = argv[i + 1];
|
|
29
|
+
if (value === undefined) {
|
|
30
|
+
return { ...parsed, error: "argument --origin-ref: expected one argument" };
|
|
31
|
+
}
|
|
32
|
+
parsed.originRef = value;
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
else if (arg?.startsWith("--origin-ref=")) {
|
|
36
|
+
parsed.originRef = arg.slice("--origin-ref=".length);
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--plan-id") {
|
|
39
|
+
const value = argv[i + 1];
|
|
40
|
+
if (value === undefined) {
|
|
41
|
+
return { ...parsed, error: "argument --plan-id: expected one argument" };
|
|
42
|
+
}
|
|
43
|
+
parsed.planId = value;
|
|
44
|
+
i += 1;
|
|
45
|
+
}
|
|
46
|
+
else if (arg?.startsWith("--plan-id=")) {
|
|
47
|
+
parsed.planId = arg.slice("--plan-id=".length);
|
|
48
|
+
}
|
|
49
|
+
else if (arg === "--base-ref") {
|
|
50
|
+
return {
|
|
51
|
+
...parsed,
|
|
52
|
+
error: "unrecognized argument: --base-ref (baseline is the computed merge base; use --origin-ref to name the origin default)",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return parsed;
|
|
60
|
+
}
|
|
61
|
+
/** Run the gate and return the process exit code. */
|
|
62
|
+
export function run(argv) {
|
|
63
|
+
const args = parseArgs(argv);
|
|
64
|
+
if (args.error !== undefined) {
|
|
65
|
+
process.stderr.write(`verify_intent_constraint: ${args.error}\n`);
|
|
66
|
+
return 2;
|
|
67
|
+
}
|
|
68
|
+
const result = evaluateIntentConstraint({
|
|
69
|
+
projectRoot: resolve(args.projectRoot),
|
|
70
|
+
originRef: args.originRef,
|
|
71
|
+
staged: args.staged,
|
|
72
|
+
quiet: args.quiet,
|
|
73
|
+
planId: args.planId,
|
|
74
|
+
});
|
|
75
|
+
if (result.message.length > 0) {
|
|
76
|
+
if (result.stream === "stdout")
|
|
77
|
+
process.stdout.write(`${result.message}\n`);
|
|
78
|
+
else if (result.stream === "stderr")
|
|
79
|
+
process.stderr.write(`${result.message}\n`);
|
|
80
|
+
}
|
|
81
|
+
return result.code;
|
|
82
|
+
}
|
|
83
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
84
|
+
process.exit(run(process.argv.slice(2)));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=verify-intent-constraint.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
originRef?: string;
|
|
5
|
+
staged: boolean;
|
|
6
|
+
quiet: boolean;
|
|
7
|
+
planId?: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Parse verify-observable-scope CLI args. */
|
|
11
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
12
|
+
/** Run the gate and return the process exit code. */
|
|
13
|
+
export declare function run(argv: string[]): number;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=verify-observable-scope.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { evaluateObservableScope } from "@deftai/directive-core/observable-scope";
|
|
5
|
+
/** Parse verify-observable-scope CLI args. */
|
|
6
|
+
export function parseArgs(argv) {
|
|
7
|
+
const parsed = { projectRoot: ".", staged: false, quiet: false };
|
|
8
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
9
|
+
const arg = argv[i];
|
|
10
|
+
if (arg === "--quiet") {
|
|
11
|
+
parsed.quiet = true;
|
|
12
|
+
}
|
|
13
|
+
else if (arg === "--staged") {
|
|
14
|
+
parsed.staged = true;
|
|
15
|
+
}
|
|
16
|
+
else if (arg === "--project-root") {
|
|
17
|
+
const value = argv[i + 1];
|
|
18
|
+
if (value === undefined) {
|
|
19
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
20
|
+
}
|
|
21
|
+
parsed.projectRoot = value;
|
|
22
|
+
i += 1;
|
|
23
|
+
}
|
|
24
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
25
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
26
|
+
}
|
|
27
|
+
else if (arg === "--origin-ref") {
|
|
28
|
+
const value = argv[i + 1];
|
|
29
|
+
if (value === undefined) {
|
|
30
|
+
return { ...parsed, error: "argument --origin-ref: expected one argument" };
|
|
31
|
+
}
|
|
32
|
+
parsed.originRef = value;
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
else if (arg?.startsWith("--origin-ref=")) {
|
|
36
|
+
parsed.originRef = arg.slice("--origin-ref=".length);
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--plan-id") {
|
|
39
|
+
const value = argv[i + 1];
|
|
40
|
+
if (value === undefined) {
|
|
41
|
+
return { ...parsed, error: "argument --plan-id: expected one argument" };
|
|
42
|
+
}
|
|
43
|
+
parsed.planId = value;
|
|
44
|
+
i += 1;
|
|
45
|
+
}
|
|
46
|
+
else if (arg?.startsWith("--plan-id=")) {
|
|
47
|
+
parsed.planId = arg.slice("--plan-id=".length);
|
|
48
|
+
}
|
|
49
|
+
else if (arg === "--base-ref") {
|
|
50
|
+
return {
|
|
51
|
+
...parsed,
|
|
52
|
+
error: "unrecognized argument: --base-ref (baseline is the computed merge base; use --origin-ref to name the origin default)",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return parsed;
|
|
60
|
+
}
|
|
61
|
+
/** Run the gate and return the process exit code. */
|
|
62
|
+
export function run(argv) {
|
|
63
|
+
const args = parseArgs(argv);
|
|
64
|
+
if (args.error !== undefined) {
|
|
65
|
+
process.stderr.write(`verify_observable_scope: ${args.error}\n`);
|
|
66
|
+
return 2;
|
|
67
|
+
}
|
|
68
|
+
const result = evaluateObservableScope({
|
|
69
|
+
projectRoot: resolve(args.projectRoot),
|
|
70
|
+
originRef: args.originRef,
|
|
71
|
+
staged: args.staged,
|
|
72
|
+
quiet: args.quiet,
|
|
73
|
+
planId: args.planId,
|
|
74
|
+
});
|
|
75
|
+
if (result.message.length > 0) {
|
|
76
|
+
if (result.stream === "stdout")
|
|
77
|
+
process.stdout.write(`${result.message}\n`);
|
|
78
|
+
else if (result.stream === "stderr")
|
|
79
|
+
process.stderr.write(`${result.message}\n`);
|
|
80
|
+
}
|
|
81
|
+
return result.code;
|
|
82
|
+
}
|
|
83
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
84
|
+
process.exit(run(process.argv.slice(2)));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=verify-observable-scope.js.map
|
|
@@ -12,7 +12,13 @@ function parsePrNumber(raw) {
|
|
|
12
12
|
}
|
|
13
13
|
/** Parse verify-pr-closeout-attestable CLI args. */
|
|
14
14
|
export function parseArgs(argv) {
|
|
15
|
-
const parsed = {
|
|
15
|
+
const parsed = {
|
|
16
|
+
projectRoot: ".",
|
|
17
|
+
repo: null,
|
|
18
|
+
pr: null,
|
|
19
|
+
quiet: false,
|
|
20
|
+
onePrUnitId: null,
|
|
21
|
+
};
|
|
16
22
|
for (let i = 0; i < argv.length; i += 1) {
|
|
17
23
|
const arg = argv[i];
|
|
18
24
|
if (arg === "--quiet") {
|
|
@@ -60,6 +66,17 @@ export function parseArgs(argv) {
|
|
|
60
66
|
}
|
|
61
67
|
parsed.pr = pr;
|
|
62
68
|
}
|
|
69
|
+
else if (arg === "--one-pr-unit") {
|
|
70
|
+
const value = argv[i + 1];
|
|
71
|
+
if (value === undefined) {
|
|
72
|
+
return { ...parsed, error: "argument --one-pr-unit: expected one argument" };
|
|
73
|
+
}
|
|
74
|
+
parsed.onePrUnitId = value;
|
|
75
|
+
i += 1;
|
|
76
|
+
}
|
|
77
|
+
else if (arg?.startsWith("--one-pr-unit=")) {
|
|
78
|
+
parsed.onePrUnitId = arg.slice("--one-pr-unit=".length);
|
|
79
|
+
}
|
|
63
80
|
else {
|
|
64
81
|
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
65
82
|
}
|
|
@@ -79,6 +96,7 @@ export function run(argv) {
|
|
|
79
96
|
const result = evaluate(resolve(args.projectRoot), args.pr, {
|
|
80
97
|
repo: args.repo,
|
|
81
98
|
quiet: args.quiet,
|
|
99
|
+
onePrUnitId: args.onePrUnitId,
|
|
82
100
|
});
|
|
83
101
|
if (result.message.length > 0) {
|
|
84
102
|
if (result.stream === "stdout") {
|
|
@@ -118,12 +118,12 @@ export function resolveClosingKeywordsSource(env, runGit = defaultRunGit) {
|
|
|
118
118
|
export function buildClosingKeywordsCheckArgv(env, extra = [], runGit = defaultRunGit) {
|
|
119
119
|
const source = resolveClosingKeywordsSource(env, runGit);
|
|
120
120
|
if (source.kind === "pr") {
|
|
121
|
-
return { argv: ["--mode", "
|
|
121
|
+
return { argv: ["--mode", "both", "--pr", source.pr, ...extra] };
|
|
122
122
|
}
|
|
123
123
|
if (source.kind === "missing-base" || source.kind === "stale-base") {
|
|
124
124
|
return { argv: [], error: source.reason };
|
|
125
125
|
}
|
|
126
|
-
return { argv: ["--mode", "
|
|
126
|
+
return { argv: ["--mode", "both", "--from-git-range", source.range, ...extra] };
|
|
127
127
|
}
|
|
128
128
|
export function run(argv, env = process.env, invoke = cmdPrCheckClosingKeywords, runGit = defaultRunGit) {
|
|
129
129
|
const built = buildClosingKeywordsCheckArgv(env, argv, runGit);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { evaluate, gitPorcelain, parseAllocationSection } from "@deftai/directive-core/story-ready";
|
|
5
|
+
import { evaluate, gitPorcelain, gitRevParseAbbrev, parseAllocationSection, } from "@deftai/directive-core/story-ready";
|
|
6
6
|
import { ROUTING_GATED_DISPATCH_PROVIDERS, resolveDispatchProvider, verifyRouting, } from "@deftai/directive-core/swarm";
|
|
7
7
|
/** Parse verify-story-ready CLI args, mirroring the Python argparse surface. */
|
|
8
8
|
export function parseArgs(argv) {
|
|
@@ -149,6 +149,7 @@ export function run(argv) {
|
|
|
149
149
|
allowDirty: args.allowDirty,
|
|
150
150
|
parsed,
|
|
151
151
|
projectRoot,
|
|
152
|
+
onePrUnitBranch: gitRevParseAbbrev(projectRoot),
|
|
152
153
|
});
|
|
153
154
|
if (result.exitCode === 0 && !args.skipRouting) {
|
|
154
155
|
const provider = resolveDispatchProvider(process.env);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.119.0",
|
|
4
4
|
"description": "Directive CLI — npm install path for the Deft Directive framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://deftai.github.io/directive/",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"provenance": true
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@deftai/directive-core": "^0.
|
|
38
|
-
"@deftai/directive-content": "^0.
|
|
37
|
+
"@deftai/directive-core": "^0.119.0",
|
|
38
|
+
"@deftai/directive-content": "^0.119.0"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -b"
|