arkgate 4.8.24 → 4.8.26
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 +95 -0
- package/README.md +2 -2
- package/bin/ark-check-runtime.mjs +17 -14
- package/bin/ark-layer-match.mjs +115 -13
- package/bin/ark-mcp-runtime.mjs +36 -31
- package/bin/ark-shared.mjs +4 -23
- package/bin/lib/adoption-stance.mjs +2 -2
- package/bin/lib/adr-path.mjs +3 -3
- package/bin/lib/agent-gates.mjs +0 -61
- package/bin/lib/agent-homes.mjs +12 -21
- package/bin/lib/agent-projection-command.mjs +4 -4
- package/bin/lib/ambient-state.mjs +9 -30
- package/bin/lib/analysis-engine.mjs +14 -14
- package/bin/lib/architecture-scan.mjs +11 -9
- package/bin/lib/ark-order-doctor.mjs +3 -28
- package/bin/lib/ark-order-facts.mjs +6 -99
- package/bin/lib/ark-order-types.mjs +1 -2
- package/bin/lib/ark-run-doctor.mjs +3 -28
- package/bin/lib/ark-run-facts.mjs +30 -40
- package/bin/lib/ark-run-sensors.mjs +1 -1
- package/bin/lib/arkrule-file-hints.mjs +2 -47
- package/bin/lib/arkrules-contract.mjs +124 -133
- package/bin/lib/arkrules-sensors.mjs +7 -5
- package/bin/lib/check-args.mjs +63 -1
- package/bin/lib/ci-and-commands.mjs +8 -72
- package/bin/lib/ci-merge-boundary.mjs +1 -1
- package/bin/lib/class-source-scan.mjs +5 -5
- package/bin/lib/clone-detection.mjs +474 -0
- package/bin/lib/codex-home.mjs +1 -1
- package/bin/lib/config-contract-slices.mjs +44 -6
- package/bin/lib/config-contract.mjs +40 -117
- package/bin/lib/config-extras.mjs +16 -22
- package/bin/lib/contract-smells.mjs +33 -15
- package/bin/lib/core-ratchet.mjs +0 -2
- package/bin/lib/dashboard-cli.mjs +2 -2
- package/bin/lib/deep-module-coach.mjs +2 -4
- package/bin/lib/deploy-path.mjs +13 -38
- package/bin/lib/design-smells.mjs +2 -2
- package/bin/lib/diagnostic-catalog.mjs +8 -1
- package/bin/lib/doctor-advisories.mjs +55 -9
- package/bin/lib/doctor-green-cite.mjs +1 -1
- package/bin/lib/doctor-human.mjs +1 -1
- package/bin/lib/doctor-next-actions.mjs +2 -2
- package/bin/lib/doctor-plan.mjs +4 -6
- package/bin/lib/duplication-io.mjs +572 -0
- package/bin/lib/effective-contract-load.mjs +181 -44
- package/bin/lib/entry-points-io.mjs +424 -0
- package/bin/lib/extra-merge-teeth.mjs +36 -0
- package/bin/lib/field-install.mjs +38 -14
- package/bin/lib/first-run-help.mjs +7 -3
- package/bin/lib/flat-parent-importers.mjs +5 -3
- package/bin/lib/gate-files.mjs +30 -89
- package/bin/lib/github-enforcement.mjs +165 -28
- package/bin/lib/golden-pattern.mjs +1 -1
- package/bin/lib/hook-templates.mjs +16 -16
- package/bin/lib/html-report-advisories.mjs +4 -0
- package/bin/lib/html-report-depth.mjs +2 -2
- package/bin/lib/html-report.mjs +2 -2
- package/bin/lib/import-graph-projection.mjs +112 -0
- package/bin/lib/improvement-compass-doctor.mjs +1 -24
- package/bin/lib/invariant-coverage-io.mjs +4 -3
- package/bin/lib/invariant-coverage.mjs +26 -0
- package/bin/lib/invariant-probe-cli.mjs +347 -0
- package/bin/lib/invariant-probe-io.mjs +165 -0
- package/bin/lib/invariant-probe-runner.mjs +268 -0
- package/bin/lib/invariant-probe-sites.mjs +174 -0
- package/bin/lib/invariant-probe-workspace.mjs +183 -0
- package/bin/lib/invariant-probe.mjs +461 -0
- package/bin/lib/invariant-tests-path.mjs +16 -22
- package/bin/lib/literal-path-drift.mjs +4 -2
- package/bin/lib/managed-upgrade.mjs +2 -8
- package/bin/lib/mcp-adoption.mjs +4 -5
- package/bin/lib/mcp-hook-payload.mjs +4 -4
- package/bin/lib/orphan-modules-io.mjs +458 -0
- package/bin/lib/orphan-modules.mjs +251 -0
- package/bin/lib/outside-importers.mjs +197 -0
- package/bin/lib/package-manager.mjs +3 -3
- package/bin/lib/parse-health.mjs +1 -1
- package/bin/lib/persistence-write-hint.mjs +33 -8
- package/bin/lib/pin-dependent-gates.mjs +2 -2
- package/bin/lib/policy-delta-io.mjs +60 -12
- package/bin/lib/post-green-path.mjs +1 -1
- package/bin/lib/prepare-change.mjs +3 -9
- package/bin/lib/prepare-write.mjs +1 -2
- package/bin/lib/presets.mjs +56 -68
- package/bin/lib/product-copy.mjs +1 -6
- package/bin/lib/project-root.mjs +43 -85
- package/bin/lib/resolved-candidate-facts.mjs +90 -62
- package/bin/lib/rules-under-contract.mjs +72 -8
- package/bin/lib/scan-files.mjs +4 -4
- package/bin/lib/schema-validation.mjs +130 -0
- package/bin/lib/sensor-promote-cli.mjs +2 -11
- package/bin/lib/sensor-promote-io.mjs +33 -22
- package/bin/lib/sensor-promotion.mjs +1 -1
- package/bin/lib/skill-catalog-apply.mjs +1 -1
- package/bin/lib/skill-install.mjs +42 -38
- package/bin/lib/snippet-analysis.mjs +1 -1
- package/bin/lib/start-install-recovery.mjs +1 -1
- package/bin/lib/start-preview.mjs +1 -1
- package/bin/lib/states-transitions-presence.mjs +3 -3
- package/bin/lib/status-command.mjs +2 -18
- package/bin/lib/status-manifest.mjs +18 -26
- package/bin/lib/status-transition-catalog.mjs +0 -6
- package/bin/lib/suggestions.mjs +3 -3
- package/bin/lib/team-parliament-io.mjs +3 -17
- package/bin/lib/team-parliament.mjs +15 -9
- package/bin/lib/upgrade-behavior-changes.mjs +2 -2
- package/bin/lib/upgrade-command.mjs +2 -24
- package/bin/lib/upgrade-outcome.mjs +1 -1
- package/bin/lib/upstream-report.mjs +21 -10
- package/bin/lib/violations.mjs +10 -9
- package/bin/lib/weakest-link.mjs +13 -0
- package/bin/lib/write-path-capabilities.mjs +2 -2
- package/dist/chunk-G3JRBJGH.js +16 -0
- package/dist/chunk-R3AJ5RSZ.cjs +16 -0
- package/dist/{configTypes-BJbaeoj4.d.cts → configTypes-GPvvdleM.d.cts} +12 -1
- package/dist/{configTypes-BJbaeoj4.d.ts → configTypes-GPvvdleM.d.ts} +12 -1
- package/dist/eslint/index.cjs +11 -11
- package/dist/eslint/index.d.cts +10 -1
- package/dist/eslint/index.d.ts +10 -1
- package/dist/eslint/index.js +11 -11
- package/dist/index.cjs +34 -34
- package/dist/index.d.cts +587 -515
- package/dist/index.d.ts +587 -515
- package/dist/index.js +34 -34
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.d.cts +1 -1
- package/dist/nestjs/index.d.ts +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/order/index.cjs +1 -1
- package/dist/order/index.js +1 -1
- package/dist/runtime/index.cjs +12 -12
- package/dist/runtime/index.d.cts +174 -136
- package/dist/runtime/index.d.ts +174 -136
- package/dist/runtime/index.js +12 -12
- package/dist/{types-DRinG-vT.d.cts → types-CnauMQQL.d.cts} +33 -25
- package/dist/{types-DRinG-vT.d.ts → types-CnauMQQL.d.ts} +33 -25
- package/docs/README.md +3 -1
- package/docs/agent-guide.md +140 -6
- package/docs/ai-gates.md +15 -1
- package/docs/configuration.md +40 -11
- package/docs/diagnostics.md +119 -3
- package/docs/package-surface.md +4 -1
- package/docs/product-voice.md +7 -1
- package/package.json +11 -2
- package/schemas/ark.config.schema.json +31 -3
- package/schemas/ark.invariant-probe.schema.json +368 -0
- package/server.json +2 -2
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +1 -0
- package/templates/agent-skills/ark-contract/SKILL.md +17 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +2 -0
- package/templates/agent-skills/ark-explore/SKILL.md +7 -0
- package/templates/agent-skills/ark-fix/SKILL.md +20 -0
- package/templates/agent-skills/ark-place/SKILL.md +8 -0
- package/templates/skills/ark-adopt.md +1 -0
- package/templates/skills/ark-contract.md +17 -0
- package/templates/skills/ark-coverage.md +2 -0
- package/templates/skills/ark-explore.md +7 -0
- package/templates/skills/ark-fix.md +20 -0
- package/templates/skills/ark-place.md +8 -0
- package/bin/lib/ark-order-error.mjs +0 -18
- package/bin/lib/ark-order-invariants.mjs +0 -388
- package/bin/lib/stable-hash.mjs +0 -90
- package/dist/chunk-MBXCFLO4.js +0 -16
- package/dist/chunk-RNQHRDCQ.cjs +0 -16
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const ADOPTION_STANCE_REL = '.ark/adoption-stance.json';
|
|
9
|
+
const ADOPTION_STANCE_VALUE = 'advisory-only';
|
|
10
10
|
export const ADOPTED_REQUIRED_MERGE = 'required-merge';
|
|
11
11
|
export const ADOPTED_ADVISORY_ACKED = 'advisory-only-acked';
|
|
12
12
|
export const ADOPTED_NOT = 'not-adopted';
|
package/bin/lib/adr-path.mjs
CHANGED
|
@@ -12,10 +12,10 @@ export const ADR_PATH_ASK =
|
|
|
12
12
|
export const ADR_PATH_NEXT =
|
|
13
13
|
'Add a short note under docs/adr/ (or docs/decisions/) and put that file path in --policy-ack as adrPath.';
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const ADR_PATH_MISSING_FILE_ASK =
|
|
16
16
|
'The acknowledgement names a decision note that is missing or empty.';
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const ADR_PATH_MISSING_FILE_NEXT =
|
|
19
19
|
'Write that note (or fix adrPath) under docs/adr/ or docs/decisions/, then run ArkGate again.';
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -24,7 +24,7 @@ export const ADR_PATH_MISSING_FILE_NEXT =
|
|
|
24
24
|
* @param {unknown} value
|
|
25
25
|
* @returns {string | null}
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
function canonicalizeAdrPath(value) {
|
|
28
28
|
if (typeof value !== 'string') return null;
|
|
29
29
|
const rel = value.trim().replace(/\\/g, '/');
|
|
30
30
|
if (!rel || rel.startsWith('/') || /^[A-Za-z]:\//.test(rel) || rel.includes('\0')) return null;
|
package/bin/lib/agent-gates.mjs
CHANGED
|
@@ -3,62 +3,24 @@
|
|
|
3
3
|
* Implementation lives in focused modules under bin/lib/.
|
|
4
4
|
*/
|
|
5
5
|
export {
|
|
6
|
-
assessCodexHomeMcp,
|
|
7
|
-
codexArkBlockHasPreferredBin,
|
|
8
|
-
codexArkBlockNeedsRewrite,
|
|
9
|
-
codexConfigPath,
|
|
10
|
-
codexPrimaryTable,
|
|
11
|
-
codexProjectMcpIsValid,
|
|
12
|
-
codexProjectSlug,
|
|
13
|
-
codexPromptsDir,
|
|
14
|
-
codexSkillsDir,
|
|
15
|
-
codexScopedTableForRoot,
|
|
16
|
-
extractCodexArkRootFromToml,
|
|
17
|
-
extractCodexRootFromBlock,
|
|
18
6
|
isTempOrUpgradeRoot,
|
|
19
|
-
listCodexArkServerTables,
|
|
20
|
-
upsertCodexMcpTable,
|
|
21
7
|
wireCodexMcp,
|
|
22
8
|
} from './codex-home.mjs';
|
|
23
9
|
|
|
24
10
|
export {
|
|
25
|
-
PREFERRED_MCP_BIN,
|
|
26
|
-
antigravityHooks,
|
|
27
11
|
claudeSettings,
|
|
28
|
-
codexProjectConfig,
|
|
29
|
-
cursorHooks,
|
|
30
12
|
grokHooks,
|
|
31
|
-
grokProjectConfig,
|
|
32
|
-
mergeAntigravityArkHook,
|
|
33
|
-
mergeCursorArkHook,
|
|
34
|
-
mergeOpencodeArkMcp,
|
|
35
|
-
opencodeProjectConfig,
|
|
36
13
|
} from './hook-templates.mjs';
|
|
37
14
|
|
|
38
15
|
export { detectWritePathCapabilities } from './write-path-detect.mjs';
|
|
39
16
|
|
|
40
|
-
export {
|
|
41
|
-
ensureBaselineFlagInCheckCommand,
|
|
42
|
-
syncBaselineIntoCheckSurfaces,
|
|
43
|
-
pinArkgateDevDependency,
|
|
44
|
-
IO_DIR_SEGMENTS,
|
|
45
|
-
detectContractFalseGreenRisk,
|
|
46
|
-
FALSE_GREEN_GAP_ID,
|
|
47
|
-
falseGreenAdoptionGap,
|
|
48
|
-
} from './field-install.mjs';
|
|
49
|
-
|
|
50
17
|
export {
|
|
51
18
|
readJson,
|
|
52
|
-
readPackageJson,
|
|
53
19
|
hasCheckArchitectureScript,
|
|
54
|
-
packageScriptsHaveTypecheck,
|
|
55
|
-
treeHasTypecheckScript,
|
|
56
20
|
ensureTypecheckScript,
|
|
57
21
|
compactRouterHost,
|
|
58
22
|
REQUIRED_GATE_FILES,
|
|
59
|
-
hasArkWorkflow,
|
|
60
23
|
missingGates,
|
|
61
|
-
ensureDirForFile,
|
|
62
24
|
isArkAgentsContent,
|
|
63
25
|
isSelfHostedLibraryAgents,
|
|
64
26
|
writeTemplate,
|
|
@@ -67,39 +29,23 @@ export {
|
|
|
67
29
|
export { loadTypeScript } from './typescript-host.mjs';
|
|
68
30
|
|
|
69
31
|
export {
|
|
70
|
-
checkArgsForRoot,
|
|
71
|
-
packageManager,
|
|
72
32
|
arkCheckCommand,
|
|
73
33
|
checkArchitectureScriptSnippet,
|
|
74
|
-
ensureCheckArchitectureScript,
|
|
75
|
-
layerPlacementTable,
|
|
76
|
-
loadConfigLayersForAgents,
|
|
77
34
|
agentInstructions,
|
|
78
|
-
mcpJson,
|
|
79
|
-
codexTomlSnippet,
|
|
80
|
-
instructionRule,
|
|
81
|
-
cursorRule,
|
|
82
|
-
detectNodeMajorFromWorkflows,
|
|
83
|
-
detectCiNode,
|
|
84
35
|
githubWorkflow,
|
|
85
36
|
} from './ci-and-commands.mjs';
|
|
86
37
|
|
|
87
38
|
export {
|
|
88
39
|
normalizeToolsList,
|
|
89
40
|
resolveTools,
|
|
90
|
-
KNOWN_TOOLS,
|
|
91
41
|
SKILL_TOOL_TARGETS,
|
|
92
42
|
detectActiveAgentHost,
|
|
93
43
|
codexConcernIsActive,
|
|
94
44
|
arkPackageVersion,
|
|
95
45
|
stampSkill,
|
|
96
46
|
installedSkillVersion,
|
|
97
|
-
isVersionOlder,
|
|
98
|
-
skillContentIdentity,
|
|
99
|
-
skillContentMatchesTemplate,
|
|
100
47
|
skillTemplates,
|
|
101
48
|
skillTemplateNames,
|
|
102
|
-
skillTemplateBodies,
|
|
103
49
|
detectCodexHomeGap,
|
|
104
50
|
detectCodexRepoSkillGap,
|
|
105
51
|
assessCodexSkillParity,
|
|
@@ -107,7 +53,6 @@ export {
|
|
|
107
53
|
detectSkillGaps,
|
|
108
54
|
skillGapsForActiveHost,
|
|
109
55
|
skillGapToolLabel,
|
|
110
|
-
SKILL_CANONICAL_TOOL,
|
|
111
56
|
agentsMdSkillRefs,
|
|
112
57
|
verifyHostSkillCatalog,
|
|
113
58
|
printSkillAndCodexGapHints,
|
|
@@ -123,18 +68,12 @@ export {
|
|
|
123
68
|
} from './mcp-adoption.mjs';
|
|
124
69
|
|
|
125
70
|
export {
|
|
126
|
-
detectPreCommitArk,
|
|
127
71
|
detectCiEnforcement,
|
|
128
72
|
classifyArkCheckFlags,
|
|
129
|
-
detectConfigGateDrift,
|
|
130
|
-
jobIdsThatRunArkCheck,
|
|
131
|
-
isArkRequiredStatusCheck,
|
|
132
|
-
reportGithubBranchProtection,
|
|
133
73
|
collectWeakestLinkGaps,
|
|
134
74
|
} from './weakest-link.mjs';
|
|
135
75
|
|
|
136
76
|
export {
|
|
137
|
-
buildManagedAssetCatalog,
|
|
138
77
|
staleRunnerGateFiles,
|
|
139
78
|
warnLockfileConflict,
|
|
140
79
|
runMigrateCommands,
|
package/bin/lib/agent-homes.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
arkPackageVersion,
|
|
14
14
|
assessSkillCatalogParity,
|
|
15
15
|
detectActiveAgentHost,
|
|
16
|
+
homeCatalogFloorState,
|
|
16
17
|
isValidSemver,
|
|
17
18
|
isVersionOlder,
|
|
18
19
|
skillTemplateNames,
|
|
@@ -52,43 +53,43 @@ const HOSTS = {
|
|
|
52
53
|
},
|
|
53
54
|
};
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
function agentHomeHostIds() {
|
|
56
57
|
return Object.keys(HOSTS);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
function claudeHomeDir(env = process.env, homeDir = os.homedir()) {
|
|
60
61
|
return resolveHomeDir(HOSTS.claude, env, homeDir);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
function grokHomeDir(env = process.env, homeDir = os.homedir()) {
|
|
64
65
|
return resolveHomeDir(HOSTS.grok, env, homeDir);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
function claudeSkillsDir(env = process.env, homeDir = os.homedir()) {
|
|
68
69
|
return path.join(claudeHomeDir(env, homeDir), 'skills');
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
function grokSkillsDir(env = process.env, homeDir = os.homedir()) {
|
|
72
73
|
return path.join(grokHomeDir(env, homeDir), 'skills');
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
function antigravityHomeDir(env = process.env, homeDir = os.homedir()) {
|
|
76
77
|
return resolveHomeDir(HOSTS.antigravity, env, homeDir);
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
function antigravitySkillsDir(env = process.env, homeDir = os.homedir()) {
|
|
80
81
|
return path.join(antigravityHomeDir(env, homeDir), 'skills');
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
function usesDefaultAntigravityHome(env = process.env, homeDir = os.homedir()) {
|
|
84
85
|
return usesDefaultHome(HOSTS.antigravity, env, homeDir);
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
function usesDefaultClaudeHome(env = process.env, homeDir = os.homedir()) {
|
|
88
89
|
return usesDefaultHome(HOSTS.claude, env, homeDir);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
function usesDefaultGrokHome(env = process.env, homeDir = os.homedir()) {
|
|
92
93
|
return usesDefaultHome(HOSTS.grok, env, homeDir);
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -129,17 +130,7 @@ function readHomeCatalogFloor(skillsDir) {
|
|
|
129
130
|
};
|
|
130
131
|
const catalog = readOne(path.join(skillsDir, HOME_SKILL_CATALOG));
|
|
131
132
|
const pending = readOne(path.join(skillsDir, HOME_SKILL_PENDING_CATALOG));
|
|
132
|
-
|
|
133
|
-
if (pending.version && (!floorVersion || isVersionOlder(floorVersion, pending.version))) {
|
|
134
|
-
floorVersion = pending.version;
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
floorVersion,
|
|
138
|
-
pendingVersion: pending.version,
|
|
139
|
-
hasMetadata: catalog.exists || pending.exists,
|
|
140
|
-
metadataInvalid:
|
|
141
|
-
(catalog.exists && !catalog.valid) || (pending.exists && !pending.valid),
|
|
142
|
-
};
|
|
133
|
+
return homeCatalogFloorState(catalog, pending);
|
|
143
134
|
}
|
|
144
135
|
|
|
145
136
|
function homeInPlay(parity, catalogState) {
|
|
@@ -43,7 +43,7 @@ function packageVersionFallback() {
|
|
|
43
43
|
* Resolve catalog short-list entries (ruleId + title) from the public catalog.
|
|
44
44
|
* @param {readonly string[]|null|undefined} [ruleIds]
|
|
45
45
|
*/
|
|
46
|
-
|
|
46
|
+
function resolveProjectionCatalogShortList(ruleIds) {
|
|
47
47
|
const ids =
|
|
48
48
|
Array.isArray(ruleIds) && ruleIds.length > 0 ? ruleIds : DEFAULT_AGENT_PROJECTION_RULE_IDS;
|
|
49
49
|
return ids.map((ruleId) => {
|
|
@@ -67,7 +67,7 @@ export function resolveProjectionCatalogShortList(ruleIds) {
|
|
|
67
67
|
* checkCommand?: string|null,
|
|
68
68
|
* }} [options]
|
|
69
69
|
*/
|
|
70
|
-
|
|
70
|
+
function collectAgentProjectionFacts(options = {}) {
|
|
71
71
|
const startRoot = path.resolve(options.root || process.cwd());
|
|
72
72
|
const configName = options.config || 'ark.config.json';
|
|
73
73
|
let resolvedRoot = startRoot;
|
|
@@ -134,7 +134,7 @@ export function collectAgentProjectionFacts(options = {}) {
|
|
|
134
134
|
* Build projection block + meta for a project (no write).
|
|
135
135
|
* @param {Parameters<typeof collectAgentProjectionFacts>[0]} [options]
|
|
136
136
|
*/
|
|
137
|
-
|
|
137
|
+
function buildProjectAgentProjection(options = {}) {
|
|
138
138
|
const facts = collectAgentProjectionFacts(options);
|
|
139
139
|
const block = buildAgentProjectionBlock(facts);
|
|
140
140
|
const meta = buildAgentProjectionMeta(facts);
|
|
@@ -211,7 +211,7 @@ export function planAgentProjectionRefresh(options = {}) {
|
|
|
211
211
|
* @param {ReturnType<typeof planAgentProjectionRefresh>} plan
|
|
212
212
|
* @param {{ write?: boolean }} [opts]
|
|
213
213
|
*/
|
|
214
|
-
|
|
214
|
+
function applyAgentProjectionRefresh(plan, opts = {}) {
|
|
215
215
|
const shouldWrite = opts.write !== false;
|
|
216
216
|
if (!plan.wouldWrite) {
|
|
217
217
|
return { wrote: false, action: plan.action, path: plan.path };
|
|
@@ -15,49 +15,28 @@
|
|
|
15
15
|
import fs from 'node:fs';
|
|
16
16
|
import path from 'node:path';
|
|
17
17
|
import { layerForFile } from '../ark-shared.mjs';
|
|
18
|
+
import { loadAckSidecar } from './contract-smells.mjs';
|
|
18
19
|
|
|
19
20
|
export const AMBIENT_STATE_ACKS_PATH = '.ark/ambient-state-acks.json';
|
|
20
21
|
|
|
21
|
-
const MAX_ACK_BYTES = 64 * 1024;
|
|
22
|
-
const MAX_ACK_ENTRIES = 200;
|
|
23
22
|
const MAX_FILE_BYTES = 256 * 1024;
|
|
24
23
|
const MAX_FINDINGS = 50;
|
|
25
24
|
|
|
26
25
|
/** Bounded, fail-loud sidecar loader (same discipline as contract-smell acks). */
|
|
27
26
|
export function loadAmbientStateAcks(root) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
stats = fs.statSync(abs);
|
|
33
|
-
} catch {
|
|
34
|
-
return { path: relPath, exists: false, acks: [] };
|
|
35
|
-
}
|
|
36
|
-
const invalid = (error) => ({ path: relPath, exists: true, invalid: true, error, acks: [] });
|
|
37
|
-
if (!stats.isFile()) return invalid('not a regular file');
|
|
38
|
-
if (stats.size > MAX_ACK_BYTES) return invalid(`larger than ${MAX_ACK_BYTES} bytes`);
|
|
39
|
-
let parsed;
|
|
40
|
-
try {
|
|
41
|
-
parsed = JSON.parse(fs.readFileSync(abs, 'utf8'));
|
|
42
|
-
} catch (error) {
|
|
43
|
-
return invalid(error instanceof Error ? error.message : 'unreadable JSON');
|
|
44
|
-
}
|
|
45
|
-
const acks = Array.isArray(parsed?.acks) ? parsed.acks : null;
|
|
46
|
-
if (!acks) return invalid('expected { acks: [{ file, name, reason? }] }');
|
|
47
|
-
if (acks.length > MAX_ACK_ENTRIES) return invalid(`more than ${MAX_ACK_ENTRIES} entries`);
|
|
48
|
-
const wellFormed = acks.every(
|
|
49
|
-
(a) =>
|
|
27
|
+
return loadAckSidecar(root, AMBIENT_STATE_ACKS_PATH, {
|
|
28
|
+
shape: '{ acks: [{ file, name, reason? }] }',
|
|
29
|
+
isWellFormed: (a) =>
|
|
50
30
|
a !== null &&
|
|
51
31
|
typeof a === 'object' &&
|
|
52
32
|
typeof a.file === 'string' &&
|
|
53
33
|
a.file.length > 0 &&
|
|
54
34
|
typeof a.name === 'string' &&
|
|
55
|
-
a.name.length > 0
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return { path: relPath, exists: true, acks: normalized };
|
|
35
|
+
a.name.length > 0,
|
|
36
|
+
malformed: 'every ack needs string file and name',
|
|
37
|
+
// Normalize separators so a Windows-authored ack file still matches.
|
|
38
|
+
normalize: (acks) => acks.map((a) => ({ ...a, file: a.file.replace(/\\/g, '/') })),
|
|
39
|
+
});
|
|
61
40
|
}
|
|
62
41
|
|
|
63
42
|
function isAcknowledged(ackState, file, name) {
|