create-agdf 0.10.0 → 0.10.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.
Files changed (89) hide show
  1. package/README.md +30 -22
  2. package/bin/agdf-validator.js +11 -0
  3. package/generated/.agdf/control/README.md +3 -3
  4. package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +1 -1
  5. package/generated/.github/skills/agdf-delivery-path-search/SKILL.md +7 -6
  6. package/generated/.github/skills/agdf-gate-check/SKILL.md +28 -91
  7. package/generated/.github/skills/agdf-interaction-locales.json +2 -0
  8. package/generated/.github/skills/contracts/gate-transition.md +4 -2
  9. package/generated/.github/skills/contracts/modes.md +12 -1
  10. package/generated/.opencode/README.md +6 -8
  11. package/generated/.opencode/agdf-interaction-locales.json +2 -0
  12. package/generated/.opencode/contracts/gate-transition.md +4 -2
  13. package/generated/.opencode/contracts/modes.md +12 -1
  14. package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +1 -1
  15. package/generated/.opencode/skills/agdf-delivery-path-search/SKILL.md +7 -6
  16. package/generated/.opencode/skills/agdf-gate-check/SKILL.md +28 -91
  17. package/generated/plugins/agdf/.claude-plugin/plugin.json +19 -0
  18. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  19. package/generated/plugins/agdf/control/README.md +3 -3
  20. package/generated/plugins/agdf/hooks/session-start.sh +1 -1
  21. package/generated/plugins/agdf/meta/agdf-interaction-locales.json +2 -0
  22. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  23. package/generated/plugins/agdf/meta/contracts/gate-transition.md +4 -2
  24. package/generated/plugins/agdf/meta/contracts/modes.md +12 -1
  25. package/generated/plugins/agdf/runtime/agdf-local.js +11 -0
  26. package/generated/plugins/agdf/runtime/create-agdf/NOTICE +10 -0
  27. package/generated/plugins/agdf/runtime/create-agdf/bin/agdf-validator.js +11 -0
  28. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +418 -0
  29. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +220 -0
  30. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +136 -0
  31. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +75 -0
  32. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +156 -0
  33. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/runtime-context.js +83 -0
  34. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +45 -0
  35. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/delivery-map.js +291 -0
  36. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +265 -0
  37. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +459 -0
  38. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +283 -0
  39. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/required-files.js +9 -0
  40. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +217 -0
  41. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +344 -0
  42. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/verified-change.js +156 -0
  43. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/aggregate.js +18 -0
  44. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/gate-approval-validator.js +49 -0
  45. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/index.js +7 -0
  46. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/legacy-migration.js +95 -0
  47. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +227 -0
  48. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-repository.js +68 -0
  49. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-resolver.js +45 -0
  50. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-writer.js +97 -0
  51. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/candidate-policy.js +99 -0
  52. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +237 -0
  53. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +44 -0
  54. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +53 -0
  55. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/protocol.js +13 -0
  56. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/generators/claude.js +40 -0
  57. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/generators/codex.js +38 -0
  58. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/generators/protocol.js +12 -0
  59. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +39 -0
  60. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/scoring.js +21 -0
  61. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +154 -0
  62. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +161 -0
  63. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +14 -0
  64. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/transports/read-only-guard.js +43 -0
  65. package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +590 -0
  66. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +142 -0
  67. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/validator-application.js +40 -0
  68. package/generated/plugins/agdf/runtime/create-agdf/package.json +66 -0
  69. package/generated/plugins/agdf/runtime/runtime-manifest.json +8 -0
  70. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +1040 -0
  71. package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +1 -1
  72. package/generated/plugins/agdf/skills/delivery-path-search/SKILL.md +7 -6
  73. package/generated/plugins/agdf/skills/gate-check/SKILL.md +28 -91
  74. package/lib/cli/application.js +21 -59
  75. package/lib/cli/command-registry.js +9 -11
  76. package/lib/cli/validation-handlers.js +45 -0
  77. package/lib/control-evaluation/doctor.js +1 -1
  78. package/lib/control-evaluation/gate-check.js +7 -7
  79. package/lib/control-evaluation/required-files.js +9 -0
  80. package/lib/installers/local-marketplace.js +322 -0
  81. package/lib/installers/opencode-activation.js +43 -0
  82. package/lib/installers/opencode.js +60 -18
  83. package/lib/installers/plugin-installers.js +102 -26
  84. package/lib/runtime/local-validator.js +142 -0
  85. package/lib/runtime/validator-application.js +40 -0
  86. package/lib/scaffold/plan.js +1 -30
  87. package/lib/scaffold/presentation.js +9 -14
  88. package/opencode-plugin.js +32 -24
  89. package/package.json +6 -2
