archctx 0.2.1 → 0.2.3
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/assets/catalog.yaml +2 -2
- package/bin/archctx.mjs +1092 -604
- package/package.json +3 -4
- package/bin/codegraph.mjs +0 -6
package/bin/archctx.mjs
CHANGED
|
@@ -696,13 +696,13 @@ function productVersionManifest() {
|
|
|
696
696
|
sqliteMigrations: "0001_runtime_state..0004_changeset_journal",
|
|
697
697
|
codeGraph: {
|
|
698
698
|
packageName: "@colbymchenry/codegraph",
|
|
699
|
-
requiredVersion: "1.0
|
|
699
|
+
requiredVersion: "1.4.0",
|
|
700
700
|
adapter: "codegraph-cli"
|
|
701
701
|
}
|
|
702
702
|
}
|
|
703
703
|
};
|
|
704
704
|
}
|
|
705
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.2.
|
|
705
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.2.3", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.3.10", ARCHCONTEXT_NODE_RANGE = ">=24 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-06-25.al0-ledger";
|
|
706
706
|
// packages/contracts/src/index.ts
|
|
707
707
|
var init_src = __esm(() => {
|
|
708
708
|
init_control_plane_routes();
|
|
@@ -5145,8 +5145,8 @@ var init_src7 = __esm(() => {
|
|
|
5145
5145
|
|
|
5146
5146
|
// packages/surfaces/cli/src/main.ts
|
|
5147
5147
|
import { execFileSync as execFileSync8, spawn as spawn2, spawnSync as spawnSync3 } from "child_process";
|
|
5148
|
-
import { accessSync, chmodSync as chmodSync5, closeSync as closeSync7, constants, existsSync as
|
|
5149
|
-
import { dirname as
|
|
5148
|
+
import { accessSync as accessSync2, chmodSync as chmodSync5, closeSync as closeSync7, constants, existsSync as existsSync15, mkdirSync as mkdirSync9, openSync as openSync7, readFileSync as readFileSync14, rmSync as rmSync10, statSync as statSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
5149
|
+
import { dirname as dirname11, join as join10, resolve as resolve18 } from "path";
|
|
5150
5150
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5151
5151
|
|
|
5152
5152
|
// packages/contracts/src/index.ts
|
|
@@ -5292,8 +5292,8 @@ var UNTRUSTED_TOOL_ESCAPE_KEYS = new Set([
|
|
|
5292
5292
|
]);
|
|
5293
5293
|
|
|
5294
5294
|
// packages/cloud/hardening/src/index.ts
|
|
5295
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
5296
|
-
import { resolve as
|
|
5295
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync4 } from "node:fs";
|
|
5296
|
+
import { resolve as resolve4 } from "node:path";
|
|
5297
5297
|
|
|
5298
5298
|
// packages/core/architecture-domain/src/index.ts
|
|
5299
5299
|
init_src();
|
|
@@ -5654,8 +5654,9 @@ init_src2();
|
|
|
5654
5654
|
|
|
5655
5655
|
// packages/local-runtime/codegraph-adapter/src/index.ts
|
|
5656
5656
|
import { execFileSync } from "node:child_process";
|
|
5657
|
-
import { closeSync, existsSync, openSync, readSync, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
5658
|
-
import {
|
|
5657
|
+
import { accessSync, closeSync, constants as fsConstants, existsSync, openSync, readFileSync as readFileSync3, readSync, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
5658
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
5659
|
+
import { basename as basename2, delimiter, dirname, isAbsolute, join, posix, resolve as resolve3 } from "node:path";
|
|
5659
5660
|
|
|
5660
5661
|
// packages/core/architecture-delta/src/index.ts
|
|
5661
5662
|
init_src();
|
|
@@ -6582,9 +6583,11 @@ function numberExtension(value) {
|
|
|
6582
6583
|
// packages/local-runtime/codegraph-adapter/src/index.ts
|
|
6583
6584
|
init_src();
|
|
6584
6585
|
var REQUIRED_CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
|
|
6585
|
-
var REQUIRED_CODEGRAPH_VERSION = "1.0
|
|
6586
|
+
var REQUIRED_CODEGRAPH_VERSION = "1.4.0";
|
|
6586
6587
|
var CODEGRAPH_TELEMETRY_ENV = "DO_NOT_TRACK";
|
|
6587
6588
|
var CODEGRAPH_TELEMETRY_DISABLED_VALUE = "1";
|
|
6589
|
+
var DEFAULT_CODEGRAPH_BINARY = "codegraph";
|
|
6590
|
+
var requireFromAdapter = createRequire2(import.meta.url);
|
|
6588
6591
|
function disableCodeGraphTelemetryByDefault(env = process.env) {
|
|
6589
6592
|
env[CODEGRAPH_TELEMETRY_ENV] ??= CODEGRAPH_TELEMETRY_DISABLED_VALUE;
|
|
6590
6593
|
return env[CODEGRAPH_TELEMETRY_ENV] ?? CODEGRAPH_TELEMETRY_DISABLED_VALUE;
|
|
@@ -6595,7 +6598,7 @@ class CodeGraphCliProvider {
|
|
|
6595
6598
|
version = REQUIRED_CODEGRAPH_VERSION;
|
|
6596
6599
|
capabilities = ["index", "context", "impact"];
|
|
6597
6600
|
workspaceRoot;
|
|
6598
|
-
constructor(workspaceRoot = process.cwd(), binary =
|
|
6601
|
+
constructor(workspaceRoot = process.cwd(), binary = DEFAULT_CODEGRAPH_BINARY) {
|
|
6599
6602
|
this.binary = binary;
|
|
6600
6603
|
this.workspaceRoot = workspaceRoot;
|
|
6601
6604
|
}
|
|
@@ -6679,27 +6682,56 @@ class CodeGraphCliProvider {
|
|
|
6679
6682
|
}
|
|
6680
6683
|
}
|
|
6681
6684
|
}
|
|
6682
|
-
function codeGraphCliInvocation(binary, cwd) {
|
|
6683
|
-
const resolved = resolveExecutable(binary, cwd);
|
|
6685
|
+
function codeGraphCliInvocation(binary, cwd, pathValue = process.env.PATH ?? "") {
|
|
6686
|
+
const resolved = resolveExecutable(binary, cwd, pathValue);
|
|
6684
6687
|
if (resolved && isNodeRuntimeScript(resolved)) {
|
|
6685
6688
|
return { command: process.execPath, argsPrefix: [resolved] };
|
|
6686
6689
|
}
|
|
6690
|
+
if (!resolved && binary === DEFAULT_CODEGRAPH_BINARY) {
|
|
6691
|
+
const packagedShim = resolvePackagedCodeGraphShim();
|
|
6692
|
+
if (packagedShim)
|
|
6693
|
+
return { command: process.execPath, argsPrefix: [packagedShim] };
|
|
6694
|
+
}
|
|
6687
6695
|
return { command: binary, argsPrefix: [] };
|
|
6688
6696
|
}
|
|
6689
|
-
function resolveExecutable(binary, cwd) {
|
|
6697
|
+
function resolveExecutable(binary, cwd, pathValue) {
|
|
6690
6698
|
if (binary.includes("/") || binary.includes("\\")) {
|
|
6691
6699
|
const path = isAbsolute(binary) ? binary : join(cwd, binary);
|
|
6692
6700
|
return existsSync(path) ? realpathSync3.native(path) : undefined;
|
|
6693
6701
|
}
|
|
6694
|
-
for (const dir of
|
|
6702
|
+
for (const dir of pathValue.split(delimiter)) {
|
|
6695
6703
|
if (!dir)
|
|
6696
6704
|
continue;
|
|
6697
6705
|
const path = join(dir, binary);
|
|
6698
|
-
if (
|
|
6706
|
+
if (isExecutablePath(path))
|
|
6699
6707
|
return realpathSync3.native(path);
|
|
6700
6708
|
}
|
|
6701
6709
|
return;
|
|
6702
6710
|
}
|
|
6711
|
+
function isExecutablePath(path) {
|
|
6712
|
+
try {
|
|
6713
|
+
if (!statSync3(path).isFile())
|
|
6714
|
+
return false;
|
|
6715
|
+
if (process.platform !== "win32")
|
|
6716
|
+
accessSync(path, fsConstants.X_OK);
|
|
6717
|
+
return true;
|
|
6718
|
+
} catch {
|
|
6719
|
+
return false;
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
function resolvePackagedCodeGraphShim() {
|
|
6723
|
+
try {
|
|
6724
|
+
const manifestPath = requireFromAdapter.resolve(`${REQUIRED_CODEGRAPH_PACKAGE}/package.json`);
|
|
6725
|
+
const manifest = JSON.parse(readFileSync3(manifestPath, "utf8"));
|
|
6726
|
+
const relativeBin = manifest.bin?.codegraph;
|
|
6727
|
+
if (manifest.version !== REQUIRED_CODEGRAPH_VERSION || !relativeBin)
|
|
6728
|
+
return;
|
|
6729
|
+
const shimPath = resolve3(dirname(manifestPath), relativeBin);
|
|
6730
|
+
return existsSync(shimPath) ? realpathSync3.native(shimPath) : undefined;
|
|
6731
|
+
} catch {
|
|
6732
|
+
return;
|
|
6733
|
+
}
|
|
6734
|
+
}
|
|
6703
6735
|
function isNodeRuntimeScript(path) {
|
|
6704
6736
|
if (/\.[cm]?js$/i.test(path))
|
|
6705
6737
|
return true;
|
|
@@ -7094,7 +7126,7 @@ function uninstallMarker(content, host) {
|
|
|
7094
7126
|
`).trim();
|
|
7095
7127
|
}
|
|
7096
7128
|
function dependencyAudit(root) {
|
|
7097
|
-
const packageJson = JSON.parse(
|
|
7129
|
+
const packageJson = JSON.parse(readFileSync4(resolve4(root, "package.json"), "utf8"));
|
|
7098
7130
|
const issues = [];
|
|
7099
7131
|
if (!packageJson.engines?.node?.includes(">=24"))
|
|
7100
7132
|
issues.push("node engine must include >=24");
|
|
@@ -7107,7 +7139,7 @@ function secretScan(root) {
|
|
|
7107
7139
|
continue;
|
|
7108
7140
|
if (file === "packages/cloud/hardening/src/index.ts" || file.includes("/test/"))
|
|
7109
7141
|
continue;
|
|
7110
|
-
const body =
|
|
7142
|
+
const body = readFileSync4(resolve4(root, file), "utf8");
|
|
7111
7143
|
if (/(sk-[A-Za-z0-9]{20,}|ghp_[A-Za-z0-9]{20,}|BEGIN PRIVATE KEY)/.test(body))
|
|
7112
7144
|
findings.push(file);
|
|
7113
7145
|
}
|
|
@@ -7141,11 +7173,11 @@ function listFiles(root) {
|
|
|
7141
7173
|
walk(".");
|
|
7142
7174
|
return out;
|
|
7143
7175
|
function walk(relativeDir) {
|
|
7144
|
-
for (const entry of readdirSync3(
|
|
7176
|
+
for (const entry of readdirSync3(resolve4(root, relativeDir), { withFileTypes: true })) {
|
|
7145
7177
|
if ([".git", "node_modules", "coverage"].includes(entry.name))
|
|
7146
7178
|
continue;
|
|
7147
7179
|
const child = relativeDir === "." ? entry.name : `${relativeDir}/${entry.name}`;
|
|
7148
|
-
const full =
|
|
7180
|
+
const full = resolve4(root, child);
|
|
7149
7181
|
if (entry.isDirectory())
|
|
7150
7182
|
walk(child);
|
|
7151
7183
|
if (entry.isFile() && statSync4(full).size < 1e6)
|
|
@@ -7157,10 +7189,10 @@ function listFiles(root) {
|
|
|
7157
7189
|
// packages/local-runtime/local-store-sqlite/src/index.ts
|
|
7158
7190
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
7159
7191
|
import { createHash as createHash5, randomUUID } from "node:crypto";
|
|
7160
|
-
import { chmodSync, closeSync as closeSync2, existsSync as existsSync2, fsyncSync, lstatSync, mkdirSync, openSync as openSync2, readFileSync as
|
|
7161
|
-
import { createRequire as
|
|
7192
|
+
import { chmodSync, closeSync as closeSync2, existsSync as existsSync2, fsyncSync, lstatSync, mkdirSync, openSync as openSync2, readFileSync as readFileSync5, realpathSync as realpathSync4, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
7193
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
7162
7194
|
import { homedir } from "node:os";
|
|
7163
|
-
import { dirname, isAbsolute as isAbsolute2, join as join2, relative as relative3, resolve as
|
|
7195
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative3, resolve as resolve5 } from "node:path";
|
|
7164
7196
|
|
|
7165
7197
|
// packages/core/architecture-ledger/src/index.ts
|
|
7166
7198
|
init_src();
|
|
@@ -7493,7 +7525,7 @@ function planYamlToArchitectureLedgerImport(input) {
|
|
|
7493
7525
|
payloadVersion: "archcontext.architecture-ledger-yaml-import/v1",
|
|
7494
7526
|
repository: input.repository,
|
|
7495
7527
|
worktree: input.worktree,
|
|
7496
|
-
baseDigest:
|
|
7528
|
+
baseDigest: architectureLedgerStateDigest(emptyArchitectureLedgerState()),
|
|
7497
7529
|
resultingDigest: graphDigest,
|
|
7498
7530
|
headSha: input.worktree.headSha,
|
|
7499
7531
|
actor: { kind: "migration", id: "archctx-ledger-yaml-import" },
|
|
@@ -7677,8 +7709,6 @@ function planYamlToArchitectureLedgerRebuild(input) {
|
|
|
7677
7709
|
const plan = planYamlToArchitectureLedgerImport(input);
|
|
7678
7710
|
const previousGraphDigest = architectureLedgerStateDigest(input.previousState);
|
|
7679
7711
|
const deleteOperations = architectureLedgerDeletionOperations(input.previousState, plan.state);
|
|
7680
|
-
if (deleteOperations.length === 0)
|
|
7681
|
-
return plan;
|
|
7682
7712
|
const payload = architectureLedgerPayload(plan.event);
|
|
7683
7713
|
const event = normalizeArchitectureLedgerEvent({
|
|
7684
7714
|
...plan.event,
|
|
@@ -8244,41 +8274,41 @@ function projectArchitectureLedgerStateToYamlFiles(state) {
|
|
|
8244
8274
|
const canonical = canonicalArchitectureLedgerState(state);
|
|
8245
8275
|
const files = [
|
|
8246
8276
|
...canonical.entities.map((entity) => {
|
|
8277
|
+
const declared = declaredProjectionRecord(entity.metadata, ["archcontext.node/v1"], `entity ${entity.entityId}`);
|
|
8278
|
+
const summary = entity.summary;
|
|
8279
|
+
if (!summary)
|
|
8280
|
+
throw new Error(`architecture-ledger-projection-invalid: entity ${entity.entityId} requires summary`);
|
|
8247
8281
|
const body = canonicalArchitectureYaml({
|
|
8282
|
+
...declared,
|
|
8248
8283
|
schemaVersion: "archcontext.node/v1",
|
|
8249
8284
|
id: entity.entityId,
|
|
8250
8285
|
kind: entity.kind,
|
|
8251
8286
|
name: entity.canonicalName,
|
|
8252
8287
|
status: entity.status,
|
|
8253
|
-
|
|
8254
|
-
...entity.summary ? { summary: entity.summary } : {},
|
|
8255
|
-
...entity.metadata ? { metadata: entity.metadata } : {}
|
|
8288
|
+
summary
|
|
8256
8289
|
});
|
|
8257
8290
|
return projectionFile(`.archcontext/model/nodes/${pathSegment(entity.entityId)}.yaml`, body, "entity", entity.entityId);
|
|
8258
8291
|
}),
|
|
8259
8292
|
...canonical.relations.map((relation) => {
|
|
8260
|
-
const
|
|
8293
|
+
const declared = declaredProjectionRecord(relation.metadata, ["archcontext.relation/v1", "archcontext.cross-repo-relation/v1"], `relation ${relation.relationId}`);
|
|
8294
|
+
const schemaVersion = requireStringField(declared, "schemaVersion", `relation ${relation.relationId}`);
|
|
8295
|
+
const body = schemaVersion === "archcontext.cross-repo-relation/v1" ? canonicalArchitectureYaml({ ...declared, id: relation.relationId, kind: relation.kind }) : canonicalArchitectureYaml({
|
|
8296
|
+
...declared,
|
|
8261
8297
|
schemaVersion: "archcontext.relation/v1",
|
|
8262
8298
|
id: relation.relationId,
|
|
8263
8299
|
kind: relation.kind,
|
|
8264
8300
|
source: relation.sourceEntityId,
|
|
8265
|
-
target: relation.targetEntityId
|
|
8266
|
-
status: relation.status,
|
|
8267
|
-
...relation.summary ? { summary: relation.summary } : {},
|
|
8268
|
-
...relation.metadata ? { metadata: relation.metadata } : {}
|
|
8301
|
+
target: relation.targetEntityId
|
|
8269
8302
|
});
|
|
8270
8303
|
return projectionFile(`.archcontext/model/relations/${pathSegment(relation.relationId)}.yaml`, body, "relation", relation.relationId);
|
|
8271
8304
|
}),
|
|
8272
8305
|
...canonical.constraints.map((constraint) => {
|
|
8306
|
+
const declared = declaredProjectionRecord(constraint.metadata, ["archcontext.constraint/v1"], `constraint ${constraint.constraintId}`);
|
|
8273
8307
|
const body = canonicalArchitectureYaml({
|
|
8308
|
+
...declared,
|
|
8274
8309
|
schemaVersion: "archcontext.constraint/v1",
|
|
8275
8310
|
id: constraint.constraintId,
|
|
8276
|
-
|
|
8277
|
-
subject: constraint.subjectId,
|
|
8278
|
-
status: constraint.status,
|
|
8279
|
-
...constraint.severity ? { severity: constraint.severity } : {},
|
|
8280
|
-
...constraint.summary ? { summary: constraint.summary } : {},
|
|
8281
|
-
...constraint.metadata ? { metadata: constraint.metadata } : {}
|
|
8311
|
+
...constraint.severity ? { severity: constraint.severity } : {}
|
|
8282
8312
|
});
|
|
8283
8313
|
return projectionFile(`.archcontext/model/constraints/${pathSegment(constraint.constraintId)}.yaml`, body, "constraint", constraint.constraintId);
|
|
8284
8314
|
})
|
|
@@ -8453,12 +8483,11 @@ function yamlRecordToLedgerOperation(value, path, schemaVersion) {
|
|
|
8453
8483
|
const entityId = requireStringField(value, "id", path);
|
|
8454
8484
|
const entity = {
|
|
8455
8485
|
entityId,
|
|
8456
|
-
kind:
|
|
8457
|
-
canonicalName:
|
|
8458
|
-
status:
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
...metadataField(value, ["schemaVersion", "id", "kind", "name", "canonicalName", "status", "path", "summary"])
|
|
8486
|
+
kind: requireStringField(value, "kind", path),
|
|
8487
|
+
canonicalName: requireStringField(value, "name", path),
|
|
8488
|
+
status: declaredStatus(value.status, path),
|
|
8489
|
+
summary: requireStringField(value, "summary", path),
|
|
8490
|
+
metadata: { declared: value }
|
|
8462
8491
|
};
|
|
8463
8492
|
return { operation: { op: "upsert_entity", entity }, targetKind: "entity", targetId: entityId };
|
|
8464
8493
|
}
|
|
@@ -8466,12 +8495,12 @@ function yamlRecordToLedgerOperation(value, path, schemaVersion) {
|
|
|
8466
8495
|
const relationId = requireStringField(value, "id", path);
|
|
8467
8496
|
const relation = {
|
|
8468
8497
|
relationId,
|
|
8469
|
-
kind:
|
|
8498
|
+
kind: requireStringField(value, "kind", path),
|
|
8470
8499
|
sourceEntityId: requireStringField(value, "source", path),
|
|
8471
8500
|
targetEntityId: requireStringField(value, "target", path),
|
|
8472
|
-
status:
|
|
8473
|
-
|
|
8474
|
-
|
|
8501
|
+
status: "active",
|
|
8502
|
+
summary: requireStringField(value, "intent", path),
|
|
8503
|
+
metadata: { declared: value }
|
|
8475
8504
|
};
|
|
8476
8505
|
return { operation: { op: "upsert_relation", relation }, targetKind: "relation", targetId: relationId };
|
|
8477
8506
|
}
|
|
@@ -8481,25 +8510,28 @@ function yamlRecordToLedgerOperation(value, path, schemaVersion) {
|
|
|
8481
8510
|
const target = repoScopedTarget(value.target, path, "target");
|
|
8482
8511
|
const relation = {
|
|
8483
8512
|
relationId,
|
|
8484
|
-
kind:
|
|
8513
|
+
kind: requireStringField(value, "kind", path),
|
|
8485
8514
|
sourceEntityId: source,
|
|
8486
8515
|
targetEntityId: target,
|
|
8487
|
-
status:
|
|
8488
|
-
|
|
8489
|
-
|
|
8516
|
+
status: "active",
|
|
8517
|
+
summary: requireStringField(value, "intent", path),
|
|
8518
|
+
metadata: { declared: value }
|
|
8490
8519
|
};
|
|
8491
8520
|
return { operation: { op: "upsert_relation", relation }, targetKind: "relation", targetId: relationId };
|
|
8492
8521
|
}
|
|
8493
8522
|
if (schemaVersion === "archcontext.constraint/v1") {
|
|
8494
8523
|
const constraintId = requireStringField(value, "id", path);
|
|
8524
|
+
const scope = requiredRecordField(value, "scope", path);
|
|
8525
|
+
const rule = requiredRecordField(value, "rule", path);
|
|
8526
|
+
const subjectId = firstStringArrayValue(scope.nodes) ?? firstStringArrayValue(scope.relations) ?? "repository";
|
|
8495
8527
|
const constraint = {
|
|
8496
8528
|
constraintId,
|
|
8497
|
-
kind:
|
|
8498
|
-
subjectId
|
|
8499
|
-
status:
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8529
|
+
kind: requireStringField(rule, "type", path),
|
|
8530
|
+
subjectId,
|
|
8531
|
+
status: "active",
|
|
8532
|
+
severity: requiredSeverity(value.severity, path),
|
|
8533
|
+
summary: requireStringField(value, "rationale", path),
|
|
8534
|
+
metadata: { declared: value }
|
|
8503
8535
|
};
|
|
8504
8536
|
return { operation: { op: "upsert_constraint", constraint }, targetKind: "constraint", targetId: constraintId };
|
|
8505
8537
|
}
|
|
@@ -8636,19 +8668,30 @@ function isEvidenceOnlySchema(schemaVersion) {
|
|
|
8636
8668
|
function isGeneratedProjectionFile(file) {
|
|
8637
8669
|
return file.schemaVersion === "archcontext.generated/v1" || file.path === ".archcontext/generated" || file.path.startsWith(".archcontext/generated/") || file.body.includes("Generated by ArchContext");
|
|
8638
8670
|
}
|
|
8639
|
-
function
|
|
8640
|
-
const
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
for (const key of Object.keys(value).sort()) {
|
|
8647
|
-
if (omitted.includes(key) || key === "metadata")
|
|
8648
|
-
continue;
|
|
8649
|
-
metadata[key] = value[key];
|
|
8671
|
+
function declaredProjectionRecord(metadata, allowedSchemaVersions, label) {
|
|
8672
|
+
const declared = metadata?.declared;
|
|
8673
|
+
if (!isRecord(declared))
|
|
8674
|
+
throw new Error(`architecture-ledger-projection-invalid: ${label} has no declared YAML record`);
|
|
8675
|
+
const schemaVersion = requireStringField(declared, "schemaVersion", label);
|
|
8676
|
+
if (!allowedSchemaVersions.includes(schemaVersion)) {
|
|
8677
|
+
throw new Error(`architecture-ledger-projection-invalid: ${label} has unsupported declared schema ${schemaVersion}`);
|
|
8650
8678
|
}
|
|
8651
|
-
return
|
|
8679
|
+
return declared;
|
|
8680
|
+
}
|
|
8681
|
+
function requiredRecordField(value, key, path) {
|
|
8682
|
+
const field = value[key];
|
|
8683
|
+
if (!isRecord(field))
|
|
8684
|
+
throw new Error(`${path}: ${key} is required`);
|
|
8685
|
+
return field;
|
|
8686
|
+
}
|
|
8687
|
+
function firstStringArrayValue(value) {
|
|
8688
|
+
return Array.isArray(value) ? value.find((item) => typeof item === "string" && item.length > 0) : undefined;
|
|
8689
|
+
}
|
|
8690
|
+
function requiredSeverity(value, path) {
|
|
8691
|
+
const severity = severityField(value);
|
|
8692
|
+
if (!severity)
|
|
8693
|
+
throw new Error(`${path}: severity is required`);
|
|
8694
|
+
return severity;
|
|
8652
8695
|
}
|
|
8653
8696
|
function declaredYamlSubject(value, path) {
|
|
8654
8697
|
const id = stringField(value, "id");
|
|
@@ -8681,8 +8724,10 @@ function requireStringField(value, key, path) {
|
|
|
8681
8724
|
function stringField(value, key) {
|
|
8682
8725
|
return typeof value[key] === "string" ? value[key] : undefined;
|
|
8683
8726
|
}
|
|
8684
|
-
function
|
|
8685
|
-
|
|
8727
|
+
function declaredStatus(value, path) {
|
|
8728
|
+
if (value === "active" || value === "planned" || value === "deprecated" || value === "removed")
|
|
8729
|
+
return value;
|
|
8730
|
+
throw new Error(`${path}: status is required`);
|
|
8686
8731
|
}
|
|
8687
8732
|
function severityField(value) {
|
|
8688
8733
|
return value === "notice" || value === "warning" || value === "error" || value === "critical" ? value : undefined;
|
|
@@ -8768,10 +8813,85 @@ function validateArchitectureLedgerEvent(event) {
|
|
|
8768
8813
|
if (event.worktree.workspaceId.length === 0 || event.worktree.storageWorkspaceId.length === 0 || event.worktree.headSha.length === 0) {
|
|
8769
8814
|
throw new Error(`architecture-ledger-invalid-event: worktree identity required for ${event.eventId}`);
|
|
8770
8815
|
}
|
|
8816
|
+
assertArchitectureLedgerPersistenceSafe(event.payload, `event.payload for ${event.eventId}`);
|
|
8817
|
+
if (event.extensions)
|
|
8818
|
+
assertArchitectureLedgerPersistenceSafe(event.extensions, `event.extensions for ${event.eventId}`);
|
|
8819
|
+
assertArchitectureLedgerPersistenceSafe(event.provenance, `event.provenance for ${event.eventId}`);
|
|
8771
8820
|
const payload = architectureLedgerPayload(event);
|
|
8772
8821
|
for (const operation of payload.operations ?? [])
|
|
8773
8822
|
validateArchitectureLedgerOperation(operation, event.eventId);
|
|
8774
8823
|
}
|
|
8824
|
+
var ARCHITECTURE_LEDGER_MAX_PERSISTED_JSON_BYTES = 262144;
|
|
8825
|
+
var ARCHITECTURE_LEDGER_MAX_PERSISTED_STRING_BYTES = 8192;
|
|
8826
|
+
var ARCHITECTURE_LEDGER_MAX_PERSISTED_DEPTH = 32;
|
|
8827
|
+
var ARCHITECTURE_LEDGER_FORBIDDEN_RAW_KEYS = new Set([
|
|
8828
|
+
"rawsource",
|
|
8829
|
+
"sourcebody",
|
|
8830
|
+
"sourcecode",
|
|
8831
|
+
"rawdiff",
|
|
8832
|
+
"diffbody",
|
|
8833
|
+
"rawpatch",
|
|
8834
|
+
"patchbody",
|
|
8835
|
+
"prompt",
|
|
8836
|
+
"promptbody",
|
|
8837
|
+
"completion",
|
|
8838
|
+
"completionbody",
|
|
8839
|
+
"codegraphoutput",
|
|
8840
|
+
"fullcodegraphoutput",
|
|
8841
|
+
"webhookbody",
|
|
8842
|
+
"rawwebhook",
|
|
8843
|
+
"secret",
|
|
8844
|
+
"secrets",
|
|
8845
|
+
"credential",
|
|
8846
|
+
"credentials",
|
|
8847
|
+
"privatekey",
|
|
8848
|
+
"accesstoken",
|
|
8849
|
+
"refreshtoken"
|
|
8850
|
+
]);
|
|
8851
|
+
var ARCHITECTURE_LEDGER_SAFE_SENSITIVE_KEY_SUFFIX = /(?:digest|id|ids|count|counts|ref|refs|path|paths|persisted)$/;
|
|
8852
|
+
var ARCHITECTURE_LEDGER_FORBIDDEN_STRING_PATTERNS = [
|
|
8853
|
+
/diff --git /,
|
|
8854
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
8855
|
+
/\bgh[pousr]_[A-Za-z0-9]{20,}\b/,
|
|
8856
|
+
/\bsk-[A-Za-z0-9_-]{20,}\b/,
|
|
8857
|
+
/\bAKIA[A-Z0-9]{16}\b/,
|
|
8858
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/i,
|
|
8859
|
+
/\b(?:api[_-]?key|secret|token|password|private[_-]?key)\s*[:=]\s*["']?[^\s"',;]{8,}/i
|
|
8860
|
+
];
|
|
8861
|
+
function assertArchitectureLedgerPersistenceSafe(value, label = "architecture-ledger-value") {
|
|
8862
|
+
const encoded = JSON.stringify(value);
|
|
8863
|
+
if (Buffer2.byteLength(encoded, "utf8") > ARCHITECTURE_LEDGER_MAX_PERSISTED_JSON_BYTES) {
|
|
8864
|
+
throw new Error(`architecture-ledger-privacy-denied: persisted JSON exceeds size limit at ${label}`);
|
|
8865
|
+
}
|
|
8866
|
+
visit(value, label, 0);
|
|
8867
|
+
function visit(current, path, depth) {
|
|
8868
|
+
if (depth > ARCHITECTURE_LEDGER_MAX_PERSISTED_DEPTH) {
|
|
8869
|
+
throw new Error(`architecture-ledger-privacy-denied: persisted JSON exceeds depth limit at ${path}`);
|
|
8870
|
+
}
|
|
8871
|
+
if (typeof current === "string") {
|
|
8872
|
+
if (Buffer2.byteLength(current, "utf8") > ARCHITECTURE_LEDGER_MAX_PERSISTED_STRING_BYTES) {
|
|
8873
|
+
throw new Error(`architecture-ledger-privacy-denied: persisted string exceeds size limit at ${path}`);
|
|
8874
|
+
}
|
|
8875
|
+
if (ARCHITECTURE_LEDGER_FORBIDDEN_STRING_PATTERNS.some((pattern) => pattern.test(current))) {
|
|
8876
|
+
throw new Error(`architecture-ledger-privacy-denied: forbidden raw or secret-shaped content at ${path}`);
|
|
8877
|
+
}
|
|
8878
|
+
return;
|
|
8879
|
+
}
|
|
8880
|
+
if (current === null || typeof current !== "object")
|
|
8881
|
+
return;
|
|
8882
|
+
if (Array.isArray(current)) {
|
|
8883
|
+
current.forEach((item, index) => visit(item, `${path}[${index}]`, depth + 1));
|
|
8884
|
+
return;
|
|
8885
|
+
}
|
|
8886
|
+
for (const [key, child] of Object.entries(current)) {
|
|
8887
|
+
const normalizedKey = key.replace(/[-_]/g, "").toLowerCase();
|
|
8888
|
+
if (ARCHITECTURE_LEDGER_FORBIDDEN_RAW_KEYS.has(normalizedKey) && !ARCHITECTURE_LEDGER_SAFE_SENSITIVE_KEY_SUFFIX.test(normalizedKey)) {
|
|
8889
|
+
throw new Error(`architecture-ledger-privacy-denied: forbidden persisted field at ${path}.${key}`);
|
|
8890
|
+
}
|
|
8891
|
+
visit(child, `${path}.${key}`, depth + 1);
|
|
8892
|
+
}
|
|
8893
|
+
}
|
|
8894
|
+
}
|
|
8775
8895
|
function validateArchitectureLedgerOperation(operation, eventId) {
|
|
8776
8896
|
if (!operation || typeof operation !== "object" || !("op" in operation)) {
|
|
8777
8897
|
throw new Error(`architecture-ledger-invalid-operation: ${eventId}`);
|
|
@@ -8894,7 +9014,7 @@ function requireNonEmpty(value, label, eventId) {
|
|
|
8894
9014
|
}
|
|
8895
9015
|
}
|
|
8896
9016
|
function requireActiveStatus(value, eventId) {
|
|
8897
|
-
if (!["active", "deprecated", "removed"].includes(value)) {
|
|
9017
|
+
if (!["active", "planned", "deprecated", "removed"].includes(value)) {
|
|
8898
9018
|
throw new Error(`architecture-ledger-invalid-operation: invalid status for ${eventId}`);
|
|
8899
9019
|
}
|
|
8900
9020
|
}
|
|
@@ -8906,7 +9026,7 @@ function assertRecord(value, label) {
|
|
|
8906
9026
|
|
|
8907
9027
|
// packages/local-runtime/local-store-sqlite/src/index.ts
|
|
8908
9028
|
init_src();
|
|
8909
|
-
var runtimeRequire =
|
|
9029
|
+
var runtimeRequire = createRequire3(import.meta.url);
|
|
8910
9030
|
var SQLITE_SIDECAR_SUFFIXES = ["", "-wal", "-shm"];
|
|
8911
9031
|
var LEGACY_MIGRATION_MARKER_FILE = "runtime.sqlite.migration.json";
|
|
8912
9032
|
var LEGACY_MIGRATION_LOCK_FILE = "runtime.sqlite.migration.lock";
|
|
@@ -8943,6 +9063,7 @@ var REQUIRED_LOCAL_STORE_TABLES = [
|
|
|
8943
9063
|
];
|
|
8944
9064
|
var SQLITE_PRAGMAS = [
|
|
8945
9065
|
"PRAGMA journal_mode = WAL",
|
|
9066
|
+
"PRAGMA synchronous = FULL",
|
|
8946
9067
|
"PRAGMA foreign_keys = ON",
|
|
8947
9068
|
"PRAGMA busy_timeout = 5000"
|
|
8948
9069
|
];
|
|
@@ -9464,6 +9585,13 @@ var LOCAL_SQLITE_MIGRATIONS = [
|
|
|
9464
9585
|
)`,
|
|
9465
9586
|
"CREATE INDEX IF NOT EXISTS idx_audit_runs_status ON audit_runs(storage_repository_id, storage_workspace_id, status)"
|
|
9466
9587
|
]
|
|
9588
|
+
},
|
|
9589
|
+
{
|
|
9590
|
+
id: "0011_changeset_cleanup_cursor",
|
|
9591
|
+
statements: [
|
|
9592
|
+
"ALTER TABLE changeset_journal ADD COLUMN cleanup_completed_at TEXT",
|
|
9593
|
+
"CREATE INDEX IF NOT EXISTS idx_changeset_journal_cleanup_pending ON changeset_journal(status, cleanup_completed_at, updated_at)"
|
|
9594
|
+
]
|
|
9467
9595
|
}
|
|
9468
9596
|
];
|
|
9469
9597
|
var ARCHCONTEXT_STATE_DIR_ENV = "ARCHCONTEXT_STATE_DIR";
|
|
@@ -9471,7 +9599,7 @@ var ARCHCONTEXT_LOCAL_STORE_PATH_ENV = "ARCHCONTEXT_LOCAL_STORE_PATH";
|
|
|
9471
9599
|
function defaultArchContextStateRoot(env = process.env, platform = process.platform, home = homedir()) {
|
|
9472
9600
|
const override = env[ARCHCONTEXT_STATE_DIR_ENV];
|
|
9473
9601
|
if (override)
|
|
9474
|
-
return { path:
|
|
9602
|
+
return { path: resolve5(override), source: "environment" };
|
|
9475
9603
|
if (platform === "darwin")
|
|
9476
9604
|
return { path: join2(home, "Library", "Application Support", "ArchContext"), source: "os-user-data" };
|
|
9477
9605
|
if (platform === "win32")
|
|
@@ -9489,7 +9617,7 @@ function runtimeStatePaths(root = process.cwd(), env = process.env) {
|
|
|
9489
9617
|
const stateRoot = defaultArchContextStateRoot(env);
|
|
9490
9618
|
const repositoryStateDir = join2(stateRoot.path, "repositories", storageRepositoryId);
|
|
9491
9619
|
const workspaceStateDir = join2(repositoryStateDir, "worktrees", storageWorkspaceId);
|
|
9492
|
-
const legacyControlDir =
|
|
9620
|
+
const legacyControlDir = resolve5(canonicalRepositoryRoot3, ".archcontext", ".local");
|
|
9493
9621
|
return {
|
|
9494
9622
|
schemaVersion: "archcontext.runtime-state-paths/v1",
|
|
9495
9623
|
stateRoot: stateRoot.path,
|
|
@@ -9557,7 +9685,7 @@ function migrateLegacyLocalStoreIfNeeded(root = process.cwd(), env = process.env
|
|
|
9557
9685
|
status: "explicit-local-store-override"
|
|
9558
9686
|
});
|
|
9559
9687
|
}
|
|
9560
|
-
ensurePrivateDir(
|
|
9688
|
+
ensurePrivateDir(dirname2(paths.localStorePath));
|
|
9561
9689
|
const legacyExists = existsSync2(paths.legacyLocalStorePath);
|
|
9562
9690
|
const integrityCheck = {};
|
|
9563
9691
|
const quarantinedFiles = [];
|
|
@@ -9655,7 +9783,7 @@ function readAppliedLocalSqliteMigrations(db) {
|
|
|
9655
9783
|
}
|
|
9656
9784
|
function openSqliteDatabaseSync(databasePath) {
|
|
9657
9785
|
if (databasePath !== ":memory:")
|
|
9658
|
-
ensurePrivateDir(
|
|
9786
|
+
ensurePrivateDir(dirname2(databasePath));
|
|
9659
9787
|
try {
|
|
9660
9788
|
const nodeSqlite = runtimeRequire("node:sqlite");
|
|
9661
9789
|
const db2 = new nodeSqlite.DatabaseSync(databasePath);
|
|
@@ -9832,7 +9960,7 @@ function publishStagedLocalStore(stagingPath, targetPath) {
|
|
|
9832
9960
|
}
|
|
9833
9961
|
renameSync(stagingPath, targetPath);
|
|
9834
9962
|
makePrivateFile(targetPath);
|
|
9835
|
-
fsyncDirectory(
|
|
9963
|
+
fsyncDirectory(dirname2(targetPath));
|
|
9836
9964
|
}
|
|
9837
9965
|
function writeLegacyMigrationMarker(paths, integrityCheck, quarantinedFiles) {
|
|
9838
9966
|
const markerPath = legacyMigrationMarkerPath(paths);
|
|
@@ -9848,7 +9976,7 @@ function writeLegacyMigrationMarker(paths, integrityCheck, quarantinedFiles) {
|
|
|
9848
9976
|
}
|
|
9849
9977
|
function acquireLegacyMigrationLock(paths) {
|
|
9850
9978
|
const lockPath = legacyMigrationLockPath(paths);
|
|
9851
|
-
ensurePrivateDir(
|
|
9979
|
+
ensurePrivateDir(dirname2(lockPath));
|
|
9852
9980
|
try {
|
|
9853
9981
|
const fd = openSync2(lockPath, "wx", 384);
|
|
9854
9982
|
writeFileSync(fd, JSON.stringify({
|
|
@@ -9877,7 +10005,7 @@ function releaseLegacyMigrationLock(lock) {
|
|
|
9877
10005
|
}
|
|
9878
10006
|
function isStaleMigrationLock(lockPath) {
|
|
9879
10007
|
try {
|
|
9880
|
-
const parsed = JSON.parse(
|
|
10008
|
+
const parsed = JSON.parse(readFileSync5(lockPath, "utf8"));
|
|
9881
10009
|
if (typeof parsed.pid !== "number" || parsed.pid <= 0)
|
|
9882
10010
|
return true;
|
|
9883
10011
|
return !isProcessAlive(parsed.pid);
|
|
@@ -9912,7 +10040,7 @@ function quarantineExistingLocalStore(paths) {
|
|
|
9912
10040
|
quarantinedFiles.push(target);
|
|
9913
10041
|
}
|
|
9914
10042
|
fsyncDirectory(quarantineDir);
|
|
9915
|
-
fsyncDirectory(
|
|
10043
|
+
fsyncDirectory(dirname2(paths.localStorePath));
|
|
9916
10044
|
return quarantinedFiles;
|
|
9917
10045
|
}
|
|
9918
10046
|
function legacyMigrationMarkerPath(paths) {
|
|
@@ -9922,7 +10050,7 @@ function legacyMigrationLockPath(paths) {
|
|
|
9922
10050
|
return join2(paths.workspaceStateDir, LEGACY_MIGRATION_LOCK_FILE);
|
|
9923
10051
|
}
|
|
9924
10052
|
function writePrivateJson(path, value) {
|
|
9925
|
-
ensurePrivateDir(
|
|
10053
|
+
ensurePrivateDir(dirname2(path));
|
|
9926
10054
|
const fd = openSync2(path, "w", 384);
|
|
9927
10055
|
try {
|
|
9928
10056
|
writeFileSync(fd, JSON.stringify(value, null, 2), "utf8");
|
|
@@ -9931,7 +10059,7 @@ function writePrivateJson(path, value) {
|
|
|
9931
10059
|
closeSync2(fd);
|
|
9932
10060
|
}
|
|
9933
10061
|
makePrivateFile(path);
|
|
9934
|
-
fsyncDirectory(
|
|
10062
|
+
fsyncDirectory(dirname2(path));
|
|
9935
10063
|
}
|
|
9936
10064
|
function ensurePrivateDir(path) {
|
|
9937
10065
|
mkdirSync(path, { recursive: true, mode: 448 });
|
|
@@ -9961,10 +10089,10 @@ function readGitPath(root, args) {
|
|
|
9961
10089
|
}
|
|
9962
10090
|
}
|
|
9963
10091
|
function resolveMaybeRelative(base, path) {
|
|
9964
|
-
return isAbsolute2(path) ?
|
|
10092
|
+
return isAbsolute2(path) ? resolve5(path) : resolve5(base, path);
|
|
9965
10093
|
}
|
|
9966
10094
|
function canonicalPath(path) {
|
|
9967
|
-
const resolved =
|
|
10095
|
+
const resolved = resolve5(path);
|
|
9968
10096
|
try {
|
|
9969
10097
|
return realpathSync4.native(resolved);
|
|
9970
10098
|
} catch {
|
|
@@ -9972,8 +10100,8 @@ function canonicalPath(path) {
|
|
|
9972
10100
|
}
|
|
9973
10101
|
}
|
|
9974
10102
|
function isPathInsideOrSame(path, parent) {
|
|
9975
|
-
const child =
|
|
9976
|
-
const base =
|
|
10103
|
+
const child = resolve5(path);
|
|
10104
|
+
const base = resolve5(parent);
|
|
9977
10105
|
const fromBase = relative3(base, child);
|
|
9978
10106
|
return fromBase === "" || !!fromBase && !fromBase.startsWith("..") && !isAbsolute2(fromBase);
|
|
9979
10107
|
}
|
|
@@ -10004,21 +10132,21 @@ function isIgnorableDirectoryFsyncError(error) {
|
|
|
10004
10132
|
// packages/local-runtime/git-adapter/src/index.ts
|
|
10005
10133
|
import { execFileSync as execFileSync3, spawnSync } from "node:child_process";
|
|
10006
10134
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
10007
|
-
import { dirname as
|
|
10135
|
+
import { dirname as dirname3, join as join3, resolve as resolve6 } from "node:path";
|
|
10008
10136
|
init_src();
|
|
10009
10137
|
function findRepositoryRoot(start) {
|
|
10010
10138
|
try {
|
|
10011
|
-
return
|
|
10139
|
+
return resolve6(execFileSync3("git", ["rev-parse", "--show-toplevel"], {
|
|
10012
10140
|
cwd: start,
|
|
10013
10141
|
encoding: "utf8",
|
|
10014
10142
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10015
10143
|
}).trim());
|
|
10016
10144
|
} catch {
|
|
10017
|
-
let cursor =
|
|
10145
|
+
let cursor = resolve6(start);
|
|
10018
10146
|
while (true) {
|
|
10019
|
-
if (existsSync3(
|
|
10147
|
+
if (existsSync3(resolve6(cursor, ".git")))
|
|
10020
10148
|
return cursor;
|
|
10021
|
-
const parent =
|
|
10149
|
+
const parent = dirname3(cursor);
|
|
10022
10150
|
if (parent === cursor)
|
|
10023
10151
|
break;
|
|
10024
10152
|
cursor = parent;
|
|
@@ -10041,18 +10169,19 @@ function readHeadSha(root) {
|
|
|
10041
10169
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
10042
10170
|
import { randomBytes } from "node:crypto";
|
|
10043
10171
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
10044
|
-
import { chmodSync as chmodSync3, closeSync as closeSync5, existsSync as
|
|
10172
|
+
import { chmodSync as chmodSync3, closeSync as closeSync5, existsSync as existsSync13, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, openSync as openSync5, readdirSync as readdirSync8, readFileSync as readFileSync12, rmSync as rmSync8, statSync as statSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10045
10173
|
import { createServer } from "node:http";
|
|
10046
10174
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
10047
|
-
import { dirname as
|
|
10175
|
+
import { dirname as dirname9, join as join8, resolve as resolve16 } from "node:path";
|
|
10048
10176
|
|
|
10049
10177
|
// packages/core/changeset-engine/src/index.ts
|
|
10050
10178
|
init_src();
|
|
10051
|
-
import { closeSync as closeSync3, existsSync as
|
|
10052
|
-
import { dirname as
|
|
10179
|
+
import { closeSync as closeSync3, existsSync as existsSync5, fsyncSync as fsyncSync2, lstatSync as lstatSync2, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync6, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
10180
|
+
import { dirname as dirname4, resolve as resolve8 } from "node:path";
|
|
10053
10181
|
|
|
10054
10182
|
// packages/core/policy-engine/src/index.ts
|
|
10055
|
-
import {
|
|
10183
|
+
import { existsSync as existsSync4, realpathSync as realpathSync5 } from "node:fs";
|
|
10184
|
+
import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve7, sep as sep3 } from "node:path";
|
|
10056
10185
|
init_src();
|
|
10057
10186
|
var INVALID_COMPAT_REASONS = new Set(["just in case", "safer to keep", "many internal callers", "large diff", "old code already exists"]);
|
|
10058
10187
|
var PLACEHOLDER_DIGEST = `sha256:${"0".repeat(64)}`;
|
|
@@ -10062,6 +10191,7 @@ var ALLOWLIST = [
|
|
|
10062
10191
|
".archcontext/practices/",
|
|
10063
10192
|
".archcontext/waivers/",
|
|
10064
10193
|
".archcontext/decisions/",
|
|
10194
|
+
".archcontext/backups/",
|
|
10065
10195
|
".archcontext/generated/",
|
|
10066
10196
|
"docs/architecture/"
|
|
10067
10197
|
];
|
|
@@ -10092,12 +10222,27 @@ function assertAllowedArchContextPath(root, relativePath) {
|
|
|
10092
10222
|
if (!ALLOWLIST.some((prefix) => normalized.startsWith(prefix))) {
|
|
10093
10223
|
throw new Error(`Path is outside ArchContext write allowlist: ${relativePath}`);
|
|
10094
10224
|
}
|
|
10095
|
-
const absoluteRoot =
|
|
10096
|
-
const absoluteTarget =
|
|
10225
|
+
const absoluteRoot = resolve7(root);
|
|
10226
|
+
const absoluteTarget = resolve7(root, relativePath);
|
|
10097
10227
|
const targetFromRoot = relative4(absoluteRoot, absoluteTarget);
|
|
10098
10228
|
if (targetFromRoot === "" || targetFromRoot === ".." || targetFromRoot.startsWith(`..${sep3}`) || isAbsolute3(targetFromRoot)) {
|
|
10099
10229
|
throw new Error(`Path escapes repository: ${relativePath}`);
|
|
10100
10230
|
}
|
|
10231
|
+
if (!existsSync4(absoluteRoot))
|
|
10232
|
+
return;
|
|
10233
|
+
const canonicalRoot = realpathSync5.native(absoluteRoot);
|
|
10234
|
+
let existingAncestor = absoluteTarget;
|
|
10235
|
+
while (!existsSync4(existingAncestor)) {
|
|
10236
|
+
const parent = resolve7(existingAncestor, "..");
|
|
10237
|
+
if (parent === existingAncestor)
|
|
10238
|
+
throw new Error(`Path has no existing repository ancestor: ${relativePath}`);
|
|
10239
|
+
existingAncestor = parent;
|
|
10240
|
+
}
|
|
10241
|
+
const canonicalAncestor = realpathSync5.native(existingAncestor);
|
|
10242
|
+
const ancestorFromRoot = relative4(canonicalRoot, canonicalAncestor);
|
|
10243
|
+
if (ancestorFromRoot === ".." || ancestorFromRoot.startsWith(`..${sep3}`) || isAbsolute3(ancestorFromRoot)) {
|
|
10244
|
+
throw new Error(`Path escapes repository through symlink: ${relativePath}`);
|
|
10245
|
+
}
|
|
10101
10246
|
}
|
|
10102
10247
|
function evaluateChangeSetPaths(root, paths) {
|
|
10103
10248
|
const findings = [];
|
|
@@ -10157,6 +10302,7 @@ class ChangeSetEngine {
|
|
|
10157
10302
|
if (!approved)
|
|
10158
10303
|
throw new Error("ChangeSet must be approved before apply");
|
|
10159
10304
|
const deps = this.requireDeps();
|
|
10305
|
+
await this.validateModel(root, draft, deps, "before");
|
|
10160
10306
|
const backups = [];
|
|
10161
10307
|
const journalId = await deps.journal?.beginChangeSet(root, draft);
|
|
10162
10308
|
let journalCommitted = false;
|
|
@@ -10171,10 +10317,7 @@ class ChangeSetEngine {
|
|
|
10171
10317
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10172
10318
|
throw new Error("fault-injection");
|
|
10173
10319
|
}
|
|
10174
|
-
} else {
|
|
10175
|
-
this.rebuildGeneratedProjection(root, deps);
|
|
10176
|
-
applied += 1;
|
|
10177
|
-
}
|
|
10320
|
+
} else {}
|
|
10178
10321
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10179
10322
|
throw new Error("fault-injection");
|
|
10180
10323
|
continue;
|
|
@@ -10186,15 +10329,24 @@ class ChangeSetEngine {
|
|
|
10186
10329
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10187
10330
|
throw new Error("fault-injection");
|
|
10188
10331
|
}
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10332
|
+
for (const projection of deps.projection.planGeneratedProjection(root)) {
|
|
10333
|
+
await this.applyFileOperation(root, projection.path, projection.expectedHash, projection.body, projection.operation, backups, journalId, applied + 1);
|
|
10334
|
+
applied += 1;
|
|
10335
|
+
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10336
|
+
throw new Error("fault-injection");
|
|
10337
|
+
}
|
|
10338
|
+
await this.validateModel(root, draft, deps, "after");
|
|
10339
|
+
const commit = await options.afterModelValidatedBeforeCommit?.({ root, draft, journalId });
|
|
10340
|
+
if (commit?.journalCommitted)
|
|
10341
|
+
journalCommitted = true;
|
|
10342
|
+
if (journalId && !journalCommitted) {
|
|
10193
10343
|
await deps.journal?.commitChangeSet(journalId);
|
|
10194
10344
|
journalCommitted = true;
|
|
10195
10345
|
}
|
|
10196
10346
|
try {
|
|
10197
10347
|
cleanupBackups(backups);
|
|
10348
|
+
if (journalId)
|
|
10349
|
+
await deps.journal?.completeChangeSetCleanup(journalId);
|
|
10198
10350
|
} catch {}
|
|
10199
10351
|
const appliedDraft = { ...draft, status: "applied" };
|
|
10200
10352
|
this.states.set(draft.id, appliedDraft);
|
|
@@ -10210,11 +10362,11 @@ class ChangeSetEngine {
|
|
|
10210
10362
|
throw error;
|
|
10211
10363
|
}
|
|
10212
10364
|
}
|
|
10213
|
-
|
|
10214
|
-
deps.
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10365
|
+
async validateModel(root, draft, deps, phase) {
|
|
10366
|
+
const result = await deps.modelStore.validateModel({ root, repositoryId: draft.reason.taskSessionId, headSha: draft.base.headSha });
|
|
10367
|
+
if (!result.valid) {
|
|
10368
|
+
throw new Error(`ChangeSet model validation failed ${phase} apply: ${result.errors.join("; ") || "unknown validation error"}`);
|
|
10369
|
+
}
|
|
10218
10370
|
}
|
|
10219
10371
|
requireDeps() {
|
|
10220
10372
|
if (!this.deps)
|
|
@@ -10224,20 +10376,17 @@ class ChangeSetEngine {
|
|
|
10224
10376
|
async applyFileOperation(root, path, expectedHash, body, operation, backups, journalId, sequence) {
|
|
10225
10377
|
assertSafeTarget(root, path);
|
|
10226
10378
|
const deps = this.requireDeps();
|
|
10227
|
-
const absolute =
|
|
10228
|
-
const existed =
|
|
10379
|
+
const absolute = resolve8(root, path);
|
|
10380
|
+
const existed = existsSync5(absolute);
|
|
10229
10381
|
const backupPath = `${absolute}.archctx-backup`;
|
|
10230
10382
|
const tempPath = operation === "delete_entity" ? undefined : `${absolute}.archctx-tmp-${process.pid}-${sequence}`;
|
|
10231
|
-
if (
|
|
10383
|
+
if (existsSync5(backupPath))
|
|
10232
10384
|
throw new Error(`Backup path already exists: ${path}`);
|
|
10233
|
-
if (existed)
|
|
10385
|
+
if (existed)
|
|
10234
10386
|
assertExpectedHash(absolute, expectedHash);
|
|
10235
|
-
|
|
10236
|
-
fsyncDirectory2(dirname3(absolute));
|
|
10237
|
-
} else if (expectedHash !== "missing") {
|
|
10387
|
+
else if (expectedHash !== "missing")
|
|
10238
10388
|
throw new Error(`Expected missing file hash for new path: ${path}`);
|
|
10239
|
-
}
|
|
10240
|
-
backups.push({ path: absolute, backupPath, tempPath, existed });
|
|
10389
|
+
const backup = { path: absolute, backupPath, tempPath, existed };
|
|
10241
10390
|
if (journalId) {
|
|
10242
10391
|
await deps.journal?.recordChangeSetFile(journalId, {
|
|
10243
10392
|
path,
|
|
@@ -10247,6 +10396,11 @@ class ChangeSetEngine {
|
|
|
10247
10396
|
operation
|
|
10248
10397
|
});
|
|
10249
10398
|
}
|
|
10399
|
+
backups.push(backup);
|
|
10400
|
+
if (existed) {
|
|
10401
|
+
renameSync2(absolute, backupPath);
|
|
10402
|
+
fsyncDirectory2(dirname4(absolute));
|
|
10403
|
+
}
|
|
10250
10404
|
if (operation === "delete_entity") {
|
|
10251
10405
|
rmSync3(absolute, { force: true });
|
|
10252
10406
|
} else {
|
|
@@ -10256,22 +10410,22 @@ class ChangeSetEngine {
|
|
|
10256
10410
|
}
|
|
10257
10411
|
function assertSafeTarget(root, path) {
|
|
10258
10412
|
assertAllowedArchContextPath(root, path);
|
|
10259
|
-
const absolute =
|
|
10260
|
-
if (
|
|
10413
|
+
const absolute = resolve8(root, path);
|
|
10414
|
+
if (existsSync5(absolute) && lstatSync2(absolute).isSymbolicLink()) {
|
|
10261
10415
|
throw new Error(`Refusing to write symlink target: ${path}`);
|
|
10262
10416
|
}
|
|
10263
10417
|
}
|
|
10264
10418
|
function assertExpectedHash(path, expectedHash) {
|
|
10265
|
-
const actual = digestJson({ body:
|
|
10419
|
+
const actual = digestJson({ body: readFileSync6(path, "utf8") });
|
|
10266
10420
|
if (expectedHash !== actual)
|
|
10267
10421
|
throw new Error(`Expected hash mismatch: ${path}`);
|
|
10268
10422
|
}
|
|
10269
10423
|
function atomicWriteFile(path, tempPath, body) {
|
|
10270
|
-
mkdirSync3(
|
|
10424
|
+
mkdirSync3(dirname4(path), { recursive: true });
|
|
10271
10425
|
writeFileSync2(tempPath, body, "utf8");
|
|
10272
10426
|
fsyncFile(tempPath);
|
|
10273
10427
|
renameSync2(tempPath, path);
|
|
10274
|
-
fsyncDirectory2(
|
|
10428
|
+
fsyncDirectory2(dirname4(path));
|
|
10275
10429
|
}
|
|
10276
10430
|
function fsyncFile(path) {
|
|
10277
10431
|
const fd = openSync3(path, process.platform === "win32" ? "r+" : "r");
|
|
@@ -10332,10 +10486,15 @@ function rollback(backups) {
|
|
|
10332
10486
|
for (const backup of backups.reverse()) {
|
|
10333
10487
|
if (backup.tempPath)
|
|
10334
10488
|
rmSync3(backup.tempPath, { recursive: true, force: true });
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10489
|
+
if (backup.existed) {
|
|
10490
|
+
if (existsSync5(backup.backupPath)) {
|
|
10491
|
+
rmSync3(backup.path, { recursive: true, force: true });
|
|
10492
|
+
renameSync2(backup.backupPath, backup.path);
|
|
10493
|
+
}
|
|
10494
|
+
} else {
|
|
10495
|
+
rmSync3(backup.path, { recursive: true, force: true });
|
|
10496
|
+
}
|
|
10497
|
+
fsyncDirectory2(dirname4(backup.path));
|
|
10339
10498
|
}
|
|
10340
10499
|
}
|
|
10341
10500
|
function cleanupBackups(backups) {
|
|
@@ -10540,19 +10699,19 @@ function digestSuffix2(digest) {
|
|
|
10540
10699
|
}
|
|
10541
10700
|
|
|
10542
10701
|
// packages/core/application/src/index.ts
|
|
10543
|
-
import { existsSync as
|
|
10544
|
-
import { extname, resolve as
|
|
10702
|
+
import { existsSync as existsSync8, statSync as statSync5 } from "node:fs";
|
|
10703
|
+
import { extname, resolve as resolve11 } from "node:path";
|
|
10545
10704
|
|
|
10546
10705
|
// packages/core/context-compiler/src/index.ts
|
|
10547
10706
|
init_src();
|
|
10548
10707
|
|
|
10549
10708
|
// packages/core/practice-catalog/src/index.ts
|
|
10550
10709
|
init_src();
|
|
10551
|
-
import { existsSync as
|
|
10552
|
-
import { dirname as
|
|
10710
|
+
import { existsSync as existsSync6, lstatSync as lstatSync3, readdirSync as readdirSync4, readFileSync as readFileSync7, realpathSync as realpathSync6 } from "node:fs";
|
|
10711
|
+
import { dirname as dirname5, relative as relative5, resolve as resolve9, sep as sep4 } from "node:path";
|
|
10553
10712
|
import { fileURLToPath } from "node:url";
|
|
10554
10713
|
var PRACTICE_CATALOG_VERSION = "2026.06.0";
|
|
10555
|
-
var BUILTIN_PRACTICE_ASSETS_DIR =
|
|
10714
|
+
var BUILTIN_PRACTICE_ASSETS_DIR = resolve9(dirname5(fileURLToPath(import.meta.url)), "../assets");
|
|
10556
10715
|
var ALLOWED_CHECK_IDS = new Set([
|
|
10557
10716
|
"compatibility-contract-required",
|
|
10558
10717
|
"no-new-cycle",
|
|
@@ -10604,13 +10763,13 @@ var PRACTICE_ROOT_KEYS = new Set([
|
|
|
10604
10763
|
"overlay"
|
|
10605
10764
|
]);
|
|
10606
10765
|
function loadPracticeCatalog(options = {}) {
|
|
10607
|
-
const root = options.root ?
|
|
10766
|
+
const root = options.root ? resolve9(options.root) : process.cwd();
|
|
10608
10767
|
const builtInAssetsDir = options.builtInAssetsDir ?? BUILTIN_PRACTICE_ASSETS_DIR;
|
|
10609
10768
|
const errors = [];
|
|
10610
10769
|
const warnings = [];
|
|
10611
|
-
const builtIn = loadAssetFiles(
|
|
10612
|
-
const profiles = loadProfileFiles(
|
|
10613
|
-
const sources = loadSourceFiles(
|
|
10770
|
+
const builtIn = loadAssetFiles(resolve9(builtInAssetsDir, "practices"), "curated-static", errors);
|
|
10771
|
+
const profiles = loadProfileFiles(resolve9(builtInAssetsDir, "profiles"), errors);
|
|
10772
|
+
const sources = loadSourceFiles(resolve9(builtInAssetsDir, "sources"), errors);
|
|
10614
10773
|
const overlays = options.includeRepoOverlay === false ? [] : loadRepoOverlayAssets(root, errors);
|
|
10615
10774
|
const merged = mergeCatalogAssets(builtIn, overlays, errors, options.now ?? new Date().toISOString());
|
|
10616
10775
|
const sourceIds = new Set(sources.map((source) => source.id));
|
|
@@ -10796,8 +10955,8 @@ function loadProfileFiles(dir, errors) {
|
|
|
10796
10955
|
return profiles.sort((a, b) => a.id.localeCompare(b.id));
|
|
10797
10956
|
}
|
|
10798
10957
|
function loadRepoOverlayAssets(root, errors) {
|
|
10799
|
-
const overlayRoot =
|
|
10800
|
-
if (!
|
|
10958
|
+
const overlayRoot = resolve9(root, ".archcontext/practices");
|
|
10959
|
+
if (!existsSync6(overlayRoot))
|
|
10801
10960
|
return [];
|
|
10802
10961
|
const out = [];
|
|
10803
10962
|
for (const path of listDataFiles(overlayRoot, overlayRoot, errors)) {
|
|
@@ -11140,7 +11299,7 @@ function validateProfile(value, path, errors) {
|
|
|
11140
11299
|
return invalid ? undefined : profile;
|
|
11141
11300
|
}
|
|
11142
11301
|
function listDataFiles(dir, allowedRoot, errors) {
|
|
11143
|
-
if (!
|
|
11302
|
+
if (!existsSync6(dir))
|
|
11144
11303
|
return [];
|
|
11145
11304
|
const out = [];
|
|
11146
11305
|
const rootReal = safeRealpath(allowedRoot);
|
|
@@ -11160,7 +11319,7 @@ function listDataFiles(dir, allowedRoot, errors) {
|
|
|
11160
11319
|
}
|
|
11161
11320
|
if (stat.isDirectory()) {
|
|
11162
11321
|
for (const entry of readdirSync4(current, { withFileTypes: true }))
|
|
11163
|
-
walk(
|
|
11322
|
+
walk(resolve9(current, entry.name));
|
|
11164
11323
|
return;
|
|
11165
11324
|
}
|
|
11166
11325
|
if (!/\.(ya?ml|json)$/.test(current))
|
|
@@ -11175,7 +11334,7 @@ function listDataFiles(dir, allowedRoot, errors) {
|
|
|
11175
11334
|
}
|
|
11176
11335
|
function parseDataFile(path, errors) {
|
|
11177
11336
|
try {
|
|
11178
|
-
const body =
|
|
11337
|
+
const body = readFileSync7(path, "utf8").replace(/^\uFEFF/, "").trim();
|
|
11179
11338
|
const withoutDocumentMarker = body.startsWith("---") ? body.replace(/^---\s*/, "").trim() : body;
|
|
11180
11339
|
return JSON.parse(withoutDocumentMarker);
|
|
11181
11340
|
} catch (error) {
|
|
@@ -11202,14 +11361,14 @@ function assertRealChild(root, path) {
|
|
|
11202
11361
|
}
|
|
11203
11362
|
function safeRealpath(path) {
|
|
11204
11363
|
try {
|
|
11205
|
-
return
|
|
11364
|
+
return realpathSync6.native(path);
|
|
11206
11365
|
} catch {
|
|
11207
|
-
return
|
|
11366
|
+
return resolve9(path);
|
|
11208
11367
|
}
|
|
11209
11368
|
}
|
|
11210
11369
|
function isRealChild(rootReal, pathReal) {
|
|
11211
11370
|
const rel = relative5(rootReal, pathReal);
|
|
11212
|
-
return rel === "" || !rel.startsWith("..") && !rel.includes(`..${sep4}`) && !
|
|
11371
|
+
return rel === "" || !rel.startsWith("..") && !rel.includes(`..${sep4}`) && !resolve9(rel).startsWith("..");
|
|
11213
11372
|
}
|
|
11214
11373
|
function displayPath(path) {
|
|
11215
11374
|
return path.split(sep4).join("/");
|
|
@@ -11773,8 +11932,8 @@ function checkResult(input, result) {
|
|
|
11773
11932
|
}
|
|
11774
11933
|
// packages/core/practice-engine/src/enforcement.ts
|
|
11775
11934
|
init_src();
|
|
11776
|
-
import { existsSync as
|
|
11777
|
-
import { basename as basename3, join as join4, relative as relative6, resolve as
|
|
11935
|
+
import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "node:fs";
|
|
11936
|
+
import { basename as basename3, join as join4, relative as relative6, resolve as resolve10, sep as sep5 } from "node:path";
|
|
11778
11937
|
var ENFORCEMENT_RANK = { advisory: 0, checkpoint: 1, complete: 2 };
|
|
11779
11938
|
var POLICY_MODES = new Set(["advisory", "active", "fail-open", "fail-closed"]);
|
|
11780
11939
|
var DEFAULT_POLICY = {
|
|
@@ -11797,16 +11956,16 @@ function shouldEvaluatePracticeEnforcement(policy) {
|
|
|
11797
11956
|
return practiceEnforcementPolicyMode(policy) !== "advisory";
|
|
11798
11957
|
}
|
|
11799
11958
|
function loadPracticeEnforcementPolicy(root) {
|
|
11800
|
-
const path =
|
|
11801
|
-
if (!
|
|
11959
|
+
const path = resolve10(root, ".archcontext/policies/practices.yaml");
|
|
11960
|
+
if (!existsSync7(path))
|
|
11802
11961
|
return defaultPracticeEnforcementPolicy();
|
|
11803
11962
|
assertRepoPolicyFile(root, path, ".archcontext/policies/practices.yaml");
|
|
11804
11963
|
const parsed = parseJsonYamlFile(path);
|
|
11805
11964
|
return validatePracticeEnforcementPolicy(parsed, ".archcontext/policies/practices.yaml");
|
|
11806
11965
|
}
|
|
11807
11966
|
function loadPracticeWaivers(root) {
|
|
11808
|
-
const dir =
|
|
11809
|
-
if (!
|
|
11967
|
+
const dir = resolve10(root, ".archcontext/waivers");
|
|
11968
|
+
if (!existsSync7(dir))
|
|
11810
11969
|
return [];
|
|
11811
11970
|
const stat = lstatSync4(dir);
|
|
11812
11971
|
if (stat.isSymbolicLink())
|
|
@@ -11826,17 +11985,17 @@ function loadPracticeWaivers(root) {
|
|
|
11826
11985
|
return waivers.sort((left, right) => waiverDigest(left).localeCompare(waiverDigest(right)));
|
|
11827
11986
|
}
|
|
11828
11987
|
function loadPracticeWaiverOwnerRegistry(root) {
|
|
11829
|
-
const modelDir =
|
|
11988
|
+
const modelDir = resolve10(root, ".archcontext/model/nodes");
|
|
11830
11989
|
const sources = [];
|
|
11831
11990
|
const subjects = [];
|
|
11832
|
-
if (
|
|
11991
|
+
if (existsSync7(modelDir)) {
|
|
11833
11992
|
if (lstatSync4(modelDir).isSymbolicLink())
|
|
11834
11993
|
throw new Error("practice-owner-registry-symlink-denied");
|
|
11835
11994
|
for (const path of collectFiles(root, ".archcontext/model/nodes")) {
|
|
11836
|
-
const absolute =
|
|
11995
|
+
const absolute = resolve10(root, path);
|
|
11837
11996
|
if (lstatSync4(absolute).isSymbolicLink())
|
|
11838
11997
|
throw new Error(`practice-owner-registry-symlink-denied: ${path}`);
|
|
11839
|
-
const body =
|
|
11998
|
+
const body = readFileSync8(absolute, "utf8");
|
|
11840
11999
|
const lifecycleOwners = extractOwnershipOwners(body, "lifecycle");
|
|
11841
12000
|
const dataOwners = extractOwnershipOwners(body, "data");
|
|
11842
12001
|
for (const kind of ["lifecycle", "data"]) {
|
|
@@ -12111,12 +12270,12 @@ function isVagueReason(reason) {
|
|
|
12111
12270
|
return /^(temporary|cleanup later|todo|tbd|later|just in case)$/i.test(trimmed);
|
|
12112
12271
|
}
|
|
12113
12272
|
function parseJsonYamlFile(path) {
|
|
12114
|
-
const body =
|
|
12273
|
+
const body = readFileSync8(path, "utf8").replace(/^\uFEFF/, "").trim();
|
|
12115
12274
|
const withoutDocumentMarker = body.startsWith("---") ? body.replace(/^---\s*/, "").trim() : body;
|
|
12116
12275
|
return JSON.parse(withoutDocumentMarker);
|
|
12117
12276
|
}
|
|
12118
12277
|
function collectFiles(root, relativeDir) {
|
|
12119
|
-
const dir =
|
|
12278
|
+
const dir = resolve10(root, relativeDir);
|
|
12120
12279
|
const out = [];
|
|
12121
12280
|
for (const entry of readdirSync5(dir, { withFileTypes: true })) {
|
|
12122
12281
|
const child = `${relativeDir}/${entry.name}`;
|
|
@@ -12204,8 +12363,8 @@ function assertRepoPolicyFile(root, path, relativePath) {
|
|
|
12204
12363
|
assertRepoRelativePath(relativePath);
|
|
12205
12364
|
if (lstatSync4(path).isSymbolicLink())
|
|
12206
12365
|
throw new Error(`practice-policy-symlink-denied: ${relativePath}`);
|
|
12207
|
-
const rootResolved =
|
|
12208
|
-
const pathResolved =
|
|
12366
|
+
const rootResolved = resolve10(root);
|
|
12367
|
+
const pathResolved = resolve10(path);
|
|
12209
12368
|
const rel = relative6(rootResolved, pathResolved);
|
|
12210
12369
|
if (rel === "" || rel.startsWith("..") || rel.includes(`..${sep5}`))
|
|
12211
12370
|
throw new Error(`practice-policy-path-escape: ${relativePath}`);
|
|
@@ -13641,8 +13800,8 @@ function classifyCheckpointPath(root, path) {
|
|
|
13641
13800
|
return "ignored";
|
|
13642
13801
|
if (isGeneratedCheckpointPath(path))
|
|
13643
13802
|
return "generated";
|
|
13644
|
-
const absolute =
|
|
13645
|
-
if (!
|
|
13803
|
+
const absolute = resolve11(root, path);
|
|
13804
|
+
if (!existsSync8(absolute))
|
|
13646
13805
|
return "deleted";
|
|
13647
13806
|
try {
|
|
13648
13807
|
if (!statSync5(absolute).isFile())
|
|
@@ -14848,8 +15007,8 @@ function uniqueSorted4(values) {
|
|
|
14848
15007
|
|
|
14849
15008
|
// packages/core/projection-engine/src/index.ts
|
|
14850
15009
|
init_src();
|
|
14851
|
-
import { existsSync as
|
|
14852
|
-
import { basename as basename4, resolve as
|
|
15010
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync9 } from "node:fs";
|
|
15011
|
+
import { basename as basename4, resolve as resolve12 } from "node:path";
|
|
14853
15012
|
function nativeNodeSource(node) {
|
|
14854
15013
|
const value = node.source;
|
|
14855
15014
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -14891,12 +15050,6 @@ function renderArchitectureDocumentationProjection(input) {
|
|
|
14891
15050
|
});
|
|
14892
15051
|
const targets = rendered.map((file) => file.target);
|
|
14893
15052
|
const expectedByPath = new Map(rendered.map((file) => [file.path, file]));
|
|
14894
|
-
const drift = architectureDocumentationProjectionDrift({
|
|
14895
|
-
targets,
|
|
14896
|
-
expectedFiles: rendered,
|
|
14897
|
-
existingFiles: input.existingFiles ?? []
|
|
14898
|
-
});
|
|
14899
|
-
const rejected = drift.diffs.filter((diff) => diff.reasonCode === "projection-ambiguous-ownership");
|
|
14900
15053
|
const projectionDigest = digestJson({
|
|
14901
15054
|
rendererVersion,
|
|
14902
15055
|
sourceDigest: input.sourceDigest,
|
|
@@ -14907,6 +15060,38 @@ function renderArchitectureDocumentationProjection(input) {
|
|
|
14907
15060
|
generatedBodyDigest: file.generatedBodyDigest
|
|
14908
15061
|
})).sort((left, right) => left.path.localeCompare(right.path))
|
|
14909
15062
|
});
|
|
15063
|
+
const manifestValue = {
|
|
15064
|
+
schemaVersion: "archcontext.architecture-docs-projection-manifest/v1",
|
|
15065
|
+
rendererVersion,
|
|
15066
|
+
sourceDigest: input.sourceDigest,
|
|
15067
|
+
projectionDigest,
|
|
15068
|
+
targetCount: targets.length,
|
|
15069
|
+
fileCount: rendered.length,
|
|
15070
|
+
targets: targets.map((target) => ({
|
|
15071
|
+
targetId: target.targetId,
|
|
15072
|
+
type: target.type,
|
|
15073
|
+
scope: target.scope,
|
|
15074
|
+
path: target.path,
|
|
15075
|
+
ownership: target.ownership,
|
|
15076
|
+
rendererVersion: target.rendererVersion,
|
|
15077
|
+
format: target.format,
|
|
15078
|
+
sourceDigest: target.sourceDigest,
|
|
15079
|
+
outputDigest: target.outputDigest
|
|
15080
|
+
}))
|
|
15081
|
+
};
|
|
15082
|
+
const manifest = {
|
|
15083
|
+
path: "docs/architecture/.projection-manifest.json",
|
|
15084
|
+
body: `${JSON.stringify(manifestValue, null, 2)}
|
|
15085
|
+
`,
|
|
15086
|
+
digest: digestJson(manifestValue)
|
|
15087
|
+
};
|
|
15088
|
+
const drift = architectureDocumentationProjectionDrift({
|
|
15089
|
+
targets,
|
|
15090
|
+
expectedFiles: rendered,
|
|
15091
|
+
expectedManifest: manifest,
|
|
15092
|
+
existingFiles: input.existingFiles ?? []
|
|
15093
|
+
});
|
|
15094
|
+
const rejected = drift.diffs.filter((diff) => diff.reasonCode === "projection-ambiguous-ownership");
|
|
14910
15095
|
return {
|
|
14911
15096
|
schemaVersion: "archcontext.architecture-docs-projection-plan/v1",
|
|
14912
15097
|
rendererVersion,
|
|
@@ -14914,6 +15099,7 @@ function renderArchitectureDocumentationProjection(input) {
|
|
|
14914
15099
|
projectionDigest,
|
|
14915
15100
|
targets,
|
|
14916
15101
|
files: rendered.filter((file) => !rejected.some((diff) => diff.path === file.path && diff.targetId === file.target.targetId)),
|
|
15102
|
+
manifest,
|
|
14917
15103
|
drift: {
|
|
14918
15104
|
...drift,
|
|
14919
15105
|
diffs: drift.diffs.map((diff) => ({
|
|
@@ -14943,12 +15129,12 @@ function architectureDocumentationSourceDigest(input) {
|
|
|
14943
15129
|
});
|
|
14944
15130
|
}
|
|
14945
15131
|
function loadArchitectureDecisionRecords(root) {
|
|
14946
|
-
const dir =
|
|
14947
|
-
if (!
|
|
15132
|
+
const dir = resolve12(root, "docs/adr");
|
|
15133
|
+
if (!existsSync9(dir))
|
|
14948
15134
|
return [];
|
|
14949
15135
|
return readdirSync6(dir).filter((file) => /^ADR-\d{4}-.+\.md$/.test(file)).sort().map((file) => {
|
|
14950
15136
|
const path = `docs/adr/${file}`;
|
|
14951
|
-
const body =
|
|
15137
|
+
const body = readFileSync9(resolve12(root, path), "utf8");
|
|
14952
15138
|
const title = body.match(/^#\s+(.+)$/m)?.[1]?.trim() ?? basename4(file, ".md");
|
|
14953
15139
|
const status = body.match(/^Status:\s*(.+)$/mi)?.[1]?.trim();
|
|
14954
15140
|
return {
|
|
@@ -14970,17 +15156,17 @@ function loadArchitectureDocumentationFiles(root) {
|
|
|
14970
15156
|
"docs/architecture/diagrams/architecture.structurizr.json",
|
|
14971
15157
|
"docs/architecture/.projection-manifest.json"
|
|
14972
15158
|
]) {
|
|
14973
|
-
const absolute =
|
|
14974
|
-
if (
|
|
14975
|
-
files.push({ path: entry, body:
|
|
15159
|
+
const absolute = resolve12(root, entry);
|
|
15160
|
+
if (existsSync9(absolute))
|
|
15161
|
+
files.push({ path: entry, body: readFileSync9(absolute, "utf8") });
|
|
14976
15162
|
}
|
|
14977
15163
|
for (const dir of ["docs/architecture/modules", "docs/architecture/relations"]) {
|
|
14978
|
-
const absoluteDir =
|
|
14979
|
-
if (!
|
|
15164
|
+
const absoluteDir = resolve12(root, dir);
|
|
15165
|
+
if (!existsSync9(absoluteDir))
|
|
14980
15166
|
continue;
|
|
14981
15167
|
for (const file of readdirSync6(absoluteDir).filter((name) => name.endsWith(".md")).sort()) {
|
|
14982
15168
|
const path = `${dir}/${file}`;
|
|
14983
|
-
files.push({ path, body:
|
|
15169
|
+
files.push({ path, body: readFileSync9(resolve12(root, path), "utf8") });
|
|
14984
15170
|
}
|
|
14985
15171
|
}
|
|
14986
15172
|
return files.sort((left, right) => left.path.localeCompare(right.path));
|
|
@@ -15074,19 +15260,19 @@ function exportDocumentationStructurizrWorkspace(model) {
|
|
|
15074
15260
|
}
|
|
15075
15261
|
function loadNativeModelFromArchContext(root) {
|
|
15076
15262
|
return {
|
|
15077
|
-
nodes: readYamlObjects(
|
|
15078
|
-
relations: readYamlObjects(
|
|
15263
|
+
nodes: readYamlObjects(resolve12(root, ".archcontext/model/nodes")),
|
|
15264
|
+
relations: readYamlObjects(resolve12(root, ".archcontext/model/relations"))
|
|
15079
15265
|
};
|
|
15080
15266
|
}
|
|
15081
15267
|
function mermaidId(id) {
|
|
15082
15268
|
return stableId(id).replace(/-/g, "_").replace(/\./g, "_");
|
|
15083
15269
|
}
|
|
15084
15270
|
function readYamlObjects(dir) {
|
|
15085
|
-
if (!
|
|
15271
|
+
if (!existsSync9(dir))
|
|
15086
15272
|
return [];
|
|
15087
15273
|
return readdirSync6(dir).filter((file) => /\.ya?ml$/.test(file)).sort().map((file) => {
|
|
15088
|
-
const path =
|
|
15089
|
-
return parseJsonOrStableYaml(
|
|
15274
|
+
const path = resolve12(dir, file);
|
|
15275
|
+
return parseJsonOrStableYaml(readFileSync9(path, "utf8"), path);
|
|
15090
15276
|
});
|
|
15091
15277
|
}
|
|
15092
15278
|
function escapeMermaid(value) {
|
|
@@ -15317,6 +15503,34 @@ function architectureDocumentationProjectionDrift(input) {
|
|
|
15317
15503
|
const expectedByPath = new Map(input.expectedFiles.map((file) => [file.path, file]));
|
|
15318
15504
|
const targetIds = new Set(input.targets.map((target) => target.targetId));
|
|
15319
15505
|
const diffs = [];
|
|
15506
|
+
const existingManifest = existingByPath.get(input.expectedManifest.path);
|
|
15507
|
+
if (!existingManifest) {
|
|
15508
|
+
diffs.push({
|
|
15509
|
+
path: input.expectedManifest.path,
|
|
15510
|
+
reasonCode: "projection-manifest-missing",
|
|
15511
|
+
expectedDigest: input.expectedManifest.digest
|
|
15512
|
+
});
|
|
15513
|
+
} else {
|
|
15514
|
+
try {
|
|
15515
|
+
const parsed = JSON.parse(existingManifest.body);
|
|
15516
|
+
const actualDigest = digestJson(parsed);
|
|
15517
|
+
if (actualDigest !== input.expectedManifest.digest) {
|
|
15518
|
+
diffs.push({
|
|
15519
|
+
path: input.expectedManifest.path,
|
|
15520
|
+
reasonCode: "projection-manifest-stale",
|
|
15521
|
+
expectedDigest: input.expectedManifest.digest,
|
|
15522
|
+
actualDigest
|
|
15523
|
+
});
|
|
15524
|
+
}
|
|
15525
|
+
} catch {
|
|
15526
|
+
diffs.push({
|
|
15527
|
+
path: input.expectedManifest.path,
|
|
15528
|
+
reasonCode: "projection-manifest-invalid",
|
|
15529
|
+
expectedDigest: input.expectedManifest.digest,
|
|
15530
|
+
actualDigest: digestJson({ path: existingManifest.path, body: existingManifest.body })
|
|
15531
|
+
});
|
|
15532
|
+
}
|
|
15533
|
+
}
|
|
15320
15534
|
for (const expected of input.expectedFiles) {
|
|
15321
15535
|
const existing = existingByPath.get(expected.path);
|
|
15322
15536
|
if (!existing) {
|
|
@@ -15355,6 +15569,8 @@ function architectureDocumentationProjectionDrift(input) {
|
|
|
15355
15569
|
}
|
|
15356
15570
|
}
|
|
15357
15571
|
for (const existing of input.existingFiles) {
|
|
15572
|
+
if (existing.path === input.expectedManifest.path)
|
|
15573
|
+
continue;
|
|
15358
15574
|
if (!isManagedArchitectureDocumentationPath(existing.path) || expectedByPath.has(existing.path))
|
|
15359
15575
|
continue;
|
|
15360
15576
|
const region = findAnyGeneratedRegion(existing.body);
|
|
@@ -15403,7 +15619,7 @@ function generatedEndMarker(targetId) {
|
|
|
15403
15619
|
return `${ARCHITECTURE_DOCS_GENERATED_END_PREFIX} target="${targetId}" -->`;
|
|
15404
15620
|
}
|
|
15405
15621
|
function isManagedArchitectureDocumentationPath(path) {
|
|
15406
|
-
return /^docs\/architecture\/(modules|relations)\/.+\.md$/.test(path) || /^docs\/architecture\/diagrams\/architecture\.(mmd|likec4|structurizr\.json)$/.test(path) || path === "docs/architecture/index.md" || path === "docs/architecture/changelog.md" || path === "docs/architecture/decisions/index.md";
|
|
15622
|
+
return /^docs\/architecture\/(modules|relations)\/.+\.md$/.test(path) || /^docs\/architecture\/diagrams\/architecture\.(mmd|likec4|structurizr\.json)$/.test(path) || path === "docs/architecture/index.md" || path === "docs/architecture/changelog.md" || path === "docs/architecture/decisions/index.md" || path === "docs/architecture/.projection-manifest.json";
|
|
15407
15623
|
}
|
|
15408
15624
|
function pathSegment2(id) {
|
|
15409
15625
|
return stableId(id).replace(/\./g, "-");
|
|
@@ -16613,23 +16829,23 @@ init_src();
|
|
|
16613
16829
|
|
|
16614
16830
|
// packages/local-runtime/git-adapter/src/index.ts
|
|
16615
16831
|
import { execFileSync as execFileSync4, spawnSync as spawnSync2 } from "node:child_process";
|
|
16616
|
-
import { existsSync as
|
|
16617
|
-
import { dirname as
|
|
16832
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
|
|
16833
|
+
import { dirname as dirname6, join as join5, resolve as resolve13 } from "node:path";
|
|
16618
16834
|
import { tmpdir } from "node:os";
|
|
16619
16835
|
init_src();
|
|
16620
16836
|
function findRepositoryRoot2(start) {
|
|
16621
16837
|
try {
|
|
16622
|
-
return
|
|
16838
|
+
return resolve13(execFileSync4("git", ["rev-parse", "--show-toplevel"], {
|
|
16623
16839
|
cwd: start,
|
|
16624
16840
|
encoding: "utf8",
|
|
16625
16841
|
stdio: ["ignore", "pipe", "ignore"]
|
|
16626
16842
|
}).trim());
|
|
16627
16843
|
} catch {
|
|
16628
|
-
let cursor =
|
|
16844
|
+
let cursor = resolve13(start);
|
|
16629
16845
|
while (true) {
|
|
16630
|
-
if (
|
|
16846
|
+
if (existsSync10(resolve13(cursor, ".git")))
|
|
16631
16847
|
return cursor;
|
|
16632
|
-
const parent =
|
|
16848
|
+
const parent = dirname6(cursor);
|
|
16633
16849
|
if (parent === cursor)
|
|
16634
16850
|
break;
|
|
16635
16851
|
cursor = parent;
|
|
@@ -16729,7 +16945,7 @@ function prepareDetachedReviewWorktree(input) {
|
|
|
16729
16945
|
observed: {}
|
|
16730
16946
|
};
|
|
16731
16947
|
}
|
|
16732
|
-
const parent = input.tempRoot ?
|
|
16948
|
+
const parent = input.tempRoot ? resolve13(input.tempRoot) : tmpdir();
|
|
16733
16949
|
mkdirSync4(parent, { recursive: true });
|
|
16734
16950
|
const temporaryRoot = mkdtempSync2(join5(parent, "archctx-review-worktree-"));
|
|
16735
16951
|
const worktreeRoot = join5(temporaryRoot, "worktree");
|
|
@@ -16781,7 +16997,7 @@ function removeDetachedReviewWorktree(worktree) {
|
|
|
16781
16997
|
} catch {
|
|
16782
16998
|
removePathWithRetry(worktree.worktreeRoot);
|
|
16783
16999
|
} finally {
|
|
16784
|
-
removePathWithRetry(worktree.temporaryRoot ||
|
|
17000
|
+
removePathWithRetry(worktree.temporaryRoot || dirname6(worktree.worktreeRoot));
|
|
16785
17001
|
}
|
|
16786
17002
|
}
|
|
16787
17003
|
function removePathWithRetry(path) {
|
|
@@ -16898,13 +17114,13 @@ function isGitWorktreeError(error) {
|
|
|
16898
17114
|
// packages/local-runtime/local-store-sqlite/src/index.ts
|
|
16899
17115
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
16900
17116
|
import { createHash as createHash6, randomUUID as randomUUID2 } from "node:crypto";
|
|
16901
|
-
import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as
|
|
17117
|
+
import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as existsSync11, fsyncSync as fsyncSync3, lstatSync as lstatSync5, mkdirSync as mkdirSync5, openSync as openSync4, readFileSync as readFileSync10, realpathSync as realpathSync7, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
16902
17118
|
import { readdir, readFile } from "node:fs/promises";
|
|
16903
|
-
import { createRequire as
|
|
17119
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
16904
17120
|
import { homedir as homedir2 } from "node:os";
|
|
16905
|
-
import { dirname as
|
|
17121
|
+
import { dirname as dirname7, isAbsolute as isAbsolute4, join as join6, relative as relative7, resolve as resolve14 } from "node:path";
|
|
16906
17122
|
init_src();
|
|
16907
|
-
var runtimeRequire2 =
|
|
17123
|
+
var runtimeRequire2 = createRequire4(import.meta.url);
|
|
16908
17124
|
var SQLITE_SIDECAR_SUFFIXES2 = ["", "-wal", "-shm"];
|
|
16909
17125
|
var LEGACY_MIGRATION_MARKER_FILE2 = "runtime.sqlite.migration.json";
|
|
16910
17126
|
var LEGACY_MIGRATION_LOCK_FILE2 = "runtime.sqlite.migration.lock";
|
|
@@ -16941,6 +17157,7 @@ var REQUIRED_LOCAL_STORE_TABLES2 = [
|
|
|
16941
17157
|
];
|
|
16942
17158
|
var SQLITE_PRAGMAS2 = [
|
|
16943
17159
|
"PRAGMA journal_mode = WAL",
|
|
17160
|
+
"PRAGMA synchronous = FULL",
|
|
16944
17161
|
"PRAGMA foreign_keys = ON",
|
|
16945
17162
|
"PRAGMA busy_timeout = 5000"
|
|
16946
17163
|
];
|
|
@@ -17462,14 +17679,22 @@ var LOCAL_SQLITE_MIGRATIONS2 = [
|
|
|
17462
17679
|
)`,
|
|
17463
17680
|
"CREATE INDEX IF NOT EXISTS idx_audit_runs_status ON audit_runs(storage_repository_id, storage_workspace_id, status)"
|
|
17464
17681
|
]
|
|
17682
|
+
},
|
|
17683
|
+
{
|
|
17684
|
+
id: "0011_changeset_cleanup_cursor",
|
|
17685
|
+
statements: [
|
|
17686
|
+
"ALTER TABLE changeset_journal ADD COLUMN cleanup_completed_at TEXT",
|
|
17687
|
+
"CREATE INDEX IF NOT EXISTS idx_changeset_journal_cleanup_pending ON changeset_journal(status, cleanup_completed_at, updated_at)"
|
|
17688
|
+
]
|
|
17465
17689
|
}
|
|
17466
17690
|
];
|
|
17691
|
+
var CHANGESET_STARTUP_CLEANUP_LIMIT = 100;
|
|
17467
17692
|
var ARCHCONTEXT_STATE_DIR_ENV2 = "ARCHCONTEXT_STATE_DIR";
|
|
17468
17693
|
var ARCHCONTEXT_LOCAL_STORE_PATH_ENV2 = "ARCHCONTEXT_LOCAL_STORE_PATH";
|
|
17469
17694
|
function defaultArchContextStateRoot2(env = process.env, platform = process.platform, home = homedir2()) {
|
|
17470
17695
|
const override = env[ARCHCONTEXT_STATE_DIR_ENV2];
|
|
17471
17696
|
if (override)
|
|
17472
|
-
return { path:
|
|
17697
|
+
return { path: resolve14(override), source: "environment" };
|
|
17473
17698
|
if (platform === "darwin")
|
|
17474
17699
|
return { path: join6(home, "Library", "Application Support", "ArchContext"), source: "os-user-data" };
|
|
17475
17700
|
if (platform === "win32")
|
|
@@ -17487,7 +17712,7 @@ function runtimeStatePaths2(root = process.cwd(), env = process.env) {
|
|
|
17487
17712
|
const stateRoot = defaultArchContextStateRoot2(env);
|
|
17488
17713
|
const repositoryStateDir = join6(stateRoot.path, "repositories", storageRepositoryId);
|
|
17489
17714
|
const workspaceStateDir = join6(repositoryStateDir, "worktrees", storageWorkspaceId);
|
|
17490
|
-
const legacyControlDir =
|
|
17715
|
+
const legacyControlDir = resolve14(canonicalRepositoryRoot3, ".archcontext", ".local");
|
|
17491
17716
|
return {
|
|
17492
17717
|
schemaVersion: "archcontext.runtime-state-paths/v1",
|
|
17493
17718
|
stateRoot: stateRoot.path,
|
|
@@ -17521,11 +17746,11 @@ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.en
|
|
|
17521
17746
|
status: "explicit-local-store-override"
|
|
17522
17747
|
});
|
|
17523
17748
|
}
|
|
17524
|
-
ensurePrivateDir2(
|
|
17525
|
-
const legacyExists =
|
|
17749
|
+
ensurePrivateDir2(dirname7(paths.localStorePath));
|
|
17750
|
+
const legacyExists = existsSync11(paths.legacyLocalStorePath);
|
|
17526
17751
|
const integrityCheck = {};
|
|
17527
17752
|
const quarantinedFiles = [];
|
|
17528
|
-
const targetExists =
|
|
17753
|
+
const targetExists = existsSync11(paths.localStorePath);
|
|
17529
17754
|
if (targetExists) {
|
|
17530
17755
|
try {
|
|
17531
17756
|
integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
|
|
@@ -17989,6 +18214,11 @@ class SqliteLocalStore {
|
|
|
17989
18214
|
throw new Error(`ChangeSet journal not found: ${journalId}`);
|
|
17990
18215
|
db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("committed", nowIso2(), nowIso2(), journalId);
|
|
17991
18216
|
}
|
|
18217
|
+
async completeChangeSetCleanup(journalId) {
|
|
18218
|
+
const db = await this.database();
|
|
18219
|
+
const completedAt = nowIso2();
|
|
18220
|
+
db.prepare("UPDATE changeset_journal SET cleanup_completed_at = ?, updated_at = ? WHERE journal_id = ? AND status = ?").run(completedAt, completedAt, journalId, "committed");
|
|
18221
|
+
}
|
|
17992
18222
|
async abortChangeSet(journalId, reason) {
|
|
17993
18223
|
const db = await this.database();
|
|
17994
18224
|
const row = db.prepare("SELECT metadata_json FROM changeset_journal WHERE journal_id = ?").get(journalId);
|
|
@@ -17999,37 +18229,61 @@ class SqliteLocalStore {
|
|
|
17999
18229
|
}
|
|
18000
18230
|
recoverPendingChangeSets() {
|
|
18001
18231
|
const db = this.requireOpenDatabase();
|
|
18002
|
-
const committed = db.prepare(
|
|
18232
|
+
const committed = db.prepare(`SELECT journal_id, files_json FROM changeset_journal
|
|
18233
|
+
WHERE status = ? AND cleanup_completed_at IS NULL
|
|
18234
|
+
ORDER BY updated_at, journal_id
|
|
18235
|
+
LIMIT ?`).all("committed", CHANGESET_STARTUP_CLEANUP_LIMIT);
|
|
18003
18236
|
for (const row of committed) {
|
|
18004
|
-
|
|
18237
|
+
try {
|
|
18238
|
+
cleanupCommittedJournalFiles(JSON.parse(String(row.files_json)));
|
|
18239
|
+
const completedAt = nowIso2();
|
|
18240
|
+
db.prepare("UPDATE changeset_journal SET cleanup_completed_at = ?, updated_at = ? WHERE journal_id = ?").run(completedAt, completedAt, String(row.journal_id));
|
|
18241
|
+
} catch {}
|
|
18005
18242
|
}
|
|
18006
18243
|
const rows = db.prepare("SELECT journal_id, root, files_json, metadata_json FROM changeset_journal WHERE status = ?").all("pending");
|
|
18244
|
+
let recovered = 0;
|
|
18007
18245
|
for (const row of rows) {
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
const
|
|
18014
|
-
if (
|
|
18015
|
-
|
|
18246
|
+
let metadata = {};
|
|
18247
|
+
try {
|
|
18248
|
+
const files = JSON.parse(String(row.files_json));
|
|
18249
|
+
metadata = JSON.parse(String(row.metadata_json));
|
|
18250
|
+
const plannedLedgerEvent = changeSetJournalPlannedLedgerEvent(metadata);
|
|
18251
|
+
const existingLedgerEvent = plannedLedgerEvent ? architectureEventByIdempotency(db, plannedLedgerEvent) : undefined;
|
|
18252
|
+
if (plannedLedgerEvent && existingLedgerEvent) {
|
|
18253
|
+
const expectedEventHash = normalizeArchitectureLedgerEvent(plannedLedgerEvent, existingLedgerEvent.previousEventHash).eventHash;
|
|
18254
|
+
if (expectedEventHash !== existingLedgerEvent.event.eventHash) {
|
|
18255
|
+
throw new Error(`changeset-ledger-recovery-idempotency-conflict: ${plannedLedgerEvent.idempotencyKey}`);
|
|
18256
|
+
}
|
|
18257
|
+
cleanupCommittedJournalFiles(files);
|
|
18258
|
+
const completedAt2 = nowIso2();
|
|
18259
|
+
db.prepare("UPDATE changeset_journal SET status = ?, metadata_json = ?, updated_at = ?, completed_at = ?, cleanup_completed_at = ? WHERE journal_id = ?").run("committed", stableJson(withChangeSetJournalArchitectureLedger(metadata, {
|
|
18260
|
+
recovery: {
|
|
18261
|
+
schemaVersion: "archcontext.changeset-ledger-recovery/v1",
|
|
18262
|
+
status: "ledger-append-detected",
|
|
18263
|
+
eventId: existingLedgerEvent.event.eventId,
|
|
18264
|
+
eventHash: existingLedgerEvent.event.eventHash ?? "",
|
|
18265
|
+
recoveredAt: completedAt2
|
|
18266
|
+
}
|
|
18267
|
+
})), completedAt2, completedAt2, completedAt2, String(row.journal_id));
|
|
18268
|
+
recovered += 1;
|
|
18269
|
+
continue;
|
|
18016
18270
|
}
|
|
18017
|
-
|
|
18018
|
-
|
|
18019
|
-
|
|
18020
|
-
|
|
18021
|
-
|
|
18022
|
-
|
|
18023
|
-
|
|
18024
|
-
|
|
18271
|
+
recoverJournalFiles(String(row.root), files);
|
|
18272
|
+
const completedAt = nowIso2();
|
|
18273
|
+
db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ?, cleanup_completed_at = ? WHERE journal_id = ?").run("recovered", completedAt, completedAt, completedAt, String(row.journal_id));
|
|
18274
|
+
recovered += 1;
|
|
18275
|
+
} catch (error) {
|
|
18276
|
+
db.prepare("UPDATE changeset_journal SET metadata_json = ?, updated_at = ? WHERE journal_id = ?").run(stableJson({
|
|
18277
|
+
...metadata,
|
|
18278
|
+
recoveryError: {
|
|
18279
|
+
schemaVersion: "archcontext.changeset-recovery-error/v1",
|
|
18280
|
+
message: error instanceof Error ? error.message : String(error),
|
|
18281
|
+
failedAt: nowIso2()
|
|
18025
18282
|
}
|
|
18026
|
-
})
|
|
18027
|
-
continue;
|
|
18283
|
+
}), nowIso2(), String(row.journal_id));
|
|
18028
18284
|
}
|
|
18029
|
-
recoverJournalFiles(String(row.root), files);
|
|
18030
|
-
db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("recovered", nowIso2(), nowIso2(), String(row.journal_id));
|
|
18031
18285
|
}
|
|
18032
|
-
return
|
|
18286
|
+
return recovered;
|
|
18033
18287
|
}
|
|
18034
18288
|
async saveTaskState(taskSessionId, state) {
|
|
18035
18289
|
const db = await this.database();
|
|
@@ -18127,52 +18381,38 @@ class SqliteLocalStore {
|
|
|
18127
18381
|
for (const event of input.events)
|
|
18128
18382
|
validateArchitectureLedgerEvent(event);
|
|
18129
18383
|
const db = await this.database();
|
|
18130
|
-
const startedAt = Date.now();
|
|
18131
|
-
const appendedEvents = [];
|
|
18132
|
-
const duplicateEvents = [];
|
|
18133
18384
|
db.exec("BEGIN IMMEDIATE");
|
|
18134
18385
|
try {
|
|
18135
|
-
|
|
18136
|
-
for (const event of input.events) {
|
|
18137
|
-
const duplicate = architectureEventByIdempotency(db, event);
|
|
18138
|
-
if (duplicate) {
|
|
18139
|
-
const expectedDuplicateHash = normalizeArchitectureLedgerEvent(event, duplicate.previousEventHash).eventHash;
|
|
18140
|
-
if (expectedDuplicateHash !== duplicate.event.eventHash) {
|
|
18141
|
-
throw new Error(`architecture-ledger-idempotency-conflict: ${event.idempotencyKey}`);
|
|
18142
|
-
}
|
|
18143
|
-
duplicateEvents.push(duplicate.event);
|
|
18144
|
-
continue;
|
|
18145
|
-
}
|
|
18146
|
-
const previousEventHash = latestArchitectureEventHash(db, event.repository.storageRepositoryId, event.worktree.storageWorkspaceId);
|
|
18147
|
-
const normalized = normalizeArchitectureLedgerEvent(event, previousEventHash);
|
|
18148
|
-
insertArchitectureEvent(db, normalized);
|
|
18149
|
-
persistArchitectureLedgerArtifacts(db, normalized);
|
|
18150
|
-
materializeArchitectureLedgerEvent(db, normalized);
|
|
18151
|
-
appendedEvents.push(normalized);
|
|
18152
|
-
processed += 1;
|
|
18153
|
-
if (input.faultAfterEvents !== undefined && processed >= input.faultAfterEvents)
|
|
18154
|
-
throw new Error("architecture-ledger-fault-injection");
|
|
18155
|
-
}
|
|
18156
|
-
const scope = architectureScopeFromEvent(input.events[0] ?? duplicateEvents[0]);
|
|
18157
|
-
const state = scope ? readArchitectureLedgerStateFromDb(db, scope) : emptyArchitectureLedgerState();
|
|
18158
|
-
if (scope) {
|
|
18159
|
-
recordArchitectureLedgerOperation(db, {
|
|
18160
|
-
scope,
|
|
18161
|
-
operationKind: "append_events",
|
|
18162
|
-
durationMs: Date.now() - startedAt,
|
|
18163
|
-
rowCount: appendedEvents.length,
|
|
18164
|
-
rebuildReason: null
|
|
18165
|
-
});
|
|
18166
|
-
}
|
|
18386
|
+
const result = appendArchitectureEventsInOpenTransaction(db, input);
|
|
18167
18387
|
db.exec("COMMIT");
|
|
18168
|
-
return
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18175
|
-
|
|
18388
|
+
return result;
|
|
18389
|
+
} catch (error) {
|
|
18390
|
+
db.exec("ROLLBACK");
|
|
18391
|
+
throw error;
|
|
18392
|
+
}
|
|
18393
|
+
}
|
|
18394
|
+
async appendArchitectureEventsAndCommitChangeSet(journalId, input) {
|
|
18395
|
+
if (input.writer !== "runtime-daemon")
|
|
18396
|
+
throw new Error("architecture-ledger-writer-must-be-runtime-daemon");
|
|
18397
|
+
for (const event of input.events)
|
|
18398
|
+
validateArchitectureLedgerEvent(event);
|
|
18399
|
+
const db = await this.database();
|
|
18400
|
+
db.exec("BEGIN IMMEDIATE");
|
|
18401
|
+
try {
|
|
18402
|
+
const row = db.prepare("SELECT status, metadata_json FROM changeset_journal WHERE journal_id = ?").get(journalId);
|
|
18403
|
+
if (!row)
|
|
18404
|
+
throw new Error(`ChangeSet journal not found: ${journalId}`);
|
|
18405
|
+
if (String(row.status) !== "pending")
|
|
18406
|
+
throw new Error(`ChangeSet journal is not pending: ${journalId}`);
|
|
18407
|
+
const metadata = JSON.parse(String(row.metadata_json));
|
|
18408
|
+
const result = appendArchitectureEventsInOpenTransaction(db, input);
|
|
18409
|
+
const completedAt = nowIso2();
|
|
18410
|
+
db.prepare("UPDATE changeset_journal SET status = ?, metadata_json = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("committed", stableJson(withChangeSetJournalArchitectureLedger(metadata, {
|
|
18411
|
+
append: changeSetLedgerAppendSummary(result),
|
|
18412
|
+
appendedAt: completedAt
|
|
18413
|
+
})), completedAt, completedAt, journalId);
|
|
18414
|
+
db.exec("COMMIT");
|
|
18415
|
+
return result;
|
|
18176
18416
|
} catch (error) {
|
|
18177
18417
|
db.exec("ROLLBACK");
|
|
18178
18418
|
throw error;
|
|
@@ -18186,24 +18426,50 @@ class SqliteLocalStore {
|
|
|
18186
18426
|
WHERE storage_repository_id = ?
|
|
18187
18427
|
AND storage_workspace_id = ?
|
|
18188
18428
|
${statusClause}
|
|
18189
|
-
ORDER BY created_at DESC, run_id ASC`).all(input.repository.storageRepositoryId, input.worktree
|
|
18429
|
+
ORDER BY created_at DESC, run_id ASC`).all(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), ...statuses).map((row) => JSON.parse(String(row.run_json)));
|
|
18430
|
+
}
|
|
18431
|
+
async resolveArchitectureLedgerScope(input) {
|
|
18432
|
+
const db = await this.database();
|
|
18433
|
+
const rows = db.prepare(`SELECT event_json FROM architecture_events
|
|
18434
|
+
WHERE storage_repository_id = ? AND workspace_id = ? AND branch = ?
|
|
18435
|
+
ORDER BY event_sequence DESC`).all(input.repository.storageRepositoryId, input.worktree.workspaceId, input.worktree.branch);
|
|
18436
|
+
for (const row of rows) {
|
|
18437
|
+
const event = JSON.parse(String(row.event_json));
|
|
18438
|
+
if (event.worktree.storageWorkspaceId === input.worktree.storageWorkspaceId) {
|
|
18439
|
+
return architectureScopeFromEvent(event);
|
|
18440
|
+
}
|
|
18441
|
+
}
|
|
18442
|
+
return input;
|
|
18443
|
+
}
|
|
18444
|
+
async resolveLatestArchitectureLedgerScope(input) {
|
|
18445
|
+
const db = await this.database();
|
|
18446
|
+
const rows = db.prepare(`SELECT event_json FROM architecture_events
|
|
18447
|
+
WHERE storage_repository_id = ? AND workspace_id = ?
|
|
18448
|
+
ORDER BY event_sequence DESC`).all(input.repository.storageRepositoryId, input.worktree.workspaceId);
|
|
18449
|
+
for (const row of rows) {
|
|
18450
|
+
const event = JSON.parse(String(row.event_json));
|
|
18451
|
+
if (event.worktree.storageWorkspaceId === input.worktree.storageWorkspaceId) {
|
|
18452
|
+
return architectureScopeFromEvent(event);
|
|
18453
|
+
}
|
|
18454
|
+
}
|
|
18455
|
+
return input;
|
|
18190
18456
|
}
|
|
18191
18457
|
async getAuditRun(input) {
|
|
18192
18458
|
const db = await this.database();
|
|
18193
18459
|
const row = db.prepare(`SELECT run_json FROM audit_runs
|
|
18194
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND run_id = ?`).get(input.repository.storageRepositoryId, input.worktree.
|
|
18460
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND run_id = ?`).get(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), architectureLedgerStorageId(input.worktree, input.runId));
|
|
18195
18461
|
return row ? JSON.parse(String(row.run_json)) : undefined;
|
|
18196
18462
|
}
|
|
18197
18463
|
async readArchitectureLedgerSourceCursor(input) {
|
|
18198
18464
|
const db = await this.database();
|
|
18199
18465
|
const row = db.prepare(`SELECT cursor_json FROM source_cursors
|
|
18200
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND cursor_id = ?`).get(input.repository.storageRepositoryId, input.worktree.
|
|
18466
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND cursor_id = ?`).get(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), architectureLedgerStorageId(input.worktree, input.cursorId));
|
|
18201
18467
|
return row ? JSON.parse(String(row.cursor_json)) : undefined;
|
|
18202
18468
|
}
|
|
18203
18469
|
async createArchitectureLedgerSnapshot(input) {
|
|
18204
18470
|
const db = await this.database();
|
|
18205
18471
|
const startedAt = Date.now();
|
|
18206
|
-
const latest = latestArchitectureEvent(db, input.repository.storageRepositoryId, input.worktree
|
|
18472
|
+
const latest = latestArchitectureEvent(db, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18207
18473
|
if (!latest)
|
|
18208
18474
|
throw new Error("architecture-ledger-snapshot-requires-event");
|
|
18209
18475
|
const state = readArchitectureLedgerStateFromDb(db, input);
|
|
@@ -18217,7 +18483,7 @@ class SqliteLocalStore {
|
|
|
18217
18483
|
(snapshot_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, branch, head_sha, worktree_digest,
|
|
18218
18484
|
source_mode, last_event_id, last_event_hash, graph_digest, projection_digest, entity_count, relation_count,
|
|
18219
18485
|
constraint_count, input_digests_json, snapshot_json, created_at)
|
|
18220
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(snapshot.snapshotId, snapshot.repository.repositoryId, snapshot.repository.storageRepositoryId, snapshot.worktree.workspaceId, snapshot.worktree
|
|
18486
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(snapshot.snapshotId, snapshot.repository.repositoryId, snapshot.repository.storageRepositoryId, snapshot.worktree.workspaceId, architectureLedgerWorkspaceKey(snapshot.worktree), snapshot.worktree.branch, snapshot.worktree.headSha, snapshot.worktree.worktreeDigest, snapshot.sourceMode, architectureLedgerStorageId(snapshot.worktree, snapshot.eventCursor.lastEventId), snapshot.eventCursor.lastEventHash, snapshot.graphDigest, snapshot.projectionDigest, snapshot.entityCount, snapshot.relationCount, snapshot.constraintCount, stableJson(snapshot.inputDigests), stableJson(snapshot), snapshot.createdAt);
|
|
18221
18487
|
recordArchitectureLedgerOperation(db, {
|
|
18222
18488
|
scope: input,
|
|
18223
18489
|
operationKind: "create_snapshot",
|
|
@@ -18286,16 +18552,16 @@ class SqliteLocalStore {
|
|
|
18286
18552
|
const db = await this.database();
|
|
18287
18553
|
const startedAt = Date.now();
|
|
18288
18554
|
const snapshot = db.prepare(`SELECT last_event_id FROM architecture_snapshots
|
|
18289
|
-
WHERE snapshot_id = ? AND storage_repository_id = ? AND storage_workspace_id = ?`).get(input.beforeSnapshotId, input.repository.storageRepositoryId, input.worktree
|
|
18555
|
+
WHERE snapshot_id = ? AND storage_repository_id = ? AND storage_workspace_id = ?`).get(input.beforeSnapshotId, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18290
18556
|
if (!snapshot)
|
|
18291
18557
|
throw new Error(`architecture-ledger-snapshot-not-found: ${input.beforeSnapshotId}`);
|
|
18292
18558
|
const cursor = db.prepare("SELECT event_sequence FROM architecture_events WHERE event_id = ?").get(String(snapshot.last_event_id));
|
|
18293
18559
|
if (!cursor)
|
|
18294
18560
|
throw new Error(`architecture-ledger-snapshot-cursor-not-found: ${String(snapshot.last_event_id)}`);
|
|
18295
18561
|
const before = Number(db.prepare(`SELECT COUNT(*) AS count FROM architecture_events
|
|
18296
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND event_sequence <= ? AND compacted_by_snapshot_id IS NULL`).get(input.repository.storageRepositoryId, input.worktree
|
|
18562
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND event_sequence <= ? AND compacted_by_snapshot_id IS NULL`).get(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), Number(cursor.event_sequence))?.count ?? 0);
|
|
18297
18563
|
db.prepare(`UPDATE architecture_events SET compacted_by_snapshot_id = ?
|
|
18298
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND event_sequence <= ? AND compacted_by_snapshot_id IS NULL`).run(input.beforeSnapshotId, input.repository.storageRepositoryId, input.worktree
|
|
18564
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND event_sequence <= ? AND compacted_by_snapshot_id IS NULL`).run(input.beforeSnapshotId, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), Number(cursor.event_sequence));
|
|
18299
18565
|
recordArchitectureLedgerOperation(db, {
|
|
18300
18566
|
scope: input,
|
|
18301
18567
|
operationKind: "compact_events",
|
|
@@ -18315,7 +18581,7 @@ class SqliteLocalStore {
|
|
|
18315
18581
|
const replay = await this.verifyArchitectureLedgerReplay(input);
|
|
18316
18582
|
if (!replay.ok)
|
|
18317
18583
|
failures.push(...replay.mismatches);
|
|
18318
|
-
const snapshotCount = Number(db.prepare("SELECT COUNT(*) AS count FROM architecture_snapshots WHERE storage_repository_id = ? AND storage_workspace_id = ?").get(input.repository.storageRepositoryId, input.worktree
|
|
18584
|
+
const snapshotCount = Number(db.prepare("SELECT COUNT(*) AS count FROM architecture_snapshots WHERE storage_repository_id = ? AND storage_workspace_id = ?").get(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree))?.count ?? 0);
|
|
18319
18585
|
const result = {
|
|
18320
18586
|
ok: failures.length === 0,
|
|
18321
18587
|
graphDigest: replay.materializedDigest,
|
|
@@ -18334,8 +18600,8 @@ class SqliteLocalStore {
|
|
|
18334
18600
|
}
|
|
18335
18601
|
async backupArchitectureLedger(input) {
|
|
18336
18602
|
const db = await this.database();
|
|
18337
|
-
ensurePrivateDir2(
|
|
18338
|
-
if (
|
|
18603
|
+
ensurePrivateDir2(dirname7(input.backupPath));
|
|
18604
|
+
if (existsSync11(input.backupPath))
|
|
18339
18605
|
rmSync5(input.backupPath, { force: true });
|
|
18340
18606
|
db.exec(`VACUUM INTO ${sqliteStringLiteral2(input.backupPath)}`);
|
|
18341
18607
|
return { backupPath: input.backupPath, integrity: assertSqliteIntegrity2(input.backupPath) };
|
|
@@ -18366,9 +18632,80 @@ class SqliteLocalStore {
|
|
|
18366
18632
|
function architectureScopeFromEvent(event) {
|
|
18367
18633
|
return event ? { repository: event.repository, worktree: event.worktree } : undefined;
|
|
18368
18634
|
}
|
|
18635
|
+
function architectureLedgerWorkspaceKey(worktree) {
|
|
18636
|
+
return `ledger-scope:${digestJson({
|
|
18637
|
+
storageWorkspaceId: worktree.storageWorkspaceId,
|
|
18638
|
+
branch: worktree.branch,
|
|
18639
|
+
headSha: worktree.headSha,
|
|
18640
|
+
worktreeDigest: worktree.worktreeDigest
|
|
18641
|
+
}).slice("sha256:".length)}`;
|
|
18642
|
+
}
|
|
18643
|
+
function architectureLedgerStorageId(worktree, logicalId) {
|
|
18644
|
+
return `${architectureLedgerWorkspaceKey(worktree)}:${logicalId}`;
|
|
18645
|
+
}
|
|
18646
|
+
function appendArchitectureEventsInOpenTransaction(db, input) {
|
|
18647
|
+
const startedAt = Date.now();
|
|
18648
|
+
const appendedEvents = [];
|
|
18649
|
+
const duplicateEvents = [];
|
|
18650
|
+
let processed = 0;
|
|
18651
|
+
for (const event of input.events) {
|
|
18652
|
+
const duplicate = architectureEventByIdempotency(db, event);
|
|
18653
|
+
if (duplicate) {
|
|
18654
|
+
const expectedDuplicateHash = normalizeArchitectureLedgerEvent(event, duplicate.previousEventHash).eventHash;
|
|
18655
|
+
if (expectedDuplicateHash !== duplicate.event.eventHash) {
|
|
18656
|
+
throw new Error(`architecture-ledger-idempotency-conflict: ${event.idempotencyKey}`);
|
|
18657
|
+
}
|
|
18658
|
+
duplicateEvents.push(duplicate.event);
|
|
18659
|
+
continue;
|
|
18660
|
+
}
|
|
18661
|
+
const previousEventHash = latestArchitectureEventHash(db, event.repository.storageRepositoryId, architectureLedgerWorkspaceKey(event.worktree));
|
|
18662
|
+
const normalized = normalizeArchitectureLedgerEvent(event, previousEventHash);
|
|
18663
|
+
const operations = architectureLedgerPayload(normalized).operations ?? [];
|
|
18664
|
+
const scope2 = architectureScopeFromEvent(normalized);
|
|
18665
|
+
if (operations.length > 0) {
|
|
18666
|
+
const currentDigest = architectureLedgerStateDigest(readArchitectureLedgerStateFromDb(db, scope2));
|
|
18667
|
+
if (normalized.baseDigest !== currentDigest) {
|
|
18668
|
+
throw new Error(`architecture-ledger-base-digest-conflict: expected ${currentDigest}, received ${normalized.baseDigest}`);
|
|
18669
|
+
}
|
|
18670
|
+
}
|
|
18671
|
+
insertArchitectureEvent(db, normalized);
|
|
18672
|
+
persistArchitectureLedgerArtifacts(db, normalized);
|
|
18673
|
+
materializeArchitectureLedgerEvent(db, normalized);
|
|
18674
|
+
if (operations.length > 0) {
|
|
18675
|
+
const resultingDigest = architectureLedgerStateDigest(readArchitectureLedgerStateFromDb(db, scope2));
|
|
18676
|
+
if (normalized.resultingDigest !== resultingDigest) {
|
|
18677
|
+
throw new Error(`architecture-ledger-resulting-digest-conflict: expected ${resultingDigest}, received ${normalized.resultingDigest}`);
|
|
18678
|
+
}
|
|
18679
|
+
}
|
|
18680
|
+
appendedEvents.push(normalized);
|
|
18681
|
+
processed += 1;
|
|
18682
|
+
if (input.faultAfterEvents !== undefined && processed >= input.faultAfterEvents) {
|
|
18683
|
+
throw new Error("architecture-ledger-fault-injection");
|
|
18684
|
+
}
|
|
18685
|
+
}
|
|
18686
|
+
const scope = architectureScopeFromEvent(input.events[0] ?? duplicateEvents[0]);
|
|
18687
|
+
const state = scope ? readArchitectureLedgerStateFromDb(db, scope) : emptyArchitectureLedgerState();
|
|
18688
|
+
if (scope) {
|
|
18689
|
+
recordArchitectureLedgerOperation(db, {
|
|
18690
|
+
scope,
|
|
18691
|
+
operationKind: "append_events",
|
|
18692
|
+
durationMs: Date.now() - startedAt,
|
|
18693
|
+
rowCount: appendedEvents.length,
|
|
18694
|
+
rebuildReason: null
|
|
18695
|
+
});
|
|
18696
|
+
}
|
|
18697
|
+
return {
|
|
18698
|
+
appendedEvents,
|
|
18699
|
+
duplicateEvents,
|
|
18700
|
+
graphDigest: architectureLedgerStateDigest(state),
|
|
18701
|
+
entityCount: state.entities.length,
|
|
18702
|
+
relationCount: state.relations.length,
|
|
18703
|
+
constraintCount: state.constraints.length
|
|
18704
|
+
};
|
|
18705
|
+
}
|
|
18369
18706
|
function architectureEventByIdempotency(db, event) {
|
|
18370
18707
|
const row = db.prepare(`SELECT event_json, previous_event_hash FROM architecture_events
|
|
18371
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND idempotency_key = ?`).get(event.repository.storageRepositoryId, event.worktree
|
|
18708
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND idempotency_key = ?`).get(event.repository.storageRepositoryId, architectureLedgerWorkspaceKey(event.worktree), event.idempotencyKey);
|
|
18372
18709
|
return row ? {
|
|
18373
18710
|
event: JSON.parse(String(row.event_json)),
|
|
18374
18711
|
previousEventHash: row.previous_event_hash === null || row.previous_event_hash === undefined ? null : String(row.previous_event_hash)
|
|
@@ -18384,11 +18721,12 @@ function latestArchitectureEvent(db, storageRepositoryId, storageWorkspaceId) {
|
|
|
18384
18721
|
return row ? { event: JSON.parse(String(row.event_json)), eventHash: String(row.event_hash) } : undefined;
|
|
18385
18722
|
}
|
|
18386
18723
|
function insertArchitectureEvent(db, event) {
|
|
18724
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18387
18725
|
db.prepare(`INSERT INTO architecture_events
|
|
18388
18726
|
(event_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, branch, head_sha, worktree_digest,
|
|
18389
18727
|
event_type, payload_version, source, actor_kind, actor_id, base_digest, resulting_digest, previous_event_hash,
|
|
18390
18728
|
event_hash, idempotency_key, payload_json, provenance_json, event_json, created_at)
|
|
18391
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.eventId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId,
|
|
18729
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, event.eventId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, event.worktree.branch, event.worktree.headSha, event.worktree.worktreeDigest, event.eventType, event.payloadVersion, event.source, event.actor.kind, event.actor.id, event.baseDigest, event.resultingDigest, event.previousEventHash ?? null, event.eventHash, event.idempotencyKey, stableJson(event.payload), stableJson(event.provenance), stableJson(event), event.timestamp);
|
|
18392
18730
|
insertArchitectureLedgerFts(db, "event", architectureLedgerPayload(event).summary ?? "", architectureLedgerPayload(event).rationale ?? "", architectureLedgerPayload(event).title ?? "", "");
|
|
18393
18731
|
const payload = architectureLedgerPayload(event);
|
|
18394
18732
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
@@ -18402,11 +18740,13 @@ function insertArchitectureEvent(db, event) {
|
|
|
18402
18740
|
}
|
|
18403
18741
|
function persistArchitectureLedgerArtifacts(db, event) {
|
|
18404
18742
|
const payload = architectureLedgerPayload(event);
|
|
18743
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18744
|
+
const storageEventId = architectureLedgerStorageId(event.worktree, event.eventId);
|
|
18405
18745
|
for (const evidence of payload.evidenceItems ?? []) {
|
|
18406
18746
|
db.prepare(`INSERT OR REPLACE INTO evidence_items
|
|
18407
18747
|
(evidence_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, kind, strength,
|
|
18408
18748
|
polarity, origin, subject, selector_json, summary, coverage_json, supports_json, provenance_json, evidence_json, digest, created_at)
|
|
18409
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(evidence.evidenceId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId,
|
|
18749
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, evidence.evidenceId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, storageEventId, evidence.kind, evidence.strength, evidence.polarity, evidence.origin, evidence.subject, stableJson(evidence.selector), evidence.summary, stableJson(evidence.coverage), stableJson(evidence.supports), stableJson(evidence.provenance), stableJson(evidence), evidence.digest, evidence.createdAt);
|
|
18410
18750
|
insertArchitectureLedgerFts(db, "evidence", evidence.summary, "", "", evidence.summary);
|
|
18411
18751
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18412
18752
|
docId: `evidence:${evidence.evidenceId}`,
|
|
@@ -18421,7 +18761,7 @@ function persistArchitectureLedgerArtifacts(db, event) {
|
|
|
18421
18761
|
db.prepare(`INSERT OR REPLACE INTO evidence_bindings
|
|
18422
18762
|
(binding_id, evidence_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id,
|
|
18423
18763
|
target_kind, target_id, binding_reason, authority_effect, provenance_json, binding_json, created_at)
|
|
18424
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(binding.bindingId, binding.evidenceId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId,
|
|
18764
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, binding.bindingId), architectureLedgerStorageId(event.worktree, binding.evidenceId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, storageEventId, binding.target.kind, binding.target.id, binding.bindingReason, binding.authorityEffect, stableJson(binding.provenance), stableJson(binding), binding.createdAt);
|
|
18425
18765
|
}
|
|
18426
18766
|
for (const run of payload.recommendationRuns ?? [])
|
|
18427
18767
|
persistRecommendationRun(db, event, run);
|
|
@@ -18441,17 +18781,19 @@ function persistArchitectureLedgerArtifacts(db, event) {
|
|
|
18441
18781
|
persistProjectionState(db, event, payload.projectionState);
|
|
18442
18782
|
}
|
|
18443
18783
|
function persistRecommendationRun(db, event, run) {
|
|
18784
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18444
18785
|
db.prepare(`INSERT OR REPLACE INTO recommendation_runs
|
|
18445
18786
|
(run_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, status, catalog_digest,
|
|
18446
18787
|
input_digest, output_digest, metrics_json, run_json, started_at, completed_at)
|
|
18447
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(run.runId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, event.worktree
|
|
18788
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, run.runId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), run.status, run.catalogDigest, run.inputDigest, run.outputDigest, stableJson(run.metrics), stableJson(run), run.startedAt, run.completedAt ?? null);
|
|
18448
18789
|
}
|
|
18449
18790
|
function persistRecommendation(db, event, recommendation) {
|
|
18791
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18450
18792
|
db.prepare(`INSERT OR REPLACE INTO recommendations
|
|
18451
18793
|
(recommendation_id, run_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, fingerprint,
|
|
18452
18794
|
subject, practice_id, status, confidence, enforcement, risk, uncertainty, evidence_binding_ids_json, explanation_json,
|
|
18453
18795
|
recommendation_json, created_at, updated_at)
|
|
18454
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(recommendation.recommendationId, recommendation.runId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, event.worktree
|
|
18796
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, recommendation.recommendationId), architectureLedgerStorageId(event.worktree, recommendation.runId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), recommendation.fingerprint, recommendation.subject, recommendation.practiceId ?? null, recommendation.status, recommendation.confidence, recommendation.enforcement, recommendation.risk, recommendation.uncertainty, stableJson(recommendation.evidenceBindingIds), stableJson(recommendation.explanation), stableJson(recommendation), recommendation.createdAt, recommendation.updatedAt);
|
|
18455
18797
|
insertArchitectureLedgerFts(db, "recommendation", recommendation.explanation.join(`
|
|
18456
18798
|
`), "", recommendation.subject, recommendation.explanation.join(`
|
|
18457
18799
|
`));
|
|
@@ -18468,44 +18810,51 @@ function persistRecommendation(db, event, recommendation) {
|
|
|
18468
18810
|
});
|
|
18469
18811
|
}
|
|
18470
18812
|
function persistAgentJob(db, event, job) {
|
|
18813
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18471
18814
|
db.prepare(`INSERT OR REPLACE INTO agent_jobs
|
|
18472
18815
|
(job_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, status, runner_port,
|
|
18473
18816
|
fingerprint, input_digest, output_digest, stale_policy, job_json, queued_at, updated_at)
|
|
18474
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(job.jobId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, event.worktree
|
|
18817
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, job.jobId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), job.status, job.runnerPort, job.fingerprint, job.inputDigest, job.outputDigest ?? null, job.stalePolicy, stableJson(job), job.queuedAt, job.updatedAt);
|
|
18475
18818
|
}
|
|
18476
18819
|
function persistAuditRun(db, event, run) {
|
|
18820
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18477
18821
|
db.prepare(`INSERT OR REPLACE INTO audit_runs
|
|
18478
18822
|
(run_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, job_id, report_id, status,
|
|
18479
18823
|
repo_name_with_owner, repo_visibility, base_sha, input_digest, output_digest, run_json, created_at)
|
|
18480
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(run.runId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, event.worktree
|
|
18824
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, run.runId), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), run.jobId, run.reportId, run.status, run.repoNameWithOwner, run.repoVisibility, run.baseSha, run.inputDigest, run.outputDigest, stableJson(run), run.createdAt);
|
|
18481
18825
|
}
|
|
18482
18826
|
function persistProjectionState(db, event, state) {
|
|
18483
18827
|
const path = String(state.path ?? "projection");
|
|
18484
18828
|
const projectionDigest = typeof state.projectionDigest === "string" ? state.projectionDigest : digestJson(state);
|
|
18829
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18485
18830
|
db.prepare(`INSERT OR REPLACE INTO projection_state
|
|
18486
18831
|
(projection_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, path, projection_digest, state_json, updated_at)
|
|
18487
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(String(state.projectionId ?? stableLedgerId("projection", event.eventId, path)), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, event.worktree
|
|
18832
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, String(state.projectionId ?? stableLedgerId("projection", event.eventId, path))), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), path, projectionDigest, stableJson(state), event.timestamp);
|
|
18488
18833
|
}
|
|
18489
18834
|
function persistSourceCursor(db, event, cursor) {
|
|
18490
18835
|
const source = String(cursor.source ?? event.source);
|
|
18836
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18491
18837
|
db.prepare(`INSERT OR REPLACE INTO source_cursors
|
|
18492
18838
|
(cursor_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, source, cursor_json, updated_at)
|
|
18493
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(String(cursor.cursorId ?? stableLedgerId("cursor", event.eventId, source)), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId,
|
|
18839
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(architectureLedgerStorageId(event.worktree, String(cursor.cursorId ?? stableLedgerId("cursor", event.eventId, source))), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, source, stableJson(cursor), event.timestamp);
|
|
18494
18840
|
}
|
|
18495
18841
|
function persistGenericLedgerJson(db, event, table, idColumn, jsonColumn, value, prefix) {
|
|
18496
18842
|
const id = String(value[idColumn] ?? value.id ?? stableLedgerId(prefix, event.eventId, stableJson(value)));
|
|
18843
|
+
const storageId = architectureLedgerStorageId(event.worktree, id);
|
|
18844
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18497
18845
|
if (table === "recommendation_feedback") {
|
|
18498
18846
|
db.prepare(`INSERT OR REPLACE INTO recommendation_feedback
|
|
18499
18847
|
(feedback_id, recommendation_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, feedback_json, created_at)
|
|
18500
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
18848
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(storageId, architectureLedgerStorageId(event.worktree, String(value.recommendationId ?? value.recommendation_id ?? "unknown")), event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), stableJson(value), String(value.createdAt ?? event.timestamp));
|
|
18501
18849
|
return;
|
|
18502
18850
|
}
|
|
18503
18851
|
db.prepare(`INSERT OR REPLACE INTO waivers
|
|
18504
18852
|
(waiver_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, target_kind, target_id, waiver_json, created_at, expires_at)
|
|
18505
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
18853
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(storageId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, workspaceKey, architectureLedgerStorageId(event.worktree, event.eventId), String(value.targetKind ?? value.target_kind ?? "unknown"), String(value.targetId ?? value.target_id ?? "unknown"), stableJson(value), String(value.createdAt ?? event.timestamp), value.expiresAt ? String(value.expiresAt) : null);
|
|
18506
18854
|
}
|
|
18507
18855
|
function materializeArchitectureLedgerEvent(db, event) {
|
|
18508
18856
|
const payload = architectureLedgerPayload(event);
|
|
18857
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18509
18858
|
for (const operation of payload.operations ?? []) {
|
|
18510
18859
|
switch (operation.op) {
|
|
18511
18860
|
case "upsert_entity":
|
|
@@ -18513,31 +18862,32 @@ function materializeArchitectureLedgerEvent(db, event) {
|
|
|
18513
18862
|
break;
|
|
18514
18863
|
case "delete_entity":
|
|
18515
18864
|
deleteArchitectureLedgerSearchDocs(db, { repository: event.repository, worktree: event.worktree }, [operation.entityId]);
|
|
18516
|
-
db.prepare("DELETE FROM architecture_entities_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND entity_id = ?").run(event.repository.storageRepositoryId,
|
|
18517
|
-
db.prepare("DELETE FROM architecture_relations_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND (source_entity_id = ? OR target_entity_id = ?)").run(event.repository.storageRepositoryId,
|
|
18865
|
+
db.prepare("DELETE FROM architecture_entities_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND entity_id = ?").run(event.repository.storageRepositoryId, workspaceKey, operation.entityId);
|
|
18866
|
+
db.prepare("DELETE FROM architecture_relations_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND (source_entity_id = ? OR target_entity_id = ?)").run(event.repository.storageRepositoryId, workspaceKey, operation.entityId, operation.entityId);
|
|
18518
18867
|
break;
|
|
18519
18868
|
case "upsert_relation":
|
|
18520
18869
|
upsertArchitectureRelation(db, event, operation.relation);
|
|
18521
18870
|
break;
|
|
18522
18871
|
case "delete_relation":
|
|
18523
18872
|
deleteArchitectureLedgerSearchDocs(db, { repository: event.repository, worktree: event.worktree }, [operation.relationId]);
|
|
18524
|
-
db.prepare("DELETE FROM architecture_relations_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND relation_id = ?").run(event.repository.storageRepositoryId,
|
|
18873
|
+
db.prepare("DELETE FROM architecture_relations_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND relation_id = ?").run(event.repository.storageRepositoryId, workspaceKey, operation.relationId);
|
|
18525
18874
|
break;
|
|
18526
18875
|
case "upsert_constraint":
|
|
18527
18876
|
upsertArchitectureConstraint(db, event, operation.constraint);
|
|
18528
18877
|
break;
|
|
18529
18878
|
case "delete_constraint":
|
|
18530
18879
|
deleteArchitectureLedgerSearchDocs(db, { repository: event.repository, worktree: event.worktree }, [operation.constraintId]);
|
|
18531
|
-
db.prepare("DELETE FROM architecture_constraints_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND constraint_id = ?").run(event.repository.storageRepositoryId,
|
|
18880
|
+
db.prepare("DELETE FROM architecture_constraints_current WHERE storage_repository_id = ? AND storage_workspace_id = ? AND constraint_id = ?").run(event.repository.storageRepositoryId, workspaceKey, operation.constraintId);
|
|
18532
18881
|
break;
|
|
18533
18882
|
}
|
|
18534
18883
|
}
|
|
18535
18884
|
}
|
|
18536
18885
|
function upsertArchitectureEntity(db, event, entity) {
|
|
18886
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18537
18887
|
db.prepare(`INSERT OR REPLACE INTO architecture_entities_current
|
|
18538
18888
|
(storage_repository_id, storage_workspace_id, entity_id, repository_id, workspace_id, branch, head_sha, worktree_digest,
|
|
18539
18889
|
kind, canonical_name, status, path, summary, metadata_json, last_event_id, updated_at)
|
|
18540
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId,
|
|
18890
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId, workspaceKey, entity.entityId, event.repository.repositoryId, event.worktree.workspaceId, event.worktree.branch, event.worktree.headSha, event.worktree.worktreeDigest, entity.kind, entity.canonicalName, entity.status, entity.path ?? null, entity.summary ?? null, stableJson(entity.metadata ?? {}), architectureLedgerStorageId(event.worktree, event.eventId), event.timestamp);
|
|
18541
18891
|
insertArchitectureLedgerFts(db, "entity", entity.summary ?? "", "", entity.canonicalName, "");
|
|
18542
18892
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18543
18893
|
docId: `entity:${entity.entityId}`,
|
|
@@ -18550,10 +18900,11 @@ function upsertArchitectureEntity(db, event, entity) {
|
|
|
18550
18900
|
});
|
|
18551
18901
|
}
|
|
18552
18902
|
function upsertArchitectureRelation(db, event, relation) {
|
|
18903
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18553
18904
|
db.prepare(`INSERT OR REPLACE INTO architecture_relations_current
|
|
18554
18905
|
(storage_repository_id, storage_workspace_id, relation_id, repository_id, workspace_id, branch, head_sha, worktree_digest,
|
|
18555
18906
|
kind, source_entity_id, target_entity_id, status, summary, metadata_json, last_event_id, updated_at)
|
|
18556
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId,
|
|
18907
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId, workspaceKey, relation.relationId, event.repository.repositoryId, event.worktree.workspaceId, event.worktree.branch, event.worktree.headSha, event.worktree.worktreeDigest, relation.kind, relation.sourceEntityId, relation.targetEntityId, relation.status, relation.summary ?? null, stableJson(relation.metadata ?? {}), architectureLedgerStorageId(event.worktree, event.eventId), event.timestamp);
|
|
18557
18908
|
insertArchitectureLedgerFts(db, "relation", relation.summary ?? "", "", relation.relationId, "");
|
|
18558
18909
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18559
18910
|
docId: `relation:${relation.relationId}`,
|
|
@@ -18566,10 +18917,11 @@ function upsertArchitectureRelation(db, event, relation) {
|
|
|
18566
18917
|
});
|
|
18567
18918
|
}
|
|
18568
18919
|
function upsertArchitectureConstraint(db, event, constraint) {
|
|
18920
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18569
18921
|
db.prepare(`INSERT OR REPLACE INTO architecture_constraints_current
|
|
18570
18922
|
(storage_repository_id, storage_workspace_id, constraint_id, repository_id, workspace_id, branch, head_sha, worktree_digest,
|
|
18571
18923
|
kind, subject_id, status, severity, summary, metadata_json, last_event_id, updated_at)
|
|
18572
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId,
|
|
18924
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId, workspaceKey, constraint.constraintId, event.repository.repositoryId, event.worktree.workspaceId, event.worktree.branch, event.worktree.headSha, event.worktree.worktreeDigest, constraint.kind, constraint.subjectId, constraint.status, constraint.severity ?? null, constraint.summary ?? null, stableJson(constraint.metadata ?? {}), architectureLedgerStorageId(event.worktree, event.eventId), event.timestamp);
|
|
18573
18925
|
insertArchitectureLedgerFts(db, "constraint", constraint.summary ?? "", "", constraint.constraintId, "");
|
|
18574
18926
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18575
18927
|
docId: `constraint:${constraint.constraintId}`,
|
|
@@ -18582,7 +18934,7 @@ function upsertArchitectureConstraint(db, event, constraint) {
|
|
|
18582
18934
|
});
|
|
18583
18935
|
}
|
|
18584
18936
|
function readArchitectureLedgerStateFromDb(db, scope) {
|
|
18585
|
-
const scopeParams = [scope.repository.storageRepositoryId, scope.worktree
|
|
18937
|
+
const scopeParams = [scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(scope.worktree)];
|
|
18586
18938
|
const entities = db.prepare(`SELECT entity_id, kind, canonical_name, status, path, summary, metadata_json
|
|
18587
18939
|
FROM architecture_entities_current
|
|
18588
18940
|
WHERE storage_repository_id = ? AND storage_workspace_id = ?
|
|
@@ -18623,7 +18975,7 @@ function readArchitectureLedgerStateFromDb(db, scope) {
|
|
|
18623
18975
|
}
|
|
18624
18976
|
function readArchitectureLedgerNeighborhoodFromDb(db, input) {
|
|
18625
18977
|
const depth = Math.max(0, Math.floor(input.depth));
|
|
18626
|
-
const scopeParams = [input.repository.storageRepositoryId, input.worktree
|
|
18978
|
+
const scopeParams = [input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree)];
|
|
18627
18979
|
const entityIds = [...new Set(db.prepare(`WITH RECURSIVE seed(entity_id) AS (
|
|
18628
18980
|
SELECT entity_id FROM architecture_entities_current
|
|
18629
18981
|
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND entity_id = ?
|
|
@@ -18704,42 +19056,43 @@ function architectureEventsForReplay(db, input) {
|
|
|
18704
19056
|
let untilEventId = input.untilEventId;
|
|
18705
19057
|
if (input.snapshotId) {
|
|
18706
19058
|
const snapshot = db.prepare(`SELECT last_event_id FROM architecture_snapshots
|
|
18707
|
-
WHERE snapshot_id = ? AND storage_repository_id = ? AND storage_workspace_id = ?`).get(input.snapshotId, input.repository.storageRepositoryId, input.worktree
|
|
19059
|
+
WHERE snapshot_id = ? AND storage_repository_id = ? AND storage_workspace_id = ?`).get(input.snapshotId, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18708
19060
|
if (!snapshot)
|
|
18709
19061
|
throw new Error(`architecture-ledger-snapshot-not-found: ${input.snapshotId}`);
|
|
18710
19062
|
untilEventId = String(snapshot.last_event_id);
|
|
18711
19063
|
}
|
|
18712
19064
|
const rows = db.prepare(`SELECT event_id, event_json FROM architecture_events
|
|
18713
19065
|
WHERE storage_repository_id = ? AND storage_workspace_id = ?
|
|
18714
|
-
ORDER BY event_sequence`).all(input.repository.storageRepositoryId, input.worktree
|
|
19066
|
+
ORDER BY event_sequence`).all(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18715
19067
|
const events = [];
|
|
18716
19068
|
for (const row of rows) {
|
|
18717
19069
|
const event = JSON.parse(String(row.event_json));
|
|
18718
19070
|
events.push(event);
|
|
18719
|
-
if (untilEventId && String(row.event_id) === untilEventId)
|
|
19071
|
+
if (untilEventId && (String(row.event_id) === untilEventId || event.eventId === untilEventId))
|
|
18720
19072
|
break;
|
|
18721
19073
|
}
|
|
18722
19074
|
return events;
|
|
18723
19075
|
}
|
|
18724
19076
|
function deleteArchitectureCurrentState(db, scope) {
|
|
18725
19077
|
for (const table of ["architecture_entities_current", "architecture_relations_current", "architecture_constraints_current"]) {
|
|
18726
|
-
db.prepare(`DELETE FROM ${table} WHERE storage_repository_id = ? AND storage_workspace_id = ?`).run(scope.repository.storageRepositoryId, scope.worktree
|
|
19078
|
+
db.prepare(`DELETE FROM ${table} WHERE storage_repository_id = ? AND storage_workspace_id = ?`).run(scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(scope.worktree));
|
|
18727
19079
|
}
|
|
18728
19080
|
}
|
|
18729
19081
|
function insertArchitectureLedgerFts(db, kind, summary, rationale, title, evidenceSummary) {
|
|
18730
19082
|
db.prepare("INSERT INTO architecture_ledger_fts(kind, summary, rationale, title, evidence_summary) VALUES (?, ?, ?, ?, ?)").run(kind, summary, rationale, title, evidenceSummary);
|
|
18731
19083
|
}
|
|
18732
19084
|
function insertArchitectureLedgerSearchDoc(db, event, doc) {
|
|
19085
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18733
19086
|
db.prepare(`DELETE FROM architecture_ledger_search_fts
|
|
18734
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND doc_id = ?`).run(event.repository.storageRepositoryId,
|
|
19087
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND doc_id = ?`).run(event.repository.storageRepositoryId, workspaceKey, doc.docId);
|
|
18735
19088
|
db.prepare(`INSERT INTO architecture_ledger_search_fts
|
|
18736
19089
|
(doc_id, storage_repository_id, storage_workspace_id, target_kind, target_id, subject_id, title, summary, rationale, evidence_summary)
|
|
18737
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(doc.docId, event.repository.storageRepositoryId,
|
|
19090
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(doc.docId, event.repository.storageRepositoryId, workspaceKey, doc.targetKind, doc.targetId, doc.subjectId ?? null, doc.title ?? "", doc.summary ?? "", doc.rationale ?? "", doc.evidenceSummary ?? "");
|
|
18738
19091
|
}
|
|
18739
19092
|
function deleteArchitectureLedgerSearchDocs(db, scope, ids) {
|
|
18740
19093
|
for (const id of ids) {
|
|
18741
19094
|
db.prepare(`DELETE FROM architecture_ledger_search_fts
|
|
18742
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND (target_id = ? OR subject_id = ?)`).run(scope.repository.storageRepositoryId, scope.worktree
|
|
19095
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND (target_id = ? OR subject_id = ?)`).run(scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(scope.worktree), id, id);
|
|
18743
19096
|
}
|
|
18744
19097
|
}
|
|
18745
19098
|
function queryArchitectureLedgerSearchFts(db, input) {
|
|
@@ -18753,7 +19106,7 @@ function queryArchitectureLedgerSearchFts(db, input) {
|
|
|
18753
19106
|
WHERE storage_repository_id = ? AND storage_workspace_id = ?
|
|
18754
19107
|
AND architecture_ledger_search_fts MATCH ?
|
|
18755
19108
|
ORDER BY rank, target_kind, target_id
|
|
18756
|
-
LIMIT ?`).all(input.repository.storageRepositoryId, input.worktree
|
|
19109
|
+
LIMIT ?`).all(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), matchQuery, limit);
|
|
18757
19110
|
return rows.map((row) => {
|
|
18758
19111
|
const title = String(row.title ?? "");
|
|
18759
19112
|
const summary = String(row.summary ?? "");
|
|
@@ -18797,7 +19150,7 @@ function ftsMatchKind(query, doc) {
|
|
|
18797
19150
|
function recordArchitectureLedgerOperation(db, input) {
|
|
18798
19151
|
db.prepare(`INSERT INTO architecture_ledger_operations
|
|
18799
19152
|
(operation_id, storage_repository_id, storage_workspace_id, operation_kind, duration_ms, row_count, rebuild_reason, created_at)
|
|
18800
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(`ledger_operation_${randomUUID2()}`, input.scope.repository.storageRepositoryId, input.scope.worktree
|
|
19153
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(`ledger_operation_${randomUUID2()}`, input.scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.scope.worktree), input.operationKind, Math.max(0, Math.trunc(input.durationMs)), input.rowCount, input.rebuildReason, nowIso2());
|
|
18801
19154
|
}
|
|
18802
19155
|
function stableLedgerId(prefix, ...parts) {
|
|
18803
19156
|
return `${prefix}.${createHash6("sha256").update(parts.join("\x00")).digest("hex").slice(0, 24)}`;
|
|
@@ -18836,7 +19189,7 @@ function readAppliedLocalSqliteMigrations2(db) {
|
|
|
18836
19189
|
async function rebuildDerivedLandscapeState(store, input) {
|
|
18837
19190
|
const landscapePath = input.landscapePath ?? LANDSCAPE_FILE;
|
|
18838
19191
|
const relationsDir = input.relationsDir ?? ".archcontext/relations";
|
|
18839
|
-
const landscape = parseLandscapeFile(await readFile(
|
|
19192
|
+
const landscape = parseLandscapeFile(await readFile(resolve14(input.root, landscapePath), "utf8"), landscapePath);
|
|
18840
19193
|
const relations = await readRelationFiles(input.root, relationsDir);
|
|
18841
19194
|
const scopedRelations = relations.filter((relation) => landscape.relations.includes(relation.id));
|
|
18842
19195
|
const relationIds = new Set(relations.map((relation) => relation.id));
|
|
@@ -18863,7 +19216,7 @@ async function rebuildDerivedLandscapeState(store, input) {
|
|
|
18863
19216
|
}
|
|
18864
19217
|
async function openSqliteDatabase(databasePath) {
|
|
18865
19218
|
if (databasePath !== ":memory:")
|
|
18866
|
-
ensurePrivateDir2(
|
|
19219
|
+
ensurePrivateDir2(dirname7(databasePath));
|
|
18867
19220
|
try {
|
|
18868
19221
|
const nodeSqlite = await import("node:sqlite");
|
|
18869
19222
|
const db = new nodeSqlite.DatabaseSync(databasePath);
|
|
@@ -18884,7 +19237,7 @@ async function openSqliteDatabase(databasePath) {
|
|
|
18884
19237
|
}
|
|
18885
19238
|
function openSqliteDatabaseSync2(databasePath) {
|
|
18886
19239
|
if (databasePath !== ":memory:")
|
|
18887
|
-
ensurePrivateDir2(
|
|
19240
|
+
ensurePrivateDir2(dirname7(databasePath));
|
|
18888
19241
|
try {
|
|
18889
19242
|
const nodeSqlite = runtimeRequire2("node:sqlite");
|
|
18890
19243
|
const db2 = new nodeSqlite.DatabaseSync(databasePath);
|
|
@@ -18980,7 +19333,7 @@ function assertTrustedLegacyLocalStoreSource2(paths) {
|
|
|
18980
19333
|
if (!stat.isFile()) {
|
|
18981
19334
|
throw new Error(`Legacy SQLite source must be a regular file: ${paths.legacyLocalStorePath}`);
|
|
18982
19335
|
}
|
|
18983
|
-
const sourceRealPath =
|
|
19336
|
+
const sourceRealPath = realpathSync7.native(paths.legacyLocalStorePath);
|
|
18984
19337
|
if (!isPathInsideOrSame2(sourceRealPath, paths.repositoryRoot)) {
|
|
18985
19338
|
throw new Error(`Legacy SQLite source must stay inside the repository root: ${paths.legacyLocalStorePath}`);
|
|
18986
19339
|
}
|
|
@@ -19034,12 +19387,12 @@ function sqliteStringLiteral2(value) {
|
|
|
19034
19387
|
function publishStagedLocalStore2(stagingPath, targetPath) {
|
|
19035
19388
|
for (const suffix of SQLITE_SIDECAR_SUFFIXES2) {
|
|
19036
19389
|
const path = `${targetPath}${suffix}`;
|
|
19037
|
-
if (
|
|
19390
|
+
if (existsSync11(path))
|
|
19038
19391
|
throw new Error(`Cannot publish migrated SQLite over existing target file: ${path}`);
|
|
19039
19392
|
}
|
|
19040
19393
|
renameSync3(stagingPath, targetPath);
|
|
19041
19394
|
makePrivateFile2(targetPath);
|
|
19042
|
-
fsyncDirectory3(
|
|
19395
|
+
fsyncDirectory3(dirname7(targetPath));
|
|
19043
19396
|
}
|
|
19044
19397
|
function writeLegacyMigrationMarker2(paths, integrityCheck, quarantinedFiles) {
|
|
19045
19398
|
const markerPath = legacyMigrationMarkerPath2(paths);
|
|
@@ -19055,7 +19408,7 @@ function writeLegacyMigrationMarker2(paths, integrityCheck, quarantinedFiles) {
|
|
|
19055
19408
|
}
|
|
19056
19409
|
function acquireLegacyMigrationLock2(paths) {
|
|
19057
19410
|
const lockPath = legacyMigrationLockPath2(paths);
|
|
19058
|
-
ensurePrivateDir2(
|
|
19411
|
+
ensurePrivateDir2(dirname7(lockPath));
|
|
19059
19412
|
try {
|
|
19060
19413
|
const fd = openSync4(lockPath, "wx", 384);
|
|
19061
19414
|
writeFileSync3(fd, JSON.stringify({
|
|
@@ -19084,7 +19437,7 @@ function releaseLegacyMigrationLock2(lock) {
|
|
|
19084
19437
|
}
|
|
19085
19438
|
function isStaleMigrationLock2(lockPath) {
|
|
19086
19439
|
try {
|
|
19087
|
-
const parsed = JSON.parse(
|
|
19440
|
+
const parsed = JSON.parse(readFileSync10(lockPath, "utf8"));
|
|
19088
19441
|
if (typeof parsed.pid !== "number" || parsed.pid <= 0)
|
|
19089
19442
|
return true;
|
|
19090
19443
|
return !isProcessAlive2(parsed.pid);
|
|
@@ -19106,20 +19459,20 @@ function quarantineExistingLocalStore2(paths) {
|
|
|
19106
19459
|
const quarantinedFiles = [];
|
|
19107
19460
|
for (const suffix of SQLITE_SIDECAR_SUFFIXES2) {
|
|
19108
19461
|
const source = `${paths.localStorePath}${suffix}`;
|
|
19109
|
-
if (!
|
|
19462
|
+
if (!existsSync11(source))
|
|
19110
19463
|
continue;
|
|
19111
19464
|
const target = join6(quarantineDir, `runtime.sqlite${suffix}`);
|
|
19112
19465
|
renameSync3(source, target);
|
|
19113
19466
|
quarantinedFiles.push(target);
|
|
19114
19467
|
}
|
|
19115
19468
|
const markerPath = legacyMigrationMarkerPath2(paths);
|
|
19116
|
-
if (
|
|
19469
|
+
if (existsSync11(markerPath)) {
|
|
19117
19470
|
const target = join6(quarantineDir, LEGACY_MIGRATION_MARKER_FILE2);
|
|
19118
19471
|
renameSync3(markerPath, target);
|
|
19119
19472
|
quarantinedFiles.push(target);
|
|
19120
19473
|
}
|
|
19121
19474
|
fsyncDirectory3(quarantineDir);
|
|
19122
|
-
fsyncDirectory3(
|
|
19475
|
+
fsyncDirectory3(dirname7(paths.localStorePath));
|
|
19123
19476
|
return quarantinedFiles;
|
|
19124
19477
|
}
|
|
19125
19478
|
function legacyMigrationMarkerPath2(paths) {
|
|
@@ -19129,7 +19482,7 @@ function legacyMigrationLockPath2(paths) {
|
|
|
19129
19482
|
return join6(paths.workspaceStateDir, LEGACY_MIGRATION_LOCK_FILE2);
|
|
19130
19483
|
}
|
|
19131
19484
|
function writePrivateJson2(path, value) {
|
|
19132
|
-
ensurePrivateDir2(
|
|
19485
|
+
ensurePrivateDir2(dirname7(path));
|
|
19133
19486
|
const fd = openSync4(path, "w", 384);
|
|
19134
19487
|
try {
|
|
19135
19488
|
writeFileSync3(fd, JSON.stringify(value, null, 2), "utf8");
|
|
@@ -19138,7 +19491,7 @@ function writePrivateJson2(path, value) {
|
|
|
19138
19491
|
closeSync4(fd);
|
|
19139
19492
|
}
|
|
19140
19493
|
makePrivateFile2(path);
|
|
19141
|
-
fsyncDirectory3(
|
|
19494
|
+
fsyncDirectory3(dirname7(path));
|
|
19142
19495
|
}
|
|
19143
19496
|
function ensurePrivateDir2(path) {
|
|
19144
19497
|
mkdirSync5(path, { recursive: true, mode: 448 });
|
|
@@ -19168,19 +19521,19 @@ function readGitPath2(root, args) {
|
|
|
19168
19521
|
}
|
|
19169
19522
|
}
|
|
19170
19523
|
function resolveMaybeRelative2(base, path) {
|
|
19171
|
-
return isAbsolute4(path) ?
|
|
19524
|
+
return isAbsolute4(path) ? resolve14(path) : resolve14(base, path);
|
|
19172
19525
|
}
|
|
19173
19526
|
function canonicalPath2(path) {
|
|
19174
|
-
const resolved =
|
|
19527
|
+
const resolved = resolve14(path);
|
|
19175
19528
|
try {
|
|
19176
|
-
return
|
|
19529
|
+
return realpathSync7.native(resolved);
|
|
19177
19530
|
} catch {
|
|
19178
19531
|
return resolved;
|
|
19179
19532
|
}
|
|
19180
19533
|
}
|
|
19181
19534
|
function isPathInsideOrSame2(path, parent) {
|
|
19182
|
-
const child =
|
|
19183
|
-
const base =
|
|
19535
|
+
const child = resolve14(path);
|
|
19536
|
+
const base = resolve14(parent);
|
|
19184
19537
|
const fromBase = relative7(base, child);
|
|
19185
19538
|
return fromBase === "" || !!fromBase && !fromBase.startsWith("..") && !isAbsolute4(fromBase);
|
|
19186
19539
|
}
|
|
@@ -19363,32 +19716,40 @@ function changeSetLedgerAppendSummary(result) {
|
|
|
19363
19716
|
}
|
|
19364
19717
|
function changeSetJournalPlannedLedgerEvent(metadata) {
|
|
19365
19718
|
const architectureLedger = metadata.architectureLedger;
|
|
19366
|
-
if (
|
|
19719
|
+
if (architectureLedger === undefined)
|
|
19367
19720
|
return;
|
|
19721
|
+
if (!isJsonRecord(architectureLedger))
|
|
19722
|
+
throw new Error("changeset-ledger-recovery-metadata-malformed");
|
|
19368
19723
|
const plannedEvent = architectureLedger.plannedEvent;
|
|
19369
|
-
if (
|
|
19724
|
+
if (plannedEvent === undefined)
|
|
19370
19725
|
return;
|
|
19726
|
+
if (!isJsonRecord(plannedEvent))
|
|
19727
|
+
throw new Error("changeset-ledger-recovery-planned-event-malformed");
|
|
19728
|
+
const event = plannedEvent;
|
|
19371
19729
|
try {
|
|
19372
|
-
const event = plannedEvent;
|
|
19373
19730
|
validateArchitectureLedgerEvent(event);
|
|
19374
|
-
|
|
19375
|
-
|
|
19376
|
-
return;
|
|
19731
|
+
} catch (error) {
|
|
19732
|
+
throw new Error(`changeset-ledger-recovery-planned-event-invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
19377
19733
|
}
|
|
19734
|
+
return event;
|
|
19378
19735
|
}
|
|
19379
19736
|
function isJsonRecord(value) {
|
|
19380
19737
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19381
19738
|
}
|
|
19382
19739
|
function recoverJournalFiles(root, files) {
|
|
19383
19740
|
for (const file of [...files].reverse()) {
|
|
19384
|
-
const absolute =
|
|
19741
|
+
const absolute = resolve14(root, file.path);
|
|
19385
19742
|
if (file.tempPath)
|
|
19386
19743
|
rmSync5(file.tempPath, { recursive: true, force: true });
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19744
|
+
if (file.existed) {
|
|
19745
|
+
if (file.backupPath && existsSync11(file.backupPath)) {
|
|
19746
|
+
rmSync5(absolute, { recursive: true, force: true });
|
|
19747
|
+
renameSync3(file.backupPath, absolute);
|
|
19748
|
+
}
|
|
19749
|
+
} else {
|
|
19750
|
+
rmSync5(absolute, { recursive: true, force: true });
|
|
19390
19751
|
}
|
|
19391
|
-
fsyncDirectory3(
|
|
19752
|
+
fsyncDirectory3(dirname7(absolute));
|
|
19392
19753
|
}
|
|
19393
19754
|
}
|
|
19394
19755
|
function cleanupCommittedJournalFiles(files) {
|
|
@@ -19425,7 +19786,7 @@ function reviewTaskSessionId(result) {
|
|
|
19425
19786
|
async function readRelationFiles(root, relationsDir) {
|
|
19426
19787
|
let entries;
|
|
19427
19788
|
try {
|
|
19428
|
-
entries = await readdir(
|
|
19789
|
+
entries = await readdir(resolve14(root, relationsDir), { withFileTypes: true });
|
|
19429
19790
|
} catch (error) {
|
|
19430
19791
|
if (error.code === "ENOENT")
|
|
19431
19792
|
return [];
|
|
@@ -19436,15 +19797,25 @@ async function readRelationFiles(root, relationsDir) {
|
|
|
19436
19797
|
if (!entry.isFile() || !/\.(json|ya?ml)$/.test(entry.name))
|
|
19437
19798
|
continue;
|
|
19438
19799
|
const relativePath = join6(relationsDir, entry.name).split("\\").join("/");
|
|
19439
|
-
relations.push(parseCrossRepoRelationFile(await readFile(
|
|
19800
|
+
relations.push(parseCrossRepoRelationFile(await readFile(resolve14(root, relativePath), "utf8"), relativePath));
|
|
19440
19801
|
}
|
|
19441
19802
|
return relations.sort((a, b) => a.id.localeCompare(b.id));
|
|
19442
19803
|
}
|
|
19443
19804
|
|
|
19444
19805
|
// packages/local-runtime/model-store-yaml/src/index.ts
|
|
19445
19806
|
init_src();
|
|
19446
|
-
import { existsSync as
|
|
19447
|
-
import { dirname as
|
|
19807
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync7, readFileSync as readFileSync11, rmSync as rmSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
19808
|
+
import { dirname as dirname8, resolve as resolve15 } from "node:path";
|
|
19809
|
+
var GENERATED_ARCHITECTURE_PATH = ".archcontext/generated/ARCHITECTURE.md";
|
|
19810
|
+
var GENERATED_ARCHITECTURE_BODY = [
|
|
19811
|
+
"<!-- Generated by ArchContext. Do not edit by hand. -->",
|
|
19812
|
+
"",
|
|
19813
|
+
"# Architecture",
|
|
19814
|
+
"",
|
|
19815
|
+
"Model projection is generated from `.archcontext/model`.",
|
|
19816
|
+
""
|
|
19817
|
+
].join(`
|
|
19818
|
+
`);
|
|
19448
19819
|
function createDefaultManifest(productId, productName) {
|
|
19449
19820
|
return {
|
|
19450
19821
|
schemaVersion: "archcontext.manifest/v1",
|
|
@@ -19594,21 +19965,55 @@ function initializeArchContextModel(root, productName = "ArchContext Project") {
|
|
|
19594
19965
|
rebuildGeneratedProjection(root);
|
|
19595
19966
|
}
|
|
19596
19967
|
function rebuildGeneratedProjection(root) {
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19968
|
+
for (const operation of planGeneratedProjection(root)) {
|
|
19969
|
+
if (operation.operation === "delete_entity") {
|
|
19970
|
+
rmSync6(resolve15(root, operation.path), { force: true });
|
|
19971
|
+
} else {
|
|
19972
|
+
writeFile(root, operation.path, operation.body);
|
|
19973
|
+
}
|
|
19974
|
+
}
|
|
19975
|
+
}
|
|
19976
|
+
function planGeneratedProjection(root) {
|
|
19977
|
+
const desiredBody = GENERATED_ARCHITECTURE_BODY;
|
|
19978
|
+
const desiredAbsolute = resolve15(root, GENERATED_ARCHITECTURE_PATH);
|
|
19979
|
+
const operations = [];
|
|
19980
|
+
if (!existsSync12(desiredAbsolute) || readFileSync11(desiredAbsolute, "utf8") !== desiredBody) {
|
|
19981
|
+
operations.push({
|
|
19982
|
+
path: GENERATED_ARCHITECTURE_PATH,
|
|
19983
|
+
expectedHash: existsSync12(desiredAbsolute) ? digestJson({ body: readFileSync11(desiredAbsolute, "utf8") }) : "missing",
|
|
19984
|
+
body: desiredBody,
|
|
19985
|
+
operation: "render_projection"
|
|
19986
|
+
});
|
|
19987
|
+
}
|
|
19988
|
+
for (const path of collectGeneratedProjectionFiles(root)) {
|
|
19989
|
+
if (path === GENERATED_ARCHITECTURE_PATH)
|
|
19990
|
+
continue;
|
|
19991
|
+
const body = readFileSync11(resolve15(root, path), "utf8");
|
|
19992
|
+
operations.push({
|
|
19993
|
+
path,
|
|
19994
|
+
expectedHash: digestJson({ body }),
|
|
19995
|
+
body: "",
|
|
19996
|
+
operation: "delete_entity"
|
|
19997
|
+
});
|
|
19998
|
+
}
|
|
19999
|
+
return operations.sort((left, right) => left.path.localeCompare(right.path));
|
|
20000
|
+
}
|
|
20001
|
+
function collectGeneratedProjectionFiles(root) {
|
|
20002
|
+
const generatedRoot = ".archcontext/generated";
|
|
20003
|
+
if (!existsSync12(resolve15(root, generatedRoot)))
|
|
20004
|
+
return [];
|
|
20005
|
+
const walk = (relativeDir) => readdirSync7(resolve15(root, relativeDir), { withFileTypes: true }).flatMap((entry) => {
|
|
20006
|
+
const child = `${relativeDir}/${entry.name}`;
|
|
20007
|
+
if (entry.isDirectory())
|
|
20008
|
+
return walk(child);
|
|
20009
|
+
return entry.isFile() ? [child] : [];
|
|
20010
|
+
});
|
|
20011
|
+
return walk(generatedRoot).sort();
|
|
19607
20012
|
}
|
|
19608
20013
|
|
|
19609
20014
|
class YamlModelStore {
|
|
19610
20015
|
async loadManifest(workspace) {
|
|
19611
|
-
return
|
|
20016
|
+
return readFileSync11(resolve15(workspace.root, ".archcontext/manifest.yaml"), "utf8");
|
|
19612
20017
|
}
|
|
19613
20018
|
async loadModel(workspace) {
|
|
19614
20019
|
return listModelFiles(workspace.root);
|
|
@@ -19617,7 +20022,7 @@ class YamlModelStore {
|
|
|
19617
20022
|
const errors = [];
|
|
19618
20023
|
for (const required of [".archcontext/manifest.yaml", ".archcontext/product.yaml"]) {
|
|
19619
20024
|
try {
|
|
19620
|
-
|
|
20025
|
+
readFileSync11(resolve15(workspace.root, required), "utf8");
|
|
19621
20026
|
} catch {
|
|
19622
20027
|
errors.push(`missing ${required}`);
|
|
19623
20028
|
}
|
|
@@ -19647,7 +20052,7 @@ function listModelFiles(root) {
|
|
|
19647
20052
|
"docs/adr"
|
|
19648
20053
|
]);
|
|
19649
20054
|
return paths.map((path) => {
|
|
19650
|
-
const body =
|
|
20055
|
+
const body = readFileSync11(resolve15(root, path), "utf8");
|
|
19651
20056
|
return {
|
|
19652
20057
|
path,
|
|
19653
20058
|
body,
|
|
@@ -19659,8 +20064,8 @@ function listModelFiles(root) {
|
|
|
19659
20064
|
function collectArchContextFiles(root, entries) {
|
|
19660
20065
|
const files = [];
|
|
19661
20066
|
for (const entry of entries) {
|
|
19662
|
-
const absolute =
|
|
19663
|
-
if (!
|
|
20067
|
+
const absolute = resolve15(root, entry);
|
|
20068
|
+
if (!existsSync12(absolute))
|
|
19664
20069
|
continue;
|
|
19665
20070
|
const stat = readdirOrFile(absolute);
|
|
19666
20071
|
if (stat === "file") {
|
|
@@ -19673,7 +20078,7 @@ function collectArchContextFiles(root, entries) {
|
|
|
19673
20078
|
return [...new Set(files)].sort();
|
|
19674
20079
|
function walk(relativeDir) {
|
|
19675
20080
|
const out = [];
|
|
19676
|
-
const dir =
|
|
20081
|
+
const dir = resolve15(root, relativeDir);
|
|
19677
20082
|
for (const entry of readdirSync7(dir, { withFileTypes: true })) {
|
|
19678
20083
|
const child = `${relativeDir}/${entry.name}`;
|
|
19679
20084
|
if (entry.isDirectory())
|
|
@@ -19714,8 +20119,8 @@ function writeYaml(root, path, value) {
|
|
|
19714
20119
|
writeFile(root, path, stableYaml(value));
|
|
19715
20120
|
}
|
|
19716
20121
|
function writeFile(root, path, body) {
|
|
19717
|
-
const absolute =
|
|
19718
|
-
mkdirSync6(
|
|
20122
|
+
const absolute = resolve15(root, path);
|
|
20123
|
+
mkdirSync6(dirname8(absolute), { recursive: true });
|
|
19719
20124
|
writeFileSync4(absolute, body.endsWith(`
|
|
19720
20125
|
`) ? body : `${body}
|
|
19721
20126
|
`, "utf8");
|
|
@@ -20075,7 +20480,8 @@ class ArchitectureLedgerReadModelStore {
|
|
|
20075
20480
|
return this.fallback.writeChangeSetPreview(changeSet);
|
|
20076
20481
|
}
|
|
20077
20482
|
async loadLedgerModel(workspace) {
|
|
20078
|
-
const
|
|
20483
|
+
const scope = await this.localStore.resolveArchitectureLedgerScope(architectureLedgerScopeForWorkspace(workspace));
|
|
20484
|
+
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
20079
20485
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state).map((file) => ({
|
|
20080
20486
|
path: file.path,
|
|
20081
20487
|
body: file.body,
|
|
@@ -20159,7 +20565,7 @@ class ArchctxDaemon {
|
|
|
20159
20565
|
this.readModelStore = new ArchitectureLedgerReadModelStore(this.modelStore, this.localStore, this.architectureLedger);
|
|
20160
20566
|
this.changeSetEngine = deps.changeSetEngine ?? new ChangeSetEngine({
|
|
20161
20567
|
modelStore: this.modelStore,
|
|
20162
|
-
projection: {
|
|
20568
|
+
projection: { planGeneratedProjection },
|
|
20163
20569
|
journal: this.localStore
|
|
20164
20570
|
});
|
|
20165
20571
|
this.devicePrivateKeySigner = deps.devicePrivateKeySigner;
|
|
@@ -21108,10 +21514,10 @@ class ArchctxDaemon {
|
|
|
21108
21514
|
return errorEnvelope("practices.waive", "AC_SCHEMA_INVALID", error instanceof Error ? error.message : String(error));
|
|
21109
21515
|
}
|
|
21110
21516
|
const path = `.archcontext/waivers/${waiverId}.json`;
|
|
21111
|
-
const absolute =
|
|
21517
|
+
const absolute = resolve16(session.workspace.root, path);
|
|
21112
21518
|
const body = `${JSON.stringify(waiver, null, 2)}
|
|
21113
21519
|
`;
|
|
21114
|
-
const expectedHash =
|
|
21520
|
+
const expectedHash = existsSync13(absolute) ? digestJson({ body: readFileSync12(absolute, "utf8") }) : "missing";
|
|
21115
21521
|
const draft = this.changeSetEngine.plan({
|
|
21116
21522
|
id: input.id ?? `changeset.practice-waiver-${waiverId.replace(/[^A-Za-z0-9_-]/g, "-")}`,
|
|
21117
21523
|
base: {
|
|
@@ -21450,6 +21856,16 @@ class ArchctxDaemon {
|
|
|
21450
21856
|
const draft = this.changesets.get(input.id);
|
|
21451
21857
|
if (!draft)
|
|
21452
21858
|
throw new Error(`Unknown ChangeSet: ${input.id}`);
|
|
21859
|
+
if (draft.base.headSha !== session.workspace.headSha)
|
|
21860
|
+
throw new Error("ChangeSet HEAD changed before apply");
|
|
21861
|
+
if (draft.base.worktreeDigest !== current)
|
|
21862
|
+
throw new Error("ChangeSet worktree digest changed before apply");
|
|
21863
|
+
const currentModel = await this.readModelStore.validateModel(session.workspace);
|
|
21864
|
+
if (!currentModel.valid) {
|
|
21865
|
+
throw new Error(`ChangeSet base model is invalid: ${currentModel.errors.join("; ") || "unknown validation error"}`);
|
|
21866
|
+
}
|
|
21867
|
+
if (draft.base.modelDigest !== currentModel.modelDigest)
|
|
21868
|
+
throw new Error("ChangeSet model digest changed before apply");
|
|
21453
21869
|
const approved = input.approved ? this.changeSetEngine.approve(draft) : draft;
|
|
21454
21870
|
let ledgerAppend;
|
|
21455
21871
|
const writesLedger = architectureLedgerWriteAppendsEvents(this.architectureLedger.writeMode);
|
|
@@ -21466,6 +21882,7 @@ class ArchctxDaemon {
|
|
|
21466
21882
|
relationCount: appended.relationCount,
|
|
21467
21883
|
constraintCount: appended.constraintCount
|
|
21468
21884
|
};
|
|
21885
|
+
return { journalCommitted: Boolean(journalId) };
|
|
21469
21886
|
} : undefined
|
|
21470
21887
|
});
|
|
21471
21888
|
return okEnvelope("apply_update", {
|
|
@@ -21499,14 +21916,72 @@ class ArchctxDaemon {
|
|
|
21499
21916
|
});
|
|
21500
21917
|
if (journalId)
|
|
21501
21918
|
await this.localStore.recordChangeSetLedgerPlan(journalId, { event: plan.event });
|
|
21502
|
-
const
|
|
21503
|
-
|
|
21504
|
-
events: [plan.event]
|
|
21505
|
-
});
|
|
21506
|
-
if (journalId)
|
|
21507
|
-
await this.localStore.recordChangeSetLedgerAppend(journalId, { result });
|
|
21919
|
+
const appendInput = { writer: "runtime-daemon", events: [plan.event] };
|
|
21920
|
+
const result = journalId ? await this.localStore.appendArchitectureEventsAndCommitChangeSet(journalId, appendInput) : await this.localStore.appendArchitectureEvents(appendInput);
|
|
21508
21921
|
return result;
|
|
21509
21922
|
}
|
|
21923
|
+
async applyArchitectureProjectionChangeSet(root, input) {
|
|
21924
|
+
const session = await this.openSession(root);
|
|
21925
|
+
const model = await this.modelStore.validateModel(session.workspace);
|
|
21926
|
+
if (!model.valid)
|
|
21927
|
+
throw new Error(`Architecture projection ChangeSet base model is invalid: ${model.errors.join("; ")}`);
|
|
21928
|
+
const projectionFiles = input.files.map((file) => ({
|
|
21929
|
+
path: file.path,
|
|
21930
|
+
body: file.body.endsWith(`
|
|
21931
|
+
`) ? file.body : `${file.body}
|
|
21932
|
+
`,
|
|
21933
|
+
expectedHash: expectedFileHash(root, file.path)
|
|
21934
|
+
}));
|
|
21935
|
+
const operations = [
|
|
21936
|
+
...projectionFiles.length > 0 ? [{ op: "render_projection", expectedHash: "missing", projectionFiles }] : [],
|
|
21937
|
+
...input.removedPaths.map((path) => ({
|
|
21938
|
+
op: "delete_entity",
|
|
21939
|
+
path,
|
|
21940
|
+
expectedHash: expectedFileHash(root, path)
|
|
21941
|
+
}))
|
|
21942
|
+
];
|
|
21943
|
+
const draft = this.changeSetEngine.approve(this.changeSetEngine.plan({
|
|
21944
|
+
id: input.id,
|
|
21945
|
+
base: {
|
|
21946
|
+
headSha: session.workspace.headSha,
|
|
21947
|
+
worktreeDigest: session.snapshot.worktreeDigest,
|
|
21948
|
+
modelDigest: model.modelDigest
|
|
21949
|
+
},
|
|
21950
|
+
reason: { taskSessionId: input.id },
|
|
21951
|
+
operations
|
|
21952
|
+
}));
|
|
21953
|
+
await this.changeSetEngine.apply(root, draft, { approved: true });
|
|
21954
|
+
}
|
|
21955
|
+
async applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentFiles, createdAt) {
|
|
21956
|
+
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
21957
|
+
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment(createdAt)}`;
|
|
21958
|
+
const backupRelativePath = uniqueBackupPath(root, backupBase);
|
|
21959
|
+
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
21960
|
+
const { backup, manifest } = architectureProjectionRollbackBackup(currentFiles, {
|
|
21961
|
+
createdAt,
|
|
21962
|
+
path: backupRelativePath,
|
|
21963
|
+
manifestPath
|
|
21964
|
+
});
|
|
21965
|
+
const removedPaths = currentFiles.filter((file) => !targetPaths.has(file.path)).map((file) => file.path);
|
|
21966
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
21967
|
+
id: `changeset.ledger-rollback-${shortDigest3(digestJson({ createdAt, projectionDigest: architectureLedgerProjectionDigest(projectedFiles) }))}`,
|
|
21968
|
+
files: [
|
|
21969
|
+
...currentFiles.map((file) => ({
|
|
21970
|
+
path: join8(backupRelativePath, archContextRelativePath(file.path)),
|
|
21971
|
+
body: file.body
|
|
21972
|
+
})),
|
|
21973
|
+
{ path: manifestPath, body: `${JSON.stringify(manifest, null, 2)}
|
|
21974
|
+
` },
|
|
21975
|
+
...projectedFiles.map(({ path, body }) => ({ path, body }))
|
|
21976
|
+
],
|
|
21977
|
+
removedPaths
|
|
21978
|
+
});
|
|
21979
|
+
return {
|
|
21980
|
+
backup,
|
|
21981
|
+
writtenPaths: projectedFiles.map((file) => file.path),
|
|
21982
|
+
removedPaths
|
|
21983
|
+
};
|
|
21984
|
+
}
|
|
21510
21985
|
async ledgerState(root) {
|
|
21511
21986
|
this.assertRunning();
|
|
21512
21987
|
return okEnvelope("ledger.state", await this.architectureLedgerReadback(root));
|
|
@@ -21860,8 +22335,13 @@ class ArchctxDaemon {
|
|
|
21860
22335
|
const scope = await this.architectureLedgerScope(root);
|
|
21861
22336
|
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
21862
22337
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
21863
|
-
if (writes)
|
|
21864
|
-
|
|
22338
|
+
if (writes) {
|
|
22339
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
22340
|
+
id: `changeset.ledger-project-${shortDigest3(architectureLedgerProjectionDigest(projectedFiles))}`,
|
|
22341
|
+
files: projectedFiles.map(({ path, body }) => ({ path, body })),
|
|
22342
|
+
removedPaths: []
|
|
22343
|
+
});
|
|
22344
|
+
}
|
|
21865
22345
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
21866
22346
|
state,
|
|
21867
22347
|
files: listModelFiles(root),
|
|
@@ -22011,7 +22491,7 @@ class ArchctxDaemon {
|
|
|
22011
22491
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
22012
22492
|
const currentManagedFiles = listModelFiles(root).filter((file) => isArchitectureLedgerManagedModelPath(file.path));
|
|
22013
22493
|
const backupPlan = architectureProjectionRollbackBackup(currentManagedFiles);
|
|
22014
|
-
const writeResult = writes ?
|
|
22494
|
+
const writeResult = writes ? await this.applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentManagedFiles, this.clock()) : { backup: backupPlan.backup, writtenPaths: [], removedPaths: [] };
|
|
22015
22495
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
22016
22496
|
state,
|
|
22017
22497
|
files: listModelFiles(root),
|
|
@@ -22050,9 +22530,12 @@ class ArchctxDaemon {
|
|
|
22050
22530
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild currently requires --from-git");
|
|
22051
22531
|
return this.withWriter(async () => {
|
|
22052
22532
|
this.assertFreshWorktree(root, input.expectedWorktreeDigest, "ledger rebuild --from-git");
|
|
22053
|
-
const scope = await this.
|
|
22533
|
+
const scope = await this.architectureLedgerGitScope(root);
|
|
22054
22534
|
const files = listModelFiles(root);
|
|
22055
|
-
const
|
|
22535
|
+
const exactReplay = await this.localStore.replayArchitectureLedger(scope);
|
|
22536
|
+
const exactScopeHasEvents = exactReplay.events.length > 0;
|
|
22537
|
+
const authorityScope = exactScopeHasEvents ? scope : await this.localStore.resolveLatestArchitectureLedgerScope(scope);
|
|
22538
|
+
const previousState = exactScopeHasEvents ? exactReplay.state : await this.localStore.readArchitectureLedgerState(authorityScope);
|
|
22056
22539
|
const previousGraphDigest = architectureLedgerStateDigest(previousState);
|
|
22057
22540
|
const rebuildCommand = input.acceptExternalProjection ? "archctx ledger rebuild --from-git --accept-external-projection" : "archctx ledger rebuild --from-git";
|
|
22058
22541
|
const plan = planYamlToArchitectureLedgerRebuild({
|
|
@@ -22062,12 +22545,18 @@ class ArchctxDaemon {
|
|
|
22062
22545
|
command: rebuildCommand,
|
|
22063
22546
|
previousState
|
|
22064
22547
|
});
|
|
22548
|
+
const importPlan = planYamlToArchitectureLedgerImport({
|
|
22549
|
+
...scope,
|
|
22550
|
+
files,
|
|
22551
|
+
createdAt: this.clock(),
|
|
22552
|
+
command: rebuildCommand
|
|
22553
|
+
});
|
|
22065
22554
|
if (plan.unsupportedFiles.length > 0) {
|
|
22066
22555
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild requires supported YAML model files");
|
|
22067
22556
|
}
|
|
22068
22557
|
const cursor = architectureLedgerGitCursorFromPlan({ ...scope, plan });
|
|
22069
22558
|
const previousCursor = await this.localStore.readArchitectureLedgerSourceCursor({
|
|
22070
|
-
...
|
|
22559
|
+
...authorityScope,
|
|
22071
22560
|
cursorId: ARCHITECTURE_LEDGER_GIT_CURSOR_ID
|
|
22072
22561
|
});
|
|
22073
22562
|
const cursorChanged = previousCursor?.cursorDigest !== cursor.cursorDigest;
|
|
@@ -22083,7 +22572,13 @@ class ArchctxDaemon {
|
|
|
22083
22572
|
let rebuildStatus = "unchanged";
|
|
22084
22573
|
let proposedExternalProjectionChange;
|
|
22085
22574
|
if (previousGraphDigest === plan.graphDigest) {
|
|
22086
|
-
if (
|
|
22575
|
+
if (!exactScopeHasEvents) {
|
|
22576
|
+
append = await this.localStore.appendArchitectureEvents({
|
|
22577
|
+
writer: "runtime-daemon",
|
|
22578
|
+
events: [importPlan.event]
|
|
22579
|
+
});
|
|
22580
|
+
rebuildStatus = isEmptyArchitectureLedgerState(previousState) ? "rebuilt" : "cursor-refreshed";
|
|
22581
|
+
} else if (cursorChanged) {
|
|
22087
22582
|
const cursorPlan = planGitCursorRefreshToArchitectureLedgerEvent({
|
|
22088
22583
|
...scope,
|
|
22089
22584
|
cursor,
|
|
@@ -22099,7 +22594,7 @@ class ArchctxDaemon {
|
|
|
22099
22594
|
}
|
|
22100
22595
|
} else if (!previousStateEmpty && !input.acceptExternalProjection) {
|
|
22101
22596
|
const proposal = planExternalProjectionChangeToArchitectureLedgerEvent({
|
|
22102
|
-
...
|
|
22597
|
+
...authorityScope,
|
|
22103
22598
|
files,
|
|
22104
22599
|
createdAt: this.clock(),
|
|
22105
22600
|
command: rebuildCommand,
|
|
@@ -22122,11 +22617,12 @@ class ArchctxDaemon {
|
|
|
22122
22617
|
} else {
|
|
22123
22618
|
append = await this.localStore.appendArchitectureEvents({
|
|
22124
22619
|
writer: "runtime-daemon",
|
|
22125
|
-
events: [plan.event]
|
|
22620
|
+
events: [exactScopeHasEvents ? plan.event : importPlan.event]
|
|
22126
22621
|
});
|
|
22127
22622
|
rebuildStatus = previousStateEmpty ? "rebuilt" : "external-projection-accepted";
|
|
22128
22623
|
}
|
|
22129
|
-
const
|
|
22624
|
+
const replayScope = rebuildStatus === "external-projection-proposed" ? authorityScope : scope;
|
|
22625
|
+
const replay = await this.localStore.rebuildArchitectureLedgerCurrentState(replayScope);
|
|
22130
22626
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
22131
22627
|
state: replay.state,
|
|
22132
22628
|
files: listModelFiles(root),
|
|
@@ -22272,6 +22768,9 @@ class ArchctxDaemon {
|
|
|
22272
22768
|
return this.running ? this.architectureLedgerContextPort(root) : undefined;
|
|
22273
22769
|
}
|
|
22274
22770
|
async architectureLedgerScope(root) {
|
|
22771
|
+
return this.localStore.resolveArchitectureLedgerScope(await this.architectureLedgerGitScope(root));
|
|
22772
|
+
}
|
|
22773
|
+
async architectureLedgerGitScope(root) {
|
|
22275
22774
|
const session = await this.openSession(root);
|
|
22276
22775
|
const paths = runtimeStatePaths2(root);
|
|
22277
22776
|
return {
|
|
@@ -22334,7 +22833,7 @@ class ArchctxDaemon {
|
|
|
22334
22833
|
cleanup: "remove-run-root"
|
|
22335
22834
|
}
|
|
22336
22835
|
};
|
|
22337
|
-
if (
|
|
22836
|
+
if (existsSync13(paths.lockPath) || existsSync13(paths.manifestPath)) {
|
|
22338
22837
|
removePathWithRetry(paths.runRoot);
|
|
22339
22838
|
throw new Error(`developer-review-run-already-active: ${input.challenge.challengeId}`);
|
|
22340
22839
|
}
|
|
@@ -22391,7 +22890,7 @@ class ArchctxDaemon {
|
|
|
22391
22890
|
const errors = [];
|
|
22392
22891
|
if (run.worktree) {
|
|
22393
22892
|
try {
|
|
22394
|
-
const hadWorktree =
|
|
22893
|
+
const hadWorktree = existsSync13(run.worktree.worktreeRoot);
|
|
22395
22894
|
removeDetachedReviewWorktree(run.worktree);
|
|
22396
22895
|
if (hadWorktree)
|
|
22397
22896
|
removed.push("worktree");
|
|
@@ -22405,7 +22904,7 @@ class ArchctxDaemon {
|
|
|
22405
22904
|
["lock", run.lockPath]
|
|
22406
22905
|
]) {
|
|
22407
22906
|
try {
|
|
22408
|
-
const existed =
|
|
22907
|
+
const existed = existsSync13(path);
|
|
22409
22908
|
removePathWithRetry(path);
|
|
22410
22909
|
if (existed)
|
|
22411
22910
|
removed.push(kind);
|
|
@@ -22425,7 +22924,7 @@ class ArchctxDaemon {
|
|
|
22425
22924
|
recoverDeveloperReviewRuns(input) {
|
|
22426
22925
|
this.assertRunning();
|
|
22427
22926
|
const sourceRoot = findRepositoryRoot2(input.repositoryRoot);
|
|
22428
|
-
const stateDir = input.stateDir ?
|
|
22927
|
+
const stateDir = input.stateDir ? resolve16(input.stateDir) : defaultDeveloperReviewRunStateDir(sourceRoot);
|
|
22429
22928
|
const recovery = {
|
|
22430
22929
|
schemaVersion: "archcontext.developer-review-run-recovery/v1",
|
|
22431
22930
|
sourceRoot,
|
|
@@ -22434,7 +22933,7 @@ class ArchctxDaemon {
|
|
|
22434
22933
|
removedLocks: [],
|
|
22435
22934
|
skippedActive: []
|
|
22436
22935
|
};
|
|
22437
|
-
if (!
|
|
22936
|
+
if (!existsSync13(stateDir))
|
|
22438
22937
|
return recovery;
|
|
22439
22938
|
for (const entry of readdirSync8(stateDir).sort()) {
|
|
22440
22939
|
if (!entry.endsWith(".json"))
|
|
@@ -22802,7 +23301,7 @@ class ArchctxDaemon {
|
|
|
22802
23301
|
}
|
|
22803
23302
|
async restoreRepositorySessions() {
|
|
22804
23303
|
for (const record of await this.localStore.listRepositorySessions()) {
|
|
22805
|
-
if (!record.root || !
|
|
23304
|
+
if (!record.root || !existsSync13(record.root))
|
|
22806
23305
|
continue;
|
|
22807
23306
|
if (repositoryFingerprint2(record.root) !== record.repositoryId)
|
|
22808
23307
|
continue;
|
|
@@ -23229,8 +23728,8 @@ class ArchctxRuntimeRpcServer {
|
|
|
23229
23728
|
const root = this.options.root ?? process.cwd();
|
|
23230
23729
|
const connectionPath = this.options.connectionPath ?? defaultDaemonConnectionPath(root);
|
|
23231
23730
|
const lockPath = this.options.lockPath ?? defaultDaemonLockPath(root);
|
|
23232
|
-
mkdirSync7(
|
|
23233
|
-
mkdirSync7(
|
|
23731
|
+
mkdirSync7(dirname9(connectionPath), { recursive: true });
|
|
23732
|
+
mkdirSync7(dirname9(lockPath), { recursive: true });
|
|
23234
23733
|
this.lockFd = acquireDaemonLock(lockPath, root);
|
|
23235
23734
|
const token = this.options.token ?? randomBytes(18).toString("base64url");
|
|
23236
23735
|
const server = createServer((request, response) => {
|
|
@@ -23535,7 +24034,7 @@ function readRuntimeRpcConnectionFile(root = process.cwd()) {
|
|
|
23535
24034
|
try {
|
|
23536
24035
|
if (!isPrivateControlFile(path))
|
|
23537
24036
|
return;
|
|
23538
|
-
const parsed = JSON.parse(
|
|
24037
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
23539
24038
|
if (!parsed || typeof parsed !== "object")
|
|
23540
24039
|
return;
|
|
23541
24040
|
return {
|
|
@@ -23576,7 +24075,7 @@ function readRuntimeRpcConnection(root = process.cwd()) {
|
|
|
23576
24075
|
try {
|
|
23577
24076
|
if (!isPrivateControlFile(path))
|
|
23578
24077
|
return;
|
|
23579
|
-
const parsed = JSON.parse(
|
|
24078
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
23580
24079
|
return isValidRuntimeRpcConnection(parsed) ? parsed : undefined;
|
|
23581
24080
|
} catch {
|
|
23582
24081
|
return;
|
|
@@ -23595,7 +24094,7 @@ function recoverStaleDaemonControlFiles(root = process.cwd(), options = {}) {
|
|
|
23595
24094
|
rmSync8(connectionPath, { force: true });
|
|
23596
24095
|
removed.push(connectionReason);
|
|
23597
24096
|
}
|
|
23598
|
-
if (
|
|
24097
|
+
if (existsSync13(lockPath) && isStaleLock(lockPath)) {
|
|
23599
24098
|
rmSync8(lockPath, { force: true });
|
|
23600
24099
|
removed.push("stale-lock-file");
|
|
23601
24100
|
}
|
|
@@ -23854,8 +24353,8 @@ function schemaVersionKind(schemaVersion) {
|
|
|
23854
24353
|
function createDeveloperReviewRunPaths(input) {
|
|
23855
24354
|
const safeChallengeId = safeControlFileSegment(input.challengeId);
|
|
23856
24355
|
const runId = `${safeChallengeId}-${randomBytes(6).toString("hex")}`;
|
|
23857
|
-
const stateDir = input.stateDir ?
|
|
23858
|
-
const tempParent = input.tempRoot ?
|
|
24356
|
+
const stateDir = input.stateDir ? resolve16(input.stateDir) : defaultDeveloperReviewRunStateDir(input.sourceRoot);
|
|
24357
|
+
const tempParent = input.tempRoot ? resolve16(input.tempRoot) : tmpdir3();
|
|
23859
24358
|
mkdirSync7(tempParent, { recursive: true });
|
|
23860
24359
|
const runRoot = mkdtempSync4(join8(tempParent, `archctx-developer-review-${safeChallengeId.slice(0, 32)}-`));
|
|
23861
24360
|
return {
|
|
@@ -24001,7 +24500,7 @@ function readExactPackageVersion(root, packageName) {
|
|
|
24001
24500
|
return;
|
|
24002
24501
|
}
|
|
24003
24502
|
function readPackageLockExactVersion(root, packageName) {
|
|
24004
|
-
const lock = readJsonFile(
|
|
24503
|
+
const lock = readJsonFile(resolve16(root, "package-lock.json"));
|
|
24005
24504
|
if (!lock || typeof lock !== "object" || Array.isArray(lock))
|
|
24006
24505
|
return;
|
|
24007
24506
|
const packages = lock.packages;
|
|
@@ -24019,7 +24518,7 @@ function readPackageLockExactVersion(root, packageName) {
|
|
|
24019
24518
|
return;
|
|
24020
24519
|
}
|
|
24021
24520
|
function packageManifestPaths(root) {
|
|
24022
|
-
const paths = [
|
|
24521
|
+
const paths = [resolve16(root, "package.json")];
|
|
24023
24522
|
const rootManifest = readJsonFile(paths[0]);
|
|
24024
24523
|
for (const pattern of workspacePatternsFromManifest(rootManifest)) {
|
|
24025
24524
|
for (const path of expandWorkspacePackageJson(root, pattern))
|
|
@@ -24042,15 +24541,15 @@ function expandWorkspacePackageJson(root, pattern) {
|
|
|
24042
24541
|
if (pattern.includes("**") || pattern.startsWith("/") || pattern.includes("\\"))
|
|
24043
24542
|
return [];
|
|
24044
24543
|
if (!pattern.includes("*")) {
|
|
24045
|
-
const path =
|
|
24046
|
-
return
|
|
24544
|
+
const path = resolve16(root, pattern, "package.json");
|
|
24545
|
+
return existsSync13(path) ? [path] : [];
|
|
24047
24546
|
}
|
|
24048
24547
|
if (!pattern.endsWith("/*"))
|
|
24049
24548
|
return [];
|
|
24050
|
-
const base =
|
|
24051
|
-
if (!
|
|
24549
|
+
const base = resolve16(root, pattern.slice(0, -2));
|
|
24550
|
+
if (!existsSync13(base) || !statSync6(base).isDirectory())
|
|
24052
24551
|
return [];
|
|
24053
|
-
return readdirSync8(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
24552
|
+
return readdirSync8(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve16(base, entry.name, "package.json")).filter((path) => existsSync13(path));
|
|
24054
24553
|
}
|
|
24055
24554
|
function exactVersionFromManifest(manifest, packageName) {
|
|
24056
24555
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest))
|
|
@@ -24066,10 +24565,10 @@ function exactVersionFromManifest(manifest, packageName) {
|
|
|
24066
24565
|
return;
|
|
24067
24566
|
}
|
|
24068
24567
|
function readJsonFile(path) {
|
|
24069
|
-
if (!
|
|
24568
|
+
if (!existsSync13(path))
|
|
24070
24569
|
return;
|
|
24071
24570
|
try {
|
|
24072
|
-
return JSON.parse(
|
|
24571
|
+
return JSON.parse(readFileSync12(path, "utf8"));
|
|
24073
24572
|
} catch {
|
|
24074
24573
|
return;
|
|
24075
24574
|
}
|
|
@@ -24078,15 +24577,15 @@ function isExactPackageVersion(value) {
|
|
|
24078
24577
|
return /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(value);
|
|
24079
24578
|
}
|
|
24080
24579
|
function readContext7Lockfile(root) {
|
|
24081
|
-
const path =
|
|
24082
|
-
if (!
|
|
24580
|
+
const path = resolve16(root, CONTEXT7_LOCKFILE);
|
|
24581
|
+
if (!existsSync13(path)) {
|
|
24083
24582
|
return {
|
|
24084
24583
|
schemaVersion: CONTEXT7_LOCKFILE_SCHEMA_VERSION,
|
|
24085
24584
|
provider: "context7",
|
|
24086
24585
|
libraries: []
|
|
24087
24586
|
};
|
|
24088
24587
|
}
|
|
24089
|
-
const parsed = JSON.parse(
|
|
24588
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
24090
24589
|
if (parsed.schemaVersion !== CONTEXT7_LOCKFILE_SCHEMA_VERSION || parsed.provider !== "context7" || !Array.isArray(parsed.libraries)) {
|
|
24091
24590
|
throw new Error("Invalid Context7 lockfile");
|
|
24092
24591
|
}
|
|
@@ -24107,13 +24606,13 @@ function upsertContext7Pin(lock, pin) {
|
|
|
24107
24606
|
};
|
|
24108
24607
|
}
|
|
24109
24608
|
function writeContext7Lockfile(root, lock) {
|
|
24110
|
-
writePrivateJson3(
|
|
24609
|
+
writePrivateJson3(resolve16(root, CONTEXT7_LOCKFILE), lock);
|
|
24111
24610
|
}
|
|
24112
24611
|
function writeDeveloperReviewRunManifest(manifest) {
|
|
24113
24612
|
writePrivateJson3(manifest.manifestPath, manifest);
|
|
24114
24613
|
}
|
|
24115
24614
|
function writePrivateJson3(path, value, flag = "w") {
|
|
24116
|
-
mkdirSync7(
|
|
24615
|
+
mkdirSync7(dirname9(path), { recursive: true });
|
|
24117
24616
|
writeFileSync6(path, JSON.stringify(value, null, 2), { mode: 384, flag });
|
|
24118
24617
|
chmodSync3(path, 384);
|
|
24119
24618
|
}
|
|
@@ -24137,7 +24636,7 @@ function readDeveloperReviewRunManifest(path) {
|
|
|
24137
24636
|
}
|
|
24138
24637
|
function readJsonObject(path) {
|
|
24139
24638
|
try {
|
|
24140
|
-
const parsed = JSON.parse(
|
|
24639
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
24141
24640
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
|
|
24142
24641
|
} catch {
|
|
24143
24642
|
return;
|
|
@@ -24328,48 +24827,9 @@ function auditApproveResultPayload(runId, status, totalCount, issuedIssues) {
|
|
|
24328
24827
|
issuedIssues
|
|
24329
24828
|
};
|
|
24330
24829
|
}
|
|
24331
|
-
function
|
|
24332
|
-
|
|
24333
|
-
|
|
24334
|
-
mkdirSync7(dirname8(absolute), { recursive: true });
|
|
24335
|
-
writeFileSync6(absolute, file.body.endsWith(`
|
|
24336
|
-
`) ? file.body : `${file.body}
|
|
24337
|
-
`, "utf8");
|
|
24338
|
-
}
|
|
24339
|
-
}
|
|
24340
|
-
function replaceArchitectureProjectionFilesForYamlRollback(root, projectedFiles, currentFiles, createdAt) {
|
|
24341
|
-
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
24342
|
-
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment(createdAt)}`;
|
|
24343
|
-
const backupRelativePath = uniqueBackupPath(root, backupBase);
|
|
24344
|
-
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
24345
|
-
const { backup, manifest } = architectureProjectionRollbackBackup(currentFiles, {
|
|
24346
|
-
createdAt,
|
|
24347
|
-
path: backupRelativePath,
|
|
24348
|
-
manifestPath
|
|
24349
|
-
});
|
|
24350
|
-
for (const file of currentFiles) {
|
|
24351
|
-
const backupPath = join8(backupRelativePath, archContextRelativePath(file.path));
|
|
24352
|
-
const absolute = resolve15(root, backupPath);
|
|
24353
|
-
mkdirSync7(dirname8(absolute), { recursive: true });
|
|
24354
|
-
writeFileSync6(absolute, file.body, "utf8");
|
|
24355
|
-
}
|
|
24356
|
-
const manifestAbsolute = resolve15(root, manifestPath);
|
|
24357
|
-
mkdirSync7(dirname8(manifestAbsolute), { recursive: true });
|
|
24358
|
-
writeFileSync6(manifestAbsolute, `${JSON.stringify(manifest, null, 2)}
|
|
24359
|
-
`, "utf8");
|
|
24360
|
-
const removedPaths = [];
|
|
24361
|
-
for (const file of currentFiles) {
|
|
24362
|
-
if (targetPaths.has(file.path))
|
|
24363
|
-
continue;
|
|
24364
|
-
rmSync8(resolve15(root, file.path), { force: true });
|
|
24365
|
-
removedPaths.push(file.path);
|
|
24366
|
-
}
|
|
24367
|
-
writeArchitectureProjectionFiles(root, projectedFiles);
|
|
24368
|
-
return {
|
|
24369
|
-
backup,
|
|
24370
|
-
writtenPaths: projectedFiles.map((file) => file.path),
|
|
24371
|
-
removedPaths
|
|
24372
|
-
};
|
|
24830
|
+
function expectedFileHash(root, path) {
|
|
24831
|
+
const absolute = resolve16(root, path);
|
|
24832
|
+
return existsSync13(absolute) ? digestJson({ body: readFileSync12(absolute, "utf8") }) : "missing";
|
|
24373
24833
|
}
|
|
24374
24834
|
function architectureProjectionRollbackBackup(files, options = {}) {
|
|
24375
24835
|
const manifest = {
|
|
@@ -24396,7 +24856,7 @@ function architectureProjectionRollbackBackup(files, options = {}) {
|
|
|
24396
24856
|
function uniqueBackupPath(root, backupBase) {
|
|
24397
24857
|
let candidate = backupBase;
|
|
24398
24858
|
let suffix = 2;
|
|
24399
|
-
while (
|
|
24859
|
+
while (existsSync13(resolve16(root, candidate))) {
|
|
24400
24860
|
candidate = `${backupBase}-${suffix}`;
|
|
24401
24861
|
suffix += 1;
|
|
24402
24862
|
}
|
|
@@ -24405,7 +24865,7 @@ function uniqueBackupPath(root, backupBase) {
|
|
|
24405
24865
|
function uniqueRuntimeBackupPath(backupBase) {
|
|
24406
24866
|
let candidate = backupBase;
|
|
24407
24867
|
let suffix = 2;
|
|
24408
|
-
while (
|
|
24868
|
+
while (existsSync13(candidate)) {
|
|
24409
24869
|
candidate = backupBase.replace(/\.sqlite$/, `-${suffix}.sqlite`);
|
|
24410
24870
|
suffix += 1;
|
|
24411
24871
|
}
|
|
@@ -24450,12 +24910,12 @@ function isValidRuntimeRpcConnection(value) {
|
|
|
24450
24910
|
return value.schemaVersion === RUNTIME_RPC_VERSION && value.protocol === "http-loopback" && value.version === 1 && typeof value.url === "string" && value.url.startsWith("http://127.0.0.1:") && typeof value.token === "string" && value.token.length > 0 && typeof value.pid === "number" && typeof value.connectionPath === "string" && typeof value.lockPath === "string";
|
|
24451
24911
|
}
|
|
24452
24912
|
function staleConnectionFileReason(path, removeUnhealthyConnection) {
|
|
24453
|
-
if (!
|
|
24913
|
+
if (!existsSync13(path))
|
|
24454
24914
|
return;
|
|
24455
24915
|
try {
|
|
24456
24916
|
if (!isPrivateControlFile(path))
|
|
24457
24917
|
return "insecure-connection-file";
|
|
24458
|
-
const parsed = JSON.parse(
|
|
24918
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
24459
24919
|
if (!isValidRuntimeRpcConnection(parsed))
|
|
24460
24920
|
return "invalid-connection-file";
|
|
24461
24921
|
if (!isProcessAlive3(parsed.pid))
|
|
@@ -24473,7 +24933,7 @@ function isPrivateControlFile(path) {
|
|
|
24473
24933
|
}
|
|
24474
24934
|
function isStaleLock(lockPath) {
|
|
24475
24935
|
try {
|
|
24476
|
-
const lock = JSON.parse(
|
|
24936
|
+
const lock = JSON.parse(readFileSync12(lockPath, "utf8"));
|
|
24477
24937
|
if (typeof lock.pid !== "number" || lock.pid <= 0)
|
|
24478
24938
|
return true;
|
|
24479
24939
|
return !isProcessAlive3(lock.pid);
|
|
@@ -24512,7 +24972,7 @@ function parsePracticeCheckpointBaselineState(state, repositoryId, taskSessionId
|
|
|
24512
24972
|
return record;
|
|
24513
24973
|
}
|
|
24514
24974
|
function completeTaskProjectionDrift(root) {
|
|
24515
|
-
if (!
|
|
24975
|
+
if (!existsSync13(resolve16(root, "docs/architecture/.projection-manifest.json")))
|
|
24516
24976
|
return;
|
|
24517
24977
|
const loaded = loadArchitectureDocumentationInputs(root);
|
|
24518
24978
|
const sourceDigest = architectureDocumentationSourceDigest({
|
|
@@ -24788,10 +25248,10 @@ init_src();
|
|
|
24788
25248
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
24789
25249
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
24790
25250
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
24791
|
-
import { chmodSync as chmodSync4, closeSync as closeSync6, existsSync as
|
|
25251
|
+
import { chmodSync as chmodSync4, closeSync as closeSync6, existsSync as existsSync14, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync5, openSync as openSync6, readdirSync as readdirSync9, readFileSync as readFileSync13, rmSync as rmSync9, statSync as statSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24792
25252
|
import { createServer as createServer2 } from "node:http";
|
|
24793
25253
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
24794
|
-
import { dirname as
|
|
25254
|
+
import { dirname as dirname10, join as join9, resolve as resolve17 } from "node:path";
|
|
24795
25255
|
init_src();
|
|
24796
25256
|
var RUNTIME_AGENT_HOOK_DEFAULT_MAX_QUEUED_JOBS2 = 32;
|
|
24797
25257
|
var RUNTIME_AGENT_HOOK_DEFAULT_PRIORITY2 = 0;
|
|
@@ -24901,7 +25361,8 @@ class ArchitectureLedgerReadModelStore2 {
|
|
|
24901
25361
|
return this.fallback.writeChangeSetPreview(changeSet);
|
|
24902
25362
|
}
|
|
24903
25363
|
async loadLedgerModel(workspace) {
|
|
24904
|
-
const
|
|
25364
|
+
const scope = await this.localStore.resolveArchitectureLedgerScope(architectureLedgerScopeForWorkspace2(workspace));
|
|
25365
|
+
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
24905
25366
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state).map((file) => ({
|
|
24906
25367
|
path: file.path,
|
|
24907
25368
|
body: file.body,
|
|
@@ -24985,7 +25446,7 @@ class ArchctxDaemon2 {
|
|
|
24985
25446
|
this.readModelStore = new ArchitectureLedgerReadModelStore2(this.modelStore, this.localStore, this.architectureLedger);
|
|
24986
25447
|
this.changeSetEngine = deps.changeSetEngine ?? new ChangeSetEngine({
|
|
24987
25448
|
modelStore: this.modelStore,
|
|
24988
|
-
projection: {
|
|
25449
|
+
projection: { planGeneratedProjection },
|
|
24989
25450
|
journal: this.localStore
|
|
24990
25451
|
});
|
|
24991
25452
|
this.devicePrivateKeySigner = deps.devicePrivateKeySigner;
|
|
@@ -25934,10 +26395,10 @@ class ArchctxDaemon2 {
|
|
|
25934
26395
|
return errorEnvelope("practices.waive", "AC_SCHEMA_INVALID", error instanceof Error ? error.message : String(error));
|
|
25935
26396
|
}
|
|
25936
26397
|
const path = `.archcontext/waivers/${waiverId}.json`;
|
|
25937
|
-
const absolute =
|
|
26398
|
+
const absolute = resolve17(session.workspace.root, path);
|
|
25938
26399
|
const body = `${JSON.stringify(waiver, null, 2)}
|
|
25939
26400
|
`;
|
|
25940
|
-
const expectedHash =
|
|
26401
|
+
const expectedHash = existsSync14(absolute) ? digestJson({ body: readFileSync13(absolute, "utf8") }) : "missing";
|
|
25941
26402
|
const draft = this.changeSetEngine.plan({
|
|
25942
26403
|
id: input.id ?? `changeset.practice-waiver-${waiverId.replace(/[^A-Za-z0-9_-]/g, "-")}`,
|
|
25943
26404
|
base: {
|
|
@@ -26276,6 +26737,16 @@ class ArchctxDaemon2 {
|
|
|
26276
26737
|
const draft = this.changesets.get(input.id);
|
|
26277
26738
|
if (!draft)
|
|
26278
26739
|
throw new Error(`Unknown ChangeSet: ${input.id}`);
|
|
26740
|
+
if (draft.base.headSha !== session.workspace.headSha)
|
|
26741
|
+
throw new Error("ChangeSet HEAD changed before apply");
|
|
26742
|
+
if (draft.base.worktreeDigest !== current)
|
|
26743
|
+
throw new Error("ChangeSet worktree digest changed before apply");
|
|
26744
|
+
const currentModel = await this.readModelStore.validateModel(session.workspace);
|
|
26745
|
+
if (!currentModel.valid) {
|
|
26746
|
+
throw new Error(`ChangeSet base model is invalid: ${currentModel.errors.join("; ") || "unknown validation error"}`);
|
|
26747
|
+
}
|
|
26748
|
+
if (draft.base.modelDigest !== currentModel.modelDigest)
|
|
26749
|
+
throw new Error("ChangeSet model digest changed before apply");
|
|
26279
26750
|
const approved = input.approved ? this.changeSetEngine.approve(draft) : draft;
|
|
26280
26751
|
let ledgerAppend;
|
|
26281
26752
|
const writesLedger = architectureLedgerWriteAppendsEvents2(this.architectureLedger.writeMode);
|
|
@@ -26292,6 +26763,7 @@ class ArchctxDaemon2 {
|
|
|
26292
26763
|
relationCount: appended.relationCount,
|
|
26293
26764
|
constraintCount: appended.constraintCount
|
|
26294
26765
|
};
|
|
26766
|
+
return { journalCommitted: Boolean(journalId) };
|
|
26295
26767
|
} : undefined
|
|
26296
26768
|
});
|
|
26297
26769
|
return okEnvelope("apply_update", {
|
|
@@ -26325,14 +26797,72 @@ class ArchctxDaemon2 {
|
|
|
26325
26797
|
});
|
|
26326
26798
|
if (journalId)
|
|
26327
26799
|
await this.localStore.recordChangeSetLedgerPlan(journalId, { event: plan.event });
|
|
26328
|
-
const
|
|
26329
|
-
|
|
26330
|
-
events: [plan.event]
|
|
26331
|
-
});
|
|
26332
|
-
if (journalId)
|
|
26333
|
-
await this.localStore.recordChangeSetLedgerAppend(journalId, { result });
|
|
26800
|
+
const appendInput = { writer: "runtime-daemon", events: [plan.event] };
|
|
26801
|
+
const result = journalId ? await this.localStore.appendArchitectureEventsAndCommitChangeSet(journalId, appendInput) : await this.localStore.appendArchitectureEvents(appendInput);
|
|
26334
26802
|
return result;
|
|
26335
26803
|
}
|
|
26804
|
+
async applyArchitectureProjectionChangeSet(root, input) {
|
|
26805
|
+
const session = await this.openSession(root);
|
|
26806
|
+
const model = await this.modelStore.validateModel(session.workspace);
|
|
26807
|
+
if (!model.valid)
|
|
26808
|
+
throw new Error(`Architecture projection ChangeSet base model is invalid: ${model.errors.join("; ")}`);
|
|
26809
|
+
const projectionFiles = input.files.map((file) => ({
|
|
26810
|
+
path: file.path,
|
|
26811
|
+
body: file.body.endsWith(`
|
|
26812
|
+
`) ? file.body : `${file.body}
|
|
26813
|
+
`,
|
|
26814
|
+
expectedHash: expectedFileHash2(root, file.path)
|
|
26815
|
+
}));
|
|
26816
|
+
const operations = [
|
|
26817
|
+
...projectionFiles.length > 0 ? [{ op: "render_projection", expectedHash: "missing", projectionFiles }] : [],
|
|
26818
|
+
...input.removedPaths.map((path) => ({
|
|
26819
|
+
op: "delete_entity",
|
|
26820
|
+
path,
|
|
26821
|
+
expectedHash: expectedFileHash2(root, path)
|
|
26822
|
+
}))
|
|
26823
|
+
];
|
|
26824
|
+
const draft = this.changeSetEngine.approve(this.changeSetEngine.plan({
|
|
26825
|
+
id: input.id,
|
|
26826
|
+
base: {
|
|
26827
|
+
headSha: session.workspace.headSha,
|
|
26828
|
+
worktreeDigest: session.snapshot.worktreeDigest,
|
|
26829
|
+
modelDigest: model.modelDigest
|
|
26830
|
+
},
|
|
26831
|
+
reason: { taskSessionId: input.id },
|
|
26832
|
+
operations
|
|
26833
|
+
}));
|
|
26834
|
+
await this.changeSetEngine.apply(root, draft, { approved: true });
|
|
26835
|
+
}
|
|
26836
|
+
async applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentFiles, createdAt) {
|
|
26837
|
+
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
26838
|
+
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment2(createdAt)}`;
|
|
26839
|
+
const backupRelativePath = uniqueBackupPath2(root, backupBase);
|
|
26840
|
+
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
26841
|
+
const { backup, manifest } = architectureProjectionRollbackBackup2(currentFiles, {
|
|
26842
|
+
createdAt,
|
|
26843
|
+
path: backupRelativePath,
|
|
26844
|
+
manifestPath
|
|
26845
|
+
});
|
|
26846
|
+
const removedPaths = currentFiles.filter((file) => !targetPaths.has(file.path)).map((file) => file.path);
|
|
26847
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
26848
|
+
id: `changeset.ledger-rollback-${shortDigest4(digestJson({ createdAt, projectionDigest: architectureLedgerProjectionDigest(projectedFiles) }))}`,
|
|
26849
|
+
files: [
|
|
26850
|
+
...currentFiles.map((file) => ({
|
|
26851
|
+
path: join9(backupRelativePath, archContextRelativePath2(file.path)),
|
|
26852
|
+
body: file.body
|
|
26853
|
+
})),
|
|
26854
|
+
{ path: manifestPath, body: `${JSON.stringify(manifest, null, 2)}
|
|
26855
|
+
` },
|
|
26856
|
+
...projectedFiles.map(({ path, body }) => ({ path, body }))
|
|
26857
|
+
],
|
|
26858
|
+
removedPaths
|
|
26859
|
+
});
|
|
26860
|
+
return {
|
|
26861
|
+
backup,
|
|
26862
|
+
writtenPaths: projectedFiles.map((file) => file.path),
|
|
26863
|
+
removedPaths
|
|
26864
|
+
};
|
|
26865
|
+
}
|
|
26336
26866
|
async ledgerState(root) {
|
|
26337
26867
|
this.assertRunning();
|
|
26338
26868
|
return okEnvelope("ledger.state", await this.architectureLedgerReadback(root));
|
|
@@ -26686,8 +27216,13 @@ class ArchctxDaemon2 {
|
|
|
26686
27216
|
const scope = await this.architectureLedgerScope(root);
|
|
26687
27217
|
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
26688
27218
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
26689
|
-
if (writes)
|
|
26690
|
-
|
|
27219
|
+
if (writes) {
|
|
27220
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
27221
|
+
id: `changeset.ledger-project-${shortDigest4(architectureLedgerProjectionDigest(projectedFiles))}`,
|
|
27222
|
+
files: projectedFiles.map(({ path, body }) => ({ path, body })),
|
|
27223
|
+
removedPaths: []
|
|
27224
|
+
});
|
|
27225
|
+
}
|
|
26691
27226
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
26692
27227
|
state,
|
|
26693
27228
|
files: listModelFiles(root),
|
|
@@ -26837,7 +27372,7 @@ class ArchctxDaemon2 {
|
|
|
26837
27372
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
26838
27373
|
const currentManagedFiles = listModelFiles(root).filter((file) => isArchitectureLedgerManagedModelPath2(file.path));
|
|
26839
27374
|
const backupPlan = architectureProjectionRollbackBackup2(currentManagedFiles);
|
|
26840
|
-
const writeResult = writes ?
|
|
27375
|
+
const writeResult = writes ? await this.applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentManagedFiles, this.clock()) : { backup: backupPlan.backup, writtenPaths: [], removedPaths: [] };
|
|
26841
27376
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
26842
27377
|
state,
|
|
26843
27378
|
files: listModelFiles(root),
|
|
@@ -26876,9 +27411,12 @@ class ArchctxDaemon2 {
|
|
|
26876
27411
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild currently requires --from-git");
|
|
26877
27412
|
return this.withWriter(async () => {
|
|
26878
27413
|
this.assertFreshWorktree(root, input.expectedWorktreeDigest, "ledger rebuild --from-git");
|
|
26879
|
-
const scope = await this.
|
|
27414
|
+
const scope = await this.architectureLedgerGitScope(root);
|
|
26880
27415
|
const files = listModelFiles(root);
|
|
26881
|
-
const
|
|
27416
|
+
const exactReplay = await this.localStore.replayArchitectureLedger(scope);
|
|
27417
|
+
const exactScopeHasEvents = exactReplay.events.length > 0;
|
|
27418
|
+
const authorityScope = exactScopeHasEvents ? scope : await this.localStore.resolveLatestArchitectureLedgerScope(scope);
|
|
27419
|
+
const previousState = exactScopeHasEvents ? exactReplay.state : await this.localStore.readArchitectureLedgerState(authorityScope);
|
|
26882
27420
|
const previousGraphDigest = architectureLedgerStateDigest(previousState);
|
|
26883
27421
|
const rebuildCommand = input.acceptExternalProjection ? "archctx ledger rebuild --from-git --accept-external-projection" : "archctx ledger rebuild --from-git";
|
|
26884
27422
|
const plan = planYamlToArchitectureLedgerRebuild({
|
|
@@ -26888,12 +27426,18 @@ class ArchctxDaemon2 {
|
|
|
26888
27426
|
command: rebuildCommand,
|
|
26889
27427
|
previousState
|
|
26890
27428
|
});
|
|
27429
|
+
const importPlan = planYamlToArchitectureLedgerImport({
|
|
27430
|
+
...scope,
|
|
27431
|
+
files,
|
|
27432
|
+
createdAt: this.clock(),
|
|
27433
|
+
command: rebuildCommand
|
|
27434
|
+
});
|
|
26891
27435
|
if (plan.unsupportedFiles.length > 0) {
|
|
26892
27436
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild requires supported YAML model files");
|
|
26893
27437
|
}
|
|
26894
27438
|
const cursor = architectureLedgerGitCursorFromPlan({ ...scope, plan });
|
|
26895
27439
|
const previousCursor = await this.localStore.readArchitectureLedgerSourceCursor({
|
|
26896
|
-
...
|
|
27440
|
+
...authorityScope,
|
|
26897
27441
|
cursorId: ARCHITECTURE_LEDGER_GIT_CURSOR_ID
|
|
26898
27442
|
});
|
|
26899
27443
|
const cursorChanged = previousCursor?.cursorDigest !== cursor.cursorDigest;
|
|
@@ -26909,7 +27453,13 @@ class ArchctxDaemon2 {
|
|
|
26909
27453
|
let rebuildStatus = "unchanged";
|
|
26910
27454
|
let proposedExternalProjectionChange;
|
|
26911
27455
|
if (previousGraphDigest === plan.graphDigest) {
|
|
26912
|
-
if (
|
|
27456
|
+
if (!exactScopeHasEvents) {
|
|
27457
|
+
append = await this.localStore.appendArchitectureEvents({
|
|
27458
|
+
writer: "runtime-daemon",
|
|
27459
|
+
events: [importPlan.event]
|
|
27460
|
+
});
|
|
27461
|
+
rebuildStatus = isEmptyArchitectureLedgerState2(previousState) ? "rebuilt" : "cursor-refreshed";
|
|
27462
|
+
} else if (cursorChanged) {
|
|
26913
27463
|
const cursorPlan = planGitCursorRefreshToArchitectureLedgerEvent({
|
|
26914
27464
|
...scope,
|
|
26915
27465
|
cursor,
|
|
@@ -26925,7 +27475,7 @@ class ArchctxDaemon2 {
|
|
|
26925
27475
|
}
|
|
26926
27476
|
} else if (!previousStateEmpty && !input.acceptExternalProjection) {
|
|
26927
27477
|
const proposal = planExternalProjectionChangeToArchitectureLedgerEvent({
|
|
26928
|
-
...
|
|
27478
|
+
...authorityScope,
|
|
26929
27479
|
files,
|
|
26930
27480
|
createdAt: this.clock(),
|
|
26931
27481
|
command: rebuildCommand,
|
|
@@ -26948,11 +27498,12 @@ class ArchctxDaemon2 {
|
|
|
26948
27498
|
} else {
|
|
26949
27499
|
append = await this.localStore.appendArchitectureEvents({
|
|
26950
27500
|
writer: "runtime-daemon",
|
|
26951
|
-
events: [plan.event]
|
|
27501
|
+
events: [exactScopeHasEvents ? plan.event : importPlan.event]
|
|
26952
27502
|
});
|
|
26953
27503
|
rebuildStatus = previousStateEmpty ? "rebuilt" : "external-projection-accepted";
|
|
26954
27504
|
}
|
|
26955
|
-
const
|
|
27505
|
+
const replayScope = rebuildStatus === "external-projection-proposed" ? authorityScope : scope;
|
|
27506
|
+
const replay = await this.localStore.rebuildArchitectureLedgerCurrentState(replayScope);
|
|
26956
27507
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
26957
27508
|
state: replay.state,
|
|
26958
27509
|
files: listModelFiles(root),
|
|
@@ -27098,6 +27649,9 @@ class ArchctxDaemon2 {
|
|
|
27098
27649
|
return this.running ? this.architectureLedgerContextPort(root) : undefined;
|
|
27099
27650
|
}
|
|
27100
27651
|
async architectureLedgerScope(root) {
|
|
27652
|
+
return this.localStore.resolveArchitectureLedgerScope(await this.architectureLedgerGitScope(root));
|
|
27653
|
+
}
|
|
27654
|
+
async architectureLedgerGitScope(root) {
|
|
27101
27655
|
const session = await this.openSession(root);
|
|
27102
27656
|
const paths = runtimeStatePaths2(root);
|
|
27103
27657
|
return {
|
|
@@ -27160,7 +27714,7 @@ class ArchctxDaemon2 {
|
|
|
27160
27714
|
cleanup: "remove-run-root"
|
|
27161
27715
|
}
|
|
27162
27716
|
};
|
|
27163
|
-
if (
|
|
27717
|
+
if (existsSync14(paths.lockPath) || existsSync14(paths.manifestPath)) {
|
|
27164
27718
|
removePathWithRetry(paths.runRoot);
|
|
27165
27719
|
throw new Error(`developer-review-run-already-active: ${input.challenge.challengeId}`);
|
|
27166
27720
|
}
|
|
@@ -27217,7 +27771,7 @@ class ArchctxDaemon2 {
|
|
|
27217
27771
|
const errors = [];
|
|
27218
27772
|
if (run.worktree) {
|
|
27219
27773
|
try {
|
|
27220
|
-
const hadWorktree =
|
|
27774
|
+
const hadWorktree = existsSync14(run.worktree.worktreeRoot);
|
|
27221
27775
|
removeDetachedReviewWorktree(run.worktree);
|
|
27222
27776
|
if (hadWorktree)
|
|
27223
27777
|
removed.push("worktree");
|
|
@@ -27231,7 +27785,7 @@ class ArchctxDaemon2 {
|
|
|
27231
27785
|
["lock", run.lockPath]
|
|
27232
27786
|
]) {
|
|
27233
27787
|
try {
|
|
27234
|
-
const existed =
|
|
27788
|
+
const existed = existsSync14(path);
|
|
27235
27789
|
removePathWithRetry(path);
|
|
27236
27790
|
if (existed)
|
|
27237
27791
|
removed.push(kind);
|
|
@@ -27251,7 +27805,7 @@ class ArchctxDaemon2 {
|
|
|
27251
27805
|
recoverDeveloperReviewRuns(input) {
|
|
27252
27806
|
this.assertRunning();
|
|
27253
27807
|
const sourceRoot = findRepositoryRoot2(input.repositoryRoot);
|
|
27254
|
-
const stateDir = input.stateDir ?
|
|
27808
|
+
const stateDir = input.stateDir ? resolve17(input.stateDir) : defaultDeveloperReviewRunStateDir2(sourceRoot);
|
|
27255
27809
|
const recovery = {
|
|
27256
27810
|
schemaVersion: "archcontext.developer-review-run-recovery/v1",
|
|
27257
27811
|
sourceRoot,
|
|
@@ -27260,7 +27814,7 @@ class ArchctxDaemon2 {
|
|
|
27260
27814
|
removedLocks: [],
|
|
27261
27815
|
skippedActive: []
|
|
27262
27816
|
};
|
|
27263
|
-
if (!
|
|
27817
|
+
if (!existsSync14(stateDir))
|
|
27264
27818
|
return recovery;
|
|
27265
27819
|
for (const entry of readdirSync9(stateDir).sort()) {
|
|
27266
27820
|
if (!entry.endsWith(".json"))
|
|
@@ -27628,7 +28182,7 @@ class ArchctxDaemon2 {
|
|
|
27628
28182
|
}
|
|
27629
28183
|
async restoreRepositorySessions() {
|
|
27630
28184
|
for (const record of await this.localStore.listRepositorySessions()) {
|
|
27631
|
-
if (!record.root || !
|
|
28185
|
+
if (!record.root || !existsSync14(record.root))
|
|
27632
28186
|
continue;
|
|
27633
28187
|
if (repositoryFingerprint2(record.root) !== record.repositoryId)
|
|
27634
28188
|
continue;
|
|
@@ -28082,7 +28636,7 @@ function readRuntimeRpcConnection2(root = process.cwd()) {
|
|
|
28082
28636
|
try {
|
|
28083
28637
|
if (!isPrivateControlFile2(path))
|
|
28084
28638
|
return;
|
|
28085
|
-
const parsed = JSON.parse(
|
|
28639
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
28086
28640
|
return isValidRuntimeRpcConnection2(parsed) ? parsed : undefined;
|
|
28087
28641
|
} catch {
|
|
28088
28642
|
return;
|
|
@@ -28345,8 +28899,8 @@ function schemaVersionKind2(schemaVersion) {
|
|
|
28345
28899
|
function createDeveloperReviewRunPaths2(input) {
|
|
28346
28900
|
const safeChallengeId = safeControlFileSegment2(input.challengeId);
|
|
28347
28901
|
const runId = `${safeChallengeId}-${randomBytes2(6).toString("hex")}`;
|
|
28348
|
-
const stateDir = input.stateDir ?
|
|
28349
|
-
const tempParent = input.tempRoot ?
|
|
28902
|
+
const stateDir = input.stateDir ? resolve17(input.stateDir) : defaultDeveloperReviewRunStateDir2(input.sourceRoot);
|
|
28903
|
+
const tempParent = input.tempRoot ? resolve17(input.tempRoot) : tmpdir4();
|
|
28350
28904
|
mkdirSync8(tempParent, { recursive: true });
|
|
28351
28905
|
const runRoot = mkdtempSync5(join9(tempParent, `archctx-developer-review-${safeChallengeId.slice(0, 32)}-`));
|
|
28352
28906
|
return {
|
|
@@ -28492,7 +29046,7 @@ function readExactPackageVersion2(root, packageName) {
|
|
|
28492
29046
|
return;
|
|
28493
29047
|
}
|
|
28494
29048
|
function readPackageLockExactVersion2(root, packageName) {
|
|
28495
|
-
const lock = readJsonFile2(
|
|
29049
|
+
const lock = readJsonFile2(resolve17(root, "package-lock.json"));
|
|
28496
29050
|
if (!lock || typeof lock !== "object" || Array.isArray(lock))
|
|
28497
29051
|
return;
|
|
28498
29052
|
const packages = lock.packages;
|
|
@@ -28510,7 +29064,7 @@ function readPackageLockExactVersion2(root, packageName) {
|
|
|
28510
29064
|
return;
|
|
28511
29065
|
}
|
|
28512
29066
|
function packageManifestPaths2(root) {
|
|
28513
|
-
const paths = [
|
|
29067
|
+
const paths = [resolve17(root, "package.json")];
|
|
28514
29068
|
const rootManifest = readJsonFile2(paths[0]);
|
|
28515
29069
|
for (const pattern of workspacePatternsFromManifest2(rootManifest)) {
|
|
28516
29070
|
for (const path of expandWorkspacePackageJson2(root, pattern))
|
|
@@ -28533,15 +29087,15 @@ function expandWorkspacePackageJson2(root, pattern) {
|
|
|
28533
29087
|
if (pattern.includes("**") || pattern.startsWith("/") || pattern.includes("\\"))
|
|
28534
29088
|
return [];
|
|
28535
29089
|
if (!pattern.includes("*")) {
|
|
28536
|
-
const path =
|
|
28537
|
-
return
|
|
29090
|
+
const path = resolve17(root, pattern, "package.json");
|
|
29091
|
+
return existsSync14(path) ? [path] : [];
|
|
28538
29092
|
}
|
|
28539
29093
|
if (!pattern.endsWith("/*"))
|
|
28540
29094
|
return [];
|
|
28541
|
-
const base =
|
|
28542
|
-
if (!
|
|
29095
|
+
const base = resolve17(root, pattern.slice(0, -2));
|
|
29096
|
+
if (!existsSync14(base) || !statSync7(base).isDirectory())
|
|
28543
29097
|
return [];
|
|
28544
|
-
return readdirSync9(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
29098
|
+
return readdirSync9(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve17(base, entry.name, "package.json")).filter((path) => existsSync14(path));
|
|
28545
29099
|
}
|
|
28546
29100
|
function exactVersionFromManifest2(manifest, packageName) {
|
|
28547
29101
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest))
|
|
@@ -28557,10 +29111,10 @@ function exactVersionFromManifest2(manifest, packageName) {
|
|
|
28557
29111
|
return;
|
|
28558
29112
|
}
|
|
28559
29113
|
function readJsonFile2(path) {
|
|
28560
|
-
if (!
|
|
29114
|
+
if (!existsSync14(path))
|
|
28561
29115
|
return;
|
|
28562
29116
|
try {
|
|
28563
|
-
return JSON.parse(
|
|
29117
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
28564
29118
|
} catch {
|
|
28565
29119
|
return;
|
|
28566
29120
|
}
|
|
@@ -28569,15 +29123,15 @@ function isExactPackageVersion2(value) {
|
|
|
28569
29123
|
return /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(value);
|
|
28570
29124
|
}
|
|
28571
29125
|
function readContext7Lockfile2(root) {
|
|
28572
|
-
const path =
|
|
28573
|
-
if (!
|
|
29126
|
+
const path = resolve17(root, CONTEXT7_LOCKFILE2);
|
|
29127
|
+
if (!existsSync14(path)) {
|
|
28574
29128
|
return {
|
|
28575
29129
|
schemaVersion: CONTEXT7_LOCKFILE_SCHEMA_VERSION,
|
|
28576
29130
|
provider: "context7",
|
|
28577
29131
|
libraries: []
|
|
28578
29132
|
};
|
|
28579
29133
|
}
|
|
28580
|
-
const parsed = JSON.parse(
|
|
29134
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
28581
29135
|
if (parsed.schemaVersion !== CONTEXT7_LOCKFILE_SCHEMA_VERSION || parsed.provider !== "context7" || !Array.isArray(parsed.libraries)) {
|
|
28582
29136
|
throw new Error("Invalid Context7 lockfile");
|
|
28583
29137
|
}
|
|
@@ -28598,13 +29152,13 @@ function upsertContext7Pin2(lock, pin) {
|
|
|
28598
29152
|
};
|
|
28599
29153
|
}
|
|
28600
29154
|
function writeContext7Lockfile2(root, lock) {
|
|
28601
|
-
writePrivateJson4(
|
|
29155
|
+
writePrivateJson4(resolve17(root, CONTEXT7_LOCKFILE2), lock);
|
|
28602
29156
|
}
|
|
28603
29157
|
function writeDeveloperReviewRunManifest2(manifest) {
|
|
28604
29158
|
writePrivateJson4(manifest.manifestPath, manifest);
|
|
28605
29159
|
}
|
|
28606
29160
|
function writePrivateJson4(path, value, flag = "w") {
|
|
28607
|
-
mkdirSync8(
|
|
29161
|
+
mkdirSync8(dirname10(path), { recursive: true });
|
|
28608
29162
|
writeFileSync7(path, JSON.stringify(value, null, 2), { mode: 384, flag });
|
|
28609
29163
|
chmodSync4(path, 384);
|
|
28610
29164
|
}
|
|
@@ -28628,7 +29182,7 @@ function readDeveloperReviewRunManifest2(path) {
|
|
|
28628
29182
|
}
|
|
28629
29183
|
function readJsonObject2(path) {
|
|
28630
29184
|
try {
|
|
28631
|
-
const parsed = JSON.parse(
|
|
29185
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
28632
29186
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
|
|
28633
29187
|
} catch {
|
|
28634
29188
|
return;
|
|
@@ -28799,48 +29353,9 @@ function auditApproveResultPayload2(runId, status, totalCount, issuedIssues) {
|
|
|
28799
29353
|
issuedIssues
|
|
28800
29354
|
};
|
|
28801
29355
|
}
|
|
28802
|
-
function
|
|
28803
|
-
|
|
28804
|
-
|
|
28805
|
-
mkdirSync8(dirname9(absolute), { recursive: true });
|
|
28806
|
-
writeFileSync7(absolute, file.body.endsWith(`
|
|
28807
|
-
`) ? file.body : `${file.body}
|
|
28808
|
-
`, "utf8");
|
|
28809
|
-
}
|
|
28810
|
-
}
|
|
28811
|
-
function replaceArchitectureProjectionFilesForYamlRollback2(root, projectedFiles, currentFiles, createdAt) {
|
|
28812
|
-
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
28813
|
-
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment2(createdAt)}`;
|
|
28814
|
-
const backupRelativePath = uniqueBackupPath2(root, backupBase);
|
|
28815
|
-
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
28816
|
-
const { backup, manifest } = architectureProjectionRollbackBackup2(currentFiles, {
|
|
28817
|
-
createdAt,
|
|
28818
|
-
path: backupRelativePath,
|
|
28819
|
-
manifestPath
|
|
28820
|
-
});
|
|
28821
|
-
for (const file of currentFiles) {
|
|
28822
|
-
const backupPath = join9(backupRelativePath, archContextRelativePath2(file.path));
|
|
28823
|
-
const absolute = resolve16(root, backupPath);
|
|
28824
|
-
mkdirSync8(dirname9(absolute), { recursive: true });
|
|
28825
|
-
writeFileSync7(absolute, file.body, "utf8");
|
|
28826
|
-
}
|
|
28827
|
-
const manifestAbsolute = resolve16(root, manifestPath);
|
|
28828
|
-
mkdirSync8(dirname9(manifestAbsolute), { recursive: true });
|
|
28829
|
-
writeFileSync7(manifestAbsolute, `${JSON.stringify(manifest, null, 2)}
|
|
28830
|
-
`, "utf8");
|
|
28831
|
-
const removedPaths = [];
|
|
28832
|
-
for (const file of currentFiles) {
|
|
28833
|
-
if (targetPaths.has(file.path))
|
|
28834
|
-
continue;
|
|
28835
|
-
rmSync9(resolve16(root, file.path), { force: true });
|
|
28836
|
-
removedPaths.push(file.path);
|
|
28837
|
-
}
|
|
28838
|
-
writeArchitectureProjectionFiles2(root, projectedFiles);
|
|
28839
|
-
return {
|
|
28840
|
-
backup,
|
|
28841
|
-
writtenPaths: projectedFiles.map((file) => file.path),
|
|
28842
|
-
removedPaths
|
|
28843
|
-
};
|
|
29356
|
+
function expectedFileHash2(root, path) {
|
|
29357
|
+
const absolute = resolve17(root, path);
|
|
29358
|
+
return existsSync14(absolute) ? digestJson({ body: readFileSync13(absolute, "utf8") }) : "missing";
|
|
28844
29359
|
}
|
|
28845
29360
|
function architectureProjectionRollbackBackup2(files, options = {}) {
|
|
28846
29361
|
const manifest = {
|
|
@@ -28867,7 +29382,7 @@ function architectureProjectionRollbackBackup2(files, options = {}) {
|
|
|
28867
29382
|
function uniqueBackupPath2(root, backupBase) {
|
|
28868
29383
|
let candidate = backupBase;
|
|
28869
29384
|
let suffix = 2;
|
|
28870
|
-
while (
|
|
29385
|
+
while (existsSync14(resolve17(root, candidate))) {
|
|
28871
29386
|
candidate = `${backupBase}-${suffix}`;
|
|
28872
29387
|
suffix += 1;
|
|
28873
29388
|
}
|
|
@@ -28876,7 +29391,7 @@ function uniqueBackupPath2(root, backupBase) {
|
|
|
28876
29391
|
function uniqueRuntimeBackupPath2(backupBase) {
|
|
28877
29392
|
let candidate = backupBase;
|
|
28878
29393
|
let suffix = 2;
|
|
28879
|
-
while (
|
|
29394
|
+
while (existsSync14(candidate)) {
|
|
28880
29395
|
candidate = backupBase.replace(/\.sqlite$/, `-${suffix}.sqlite`);
|
|
28881
29396
|
suffix += 1;
|
|
28882
29397
|
}
|
|
@@ -28938,7 +29453,7 @@ function parsePracticeCheckpointBaselineState2(state, repositoryId, taskSessionI
|
|
|
28938
29453
|
return record;
|
|
28939
29454
|
}
|
|
28940
29455
|
function completeTaskProjectionDrift2(root) {
|
|
28941
|
-
if (!
|
|
29456
|
+
if (!existsSync14(resolve17(root, "docs/architecture/.projection-manifest.json")))
|
|
28942
29457
|
return;
|
|
28943
29458
|
const loaded = loadArchitectureDocumentationInputs(root);
|
|
28944
29459
|
const sourceDigest = architectureDocumentationSourceDigest({
|
|
@@ -29524,7 +30039,7 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
|
|
|
29524
30039
|
const subcommand = args2[0] ?? "list";
|
|
29525
30040
|
if (subcommand === "add") {
|
|
29526
30041
|
const root = readFlag(args2, "--root") ?? cwd;
|
|
29527
|
-
if (
|
|
30042
|
+
if (resolve18(root) !== resolve18(cwd)) {
|
|
29528
30043
|
return errorEnvelope("repo.add", "AC_CAPABILITY_UNSUPPORTED", "Multi-repo architecture context is outside the Local Core MVP; run archctx inside one Git repository.");
|
|
29529
30044
|
}
|
|
29530
30045
|
const daemon2 = await runtime();
|
|
@@ -30197,37 +30712,10 @@ function buildArchitectureDocsProjection(root, generatedAt) {
|
|
|
30197
30712
|
sourceDigest,
|
|
30198
30713
|
generatedAt
|
|
30199
30714
|
});
|
|
30200
|
-
const manifestBody = `${JSON.stringify({
|
|
30201
|
-
schemaVersion: "archcontext.architecture-docs-projection-manifest/v1",
|
|
30202
|
-
rendererVersion: plan.rendererVersion,
|
|
30203
|
-
sourceDigest: plan.sourceDigest,
|
|
30204
|
-
projectionDigest: plan.projectionDigest,
|
|
30205
|
-
targetCount: plan.targets.length,
|
|
30206
|
-
fileCount: plan.files.length,
|
|
30207
|
-
targets: plan.targets.map((target) => ({
|
|
30208
|
-
targetId: target.targetId,
|
|
30209
|
-
type: target.type,
|
|
30210
|
-
scope: target.scope,
|
|
30211
|
-
path: target.path,
|
|
30212
|
-
ownership: target.ownership,
|
|
30213
|
-
rendererVersion: target.rendererVersion,
|
|
30214
|
-
format: target.format,
|
|
30215
|
-
sourceDigest: target.sourceDigest,
|
|
30216
|
-
outputDigest: target.outputDigest
|
|
30217
|
-
}))
|
|
30218
|
-
}, null, 2)}
|
|
30219
|
-
`;
|
|
30220
|
-
const manifest = {
|
|
30221
|
-
path: "docs/architecture/.projection-manifest.json",
|
|
30222
|
-
body: manifestBody,
|
|
30223
|
-
digest: digestJson({ path: "docs/architecture/.projection-manifest.json", body: manifestBody }),
|
|
30224
|
-
target: plan.targets[0],
|
|
30225
|
-
generatedBodyDigest: digestJson({ body: manifestBody })
|
|
30226
|
-
};
|
|
30227
30715
|
return {
|
|
30228
30716
|
plan,
|
|
30229
|
-
manifest,
|
|
30230
|
-
files: [...plan.files, manifest]
|
|
30717
|
+
manifest: plan.manifest,
|
|
30718
|
+
files: [...plan.files, plan.manifest]
|
|
30231
30719
|
};
|
|
30232
30720
|
}
|
|
30233
30721
|
function architectureDocsRenderProjectionOperation(root, files) {
|
|
@@ -30242,8 +30730,8 @@ function architectureDocsRenderProjectionOperation(root, files) {
|
|
|
30242
30730
|
};
|
|
30243
30731
|
}
|
|
30244
30732
|
function currentBodyHash(root, path) {
|
|
30245
|
-
const absolute =
|
|
30246
|
-
return
|
|
30733
|
+
const absolute = resolve18(root, path);
|
|
30734
|
+
return existsSync15(absolute) ? digestJson({ body: readFileSync14(absolute, "utf8") }) : "missing";
|
|
30247
30735
|
}
|
|
30248
30736
|
async function runPracticesCommand(args2, cwd, daemon) {
|
|
30249
30737
|
const subcommand = args2[0] ?? "list";
|
|
@@ -30590,12 +31078,12 @@ function auditManifestGateRoot(cwd) {
|
|
|
30590
31078
|
}
|
|
30591
31079
|
}
|
|
30592
31080
|
function auditGithubIssuesEnabled(cwd) {
|
|
30593
|
-
const manifestPath =
|
|
30594
|
-
if (!
|
|
31081
|
+
const manifestPath = resolve18(auditManifestGateRoot(cwd), ".archcontext/manifest.yaml");
|
|
31082
|
+
if (!existsSync15(manifestPath))
|
|
30595
31083
|
return false;
|
|
30596
31084
|
let raw;
|
|
30597
31085
|
try {
|
|
30598
|
-
raw =
|
|
31086
|
+
raw = readFileSync14(manifestPath, "utf8");
|
|
30599
31087
|
} catch {
|
|
30600
31088
|
return false;
|
|
30601
31089
|
}
|
|
@@ -31190,11 +31678,11 @@ async function digestReviewChallenge(challenge) {
|
|
|
31190
31678
|
}
|
|
31191
31679
|
function defaultGithubDeveloperReviewStatePath(cwd, pullRequestNumber) {
|
|
31192
31680
|
const suffix = pullRequestNumber ? `github-developer-review-pr-${pullRequestNumber}.json` : "github-developer-review.json";
|
|
31193
|
-
return join10(
|
|
31681
|
+
return join10(dirname11(defaultDaemonConnectionPath(cwd)), suffix);
|
|
31194
31682
|
}
|
|
31195
31683
|
async function writeGithubDeveloperReviewState(cwd, state) {
|
|
31196
31684
|
const path = defaultGithubDeveloperReviewStatePath(cwd, state.challenge.pullRequestNumber);
|
|
31197
|
-
mkdirSync9(
|
|
31685
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
31198
31686
|
const serialized = `${JSON.stringify(state, null, 2)}
|
|
31199
31687
|
`;
|
|
31200
31688
|
assertNoCliSecretMaterial(serialized);
|
|
@@ -31204,10 +31692,10 @@ async function writeGithubDeveloperReviewState(cwd, state) {
|
|
|
31204
31692
|
return { state, path };
|
|
31205
31693
|
}
|
|
31206
31694
|
function readGithubDeveloperReviewState(path) {
|
|
31207
|
-
if (!
|
|
31695
|
+
if (!existsSync15(path))
|
|
31208
31696
|
return;
|
|
31209
31697
|
try {
|
|
31210
|
-
const parsed = JSON.parse(
|
|
31698
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
31211
31699
|
if (parsed.schemaVersion !== "archcontext.github-developer-review-state/v1")
|
|
31212
31700
|
return;
|
|
31213
31701
|
if (!parsed.challenge || typeof parsed.challenge.pullRequestNumber !== "number")
|
|
@@ -31253,13 +31741,13 @@ function sanitizeGithubDeveloperReviewState(state, statePath) {
|
|
|
31253
31741
|
return data;
|
|
31254
31742
|
}
|
|
31255
31743
|
function defaultGithubConnectionPath(cwd) {
|
|
31256
|
-
return join10(
|
|
31744
|
+
return join10(dirname11(defaultDaemonConnectionPath(cwd)), "github-connection.json");
|
|
31257
31745
|
}
|
|
31258
31746
|
function readGithubConnection(path) {
|
|
31259
|
-
if (!
|
|
31747
|
+
if (!existsSync15(path))
|
|
31260
31748
|
return;
|
|
31261
31749
|
try {
|
|
31262
|
-
const parsed = JSON.parse(
|
|
31750
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
31263
31751
|
if (parsed.schemaVersion !== "archcontext.github-connection/v1" || parsed.status !== "connected")
|
|
31264
31752
|
return;
|
|
31265
31753
|
return parsed;
|
|
@@ -31268,7 +31756,7 @@ function readGithubConnection(path) {
|
|
|
31268
31756
|
}
|
|
31269
31757
|
}
|
|
31270
31758
|
function writeGithubConnection(path, record) {
|
|
31271
|
-
mkdirSync9(
|
|
31759
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
31272
31760
|
const serialized = `${JSON.stringify(record, null, 2)}
|
|
31273
31761
|
`;
|
|
31274
31762
|
assertNoCliSecretMaterial(serialized);
|
|
@@ -31303,7 +31791,7 @@ async function readReviewChallengeV2Arg(args2, cwd, commandName = "github verify
|
|
|
31303
31791
|
if (!inline && !challengePath)
|
|
31304
31792
|
return { ok: false, message: `${commandName} requires --challenge-json or --challenge-path` };
|
|
31305
31793
|
try {
|
|
31306
|
-
const raw = inline ??
|
|
31794
|
+
const raw = inline ?? readFileSync14(resolve18(cwd, challengePath), "utf8");
|
|
31307
31795
|
const parsed = JSON.parse(raw);
|
|
31308
31796
|
const attestation = await Promise.resolve().then(() => (init_src7(), exports_src3));
|
|
31309
31797
|
const assertReviewChallengeV23 = attestation.assertReviewChallengeV2;
|
|
@@ -31770,16 +32258,16 @@ function doctorSqlite(cwd) {
|
|
|
31770
32258
|
const legacyLocalStore = inspectLegacyLocalStoreMigration(cwd);
|
|
31771
32259
|
return {
|
|
31772
32260
|
path,
|
|
31773
|
-
exists:
|
|
32261
|
+
exists: existsSync15(path),
|
|
31774
32262
|
migrations: productVersionManifest().runtime.sqliteMigrations,
|
|
31775
32263
|
legacyPath: paths.legacyLocalStorePath,
|
|
31776
|
-
legacyExists:
|
|
32264
|
+
legacyExists: existsSync15(paths.legacyLocalStorePath),
|
|
31777
32265
|
legacyLocalStore
|
|
31778
32266
|
};
|
|
31779
32267
|
}
|
|
31780
32268
|
function doctorPermissions(cwd) {
|
|
31781
32269
|
const paths = runtimeStatePaths(cwd);
|
|
31782
|
-
const controlDir =
|
|
32270
|
+
const controlDir = dirname11(defaultDaemonConnectionPath(cwd));
|
|
31783
32271
|
return {
|
|
31784
32272
|
workspace: pathAccess(cwd),
|
|
31785
32273
|
stateRoot: pathAccess(paths.stateRoot),
|
|
@@ -31804,7 +32292,7 @@ function runtimePathsReport(cwd) {
|
|
|
31804
32292
|
};
|
|
31805
32293
|
}
|
|
31806
32294
|
function pathAccess(path) {
|
|
31807
|
-
const exists =
|
|
32295
|
+
const exists = existsSync15(path);
|
|
31808
32296
|
return {
|
|
31809
32297
|
path,
|
|
31810
32298
|
exists,
|
|
@@ -31815,7 +32303,7 @@ function pathAccess(path) {
|
|
|
31815
32303
|
}
|
|
31816
32304
|
function canAccess(path, mode) {
|
|
31817
32305
|
try {
|
|
31818
|
-
|
|
32306
|
+
accessSync2(path, mode);
|
|
31819
32307
|
return true;
|
|
31820
32308
|
} catch {
|
|
31821
32309
|
return false;
|
|
@@ -32024,7 +32512,7 @@ async function startBackgroundDaemon(args2, cwd) {
|
|
|
32024
32512
|
}
|
|
32025
32513
|
const recovery = discovered.recovery;
|
|
32026
32514
|
const connectionPath = defaultDaemonConnectionPath(cwd);
|
|
32027
|
-
const controlDir =
|
|
32515
|
+
const controlDir = dirname11(connectionPath);
|
|
32028
32516
|
const logPath = join10(controlDir, "archctxd.log");
|
|
32029
32517
|
mkdirSync9(controlDir, { recursive: true });
|
|
32030
32518
|
const logFd = openSync7(logPath, "a", 384);
|
|
@@ -32223,11 +32711,11 @@ async function waitForDaemonReady(cwd, timeoutMs, shouldStop) {
|
|
|
32223
32711
|
return;
|
|
32224
32712
|
}
|
|
32225
32713
|
function sleep(ms) {
|
|
32226
|
-
return new Promise((
|
|
32714
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
32227
32715
|
}
|
|
32228
32716
|
function readFileTail(path, maxBytes = 4096) {
|
|
32229
32717
|
try {
|
|
32230
|
-
const content =
|
|
32718
|
+
const content = readFileSync14(path, "utf8");
|
|
32231
32719
|
return content.slice(Math.max(0, content.length - maxBytes)).replace(/\s+/g, " ").trim();
|
|
32232
32720
|
} catch {
|
|
32233
32721
|
return "<unavailable>";
|
|
@@ -32236,8 +32724,8 @@ function readFileTail(path, maxBytes = 4096) {
|
|
|
32236
32724
|
async function runForegroundDaemon(cwd, args2) {
|
|
32237
32725
|
const daemon = await createStartedProductionDaemon({ root: cwd });
|
|
32238
32726
|
let resolveStopped;
|
|
32239
|
-
const stopped = new Promise((
|
|
32240
|
-
resolveStopped =
|
|
32727
|
+
const stopped = new Promise((resolve19) => {
|
|
32728
|
+
resolveStopped = resolve19;
|
|
32241
32729
|
});
|
|
32242
32730
|
const idleTimeoutFlag = readFlag(args2, "--idle-timeout-ms");
|
|
32243
32731
|
const server = new ArchctxRuntimeRpcServer(daemon, {
|