arkgate 2.13.0 → 3.0.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 +39 -0
- package/README.md +37 -22
- package/bin/ark-check.mjs +62 -4
- package/bin/ark-mcp.mjs +108 -1
- package/bin/ark-shared.mjs +204 -149
- package/bin/ark.mjs +90 -25
- package/bin/lib/adapter-contract.mjs +93 -0
- package/bin/lib/agent-gates.mjs +1 -0
- package/bin/lib/analysis-engine.mjs +1171 -0
- package/bin/lib/architecture-scan.mjs +84 -135
- package/bin/lib/ci-and-commands.mjs +31 -0
- package/bin/lib/config-warnings.mjs +7 -205
- package/bin/lib/field-install.mjs +67 -10
- package/bin/lib/gate-files.mjs +42 -3
- package/bin/lib/graph-cycles.mjs +4 -54
- package/bin/lib/hook-templates.mjs +33 -1
- package/bin/lib/host-support-matrix.mjs +7 -1
- package/bin/lib/install-migrate.mjs +54 -16
- package/bin/lib/presets.mjs +42 -2
- package/bin/lib/safety-diagnostics.mjs +18 -17
- package/bin/lib/scan-files.mjs +12 -1
- package/bin/lib/skill-install.mjs +8 -1
- package/bin/lib/source-policy.mjs +36 -0
- package/bin/lib/start-preview.mjs +271 -0
- package/bin/lib/ts-resolve.mjs +11 -2
- package/bin/lib/write-path-capabilities.mjs +4 -0
- package/compat/nestjs.cjs +2 -0
- package/compat/nestjs.d.ts +2 -0
- package/compat/nestjs.js +1 -0
- package/compat/runtime.cjs +2 -0
- package/compat/runtime.d.ts +2 -0
- package/compat/runtime.js +1 -0
- package/dist/configContract-BxSIwVRo.d.cts +259 -0
- package/dist/configContract-BxSIwVRo.d.ts +259 -0
- package/dist/eslint/index.cjs +125 -48
- package/dist/eslint/index.d.cts +7 -1
- package/dist/eslint/index.d.ts +7 -1
- package/dist/eslint/index.js +125 -48
- package/dist/index.cjs +1248 -3302
- package/dist/index.d.cts +359 -483
- package/dist/index.d.ts +359 -483
- package/dist/index.js +1231 -3248
- package/docs/agent-guide.md +28 -16
- package/docs/ai-gates.md +30 -7
- package/docs/migrate-from-ark-runtime-kernel.md +2 -3
- package/docs/package-surface.md +8 -13
- package/docs/production-hardening.md +17 -4
- package/docs/typescript-support.md +27 -0
- package/package.json +33 -11
- package/schemas/ark.analysis-result.schema.json +91 -0
- package/server.json +2 -2
- package/templates/skills/ark-architect.md +3 -2
- package/dist/configContract-iBLxx5Tz.d.cts +0 -53
- package/dist/configContract-iBLxx5Tz.d.ts +0 -53
- package/dist/eslint/index.cjs.map +0 -1
- package/dist/eslint/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/nestjs/index.cjs +0 -2606
- package/dist/nestjs/index.cjs.map +0 -1
- package/dist/nestjs/index.d.cts +0 -23
- package/dist/nestjs/index.d.ts +0 -23
- package/dist/nestjs/index.js +0 -2582
- package/dist/nestjs/index.js.map +0 -1
- package/dist/runtime/index.cjs +0 -4014
- package/dist/runtime/index.cjs.map +0 -1
- package/dist/runtime/index.d.cts +0 -3
- package/dist/runtime/index.d.ts +0 -3
- package/dist/runtime/index.js +0 -3925
- package/dist/runtime/index.js.map +0 -1
- package/dist/types-BxBwnBpC.d.cts +0 -1041
- package/dist/types-Wcs_l1_J.d.ts +0 -1041
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { arkCommand, buildArchitectureRecommendation } from '../ark-shared.mjs';
|
|
7
|
+
import { compactAgentInstructions, instructionRule, mcpJson } from './ci-and-commands.mjs';
|
|
8
|
+
import { claudeSettings, codexHooks, grokHooks, grokProjectConfig } from './hook-templates.mjs';
|
|
9
|
+
|
|
10
|
+
const COMPACT_HOST_TEMPLATES = {
|
|
11
|
+
claude: (root) => [
|
|
12
|
+
['.claude/settings.json', claudeSettings(root)],
|
|
13
|
+
['.mcp.json', mcpJson(root)],
|
|
14
|
+
],
|
|
15
|
+
grok: (root) => [
|
|
16
|
+
['.grok/config.toml', grokProjectConfig(root)],
|
|
17
|
+
['.grok/hooks/ark-write-gate.json', grokHooks(root)],
|
|
18
|
+
],
|
|
19
|
+
cursor: (root) => [['.cursor/mcp.json', mcpJson(root)]],
|
|
20
|
+
codex: (root) => [['.codex/hooks.json', codexHooks(root)]],
|
|
21
|
+
windsurf: (root) => [['.windsurf/rules/ark.md', instructionRule(root)]],
|
|
22
|
+
cline: (root) => [['.clinerules/ark.md', instructionRule(root)]],
|
|
23
|
+
copilot: (root) => [['.github/copilot-instructions.md', instructionRule(root)]],
|
|
24
|
+
kiro: (root) => [['.kiro/steering/ark.md', instructionRule(root)]],
|
|
25
|
+
roo: (root) => [['.roo/rules/ark.md', instructionRule(root)]],
|
|
26
|
+
continue: (root) => [['.continue/rules/ark.md', instructionRule(root)]],
|
|
27
|
+
gemini: (root) => [['GEMINI.md', instructionRule(root)]],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function treeFiles(root) {
|
|
31
|
+
const files = new Map();
|
|
32
|
+
const visit = (dir) => {
|
|
33
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
+
if (['.git', 'node_modules', 'dist', 'coverage'].includes(entry.name)) continue;
|
|
35
|
+
const absolute = path.join(dir, entry.name);
|
|
36
|
+
if (entry.isDirectory()) visit(absolute);
|
|
37
|
+
else if (entry.isFile()) {
|
|
38
|
+
files.set(path.relative(root, absolute).split(path.sep).join('/'), fs.readFileSync(absolute));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
visit(root);
|
|
43
|
+
return files;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function normalizedContent(content, shadowRoot, root) {
|
|
47
|
+
if (!content) return content;
|
|
48
|
+
const text = content.toString('utf8');
|
|
49
|
+
return text.includes('\u0000') ? content : Buffer.from(text.split(shadowRoot).join(root));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function digest(content) {
|
|
53
|
+
return `sha256:${crypto.createHash('sha256').update(content ?? Buffer.alloc(0)).digest('hex')}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function change(pathname, before, after) {
|
|
57
|
+
return {
|
|
58
|
+
path: pathname,
|
|
59
|
+
action: !before ? 'create' : !after ? 'delete' : 'edit',
|
|
60
|
+
beforeHash: before ? digest(before) : null,
|
|
61
|
+
afterHash: after ? digest(after) : null,
|
|
62
|
+
beforeBase64: before ? before.toString('base64') : null,
|
|
63
|
+
afterBase64: after ? after.toString('base64') : null,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function setupBudget(changes) {
|
|
68
|
+
const generatedChanges = changes.filter((item) => item.path !== 'package.json');
|
|
69
|
+
const bytes = generatedChanges.reduce(
|
|
70
|
+
(total, item) => total + (item.afterBase64 ? Buffer.from(item.afterBase64, 'base64').length : 0),
|
|
71
|
+
0
|
|
72
|
+
);
|
|
73
|
+
return {
|
|
74
|
+
files: generatedChanges.length,
|
|
75
|
+
bytes,
|
|
76
|
+
maxFiles: 5,
|
|
77
|
+
maxBytes: 25 * 1024,
|
|
78
|
+
ok: generatedChanges.length <= 5 && bytes < 25 * 1024,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function commands(root, args, helpers) {
|
|
83
|
+
if (args.removeHost) {
|
|
84
|
+
return [`ark start --root ${root} --tools ${args.removeHost} --apply`];
|
|
85
|
+
}
|
|
86
|
+
const result = [];
|
|
87
|
+
if (args.installExplicit && args.install && fs.existsSync(path.join(root, 'package.json'))) {
|
|
88
|
+
const [command, commandArgs] = helpers.packageInstallArgv(root, `^${helpers.cliVersion()}`);
|
|
89
|
+
result.push(`${command} ${commandArgs.join(' ')}`);
|
|
90
|
+
}
|
|
91
|
+
result.push(arkCommand(root, 'ark-check', '--init'));
|
|
92
|
+
const host = args.tools ? ` --tools ${args.tools}` : '';
|
|
93
|
+
result.push(arkCommand(root, 'ark-check', `--install-agent-gates --compact${host}`));
|
|
94
|
+
result.push(arkCommand(root, 'ark-check', '--plan --json'));
|
|
95
|
+
result.push(arkCommand(root, 'ark-check', '--coverage --json'));
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function renderStartPreview(preview) {
|
|
100
|
+
console.log('Ark start preview — no files were changed.');
|
|
101
|
+
if (preview.analysis) {
|
|
102
|
+
console.log(`Your project looks like: ${preview.analysis.label} (${preview.analysis.archetype}, confidence ${preview.analysis.confidence}).`);
|
|
103
|
+
}
|
|
104
|
+
console.log(`Projected governed coverage: ${preview.projectedCoverage.percent ?? 'unknown'}% (${preview.projectedCoverage.classifiedFiles}/${preview.projectedCoverage.totalFiles} files)`);
|
|
105
|
+
console.log(`Compact setup budget: ${preview.setupBudget.files}/${preview.setupBudget.maxFiles} files, ${preview.setupBudget.bytes}/${preview.setupBudget.maxBytes} bytes${preview.setupBudget.ok ? '' : ' (exceeded)'}.`);
|
|
106
|
+
console.log('Files to create/edit/delete:');
|
|
107
|
+
if (preview.changes.length === 0) console.log(' (none)');
|
|
108
|
+
for (const change of preview.changes) {
|
|
109
|
+
console.log(` ${change.action.padEnd(6)} ${change.path} ${change.afterHash ?? '(deleted)'}`);
|
|
110
|
+
}
|
|
111
|
+
console.log('Commands in the approved setup plan:');
|
|
112
|
+
for (const command of preview.commands) console.log(` ${command}`);
|
|
113
|
+
console.log('Host guarantees:');
|
|
114
|
+
for (const guarantee of preview.hostGuarantees) console.log(` ${guarantee}`);
|
|
115
|
+
if (preview.unresolvedDecisions.length > 0) {
|
|
116
|
+
console.log('Unresolved decisions:');
|
|
117
|
+
for (const decision of preview.unresolvedDecisions) console.log(` ${decision}`);
|
|
118
|
+
}
|
|
119
|
+
console.log('Review complete file contents with --json. Apply this plan with: ark start --apply');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function applyStartPreview(root, preview) {
|
|
123
|
+
if (!preview.setupBudget?.ok) {
|
|
124
|
+
throw new Error('Refusing to apply a start plan that exceeds the compact setup budget.');
|
|
125
|
+
}
|
|
126
|
+
for (const change of preview.changes) {
|
|
127
|
+
const target = path.join(root, change.path);
|
|
128
|
+
const current = fs.existsSync(target) ? fs.readFileSync(target) : null;
|
|
129
|
+
const currentHash = current ? digest(current) : null;
|
|
130
|
+
if (currentHash !== change.beforeHash) {
|
|
131
|
+
throw new Error(`Refusing to apply stale preview: ${change.path} changed after planning.`);
|
|
132
|
+
}
|
|
133
|
+
if (change.action === 'delete') {
|
|
134
|
+
fs.rmSync(target, { force: true });
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
138
|
+
fs.writeFileSync(target, Buffer.from(change.afterBase64, 'base64'));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function planHostRemoval(args, helpers) {
|
|
143
|
+
const host = args.removeHost;
|
|
144
|
+
const templateFactory = COMPACT_HOST_TEMPLATES[host];
|
|
145
|
+
if (!templateFactory) throw new Error(`Unknown compact host: ${host}.`);
|
|
146
|
+
const changes = [];
|
|
147
|
+
const unresolvedDecisions = [];
|
|
148
|
+
for (const [relativePath, expected] of templateFactory(args.root)) {
|
|
149
|
+
const target = path.join(args.root, relativePath);
|
|
150
|
+
if (!fs.existsSync(target)) continue;
|
|
151
|
+
const before = fs.readFileSync(target);
|
|
152
|
+
if (before.toString('utf8') !== expected) {
|
|
153
|
+
unresolvedDecisions.push(`${relativePath} was customized and was left untouched.`);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
changes.push(change(relativePath, before, null));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const agentsPath = path.join(args.root, 'AGENTS.md');
|
|
160
|
+
if (fs.existsSync(agentsPath)) {
|
|
161
|
+
const before = fs.readFileSync(agentsPath);
|
|
162
|
+
if (before.toString('utf8') === compactAgentInstructions(args.root, host)) {
|
|
163
|
+
changes.push(change('AGENTS.md', before, Buffer.from(compactAgentInstructions(args.root))));
|
|
164
|
+
} else {
|
|
165
|
+
unresolvedDecisions.push('AGENTS.md is not the expected compact router and was left untouched.');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const genericMcp = path.join(args.root, '.mcp.json');
|
|
170
|
+
if (!fs.existsSync(genericMcp)) {
|
|
171
|
+
changes.push(change('.mcp.json', null, Buffer.from(mcpJson(args.root))));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
version: 1,
|
|
176
|
+
root: args.root,
|
|
177
|
+
readOnly: true,
|
|
178
|
+
mode: 'remove-host',
|
|
179
|
+
host,
|
|
180
|
+
analysis: null,
|
|
181
|
+
projectedCoverage: { percent: null, classifiedFiles: 0, totalFiles: 0 },
|
|
182
|
+
changes,
|
|
183
|
+
setupBudget: setupBudget(changes),
|
|
184
|
+
commands: commands(args.root, args, helpers),
|
|
185
|
+
hostGuarantees: ['host removal is limited to Ark-owned compact artifacts', 'restore with the displayed --tools command'],
|
|
186
|
+
unresolvedDecisions,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function planStart(args, helpers) {
|
|
191
|
+
if (args.removeHost) return planHostRemoval(args, helpers);
|
|
192
|
+
const root = args.root;
|
|
193
|
+
const before = treeFiles(root);
|
|
194
|
+
let recommendation = null;
|
|
195
|
+
try {
|
|
196
|
+
const rec = buildArchitectureRecommendation(root);
|
|
197
|
+
recommendation = {
|
|
198
|
+
archetype: rec.archetype,
|
|
199
|
+
label: rec.label,
|
|
200
|
+
confidence: rec.confidence,
|
|
201
|
+
mature: rec.mature,
|
|
202
|
+
};
|
|
203
|
+
} catch {
|
|
204
|
+
recommendation = null;
|
|
205
|
+
}
|
|
206
|
+
const shadowRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ark-start-preview-'));
|
|
207
|
+
try {
|
|
208
|
+
fs.cpSync(root, shadowRoot, {
|
|
209
|
+
recursive: true,
|
|
210
|
+
filter: (source) => {
|
|
211
|
+
const relative = path.relative(root, source).split(path.sep).join('/');
|
|
212
|
+
return !relative.split('/').some((part) => ['.git', 'node_modules', 'dist', 'coverage'].includes(part));
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
const childArgs = ['start', '--root', shadowRoot, '--internal-apply', '--skip-package-manager'];
|
|
216
|
+
if (args.yes) childArgs.push('--yes');
|
|
217
|
+
if (args.force) childArgs.push('--force');
|
|
218
|
+
if (!args.strict) childArgs.push('--no-strict');
|
|
219
|
+
if (args.installExplicit && args.install) childArgs.push('--install');
|
|
220
|
+
if (args.installExplicit && !args.install) childArgs.push('--no-install');
|
|
221
|
+
if (args.tools) childArgs.push('--tools', args.tools);
|
|
222
|
+
if (args.requireWriteHook) childArgs.push('--require-write-hook', args.requireWriteHook);
|
|
223
|
+
const planned = spawnSync(process.execPath, [helpers.cliPath, ...childArgs], {
|
|
224
|
+
cwd: shadowRoot,
|
|
225
|
+
encoding: 'utf8',
|
|
226
|
+
stdio: 'pipe',
|
|
227
|
+
});
|
|
228
|
+
if ((planned.status ?? 1) !== 0) {
|
|
229
|
+
throw new Error(`Unable to produce a safe start plan (exit ${planned.status ?? 1}): ${planned.stderr || planned.stdout}`.trim());
|
|
230
|
+
}
|
|
231
|
+
const coverageRun = spawnSync(process.execPath, [helpers.arkCheck, '--root', shadowRoot, '--config', 'ark.config.json', '--coverage', '--json'], { cwd: shadowRoot, encoding: 'utf8' });
|
|
232
|
+
let coverage = {};
|
|
233
|
+
try {
|
|
234
|
+
coverage = JSON.parse(coverageRun.stdout || '{}').coverage || {};
|
|
235
|
+
} catch {
|
|
236
|
+
coverage = {};
|
|
237
|
+
}
|
|
238
|
+
const afterRaw = treeFiles(shadowRoot);
|
|
239
|
+
const after = new Map([...afterRaw].map(([file, content]) => [file, normalizedContent(content, shadowRoot, root)]));
|
|
240
|
+
const changes = [];
|
|
241
|
+
for (const file of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
242
|
+
const oldContent = before.get(file);
|
|
243
|
+
const newContent = after.get(file);
|
|
244
|
+
if ((oldContent && newContent && oldContent.equals(newContent)) || (!oldContent && !newContent)) continue;
|
|
245
|
+
changes.push(change(file, oldContent, newContent));
|
|
246
|
+
}
|
|
247
|
+
const percent = coverage.governed?.percent ?? null;
|
|
248
|
+
return {
|
|
249
|
+
version: 1,
|
|
250
|
+
root,
|
|
251
|
+
readOnly: true,
|
|
252
|
+
analysis: recommendation,
|
|
253
|
+
projectedCoverage: {
|
|
254
|
+
percent,
|
|
255
|
+
classifiedFiles: coverage.governed?.classifiedFiles ?? 0,
|
|
256
|
+
totalFiles: coverage.governed?.totalFiles ?? coverage.totalFiles ?? 0,
|
|
257
|
+
},
|
|
258
|
+
changes,
|
|
259
|
+
setupBudget: setupBudget(changes),
|
|
260
|
+
commands: commands(root, args, helpers),
|
|
261
|
+
hostGuarantees: [
|
|
262
|
+
args.requireWriteHook ? `Hard-write hook verified for ${args.requireWriteHook}` : 'shared CI merge gate will be installed',
|
|
263
|
+
'preview phase performs no writes in the target project',
|
|
264
|
+
'apply writes the exact bytes identified by each afterHash',
|
|
265
|
+
],
|
|
266
|
+
unresolvedDecisions: percent !== null && percent < 90 ? [`Projected governed coverage is ${percent}%; review unclassified files before treating the contract as complete.`] : [],
|
|
267
|
+
};
|
|
268
|
+
} finally {
|
|
269
|
+
fs.rmSync(shadowRoot, { recursive: true, force: true });
|
|
270
|
+
}
|
|
271
|
+
}
|
package/bin/lib/ts-resolve.mjs
CHANGED
|
@@ -203,8 +203,17 @@ export function resolveRelativeFallback(fromFile, specifier) {
|
|
|
203
203
|
* lookup); edges that resolve outside the root are still skipped.
|
|
204
204
|
*/
|
|
205
205
|
export function resolveImport(ts, specifier, containingFile, options, host, root) {
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
let file;
|
|
207
|
+
// Explicit relative extensions are already unambiguous on disk. Avoid a full TypeScript
|
|
208
|
+
// resolver walk for the common ESM/CJS form; retain TypeScript as the fallback for aliases,
|
|
209
|
+
// packages, extensionless imports, and any explicit path that is not an existing file.
|
|
210
|
+
if (specifier.startsWith('.') && path.extname(specifier)) {
|
|
211
|
+
file = resolveRelativeFallback(containingFile, specifier);
|
|
212
|
+
}
|
|
213
|
+
if (!file) {
|
|
214
|
+
const res = ts.resolveModuleName(specifier, containingFile, options, host);
|
|
215
|
+
file = res.resolvedModule?.resolvedFileName;
|
|
216
|
+
}
|
|
208
217
|
if (!file && specifier.startsWith('.')) {
|
|
209
218
|
file = resolveRelativeFallback(containingFile, specifier);
|
|
210
219
|
}
|
|
@@ -138,6 +138,10 @@ export function detectWritePathInventory(root) {
|
|
|
138
138
|
merge
|
|
139
139
|
),
|
|
140
140
|
cursor: hostRecord([], mcpEvidence(root, '.cursor/mcp.json'), [], merge),
|
|
141
|
+
// Codex 0.123+ emits PreToolUse for the native apply_patch handler, but some
|
|
142
|
+
// Code Mode hosts execute deferred nested writes without dispatching that
|
|
143
|
+
// project hook. Keep the installed hook as best-effort protection; do not
|
|
144
|
+
// report a hard boundary that cannot be verified for every write surface.
|
|
141
145
|
codex: hostRecord([], codexMcpEvidence(root), [], merge),
|
|
142
146
|
};
|
|
143
147
|
|
package/compat/nestjs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@arkgate/runtime/nestjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@arkgate/runtime';
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical, pure contract for ark.config.json.
|
|
3
|
+
*
|
|
4
|
+
* Tooling adapters own filesystem I/O; this module owns JSON parsing, deterministic
|
|
5
|
+
* migration, defaults, validation, diagnostics, and the published JSON Schema.
|
|
6
|
+
* The standalone CLI artifact is generated into bin/lib/config-contract.mjs.
|
|
7
|
+
*/
|
|
8
|
+
declare const ARK_CONFIG_SCHEMA_VERSION: "1.0";
|
|
9
|
+
type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
|
|
10
|
+
type ArkConfigLayer = {
|
|
11
|
+
name: string;
|
|
12
|
+
patterns: string[];
|
|
13
|
+
exclude?: string[];
|
|
14
|
+
intentPrefixes?: string[];
|
|
15
|
+
description?: string;
|
|
16
|
+
forbiddenGlobals?: string[];
|
|
17
|
+
mayImportInfrastructure?: boolean;
|
|
18
|
+
optional?: boolean;
|
|
19
|
+
};
|
|
20
|
+
type ArkConfigRule = {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
allowed: boolean;
|
|
24
|
+
message?: string;
|
|
25
|
+
peerIsolation?: boolean;
|
|
26
|
+
sliceFolders?: string[];
|
|
27
|
+
};
|
|
28
|
+
type ArkConfigSafety = {
|
|
29
|
+
maxTsSuppressions?: number;
|
|
30
|
+
maxAnyCasts?: number;
|
|
31
|
+
allowInMemory?: boolean;
|
|
32
|
+
allowDisabledPeerIsolation?: boolean;
|
|
33
|
+
};
|
|
34
|
+
type ArkConfig = {
|
|
35
|
+
$schema: string;
|
|
36
|
+
schemaVersion: typeof ARK_CONFIG_SCHEMA_VERSION;
|
|
37
|
+
name?: string;
|
|
38
|
+
include: string[];
|
|
39
|
+
exclude?: string[];
|
|
40
|
+
excludeGenerated?: boolean;
|
|
41
|
+
frameworkOverlay?: string;
|
|
42
|
+
layers: ArkConfigLayer[];
|
|
43
|
+
rules: ArkConfigRule[];
|
|
44
|
+
cyclePolicy?: ArkConfigCyclePolicy;
|
|
45
|
+
dynamicImportAllowlist?: string[];
|
|
46
|
+
safety?: ArkConfigSafety;
|
|
47
|
+
};
|
|
48
|
+
declare const ARK_CONFIG_SCHEMA: {
|
|
49
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
50
|
+
readonly $id: "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json";
|
|
51
|
+
readonly title: "ArkGate architecture contract";
|
|
52
|
+
readonly description: "Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.";
|
|
53
|
+
readonly type: "object";
|
|
54
|
+
readonly additionalProperties: false;
|
|
55
|
+
readonly required: readonly ["$schema", "schemaVersion", "include", "layers", "rules"];
|
|
56
|
+
readonly properties: {
|
|
57
|
+
readonly $schema: {
|
|
58
|
+
readonly type: "string";
|
|
59
|
+
readonly minLength: 1;
|
|
60
|
+
readonly default: "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json";
|
|
61
|
+
readonly description: "Editor-facing URL or local path for this JSON Schema.";
|
|
62
|
+
};
|
|
63
|
+
readonly schemaVersion: {
|
|
64
|
+
readonly type: "string";
|
|
65
|
+
readonly const: "1.0";
|
|
66
|
+
readonly default: "1.0";
|
|
67
|
+
};
|
|
68
|
+
readonly name: {
|
|
69
|
+
readonly type: "string";
|
|
70
|
+
readonly minLength: 1;
|
|
71
|
+
};
|
|
72
|
+
readonly include: {
|
|
73
|
+
readonly minItems: 1;
|
|
74
|
+
readonly default: readonly ["src"];
|
|
75
|
+
readonly type: "array";
|
|
76
|
+
readonly items: {
|
|
77
|
+
readonly type: "string";
|
|
78
|
+
readonly minLength: 1;
|
|
79
|
+
};
|
|
80
|
+
readonly uniqueItems: true;
|
|
81
|
+
};
|
|
82
|
+
readonly exclude: {
|
|
83
|
+
readonly default: readonly [];
|
|
84
|
+
readonly type: "array";
|
|
85
|
+
readonly items: {
|
|
86
|
+
readonly type: "string";
|
|
87
|
+
readonly minLength: 1;
|
|
88
|
+
};
|
|
89
|
+
readonly uniqueItems: true;
|
|
90
|
+
};
|
|
91
|
+
readonly excludeGenerated: {
|
|
92
|
+
readonly type: "boolean";
|
|
93
|
+
readonly default: true;
|
|
94
|
+
};
|
|
95
|
+
readonly frameworkOverlay: {
|
|
96
|
+
readonly type: "string";
|
|
97
|
+
readonly minLength: 1;
|
|
98
|
+
};
|
|
99
|
+
readonly layers: {
|
|
100
|
+
readonly type: "array";
|
|
101
|
+
readonly default: readonly [];
|
|
102
|
+
readonly items: {
|
|
103
|
+
readonly $ref: "#/$defs/layer";
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
readonly rules: {
|
|
107
|
+
readonly type: "array";
|
|
108
|
+
readonly default: ArkConfigRule[];
|
|
109
|
+
readonly items: {
|
|
110
|
+
readonly $ref: "#/$defs/rule";
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
readonly cyclePolicy: {
|
|
114
|
+
readonly type: "string";
|
|
115
|
+
readonly enum: readonly ["strict", "soft", "framework-soft", "off"];
|
|
116
|
+
readonly default: "strict";
|
|
117
|
+
};
|
|
118
|
+
readonly dynamicImportAllowlist: {
|
|
119
|
+
readonly default: readonly [];
|
|
120
|
+
readonly type: "array";
|
|
121
|
+
readonly items: {
|
|
122
|
+
readonly type: "string";
|
|
123
|
+
readonly minLength: 1;
|
|
124
|
+
};
|
|
125
|
+
readonly uniqueItems: true;
|
|
126
|
+
};
|
|
127
|
+
readonly safety: {
|
|
128
|
+
readonly $ref: "#/$defs/safety";
|
|
129
|
+
readonly default: {
|
|
130
|
+
readonly maxTsSuppressions: 0;
|
|
131
|
+
readonly maxAnyCasts: 0;
|
|
132
|
+
readonly allowInMemory: false;
|
|
133
|
+
readonly allowDisabledPeerIsolation: false;
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
readonly $defs: {
|
|
138
|
+
readonly layer: {
|
|
139
|
+
readonly type: "object";
|
|
140
|
+
readonly additionalProperties: false;
|
|
141
|
+
readonly required: readonly ["name", "patterns"];
|
|
142
|
+
readonly properties: {
|
|
143
|
+
readonly name: {
|
|
144
|
+
readonly type: "string";
|
|
145
|
+
readonly minLength: 1;
|
|
146
|
+
};
|
|
147
|
+
readonly patterns: {
|
|
148
|
+
readonly minItems: 1;
|
|
149
|
+
readonly type: "array";
|
|
150
|
+
readonly items: {
|
|
151
|
+
readonly type: "string";
|
|
152
|
+
readonly minLength: 1;
|
|
153
|
+
};
|
|
154
|
+
readonly uniqueItems: true;
|
|
155
|
+
};
|
|
156
|
+
readonly exclude: {
|
|
157
|
+
readonly type: "array";
|
|
158
|
+
readonly items: {
|
|
159
|
+
readonly type: "string";
|
|
160
|
+
readonly minLength: 1;
|
|
161
|
+
};
|
|
162
|
+
readonly uniqueItems: true;
|
|
163
|
+
};
|
|
164
|
+
readonly intentPrefixes: {
|
|
165
|
+
readonly type: "array";
|
|
166
|
+
readonly items: {
|
|
167
|
+
readonly type: "string";
|
|
168
|
+
readonly minLength: 1;
|
|
169
|
+
};
|
|
170
|
+
readonly uniqueItems: true;
|
|
171
|
+
};
|
|
172
|
+
readonly description: {
|
|
173
|
+
readonly type: "string";
|
|
174
|
+
readonly minLength: 1;
|
|
175
|
+
};
|
|
176
|
+
readonly forbiddenGlobals: {
|
|
177
|
+
readonly type: "array";
|
|
178
|
+
readonly items: {
|
|
179
|
+
readonly type: "string";
|
|
180
|
+
readonly minLength: 1;
|
|
181
|
+
};
|
|
182
|
+
readonly uniqueItems: true;
|
|
183
|
+
};
|
|
184
|
+
readonly mayImportInfrastructure: {
|
|
185
|
+
readonly type: "boolean";
|
|
186
|
+
};
|
|
187
|
+
readonly optional: {
|
|
188
|
+
readonly type: "boolean";
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
readonly rule: {
|
|
193
|
+
readonly type: "object";
|
|
194
|
+
readonly additionalProperties: false;
|
|
195
|
+
readonly required: readonly ["from", "to", "allowed"];
|
|
196
|
+
readonly properties: {
|
|
197
|
+
readonly from: {
|
|
198
|
+
readonly type: "string";
|
|
199
|
+
readonly minLength: 1;
|
|
200
|
+
};
|
|
201
|
+
readonly to: {
|
|
202
|
+
readonly type: "string";
|
|
203
|
+
readonly minLength: 1;
|
|
204
|
+
};
|
|
205
|
+
readonly allowed: {
|
|
206
|
+
readonly type: "boolean";
|
|
207
|
+
};
|
|
208
|
+
readonly message: {
|
|
209
|
+
readonly type: "string";
|
|
210
|
+
readonly minLength: 1;
|
|
211
|
+
};
|
|
212
|
+
readonly peerIsolation: {
|
|
213
|
+
readonly type: "boolean";
|
|
214
|
+
};
|
|
215
|
+
readonly sliceFolders: {
|
|
216
|
+
readonly minItems: 1;
|
|
217
|
+
readonly type: "array";
|
|
218
|
+
readonly items: {
|
|
219
|
+
readonly type: "string";
|
|
220
|
+
readonly minLength: 1;
|
|
221
|
+
};
|
|
222
|
+
readonly uniqueItems: true;
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
readonly safety: {
|
|
227
|
+
readonly type: "object";
|
|
228
|
+
readonly additionalProperties: false;
|
|
229
|
+
readonly properties: {
|
|
230
|
+
readonly maxTsSuppressions: {
|
|
231
|
+
readonly type: "integer";
|
|
232
|
+
readonly minimum: 0;
|
|
233
|
+
readonly default: 0;
|
|
234
|
+
};
|
|
235
|
+
readonly maxAnyCasts: {
|
|
236
|
+
readonly type: "integer";
|
|
237
|
+
readonly minimum: 0;
|
|
238
|
+
readonly default: 0;
|
|
239
|
+
};
|
|
240
|
+
readonly allowInMemory: {
|
|
241
|
+
readonly type: "boolean";
|
|
242
|
+
readonly default: false;
|
|
243
|
+
};
|
|
244
|
+
readonly allowDisabledPeerIsolation: {
|
|
245
|
+
readonly type: "boolean";
|
|
246
|
+
readonly default: false;
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
type ArkConfigLoadResult = {
|
|
253
|
+
config: ArkConfig;
|
|
254
|
+
migratedFrom: 'unversioned' | null;
|
|
255
|
+
};
|
|
256
|
+
declare function loadArkConfigContract(input: unknown, source?: string): ArkConfigLoadResult;
|
|
257
|
+
declare function parseArkConfigJson(json: string, source?: string): ArkConfigLoadResult;
|
|
258
|
+
|
|
259
|
+
export { type ArkConfig as A, type ArkConfigRule as a, type ArkConfigLayer as b, type ArkConfigLoadResult as c, ARK_CONFIG_SCHEMA as d, ARK_CONFIG_SCHEMA_VERSION as e, loadArkConfigContract as l, parseArkConfigJson as p };
|