@@ -0,0 +1,136 @@
1
+ function command(name, usages) {
2
+ return Object.freeze({
3
+ name,
4
+ handler: name,
5
+ groups: Object.freeze(Object.keys(usages)),
6
+ usages: Object.freeze(Object.fromEntries(
7
+ Object.entries(usages).map(([group, suffixes]) => [group, Object.freeze(suffixes)]),
8
+ )),
9
+ });
10
+ }
11
+
12
+ export const commandRegistry = Object.freeze([
13
+ command("codex", { preferred: [""], scaffold: [""] }),
14
+ command("codex-repo", { preferred: [""], scaffold: [""] }),
15
+ command("claude", { preferred: [""], scaffold: [""] }),
16
+ command("copilot", { preferred: [""], scaffold: [""] }),
17
+ command("opencode", { preferred: [""], scaffold: [""] }),
18
+ command("opencode-status", { preferred: [""], scaffold: [""] }),
19
+ command("status", { preferred: [" [--surface <surface>] [--run <run_id>] [--json]"] }),
20
+ command("disable", { preferred: [" --surface <surface> [--scope repository] [--dir <path>]"] }),
21
+ command("uninstall", { preferred: [" --surface <surface> --scope global [--confirm]"] }),
22
+ command("opencode-repo", { preferred: [""], scaffold: [""] }),
23
+ command("both", { scaffold: [""] }),
24
+ command("init", { preferred: [""], scaffold: [""] }),
25
+ command("config", { scaffold: [" --language de"] }),
26
+ command("doctor", { local: [""], scaffold: [""], legacy: [" --json"] }),
27
+ command("gate-check", { local: [" --approval-envelope", " --json"], scaffold: [""], legacy: [" --json"] }),
28
+ command("delivery-map", { local: [" --json"], scaffold: [""] }),
29
+ command("delivery-path-search", {
30
+ local: [" --surface codex --json", " --surface claude --json"],
31
+ scaffold: [" --surface codex", " --surface claude"],
32
+ }),
33
+ command("run-create", { local: [" --run <run_id>"] }),
34
+ command("run-migrate", { local: [" [--run <run_id>]"] }),
35
+ command("run-render-legacy", { local: [" --run <run_id>"] }),
36
+ ]);
37
+
38
+ const commandByName = new Map(commandRegistry.map((entry) => [entry.name, entry]));
39
+
40
+ export function resolveCommand(name) {
41
+ return commandByName.get(name) ?? null;
42
+ }
43
+
44
+ export function supportedCommandNames() {
45
+ return commandRegistry.map((entry) => entry.name);
46
+ }
47
+
48
+ export function validateCommandOptions(options) {
49
+ if (options.allActive && !["doctor", "delivery-map"].includes(options.target)) {
50
+ throw new Error("--all-active is supported only by doctor and delivery-map");
51
+ }
52
+ if (options.target === "run-create" && (!options.runId || options.allActive)) {
53
+ throw new Error("run-create requires --run and rejects --all-active");
54
+ }
55
+ if (options.target === "run-render-legacy" && !options.runId) {
56
+ throw new Error("run-render-legacy requires --run");
57
+ }
58
+ if (["disable", "uninstall"].includes(options.target) && ["", "generic", undefined].includes(options.surface)) {
59
+ throw new Error(`${options.target} requires an explicit --surface`);
60
+ }
61
+ if (options.target === "disable" && options.scope && options.scope !== "repository") {
62
+ throw new Error("disable supports repository scope only");
63
+ }
64
+ if (options.target === "uninstall" && options.scope !== "global") {
65
+ throw new Error("uninstall requires explicit --scope global");
66
+ }
67
+ if (options.confirm && options.target !== "uninstall") throw new Error("--confirm is supported only by uninstall");
68
+ if (options.approvalEnvelope && options.target !== "gate-check") throw new Error("--approval-envelope is supported only by gate-check");
69
+ if (options.approvalEnvelope && (options.json || options.statusCard || options.allActive)) {
70
+ throw new Error("--approval-envelope cannot be combined with --json, --status-card or --all-active");
71
+ }
72
+ return options;
73
+ }
74
+
75
+ function usageLines(group, prefix) {
76
+ return commandRegistry
77
+ .flatMap((entry) => (entry.usages[group] ?? []).map((suffix) => ` ${prefix}${entry.name}${suffix}`))
78
+ .join("\n");
79
+ }
80
+
81
+ export function renderUsage() {
82
+ return `AGDF CLI
83
+
84
+ Operating model:
85
+ Chat/skill is the normal interaction surface.
86
+ .agdf/control is the durable source of truth.
87
+ The CLI validates, renders deterministic gate output and supports automation.
88
+
89
+ Repeated local validation (after global installation):
90
+ ${usageLines("local", "agdf ")}
91
+
92
+ Bootstrap, installation and explicit refresh:
93
+
94
+ Bootstrap and lifecycle commands:
95
+ ${usageLines("preferred", "npx --yes @agdf/cli@latest ")}
96
+
97
+ Advanced / Compatibility
98
+
99
+ Scaffold-compatible npm create usage:
100
+ ${usageLines("scaffold", "npm create agdf@latest -- ")}
101
+
102
+ Backward-compatible create-agdf usage:
103
+ ${usageLines("legacy", "npx --yes create-agdf@latest ")}
104
+
105
+ Options:
106
+ --dir <path> Write files into a specific directory. With opencode, use this as the OpenCode config directory.
107
+ --force Overwrite existing generated files
108
+ --language <tag>
109
+ Set AGDF chat and artefact language. Defaults to detected system locale.
110
+ --lang <tag> Alias for --language
111
+ --json Print machine-readable command output as JSON
112
+ --verbose Print captured host command output and generated-file details
113
+ --status-card Print compact gate-check status-card output for interactive use
114
+ --approval-envelope
115
+ Print the deterministic ready-gate cards and exact-text request
116
+ --run <run_id> Select one canonical run
117
+ --all-active Evaluate every active run (doctor and delivery-map only)
118
+ --surface <codex|claude|copilot|opencode|generic>
119
+ Declare the active Delivery Path Search surface
120
+ --scope <repository|global>
121
+ Select the lifecycle mutation scope
122
+ --confirm Apply a previously previewed global uninstall plan
123
+ --fixture <path>
124
+ Use deterministic evaluator/candidate fixtures instead of a live evaluator
125
+ --persist Persist the redacted Delivery Path Search result under the current scope
126
+ --model <id> Optional Codex evaluator model
127
+ --generate-candidates
128
+ Add one bounded AI-native candidate-generation call before evaluation
129
+ --generator-model <id>
130
+ Optional candidate-generator model override
131
+ --max-generated-candidates <1-5>
132
+ --generation-timeout-ms <1-30000>
133
+ --generation-cost-units <1-5>
134
+ --help Show this help
135
+ `;
136
+ }
@@ -0,0 +1,75 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { searchInputFromControl } from '../delivery-path-search/state-adapter.js';
3
+ import { runDeliveryPathSearch } from '../delivery-path-search/search-engine.js';
4
+ import { codexEvaluator } from '../delivery-path-search/evaluators/codex.js';
5
+ import { claudeEvaluator } from '../delivery-path-search/evaluators/claude.js';
6
+ import { fixtureEvaluator } from '../delivery-path-search/evaluators/protocol.js';
7
+ import { codexGenerator } from '../delivery-path-search/generators/codex.js';
8
+ import { claudeGenerator } from '../delivery-path-search/generators/claude.js';
9
+ import { fixtureGenerator } from '../delivery-path-search/generators/protocol.js';
10
+ import { enforcementForSurface } from '../delivery-path-search/surfaces/capabilities.js';
11
+ import { persistSearchResult } from '../delivery-path-search/persistence.js';
12
+
13
+ export async function executeDeliveryPathSearch(options, io = console) {
14
+ const fixture = options.fixture ? JSON.parse(readFileSync(options.fixture, "utf8")) : null;
15
+ const enforcement = fixture?.input?.enforcement ?? enforcementForSurface(options.surface);
16
+ const fixtureGeneration = fixture?.generator_response;
17
+ const generationEnabled = Boolean(fixtureGeneration || options.generateCandidates);
18
+ const baseInput = fixture?.input ?? searchInputFromControl(options.dir, {
19
+ scopeKey: options.runId,
20
+ enforcement,
21
+ generation: generationEnabled ? {
22
+ enabled: true,
23
+ maxProposals: options.maxGeneratedCandidates,
24
+ maxDurationMs: options.generationTimeoutMs,
25
+ maxCostUnits: options.generationCostUnits,
26
+ } : undefined,
27
+ });
28
+ const input = generationEnabled && !baseInput.generation ? {
29
+ ...baseInput,
30
+ generation: {
31
+ enabled: true,
32
+ max_calls: 1,
33
+ max_proposals: options.maxGeneratedCandidates,
34
+ max_duration_ms: options.generationTimeoutMs,
35
+ max_cost_units: options.generationCostUnits,
36
+ },
37
+ } : baseInput;
38
+ const evaluator = fixture
39
+ ? fixtureEvaluator(fixture.evaluations ?? {})
40
+ : options.surface === "codex"
41
+ ? codexEvaluator({ cwd: options.dir, model: options.model })
42
+ : options.surface === "claude"
43
+ ? claudeEvaluator({ cwd: options.dir, model: options.model })
44
+ : null;
45
+ if (!evaluator) {
46
+ throw new Error(`${options.surface} has no executable evaluator in this release. Codex and Claude are the reference adapters; --fixture is available for deterministic contract testing.`);
47
+ }
48
+ const generator = fixtureGeneration
49
+ ? fixtureGenerator(fixtureGeneration)
50
+ : options.generateCandidates && options.surface === "codex"
51
+ ? codexGenerator({ cwd: options.dir, model: options.generatorModel, timeoutMs: options.generationTimeoutMs })
52
+ : options.generateCandidates && options.surface === "claude"
53
+ ? claudeGenerator({ cwd: options.dir, model: options.generatorModel, timeoutMs: options.generationTimeoutMs })
54
+ : null;
55
+ if (options.generateCandidates && !generator) {
56
+ throw new Error(`${options.surface} has no executable candidate generator; Codex and Claude are tool-enforced reference transports.`);
57
+ }
58
+ const result = await runDeliveryPathSearch(input, evaluator, { candidates: fixture?.candidates, generator });
59
+ if (options.persist) result.persistence = persistSearchResult(options.dir, result);
60
+ if (options.json) {
61
+ io.log(JSON.stringify(result, null, 2));
62
+ return result;
63
+ }
64
+ io.log(`AGDF Delivery Path Search: ${result.status}`);
65
+ io.log(`Current gate: ${result.current_gate}`);
66
+ io.log(`Enforcement: ${result.enforcement.level}`);
67
+ io.log(`Recommendation: ${result.recommendation?.action ?? "none"}`);
68
+ io.log(`Evaluations: ${result.budgets.evaluations}`);
69
+ io.log(`Generation: ${result.generation.status} (${result.generation.accepted}/${result.generation.returned} accepted)`);
70
+ io.log(`Generation budget: ${result.generation.cost_units} cost units, ${result.generation.duration_ms} ms`);
71
+ if (result.generation.failure_code) io.log(`Generation failure: ${result.generation.failure_code}`);
72
+ io.log(`Stopping reason: ${result.stopping_reason}`);
73
+ io.log(result.next_gate_action);
74
+ return result;
75
+ }
@@ -0,0 +1,156 @@
1
+ import { resolve } from "node:path";
2
+ import process from "node:process";
3
+ import { configuredLanguage, resolveLanguagePreference } from "./runtime-context.js";
4
+ import { resolveCommand, supportedCommandNames } from "./command-registry.js";
5
+
6
+ export class CliUsageError extends Error {
7
+ constructor(message, { showUsage = false } = {}) {
8
+ super(message);
9
+ this.name = "CliUsageError";
10
+ this.exitCode = 1;
11
+ this.showUsage = showUsage;
12
+ }
13
+ }
14
+
15
+ function requiredValue(args, index, option) {
16
+ const next = args[index + 1];
17
+ if (!next) throw new CliUsageError(`Missing value for ${option}`);
18
+ return next;
19
+ }
20
+
21
+ export function parseArgs(argv, dependencies = {}) {
22
+ const cwd = dependencies.cwd ?? process.cwd();
23
+ const languagePreference = dependencies.resolveLanguagePreference ?? resolveLanguagePreference;
24
+ const normalizeLanguage = dependencies.configuredLanguage ?? configuredLanguage;
25
+ const args = [...argv];
26
+ let target;
27
+ let dir = ".";
28
+ let force = false;
29
+ let json = false;
30
+ let verbose = false;
31
+ let statusCard = false;
32
+ let approvalEnvelope = false;
33
+ let language;
34
+ let dirExplicit = false;
35
+ let surface = "generic";
36
+ let fixture;
37
+ let persist = false;
38
+ let model;
39
+ let generateCandidates = false;
40
+ let generatorModel;
41
+ let maxGeneratedCandidates = 5;
42
+ let generationTimeoutMs = 30000;
43
+ let generationCostUnits = 5;
44
+ let runId;
45
+ let allActive = false;
46
+ let scope;
47
+ let confirm = false;
48
+
49
+ for (let i = 0; i < args.length; i += 1) {
50
+ const arg = args[i];
51
+ if (!arg) continue;
52
+ if (arg === "--help" || arg === "-h") return { kind: "help" };
53
+ if (arg === "--force") { force = true; continue; }
54
+ if (arg === "--json") { json = true; continue; }
55
+ if (arg === "--verbose") { verbose = true; continue; }
56
+ if (arg === "--status-card") { statusCard = true; continue; }
57
+ if (arg === "--approval-envelope") { approvalEnvelope = true; continue; }
58
+ if (arg === "--persist") { persist = true; continue; }
59
+ if (arg === "--generate-candidates") { generateCandidates = true; continue; }
60
+ if (arg === "--all-active") { allActive = true; continue; }
61
+ if (arg === "--confirm") { confirm = true; continue; }
62
+
63
+ if (arg === "--run") {
64
+ runId = requiredValue(args, i, arg);
65
+ i += 1;
66
+ continue;
67
+ }
68
+
69
+ if (["--surface", "--scope", "--fixture", "--model", "--generator-model", "--max-generated-candidates", "--generation-timeout-ms", "--generation-cost-units"].includes(arg)) {
70
+ const next = requiredValue(args, i, arg);
71
+ if (arg === "--surface") {
72
+ if (!["codex", "claude", "copilot", "opencode", "generic"].includes(next)) {
73
+ throw new CliUsageError("Unsupported surface. Use codex, claude, copilot, opencode or generic.");
74
+ }
75
+ surface = next;
76
+ } else if (arg === "--scope") {
77
+ if (!["repository", "global"].includes(next)) throw new CliUsageError("Unsupported scope. Use repository or global.");
78
+ scope = next;
79
+ } else if (arg === "--fixture") fixture = next;
80
+ else if (arg === "--model") model = next;
81
+ else if (arg === "--generator-model") generatorModel = next;
82
+ else {
83
+ const value = Number(next);
84
+ const maximum = arg === "--generation-timeout-ms" ? 30000 : 5;
85
+ if (!Number.isInteger(value) || value < 1 || value > maximum) {
86
+ throw new CliUsageError(`${arg} must be an integer from 1 to ${maximum}.`);
87
+ }
88
+ if (arg === "--max-generated-candidates") maxGeneratedCandidates = value;
89
+ else if (arg === "--generation-timeout-ms") generationTimeoutMs = value;
90
+ else generationCostUnits = value;
91
+ }
92
+ i += 1;
93
+ continue;
94
+ }
95
+
96
+ if (arg === "--language" || arg === "--lang") {
97
+ const next = requiredValue(args, i, arg);
98
+ const normalized = normalizeLanguage(next);
99
+ if (!normalized) throw new CliUsageError("Invalid language tag. Use a BCP 47 tag such as de, en or fr-CA.");
100
+ language = normalized;
101
+ i += 1;
102
+ continue;
103
+ }
104
+
105
+ if (arg === "--dir") {
106
+ dir = requiredValue(args, i, arg);
107
+ dirExplicit = true;
108
+ i += 1;
109
+ continue;
110
+ }
111
+
112
+ if (arg === "--target" || arg === "-t") {
113
+ target = requiredValue(args, i, arg);
114
+ i += 1;
115
+ continue;
116
+ }
117
+
118
+ if (!arg.startsWith("-") && !target) {
119
+ target = arg;
120
+ continue;
121
+ }
122
+ throw new CliUsageError(`Unknown argument: ${arg}`);
123
+ }
124
+
125
+ if (!target || !resolveCommand(target)) {
126
+ throw new CliUsageError(`Please choose one target: ${supportedCommandNames().join(", ")}.`, { showUsage: true });
127
+ }
128
+
129
+ return {
130
+ kind: "command",
131
+ options: {
132
+ target,
133
+ dir: resolve(cwd, dir),
134
+ force,
135
+ json,
136
+ verbose,
137
+ statusCard,
138
+ approvalEnvelope,
139
+ dirExplicit,
140
+ language: languagePreference(language),
141
+ surface,
142
+ fixture: fixture ? resolve(cwd, fixture) : null,
143
+ persist,
144
+ model,
145
+ generateCandidates,
146
+ runId,
147
+ allActive,
148
+ scope,
149
+ confirm,
150
+ generatorModel,
151
+ maxGeneratedCandidates,
152
+ generationTimeoutMs,
153
+ generationCostUnits,
154
+ },
155
+ };
156
+ }
@@ -0,0 +1,83 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import process from "node:process";
5
+ import {
6
+ canonicalizeLanguageTag,
7
+ resolvePresentationLocale,
8
+ } from "../interaction-presentation.js";
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+
12
+ export const packageRoot = resolve(__dirname, "../..");
13
+ export const generatedRoot = join(packageRoot, "generated");
14
+
15
+ const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
16
+ const interactionLocalesPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-interaction-locales.json");
17
+
18
+ export const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
19
+ export const interactionLocales = JSON.parse(readFileSync(interactionLocalesPath, "utf8"));
20
+
21
+ export function configuredLanguage(value) {
22
+ const normalized = canonicalizeLanguageTag(value);
23
+ if (!normalized) return "";
24
+ const language = normalized.split("-")[0];
25
+ if (interactionLocales.locales[normalized] || interactionLocales.locales[language]) {
26
+ return resolvePresentationLocale(interactionLocales, normalized);
27
+ }
28
+ return normalized;
29
+ }
30
+
31
+ export function detectSystemLocale(env = process.env) {
32
+ const envLocale = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE || "";
33
+ if (envLocale) return envLocale;
34
+ try {
35
+ return Intl.DateTimeFormat().resolvedOptions().locale || "";
36
+ } catch {
37
+ return "";
38
+ }
39
+ }
40
+
41
+ export function resolveLanguagePreference(explicitLanguage, env = process.env) {
42
+ const explicit = configuredLanguage(explicitLanguage);
43
+ if (explicit) {
44
+ return {
45
+ artifact_language: explicit,
46
+ chat_language: explicit,
47
+ runtime_language: "en",
48
+ source: "parameter",
49
+ detected_locale: detectSystemLocale(env) || "unknown",
50
+ };
51
+ }
52
+
53
+ const detectedLocale = detectSystemLocale(env);
54
+ const detected = configuredLanguage(detectedLocale) || interactionLocales.fallbackLocale;
55
+ return {
56
+ artifact_language: detected,
57
+ chat_language: detected,
58
+ runtime_language: "en",
59
+ source: detectedLocale ? "system_locale" : "default",
60
+ detected_locale: detectedLocale || "unknown",
61
+ };
62
+ }
63
+
64
+ export function resolveConfiguredChatLanguage(targetDir) {
65
+ const configPath = join(targetDir, ".agdf", "control", "config.json");
66
+ if (!existsSync(configPath)) return interactionLocales.fallbackLocale;
67
+ try {
68
+ const config = JSON.parse(readFileSync(configPath, "utf8"));
69
+ return resolvePresentationLocale(interactionLocales, config.chat_language);
70
+ } catch {
71
+ return interactionLocales.fallbackLocale;
72
+ }
73
+ }
74
+
75
+ export function languageConfigContent(languagePreference) {
76
+ return `${JSON.stringify({
77
+ artifact_language: languagePreference.artifact_language,
78
+ chat_language: languagePreference.chat_language,
79
+ runtime_language: languagePreference.runtime_language,
80
+ source: languagePreference.source,
81
+ detected_locale: languagePreference.detected_locale,
82
+ }, null, 2)}\n`;
83
+ }
@@ -0,0 +1,45 @@
1
+ import {
2
+ buildStatusCard,
3
+ evaluateGateCheck,
4
+ printApprovalEnvelope,
5
+ postApprovalTransition,
6
+ printGateCheckReport,
7
+ } from "../control-evaluation/gate-check.js";
8
+ import { evaluateDeliveryMap, printDeliveryMapReport } from "../control-evaluation/delivery-map.js";
9
+ import { evaluateDoctor, printDoctorReport } from "../control-evaluation/doctor.js";
10
+ import { executeDeliveryPathSearch } from "./delivery-path-search-command.js";
11
+
12
+ const deliveryMapDependencies = Object.freeze({ evaluateDoctor, buildStatusCard, postApprovalTransition });
13
+
14
+ export function createValidationHandlers(io = console) {
15
+ return new Map([
16
+ ["doctor", (options) => {
17
+ const report = evaluateDoctor(options.dir, options);
18
+ printDoctorReport(report, options.json, io);
19
+ return report.status === "block" ? 2 : 0;
20
+ }],
21
+ ["gate-check", (options) => {
22
+ const report = evaluateGateCheck(options.dir, options);
23
+ if (options.approvalEnvelope) {
24
+ const output = printApprovalEnvelope(report, { io, reEvaluate: () => evaluateGateCheck(options.dir, options) });
25
+ return output.status === "blocked" ? 2 : 0;
26
+ }
27
+ printGateCheckReport(report, options.json, options.statusCard, io);
28
+ return report.status === "blocked" ? 2 : 0;
29
+ }],
30
+ ["delivery-map", (options) => {
31
+ const report = evaluateDeliveryMap(options.dir, options, deliveryMapDependencies);
32
+ printDeliveryMapReport(report, options.json, io);
33
+ return report.status === "block" ? 2 : 0;
34
+ }],
35
+ ["delivery-path-search", async (options) => {
36
+ try {
37
+ const result = await executeDeliveryPathSearch(options, io);
38
+ return result.status === "recommendation" ? 0 : 2;
39
+ } catch (error) {
40
+ io.error(`Delivery Path Search failed: ${error.message}`);
41
+ return 2;
42
+ }
43
+ }],
44
+ ]);
45
+ }