@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
package/dist/src/issues/live.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveSensitiveInput } from '../auth/sensitive-input.js';
|
|
2
|
+
import { isInteractive } from '../cli/env.js';
|
|
1
3
|
export class LiveIssueClient {
|
|
2
4
|
options;
|
|
3
5
|
baseUrl;
|
|
@@ -63,24 +65,51 @@ export class LiveIssueClient {
|
|
|
63
65
|
headers['Content-Type'] = 'application/json';
|
|
64
66
|
if (this.options.token)
|
|
65
67
|
headers.Authorization = `Bearer ${this.options.token}`;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
try {
|
|
69
|
+
const response = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
70
|
+
method,
|
|
71
|
+
headers,
|
|
72
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
const text = await response.text().catch(() => '');
|
|
76
|
+
throw new Error(`${this.options.provider} issue API ${method} ${path} failed: ${response.status}${text ? ` ${redactSecrets(text, this.options.token)}` : ''}`);
|
|
77
|
+
}
|
|
78
|
+
const result = await response.json();
|
|
79
|
+
// A server can reflect request credentials in issue fields or comments.
|
|
80
|
+
// Scrub them before they reach local storage or CLI output.
|
|
81
|
+
if (!this.options.token)
|
|
82
|
+
return result;
|
|
83
|
+
const encodedToken = JSON.stringify(this.options.token).slice(1, -1);
|
|
84
|
+
return JSON.parse(JSON.stringify(result).split(encodedToken).join('[REDACTED]'));
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw new Error(redactSecrets(error instanceof Error ? error.message : 'Live issue request failed', this.options.token));
|
|
74
88
|
}
|
|
75
|
-
return response.json();
|
|
76
89
|
}
|
|
77
90
|
}
|
|
78
91
|
export function createLiveIssueClient(options) {
|
|
79
92
|
return new LiveIssueClient({
|
|
80
93
|
...options,
|
|
81
|
-
token: resolveToken(options.provider, options.tokenEnv ?? process.env),
|
|
94
|
+
token: options.token ?? resolveToken(options.provider, options.tokenEnv ?? process.env),
|
|
82
95
|
});
|
|
83
96
|
}
|
|
97
|
+
/** CLI source selection; the synchronous client factory remains available to callers. */
|
|
98
|
+
export async function resolveLiveIssueToken(provider, source = {}, dependencies = {}) {
|
|
99
|
+
const environment = dependencies.environment ?? process.env;
|
|
100
|
+
const isTTY = dependencies.isTTY ?? isInteractive();
|
|
101
|
+
const selected = { ...source, prefix: 'token' };
|
|
102
|
+
const hasSource = selected.interactive || selected.stdin || selected.file !== undefined || selected.store !== undefined || selected.env !== undefined;
|
|
103
|
+
if (!hasSource) {
|
|
104
|
+
// Established behavior: use the provider variable when set, otherwise make
|
|
105
|
+
// unauthenticated requests (public repositories). Prompt only on request.
|
|
106
|
+
const names = provider === 'gitea' ? ['AIWG_GITEA_TOKEN', 'GITEA_TOKEN'] : ['AIWG_GITHUB_TOKEN', 'GITHUB_TOKEN'];
|
|
107
|
+
selected.env = names.find(name => environment[name] !== undefined);
|
|
108
|
+
if (selected.env === undefined)
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return resolveSensitiveInput(selected, { ...dependencies, environment, isTTY });
|
|
112
|
+
}
|
|
84
113
|
export function resolveToken(provider, env) {
|
|
85
114
|
if (provider === 'gitea')
|
|
86
115
|
return env.AIWG_GITEA_TOKEN ?? env.GITEA_TOKEN;
|
|
@@ -148,7 +177,10 @@ function requireString(value, field) {
|
|
|
148
177
|
return value;
|
|
149
178
|
throw new Error(`live issue response missing ${field}`);
|
|
150
179
|
}
|
|
151
|
-
function redactSecrets(value) {
|
|
152
|
-
|
|
180
|
+
function redactSecrets(value, token) {
|
|
181
|
+
const redacted = token ? value.split(token).join('[REDACTED]') : value;
|
|
182
|
+
return redacted
|
|
183
|
+
.replace(/Bearer\s+[^\s"',}]+/gi, 'Bearer [REDACTED]')
|
|
184
|
+
.replace(/(token|authorization|password|secret)["':=\s]+[^\s"',}]+/gi, '$1=[REDACTED]');
|
|
153
185
|
}
|
|
154
186
|
//# sourceMappingURL=live.js.map
|
package/dist/src/jobs/flow.js
CHANGED
|
@@ -2,6 +2,7 @@ import { promises as fs } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { load as loadYaml } from 'js-yaml';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
+
import { integer, url } from '../schema/zod-validation.mjs';
|
|
5
6
|
import { JOB_API_VERSION, JOB_KIND } from './types.js';
|
|
6
7
|
const relativeFile = z.string().min(1).refine(value => {
|
|
7
8
|
if (path.isAbsolute(value))
|
|
@@ -12,51 +13,51 @@ const relativeFile = z.string().min(1).refine(value => {
|
|
|
12
13
|
const absolutePath = z.string().min(1)
|
|
13
14
|
.refine(path.isAbsolute, 'must be an absolute path')
|
|
14
15
|
.refine(value => path.resolve(value) !== path.parse(path.resolve(value)).root, 'must not be a filesystem root');
|
|
15
|
-
const httpsOrigin =
|
|
16
|
+
const httpsOrigin = url().refine(value => new URL(value).protocol === 'https:', 'must use https');
|
|
16
17
|
const accountName = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_.@:-]{0,127}$/u);
|
|
17
|
-
export const externalJobFlowSchema = z.
|
|
18
|
+
export const externalJobFlowSchema = z.strictObject({
|
|
18
19
|
apiVersion: z.literal(JOB_API_VERSION),
|
|
19
20
|
kind: z.literal(JOB_KIND),
|
|
20
|
-
metadata: z.
|
|
21
|
+
metadata: z.strictObject({
|
|
21
22
|
name: z.string().regex(/^[a-z][a-z0-9-]{0,62}$/u),
|
|
22
23
|
revision: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u),
|
|
23
|
-
})
|
|
24
|
-
spec: z.
|
|
25
|
-
trigger: z.
|
|
26
|
-
executor: z.
|
|
24
|
+
}),
|
|
25
|
+
spec: z.strictObject({
|
|
26
|
+
trigger: z.strictObject({ type: z.literal('external') }),
|
|
27
|
+
executor: z.strictObject({
|
|
27
28
|
provider: z.literal('codex'),
|
|
28
29
|
mode: z.literal('exec'),
|
|
29
30
|
workspace: absolutePath,
|
|
30
31
|
prompt: relativeFile,
|
|
31
32
|
resultSchema: relativeFile,
|
|
32
33
|
binary: absolutePath,
|
|
33
|
-
})
|
|
34
|
-
workItem: z.
|
|
34
|
+
}),
|
|
35
|
+
workItem: z.strictObject({
|
|
35
36
|
provider: z.literal('gitea'),
|
|
36
|
-
baseUrl:
|
|
37
|
+
baseUrl: url().refine(value => new URL(value).protocol === 'https:', 'must use https'),
|
|
37
38
|
repository: z.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u),
|
|
38
39
|
tokenFile: absolutePath,
|
|
39
40
|
eligibleLabels: z.array(z.string().min(1)).min(1),
|
|
40
|
-
claimTtlSeconds:
|
|
41
|
-
claimSettleMs:
|
|
42
|
-
})
|
|
43
|
-
approval: z.
|
|
41
|
+
claimTtlSeconds: integer().min(30).max(86400).optional(),
|
|
42
|
+
claimSettleMs: integer().min(100).max(30000).optional(),
|
|
43
|
+
}),
|
|
44
|
+
approval: z.strictObject({
|
|
44
45
|
required: z.boolean().optional(),
|
|
45
46
|
label: z.string().min(1).optional(),
|
|
46
|
-
}).
|
|
47
|
-
security: z.
|
|
47
|
+
}).optional(),
|
|
48
|
+
security: z.strictObject({
|
|
48
49
|
allowedOrigins: z.array(httpsOrigin).min(1),
|
|
49
50
|
allowedAccounts: z.array(accountName).min(1),
|
|
50
51
|
approvedAttachmentRoots: z.array(absolutePath),
|
|
51
52
|
sensitiveValueFiles: z.array(absolutePath).optional(),
|
|
52
|
-
})
|
|
53
|
-
completion: z.
|
|
53
|
+
}),
|
|
54
|
+
completion: z.strictObject({
|
|
54
55
|
require: z.array(z.enum([
|
|
55
56
|
'external-result-url', 'issue-comment', 'idempotency-key', 'verification',
|
|
56
57
|
])).min(1),
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
}).
|
|
58
|
+
}),
|
|
59
|
+
}),
|
|
60
|
+
}).superRefine((flow, ctx) => {
|
|
60
61
|
const workspace = path.resolve(flow.spec.executor.workspace);
|
|
61
62
|
const within = (candidate) => {
|
|
62
63
|
const relative = path.relative(workspace, path.resolve(candidate));
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
/** Activation checks within the existing lint runner, not a delivery selector. */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
1
4
|
import { loadLocalCapabilityEntries, resolveRuleBindingTarget } from '../artifacts/query-engine.js';
|
|
2
|
-
import { parseRuleFrontmatter, RULE_BINDING_TYPES } from '../rules/activation.mjs';
|
|
5
|
+
import { parseRuleFrontmatter, RULE_BINDING_TYPES, coreBodyPath, validateCoreBody } from '../rules/activation.mjs';
|
|
3
6
|
export const ruleActivationRuleset = {
|
|
4
7
|
id: 'rule-activation', name: 'Rule activation', framework: 'core', version: '1.0.0',
|
|
5
8
|
description: 'Validate rule and behavior activation contracts and exact indexed bindings',
|
|
@@ -10,17 +13,29 @@ export const ruleActivationRuleset = {
|
|
|
10
13
|
checks: [{ type: 'rule-activation' }],
|
|
11
14
|
}],
|
|
12
15
|
};
|
|
13
|
-
export function lintRuleActivation(content, file, projectRoot, entries) {
|
|
14
|
-
//
|
|
15
|
-
if (/^(?:RULES-INDEX|RULES-ONDEMAND)\.md$/.test(file.split('/').pop()))
|
|
16
|
+
export function lintRuleActivation(content, file, projectRoot, entries, absolutePath) {
|
|
17
|
+
// Directory documentation and generated indexes are not authored rules.
|
|
18
|
+
if (/^(?:README|RULES-INDEX|RULES-ONDEMAND)\.md$/.test(file.split('/').pop()))
|
|
16
19
|
return [];
|
|
20
|
+
// <rule>.core.md is a delivery body (#3450), validated through its owning rule.
|
|
21
|
+
if (/\.core\.md$/.test(file))
|
|
22
|
+
return [];
|
|
23
|
+
const shipped = /(?:^|\/)agentic\/code\//.test((absolutePath ?? path.resolve(projectRoot, file)).replaceAll('\\', '/'));
|
|
17
24
|
const result = parseRuleFrontmatter(content);
|
|
18
25
|
const diagnostics = result.diagnostics.map(item => ({
|
|
19
26
|
ruleId: 'rules/activation', ruleName: 'Rule activation contract',
|
|
20
|
-
file, severity: item.severity, message: item.message,
|
|
27
|
+
file, severity: item.code === 'missing-activation' && shipped ? 'error' : item.severity, message: item.message,
|
|
21
28
|
}));
|
|
22
29
|
if (!result.rule)
|
|
23
30
|
return diagnostics;
|
|
31
|
+
if (result.rule.activation === 'core') {
|
|
32
|
+
const body = coreBodyPath(absolutePath ?? (path.isAbsolute(file) ? file : path.resolve(projectRoot, file)));
|
|
33
|
+
const problems = fs.existsSync(body)
|
|
34
|
+
? validateCoreBody(fs.readFileSync(body, 'utf8').trim(), path.basename(body))
|
|
35
|
+
: [`${path.basename(body)}: activation core requires a compact body file beside the rule`];
|
|
36
|
+
for (const message of problems)
|
|
37
|
+
diagnostics.push({ ruleId: 'rules/activation', ruleName: 'Rule activation contract', file, severity: 'error', message });
|
|
38
|
+
}
|
|
24
39
|
const bindings = result.rule.bound_to;
|
|
25
40
|
if (!Object.values(bindings).some(list => list.length > 0))
|
|
26
41
|
return diagnostics;
|
package/dist/src/lint/runner.js
CHANGED
|
@@ -563,7 +563,7 @@ async function runRule(rule, targetDir, allFiles, referenceIndex, projectRoot, a
|
|
|
563
563
|
if (check.type === 'id-unique')
|
|
564
564
|
continue; // Already handled
|
|
565
565
|
if (check.type === 'rule-activation') {
|
|
566
|
-
diagnostics.push(...lintRuleActivation(content, file, projectRoot, artifactEntries));
|
|
566
|
+
diagnostics.push(...lintRuleActivation(content, file, projectRoot, artifactEntries, absPath));
|
|
567
567
|
continue;
|
|
568
568
|
}
|
|
569
569
|
const checkDiagnostics = runCheck(check, content, frontmatter, file, targetDir, allFiles, referenceIndex, projectRoot);
|
|
@@ -9,6 +9,7 @@ import { access, chmod, mkdir, mkdtemp, readFile, rename, rm, writeFile, } from
|
|
|
9
9
|
import { existsSync } from 'node:fs';
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
+
import { resolveSensitiveInput } from '../auth/sensitive-input.js';
|
|
12
13
|
import { setPackageEntry } from '../packages/package-registry.js';
|
|
13
14
|
import { discoverInstallablePackage } from '../packages/package-discovery.js';
|
|
14
15
|
import { parseTrustRoot, sha256 as artifactSha256, } from '../security/artifact-trust.js';
|
|
@@ -236,7 +237,13 @@ export async function verifyIndexedPackage(options) {
|
|
|
236
237
|
});
|
|
237
238
|
return { verification, receipt, entry };
|
|
238
239
|
}
|
|
239
|
-
export async function publishLocalPackage(options) {
|
|
240
|
+
export async function publishLocalPackage(options, sensitiveDependencies = {}) {
|
|
241
|
+
const privateKey = await resolveSensitiveInput({
|
|
242
|
+
...options.keyInput,
|
|
243
|
+
prefix: 'key',
|
|
244
|
+
file: options.keyInput?.file ?? options.privateKeyPath,
|
|
245
|
+
multiline: true,
|
|
246
|
+
}, sensitiveDependencies);
|
|
240
247
|
const sourceDir = path.resolve(options.sourceDir);
|
|
241
248
|
const discovered = await discoverInstallablePackage(sourceDir, options.packageSelector);
|
|
242
249
|
const unsigned = await createProvenanceEnvelope({
|
|
@@ -248,12 +255,17 @@ export async function publishLocalPackage(options) {
|
|
|
248
255
|
publisher: options.publisher,
|
|
249
256
|
sequence: options.sequence,
|
|
250
257
|
});
|
|
251
|
-
const privateKey = await readFile(path.resolve(options.privateKeyPath), 'utf8');
|
|
252
258
|
const publicKey = options.publicKeyPath ? await readFile(path.resolve(options.publicKeyPath), 'utf8') : undefined;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
259
|
+
let envelope;
|
|
260
|
+
try {
|
|
261
|
+
envelope = signProvenanceEnvelope(unsigned, privateKey, {
|
|
262
|
+
keyId: options.keyId,
|
|
263
|
+
publicKeyPem: publicKey,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
throw new Error('Marketplace signing failed; check the Ed25519 private key and public-key options.');
|
|
268
|
+
}
|
|
257
269
|
const lock = createPackageLock(envelope, envelope.publication.publishedAt);
|
|
258
270
|
const fortemi = await buildFortemiEnvelopeShard(envelope);
|
|
259
271
|
const receipt = createOperationReceipt({
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @implements #2009
|
|
9
9
|
*/
|
|
10
10
|
import { execFile } from 'node:child_process';
|
|
11
|
+
import { helperEnvironment } from '../process/cli-command.mjs';
|
|
11
12
|
import { createHash, createPrivateKey, createPublicKey, sign as cryptoSign, verify as cryptoVerify, } from 'node:crypto';
|
|
12
13
|
import { lstat, readFile, readdir } from 'node:fs/promises';
|
|
13
14
|
import path from 'node:path';
|
|
@@ -157,7 +158,7 @@ async function git(cwd, args) {
|
|
|
157
158
|
cwd,
|
|
158
159
|
encoding: 'utf8',
|
|
159
160
|
timeout: 120_000,
|
|
160
|
-
env: { ...
|
|
161
|
+
env: { ...helperEnvironment(), GIT_TERMINAL_PROMPT: '0' },
|
|
161
162
|
});
|
|
162
163
|
return stdout.trim();
|
|
163
164
|
}
|
|
@@ -166,7 +167,7 @@ async function gitBytes(cwd, args) {
|
|
|
166
167
|
cwd,
|
|
167
168
|
encoding: 'buffer',
|
|
168
169
|
timeout: 120_000,
|
|
169
|
-
env: { ...
|
|
170
|
+
env: { ...helperEnvironment(), GIT_TERMINAL_PROMPT: '0' },
|
|
170
171
|
});
|
|
171
172
|
return stdout;
|
|
172
173
|
}
|
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @implements #892
|
|
16
16
|
*/
|
|
17
|
+
import { readPrivateValueFile } from '../../auth/sensitive-input.js';
|
|
17
18
|
import { signalChild } from '../../process/signal-child.mjs';
|
|
18
|
-
import {
|
|
19
|
+
import { helperEnvironment, HELPER_ENV_ALLOWLIST, DESKTOP_HELPER_ENV_ALLOWLIST } from '../../process/cli-command.mjs';
|
|
20
|
+
import { readFile, mkdir, symlink, access, readdir, chmod } from 'fs/promises';
|
|
19
21
|
import { join } from 'path';
|
|
20
22
|
import { homedir } from 'os';
|
|
21
|
-
import { existsSync
|
|
23
|
+
import { existsSync } from 'fs';
|
|
22
24
|
import { spawn, spawnSync } from 'child_process';
|
|
23
25
|
import { boundedSpawnSync, resolveSyncProcessTimeoutMs } from '../../process/bounded-child-process.mjs';
|
|
24
26
|
import { isInteractive } from '../../cli/env.js';
|
|
@@ -228,73 +230,9 @@ function envWithoutSecretValue(base, envVarName, secretValue) {
|
|
|
228
230
|
}
|
|
229
231
|
return result;
|
|
230
232
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Read an API key from a private file (#3062 go/no-go review, blocker 1C):
|
|
233
|
-
* `--api-key-file <path>` reads the key from disk instead of an
|
|
234
|
-
* environment variable, so a file that does not meet the same bar the
|
|
235
|
-
* decision ledger's own file writer enforces
|
|
236
|
-
* (`src/decision/ledger.ts`'s `openLedgerFileForAppend`) is refused rather
|
|
237
|
-
* than silently trusted. This mirrors that check for a read instead of a
|
|
238
|
-
* write — there is no already-exported helper at this layer to reuse (the
|
|
239
|
-
* ledger's checks are private to that module and tied to its own
|
|
240
|
-
* create-if-missing write path), so this re-implements the same checks for
|
|
241
|
-
* a read: never follow a symlink; the open file descriptor must resolve to
|
|
242
|
-
* a regular file with exactly one hard link; and, on POSIX, must be owned
|
|
243
|
-
* by the current user with no group/other permission bits. The file's
|
|
244
|
-
* contents are returned trimmed; no error message here ever includes them.
|
|
245
|
-
*/
|
|
233
|
+
/** Backward-compatible MCP export; the validation is shared by all input commands. */
|
|
246
234
|
async function readApiKeyFromFile(filePath) {
|
|
247
|
-
|
|
248
|
-
const pre = await lstat(filePath);
|
|
249
|
-
if (pre.isSymbolicLink()) {
|
|
250
|
-
throw new Error(`--api-key-file: "${filePath}" is a symlink; refusing to follow it.`);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
catch (error) {
|
|
254
|
-
if (error.code === 'ENOENT') {
|
|
255
|
-
throw new Error(`--api-key-file: "${filePath}" does not exist.`);
|
|
256
|
-
}
|
|
257
|
-
if (error instanceof Error && error.message.startsWith('--api-key-file:'))
|
|
258
|
-
throw error;
|
|
259
|
-
throw new Error(`--api-key-file: cannot stat "${filePath}": ${error.message}`);
|
|
260
|
-
}
|
|
261
|
-
const hasNoFollow = typeof constants.O_NOFOLLOW === 'number';
|
|
262
|
-
const flags = constants.O_RDONLY | (hasNoFollow ? constants.O_NOFOLLOW : 0);
|
|
263
|
-
let handle;
|
|
264
|
-
try {
|
|
265
|
-
handle = await open(filePath, flags);
|
|
266
|
-
}
|
|
267
|
-
catch (error) {
|
|
268
|
-
const code = error.code;
|
|
269
|
-
if (code === 'ELOOP')
|
|
270
|
-
throw new Error(`--api-key-file: "${filePath}" is a symlink; refusing to follow it.`);
|
|
271
|
-
if (code === 'ENOENT')
|
|
272
|
-
throw new Error(`--api-key-file: "${filePath}" does not exist.`);
|
|
273
|
-
throw new Error(`--api-key-file: cannot open "${filePath}": ${error.message}`);
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
const stat = await handle.stat();
|
|
277
|
-
if (!stat.isFile()) {
|
|
278
|
-
throw new Error(`--api-key-file: "${filePath}" is not a regular file.`);
|
|
279
|
-
}
|
|
280
|
-
if (stat.nlink !== 1) {
|
|
281
|
-
throw new Error(`--api-key-file: "${filePath}" has more than one hard link; refusing to read it.`);
|
|
282
|
-
}
|
|
283
|
-
if (process.platform !== 'win32') {
|
|
284
|
-
const uid = typeof process.getuid === 'function' ? process.getuid() : null;
|
|
285
|
-
if (uid !== null && stat.uid !== uid) {
|
|
286
|
-
throw new Error(`--api-key-file: "${filePath}" is not owned by the current user.`);
|
|
287
|
-
}
|
|
288
|
-
if ((stat.mode & 0o077) !== 0) {
|
|
289
|
-
throw new Error(`--api-key-file: "${filePath}" must not be readable or writable by group or other ` +
|
|
290
|
-
'(chmod 600 it).');
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return (await handle.readFile({ encoding: 'utf-8' })).trim();
|
|
294
|
-
}
|
|
295
|
-
finally {
|
|
296
|
-
await handle.close();
|
|
297
|
-
}
|
|
235
|
+
return readPrivateValueFile(filePath, '--api-key-file');
|
|
298
236
|
}
|
|
299
237
|
/**
|
|
300
238
|
* Async, credential-safe launch of `codex login --with-api-key` (#3062
|
|
@@ -320,17 +258,37 @@ function spawnCodexLoginWithApiKey(apiKey, env) {
|
|
|
320
258
|
return new Promise((resolve) => {
|
|
321
259
|
const child = spawn('codex', ['login', '--with-api-key'], {
|
|
322
260
|
env,
|
|
323
|
-
stdio: ['pipe', '
|
|
261
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
324
262
|
});
|
|
325
263
|
let settled = false;
|
|
326
264
|
let timer;
|
|
265
|
+
const stdout = [];
|
|
266
|
+
const stderr = [];
|
|
267
|
+
let outputBytes = 0;
|
|
268
|
+
// Buffer through close so a credential split between chunks cannot escape
|
|
269
|
+
// redaction. The combined cap bounds both memory and forwarded diagnostics.
|
|
270
|
+
const collect = (target, chunk) => {
|
|
271
|
+
if (settled)
|
|
272
|
+
return;
|
|
273
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
274
|
+
outputBytes += buffer.length;
|
|
275
|
+
if (outputBytes > 1024 * 1024) {
|
|
276
|
+
settle({ status: null, signal: 'SIGKILL', error: new Error('codex login output exceeded the 1 MiB limit.') });
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
target.push(buffer);
|
|
280
|
+
};
|
|
281
|
+
const onStdout = (chunk) => collect(stdout, chunk);
|
|
282
|
+
const onStderr = (chunk) => collect(stderr, chunk);
|
|
283
|
+
child.stdout?.on('data', onStdout);
|
|
284
|
+
child.stderr?.on('data', onStderr);
|
|
327
285
|
// #3062 go/no-go review, blocker 2: stdin error, write completion,
|
|
328
|
-
// child 'error', child '
|
|
286
|
+
// child 'error', child 'close', and the deadline all funnel through this
|
|
329
287
|
// one function, which settles exactly once, always clears the timer and
|
|
330
288
|
// removes every listener this call added, and kills the child if it is
|
|
331
289
|
// still alive on a failing settlement (a running process on the
|
|
332
290
|
// timeout path; a process that may still be running on an unexpected
|
|
333
|
-
// stdin-write error). The '
|
|
291
|
+
// stdin-write error). The 'close' path never reaches the kill — by the
|
|
334
292
|
// time that event fires the child has already exited.
|
|
335
293
|
const settle = (result) => {
|
|
336
294
|
if (settled)
|
|
@@ -340,13 +298,23 @@ function spawnCodexLoginWithApiKey(apiKey, env) {
|
|
|
340
298
|
clearTimeout(timer);
|
|
341
299
|
child.stdin?.removeListener('error', onStdinError);
|
|
342
300
|
child.removeListener('error', onChildError);
|
|
343
|
-
child.removeListener('
|
|
301
|
+
child.removeListener('close', onClose);
|
|
302
|
+
child.stdout?.removeListener('data', onStdout);
|
|
303
|
+
child.stderr?.removeListener('data', onStderr);
|
|
304
|
+
child.stdout?.destroy();
|
|
305
|
+
child.stderr?.destroy();
|
|
344
306
|
if (result.error && child.exitCode === null && child.signalCode === null) {
|
|
345
307
|
try {
|
|
346
308
|
signalChild(child, 'SIGKILL');
|
|
347
309
|
}
|
|
348
310
|
catch { /* already gone */ }
|
|
349
311
|
}
|
|
312
|
+
// On a failed/oversized stream, suppress buffered fragments entirely:
|
|
313
|
+
// the missing remainder might contain the rest of a credential.
|
|
314
|
+
if (!result.error) {
|
|
315
|
+
process.stdout.write(Buffer.concat(stdout).toString('utf8').split(apiKey).join('[redacted]'));
|
|
316
|
+
process.stderr.write(Buffer.concat(stderr).toString('utf8').split(apiKey).join('[redacted]'));
|
|
317
|
+
}
|
|
350
318
|
resolve(result);
|
|
351
319
|
};
|
|
352
320
|
timer = setTimeout(() => {
|
|
@@ -358,15 +326,15 @@ function spawnCodexLoginWithApiKey(apiKey, env) {
|
|
|
358
326
|
}, boundMs);
|
|
359
327
|
const onChildError = (err) => settle({ status: null, signal: null, error: err });
|
|
360
328
|
child.on('error', onChildError);
|
|
361
|
-
const
|
|
362
|
-
child.on('
|
|
329
|
+
const onClose = (code, signal) => settle({ status: code, signal });
|
|
330
|
+
child.on('close', onClose);
|
|
363
331
|
// A child that exits (or closes its read end) before reading stdin
|
|
364
332
|
// raises EPIPE/ECONNRESET on the *stdin stream*, not on the child
|
|
365
333
|
// object — `child.on('error', ...)` above never sees it, so without
|
|
366
334
|
// this listener it is an unhandled 'error' event, which Node turns into
|
|
367
335
|
// an uncaught exception. Installed before the write/end below, per the
|
|
368
336
|
// review. EPIPE/ECONNRESET specifically mean "the child already went
|
|
369
|
-
// away"; the already-firing (or about-to-fire) '
|
|
337
|
+
// away"; the already-firing (or about-to-fire) 'close' event carries the
|
|
370
338
|
// real, non-secret result, so this swallows exactly those two codes and
|
|
371
339
|
// lets settle() happen there instead. Anything else is a genuine,
|
|
372
340
|
// unexpected stdin failure and is itself the settling error.
|
|
@@ -413,7 +381,9 @@ export async function loginInProfile(profile, options = {}) {
|
|
|
413
381
|
await ensureRuntimeHome(profile);
|
|
414
382
|
const rtHome = runtimeHomePath(profile);
|
|
415
383
|
const env = {
|
|
416
|
-
...process.env,
|
|
384
|
+
...helperEnvironment(process.env, [
|
|
385
|
+
...HELPER_ENV_ALLOWLIST, ...DESKTOP_HELPER_ENV_ALLOWLIST, 'NODE_EXTRA_CA_CERTS',
|
|
386
|
+
]),
|
|
417
387
|
HOME: rtHome,
|
|
418
388
|
CODEX_HOME: rtHome,
|
|
419
389
|
AIWG_CONFIG: resolveUserConfigDir(),
|