@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
|
@@ -8,7 +8,7 @@ import { isDeepStrictEqual } from 'node:util';
|
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { glob } from 'glob';
|
|
10
10
|
import { load as loadYaml } from 'js-yaml';
|
|
11
|
-
import { compileModelPolicy, validateCanonicalModelPolicy, validateUserProjectModelConfig, loadProviderModelCapabilities, WorkerPolicyError, } from '../../models/provider-policy.js';
|
|
11
|
+
import { compileModelPolicy, validateCanonicalModelPolicy, validateUserProjectModelConfig, loadProviderModelCapabilities, WorkerPolicyError, assertWorkerRoleEffort, } from '../../models/provider-policy.js';
|
|
12
12
|
import { resolveGrokBuildRoleModel } from '../../models/grok-build-models.js';
|
|
13
13
|
import { readAiwgConfig, emptyConfig } from '../../config/aiwg-config.js';
|
|
14
14
|
import { ConfigLoader } from '../../models/config-loader.js';
|
|
@@ -39,8 +39,38 @@ export async function loadWorkerInputs(ctx) {
|
|
|
39
39
|
return { snapshot: { config, models, modelDigests: loader.getInputDigests(), catalog,
|
|
40
40
|
registry, installations: {} }, drivers: {} };
|
|
41
41
|
}
|
|
42
|
+
// Explain missing policy before a recorded approval's digest check can
|
|
43
|
+
// mask it. The host owner first preserves its missing-installation errors.
|
|
44
|
+
const parallelism = config.parallelism;
|
|
45
|
+
const precheckPolicy = () => {
|
|
46
|
+
if (!ctx.args.some(arg => arg === '--role' || arg.startsWith('--role=')))
|
|
47
|
+
return;
|
|
48
|
+
const request = parseWorkerCommandArgs(ctx.args.slice(1));
|
|
49
|
+
const members = Object.entries(parallelism.groups ?? {})
|
|
50
|
+
.filter(([id]) => !request.group || request.group === id)
|
|
51
|
+
.flatMap(([, group]) => group.members).filter(member => member.enabled !== false
|
|
52
|
+
&& parallelism.clis?.[member.cli]?.enabled !== false && member.roles.includes(request.role));
|
|
53
|
+
const requiresExplicit = members.length > 0 && members.every(member => {
|
|
54
|
+
// Health metadata can identify the provider before an operator has
|
|
55
|
+
// qualified its dispatch adapter. It grants no dispatch authority.
|
|
56
|
+
const [namespace, id] = (parallelism.clis?.[member.cli]?.adapter ?? `providers:${member.cli}`).split(':');
|
|
57
|
+
const provider = namespace === 'providers' ? registry.providers[id] : undefined;
|
|
58
|
+
const adapter = namespace === 'workerAdapters' ? registry.workerAdapters?.[id]
|
|
59
|
+
: provider?.workerAdapter ?? provider?.workerHealthAdapter;
|
|
60
|
+
const observation = (catalog.discovery?.instances?.[member.cli]
|
|
61
|
+
?? catalog.discovery?.providers?.[adapter?.provider ?? id])?.models.find(row => row.id === member.model)?.worker;
|
|
62
|
+
if (observation?.effortSupport === 'explicit')
|
|
63
|
+
return true;
|
|
64
|
+
if (observation?.effortSupport === 'not-applicable')
|
|
65
|
+
return false;
|
|
66
|
+
return adapter?.capabilities.effort === 'explicit';
|
|
67
|
+
});
|
|
68
|
+
// With no matching worker, do not invent policy needs.
|
|
69
|
+
if (members.length)
|
|
70
|
+
assertWorkerRoleEffort(models.defaults.workerSelection, request.role, requiresExplicit);
|
|
71
|
+
};
|
|
42
72
|
const { registry: qualifiedRegistry, installations, drivers, observations } = await loadRecordedWorkerInstallations({
|
|
43
|
-
registry, cwd: ctx.cwd, policy: models.defaults.workerSelection, parallelism: config.parallelism,
|
|
73
|
+
registry, cwd: ctx.cwd, policy: models.defaults.workerSelection, parallelism: config.parallelism, precheckPolicy,
|
|
44
74
|
});
|
|
45
75
|
catalog.discovery ??= { source: 'static', fetchedAt: new Date().toISOString(), providers: {} };
|
|
46
76
|
catalog.discovery.instances = { ...catalog.discovery.instances };
|
|
@@ -62,6 +62,13 @@ export function generateLoopId(objective) {
|
|
|
62
62
|
* Build command-line arguments for the external Ralph process
|
|
63
63
|
*/
|
|
64
64
|
export function buildArgs(options) {
|
|
65
|
+
if (options.managedWorker) {
|
|
66
|
+
if (!options.managedAdmission)
|
|
67
|
+
throw new Error('Managed worker execution requires admission');
|
|
68
|
+
return ['--launch-worker', '--invocation', options.managedWorker.invocationPath,
|
|
69
|
+
'--run-dir', options.managedWorker.runDir, '--managed-request', options.managedAdmission.requestId,
|
|
70
|
+
'--managed-generation', String(options.managedAdmission.generation)];
|
|
71
|
+
}
|
|
65
72
|
const args = [options.objective];
|
|
66
73
|
args.push('--completion', options.completionCriteria);
|
|
67
74
|
if (options.maxIterations) {
|
|
@@ -175,7 +182,9 @@ export async function assertRalphParallelismCap(projectRoot) {
|
|
|
175
182
|
* Launch the external Ralph process as a detached daemon
|
|
176
183
|
*/
|
|
177
184
|
export async function launchExternalRalph(frameworkRoot, projectRoot, options) {
|
|
178
|
-
const orchestratorPath =
|
|
185
|
+
const orchestratorPath = options.managedWorker
|
|
186
|
+
? join(frameworkRoot, 'tools', 'ralph-external', 'session-launcher.mjs')
|
|
187
|
+
: getOrchestratorPath(frameworkRoot);
|
|
179
188
|
if (!existsSync(orchestratorPath)) {
|
|
180
189
|
throw new AiwgError({
|
|
181
190
|
code: 'ERR_RALPH_ORCHESTRATOR_MISSING',
|
|
@@ -191,6 +200,9 @@ export async function launchExternalRalph(frameworkRoot, projectRoot, options) {
|
|
|
191
200
|
// surprising. Tell the operator what's running and how to lift the cap.
|
|
192
201
|
await assertRalphParallelismCap(projectRoot);
|
|
193
202
|
const loopId = options.loopId || generateLoopId(options.objective);
|
|
203
|
+
if (loadLauncherRegistry(projectRoot).loops[loopId]?.managedAdmission) {
|
|
204
|
+
throw new Error('Managed loop identity cannot be relaunched before admission reconciliation');
|
|
205
|
+
}
|
|
194
206
|
const loopDir = join(registryDir, 'loops', loopId);
|
|
195
207
|
mkdirSync(loopDir, { recursive: true });
|
|
196
208
|
// Create output file for the detached process
|
|
@@ -200,6 +212,17 @@ export async function launchExternalRalph(frameworkRoot, projectRoot, options) {
|
|
|
200
212
|
const promptFile = join(loopDir, 'prompts', '001-prompt.md');
|
|
201
213
|
// Build arguments
|
|
202
214
|
const args = buildArgs(options);
|
|
215
|
+
if (options.managedAdmission) {
|
|
216
|
+
const registry = loadLauncherRegistry(projectRoot);
|
|
217
|
+
registry.loops[loopId] = { loopId, pid: 0, objective: options.objective,
|
|
218
|
+
completionCriteria: options.completionCriteria, status: 'running',
|
|
219
|
+
startedAt: new Date().toISOString(), lastUpdate: new Date().toISOString(),
|
|
220
|
+
iteration: 0, maxIterations: options.managedWorker ? 1 : options.maxIterations || 5, outputFile,
|
|
221
|
+
sessionStdoutFile, sessionStderrFile, promptFile, provider: options.provider,
|
|
222
|
+
managedAdmission: { ...options.managedAdmission },
|
|
223
|
+
...(options.managedWorker ? { managedWorker: { ...options.managedWorker } } : {}) };
|
|
224
|
+
saveLauncherRegistry(projectRoot, registry);
|
|
225
|
+
}
|
|
203
226
|
// Create output file descriptors
|
|
204
227
|
const { openSync, closeSync } = await import('fs');
|
|
205
228
|
const outFd = openSync(outputFile, 'w');
|
|
@@ -232,6 +255,25 @@ export async function launchExternalRalph(frameworkRoot, projectRoot, options) {
|
|
|
232
255
|
exitCode: EXIT_CODES.GENERAL,
|
|
233
256
|
});
|
|
234
257
|
}
|
|
258
|
+
let managedAdmission;
|
|
259
|
+
if (options.managedAdmission) {
|
|
260
|
+
const { sampleWorkerIdentity, createWorkerIdentityCapture } = await import(join(frameworkRoot, 'tools', 'ralph-external', 'process-monitor.mjs'));
|
|
261
|
+
const capture = createWorkerIdentityCapture({ timeoutMs: 250 });
|
|
262
|
+
const identityDeadline = process.hrtime.bigint() + 250000000n;
|
|
263
|
+
let identity;
|
|
264
|
+
while (!identity && process.hrtime.bigint() < identityDeadline) {
|
|
265
|
+
if ((child.exitCode !== null && child.exitCode !== undefined) || child.signalCode)
|
|
266
|
+
break;
|
|
267
|
+
identity = capture.observe(sampleWorkerIdentity(pid));
|
|
268
|
+
if (!identity)
|
|
269
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
270
|
+
}
|
|
271
|
+
if (!identity?.bootId || !identity.startTicks || !Number.isSafeInteger(identity.uid)) {
|
|
272
|
+
throw new Error('managed Ralph execution identity unavailable; reconcile uncertain launch');
|
|
273
|
+
}
|
|
274
|
+
managedAdmission = { ...options.managedAdmission,
|
|
275
|
+
execution: { pid, startedAt: `${identity.bootId}:${identity.startTicks}:${identity.uid}` }, processIdentity: identity };
|
|
276
|
+
}
|
|
235
277
|
// Record the loop in our launcher registry (backup to the external-multi-loop-state-manager)
|
|
236
278
|
const launcherRegistry = loadLauncherRegistry(projectRoot);
|
|
237
279
|
launcherRegistry.loops[loopId] = {
|
|
@@ -243,12 +285,14 @@ export async function launchExternalRalph(frameworkRoot, projectRoot, options) {
|
|
|
243
285
|
startedAt: new Date().toISOString(),
|
|
244
286
|
lastUpdate: new Date().toISOString(),
|
|
245
287
|
iteration: 0,
|
|
246
|
-
maxIterations: options.maxIterations || 5,
|
|
288
|
+
maxIterations: options.managedWorker ? 1 : options.maxIterations || 5,
|
|
247
289
|
outputFile,
|
|
248
290
|
sessionStdoutFile,
|
|
249
291
|
sessionStderrFile,
|
|
250
292
|
promptFile,
|
|
251
293
|
provider: options.provider,
|
|
294
|
+
...(managedAdmission ? { managedAdmission } : {}),
|
|
295
|
+
...(options.managedWorker ? { managedWorker: { ...options.managedWorker } } : {}),
|
|
252
296
|
};
|
|
253
297
|
saveLauncherRegistry(projectRoot, launcherRegistry);
|
|
254
298
|
return {
|
|
@@ -257,6 +301,7 @@ export async function launchExternalRalph(frameworkRoot, projectRoot, options) {
|
|
|
257
301
|
pid,
|
|
258
302
|
message: `agent loop started (${loopId}). Check status: aiwg ralph-status`,
|
|
259
303
|
registryPath: getRegistryPath(projectRoot),
|
|
304
|
+
...(managedAdmission ? { execution: managedAdmission.execution } : {}),
|
|
260
305
|
};
|
|
261
306
|
}
|
|
262
307
|
/**
|
|
@@ -341,7 +386,7 @@ export function getLoopStatuses(projectRoot, options = {}) {
|
|
|
341
386
|
entry.stale = true;
|
|
342
387
|
}
|
|
343
388
|
// Auto-clean completed entries if requested
|
|
344
|
-
if (options.autoCleanCompleted && (entry.status === 'completed')) {
|
|
389
|
+
if (options.autoCleanCompleted && !entry.managedAdmission && (entry.status === 'completed')) {
|
|
345
390
|
cleanupCompletedLoop(projectRoot, loopId);
|
|
346
391
|
registryDirty = true;
|
|
347
392
|
continue; // Don't include in statuses
|
|
@@ -372,6 +417,8 @@ export function abortLoop(projectRoot, loopId) {
|
|
|
372
417
|
if (!entry) {
|
|
373
418
|
return { success: false, message: `Loop not found: ${loopId}` };
|
|
374
419
|
}
|
|
420
|
+
if (entry.managedAdmission)
|
|
421
|
+
return { success: false, message: 'Managed loop cancellation requires its current admission generation' };
|
|
375
422
|
if (!isProcessAlive(entry.pid)) {
|
|
376
423
|
entry.status = 'aborted';
|
|
377
424
|
saveLauncherRegistry(projectRoot, registry);
|
|
@@ -391,6 +438,26 @@ export function abortLoop(projectRoot, loopId) {
|
|
|
391
438
|
};
|
|
392
439
|
}
|
|
393
440
|
}
|
|
441
|
+
/** Signal only the birth identity bound to this current managed reservation.
|
|
442
|
+
* Native Ralph exit/status cannot prove descendant termination, so cancellation
|
|
443
|
+
* always leaves its admission reservation uncertain for explicit reconciliation.
|
|
444
|
+
*/
|
|
445
|
+
export async function cancelManagedRalph(frameworkRoot, projectRoot, loopId, binding) {
|
|
446
|
+
const entry = loadLauncherRegistry(projectRoot).loops[loopId];
|
|
447
|
+
const owned = entry?.managedAdmission;
|
|
448
|
+
if (!owned?.execution || !owned.processIdentity || owned.requestId !== binding.requestId || owned.generation !== binding.generation
|
|
449
|
+
|| owned.execution.pid !== binding.execution.pid || owned.execution.startedAt !== binding.execution.startedAt) {
|
|
450
|
+
return { state: 'uncertain', signalled: false };
|
|
451
|
+
}
|
|
452
|
+
const { sampleWorkerIdentity } = await import(join(frameworkRoot, 'tools', 'ralph-external', 'process-monitor.mjs'));
|
|
453
|
+
const identity = sampleWorkerIdentity(owned.execution.pid);
|
|
454
|
+
const expected = owned.processIdentity;
|
|
455
|
+
if (!identity || ['pid', 'uid', 'bootId', 'startTicks', 'executable', 'pgid', 'sessionId']
|
|
456
|
+
.some(key => identity[key] !== expected[key]))
|
|
457
|
+
return { state: 'uncertain', signalled: false };
|
|
458
|
+
const { signalOwnedWorker } = await import(join(frameworkRoot, 'tools', 'ralph-external', 'session-launcher.mjs'));
|
|
459
|
+
return { state: 'uncertain', signalled: signalOwnedWorker(identity, 'SIGTERM') };
|
|
460
|
+
}
|
|
394
461
|
/**
|
|
395
462
|
* Resume an interrupted agent loop
|
|
396
463
|
*/
|
|
@@ -438,6 +505,8 @@ export async function resumeLoop(frameworkRoot, projectRoot, loopId, overrides)
|
|
|
438
505
|
exitCode: EXIT_CODES.USAGE,
|
|
439
506
|
});
|
|
440
507
|
}
|
|
508
|
+
if (entry.managedAdmission)
|
|
509
|
+
throw new Error('Managed loops require policy and admission reconciliation before resume');
|
|
441
510
|
const loopDir = join(registryDir, 'loops', targetLoopId);
|
|
442
511
|
const outputFile = join(loopDir, 'daemon-output.log');
|
|
443
512
|
// Create output file descriptor
|
|
@@ -494,6 +563,9 @@ export function cleanupCompletedLoop(projectRoot, loopId, options = {}) {
|
|
|
494
563
|
const registryDir = getRegistryDir(projectRoot);
|
|
495
564
|
const loopDir = join(registryDir, 'loops', loopId);
|
|
496
565
|
const preserved = [];
|
|
566
|
+
if (loadLauncherRegistry(projectRoot).loops[loopId]?.managedAdmission) {
|
|
567
|
+
return { success: false, message: 'Managed loop artifacts require admission reconciliation before cleanup', preserved };
|
|
568
|
+
}
|
|
497
569
|
// Preserve completion reports before deleting the loop directory
|
|
498
570
|
if (existsSync(loopDir)) {
|
|
499
571
|
try {
|
|
@@ -616,7 +688,7 @@ export function cleanupRegistry(projectRoot, keepDays = 7) {
|
|
|
616
688
|
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1000;
|
|
617
689
|
let cleaned = 0;
|
|
618
690
|
for (const [loopId, entry] of Object.entries(registry.loops)) {
|
|
619
|
-
if (entry.status !== 'running') {
|
|
691
|
+
if (entry.status !== 'running' && !entry.managedAdmission) {
|
|
620
692
|
const lastUpdate = new Date(entry.lastUpdate).getTime();
|
|
621
693
|
if (lastUpdate < cutoff) {
|
|
622
694
|
delete registry.loops[loopId];
|
|
@@ -68,7 +68,7 @@ export const rulesHandler = {
|
|
|
68
68
|
throw new Error('Invalid inventory scope');
|
|
69
69
|
const activation = list('--activation');
|
|
70
70
|
const tier = list('--tier');
|
|
71
|
-
if (activation?.some(value => !['kernel', 'summary', 'bound', 'paths', 'on-demand'].includes(value)))
|
|
71
|
+
if (activation?.some(value => !['core', 'kernel', 'summary', 'bound', 'paths', 'on-demand'].includes(value)))
|
|
72
72
|
throw new Error('Invalid activation filter');
|
|
73
73
|
if (tier?.some(value => !['critical', 'high', 'medium', 'low'].includes(value)))
|
|
74
74
|
throw new Error('Invalid tier filter');
|
|
@@ -11,10 +11,17 @@
|
|
|
11
11
|
import { signalChild } from '../../process/signal-child.mjs';
|
|
12
12
|
import { spawn } from 'child_process';
|
|
13
13
|
import path from 'path';
|
|
14
|
+
import { pathToFileURL } from 'node:url';
|
|
15
|
+
import { Console } from 'node:console';
|
|
16
|
+
import { Writable } from 'node:stream';
|
|
17
|
+
import { writeSync } from 'node:fs';
|
|
18
|
+
// Embedded deployers use process-wide console/environment APIs. Serialize the
|
|
19
|
+
// complete invocation (including import), and restore them even after failure.
|
|
20
|
+
let deploymentQueue = Promise.resolve();
|
|
14
21
|
/**
|
|
15
22
|
* Default script runner implementation
|
|
16
23
|
*
|
|
17
|
-
*
|
|
24
|
+
* Embeds repeatable agent deployment passes; runs other scripts in a child.
|
|
18
25
|
*/
|
|
19
26
|
export class DefaultScriptRunner {
|
|
20
27
|
frameworkRoot;
|
|
@@ -30,12 +37,26 @@ export class DefaultScriptRunner {
|
|
|
30
37
|
*/
|
|
31
38
|
async run(scriptPath, args = [], options = {}) {
|
|
32
39
|
const fullPath = path.join(this.frameworkRoot, scriptPath);
|
|
40
|
+
if (scriptPath === 'tools/agents/deploy-agents.mjs'
|
|
41
|
+
&& process.env.AIWG_DEPLOY_SUBPROCESS !== '1'
|
|
42
|
+
&& options.env?.AIWG_DEPLOY_SUBPROCESS !== '1'
|
|
43
|
+
&& !options.timeout
|
|
44
|
+
&& (!options.cwd || path.resolve(options.cwd) === process.cwd())
|
|
45
|
+
// Other environment overrides can affect module initialization. Keep
|
|
46
|
+
// those callers isolated; AIWG_ROOT is resolved afresh by each pass.
|
|
47
|
+
&& Object.keys(options.env ?? {}).every(key => key === 'AIWG_ROOT')) {
|
|
48
|
+
const invocation = deploymentQueue.then(() => this.runDeployment(fullPath, args, options));
|
|
49
|
+
deploymentQueue = invocation.catch(() => { });
|
|
50
|
+
return invocation;
|
|
51
|
+
}
|
|
33
52
|
return new Promise((resolve) => {
|
|
34
53
|
// When capture mode is enabled, stdout/stderr are piped so that
|
|
35
54
|
// quiet-mode callers can suppress output. When not
|
|
36
55
|
// capturing, stdio: 'inherit' lets subprocess output flow directly to
|
|
37
56
|
// the terminal (verbose mode).
|
|
38
|
-
const stdio = options.capture
|
|
57
|
+
const stdio = options.capture
|
|
58
|
+
? ['pipe', options.stdoutFd ?? 'pipe', 'pipe']
|
|
59
|
+
: 'inherit';
|
|
39
60
|
const child = spawn('node', [fullPath, ...args], {
|
|
40
61
|
stdio,
|
|
41
62
|
cwd: options.cwd || process.cwd(),
|
|
@@ -122,6 +143,56 @@ export class DefaultScriptRunner {
|
|
|
122
143
|
});
|
|
123
144
|
});
|
|
124
145
|
}
|
|
146
|
+
async runDeployment(fullPath, args, options) {
|
|
147
|
+
const previousConsole = globalThis.console;
|
|
148
|
+
const previousRoot = process.env.AIWG_ROOT;
|
|
149
|
+
const stderrLimit = 1024 * 1024;
|
|
150
|
+
const diagnostics = [];
|
|
151
|
+
let diagnosticBytes = 0;
|
|
152
|
+
try {
|
|
153
|
+
if (options.env?.AIWG_ROOT !== undefined)
|
|
154
|
+
process.env.AIWG_ROOT = options.env.AIWG_ROOT;
|
|
155
|
+
if (options.capture) {
|
|
156
|
+
const stdout = new Writable({ write(chunk, _encoding, done) {
|
|
157
|
+
try {
|
|
158
|
+
if (options.stdoutFd !== undefined)
|
|
159
|
+
writeSync(options.stdoutFd, chunk);
|
|
160
|
+
done();
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
done(error);
|
|
164
|
+
}
|
|
165
|
+
} });
|
|
166
|
+
const stderr = new Writable({ write(chunk, _encoding, done) {
|
|
167
|
+
const retained = chunk.subarray(0, stderrLimit - diagnosticBytes);
|
|
168
|
+
if (retained.length) {
|
|
169
|
+
diagnostics.push(Buffer.from(retained));
|
|
170
|
+
diagnosticBytes += retained.length;
|
|
171
|
+
}
|
|
172
|
+
done();
|
|
173
|
+
} });
|
|
174
|
+
globalThis.console = new Console({ stdout, stderr });
|
|
175
|
+
}
|
|
176
|
+
// Runtime loading follows the provider preparation coordinator precedent;
|
|
177
|
+
// the runner still supports arbitrary scripts via its subprocess path.
|
|
178
|
+
const deployer = await import(pathToFileURL(fullPath).href);
|
|
179
|
+
const exitCode = (await deployer.main(args, { capture: options.capture === true })) ?? 0;
|
|
180
|
+
const message = Buffer.concat(diagnostics).toString().trim();
|
|
181
|
+
return exitCode && message ? { exitCode, message } : { exitCode };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
const message = Buffer.concat(diagnostics).toString().trim()
|
|
185
|
+
|| (error instanceof Error ? error.message : String(error));
|
|
186
|
+
return { exitCode: 1, message };
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
globalThis.console = previousConsole;
|
|
190
|
+
if (previousRoot === undefined)
|
|
191
|
+
delete process.env.AIWG_ROOT;
|
|
192
|
+
else
|
|
193
|
+
process.env.AIWG_ROOT = previousRoot;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
125
196
|
}
|
|
126
197
|
/**
|
|
127
198
|
* Create a script runner for the given framework root
|
|
@@ -735,9 +735,11 @@ export async function startServer(opts) {
|
|
|
735
735
|
if (!valid) {
|
|
736
736
|
return c.json({ error: `Invalid register payload: ${errors}` }, 400);
|
|
737
737
|
}
|
|
738
|
-
const
|
|
739
|
-
|
|
740
|
-
|
|
738
|
+
const authHeader = c.req.header('authorization') ?? '';
|
|
739
|
+
const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : '';
|
|
740
|
+
const result = executorRegistry.register(body, token);
|
|
741
|
+
if ('status' in result) {
|
|
742
|
+
return c.json({ error: result.error }, result.status);
|
|
741
743
|
}
|
|
742
744
|
// Emit telemetry (reuse agent.spawn as closest match for executor registration)
|
|
743
745
|
const resp = result;
|
|
@@ -76,6 +76,7 @@ Options:
|
|
|
76
76
|
--manifest <path> Override the discovery manifest path
|
|
77
77
|
--provider-home <path> Override the provider home root (testing/portable homes)
|
|
78
78
|
--codex-root <path> Authorize a shared Codex sessions/export root (repeatable)
|
|
79
|
+
Adds to defaults separately authorized by --provider-home
|
|
79
80
|
--omp-root <path> Explicitly authorize an OMP profile sessions root
|
|
80
81
|
--muse-root <path> Explicitly authorize a Muse Code sessions root
|
|
81
82
|
--dsh-root <path> Explicitly authorize a DeepSeek Harness sessions root
|