@event4u/agent-config 16.0.0 → 16.1.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +297 -137
- package/CONTRIBUTING.md +9 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +26 -0
- package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
- package/dist/agent-src/commands/challenge-me/closure.md +178 -0
- package/dist/agent-src/commands/challenge-me.md +9 -2
- package/dist/agent-src/commands/council/default.md +25 -5
- package/dist/agent-src/commands/feature/plan.md +28 -1
- package/dist/agent-src/commands/feature/roadmap.md +28 -1
- package/dist/agent-src/commands/implement-ticket.md +27 -0
- package/dist/agent-src/commands/jira-ticket.md +27 -0
- package/dist/agent-src/commands/pr/create.md +29 -0
- package/dist/agent-src/commands/pr/merge.md +60 -9
- package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
- package/dist/agent-src/commands/roadmap/create.md +74 -27
- package/dist/agent-src/commands/roadmap/materialize.md +27 -0
- package/dist/agent-src/commands/roadmap/process-full.md +123 -18
- package/dist/agent-src/commands/team.md +22 -0
- package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
- package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
- package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
- package/dist/agent-src/rules/autonomous-execution.md +15 -8
- package/dist/agent-src/rules/delegation-policy.md +23 -45
- package/dist/agent-src/rules/design-fidelity.md +32 -37
- package/dist/agent-src/rules/evaluator-independence.md +43 -49
- package/dist/agent-src/rules/test-first.md +41 -0
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
- package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
- package/dist/agent-src/skills/database/data/manifest.json +4 -4
- package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
- package/dist/agent-src/skills/design-review/SKILL.md +50 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
- package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
- package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
- package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +188 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/dist/cli-delegate/check_update_banner.js +40 -2
- package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
- package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
- package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
- package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
- package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
- package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
- package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
- package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
- package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
- package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
- package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
- package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
- package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
- package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +90 -56
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +9 -7
- package/dist/cli-delegate/cmd_fleet.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +4 -4
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +4 -2
- package/dist/cli-delegate/cmd_prune.js +10 -8
- package/dist/cli-delegate/cmd_route_audit.js +2 -2
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_settings_get.js +28 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +10 -8
- package/dist/cli-delegate/cmd_uninstall.js +16 -13
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +12 -10
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +85 -38
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +10 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +8 -6
- package/dist/hooks/dispatch.js +1832 -1007
- package/dist/install/claudeRuleRewrite.js +14 -3
- package/dist/install/conflict.js +60 -10
- package/dist/install/conflictTracker.js +218 -0
- package/dist/install/fsPrimitives.js +54 -0
- package/dist/install/install.mjs +2007 -1481
- package/dist/install/manifestFiles.js +259 -0
- package/dist/install/preflight.js +14 -2
- package/dist/install/preserve.js +157 -0
- package/dist/install/recordedOwnership.js +132 -0
- package/dist/install/txlog.js +11 -2
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +398 -39
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +3 -2
- package/dist/scripts/_lib/fs_atomic.js +167 -0
- package/dist/scripts/_lib/installed_tools.js +460 -0
- package/dist/scripts/_lib/lean_projection_mode.js +3 -2
- package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
- package/dist/server/routes/install.js +8 -0
- package/dist/server/routes/wizard.js +9 -3
- package/dist/server/schemas/settings.js +17 -5
- package/dist/shared/missionExecution.js +97 -0
- package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +103 -0
- package/docs/contracts/settings-classes.md +26 -7
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/docs/guidelines/design-fidelity-routing.md +29 -0
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/src/config/agent-settings.template.yml +139 -27
- package/src/config/auto-rule-budget.json +16 -0
- package/src/config/ci-local-parity.yml +18 -5
- package/src/config/continuity-surface.json +21 -0
- package/src/config/gate-coverage.yml +146 -13
- package/src/config/gate-violation-baselines.json +6 -6
- package/src/config/hook-token-budget.json +2 -0
- package/src/config/loop-surfaces.yaml +215 -0
- package/src/config/platform-anchor.json +3 -2
- package/src/config/release-gate-locality.yml +11 -0
- package/src/config/routing-coverage-seed.json +18 -4
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/install/claudeRuleRewrite.ts +16 -2
- package/src/install/conflict.ts +65 -9
- package/src/install/conflictTracker.ts +299 -0
- package/src/install/fsPrimitives.ts +54 -0
- package/src/install/manifestFiles.ts +312 -0
- package/src/install/preflight.ts +16 -2
- package/src/install/preserve.ts +205 -0
- package/src/install/recordedOwnership.ts +149 -0
- package/src/install/txlog.ts +11 -2
- package/src/install/types.ts +19 -4
- package/src/scripts/_cli/cmd_conformance.ts +88 -15
- package/src/scripts/_cli/cmd_doctor.ts +4 -3
- package/src/scripts/_cli/cmd_route_explain.ts +9 -2
- package/src/scripts/_cli/cmd_settings_get.ts +44 -0
- package/src/scripts/_cli/doctor_execution.ts +90 -0
- package/src/scripts/_lib/activation_payload.ts +247 -0
- package/src/scripts/_lib/agent_settings.ts +4 -2
- package/src/scripts/_lib/authority_path.ts +102 -0
- package/src/scripts/_lib/cascade_base.ts +94 -0
- package/src/scripts/_lib/changelog_eras.ts +7 -2
- package/src/scripts/_lib/continuation_ladder.ts +149 -2
- package/src/scripts/_lib/council_transport.ts +129 -0
- package/src/scripts/_lib/delivery_ready.ts +112 -0
- package/src/scripts/_lib/forge_protection.ts +267 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- package/src/scripts/_lib/json_python_parity.ts +127 -0
- package/src/scripts/_lib/lean_projection_mode.ts +14 -3
- package/src/scripts/_lib/loop_surfaces.ts +382 -0
- package/src/scripts/_lib/mission_record.ts +190 -0
- package/src/scripts/_lib/obligation_frequency.ts +217 -0
- package/src/scripts/_lib/obligations.ts +402 -0
- package/src/scripts/_lib/orchestration_record.ts +11 -20
- package/src/scripts/_lib/release_highlights.ts +199 -10
- package/src/scripts/_lib/release_holds.ts +493 -0
- package/src/scripts/_lib/release_migration_gate.ts +184 -0
- package/src/scripts/_lib/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -0
- package/src/scripts/_lib/typed_op_grant.ts +246 -0
- package/src/scripts/_lib/typed_op_watch.ts +185 -0
- package/src/scripts/ai_council/config.ts +8 -11
- package/src/scripts/ai_council/fallback_config.ts +5 -3
- package/src/scripts/ai_council/ownership_classes.ts +118 -0
- package/src/scripts/ask_block_census.ts +285 -15
- package/src/scripts/check_enforcement_matrix.ts +624 -0
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +954 -0
- package/src/scripts/check_preamble_payload_budget.ts +75 -2
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +567 -0
- package/src/scripts/check_rule_projection_integrity.ts +22 -12
- package/src/scripts/check_test_delta.ts +294 -0
- package/src/scripts/check_test_weakening.ts +299 -0
- package/src/scripts/closure_scan.ts +333 -0
- package/src/scripts/compile_hook_manifest.ts +43 -3
- package/src/scripts/council_record_shape.ts +209 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +88 -9
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/design_pass_hook.ts +128 -3
- package/src/scripts/hooks/evidence_independence.ts +96 -0
- package/src/scripts/hooks/memory_recall_hook.ts +540 -0
- package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
- package/src/scripts/hooks/rule_inject_hook.ts +49 -1
- package/src/scripts/hooks/run_continuation_hook.ts +17 -20
- package/src/scripts/hooks_doctor.ts +85 -0
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +106 -206
- package/src/scripts/janitor.ts +7 -0
- package/src/scripts/lint_decision_classes.ts +464 -0
- package/src/scripts/lint_hook_manifest.ts +11 -0
- package/src/scripts/lint_major_migration_sections.ts +450 -0
- package/src/scripts/lint_plan_risk_register.ts +47 -3
- package/src/scripts/lint_roadmap_blockers.ts +61 -0
- package/src/scripts/lint_roadmap_producers.ts +202 -0
- package/src/scripts/measure_rule_budget.ts +101 -5
- package/src/scripts/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/release.ts +14 -98
- package/src/scripts/release_drill.ts +267 -1
- package/src/scripts/release_publication.ts +51 -0
- package/src/scripts/report_enforcement_drift.ts +566 -0
- package/src/scripts/report_host_injection_effect.ts +3 -11
- package/src/scripts/report_standing_payload_by_host.ts +26 -152
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/command.schema.json +4 -0
- package/src/scripts/scope_growth.ts +219 -0
- package/src/scripts/trigger_eval_grandfather.json +0 -1
- package/src/scripts/ui_conformance_probe.ts +622 -0
- package/src/server/schemas/settings.ts +31 -7
- package/src/shared/missionExecution.ts +126 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
package/src/scripts/install.ts
CHANGED
|
@@ -20,13 +20,17 @@
|
|
|
20
20
|
* Usage:
|
|
21
21
|
* tsx src/scripts/install.ts # defaults: rule_loading_tier=balanced
|
|
22
22
|
* tsx src/scripts/install.ts --profile=minimal # set rule_loading_tier=minimal (kernel only)
|
|
23
|
-
* tsx src/scripts/install.ts --force #
|
|
23
|
+
* tsx src/scripts/install.ts --force # replace managed files the user has edited
|
|
24
24
|
* tsx src/scripts/install.ts --skip-bridges # only create .agent-settings.yml
|
|
25
25
|
* tsx src/scripts/install.ts --project <dir> # override project root
|
|
26
26
|
*
|
|
27
|
-
* Idempotent — safe to run multiple times. A run
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* Idempotent — safe to run multiple times. A run refreshes every deployed file
|
|
28
|
+
* with the current package content, EXCEPT a managed file whose bytes diverge
|
|
29
|
+
* from the digest the install manifest recorded: that one is preserved, package
|
|
30
|
+
* content is staged beside it as `<path>.agent-config.new`, and the run exits 3
|
|
31
|
+
* rather than 0 so the staleness is stated, not silent; `--force` replaces it
|
|
32
|
+
* instead. Contract + state machine: `install/preserve.ts`, `conflictTracker.ts`.
|
|
33
|
+
* User config (.agent-settings.yml) is settings-layer merged, never clobbered.
|
|
30
34
|
*
|
|
31
35
|
* --- Parity notes (ADR-200) ---
|
|
32
36
|
*
|
|
@@ -72,11 +76,16 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
72
76
|
import type * as YamlModule from 'yaml';
|
|
73
77
|
|
|
74
78
|
import { build_merge_entries } from './_lib/json_pointers.js';
|
|
79
|
+
import { jsonDumpsCompact, jsonDumpsIndent } from './_lib/json_python_parity.js';
|
|
75
80
|
import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
|
|
76
81
|
import * as installed_lock from './_lib/installed_lock.js';
|
|
77
82
|
import * as mcp_bridge from './_lib/mcp_bridge.js';
|
|
78
83
|
import * as mcp_consent from './_lib/mcp_consent_residual.js';
|
|
79
84
|
import * as scoped_projection from './_lib/scoped_projection.js';
|
|
85
|
+
import { createConflictTracker } from '../install/conflictTracker.js';
|
|
86
|
+
import { mkdirp, pathExists, resolvePath, sha256OfFile } from '../install/fsPrimitives.js';
|
|
87
|
+
import { filesByToolFromBridges as _files_by_tool_from_bridges, filesByToolFromDeploy as _files_by_tool_from_deploy, hydrateRecordedInventories, preservedIndex, readRecordedByTool, reconcileToolFiles, type ManifestFileEntry } from '../install/manifestFiles.js';
|
|
88
|
+
import { EXIT_COMPLETED_WITH_CONFLICTS } from '../install/preserve.js';
|
|
80
89
|
import * as surface_tiers from './_lib/surface_tiers.js';
|
|
81
90
|
import * as global_deploy_inventory from './_lib/global_deploy_inventory.js';
|
|
82
91
|
import * as rule_layer_overlap from './_lib/rule_layer_overlap.js';
|
|
@@ -113,6 +122,8 @@ import {
|
|
|
113
122
|
} from './_lib/model_tier.js';
|
|
114
123
|
import { main as cmdMigrateMain } from './_cli/cmd_migrate.js';
|
|
115
124
|
import { SCOPE_DETECT_AI_DIRS, SCOPE_DETECT_MANIFESTS } from '../install/detect.js';
|
|
125
|
+
import { getLogPath } from '../install/paths.js';
|
|
126
|
+
import { appendTxLog } from '../install/txlog.js';
|
|
116
127
|
|
|
117
128
|
// ---------------------------------------------------------------------------
|
|
118
129
|
// Python-runtime parity helpers
|
|
@@ -143,15 +154,6 @@ function expanduser(p: string): string {
|
|
|
143
154
|
return p;
|
|
144
155
|
}
|
|
145
156
|
|
|
146
|
-
/** `Path.resolve()` — absolute, symlink-resolved where possible. */
|
|
147
|
-
function resolvePath(p: string): string {
|
|
148
|
-
try {
|
|
149
|
-
return fs.realpathSync(path.resolve(p));
|
|
150
|
-
} catch {
|
|
151
|
-
return path.resolve(p);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
157
|
function isFile(p: string): boolean {
|
|
156
158
|
try {
|
|
157
159
|
return fs.statSync(p).isFile();
|
|
@@ -168,15 +170,6 @@ function isDir(p: string): boolean {
|
|
|
168
170
|
}
|
|
169
171
|
}
|
|
170
172
|
|
|
171
|
-
function pathExists(p: string): boolean {
|
|
172
|
-
try {
|
|
173
|
-
fs.statSync(p);
|
|
174
|
-
return true;
|
|
175
|
-
} catch {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
173
|
function isSymlink(p: string): boolean {
|
|
181
174
|
try {
|
|
182
175
|
return fs.lstatSync(p).isSymbolicLink();
|
|
@@ -193,11 +186,6 @@ function writeText(p: string, content: string): void {
|
|
|
193
186
|
fs.writeFileSync(p, content, 'utf-8');
|
|
194
187
|
}
|
|
195
188
|
|
|
196
|
-
/** `path.mkdir(parents=True, exist_ok=True)`. */
|
|
197
|
-
function mkdirp(p: string): void {
|
|
198
|
-
fs.mkdirSync(p, { recursive: true });
|
|
199
|
-
}
|
|
200
|
-
|
|
201
189
|
/**
|
|
202
190
|
* `sorted(Path.glob(pattern))` with PyYAML/pathlib component-wise ordering.
|
|
203
191
|
* We only need a non-recursive `*.glob("<pat>")`; pathlib sorts the matched
|
|
@@ -238,17 +226,6 @@ function countZips(directory: string): number {
|
|
|
238
226
|
return n;
|
|
239
227
|
}
|
|
240
228
|
|
|
241
|
-
/** `hashlib.sha256(data).hexdigest()` of a file's bytes, or null when unreadable. */
|
|
242
|
-
function sha256OfFile(p: string): string | null {
|
|
243
|
-
let data: Buffer;
|
|
244
|
-
try {
|
|
245
|
-
data = fs.readFileSync(p);
|
|
246
|
-
} catch {
|
|
247
|
-
return null;
|
|
248
|
-
}
|
|
249
|
-
return crypto.createHash('sha256').update(data).digest('hex');
|
|
250
|
-
}
|
|
251
|
-
|
|
252
229
|
/**
|
|
253
230
|
* Atomic write mirroring the Python `tempfile.mkstemp(...) → os.fdopen → write
|
|
254
231
|
* → os.chmod(0o644) → os.replace` pattern in `_write_consumer_bridge_marker`
|
|
@@ -299,108 +276,6 @@ function utcStamp(now?: Date): string {
|
|
|
299
276
|
);
|
|
300
277
|
}
|
|
301
278
|
|
|
302
|
-
// --- JSON byte-parity (ensure_ascii=False; insertion order) ---
|
|
303
|
-
|
|
304
|
-
function _jsonStrNoAscii(s: string): string {
|
|
305
|
-
// json.dumps(ensure_ascii=False): escape control chars + " + \, keep >=0x20
|
|
306
|
-
let out = '"';
|
|
307
|
-
for (const ch of s) {
|
|
308
|
-
const code = ch.codePointAt(0) as number;
|
|
309
|
-
switch (ch) {
|
|
310
|
-
case '"':
|
|
311
|
-
out += '\\"';
|
|
312
|
-
break;
|
|
313
|
-
case '\\':
|
|
314
|
-
out += '\\\\';
|
|
315
|
-
break;
|
|
316
|
-
case '\n':
|
|
317
|
-
out += '\\n';
|
|
318
|
-
break;
|
|
319
|
-
case '\r':
|
|
320
|
-
out += '\\r';
|
|
321
|
-
break;
|
|
322
|
-
case '\t':
|
|
323
|
-
out += '\\t';
|
|
324
|
-
break;
|
|
325
|
-
case '\b':
|
|
326
|
-
out += '\\b';
|
|
327
|
-
break;
|
|
328
|
-
case '\f':
|
|
329
|
-
out += '\\f';
|
|
330
|
-
break;
|
|
331
|
-
default:
|
|
332
|
-
if (code < 0x20) {
|
|
333
|
-
out += '\\u' + code.toString(16).padStart(4, '0');
|
|
334
|
-
} else {
|
|
335
|
-
out += ch;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return out + '"';
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function _jsonScalar(value: unknown): string | null {
|
|
343
|
-
if (value === null || value === undefined) return 'null';
|
|
344
|
-
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
345
|
-
if (typeof value === 'number') {
|
|
346
|
-
if (!Number.isFinite(value)) {
|
|
347
|
-
if (Number.isNaN(value)) return 'NaN';
|
|
348
|
-
return value > 0 ? 'Infinity' : '-Infinity';
|
|
349
|
-
}
|
|
350
|
-
// Our payloads carry only integers; render as-is.
|
|
351
|
-
return String(value);
|
|
352
|
-
}
|
|
353
|
-
if (typeof value === 'string') return _jsonStrNoAscii(value);
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function _dumpIndent(value: unknown, indent: number, depth: number): string {
|
|
358
|
-
const scalar = _jsonScalar(value);
|
|
359
|
-
if (scalar !== null) return scalar;
|
|
360
|
-
const pad = ' '.repeat(indent * (depth + 1));
|
|
361
|
-
const closePad = ' '.repeat(indent * depth);
|
|
362
|
-
if (Array.isArray(value)) {
|
|
363
|
-
if (value.length === 0) return '[]';
|
|
364
|
-
const items = value.map((v) => pad + _dumpIndent(v, indent, depth + 1));
|
|
365
|
-
return `[\n${items.join(',\n')}\n${closePad}]`;
|
|
366
|
-
}
|
|
367
|
-
if (typeof value === 'object' && value !== null) {
|
|
368
|
-
const obj = value as Record<string, unknown>;
|
|
369
|
-
const keys = Object.keys(obj);
|
|
370
|
-
if (keys.length === 0) return '{}';
|
|
371
|
-
const items = keys.map(
|
|
372
|
-
(k) => `${pad}${_jsonStrNoAscii(k)}: ${_dumpIndent(obj[k], indent, depth + 1)}`,
|
|
373
|
-
);
|
|
374
|
-
return `{\n${items.join(',\n')}\n${closePad}}`;
|
|
375
|
-
}
|
|
376
|
-
return _jsonStrNoAscii(String(value));
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/** `json.dumps(data, indent=N, ensure_ascii=False)` (sort_keys=False). */
|
|
380
|
-
function jsonDumpsIndent(value: unknown, indent: number): string {
|
|
381
|
-
return _dumpIndent(value, indent, 0);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/** `json.dumps(obj, separators=(",", ":"))` — compact, ensure_ascii=False here. */
|
|
385
|
-
function jsonDumpsCompact(value: unknown): string {
|
|
386
|
-
const scalar = _jsonScalar(value);
|
|
387
|
-
if (scalar !== null) return scalar;
|
|
388
|
-
if (Array.isArray(value)) {
|
|
389
|
-
return '[' + value.map((v) => jsonDumpsCompact(v)).join(',') + ']';
|
|
390
|
-
}
|
|
391
|
-
if (typeof value === 'object' && value !== null) {
|
|
392
|
-
const obj = value as Record<string, unknown>;
|
|
393
|
-
return (
|
|
394
|
-
'{' +
|
|
395
|
-
Object.keys(obj)
|
|
396
|
-
.map((k) => `${_jsonStrNoAscii(k)}:${jsonDumpsCompact(obj[k])}`)
|
|
397
|
-
.join(',') +
|
|
398
|
-
'}'
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
return _jsonStrNoAscii(String(value));
|
|
402
|
-
}
|
|
403
|
-
|
|
404
279
|
/** Lazy YAML safe_load mirroring PyYAML (version 1.1), `{}` on every error. */
|
|
405
280
|
function yamlSafeLoad(text: string): unknown {
|
|
406
281
|
let YAML: typeof YamlModule;
|
|
@@ -482,6 +357,11 @@ function _emit_progress_terminal(rc: number): void {
|
|
|
482
357
|
if (!state.PROGRESS_NDJSON) return;
|
|
483
358
|
if (rc === 0) {
|
|
484
359
|
_emit_progress({ type: 'done' });
|
|
360
|
+
} else if (rc === EXIT_COMPLETED_WITH_CONFLICTS) {
|
|
361
|
+
// A conflict is a completion, not a failure, so the count rides on
|
|
362
|
+
// `done`, not an `error` frame. Zero conflicts never reach here, so that
|
|
363
|
+
// frame stays byte-identical to `{"type":"done"}`.
|
|
364
|
+
_emit_progress({ type: 'done', conflicts: tracker.conflictState.preserved.length });
|
|
485
365
|
} else {
|
|
486
366
|
_emit_progress({ type: 'error', code: 'E_INSTALL', exitCode: rc });
|
|
487
367
|
}
|
|
@@ -553,10 +433,21 @@ function _is_interactive(): boolean {
|
|
|
553
433
|
}
|
|
554
434
|
}
|
|
555
435
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
436
|
+
/**
|
|
437
|
+
* Per-run conflict tracking; the state machine, the sidecar staging and the
|
|
438
|
+
* exit-code folding live in `src/install/conflictTracker.ts`, and only the
|
|
439
|
+
* wiring is here. Module scope, like `state` above, because
|
|
440
|
+
* `_copy_dir_dereferencing_symlinks` is reached through six `_deploy_*` frames
|
|
441
|
+
* carrying no project root — `begin()` scopes the tracker to a run instead.
|
|
442
|
+
*/
|
|
443
|
+
const tracker = createConflictTracker({
|
|
444
|
+
warn,
|
|
445
|
+
fail,
|
|
446
|
+
logWrite: (target) => _log_tx_entry('write', target),
|
|
447
|
+
emitProgress: (frame) => _emit_progress(frame),
|
|
448
|
+
tagDeployed: (target, source, package_root) =>
|
|
449
|
+
_inject_package_tag(target, source, package_root),
|
|
450
|
+
});
|
|
560
451
|
|
|
561
452
|
// --- File utilities ---
|
|
562
453
|
|
|
@@ -2444,75 +2335,36 @@ void prompt_collision_choice;
|
|
|
2444
2335
|
|
|
2445
2336
|
// --- Manifest / inventory helpers (lazy-import twins are eager static here) ---
|
|
2446
2337
|
|
|
2447
|
-
function _sha256_of_file(p: string): string | null {
|
|
2448
|
-
return sha256OfFile(p);
|
|
2449
|
-
}
|
|
2450
|
-
|
|
2451
|
-
function _file_entry(p: string, kind: string, hash_content: boolean): Record<string, unknown> {
|
|
2452
|
-
return {
|
|
2453
|
-
path: p,
|
|
2454
|
-
kind,
|
|
2455
|
-
sha256: hash_content ? _sha256_of_file(p) : null,
|
|
2456
|
-
};
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
2338
|
type DeployResult = scoped_projection.DeployTuple;
|
|
2460
2339
|
|
|
2461
|
-
function _files_by_tool_from_deploy(
|
|
2462
|
-
deploy_results: Record<string, DeployResult>,
|
|
2463
|
-
): Record<string, Record<string, unknown>[]> {
|
|
2464
|
-
const out: Record<string, Record<string, unknown>[]> = {};
|
|
2465
|
-
for (const tool_id of Object.keys(deploy_results)) {
|
|
2466
|
-
const [, , status, paths] = deploy_results[tool_id] as DeployResult;
|
|
2467
|
-
if (status === 'deployed') {
|
|
2468
|
-
out[tool_id] = paths.map((p) => _file_entry(p, 'deployed', true));
|
|
2469
|
-
} else if (status === 'marker') {
|
|
2470
|
-
out[tool_id] = paths.map((p) => _file_entry(p, 'marker', true));
|
|
2471
|
-
} else {
|
|
2472
|
-
out[tool_id] = [];
|
|
2473
|
-
}
|
|
2474
|
-
}
|
|
2475
|
-
return out;
|
|
2476
|
-
}
|
|
2477
|
-
|
|
2478
|
-
function _files_by_tool_from_bridges(
|
|
2479
|
-
tools: Set<string>,
|
|
2480
|
-
project_root: string,
|
|
2481
|
-
scope: string,
|
|
2482
|
-
): Record<string, Record<string, unknown>[]> {
|
|
2483
|
-
const out: Record<string, Record<string, unknown>[]> = {};
|
|
2484
|
-
for (const tool_id of [...tools].sort()) {
|
|
2485
|
-
const marker = _bridge_marker(tool_id, scope);
|
|
2486
|
-
if (!marker) continue;
|
|
2487
|
-
let marker_path = marker;
|
|
2488
|
-
if (!path.isAbsolute(marker_path)) {
|
|
2489
|
-
marker_path = path.join(project_root, marker_path);
|
|
2490
|
-
}
|
|
2491
|
-
out[tool_id] = [_file_entry(marker_path, 'bridge', false)];
|
|
2492
|
-
}
|
|
2493
|
-
return out;
|
|
2494
|
-
}
|
|
2495
|
-
|
|
2496
2340
|
function _update_installed_tools_manifest(
|
|
2497
2341
|
project_root: string,
|
|
2498
2342
|
tools: Set<string>,
|
|
2499
2343
|
scope: string,
|
|
2500
2344
|
force: boolean,
|
|
2501
|
-
files_by_tool: Record<string,
|
|
2345
|
+
files_by_tool: Record<string, ManifestFileEntry[] | null> | null = null,
|
|
2502
2346
|
merged_keys_by_tool: Record<string, Record<string, unknown>[]> | null = null,
|
|
2503
2347
|
): number {
|
|
2504
2348
|
const target = installed_tools.manifest_path(project_root);
|
|
2505
2349
|
const existing = (installed_tools.read_manifest(target) ?? {}) as Record<string, unknown>;
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2350
|
+
// Hydrated because `read_manifest` drops nested `files[]` by design: without
|
|
2351
|
+
// this, rewriting the manifest erases every recorded digest it did not just
|
|
2352
|
+
// rebuild, and an unrecorded managed file is overwritten on the next run.
|
|
2353
|
+
const prior = readRecordedByTool(target, project_root);
|
|
2354
|
+
const preserved = preservedIndex(tracker.conflictState.preserved, tracker.conflictState.staged);
|
|
2355
|
+
let entries = hydrateRecordedInventories(
|
|
2356
|
+
Array.isArray(existing['tools'])
|
|
2357
|
+
? ([...(existing['tools'] as unknown[])] as Record<string, unknown>[])
|
|
2358
|
+
: [],
|
|
2359
|
+
prior,
|
|
2360
|
+
);
|
|
2509
2361
|
|
|
2510
2362
|
const version = installed_lock.current_package_version();
|
|
2511
2363
|
|
|
2512
2364
|
for (const tool_id of [...tools].sort()) {
|
|
2513
2365
|
const marker = _bridge_marker(tool_id, scope);
|
|
2514
2366
|
if (!marker) continue;
|
|
2515
|
-
const files =
|
|
2367
|
+
const files = reconcileToolFiles(files_by_tool?.[tool_id], prior.get(tool_id), preserved);
|
|
2516
2368
|
const merged_keys = merged_keys_by_tool ? (merged_keys_by_tool[tool_id] ?? null) : null;
|
|
2517
2369
|
try {
|
|
2518
2370
|
entries = installed_tools.upsert_tool(entries, {
|
|
@@ -2890,6 +2742,25 @@ function _escapes_package_root(resolved: string, package_root: string | null): b
|
|
|
2890
2742
|
return !global_deploy_inventory.is_ancestor(root, resolved);
|
|
2891
2743
|
}
|
|
2892
2744
|
|
|
2745
|
+
/**
|
|
2746
|
+
* Append one `write`/`skip` entry to the transaction log, through the same
|
|
2747
|
+
* `appendTxLog` module the recovery-dismiss route calls — one writer, two
|
|
2748
|
+
* callers, identical entry shape. Failure is swallowed: the log is a recovery
|
|
2749
|
+
* aid, never a condition for the install itself to proceed.
|
|
2750
|
+
*/
|
|
2751
|
+
function _log_tx_entry(kind: 'write' | 'skip', target: string): void {
|
|
2752
|
+
try {
|
|
2753
|
+
appendTxLog(getLogPath(), {
|
|
2754
|
+
ts: new Date().toISOString(),
|
|
2755
|
+
kind,
|
|
2756
|
+
path: target,
|
|
2757
|
+
sha256: kind === 'write' ? sha256OfFile(target) : null,
|
|
2758
|
+
});
|
|
2759
|
+
} catch {
|
|
2760
|
+
/* swallow — the log is a recovery aid, not a precondition */
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2893
2764
|
/**
|
|
2894
2765
|
* Copy `src` → `dest`, dereferencing symlinks, returning
|
|
2895
2766
|
* `[written, skipped, written_paths]`.
|
|
@@ -2925,10 +2796,15 @@ function _copy_dir_dereferencing_symlinks(
|
|
|
2925
2796
|
return [0, 0, written_paths];
|
|
2926
2797
|
}
|
|
2927
2798
|
mkdirp(path.dirname(dest));
|
|
2928
|
-
const decision =
|
|
2929
|
-
if (decision === '
|
|
2799
|
+
const decision = tracker.resolve(dest, force);
|
|
2800
|
+
if (decision === 'preserve') {
|
|
2801
|
+
tracker.preserve(dest, resolved_src, package_root);
|
|
2802
|
+
_log_tx_entry('skip', dest);
|
|
2803
|
+
return [0, 1, written_paths];
|
|
2804
|
+
}
|
|
2930
2805
|
fs.copyFileSync(src, dest); // follow_symlinks=True is fs.copyFileSync default
|
|
2931
2806
|
_inject_package_tag(dest, src, package_root);
|
|
2807
|
+
_log_tx_entry('write', dest);
|
|
2932
2808
|
written_paths.push(dest);
|
|
2933
2809
|
return [1, 0, written_paths];
|
|
2934
2810
|
}
|
|
@@ -2995,14 +2871,17 @@ function _copy_dir_dereferencing_symlinks(
|
|
|
2995
2871
|
if (file_filter !== null && !file_filter(entry)) {
|
|
2996
2872
|
continue;
|
|
2997
2873
|
}
|
|
2998
|
-
const decision =
|
|
2999
|
-
if (decision === '
|
|
2874
|
+
const decision = tracker.resolve(target, force);
|
|
2875
|
+
if (decision === 'preserve') {
|
|
2876
|
+
tracker.preserve(target, resolved, package_root);
|
|
3000
2877
|
skipped += 1;
|
|
2878
|
+
_log_tx_entry('skip', target);
|
|
3001
2879
|
continue;
|
|
3002
2880
|
}
|
|
3003
2881
|
mkdirp(path.dirname(target));
|
|
3004
2882
|
fs.copyFileSync(resolved, target);
|
|
3005
2883
|
_inject_package_tag(target, resolved, package_root);
|
|
2884
|
+
_log_tx_entry('write', target);
|
|
3006
2885
|
written += 1;
|
|
3007
2886
|
written_paths.push(target);
|
|
3008
2887
|
}
|
|
@@ -3014,7 +2893,7 @@ function _claude_desktop_bundles_dir(): string {
|
|
|
3014
2893
|
}
|
|
3015
2894
|
|
|
3016
2895
|
function _write_claude_desktop_marker(
|
|
3017
|
-
|
|
2896
|
+
force: boolean,
|
|
3018
2897
|
lockfile_path: string,
|
|
3019
2898
|
bundles_dir: string,
|
|
3020
2899
|
bundle_count: number,
|
|
@@ -3023,7 +2902,15 @@ function _write_claude_desktop_marker(
|
|
|
3023
2902
|
const target = path.join(anchor, 'agent-config.md');
|
|
3024
2903
|
mkdirp(anchor);
|
|
3025
2904
|
const body = claudeDesktopMarkerBody(lockfile_path, anchor, bundles_dir, bundle_count);
|
|
2905
|
+
// Generated, but manifest-recorded with a digest — so it is in the class the
|
|
2906
|
+
// preservation ruling covers, and it used to write unconditionally, ignoring
|
|
2907
|
+
// even `--force`, because the tracker was wired only into the copy loop.
|
|
2908
|
+
if (tracker.resolve(target, force) === 'preserve') {
|
|
2909
|
+
tracker.preserveContent(target, body);
|
|
2910
|
+
return [0, 1, []];
|
|
2911
|
+
}
|
|
3026
2912
|
writeText(target, body);
|
|
2913
|
+
_log_tx_entry('write', target);
|
|
3027
2914
|
return [1, 0, [target]];
|
|
3028
2915
|
}
|
|
3029
2916
|
|
|
@@ -3217,6 +3104,7 @@ function _deploy_global_content(
|
|
|
3217
3104
|
info,
|
|
3218
3105
|
warn,
|
|
3219
3106
|
res,
|
|
3107
|
+
new Set(tracker.conflictState.preserved.map((p) => path.resolve(p))),
|
|
3220
3108
|
);
|
|
3221
3109
|
}
|
|
3222
3110
|
|
|
@@ -4927,10 +4815,16 @@ function main(argv: string[]): number {
|
|
|
4927
4815
|
const rc = _run_migrate_to_global(detect_root);
|
|
4928
4816
|
if (rc !== 0) return rc;
|
|
4929
4817
|
}
|
|
4930
|
-
|
|
4818
|
+
tracker.begin(detect_root);
|
|
4819
|
+
const rc = tracker.finalizeRc(
|
|
4820
|
+
install_global(parsed_tools, opts.force, detect_root, opts.core_only),
|
|
4821
|
+
);
|
|
4931
4822
|
_emit_progress_terminal(rc);
|
|
4932
|
-
|
|
4933
|
-
|
|
4823
|
+
// A preserved edit does not withhold the wizard, but it survives one: a
|
|
4824
|
+
// zero from the wizard must not erase the conflict signal this run earned.
|
|
4825
|
+
if ((rc === 0 || rc === EXIT_COMPLETED_WITH_CONFLICTS) && wizard_handoff) {
|
|
4826
|
+
const wizard_rc = _wizard_spawn(detect_root, false);
|
|
4827
|
+
return wizard_rc === 0 ? rc : wizard_rc;
|
|
4934
4828
|
}
|
|
4935
4829
|
return rc;
|
|
4936
4830
|
}
|
|
@@ -4938,10 +4832,12 @@ function main(argv: string[]): number {
|
|
|
4938
4832
|
const project_root =
|
|
4939
4833
|
custom_path || resolvePath(opts.project || process.env['PROJECT_ROOT'] || process.cwd());
|
|
4940
4834
|
const is_first_run = !pathExists(path.join(project_root, SETTINGS_FILE));
|
|
4941
|
-
|
|
4835
|
+
tracker.begin(project_root);
|
|
4836
|
+
let rc = _main_project_install(opts, project_root, parsed_tools, is_first_run);
|
|
4942
4837
|
if (rc === 0 && opts.interactive) {
|
|
4943
4838
|
run_interactive_init(project_root, opts.force);
|
|
4944
4839
|
}
|
|
4840
|
+
rc = tracker.finalizeRc(rc);
|
|
4945
4841
|
_emit_progress_terminal(rc);
|
|
4946
4842
|
return rc;
|
|
4947
4843
|
}
|
|
@@ -5185,7 +5081,7 @@ function _main_project_install(
|
|
|
5185
5081
|
}
|
|
5186
5082
|
|
|
5187
5083
|
if (!opts.skip_bridges) {
|
|
5188
|
-
const files_by_tool = _files_by_tool_from_bridges(parsed_tools, project_root, 'project');
|
|
5084
|
+
const files_by_tool = _files_by_tool_from_bridges(parsed_tools, project_root, 'project', _bridge_marker);
|
|
5189
5085
|
const rc = _update_installed_tools_manifest(
|
|
5190
5086
|
project_root,
|
|
5191
5087
|
parsed_tools,
|
|
@@ -5301,6 +5197,7 @@ export {
|
|
|
5301
5197
|
_format_global_root_for_marker,
|
|
5302
5198
|
_files_by_tool_from_bridges,
|
|
5303
5199
|
_files_by_tool_from_deploy,
|
|
5200
|
+
_update_installed_tools_manifest,
|
|
5304
5201
|
_verify_deploy_targets,
|
|
5305
5202
|
_wizard_should_launch,
|
|
5306
5203
|
_dry_run_summary,
|
|
@@ -5363,6 +5260,9 @@ export {
|
|
|
5363
5260
|
// road-to-local-ci-trust: exported for the symlink-confinement tests
|
|
5364
5261
|
// (PR #1076 review-gate finding).
|
|
5365
5262
|
_copy_dir_dereferencing_symlinks,
|
|
5263
|
+
// road-to-a-conformance-check-that-can-fail Phase 5.1: the wired tracker,
|
|
5264
|
+
// so the preservation path is testable (owner ruling 2026-09-21).
|
|
5265
|
+
tracker,
|
|
5366
5266
|
_preview_global_reap,
|
|
5367
5267
|
_resolve_global_rule_scope,
|
|
5368
5268
|
_rule_filter_for_source,
|
package/src/scripts/janitor.ts
CHANGED
|
@@ -87,6 +87,13 @@ const TTL_CONFIG: ReadonlyArray<{
|
|
|
87
87
|
owner: 'maintainer',
|
|
88
88
|
reviewBy: '2026-11-10',
|
|
89
89
|
},
|
|
90
|
+
{
|
|
91
|
+
dir: 'agents/runtime/state/memory-recall',
|
|
92
|
+
ttlDays: 7,
|
|
93
|
+
description: 'Per-session memory-recall latch (one flag per delivered memory slug)',
|
|
94
|
+
owner: 'maintainer',
|
|
95
|
+
reviewBy: '2026-11-10',
|
|
96
|
+
},
|
|
90
97
|
{
|
|
91
98
|
dir: 'agents/runtime/state/end-review-nudge',
|
|
92
99
|
ttlDays: 7,
|