arkgate 2.12.0 → 2.13.0
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/CHANGELOG.md +83 -0
- package/README.md +55 -31
- package/bin/ark-check.mjs +95 -36
- package/bin/ark-mcp.mjs +11 -5
- package/bin/ark-shared.mjs +88 -56
- package/bin/ark.mjs +45 -10
- package/bin/lib/agent-gates.mjs +12 -0
- package/bin/lib/architecture-scan.mjs +8 -0
- package/bin/lib/ci-and-commands.mjs +9 -3
- package/bin/lib/codex-home.mjs +7 -0
- package/bin/lib/config-contract.mjs +331 -0
- package/bin/lib/doctor-plan.mjs +43 -16
- package/bin/lib/enforcement-profiles.mjs +97 -0
- package/bin/lib/host-support-matrix.mjs +77 -0
- package/bin/lib/install-migrate.mjs +45 -14
- package/bin/lib/mcp-adoption.mjs +35 -3
- package/bin/lib/open-html.mjs +75 -0
- package/bin/lib/presets.mjs +3 -2
- package/bin/lib/safety-diagnostics.mjs +31 -11
- package/bin/lib/skill-install.mjs +64 -0
- package/bin/lib/ts-resolve.mjs +2 -1
- package/bin/lib/weakest-link.mjs +417 -0
- package/bin/lib/write-path-capabilities.mjs +182 -0
- package/bin/lib/write-path-detect.mjs +62 -99
- package/dist/configContract-iBLxx5Tz.d.cts +53 -0
- package/dist/configContract-iBLxx5Tz.d.ts +53 -0
- package/dist/eslint/index.cjs +375 -13
- package/dist/eslint/index.cjs.map +1 -1
- package/dist/eslint/index.d.cts +30 -20
- package/dist/eslint/index.d.ts +30 -20
- package/dist/eslint/index.js +375 -13
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.cjs +723 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -5
- package/dist/index.d.ts +95 -5
- package/dist/index.js +716 -61
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +150 -42
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +2 -1
- package/dist/nestjs/index.d.ts +2 -1
- package/dist/nestjs/index.js +150 -42
- package/dist/nestjs/index.js.map +1 -1
- package/dist/runtime/index.cjs +723 -61
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +3 -2
- package/dist/runtime/index.d.ts +3 -2
- package/dist/runtime/index.js +716 -61
- package/dist/runtime/index.js.map +1 -1
- package/dist/{types-BZ17b9i5.d.cts → types-BxBwnBpC.d.cts} +9 -36
- package/dist/{types-BZ17b9i5.d.ts → types-Wcs_l1_J.d.ts} +9 -36
- package/docs/agent-guide.md +32 -20
- package/docs/ai-gates.md +53 -18
- package/docs/configuration.md +97 -0
- package/docs/enthusiast/README.md +3 -3
- package/docs/enthusiast/how-to-agent-gates.md +7 -3
- package/docs/migrate-from-ark-runtime-kernel.md +3 -0
- package/docs/package-surface.md +14 -9
- package/docs/production-hardening.md +15 -2
- package/docs/threat-model.md +65 -0
- package/docs/typescript-support.md +3 -3
- package/package.json +15 -2
- package/schemas/ark.config.schema.json +750 -0
- package/server.json +2 -2
- package/templates/hooks/pre-commit-ark +37 -0
- package/templates/skills/ark-coverage.md +2 -2
- package/templates/skills/ark-runtime.md +8 -5
- package/templates/skills/ark-upgrade.md +36 -16
- package/tests/fixtures/ts-consumer/ark.config.json +2 -0
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
codexPromptsDir,
|
|
15
15
|
codexConfigPath,
|
|
16
16
|
isTempOrUpgradeRoot,
|
|
17
|
+
usesDefaultCodexHome,
|
|
17
18
|
wireCodexMcp,
|
|
18
19
|
} from './codex-home.mjs';
|
|
19
20
|
import {
|
|
@@ -40,9 +41,7 @@ import {
|
|
|
40
41
|
checkArchitectureScriptSnippet,
|
|
41
42
|
} from './ci-and-commands.mjs';
|
|
42
43
|
import {
|
|
43
|
-
normalizeToolsList,
|
|
44
44
|
resolveTools,
|
|
45
|
-
KNOWN_TOOLS,
|
|
46
45
|
SKILL_TOOL_TARGETS,
|
|
47
46
|
skillTemplates,
|
|
48
47
|
stampSkill,
|
|
@@ -59,6 +58,11 @@ import {
|
|
|
59
58
|
PREFERRED_CHECK_BIN,
|
|
60
59
|
RUNNER_BEFORE_ARK,
|
|
61
60
|
} from './mcp-adoption.mjs';
|
|
61
|
+
import {
|
|
62
|
+
hasHardWriteHook,
|
|
63
|
+
validateHardWriteRequest,
|
|
64
|
+
validateSelectedTools,
|
|
65
|
+
} from './enforcement-profiles.mjs';
|
|
62
66
|
|
|
63
67
|
export function staleRunnerGateFiles(root) {
|
|
64
68
|
const want = execRunner(root);
|
|
@@ -179,17 +183,35 @@ export function runInstallAgentGates(args) {
|
|
|
179
183
|
return;
|
|
180
184
|
}
|
|
181
185
|
if (args.tools != null) {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (list.length === 0 || unknown.length > 0) {
|
|
186
|
-
console.error(
|
|
187
|
-
`--tools expects a comma-separated subset of: ${KNOWN_TOOLS.join(', ')}` +
|
|
188
|
-
(unknown.length > 0 ? ` (unknown: ${unknown.join(', ')})` : '')
|
|
189
|
-
);
|
|
186
|
+
const selection = validateSelectedTools(args.tools);
|
|
187
|
+
if (!selection.ok) {
|
|
188
|
+
console.error(selection.error);
|
|
190
189
|
process.exitCode = 2;
|
|
191
190
|
return;
|
|
192
191
|
}
|
|
192
|
+
args.tools = selection.tools;
|
|
193
|
+
}
|
|
194
|
+
const writeRequest = validateHardWriteRequest({
|
|
195
|
+
root,
|
|
196
|
+
host: args.requireWriteHook,
|
|
197
|
+
tools: args.tools,
|
|
198
|
+
force: args.force,
|
|
199
|
+
});
|
|
200
|
+
if (!writeRequest.ok) {
|
|
201
|
+
console.error(writeRequest.error);
|
|
202
|
+
process.exitCode = 2;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (writeRequest.host && args.tools == null) {
|
|
206
|
+
args.tools = writeRequest.tools;
|
|
207
|
+
}
|
|
208
|
+
if (writeRequest.host && args.skillsOnly && !hasHardWriteHook(root, writeRequest.host)) {
|
|
209
|
+
console.error(
|
|
210
|
+
`--skills-only cannot install the requested ${writeRequest.host} hard-write hook. ` +
|
|
211
|
+
'Remove --skills-only or omit --require-write-hook.'
|
|
212
|
+
);
|
|
213
|
+
process.exitCode = 2;
|
|
214
|
+
return;
|
|
193
215
|
}
|
|
194
216
|
const pm = packageManager(root);
|
|
195
217
|
const hasCheckScript = hasCheckArchitectureScript(root);
|
|
@@ -370,16 +392,17 @@ export function runInstallAgentGates(args) {
|
|
|
370
392
|
// without a manual copy step.
|
|
371
393
|
//
|
|
372
394
|
// Skip home-dir mutation when the project root is a temp/upgrade scratch *and*
|
|
373
|
-
// CODEX_HOME
|
|
374
|
-
//
|
|
375
|
-
//
|
|
395
|
+
// CODEX_HOME resolves to the default (~/.codex). Codex itself may export that exact
|
|
396
|
+
// path, so presence alone does not prove isolation. Fixtures must not rewrite the
|
|
397
|
+
// developer's real config. A genuinely redirected CODEX_HOME or explicit
|
|
398
|
+
// --codex-home still wires as requested.
|
|
376
399
|
let codexMcp = null;
|
|
377
400
|
const wantCodexWire = tools.has('codex') || args.codexHome;
|
|
378
401
|
const skipHomeWire =
|
|
379
402
|
wantCodexWire &&
|
|
380
403
|
isTempOrUpgradeRoot(root) &&
|
|
381
404
|
!args.codexHome &&
|
|
382
|
-
|
|
405
|
+
usesDefaultCodexHome();
|
|
383
406
|
if (wantCodexWire && !skipHomeWire) {
|
|
384
407
|
codexMcp = wireCodexMcp(root, args.force);
|
|
385
408
|
console.log('');
|
|
@@ -416,6 +439,14 @@ export function runInstallAgentGates(args) {
|
|
|
416
439
|
`\nWarning: Codex home MCP registration failed (${codexMcp.message}). Repo gates were written; fix ~/.codex access or re-run with --tools codex --force.`
|
|
417
440
|
);
|
|
418
441
|
}
|
|
442
|
+
if (writeRequest.host) {
|
|
443
|
+
if (!hasHardWriteHook(root, writeRequest.host)) {
|
|
444
|
+
console.error(`\nFailed to verify the ${writeRequest.host} hard-write hook after install.`);
|
|
445
|
+
process.exitCode = 1;
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
console.log(`\nHard-write hook verified for ${writeRequest.host}.`);
|
|
449
|
+
}
|
|
419
450
|
console.log('');
|
|
420
451
|
console.log('Next steps:');
|
|
421
452
|
console.log(' 1. Review the generated files and commit the ones that match your tools.');
|
package/bin/lib/mcp-adoption.mjs
CHANGED
|
@@ -9,8 +9,9 @@ import { CORE_LAYER_NAMES } from './core-layers.mjs';
|
|
|
9
9
|
import { falseGreenAdoptionGap } from './field-install.mjs';
|
|
10
10
|
import { assessCodexHomeMcp, codexConfigPath } from './codex-home.mjs';
|
|
11
11
|
import { detectWritePathCapabilities } from './write-path-detect.mjs';
|
|
12
|
-
import { skillTemplateNames } from './skill-install.mjs';
|
|
12
|
+
import { detectActiveAgentHost, skillTemplateNames } from './skill-install.mjs';
|
|
13
13
|
import { detectDeployPathQuality } from './deploy-path.mjs';
|
|
14
|
+
import { collectWeakestLinkGaps } from './weakest-link.mjs';
|
|
14
15
|
|
|
15
16
|
export { detectDeployPathQuality };
|
|
16
17
|
|
|
@@ -195,10 +196,22 @@ export function collectAdoptionGaps(root, config, coverage) {
|
|
|
195
196
|
scopedTable: assessed.scopedTable,
|
|
196
197
|
};
|
|
197
198
|
if (assessed.gap) {
|
|
199
|
+
// Temp/upgrade MCP roots stay urgent (fail-closed). Non-temp Codex-home debt
|
|
200
|
+
// is deferred only when the session host is known and is not Codex
|
|
201
|
+
// (Grok/Claude/Cursor…). Unknown host (CI/plain shell) keeps original severity.
|
|
202
|
+
const tempUrgent = Boolean(assessed.tempPath);
|
|
203
|
+
const activeHost = detectActiveAgentHost();
|
|
204
|
+
const deferred =
|
|
205
|
+
!tempUrgent && activeHost != null && activeHost !== 'codex';
|
|
206
|
+
const severity = deferred ? 'info' : assessed.gap.severity;
|
|
207
|
+
const message = deferred
|
|
208
|
+
? `Deferred (fix when using Codex): ${assessed.gap.message}`
|
|
209
|
+
: assessed.gap.message;
|
|
198
210
|
gaps.push({
|
|
199
211
|
id: assessed.gap.id,
|
|
200
|
-
severity
|
|
201
|
-
|
|
212
|
+
severity,
|
|
213
|
+
deferred,
|
|
214
|
+
message,
|
|
202
215
|
fix: arkCommand(root, 'ark-check', assessed.gap.fixArgs),
|
|
203
216
|
});
|
|
204
217
|
}
|
|
@@ -403,6 +416,19 @@ export function collectAdoptionGaps(root, config, coverage) {
|
|
|
403
416
|
}
|
|
404
417
|
}
|
|
405
418
|
|
|
419
|
+
// --- Q3 weakest-link: CI / pre-commit / config drift (local FS; optional GH via ARK_DOCTOR_GITHUB=1) ---
|
|
420
|
+
const includeGithub =
|
|
421
|
+
process.env.ARK_DOCTOR_GITHUB === '1' ||
|
|
422
|
+
process.env.ARK_DOCTOR_GITHUB === 'true';
|
|
423
|
+
const weakest = collectWeakestLinkGaps(root, {
|
|
424
|
+
adopted,
|
|
425
|
+
isProducer,
|
|
426
|
+
includeGithub,
|
|
427
|
+
});
|
|
428
|
+
for (const g of weakest.gaps) {
|
|
429
|
+
gaps.push(g);
|
|
430
|
+
}
|
|
431
|
+
|
|
406
432
|
return {
|
|
407
433
|
gaps,
|
|
408
434
|
hosts,
|
|
@@ -415,6 +441,12 @@ export function collectAdoptionGaps(root, config, coverage) {
|
|
|
415
441
|
deployPath,
|
|
416
442
|
contractFalseGreen,
|
|
417
443
|
writePath,
|
|
444
|
+
enforcement: {
|
|
445
|
+
ci: weakest.ci,
|
|
446
|
+
preCommit: weakest.preCommit,
|
|
447
|
+
drift: weakest.drift,
|
|
448
|
+
github: weakest.github,
|
|
449
|
+
},
|
|
418
450
|
};
|
|
419
451
|
}
|
|
420
452
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open a local HTML file in the default browser (macOS / Windows / Linux).
|
|
3
|
+
* Used after ark-check --report writes a showcase/beginner report.
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { pathToFileURL } from 'node:url';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether report generation should open the browser.
|
|
12
|
+
* Default: yes for interactive local TTY; never in CI/Vitest unless forced.
|
|
13
|
+
*
|
|
14
|
+
* @param {{ force?: boolean, noOpen?: boolean, env?: NodeJS.ProcessEnv, isTty?: boolean }} [opts]
|
|
15
|
+
*/
|
|
16
|
+
export function shouldOpenHtmlReport(opts = {}) {
|
|
17
|
+
const env = opts.env ?? process.env;
|
|
18
|
+
if (opts.noOpen) return false;
|
|
19
|
+
if (opts.force) return true;
|
|
20
|
+
const off = env.ARK_NO_OPEN_REPORT;
|
|
21
|
+
if (off === '1' || off === 'true' || off === 'yes') return false;
|
|
22
|
+
if (env.CI === 'true' || env.CI === '1') return false;
|
|
23
|
+
if (env.GITHUB_ACTIONS === 'true') return false;
|
|
24
|
+
if (env.VITEST) return false;
|
|
25
|
+
const tty = opts.isTty ?? Boolean(process.stdout.isTTY);
|
|
26
|
+
return tty;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Launch the OS default browser for a local file path (non-blocking).
|
|
31
|
+
* Errors are swallowed — report generation must not fail if the browser cannot open.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} filePath
|
|
34
|
+
* @param {{ platform?: NodeJS.Platform, spawn?: typeof spawn }} [opts]
|
|
35
|
+
* @returns {{ ok: boolean, command?: string, reason?: string }}
|
|
36
|
+
*/
|
|
37
|
+
export function openHtmlInBrowser(filePath, opts = {}) {
|
|
38
|
+
const abs = path.resolve(filePath);
|
|
39
|
+
if (!fs.existsSync(abs)) {
|
|
40
|
+
return { ok: false, reason: 'missing-file' };
|
|
41
|
+
}
|
|
42
|
+
const platform = opts.platform ?? process.platform;
|
|
43
|
+
const spawnFn = opts.spawn ?? spawn;
|
|
44
|
+
|
|
45
|
+
/** @type {string} */
|
|
46
|
+
let command;
|
|
47
|
+
/** @type {string[]} */
|
|
48
|
+
let args;
|
|
49
|
+
if (platform === 'darwin') {
|
|
50
|
+
command = 'open';
|
|
51
|
+
args = [abs];
|
|
52
|
+
} else if (platform === 'win32') {
|
|
53
|
+
command = 'rundll32.exe';
|
|
54
|
+
args = ['url.dll,FileProtocolHandler', pathToFileURL(abs).href];
|
|
55
|
+
} else {
|
|
56
|
+
command = 'xdg-open';
|
|
57
|
+
args = [abs];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const child = spawnFn(command, args, {
|
|
62
|
+
detached: true,
|
|
63
|
+
stdio: 'ignore',
|
|
64
|
+
windowsHide: true,
|
|
65
|
+
shell: false,
|
|
66
|
+
});
|
|
67
|
+
child.on('error', () => {
|
|
68
|
+
/* browser missing (e.g. headless Linux) — ignore */
|
|
69
|
+
});
|
|
70
|
+
child.unref();
|
|
71
|
+
return { ok: true, command };
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
74
|
+
}
|
|
75
|
+
}
|
package/bin/lib/presets.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DEFAULT_INTENT_PREFIXES,
|
|
9
9
|
resolveIncludeRoots,
|
|
10
10
|
} from '../ark-shared.mjs';
|
|
11
|
+
import { withArkConfigMetadata } from './config-contract.mjs';
|
|
11
12
|
|
|
12
13
|
export function denyUpward(names) {
|
|
13
14
|
const rules = [];
|
|
@@ -49,8 +50,8 @@ export function peerIsolationEdges(layerNames, sliceFolders, message) {
|
|
|
49
50
|
// (that carves out legitimate `src/shared/kernel/**` SharedKernel paths).
|
|
50
51
|
export const FRAMEWORK_INTERNAL_EXCLUDE = ['src/kernel/**', '**/src/kernel/**'];
|
|
51
52
|
export function presetWithOverlays(baseConfig, root) {
|
|
52
|
-
|
|
53
|
-
return
|
|
53
|
+
const config = root ? applyFrameworkLayoutOverlays(baseConfig, root) : baseConfig;
|
|
54
|
+
return withArkConfigMetadata(config);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
export const ARCHITECTURE_PRESETS = {
|
|
@@ -146,15 +146,20 @@ export function collectSafetyDiagnostics(ts, root, config, files) {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
if (ts.isCallExpression(node)
|
|
149
|
+
if (ts.isCallExpression(node)) {
|
|
150
|
+
const dynamicImport = node.expression?.kind === ts.SyntaxKind.ImportKeyword;
|
|
151
|
+
const directRequire =
|
|
152
|
+
ts.isIdentifier(node.expression) && node.expression.text === 'require';
|
|
150
153
|
const argument = node.arguments[0];
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
const unresolved =
|
|
155
|
+
(dynamicImport || directRequire) &&
|
|
156
|
+
(!argument || !ts.isStringLiteralLike(argument));
|
|
157
|
+
if (unresolved && !matchesAny(relFile, dynamicAllowlist)) {
|
|
158
|
+
report.nonLiteralDynamicImports.push({
|
|
159
|
+
file: relFile,
|
|
160
|
+
line: lineOf(sourceFile, node.getStart(sourceFile)),
|
|
161
|
+
kind: directRequire ? 'require' : 'import',
|
|
162
|
+
});
|
|
158
163
|
}
|
|
159
164
|
}
|
|
160
165
|
|
|
@@ -216,13 +221,28 @@ export function collectSafetyDiagnostics(ts, root, config, files) {
|
|
|
216
221
|
}
|
|
217
222
|
|
|
218
223
|
const warnings = [];
|
|
219
|
-
|
|
220
|
-
|
|
224
|
+
const nonLiteralImports = report.nonLiteralDynamicImports.filter(
|
|
225
|
+
(entry) => entry.kind !== 'require'
|
|
226
|
+
);
|
|
227
|
+
if (nonLiteralImports.length > 0) {
|
|
228
|
+
const first = nonLiteralImports[0];
|
|
221
229
|
warnings.push({
|
|
222
230
|
ruleId: 'DYNAMIC_IMPORT_NOT_ALLOWLISTED',
|
|
223
231
|
file: first.file,
|
|
224
232
|
line: first.line,
|
|
225
|
-
message: `${
|
|
233
|
+
message: `${nonLiteralImports.length} non-literal dynamic import(s) cannot be resolved statically. Add only reviewed files to dynamicImportAllowlist.`,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const nonLiteralRequires = report.nonLiteralDynamicImports.filter(
|
|
237
|
+
(entry) => entry.kind === 'require'
|
|
238
|
+
);
|
|
239
|
+
if (nonLiteralRequires.length > 0) {
|
|
240
|
+
const first = nonLiteralRequires[0];
|
|
241
|
+
warnings.push({
|
|
242
|
+
ruleId: 'DYNAMIC_REQUIRE_NOT_ALLOWLISTED',
|
|
243
|
+
file: first.file,
|
|
244
|
+
line: first.line,
|
|
245
|
+
message: `${nonLiteralRequires.length} non-literal require call(s) cannot be resolved statically. Add only reviewed files to dynamicImportAllowlist.`,
|
|
226
246
|
});
|
|
227
247
|
}
|
|
228
248
|
if (report.tsSuppressions.length > maxTsSuppressions) {
|
|
@@ -23,6 +23,70 @@ export function normalizeToolsList(tools) {
|
|
|
23
23
|
return [];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function envTruthy(v) {
|
|
27
|
+
if (v == null || v === '') return false;
|
|
28
|
+
const s = String(v).trim().toLowerCase();
|
|
29
|
+
return s !== '0' && s !== 'false' && s !== 'no' && s !== 'off';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Best-effort active agent host for this process (session host).
|
|
34
|
+
* Prefer ARK_ACTIVE_HOST when set. Do NOT treat CODEX_HOME alone as Codex —
|
|
35
|
+
* that dir exists for anyone who installed Codex, even when running Grok/Claude.
|
|
36
|
+
*
|
|
37
|
+
* @param {NodeJS.ProcessEnv} [env]
|
|
38
|
+
* @returns {string|null} tool id (claude|cursor|codex|grok|…) or null if unknown
|
|
39
|
+
*/
|
|
40
|
+
export function detectActiveAgentHost(env = process.env) {
|
|
41
|
+
const explicit = String(env.ARK_ACTIVE_HOST || '')
|
|
42
|
+
.trim()
|
|
43
|
+
.toLowerCase();
|
|
44
|
+
if (explicit) return explicit;
|
|
45
|
+
|
|
46
|
+
// Grok / xAI Build
|
|
47
|
+
if (
|
|
48
|
+
envTruthy(env.GROK_BUILD) ||
|
|
49
|
+
envTruthy(env.XAI_GROK) ||
|
|
50
|
+
env.GROK_WORKSPACE_ROOT ||
|
|
51
|
+
env.GROK_SESSION_ID
|
|
52
|
+
) {
|
|
53
|
+
return 'grok';
|
|
54
|
+
}
|
|
55
|
+
// Claude Code
|
|
56
|
+
if (
|
|
57
|
+
env.CLAUDE_PROJECT_DIR ||
|
|
58
|
+
envTruthy(env.CLAUDE_CODE) ||
|
|
59
|
+
envTruthy(env.CLAUDECODE) ||
|
|
60
|
+
env.CLAUDE_CODE_ENTRYPOINT
|
|
61
|
+
) {
|
|
62
|
+
return 'claude';
|
|
63
|
+
}
|
|
64
|
+
// Cursor agent
|
|
65
|
+
if (env.CURSOR_TRACE_ID || env.CURSOR_AGENT || envTruthy(env.CURSOR_AGENT_CLI)) {
|
|
66
|
+
return 'cursor';
|
|
67
|
+
}
|
|
68
|
+
// Codex session — never CODEX_HOME alone (see above)
|
|
69
|
+
if (
|
|
70
|
+
envTruthy(env.CODEX_SANDBOX) ||
|
|
71
|
+
env.CODEX_THREAD_ID ||
|
|
72
|
+
envTruthy(env.CODEX_CI) ||
|
|
73
|
+
env.CODEX_SESSION_ID
|
|
74
|
+
) {
|
|
75
|
+
return 'codex';
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* True when Codex home / MCP / prompts should be treated as an urgent concern
|
|
82
|
+
* for this process. Non-Codex hosts (Grok, Claude, Cursor, …) defer Codex debt.
|
|
83
|
+
*
|
|
84
|
+
* @param {NodeJS.ProcessEnv} [env]
|
|
85
|
+
*/
|
|
86
|
+
export function codexConcernIsActive(env = process.env) {
|
|
87
|
+
return detectActiveAgentHost(env) === 'codex';
|
|
88
|
+
}
|
|
89
|
+
|
|
26
90
|
export function resolveTools(args) {
|
|
27
91
|
const explicit = normalizeToolsList(args.tools);
|
|
28
92
|
if (explicit.length > 0) {
|
package/bin/lib/ts-resolve.mjs
CHANGED
|
@@ -128,9 +128,10 @@ export function scanCacheKey(root, args) {
|
|
|
128
128
|
// warm cache from an older Ark can't feed stale entries to new logic. v2: typeOnly on edges.
|
|
129
129
|
// v3: per-file exportsOnlyTypes. v4: typeOnlyExportNames + namedBindings.
|
|
130
130
|
// v5: hasTopLevelSideEffects. v6: non-exported impure inits + non-export class statics.
|
|
131
|
+
// v7: scope-aware forbidden globals + import-equals dependency edges.
|
|
131
132
|
return crypto
|
|
132
133
|
.createHash('sha1')
|
|
133
|
-
.update(`ark-check-cache-
|
|
134
|
+
.update(`ark-check-cache-v7\0${read(configPath)}\0${manifestPath ? read(manifestPath) : ''}`)
|
|
134
135
|
.digest('hex');
|
|
135
136
|
}
|
|
136
137
|
|