@aiwg/cli 2026.10.6 → 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/bin/aiwg.mjs +4 -2
- 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/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/index-preparation.js +2 -0
- 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 +3 -2
- package/dist/src/cli/handlers/effect.js +4 -84
- package/dist/src/cli/handlers/guided-setup.js +1 -1
- package/dist/src/cli/handlers/init.js +1 -1
- package/dist/src/cli/handlers/install.js +6 -0
- package/dist/src/cli/handlers/marketplace.js +15 -4
- package/dist/src/cli/handlers/setup.js +24 -20
- package/dist/src/cli/handlers/use.js +57 -15
- package/dist/src/cli/prompt-utils.js +73 -0
- package/dist/src/config/gitignore.js +4 -0
- package/dist/src/config/workspace.js +2 -1
- package/dist/src/decision/adapters/jev.js +20 -31
- package/dist/src/decision/ask.js +6 -1
- package/dist/src/decision/benchmark.js +19 -6
- package/dist/src/decision/qualification/gate-evidence.js +6 -4
- package/dist/src/decision/qualification/load-staged.js +47 -10
- package/dist/src/decision/qualification/runner.js +7 -3
- package/dist/src/discovery/interview.js +10 -5
- package/dist/src/discovery/plan-apply.js +26 -30
- package/dist/src/discovery/plan-validation.js +2 -2
- package/dist/src/effects/host.js +91 -0
- package/dist/src/extensions/commands/definitions.js +2 -2
- package/dist/src/extensions/project-local-gitignore.js +2 -0
- package/dist/src/issues/cli.js +16 -5
- package/dist/src/issues/live.js +44 -12
- 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 +17 -90
- package/dist/src/mcp/grok-build-config.mjs +2 -1
- package/dist/src/mcp/muse-native-config.mjs +2 -1
- package/dist/src/mcp/tools/worker-invoke.mjs +13 -2
- package/dist/src/memory/project-registry.js +2 -1
- package/dist/src/mission-protocol/worker-status.js +91 -1
- package/dist/src/models/worker-installation.d.mts +1 -1
- package/dist/src/models/worker-installation.mjs +65 -4
- 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/process/cli-command.d.mts +5 -0
- package/dist/src/process/cli-command.mjs +42 -0
- package/dist/src/serve/worker-invocation.js +10 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +9 -9
- 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/workspace-context.js +4 -12
- package/dist/src/tracker/project-inputs.js +2 -0
- package/dist/src/update/notifier.mjs +2 -4
- package/package.json +1 -1
- package/tools/agents/providers/base.mjs +5 -1
- package/tools/agents/providers/claude.mjs +5 -2
- package/tools/agents/providers/codex.mjs +4 -1
- package/tools/agents/providers/context-write.mjs +28 -0
- package/tools/agents/providers/copilot.mjs +5 -2
- package/tools/agents/providers/hermes.mjs +5 -2
- package/tools/agents/providers/omp.mjs +3 -1
- package/tools/agents/providers/rule-delivery.mjs +29 -12
- package/tools/agents/providers/warp.mjs +4 -1
- package/tools/agents/providers/windsurf.mjs +6 -3
- 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/recovery-probe.mjs +14 -4
- package/tools/ralph-external/process-monitor.mjs +42 -4
- package/tools/ralph-external/session-launcher.mjs +125 -3
|
@@ -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,3 +1,4 @@
|
|
|
1
|
+
import { resolveSensitiveInput, sensitiveInputOptions } from '../../auth/sensitive-input.js';
|
|
1
2
|
import { decisionPricing } from '../../decision/pricing.js';
|
|
2
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';
|
|
3
4
|
function jsonResult(value, exitCode = 0) {
|
|
@@ -17,7 +18,7 @@ function usage() {
|
|
|
17
18
|
' validate <request|definition|ruleset|binding> <path>',
|
|
18
19
|
' evaluate --request <path> [--host-policy-module <path>]',
|
|
19
20
|
' setup synthetic-classification [--output-dir <dir>]',
|
|
20
|
-
' 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]',
|
|
21
22
|
' ask --question "<q>" (--yes-no | --choices a,b,c | --scale 1-5) [--provider <id>] [--session <id>] [--caller <tag>] [--record-text]',
|
|
22
23
|
' history [--since <date>] [--provider <id>] [--session <id>] [--kind yes-no|choices|scale] [--status answered|fallback] [--caller <tag>|<prefix>* | --no-caller] [--json]',
|
|
23
24
|
' pricing [--refresh --model jev-X.Y.Z] [--dry-run] [--offline | --allow-snapshot] [--json]',
|
|
@@ -101,7 +102,7 @@ function takeAttributionOption(args, name, reason) {
|
|
|
101
102
|
return value;
|
|
102
103
|
}
|
|
103
104
|
async function decisionSetupJev(rest) {
|
|
104
|
-
const token = rest.includes('--
|
|
105
|
+
const token = rest.includes('--remove') ? undefined : await resolveSensitiveInput(sensitiveInputOptions(rest, 'token'));
|
|
105
106
|
const result = await setupJev({
|
|
106
107
|
token,
|
|
107
108
|
region: takeOption(rest, '--region'),
|
|
@@ -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':
|
|
@@ -56,7 +56,7 @@ export function parseGuidedSetupFlags(args, command) {
|
|
|
56
56
|
const separator = raw.indexOf('=');
|
|
57
57
|
const provider = raw.slice(0, separator) === 'jev' ? 'jev' : normalizeProviderDefinitionId(raw.slice(0, separator));
|
|
58
58
|
if (separator < 1 || !provider || provider === 'generic')
|
|
59
|
-
throw new Error('--credential requires a known <provider>=
|
|
59
|
+
throw new Error('--credential requires a known <provider>=stdin|file:PATH|store:NAME|env:NAME.');
|
|
60
60
|
credentials[provider] = credentialReference(raw.slice(separator + 1));
|
|
61
61
|
}
|
|
62
62
|
if (tokenStdin) {
|
|
@@ -191,7 +191,7 @@ export const initHandler = {
|
|
|
191
191
|
--intent code|docs|ops|mixed Workspace usage intent
|
|
192
192
|
--jev enable|decline|defer Optional external decision service (default off)
|
|
193
193
|
--region <r> --endpoint <url> --verify --remove --token-stdin Existing Jev options
|
|
194
|
-
--credential <provider>=
|
|
194
|
+
--credential <provider>=stdin|file:PATH|store:NAME|env:NAME Credential reference only
|
|
195
195
|
--providers <list> Provider IDs
|
|
196
196
|
--default-scripts true|false Include default scripts
|
|
197
197
|
--custom-scripts true|false Include custom scripts
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* @implements #804
|
|
19
19
|
*/
|
|
20
20
|
import path from 'path';
|
|
21
|
+
import { sensitiveInputOptions } from '../../auth/sensitive-input.js';
|
|
21
22
|
import { installPackage } from '../../packages/registry.js';
|
|
22
23
|
import { recordDeployment } from '../../packages/package-registry.js';
|
|
23
24
|
import { marketplaceConfigDir, resolveVerificationPolicy } from '../../marketplace/exchange.js';
|
|
@@ -59,6 +60,7 @@ export const installHandler = {
|
|
|
59
60
|
' --deploy Deploy immediately after install',
|
|
60
61
|
' --provider <name> Target provider (claude, copilot, cursor...)',
|
|
61
62
|
' --target <dir> Project directory to deploy into',
|
|
63
|
+
' --token-interactive | --token-stdin | --token-file <path> | --token-store <name> | --token-env <name>',
|
|
62
64
|
' --refresh Force re-pull even if cached',
|
|
63
65
|
' --ref <tag-or-sha> Resolve this ref and lock its immutable commit',
|
|
64
66
|
' --package <id> Select one wrapper when a repository contains several',
|
|
@@ -69,6 +71,9 @@ export const installHandler = {
|
|
|
69
71
|
].join('\n'),
|
|
70
72
|
};
|
|
71
73
|
}
|
|
74
|
+
if (/^https?:\/\/[^/]*@/.test(rawRef)) {
|
|
75
|
+
return { exitCode: 1, message: 'Credentials in Git URLs are refused; use --token-stdin, --token-file, --token-store or --token-env.' };
|
|
76
|
+
}
|
|
72
77
|
const deploy = hasFlag(ctx.args, '--deploy');
|
|
73
78
|
const refresh = hasFlag(ctx.args, '--refresh');
|
|
74
79
|
const provider = parseFlag(ctx.args, '--provider') ?? 'claude';
|
|
@@ -97,6 +102,7 @@ export const installHandler = {
|
|
|
97
102
|
const resolvedPolicy = await resolveVerificationPolicy(policyName, scope);
|
|
98
103
|
const installed = await installPackage(rawRef, {
|
|
99
104
|
refresh,
|
|
105
|
+
tokenInput: sensitiveInputOptions(ctx.args, 'token'),
|
|
100
106
|
ref: parseFlag(ctx.args, '--ref'),
|
|
101
107
|
packageSelector: parseFlag(ctx.args, '--package'),
|
|
102
108
|
verify,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import fs from 'node:fs';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
+
import { sensitiveInputOptions } from '../../auth/sensitive-input.js';
|
|
12
13
|
import { searchSkills } from '../../skills/registry.js';
|
|
13
14
|
import { installPackage, listInstalledPackages } from '../../packages/registry.js';
|
|
14
15
|
import { GitAdapter } from '../../packages/adapters/git.js';
|
|
@@ -24,7 +25,7 @@ const USAGE = [
|
|
|
24
25
|
' aiwg marketplace verify <package|lock> Verify cached content and receipts offline',
|
|
25
26
|
' aiwg marketplace export <package> --output <archive.json>',
|
|
26
27
|
' aiwg marketplace import <archive.json> [--project-local]',
|
|
27
|
-
' aiwg marketplace publish <source> --
|
|
28
|
+
' aiwg marketplace publish <source> --publisher <id> [--key-file <pem> | --key-stdin]',
|
|
28
29
|
' aiwg marketplace remove <catalog-id>',
|
|
29
30
|
' aiwg marketplace list List installed marketplace packages',
|
|
30
31
|
'',
|
|
@@ -33,6 +34,11 @@ const USAGE = [
|
|
|
33
34
|
' --project-local Store/read state below the target project .aiwg directory',
|
|
34
35
|
' --global Store/read state in the user AIWG directory (default)',
|
|
35
36
|
' --policy <name> Named trust policy or JSON policy path',
|
|
37
|
+
'Git fetch token sources:',
|
|
38
|
+
' --token-interactive | --token-stdin | --token-file <path> | --token-store <name> | --token-env <name>',
|
|
39
|
+
'Publish key sources (multiline PEM):',
|
|
40
|
+
' --key-interactive | --key-stdin | --key-file <path> | --key-store <name> | --key-env <name>',
|
|
41
|
+
' --key <path> Compatibility alias for --key-file (private file required)',
|
|
36
42
|
].join('\n');
|
|
37
43
|
function parseFlag(args, flag) {
|
|
38
44
|
const idx = args.indexOf(flag);
|
|
@@ -105,7 +111,10 @@ async function handleAdd(ctx) {
|
|
|
105
111
|
const requestedRef = parseFlag(ctx.args, '--ref') ?? 'HEAD';
|
|
106
112
|
const adapter = new GitAdapter();
|
|
107
113
|
const source = { gitUrl: argument, ref: requestedRef, label: argument };
|
|
108
|
-
const cachePath = await adapter.fetch(source, {
|
|
114
|
+
const cachePath = await adapter.fetch(source, {
|
|
115
|
+
refresh: hasFlag(ctx.args, '--refresh'),
|
|
116
|
+
tokenInput: sensitiveInputOptions(ctx.args, 'token'),
|
|
117
|
+
});
|
|
109
118
|
const identity = await inspectGitCheckout(cachePath);
|
|
110
119
|
const candidates = [
|
|
111
120
|
path.join(cachePath, 'aiwg-marketplace-catalog.json'),
|
|
@@ -251,6 +260,7 @@ async function handleInstall(ctx) {
|
|
|
251
260
|
}
|
|
252
261
|
const installed = await installPackage(rawRef, {
|
|
253
262
|
configDir,
|
|
263
|
+
tokenInput: sensitiveInputOptions(ctx.args, 'token'),
|
|
254
264
|
ref,
|
|
255
265
|
packageSelector: parseFlag(ctx.args, '--package'),
|
|
256
266
|
refresh: hasFlag(ctx.args, '--refresh'),
|
|
@@ -342,8 +352,8 @@ async function handlePublish(ctx) {
|
|
|
342
352
|
return argument;
|
|
343
353
|
const privateKeyPath = parseFlag(ctx.args, '--key');
|
|
344
354
|
const publisher = parseFlag(ctx.args, '--publisher');
|
|
345
|
-
if (!
|
|
346
|
-
return { exitCode: 1, message: 'Error: Usage: aiwg marketplace publish <source> --key <ed25519.pem> --publisher <id> [--output <dir>]' };
|
|
355
|
+
if (!publisher) {
|
|
356
|
+
return { exitCode: 1, message: 'Error: Usage: aiwg marketplace publish <source> [--key-file <ed25519.pem> | --key-stdin] --publisher <id> [--output <dir>]' };
|
|
347
357
|
}
|
|
348
358
|
try {
|
|
349
359
|
const outputDir = parseFlag(ctx.args, '--output') ?? path.join(path.resolve(argument), '.aiwg', 'marketplace');
|
|
@@ -355,6 +365,7 @@ async function handlePublish(ctx) {
|
|
|
355
365
|
sourceDir: argument,
|
|
356
366
|
outputDir,
|
|
357
367
|
privateKeyPath,
|
|
368
|
+
keyInput: sensitiveInputOptions(ctx.args, 'key'),
|
|
358
369
|
publicKeyPath: parseFlag(ctx.args, '--public-key'),
|
|
359
370
|
keyId: parseFlag(ctx.args, '--key-id'),
|
|
360
371
|
publisher,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { boundedSpawnSync } from '../../process/bounded-child-process.mjs';
|
|
2
|
+
import { helperEnvironment, HELPER_ENV_ALLOWLIST } from '../../process/cli-command.mjs';
|
|
3
|
+
import { readPrivateValueFile } from '../../auth/sensitive-input.js';
|
|
4
|
+
import { setupJev } from '../../decision/driver.js';
|
|
2
5
|
import { existsSync } from 'fs';
|
|
3
6
|
import { emptyConfig, FORCE_PUSH_POLICY_ALIAS_NOTE, normalizeForcePushPolicy as normalizeForcePushPolicyShared, getConfigPath, getProjectDir, readAiwgConfig, resolveRemoteProvider, VALID_PROVIDERS, writeAiwgConfig, } from '../../config/aiwg-config.js';
|
|
4
7
|
import { AiwgError, EXIT_CODES } from '../errors.js';
|
|
@@ -133,6 +136,7 @@ export function parseSetupProjectOptions(ctx) {
|
|
|
133
136
|
}
|
|
134
137
|
export function detectGitRemotes(projectDir) {
|
|
135
138
|
const result = boundedSpawnSync('git', ['-C', projectDir, 'remote', '-v'], 'quick', {
|
|
139
|
+
env: helperEnvironment(),
|
|
136
140
|
encoding: 'utf-8',
|
|
137
141
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
138
142
|
});
|
|
@@ -156,6 +160,7 @@ export function detectGitRemotes(projectDir) {
|
|
|
156
160
|
}
|
|
157
161
|
function detectDefaultBranch(projectDir) {
|
|
158
162
|
const symbolic = boundedSpawnSync('git', ['-C', projectDir, 'symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'], 'quick', {
|
|
163
|
+
env: helperEnvironment(),
|
|
159
164
|
encoding: 'utf-8',
|
|
160
165
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
161
166
|
});
|
|
@@ -163,6 +168,7 @@ function detectDefaultBranch(projectDir) {
|
|
|
163
168
|
if (symbolic.status === 0 && fromOrigin)
|
|
164
169
|
return fromOrigin;
|
|
165
170
|
const branch = boundedSpawnSync('git', ['-C', projectDir, 'branch', '--show-current'], 'quick', {
|
|
171
|
+
env: helperEnvironment(),
|
|
166
172
|
encoding: 'utf-8',
|
|
167
173
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
168
174
|
});
|
|
@@ -170,6 +176,7 @@ function detectDefaultBranch(projectDir) {
|
|
|
170
176
|
}
|
|
171
177
|
function gitConfig(projectDir, key) {
|
|
172
178
|
const result = boundedSpawnSync('git', ['-C', projectDir, 'config', '--get', key], 'quick', {
|
|
179
|
+
env: helperEnvironment(),
|
|
173
180
|
encoding: 'utf-8',
|
|
174
181
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
175
182
|
});
|
|
@@ -656,7 +663,7 @@ function defaultGuidedApplyIO(plan, fresh, ctx, projectDir, frameworkRoot, canPr
|
|
|
656
663
|
chunks.push(Buffer.from(chunk));
|
|
657
664
|
return Buffer.concat(chunks).toString('utf8');
|
|
658
665
|
} } : {}),
|
|
659
|
-
readCredentialFile: async (path) =>
|
|
666
|
+
readCredentialFile: async (path) => readPrivateValueFile(path, '--credential'),
|
|
660
667
|
// stdin-at-apply prompts for the value without echoing it anywhere: the
|
|
661
668
|
// label names the consumer only, and the value never reaches output.
|
|
662
669
|
...(canPrompt ? { promptCredential: async (label) => {
|
|
@@ -674,26 +681,20 @@ function defaultGuidedApplyIO(plan, fresh, ctx, projectDir, frameworkRoot, canPr
|
|
|
674
681
|
await writeSetupPlan(projectDir, next);
|
|
675
682
|
},
|
|
676
683
|
owners: {
|
|
677
|
-
configureJev: async ({ action, token, options
|
|
684
|
+
configureJev: async ({ action, token, options }) => {
|
|
678
685
|
if (options != null)
|
|
679
686
|
validateJevOptions(options);
|
|
680
687
|
const settings = (options ?? {});
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
cwd: action.workspace, env: environment, input: token ? `${token}\n` : '', encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
692
|
-
maxBuffer: 1024 * 1024,
|
|
693
|
-
});
|
|
694
|
-
if (child.error || child.status !== 0)
|
|
695
|
-
throw new Error('Jev setup failed.');
|
|
696
|
-
if (settings.verify === true && settings.remove !== true && JSON.parse(child.stdout).verified !== true) {
|
|
688
|
+
// Invoke the existing owner directly. spawnSync's input option is
|
|
689
|
+
// rendered by NODE_DEBUG=child_process before the child can read it.
|
|
690
|
+
const result = await setupJev({
|
|
691
|
+
token,
|
|
692
|
+
...(typeof settings.region === 'string' ? { region: settings.region } : {}),
|
|
693
|
+
...(typeof settings.endpoint === 'string' ? { endpoint: settings.endpoint } : {}),
|
|
694
|
+
verify: settings.verify === true,
|
|
695
|
+
remove: settings.remove === true,
|
|
696
|
+
}, { env: process.env, cwd: action.workspace });
|
|
697
|
+
if (settings.verify === true && settings.remove !== true && result.verified !== true) {
|
|
697
698
|
throw new Error('Jev verification incomplete.');
|
|
698
699
|
}
|
|
699
700
|
},
|
|
@@ -711,7 +712,10 @@ function defaultGuidedApplyIO(plan, fresh, ctx, projectDir, frameworkRoot, canPr
|
|
|
711
712
|
await writeAiwgConfig(action.workspace, next);
|
|
712
713
|
const child = boundedSpawnSync(process.execPath, [join(frameworkRoot, 'bin', 'aiwg.mjs'),
|
|
713
714
|
'doctor', '--probe-workers', '--qualify', '--yes', '--json'], 'long', {
|
|
714
|
-
cwd: action.workspace,
|
|
715
|
+
cwd: action.workspace, env: helperEnvironment(process.env, [...HELPER_ENV_ALLOWLIST,
|
|
716
|
+
'AIWG_ROOT', 'AIWG_HOME', 'AIWG_CONFIG', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME',
|
|
717
|
+
'AIWG_ARTIFACTS_PATH', 'AIWG_PROJECT_ARTIFACTS_PATH', 'AIWG_PROJECT_AIWG_DIR',
|
|
718
|
+
'AIWG_PROJECT_MEMORY_HOME', 'NO_UPDATE_NOTIFIER', 'NO_COLOR', 'CI']), encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 1024 * 1024,
|
|
715
719
|
});
|
|
716
720
|
if (child.error || child.status !== 0)
|
|
717
721
|
throw new Error('Worker qualification failed.');
|
|
@@ -813,7 +817,7 @@ Options:
|
|
|
813
817
|
--intent code|docs|ops|mixed Workspace usage intent
|
|
814
818
|
--jev enable|decline|defer Optional external decision service (default off)
|
|
815
819
|
--region <r> --endpoint <url> --verify --remove --token-stdin Existing Jev options
|
|
816
|
-
--credential <provider>=
|
|
820
|
+
--credential <provider>=stdin|file:PATH|store:NAME|env:NAME Credential reference only
|
|
817
821
|
--yes Confirm writes without prompting
|
|
818
822
|
--dry-run Preview the setup plan
|
|
819
823
|
--review Render the saved guided plan per workspace/provider (writes nothing)
|