@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
|
@@ -487,6 +487,10 @@ function workerLaunchRefusal(outcome) {
|
|
|
487
487
|
: 'Worker launch did not return an attached child');
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
// Only the admitted direct owner can supply inputs for an automatic correction.
|
|
491
|
+
// Neither worker output nor a caller-supplied result can populate this context.
|
|
492
|
+
const directStartupCorrectionContext = new WeakMap();
|
|
493
|
+
|
|
490
494
|
async function launchOneWorker(owner, options) {
|
|
491
495
|
const { inspectWorkerPath: inspect, revalidateWorkerInvocationPlan: validate } = await importImpl(import.meta.url, 'serve/worker-invocation.js');
|
|
492
496
|
const { qualificationDigest } = await importImpl(import.meta.url, 'models/qualification-digest.mjs');
|
|
@@ -664,6 +668,7 @@ async function launchOneWorker(owner, options) {
|
|
|
664
668
|
// worker-writable captureRoot fell back to the in-process ledger) is
|
|
665
669
|
// folded in up front so every exit path reports it.
|
|
666
670
|
const ledgerDiagnostics = admission.ledgerDiagnostic ? [admission.ledgerDiagnostic] : [];
|
|
671
|
+
const startupQualification = structuredClone(inputs.drivers[invocation.selected.cli].qualification);
|
|
667
672
|
const settleLedger = async (outcome) => {
|
|
668
673
|
const diagnostic = await settleDirectWorker(admission, outcome);
|
|
669
674
|
if (diagnostic) ledgerDiagnostics.push(diagnostic);
|
|
@@ -747,11 +752,22 @@ async function launchOneWorker(owner, options) {
|
|
|
747
752
|
// writes; `.catch(() => {})` keeps a prior failure from poisoning it, and
|
|
748
753
|
// the per-call promise returned to the caller still reflects this write's
|
|
749
754
|
// own outcome.
|
|
755
|
+
let latestProcessRecord = null;
|
|
750
756
|
const publish = (name, value) => {
|
|
757
|
+
if (name === 'process.json') {
|
|
758
|
+
value = { ...value, recovery: { ...admission.breaker.recoveryStatus(), observedAt: new Date().toISOString() } };
|
|
759
|
+
if (options.startupCorrectionRecord) value.startupCorrection = options.startupCorrectionRecord;
|
|
760
|
+
latestProcessRecord = value;
|
|
761
|
+
}
|
|
751
762
|
const write = publishing.catch(() => {}).then(() => writeRecord(runDir, name, value, inspect));
|
|
752
763
|
publishing = write.catch(error => { publishFailures.push({ name, error: error?.message ?? String(error) }); });
|
|
753
764
|
return write;
|
|
754
765
|
};
|
|
766
|
+
const publishRecovery = () => {
|
|
767
|
+
if (latestProcessRecord) return publish('process.json', latestProcessRecord);
|
|
768
|
+
};
|
|
769
|
+
const onScopeTransition = () => { publishRecovery()?.catch(() => {}); };
|
|
770
|
+
admission.breaker.on('transition', onScopeTransition);
|
|
755
771
|
const handles = [];
|
|
756
772
|
let outcome;
|
|
757
773
|
let artifacts;
|
|
@@ -914,6 +930,8 @@ async function launchOneWorker(owner, options) {
|
|
|
914
930
|
// accumulated across this attempt's lifecycle on the returned result,
|
|
915
931
|
// mirroring `publishFailures` — never silently discarded.
|
|
916
932
|
if (ledgerDiagnostics.length && result) result.ledgerDiagnostics = ledgerDiagnostics.slice();
|
|
933
|
+
directStartupCorrectionContext.set(owner, { saved, invocation, loadInputs, clock, dispatchGuard,
|
|
934
|
+
ledger: admission.ledger, inspect, qualification: startupQualification });
|
|
917
935
|
return result;
|
|
918
936
|
} catch (error) {
|
|
919
937
|
if (!outcome?.child) {
|
|
@@ -985,6 +1003,8 @@ async function launchOneWorker(owner, options) {
|
|
|
985
1003
|
if (ledgerDiagnostics.length) error.ledgerDiagnostics = ledgerDiagnostics;
|
|
986
1004
|
throw error;
|
|
987
1005
|
} finally {
|
|
1006
|
+
admission.breaker.removeListener('transition', onScopeTransition);
|
|
1007
|
+
await publishing;
|
|
988
1008
|
try { await artifacts?.cleanup(); } finally {
|
|
989
1009
|
// Never chmod a worker-replaced pathname; only the inodes we opened.
|
|
990
1010
|
for (const handle of handles) { await handle.chmod(0o600).catch(() => {}); await handle.close().catch(() => {}); }
|
|
@@ -3916,6 +3936,102 @@ export function classifyAttemptForSettlement(invocation, result, { quotaAccount
|
|
|
3916
3936
|
inferenceProvider: selected.inferenceProvider ?? null, quotaAccount, installationQualifier };
|
|
3917
3937
|
}
|
|
3918
3938
|
|
|
3939
|
+
/** Refresh only a demonstrated stale executable binding. Installation, login,
|
|
3940
|
+
* permissions, models, working directories and policy are never repaired here.
|
|
3941
|
+
* One retry shares the original task clock and the existing atomic ledgers. */
|
|
3942
|
+
async function correctDirectWorkerStartup(owner, options, previous) {
|
|
3943
|
+
const context = directStartupCorrectionContext.get(owner);
|
|
3944
|
+
if (!context || options.correctStartup !== undefined || previous?.errorCode !== 'ENOENT'
|
|
3945
|
+
|| previous.termination !== 'confirmed' || previous.exitCode != null || previous.signal != null
|
|
3946
|
+
|| previous.cancelled || previous.timedOut || previous.publishFailures?.length
|
|
3947
|
+
|| classifyLaunchOutcomeForRecovery(previous).reasonCode !== 'NOT_FOUND') return previous;
|
|
3948
|
+
const { saved, invocation, loadInputs, clock, dispatchGuard, ledger, inspect, qualification } = context;
|
|
3949
|
+
const record = { action: 'refresh-executable-binding', reasonCode: 'NOT_FOUND', state: 'stopped',
|
|
3950
|
+
previousInvocationId: previous.invocationId };
|
|
3951
|
+
const recordAt = async (runDir, invocationId) => {
|
|
3952
|
+
const processRecord = JSON.parse((await boundedPrivateRead(join(runDir, 'process.json'), 65536, inspect)).toString('utf8'));
|
|
3953
|
+
if (processRecord.origin !== 'launcher' || processRecord.invocationId !== invocationId) throw new Error('Correction record identity changed');
|
|
3954
|
+
await (options.publishRecord ?? publishWorkerRecord)(runDir, 'process.json', { ...processRecord, startupCorrection: { ...record } }, inspect);
|
|
3955
|
+
};
|
|
3956
|
+
const stop = async code => {
|
|
3957
|
+
record.stopCode = code;
|
|
3958
|
+
previous.startupCorrection = { ...record };
|
|
3959
|
+
await recordAt(options.runDir, previous.invocationId);
|
|
3960
|
+
return previous;
|
|
3961
|
+
};
|
|
3962
|
+
const guardStop = () => dispatchGuard?.isCancelled?.() === true ? 'CANCELLED'
|
|
3963
|
+
: dispatchGuard?.deadlineAtMs != null && (dispatchGuard.nowMs?.() ?? Date.now()) >= dispatchGuard.deadlineAtMs ? 'DEADLINE' : null;
|
|
3964
|
+
if (ledger?.n >= ledger?.maxAttempts) return stop('ATTEMPT_LIMIT');
|
|
3965
|
+
if (guardStop()) return stop(guardStop());
|
|
3966
|
+
let inputs;
|
|
3967
|
+
let plan;
|
|
3968
|
+
const retryId = randomUUID();
|
|
3969
|
+
const finalPath = `${invocation.finalPath}.recovery-${retryId}`;
|
|
3970
|
+
try {
|
|
3971
|
+
inputs = await loadInputs();
|
|
3972
|
+
const { resolveWorkerInvocation } = await importImpl(import.meta.url, 'serve/worker-invocation.js');
|
|
3973
|
+
plan = await resolveWorkerInvocation(inputs.snapshot, { ...saved.request, final_output: finalPath }, inputs.drivers, clock());
|
|
3974
|
+
} catch { return stop('QUALIFICATION_REFUSED'); }
|
|
3975
|
+
if (guardStop()) return stop(guardStop());
|
|
3976
|
+
if (plan?.status !== 'eligible' || plan.mode !== 'direct' || plan.invocation?.readiness !== 'launchable') return stop('QUALIFICATION_REFUSED');
|
|
3977
|
+
if (plan.invocation.argv[0] === invocation.argv[0]) return stop('UNCHANGED_EXECUTABLE');
|
|
3978
|
+
// A freshly requalified installation may have new binary/proof digests.
|
|
3979
|
+
// Preserve every effective adapter declaration and installation boundary.
|
|
3980
|
+
const effectiveQualification = value => {
|
|
3981
|
+
const copy = structuredClone(value);
|
|
3982
|
+
const stripEvidence = evidence => {
|
|
3983
|
+
if (evidence) for (const key of ['scopeDigest', 'fixtureDigest', 'verifiedAt', 'evidenceRef']) delete evidence[key];
|
|
3984
|
+
};
|
|
3985
|
+
stripEvidence(copy.adapter?.qualification);
|
|
3986
|
+
for (const profile of Object.values(copy.adapter?.invocationProfiles ?? {})) stripEvidence(profile.installationQualification);
|
|
3987
|
+
if (copy.installation) {
|
|
3988
|
+
delete copy.installation.executable;
|
|
3989
|
+
delete copy.installation.evidence;
|
|
3990
|
+
}
|
|
3991
|
+
if (copy.stdinFramerBinding) delete copy.stdinFramerBinding.storeDigest;
|
|
3992
|
+
return JSON.stringify(copy);
|
|
3993
|
+
};
|
|
3994
|
+
if (effectiveQualification(qualification) !== effectiveQualification(inputs.drivers[invocation.selected.cli]?.qualification)) return stop('BINDING_CHANGED');
|
|
3995
|
+
// The resolver is authoritative for the replacement executable. Everything
|
|
3996
|
+
// else must remain identical, including qualified selection, policy, limits,
|
|
3997
|
+
// framing, environment, controls, prompt digest and workspace. Only fresh
|
|
3998
|
+
// output names and expiration are expected to differ between attempts.
|
|
3999
|
+
const binding = value => {
|
|
4000
|
+
const copy = structuredClone(value);
|
|
4001
|
+
const replacements = ['stderrPath', 'stdoutPath', 'finalPath'].map(key => [copy[key], `<${key}>`]);
|
|
4002
|
+
const normalize = value => replacements.find(([path]) => path === value)?.[1] ?? value;
|
|
4003
|
+
copy.argv = copy.argv.map((value, index) => index === 0 ? '<executable>' : normalize(value));
|
|
4004
|
+
delete copy.selected.qualificationDigest;
|
|
4005
|
+
for (const key of ['stdoutPath', 'stderrPath', 'finalPath', 'expiresAt', 'shellCommand', 'profileDigest']) delete copy[key];
|
|
4006
|
+
return JSON.stringify(copy);
|
|
4007
|
+
};
|
|
4008
|
+
if (binding(plan.invocation) !== binding(invocation)) return stop('BINDING_CHANGED');
|
|
4009
|
+
const invocationPath = join(options.runDir, `recovery-plan-${retryId}.json`);
|
|
4010
|
+
const runDir = `${options.runDir}.recovery-${retryId}`;
|
|
4011
|
+
if (guardStop()) return stop(guardStop());
|
|
4012
|
+
let retry;
|
|
4013
|
+
try {
|
|
4014
|
+
const planHandle = await withWorkerPath(invocationPath, target => open(target,
|
|
4015
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600));
|
|
4016
|
+
try { await planHandle.writeFile(JSON.stringify(plan)); await planHandle.sync(); } finally { await planHandle.close(); }
|
|
4017
|
+
// Publication happens before any retry launch. A record failure stops work.
|
|
4018
|
+
record.state = 'applied';
|
|
4019
|
+
await recordAt(options.runDir, previous.invocationId);
|
|
4020
|
+
retry = await launchOneWorker(owner, { ...options, invocationPath, runDir, dispatchGuard,
|
|
4021
|
+
inputs: undefined, loadInputs, retryOf: { invocationId: previous.invocationId, runDir: options.runDir },
|
|
4022
|
+
correctStartup: { reasonCode: 'NOT_FOUND' }, startupCorrectionRecord: { ...record } });
|
|
4023
|
+
} catch {
|
|
4024
|
+
record.state = 'stopped';
|
|
4025
|
+
return stop(guardStop() ?? 'RETRY_REFUSED');
|
|
4026
|
+
}
|
|
4027
|
+
record.retryInvocationId = retry.invocationId;
|
|
4028
|
+
if (retry.attemptOutcome !== 'succeeded') { record.state = 'stopped'; record.stopCode = 'RETRY_FAILED'; }
|
|
4029
|
+
retry.startupCorrection = { ...record };
|
|
4030
|
+
await recordAt(options.runDir, previous.invocationId);
|
|
4031
|
+
await recordAt(runDir, retry.invocationId);
|
|
4032
|
+
return retry;
|
|
4033
|
+
}
|
|
4034
|
+
|
|
3919
4035
|
// #2915 round 8 (D6, "lazy public fields still differ after mixed use"):
|
|
3920
4036
|
// `lastAttemptResult`/`lastAttemptInvocationId` are informational
|
|
3921
4037
|
// bookkeeping only (#2915 step 4 — the retry gate no longer reads them;
|
|
@@ -3987,8 +4103,9 @@ export class SessionLauncher extends EventEmitter {
|
|
|
3987
4103
|
* `options.correctStartup: { reasonCode, correctionsUsed }` enforces the
|
|
3988
4104
|
* one-qualified-startup-correction budget on a conductor-declared
|
|
3989
4105
|
* correction retry (startupCorrectionGate): unqualified causes and second
|
|
3990
|
-
* corrections are refused, within the task's existing allowance.
|
|
3991
|
-
*
|
|
4106
|
+
* corrections are refused, within the task's existing allowance. The only
|
|
4107
|
+
* automatic correction refreshes a changed qualified executable binding
|
|
4108
|
+
* after a launcher-observed ENOENT with confirmed stop, once per task chain.
|
|
3992
4109
|
*
|
|
3993
4110
|
* Both checks are gated recovery behavior, not a general launch
|
|
3994
4111
|
* precondition: enforcement happens entirely INSIDE `launchOneWorker`,
|
|
@@ -4015,8 +4132,13 @@ export class SessionLauncher extends EventEmitter {
|
|
|
4015
4132
|
// `options.retryOf`-driven and disk-verified every time) is set inside
|
|
4016
4133
|
// `launchOneWorker` itself, gated on whether recovery actually admitted
|
|
4017
4134
|
// this attempt (#2915 review 6, finding 6) — never here unconditionally.
|
|
4018
|
-
|
|
4135
|
+
directStartupCorrectionContext.delete(this);
|
|
4136
|
+
try {
|
|
4137
|
+
const result = await launchOneWorker(this, options);
|
|
4138
|
+
return await correctDirectWorkerStartup(this, options, result);
|
|
4139
|
+
}
|
|
4019
4140
|
finally {
|
|
4141
|
+
directStartupCorrectionContext.delete(this);
|
|
4020
4142
|
_workerRecoverySubscriptions.get(this)?.();
|
|
4021
4143
|
_workerRecoverySubscriptions.delete(this);
|
|
4022
4144
|
this.workerLaunchPending = false;
|