@aiwg/cli 2026.10.5 → 2026.10.7
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/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
- package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
- package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
- package/agentic/code/providers/model-capabilities.v1.json +74 -50
- package/bin/aiwg.mjs +7 -3
- package/dist/src/a2a/agent-card.js +11 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/browser-export.js +1 -0
- package/dist/src/artifacts/citation-parser.js +8 -1
- package/dist/src/artifacts/cli.js +57 -6
- package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
- package/dist/src/artifacts/fortemi-core-sync.js +26 -8
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/contract.json +103 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-config.schema.json +212 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-set.schema.json +240 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-manifest.schema.json +451 -0
- package/dist/src/artifacts/fortemi-shard-export.js +284 -0
- package/dist/src/artifacts/graph-query.js +18 -8
- package/dist/src/artifacts/index-adapters.js +339 -0
- package/dist/src/artifacts/index-builder.js +143 -14
- package/dist/src/artifacts/index-files.js +15 -4
- package/dist/src/artifacts/index-preparation.js +2 -0
- package/dist/src/artifacts/index-reader.js +44 -0
- package/dist/src/artifacts/index-refresh.js +114 -55
- package/dist/src/artifacts/index-status.js +20 -5
- package/dist/src/artifacts/memory-maintenance.js +503 -0
- package/dist/src/artifacts/prebuilt-relations.js +3 -1
- package/dist/src/artifacts/query-engine.js +263 -108
- package/dist/src/artifacts/relations-builder.js +2 -2
- package/dist/src/artifacts/source-graph.js +2 -2
- package/dist/src/artifacts/types.js +9 -1
- package/dist/src/auth/client.js +5 -1
- package/dist/src/auth/credential-store.js +5 -1
- package/dist/src/auth/sensitive-input.js +151 -0
- package/dist/src/channel/manager.mjs +3 -0
- package/dist/src/cli/handlers/agentcard.js +47 -25
- package/dist/src/cli/handlers/auth.js +22 -2
- package/dist/src/cli/handlers/decision.js +22 -3
- package/dist/src/cli/handlers/effect.js +4 -84
- package/dist/src/cli/handlers/guided-setup.js +470 -0
- package/dist/src/cli/handlers/help.js +2 -2
- package/dist/src/cli/handlers/housekeeper.js +1110 -0
- package/dist/src/cli/handlers/index.js +4 -2
- package/dist/src/cli/handlers/init.js +41 -6
- package/dist/src/cli/handlers/install.js +6 -0
- package/dist/src/cli/handlers/local-executor.js +5 -3
- package/dist/src/cli/handlers/marketplace.js +15 -4
- package/dist/src/cli/handlers/mc.js +509 -53
- package/dist/src/cli/handlers/models.js +32 -2
- package/dist/src/cli/handlers/ralph-launcher.js +76 -4
- package/dist/src/cli/handlers/rules.js +1 -1
- package/dist/src/cli/handlers/script-runner.js +73 -2
- package/dist/src/cli/handlers/serve.js +5 -3
- package/dist/src/cli/handlers/sessions.js +1 -0
- package/dist/src/cli/handlers/setup.js +432 -1
- package/dist/src/cli/handlers/skill-lint.js +1 -1
- package/dist/src/cli/handlers/subcommands.js +118 -8
- package/dist/src/cli/handlers/use.js +335 -107
- package/dist/src/cli/handlers/workspace.js +3 -1
- package/dist/src/cli/prompt-utils.js +81 -0
- package/dist/src/cli/router.js +16 -1
- package/dist/src/config/aiwg-config.js +42 -0
- package/dist/src/config/cli.js +7 -3
- package/dist/src/config/decision-config.js +14 -1
- package/dist/src/config/gitignore.js +4 -0
- package/dist/src/config/native-sandbox-warnings.js +25 -0
- package/dist/src/config/workspace.js +2 -1
- package/dist/src/contributors/validation.js +6 -5
- package/dist/src/decision/adapters/jev.js +20 -31
- package/dist/src/decision/admission.js +7 -3
- package/dist/src/decision/ask.js +6 -1
- package/dist/src/decision/benchmark.js +482 -0
- package/dist/src/decision/ledger.js +22 -3
- package/dist/src/decision/pricing.js +147 -0
- package/dist/src/decision/qualification/gate-evidence.js +23 -18
- package/dist/src/decision/qualification/load-staged.js +576 -0
- package/dist/src/decision/qualification/load.js +109 -33
- package/dist/src/decision/qualification/runner.js +12 -5
- package/dist/src/decision/review/service.js +6 -4
- package/dist/src/decision/review/validate.js +23 -2
- package/dist/src/decision/savings.js +8 -3
- package/dist/src/discovery/index.js +492 -0
- package/dist/src/discovery/interview.js +238 -0
- package/dist/src/discovery/plan-apply.js +567 -0
- package/dist/src/discovery/plan-store.js +171 -0
- package/dist/src/discovery/plan-types.js +2 -0
- package/dist/src/discovery/plan-validation.js +139 -0
- package/dist/src/discovery/types.js +2 -0
- package/dist/src/effects/host.js +91 -0
- package/dist/src/extensions/commands/definitions.js +49 -9
- package/dist/src/extensions/manifest.js +71 -44
- package/dist/src/extensions/project-local-discovery.js +1 -1
- package/dist/src/extensions/project-local-gitignore.js +2 -0
- package/dist/src/extensions/project-quickref.js +18 -17
- package/dist/src/extensions/validation.js +32 -29
- package/dist/src/housekeeper/daemon-config.js +148 -0
- package/dist/src/housekeeper/ipc.js +84 -0
- package/dist/src/housekeeper/lifecycle.js +148 -0
- package/dist/src/housekeeper/platform.js +35 -0
- package/dist/src/housekeeper/status.js +70 -0
- package/dist/src/housekeeper/units.js +114 -0
- package/dist/src/issues/cli.js +16 -5
- package/dist/src/issues/live.js +44 -12
- package/dist/src/jobs/flow.js +22 -21
- package/dist/src/lint/rule-activation.js +20 -5
- package/dist/src/lint/runner.js +1 -1
- package/dist/src/marketplace/exchange.js +18 -6
- package/dist/src/marketplace/provenance.js +3 -2
- package/dist/src/mcp/adapters/codex-runtime.js +46 -76
- package/dist/src/mcp/cli.mjs +22 -96
- package/dist/src/mcp/config-file.mjs +6 -2
- package/dist/src/mcp/config-layers.mjs +23 -7
- package/dist/src/mcp/grok-build-config.mjs +2 -1
- package/dist/src/mcp/muse-native-config.mjs +2 -1
- package/dist/src/mcp/profiles.js +18 -31
- package/dist/src/mcp/profiles.mjs +18 -32
- package/dist/src/mcp/registry.js +7 -27
- package/dist/src/mcp/registry.mjs +7 -28
- package/dist/src/mcp/server.mjs +34 -1
- package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
- package/dist/src/mcp/tools/command-run.mjs +3 -2
- package/dist/src/mcp/tools/decision.mjs +49 -48
- package/dist/src/mcp/tools/discovery.mjs +46 -21
- package/dist/src/mcp/tools/orchestration.mjs +22 -22
- package/dist/src/mcp/tools/subsystems.mjs +9 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +30 -6
- package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
- package/dist/src/memory/audit.js +719 -0
- package/dist/src/memory/canonical-context.js +392 -13
- package/dist/src/memory/canonical-maintenance.js +95 -0
- package/dist/src/memory/cli-result.js +22 -0
- package/dist/src/memory/cli.js +176 -0
- package/dist/src/memory/context-pack.js +57 -6
- package/dist/src/memory/cost.js +512 -0
- package/dist/src/memory/firewall-classification.d.mts +7 -0
- package/dist/src/memory/firewall-classification.mjs +32 -0
- package/dist/src/memory/index.js +8 -0
- package/dist/src/memory/line-maintenance.js +68 -0
- package/dist/src/memory/maintenance-cli.js +286 -0
- package/dist/src/memory/maintenance-contract.js +136 -0
- package/dist/src/memory/maintenance-index.js +18 -0
- package/dist/src/memory/maintenance-owner.js +2 -0
- package/dist/src/memory/maintenance-record.js +138 -0
- package/dist/src/memory/maintenance.js +254 -0
- package/dist/src/memory/project-registry.js +2 -1
- package/dist/src/memory/provider-memory-adapter.js +154 -0
- package/dist/src/memory/recommend-cli.js +83 -0
- package/dist/src/memory/recommend.js +269 -0
- package/dist/src/memory/scheduled.js +81 -0
- package/dist/src/memory/taxonomy.js +44 -0
- package/dist/src/mission-protocol/codecs.js +19 -9
- package/dist/src/mission-protocol/worker-status.js +91 -1
- package/dist/src/models/config-loader.js +11 -1
- package/dist/src/models/model-capabilities.v1.json +74 -50
- package/dist/src/models/provider-policy.js +125 -62
- package/dist/src/models/resolver.js +45 -8
- package/dist/src/models/worker-installation.d.mts +8 -1
- package/dist/src/models/worker-installation.mjs +231 -38
- package/dist/src/models/wrapper-route.js +1 -1
- package/dist/src/output-modes/registry.js +8 -7
- package/dist/src/packages/adapters/git.js +99 -23
- package/dist/src/packages/adapters/gitea.js +8 -27
- package/dist/src/packages/adapters/github.js +7 -25
- package/dist/src/packages/registry.js +4 -4
- package/dist/src/plugin/metadata-validator.js +1 -1
- package/dist/src/process/cli-command.d.mts +5 -0
- package/dist/src/process/cli-command.mjs +42 -0
- package/dist/src/providers/deploy-version.d.mts +1 -0
- package/dist/src/providers/deploy-version.mjs +17 -0
- package/dist/src/providers/provider-definitions.js +19 -16
- package/dist/src/providers/skill-ownership.d.mts +11 -2
- package/dist/src/providers/skill-ownership.mjs +35 -17
- package/dist/src/rules/activation.d.mts +11 -2
- package/dist/src/rules/activation.mjs +82 -6
- package/dist/src/rules/inventory.js +1 -1
- package/dist/src/rules/rule-frontmatter.schema.json +2 -0
- package/dist/src/schema/zod-validation.d.mts +6 -0
- package/dist/src/schema/zod-validation.mjs +50 -0
- package/dist/src/serve/executor-registry.js +297 -20
- package/dist/src/serve/executor-token.d.mts +1 -0
- package/dist/src/serve/executor-token.mjs +8 -0
- package/dist/src/serve/shared-host-scheduler.js +1102 -31
- package/dist/src/serve/worker-invocation.js +124 -15
- package/dist/src/sessions/adapters/claude.js +19 -18
- package/dist/src/sessions/adapters/codex.js +10 -9
- package/dist/src/sessions/adapters/copilot.js +14 -13
- package/dist/src/sessions/adapters/cursor.js +19 -18
- package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
- package/dist/src/sessions/adapters/factory.js +11 -10
- package/dist/src/sessions/adapters/generic.js +32 -23
- package/dist/src/sessions/adapters/grokbot.js +35 -35
- package/dist/src/sessions/adapters/hermes.js +20 -19
- package/dist/src/sessions/adapters/muse.js +50 -49
- package/dist/src/sessions/adapters/omp.js +5 -4
- package/dist/src/sessions/adapters/openclaw.js +30 -29
- package/dist/src/sessions/adapters/opencode.js +26 -26
- package/dist/src/sessions/adapters/openhuman.js +24 -23
- package/dist/src/sessions/adapters/pi.js +5 -4
- package/dist/src/sessions/adapters/windsurf.js +8 -8
- package/dist/src/sessions/analytics.js +10 -9
- package/dist/src/sessions/candidates.js +7 -6
- package/dist/src/sessions/contracts.js +63 -53
- package/dist/src/sessions/output-registration.js +11 -10
- package/dist/src/sessions/workspace-discovery.js +3 -4
- package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +46 -10
- package/dist/src/smiths/context-pipeline/context-file-safety.js +330 -9
- package/dist/src/smiths/context-pipeline/finalization.js +3 -2
- package/dist/src/smiths/context-pipeline/generator.js +7 -19
- package/dist/src/smiths/context-pipeline/legacy-inject.js +3 -10
- package/dist/src/smiths/context-pipeline/managed-hook.js +5 -5
- package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
- package/dist/src/smiths/context-pipeline/workspace-context.js +110 -22
- package/dist/src/tracker/project-inputs.js +2 -0
- package/dist/src/update/checker.d.mts +4 -0
- package/dist/src/update/checker.mjs +14 -0
- package/dist/src/update/notifier.mjs +2 -4
- package/dist/src/writing/exemplar-selection.js +6 -6
- package/dist/src/writing/voice-evaluation.js +24 -23
- package/dist/src/writing/writer-migration.js +14 -13
- package/dist/src/writing/writer-profile.js +19 -18
- package/dist/src/writing/writing-brief.js +18 -17
- package/dist/src/writing/writing-receipt.js +47 -46
- package/package.json +5 -2
- package/schemas/decision/DecisionReview.schema.json +78 -1
- package/schemas/mission-v1.schema.json +3 -0
- package/tools/agents/deploy-agents.mjs +67 -39
- package/tools/agents/providers/antigravity.mjs +6 -1
- package/tools/agents/providers/base.mjs +24 -14
- package/tools/agents/providers/claude.mjs +6 -3
- package/tools/agents/providers/codex.mjs +54 -57
- package/tools/agents/providers/context-write.mjs +28 -0
- package/tools/agents/providers/copilot.mjs +13 -4
- package/tools/agents/providers/cursor.mjs +1 -1
- package/tools/agents/providers/deepseek-harness.mjs +1 -1
- package/tools/agents/providers/factory.mjs +7 -1
- package/tools/agents/providers/grok-build.mjs +18 -2
- package/tools/agents/providers/grokbot.mjs +1 -1
- package/tools/agents/providers/hermes.mjs +12 -15
- package/tools/agents/providers/muse-hooks.mjs +21 -14
- package/tools/agents/providers/muse.mjs +7 -2
- package/tools/agents/providers/omp.mjs +31 -5
- package/tools/agents/providers/opencode.mjs +14 -5
- package/tools/agents/providers/openhuman.mjs +1 -1
- package/tools/agents/providers/pi.mjs +1 -1
- package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
- package/tools/agents/providers/rule-delivery.mjs +289 -80
- package/tools/agents/providers/warp.mjs +4 -1
- package/tools/agents/providers/windsurf.mjs +13 -3
- package/tools/cli/workspace-status.mjs +5 -0
- package/tools/commands/deploy-prompts-codex.mjs +11 -8
- package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +26 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +7 -1
- package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
- package/tools/ralph-external/lib/recovery-probe.mjs +14 -4
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
- package/tools/ralph-external/process-monitor.mjs +49 -8
- package/tools/ralph-external/session-launcher.mjs +405 -35
- package/tools/skills/deploy-skills-codex.mjs +11 -7
- package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { lstat, open } from 'node:fs/promises';
|
|
3
|
+
import { isInteractive } from '../cli/env.js';
|
|
4
|
+
import { askMultilineSecret, askString, createSecretPromptInterface } from '../cli/prompt-utils.js';
|
|
5
|
+
import { createSecretStore } from './credential-store.js';
|
|
6
|
+
/** Named raw values share the native store used by auth login, in a separate service. */
|
|
7
|
+
export const SENSITIVE_VALUE_SERVICE = 'aiwg.sensitive-values';
|
|
8
|
+
export function namedSensitiveStore(name) {
|
|
9
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/.test(name)) {
|
|
10
|
+
throw new Error('Sensitive value store name must contain only letters, digits, dots, underscores or hyphens (1–128 characters).');
|
|
11
|
+
}
|
|
12
|
+
return createSecretStore({ service: SENSITIVE_VALUE_SERVICE, account: name });
|
|
13
|
+
}
|
|
14
|
+
/** Extract references, never literal values, from the standard command options. */
|
|
15
|
+
export function sensitiveInputOptions(args, prefix = 'value') {
|
|
16
|
+
const result = { prefix };
|
|
17
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
18
|
+
const token = args[index];
|
|
19
|
+
if (token === '--')
|
|
20
|
+
break;
|
|
21
|
+
for (const source of ['file', 'store', 'env']) {
|
|
22
|
+
const flag = `--${prefix}-${source}`;
|
|
23
|
+
if (token !== flag && !token.startsWith(`${flag}=`))
|
|
24
|
+
continue;
|
|
25
|
+
const value = token === flag ? args[++index] : token.slice(flag.length + 1);
|
|
26
|
+
if (!value || value.startsWith('--'))
|
|
27
|
+
throw new Error(`${flag} requires a value`);
|
|
28
|
+
if (result[source] !== undefined)
|
|
29
|
+
throw new Error(`${flag} may only be given once`);
|
|
30
|
+
result[source] = value;
|
|
31
|
+
}
|
|
32
|
+
if (token === `--${prefix}-stdin`)
|
|
33
|
+
result.stdin = true;
|
|
34
|
+
if (token === `--${prefix}-interactive`)
|
|
35
|
+
result.interactive = true;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/** Extracted from MCP profile login: validate the opened descriptor, never a later path read. */
|
|
40
|
+
export async function readPrivateValueFile(filePath, flag = '--value-file') {
|
|
41
|
+
if (process.platform === 'win32')
|
|
42
|
+
throw new Error(`${flag}: private-file input requires native ACL validation on Windows; use stdin or the OS store.`);
|
|
43
|
+
try {
|
|
44
|
+
const pre = await lstat(filePath);
|
|
45
|
+
if (pre.isSymbolicLink())
|
|
46
|
+
throw new Error('file is a symlink; refusing to follow it');
|
|
47
|
+
// Reject FIFOs/devices before open, which could otherwise wait indefinitely.
|
|
48
|
+
if (!pre.isFile())
|
|
49
|
+
throw new Error('not a regular file');
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const code = error.code;
|
|
53
|
+
throw new Error(`${flag}: ${code === 'ENOENT' ? 'file does not exist' : code ? 'cannot stat private file' : error.message}.`);
|
|
54
|
+
}
|
|
55
|
+
let handle;
|
|
56
|
+
try {
|
|
57
|
+
handle = await open(filePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
throw new Error(`${flag}: cannot open private file (symlinks are refused).`);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const stat = await handle.stat();
|
|
64
|
+
if (!stat.isFile())
|
|
65
|
+
throw new Error(`${flag}: not a regular file.`);
|
|
66
|
+
if (stat.nlink !== 1)
|
|
67
|
+
throw new Error(`${flag}: more than one hard link; refusing to read it.`);
|
|
68
|
+
if (typeof process.getuid === 'function' && stat.uid !== process.getuid()) {
|
|
69
|
+
throw new Error(`${flag}: file is not owned by the current user.`);
|
|
70
|
+
}
|
|
71
|
+
if ((stat.mode & 0o077) !== 0)
|
|
72
|
+
throw new Error(`${flag}: file must not allow group or other access (chmod 600).`);
|
|
73
|
+
return (await handle.readFile({ encoding: 'utf8' })).trim();
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
await handle.close();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function readStdin() {
|
|
80
|
+
const chunks = [];
|
|
81
|
+
for await (const chunk of process.stdin)
|
|
82
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
83
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Explicit entry, stdin, private file, native-store reference, named shell variable.
|
|
87
|
+
* No implicit stdin consumption, env discovery or store probing. An empty selected
|
|
88
|
+
* source is an error, never permission to try a less preferred source.
|
|
89
|
+
*/
|
|
90
|
+
export async function resolveSensitiveInput(options = {}, dependencies = {}) {
|
|
91
|
+
const prefix = options.prefix ?? 'value';
|
|
92
|
+
const terminal = dependencies.isTTY ?? isInteractive();
|
|
93
|
+
const choices = `--${prefix}-interactive, --${prefix}-stdin, --${prefix}-file <path>, --${prefix}-store <name>, or --${prefix}-env <name>`;
|
|
94
|
+
const explicitSource = options.stdin || options.file !== undefined || options.store !== undefined || options.env !== undefined;
|
|
95
|
+
let value;
|
|
96
|
+
let source;
|
|
97
|
+
if (options.interactive || (!explicitSource && terminal)) {
|
|
98
|
+
if (!terminal)
|
|
99
|
+
throw new Error(`An interactive terminal is required; supply ${choices}.`);
|
|
100
|
+
source = `--${prefix}-interactive`;
|
|
101
|
+
if (dependencies.prompt)
|
|
102
|
+
value = await dependencies.prompt(prefix);
|
|
103
|
+
else {
|
|
104
|
+
const rl = createSecretPromptInterface();
|
|
105
|
+
try {
|
|
106
|
+
process.stderr.write(`Enter ${prefix} (hidden${options.multiline ? '; finish with an empty line' : ''}): `);
|
|
107
|
+
value = options.multiline ? await askMultilineSecret(rl, options.signal) : await askString(rl, '', '', options.signal);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
rl.close();
|
|
111
|
+
process.stderr.write('\n');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else if (options.stdin) {
|
|
116
|
+
source = `--${prefix}-stdin`;
|
|
117
|
+
if (dependencies.stdinIsTTY ?? dependencies.isTTY ?? Boolean(process.stdin.isTTY))
|
|
118
|
+
throw new Error(`${source} requires piped input, not a terminal.`);
|
|
119
|
+
value = await (dependencies.readStdin ?? readStdin)();
|
|
120
|
+
}
|
|
121
|
+
else if (options.file !== undefined) {
|
|
122
|
+
source = `--${prefix}-file`;
|
|
123
|
+
value = await (dependencies.readFile ? dependencies.readFile(options.file) : readPrivateValueFile(options.file, source));
|
|
124
|
+
}
|
|
125
|
+
else if (options.store !== undefined) {
|
|
126
|
+
source = `--${prefix}-store`;
|
|
127
|
+
try {
|
|
128
|
+
value = await (dependencies.readStore ? dependencies.readStore(options.store) : namedSensitiveStore(options.store).loadSecret());
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
throw new Error(`${source}: native store entry could not be read.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else if (options.env !== undefined) {
|
|
135
|
+
source = `--${prefix}-env`;
|
|
136
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(options.env))
|
|
137
|
+
throw new Error(`${source} requires a shell variable name.`);
|
|
138
|
+
value = dependencies.readEnv ? dependencies.readEnv(options.env) : (dependencies.environment ?? process.env)[options.env];
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
throw new Error(`A sensitive value requires an interactive terminal, or a key supplied via ${choices}.`);
|
|
142
|
+
}
|
|
143
|
+
const trimmed = value?.trim();
|
|
144
|
+
if (!trimmed)
|
|
145
|
+
throw new Error(`${source} received no key (input is empty or not set${options.env && source.endsWith('-env') ? `: ${options.env}` : ''}).`);
|
|
146
|
+
const controls = options.multiline ? /[\u0000-\u0009\u000b\u000c\u000e-\u001f\u007f]/ : /[\u0000-\u001f\u007f]/;
|
|
147
|
+
if (trimmed.length > 16384 || controls.test(trimmed))
|
|
148
|
+
throw new Error(`${source} requires ${options.multiline ? 'non-empty text without control characters' : 'one non-empty line'} (at most 16384 characters).`);
|
|
149
|
+
return trimmed;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=sensitive-input.js.map
|
|
@@ -18,6 +18,7 @@ import { spawn } from 'child_process';
|
|
|
18
18
|
import os from 'os';
|
|
19
19
|
import { resolveUserConfigDir } from '../config/user-config-dir.mjs';
|
|
20
20
|
import { boundedExecFileSync } from '../process/bounded-child-process.mjs';
|
|
21
|
+
import { helperEnvironment } from '../process/cli-command.mjs';
|
|
21
22
|
import {
|
|
22
23
|
assertCanonicalInstallation,
|
|
23
24
|
createInstallationIdentity,
|
|
@@ -594,10 +595,12 @@ export async function getVersionInfo() {
|
|
|
594
595
|
try {
|
|
595
596
|
const gitHash = boundedExecFileSync('git', ['rev-parse', '--short', 'HEAD'], 'quick', {
|
|
596
597
|
cwd: config.edgePath,
|
|
598
|
+
env: helperEnvironment(),
|
|
597
599
|
encoding: 'utf8',
|
|
598
600
|
}).trim();
|
|
599
601
|
const gitBranch = boundedExecFileSync('git', ['branch', '--show-current'], 'quick', {
|
|
600
602
|
cwd: config.edgePath,
|
|
603
|
+
env: helperEnvironment(),
|
|
601
604
|
encoding: 'utf8',
|
|
602
605
|
}).trim();
|
|
603
606
|
info.edgePath = config.edgePath;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* @issue #1253
|
|
11
11
|
*/
|
|
12
12
|
import { fetchAgentCard } from '../../a2a/agent-card.js';
|
|
13
|
+
import { resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
|
|
13
14
|
import { loadJwkSet } from '../../a2a/jws.js';
|
|
14
15
|
import { AiwgError, EXIT_CODES, handlerResultFromError } from '../errors.js';
|
|
15
16
|
function parseVerifyArgs(args) {
|
|
@@ -39,6 +40,9 @@ function parseVerifyArgs(args) {
|
|
|
39
40
|
}
|
|
40
41
|
const jwks = get('--jwks');
|
|
41
42
|
const bearer = get('--bearer');
|
|
43
|
+
if (args.includes('--bearer') && (!bearer || bearer.startsWith('--'))) {
|
|
44
|
+
throw new AiwgError({ code: 'ERR_AGENTCARD_BEARER', message: '--bearer requires a value; prefer --bearer-stdin, --bearer-file, --bearer-store or --bearer-env.', exitCode: EXIT_CODES.USAGE });
|
|
45
|
+
}
|
|
42
46
|
const skipVerify = args.includes('--skip-verify');
|
|
43
47
|
const json = args.includes('--json');
|
|
44
48
|
if (!jwks && !skipVerify) {
|
|
@@ -73,36 +77,49 @@ async function loadJwksFromSource(source) {
|
|
|
73
77
|
}
|
|
74
78
|
async function handleVerify(args) {
|
|
75
79
|
const parsed = parseVerifyArgs(args);
|
|
80
|
+
const sources = sensitiveInputOptions(args, 'bearer');
|
|
81
|
+
const hasSource = sources.interactive || sources.stdin || sources.file !== undefined || sources.store !== undefined || sources.env !== undefined;
|
|
82
|
+
if (parsed.bearer !== undefined) {
|
|
83
|
+
console.error('Warning: --bearer is deprecated and exposes the value on argv; use --bearer-interactive, --bearer-stdin, --bearer-file, --bearer-store or --bearer-env.');
|
|
84
|
+
}
|
|
85
|
+
// No source intentionally means public/unauthenticated access, even at a TTY.
|
|
86
|
+
const bearer = hasSource
|
|
87
|
+
? await resolveSensitiveInput(sources)
|
|
88
|
+
: parsed.bearer === undefined ? undefined : await resolveSensitiveInput({ prefix: 'bearer', env: 'LEGACY_BEARER' }, { readEnv: () => parsed.bearer });
|
|
89
|
+
const redact = (text) => bearer ? text.split(bearer).join('[REDACTED]') : text;
|
|
90
|
+
const log = (text) => console.log(redact(text));
|
|
91
|
+
const error = (text) => console.error(redact(text));
|
|
92
|
+
const jsonReplacer = (_key, value) => typeof value === 'string' ? redact(value) : value;
|
|
76
93
|
const opts = {
|
|
77
94
|
skipVerify: parsed.skipVerify,
|
|
78
95
|
};
|
|
79
|
-
if (
|
|
80
|
-
opts.bearer =
|
|
81
|
-
if (parsed.jwks !== undefined && !parsed.skipVerify) {
|
|
82
|
-
opts.jwks = await loadJwksFromSource(parsed.jwks);
|
|
83
|
-
}
|
|
96
|
+
if (bearer !== undefined)
|
|
97
|
+
opts.bearer = bearer;
|
|
84
98
|
let verified;
|
|
85
99
|
try {
|
|
100
|
+
if (parsed.jwks !== undefined && !parsed.skipVerify) {
|
|
101
|
+
opts.jwks = await loadJwksFromSource(parsed.jwks);
|
|
102
|
+
}
|
|
86
103
|
verified = await fetchAgentCard(parsed.host, parsed.instance, opts);
|
|
87
104
|
}
|
|
88
105
|
catch (err) {
|
|
89
106
|
const message = err.message;
|
|
90
107
|
if (parsed.json) {
|
|
91
|
-
|
|
108
|
+
log(JSON.stringify({
|
|
92
109
|
ok: false,
|
|
93
110
|
host: parsed.host,
|
|
94
111
|
instance: parsed.instance,
|
|
95
112
|
error: message,
|
|
96
|
-
},
|
|
113
|
+
}, jsonReplacer, 2));
|
|
97
114
|
}
|
|
98
115
|
else {
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
error(`AgentCard verification FAILED for ${parsed.host}/${parsed.instance}`);
|
|
117
|
+
error(` ${message}`);
|
|
101
118
|
}
|
|
102
119
|
return { exitCode: EXIT_CODES.GENERAL };
|
|
103
120
|
}
|
|
104
121
|
if (parsed.json) {
|
|
105
|
-
|
|
122
|
+
log(JSON.stringify({
|
|
106
123
|
ok: true,
|
|
107
124
|
host: parsed.host,
|
|
108
125
|
instance: parsed.instance,
|
|
@@ -118,38 +135,38 @@ async function handleVerify(args) {
|
|
|
118
135
|
capabilities: verified.card.capabilities,
|
|
119
136
|
skills: verified.card.skills,
|
|
120
137
|
},
|
|
121
|
-
},
|
|
138
|
+
}, jsonReplacer, 2));
|
|
122
139
|
}
|
|
123
140
|
else {
|
|
124
141
|
const banner = parsed.skipVerify ? '(verification SKIPPED)' : 'VERIFIED';
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
142
|
+
log(`AgentCard ${banner} for ${parsed.host}/${parsed.instance}`);
|
|
143
|
+
log(` name: ${verified.card.name}`);
|
|
144
|
+
log(` protocolVersion: ${verified.card.protocolVersion}`);
|
|
145
|
+
log(` url: ${verified.card.url}`);
|
|
146
|
+
log(` version: ${verified.card.version}`);
|
|
130
147
|
if (verified.card.preferredTransport) {
|
|
131
|
-
|
|
148
|
+
log(` preferredTransport: ${verified.card.preferredTransport}`);
|
|
132
149
|
}
|
|
133
150
|
if (verified.kid) {
|
|
134
|
-
|
|
151
|
+
log(` signing kid: ${verified.kid}`);
|
|
135
152
|
}
|
|
136
|
-
|
|
153
|
+
log(` verifiedAt: ${verified.verifiedAt}`);
|
|
137
154
|
const exts = verified.card.capabilities?.extensions ?? [];
|
|
138
155
|
if (exts.length > 0) {
|
|
139
|
-
|
|
156
|
+
log(` extensions:`);
|
|
140
157
|
for (const e of exts) {
|
|
141
158
|
const tag = e.required ? '[required]' : '[optional]';
|
|
142
|
-
|
|
159
|
+
log(` ${tag} ${e.uri}`);
|
|
143
160
|
}
|
|
144
161
|
}
|
|
145
162
|
const skills = verified.card.skills ?? [];
|
|
146
163
|
if (skills.length > 0) {
|
|
147
|
-
|
|
164
|
+
log(` skills (${skills.length}):`);
|
|
148
165
|
for (const s of skills.slice(0, 5)) {
|
|
149
|
-
|
|
166
|
+
log(` - ${s.id}${s.name ? ' (' + s.name + ')' : ''}`);
|
|
150
167
|
}
|
|
151
168
|
if (skills.length > 5)
|
|
152
|
-
|
|
169
|
+
log(` ... and ${skills.length - 5} more`);
|
|
153
170
|
}
|
|
154
171
|
}
|
|
155
172
|
return { exitCode: 0 };
|
|
@@ -164,7 +181,12 @@ function printUsage() {
|
|
|
164
181
|
console.log(' --host <url> Executor host (e.g. https://exec.test)');
|
|
165
182
|
console.log(' --instance <id> Instance id (UUIDv7)');
|
|
166
183
|
console.log(' --jwks <path|url> JWKS file path or URL (required unless --skip-verify)');
|
|
167
|
-
console.log(' --bearer
|
|
184
|
+
console.log(' --bearer-interactive Read optional bearer in a terminal without echo');
|
|
185
|
+
console.log(' --bearer-stdin Read optional bearer from piped stdin');
|
|
186
|
+
console.log(' --bearer-file <path> Read optional bearer from an owner-only private file');
|
|
187
|
+
console.log(' --bearer-store <name> Read optional bearer from a named OS store entry');
|
|
188
|
+
console.log(' --bearer-env <NAME> Read optional bearer from a named shell variable');
|
|
189
|
+
console.log(' --bearer <token> Deprecated: exposes the value on argv');
|
|
168
190
|
console.log(' --skip-verify Skip JWS verification (NOT recommended)');
|
|
169
191
|
console.log(' --json Emit JSON output');
|
|
170
192
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { namedSensitiveStore, resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
|
|
1
2
|
import { AuthClient, defaultBrowserOpener } from "../../auth/client.js";
|
|
2
3
|
import { authConfigFromEnvironment } from "../../auth/config.js";
|
|
3
4
|
import { createCredentialStore } from "../../auth/credential-store.js";
|
|
@@ -5,6 +6,8 @@ function usage() {
|
|
|
5
6
|
return [
|
|
6
7
|
"Usage:",
|
|
7
8
|
" aiwg auth login [--device] [--device-label <label>] [--store native|file] [--allow-file-store]",
|
|
9
|
+
" aiwg auth secret set <name> [--value-interactive | --value-stdin | --value-file <path> | --value-store <name> | --value-env <name>]",
|
|
10
|
+
" aiwg auth secret delete <name>",
|
|
8
11
|
" aiwg auth status [--json] [--store native|file] [--allow-file-store]",
|
|
9
12
|
" aiwg auth logout [--all] [--store native|file] [--allow-file-store]",
|
|
10
13
|
"",
|
|
@@ -46,9 +49,25 @@ export function createAuthHandler(dependencies = {}) {
|
|
|
46
49
|
return { exitCode: 0 };
|
|
47
50
|
}
|
|
48
51
|
const [subcommand, ...args] = ctx.args;
|
|
49
|
-
if (!["login", "status", "logout"].includes(subcommand))
|
|
52
|
+
if (!["login", "status", "logout", "secret"].includes(subcommand))
|
|
50
53
|
return { exitCode: 2, message: usage() };
|
|
51
54
|
try {
|
|
55
|
+
if (subcommand === "secret") {
|
|
56
|
+
const [operation, name, ...inputArgs] = args;
|
|
57
|
+
if (!["set", "delete"].includes(operation) || !name || name.startsWith('--'))
|
|
58
|
+
return { exitCode: 2, message: usage() };
|
|
59
|
+
const store = (dependencies.secretStore ?? namedSensitiveStore)(name);
|
|
60
|
+
if (operation === "delete")
|
|
61
|
+
await store.deleteSecret();
|
|
62
|
+
else {
|
|
63
|
+
const secret = await resolveSensitiveInput({ ...sensitiveInputOptions(inputArgs), signal: ctx.signal }, {
|
|
64
|
+
environment: dependencies.env, ...dependencies.sensitiveInput,
|
|
65
|
+
});
|
|
66
|
+
await store.saveSecret(secret);
|
|
67
|
+
}
|
|
68
|
+
console.log(operation === "delete" ? "Named sensitive value removed." : "Named sensitive value stored.");
|
|
69
|
+
return { exitCode: 0 };
|
|
70
|
+
}
|
|
52
71
|
const storeMode = value(args, "--store") || "native";
|
|
53
72
|
if (!["native", "file"].includes(storeMode))
|
|
54
73
|
return { exitCode: 2, message: "--store must be native or file" };
|
|
@@ -119,7 +138,8 @@ export function createAuthHandler(dependencies = {}) {
|
|
|
119
138
|
return { exitCode: 0 };
|
|
120
139
|
}
|
|
121
140
|
catch (error) {
|
|
122
|
-
return { exitCode: classify(error), message: error instanceof Error ? error.message :
|
|
141
|
+
return { exitCode: classify(error), message: subcommand === 'secret' && !/^(--value-|A sensitive value|An interactive terminal|Sensitive value store name)/.test(error instanceof Error ? error.message : '')
|
|
142
|
+
? 'Native sensitive value store operation failed.' : error instanceof Error ? error.message : String(error) };
|
|
123
143
|
}
|
|
124
144
|
},
|
|
125
145
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
|
|
2
|
+
import { decisionPricing } from '../../decision/pricing.js';
|
|
1
3
|
import { ATTRIBUTION_FIELD_PATTERN, DecisionAskUsageError, decisionCapabilities, DecisionLedgerSinceError, decisionLedgerHistory, decisionLedgerStats, evaluateRequestPath, listPatterns, livePlan, MAX_ATTRIBUTION_FIELD_LENGTH, materializeSyntheticClassificationSetup, parseDecisionLedgerSince, readDecisionContextFile, runDecisionOffloadCheckpoint, runOfflinePattern, setupJev, showPattern, syntheticClassificationSetup, validateDecisionInput, } from '../../decision/driver.js';
|
|
2
4
|
function jsonResult(value, exitCode = 0) {
|
|
3
5
|
return { exitCode, message: JSON.stringify(value, null, 2), rawOutput: true };
|
|
4
6
|
}
|
|
5
7
|
function usage() {
|
|
6
8
|
return [
|
|
7
|
-
'Usage: aiwg decision <capabilities|status|patterns|validate|evaluate|setup|history|stats> [options]',
|
|
9
|
+
'Usage: aiwg decision <capabilities|status|patterns|validate|evaluate|setup|history|stats|pricing> [options]',
|
|
8
10
|
' aiwg decision ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--context <text> | --context-file <path> | --context-stdin] [--threshold 0.8] [--timeout-ms 15000] [--passes N] [--escalation-passes N] [--provider <id>] [--session <id>] [--caller <tag>] [--record-text] [--json]',
|
|
9
11
|
'',
|
|
10
12
|
'Commands:',
|
|
@@ -16,9 +18,10 @@ function usage() {
|
|
|
16
18
|
' validate <request|definition|ruleset|binding> <path>',
|
|
17
19
|
' evaluate --request <path> [--host-policy-module <path>]',
|
|
18
20
|
' setup synthetic-classification [--output-dir <dir>]',
|
|
19
|
-
' setup jev [--token-stdin] [--region <r>] [--endpoint <url>] [--verify] [--remove]',
|
|
21
|
+
' setup jev [--token-interactive | --token-stdin | --token-file <path> | --token-store <name> | --token-env <name>] [--region <r>] [--endpoint <url>] [--verify] [--remove]',
|
|
20
22
|
' ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--provider <id>] [--session <id>] [--caller <tag>] [--record-text]',
|
|
21
23
|
' history [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--json]',
|
|
24
|
+
' pricing [--refresh --model jev-X.Y.Z] [--dry-run] [--offline | --allow-snapshot] [--json]',
|
|
22
25
|
' stats [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--group-by provider|session|kind|caller|passes|escalation] [--json]',
|
|
23
26
|
'',
|
|
24
27
|
'Notes:',
|
|
@@ -99,7 +102,7 @@ function takeAttributionOption(args, name, reason) {
|
|
|
99
102
|
return value;
|
|
100
103
|
}
|
|
101
104
|
async function decisionSetupJev(rest) {
|
|
102
|
-
const token = rest.includes('--
|
|
105
|
+
const token = rest.includes('--remove') ? undefined : await resolveSensitiveInput(sensitiveInputOptions(rest, 'token'));
|
|
103
106
|
const result = await setupJev({
|
|
104
107
|
token,
|
|
105
108
|
region: takeOption(rest, '--region'),
|
|
@@ -314,6 +317,7 @@ async function decisionStats(ctx) {
|
|
|
314
317
|
` jev usage: input=${group.jevUsage.inputTokens} output=${group.jevUsage.outputTokens}`,
|
|
315
318
|
` tokens per answered decision=${group.tokensPerAnsweredDecision?.toFixed(2) ?? '-'}`,
|
|
316
319
|
` llm_tokens_avoided=${group.llm_tokens_avoided} jev_tokens=${group.jev_tokens} cost_weighted_net_usd=${group.cost_weighted_net_usd.toFixed(6)}`,
|
|
320
|
+
...group.ratesUsed.map(rate => ` rates used (${rate.calls} calls): ${JSON.stringify(rate.method)} source=${rate.method.source ?? 'manual'} checked_at=${rate.method.checked_at ?? 'unknown'}`),
|
|
317
321
|
` v1 comparison only: estimated LLM tokens avoided=${group.estimatedLlmTokensAvoidedTotal} net savings=${group.netSavingsTokens}`,
|
|
318
322
|
...(group.legacyReestimatedCalls ? [` v1 records re-estimated=${group.legacyReestimatedCalls} weights=${JSON.stringify(result.legacyEstimationWeights)}`] : []),
|
|
319
323
|
]);
|
|
@@ -331,6 +335,21 @@ async function executeDecision(ctx) {
|
|
|
331
335
|
return await decisionAsk(ctx);
|
|
332
336
|
if (command === 'history')
|
|
333
337
|
return await decisionHistory(ctx);
|
|
338
|
+
if (command === 'pricing') {
|
|
339
|
+
const args = ctx.args.slice(1);
|
|
340
|
+
assertLedgerArgs(args, ['--model'], ['--refresh', '--dry-run', '--offline', '--allow-snapshot', '--json']);
|
|
341
|
+
const result = await decisionPricing({ cwd: ctx.cwd, refresh: args.includes('--refresh'), dryRun: args.includes('--dry-run'),
|
|
342
|
+
offline: args.includes('--offline'), allowSnapshot: args.includes('--allow-snapshot'), model: args.includes('--model') ? takeRequiredOption(args, '--model') : undefined });
|
|
343
|
+
if (args.includes('--json'))
|
|
344
|
+
return jsonResult(result);
|
|
345
|
+
return { exitCode: 0, rawOutput: true, message: [
|
|
346
|
+
`decision.ask.cost: ${JSON.stringify(result.current)}`,
|
|
347
|
+
`Source URL: ${result.sourceUrl}`,
|
|
348
|
+
...('snapshotDate' in result && result.snapshotDate ? [`Bundled snapshot dated ${result.snapshotDate}`] : []),
|
|
349
|
+
...('warning' in result && result.warning ? [`Warning: ${result.warning}`] : []),
|
|
350
|
+
...('diff' in result ? [`${result.written ? 'Written' : 'Dry run; config unchanged'}: ${JSON.stringify(result.diff)}`] : []),
|
|
351
|
+
].join('\n') };
|
|
352
|
+
}
|
|
334
353
|
if (command === 'stats')
|
|
335
354
|
return await decisionStats(ctx);
|
|
336
355
|
if (command === 'patterns') {
|
|
@@ -19,10 +19,8 @@
|
|
|
19
19
|
* @see docs/contracts/effect-ledger.v1.md
|
|
20
20
|
*/
|
|
21
21
|
import { readFile } from 'node:fs/promises';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { readAiwgConfig } from '../../config/aiwg-config.js';
|
|
25
|
-
import { CORE_EFFECT_KINDS, DEFAULT_LEDGER_KEY_SERVICE, EFFECT_EXIT_CODES, EFFECT_SUBSYSTEMS, EffectLedgerError, LEDGER_TEST_KEY_ENV, LedgerSigningKey, activeKey, containsRestrictedMaterial, createBuiltinVerifierRegistry, createTrackerVerifiers, credentialStoreKeyProvider, effectId as deriveEffectId, effectOutputJson, environmentTestKeyProvider, generateLedgerKeySecret, initLedgerKeyring, inspectLedgerLocks, isValidEffectId, ledgerLockRecoveryVerifier, lookupEffect, openEffectLedger, payloadDigest, readLedgerKeyring, reconcileEffect, recordIntent, recordOutcome, recordReconciled, recoverStaleLedgerLock, rotateKey, runVerifier, staticKeyProvider, verifyDecisionLinks, verifyLedger, writeCheckpoint, } from '../../effects/index.js';
|
|
22
|
+
import { resolve } from 'node:path';
|
|
23
|
+
import { CORE_EFFECT_KINDS, EFFECT_EXIT_CODES, EFFECT_SUBSYSTEMS, EffectLedgerError, LedgerSigningKey, activeKey, containsRestrictedMaterial, createBuiltinVerifierRegistry, createTrackerVerifiers, effectId as deriveEffectId, effectOutputJson, generateLedgerKeySecret, initLedgerKeyring, inspectLedgerLocks, isValidEffectId, ledgerLockRecoveryVerifier, lookupEffect, payloadDigest, readLedgerKeyring, reconcileEffect, recordIntent, recordOutcome, recordReconciled, recoverStaleLedgerLock, rotateKey, runVerifier, staticKeyProvider, verifyDecisionLinks, verifyLedger, writeCheckpoint, } from '../../effects/index.js';
|
|
26
24
|
import { parseLedgerPrivateKey } from '../../effects/keys.js';
|
|
27
25
|
import { JsonlOperatorDecisionStore, verifyDecisionChain } from '../../audit/operator-decision.js';
|
|
28
26
|
import { readConfig, readGitRemoteUrls } from '../../tracker/project-inputs.js';
|
|
@@ -166,77 +164,7 @@ function keyValue(entry, flag) {
|
|
|
166
164
|
throw usage(`--${flag} expects key=value`, 'invalid-key-value');
|
|
167
165
|
return [entry.slice(0, eq), entry.slice(eq + 1)];
|
|
168
166
|
}
|
|
169
|
-
|
|
170
|
-
function defaultProject(projectDir) {
|
|
171
|
-
const cleaned = basename(resolve(projectDir)).replace(/[^A-Za-z0-9._:/@-]/g, '-').replace(/^[^A-Za-z0-9]+/, '');
|
|
172
|
-
return cleaned && IDENTIFIER.test(cleaned) ? cleaned : 'project';
|
|
173
|
-
}
|
|
174
|
-
async function hostConfig(projectDir) {
|
|
175
|
-
let config;
|
|
176
|
-
try {
|
|
177
|
-
config = await readAiwgConfig(projectDir);
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
throw new EffectLedgerError('usage', 'aiwg.config could not be read', 'config-unreadable');
|
|
181
|
-
}
|
|
182
|
-
const effects = config?.effects;
|
|
183
|
-
if (effects === undefined || effects === null)
|
|
184
|
-
return {};
|
|
185
|
-
if (typeof effects !== 'object' || Array.isArray(effects))
|
|
186
|
-
throw usage('aiwg.config effects must be an object', 'config-invalid');
|
|
187
|
-
return effects;
|
|
188
|
-
}
|
|
189
|
-
function testContext(env) {
|
|
190
|
-
return env.VITEST === 'true' || env.NODE_ENV === 'test' || env.CI === 'true' || env.CI === '1';
|
|
191
|
-
}
|
|
192
|
-
function keyStore(session, role) {
|
|
193
|
-
const { deps, config, account } = session;
|
|
194
|
-
if (deps.keyStore)
|
|
195
|
-
return deps.keyStore(role, account);
|
|
196
|
-
if (session.env[LEDGER_TEST_KEY_ENV] && testContext(session.env))
|
|
197
|
-
return null;
|
|
198
|
-
const provider = config.keyProvider ?? {};
|
|
199
|
-
try {
|
|
200
|
-
if (provider.type === 'file') {
|
|
201
|
-
if (!provider.path)
|
|
202
|
-
throw new Error('missing path');
|
|
203
|
-
const pathname = resolve(session.projectDir, provider.path);
|
|
204
|
-
return createSecretStore({ useFile: true, allowFile: true, pathname: role === 'next' ? `${pathname}.next` : pathname, service: DEFAULT_LEDGER_KEY_SERVICE, account });
|
|
205
|
-
}
|
|
206
|
-
if (provider.type !== undefined && provider.type !== 'credential-store')
|
|
207
|
-
throw new Error('unknown provider');
|
|
208
|
-
return createSecretStore({ service: provider.service ?? DEFAULT_LEDGER_KEY_SERVICE, account: role === 'next' ? `${account}.next` : account });
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
throw new EffectLedgerError('key-unavailable', 'Effect ledger key provider is not configured correctly on this host', 'key-provider-invalid');
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function keyProvider(session) {
|
|
215
|
-
const store = keyStore(session, 'current');
|
|
216
|
-
if (!store)
|
|
217
|
-
return environmentTestKeyProvider(session.env);
|
|
218
|
-
return credentialStoreKeyProvider({ account: session.account, store });
|
|
219
|
-
}
|
|
220
|
-
function describeKeyProvider(session) {
|
|
221
|
-
if (session.deps.keyStore)
|
|
222
|
-
return { type: 'injected', account: session.account };
|
|
223
|
-
if (session.env[LEDGER_TEST_KEY_ENV] && testContext(session.env))
|
|
224
|
-
return { type: 'environment-test-key' };
|
|
225
|
-
const provider = session.config.keyProvider ?? {};
|
|
226
|
-
if (provider.type === 'file')
|
|
227
|
-
return { type: 'file', account: session.account };
|
|
228
|
-
return { type: 'credential-store', service: provider.service ?? DEFAULT_LEDGER_KEY_SERVICE, account: session.account };
|
|
229
|
-
}
|
|
230
|
-
function openLedger(session, registry) {
|
|
231
|
-
const writer = session.config.writer ?? 'cli';
|
|
232
|
-
return openEffectLedger({
|
|
233
|
-
projectDir: session.projectDir, scope: session.scope, writer, keyProvider: keyProvider(session),
|
|
234
|
-
...(session.deps.clock ? { clock: session.deps.clock } : {}),
|
|
235
|
-
...(session.deps.sink ? { sink: session.deps.sink } : {}),
|
|
236
|
-
...(registry ? { verifiers: registry } : {}),
|
|
237
|
-
...(session.deps.lockTimeoutMs ? { lockTimeoutMs: session.deps.lockTimeoutMs } : {}),
|
|
238
|
-
});
|
|
239
|
-
}
|
|
167
|
+
import { effectSession, keyStore, describeKeyProvider, openLedger } from '../../effects/host.js';
|
|
240
168
|
/**
|
|
241
169
|
* The one place the CLI builds its verifier registry: the built-ins, lock
|
|
242
170
|
* recovery, the tracker verifiers (#2719) and any injected extensions.
|
|
@@ -804,15 +732,7 @@ async function execute(ctx, deps) {
|
|
|
804
732
|
throw usage('--format must be json or text', 'invalid-format');
|
|
805
733
|
const projectDir = resolve(one(parsed, 'project-dir') ?? ctx.cwd ?? process.cwd());
|
|
806
734
|
const subsystem = resolveSubsystem(parsed);
|
|
807
|
-
const
|
|
808
|
-
const tenant = config.tenant ?? 'local';
|
|
809
|
-
const project = config.project ?? defaultProject(projectDir);
|
|
810
|
-
if (!IDENTIFIER.test(tenant) || !IDENTIFIER.test(project))
|
|
811
|
-
throw usage('aiwg.config effects tenant and project must be identifiers', 'config-invalid');
|
|
812
|
-
const scope = { tenant, project, subsystem };
|
|
813
|
-
const env = deps.env ?? process.env;
|
|
814
|
-
const account = config.keyProvider?.account ?? `ledger/${tenant}/${project}/${subsystem}`;
|
|
815
|
-
const session = { projectDir, scope, config, account, deps, env };
|
|
735
|
+
const session = await effectSession(projectDir, subsystem, deps);
|
|
816
736
|
let rendered;
|
|
817
737
|
switch (sub) {
|
|
818
738
|
case 'id':
|