archctx 0.2.1 → 0.2.2
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 +883 -427
- package/package.json +1 -1
package/bin/archctx.mjs
CHANGED
|
@@ -702,7 +702,7 @@ function productVersionManifest() {
|
|
|
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.2", 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,7 +5145,7 @@ 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
|
|
5148
|
+
import { accessSync, chmodSync as chmodSync5, closeSync as closeSync7, constants, existsSync as existsSync15, mkdirSync as mkdirSync9, openSync as openSync7, readFileSync as readFileSync13, rmSync as rmSync10, statSync as statSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
5149
5149
|
import { dirname as dirname10, join as join10, resolve as resolve17 } from "path";
|
|
5150
5150
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5151
5151
|
|
|
@@ -7493,7 +7493,7 @@ function planYamlToArchitectureLedgerImport(input) {
|
|
|
7493
7493
|
payloadVersion: "archcontext.architecture-ledger-yaml-import/v1",
|
|
7494
7494
|
repository: input.repository,
|
|
7495
7495
|
worktree: input.worktree,
|
|
7496
|
-
baseDigest:
|
|
7496
|
+
baseDigest: architectureLedgerStateDigest(emptyArchitectureLedgerState()),
|
|
7497
7497
|
resultingDigest: graphDigest,
|
|
7498
7498
|
headSha: input.worktree.headSha,
|
|
7499
7499
|
actor: { kind: "migration", id: "archctx-ledger-yaml-import" },
|
|
@@ -7677,8 +7677,6 @@ function planYamlToArchitectureLedgerRebuild(input) {
|
|
|
7677
7677
|
const plan = planYamlToArchitectureLedgerImport(input);
|
|
7678
7678
|
const previousGraphDigest = architectureLedgerStateDigest(input.previousState);
|
|
7679
7679
|
const deleteOperations = architectureLedgerDeletionOperations(input.previousState, plan.state);
|
|
7680
|
-
if (deleteOperations.length === 0)
|
|
7681
|
-
return plan;
|
|
7682
7680
|
const payload = architectureLedgerPayload(plan.event);
|
|
7683
7681
|
const event = normalizeArchitectureLedgerEvent({
|
|
7684
7682
|
...plan.event,
|
|
@@ -8244,41 +8242,41 @@ function projectArchitectureLedgerStateToYamlFiles(state) {
|
|
|
8244
8242
|
const canonical = canonicalArchitectureLedgerState(state);
|
|
8245
8243
|
const files = [
|
|
8246
8244
|
...canonical.entities.map((entity) => {
|
|
8245
|
+
const declared = declaredProjectionRecord(entity.metadata, ["archcontext.node/v1"], `entity ${entity.entityId}`);
|
|
8246
|
+
const summary = entity.summary;
|
|
8247
|
+
if (!summary)
|
|
8248
|
+
throw new Error(`architecture-ledger-projection-invalid: entity ${entity.entityId} requires summary`);
|
|
8247
8249
|
const body = canonicalArchitectureYaml({
|
|
8250
|
+
...declared,
|
|
8248
8251
|
schemaVersion: "archcontext.node/v1",
|
|
8249
8252
|
id: entity.entityId,
|
|
8250
8253
|
kind: entity.kind,
|
|
8251
8254
|
name: entity.canonicalName,
|
|
8252
8255
|
status: entity.status,
|
|
8253
|
-
|
|
8254
|
-
...entity.summary ? { summary: entity.summary } : {},
|
|
8255
|
-
...entity.metadata ? { metadata: entity.metadata } : {}
|
|
8256
|
+
summary
|
|
8256
8257
|
});
|
|
8257
8258
|
return projectionFile(`.archcontext/model/nodes/${pathSegment(entity.entityId)}.yaml`, body, "entity", entity.entityId);
|
|
8258
8259
|
}),
|
|
8259
8260
|
...canonical.relations.map((relation) => {
|
|
8260
|
-
const
|
|
8261
|
+
const declared = declaredProjectionRecord(relation.metadata, ["archcontext.relation/v1", "archcontext.cross-repo-relation/v1"], `relation ${relation.relationId}`);
|
|
8262
|
+
const schemaVersion = requireStringField(declared, "schemaVersion", `relation ${relation.relationId}`);
|
|
8263
|
+
const body = schemaVersion === "archcontext.cross-repo-relation/v1" ? canonicalArchitectureYaml({ ...declared, id: relation.relationId, kind: relation.kind }) : canonicalArchitectureYaml({
|
|
8264
|
+
...declared,
|
|
8261
8265
|
schemaVersion: "archcontext.relation/v1",
|
|
8262
8266
|
id: relation.relationId,
|
|
8263
8267
|
kind: relation.kind,
|
|
8264
8268
|
source: relation.sourceEntityId,
|
|
8265
|
-
target: relation.targetEntityId
|
|
8266
|
-
status: relation.status,
|
|
8267
|
-
...relation.summary ? { summary: relation.summary } : {},
|
|
8268
|
-
...relation.metadata ? { metadata: relation.metadata } : {}
|
|
8269
|
+
target: relation.targetEntityId
|
|
8269
8270
|
});
|
|
8270
8271
|
return projectionFile(`.archcontext/model/relations/${pathSegment(relation.relationId)}.yaml`, body, "relation", relation.relationId);
|
|
8271
8272
|
}),
|
|
8272
8273
|
...canonical.constraints.map((constraint) => {
|
|
8274
|
+
const declared = declaredProjectionRecord(constraint.metadata, ["archcontext.constraint/v1"], `constraint ${constraint.constraintId}`);
|
|
8273
8275
|
const body = canonicalArchitectureYaml({
|
|
8276
|
+
...declared,
|
|
8274
8277
|
schemaVersion: "archcontext.constraint/v1",
|
|
8275
8278
|
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 } : {}
|
|
8279
|
+
...constraint.severity ? { severity: constraint.severity } : {}
|
|
8282
8280
|
});
|
|
8283
8281
|
return projectionFile(`.archcontext/model/constraints/${pathSegment(constraint.constraintId)}.yaml`, body, "constraint", constraint.constraintId);
|
|
8284
8282
|
})
|
|
@@ -8453,12 +8451,11 @@ function yamlRecordToLedgerOperation(value, path, schemaVersion) {
|
|
|
8453
8451
|
const entityId = requireStringField(value, "id", path);
|
|
8454
8452
|
const entity = {
|
|
8455
8453
|
entityId,
|
|
8456
|
-
kind:
|
|
8457
|
-
canonicalName:
|
|
8458
|
-
status:
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
...metadataField(value, ["schemaVersion", "id", "kind", "name", "canonicalName", "status", "path", "summary"])
|
|
8454
|
+
kind: requireStringField(value, "kind", path),
|
|
8455
|
+
canonicalName: requireStringField(value, "name", path),
|
|
8456
|
+
status: declaredStatus(value.status, path),
|
|
8457
|
+
summary: requireStringField(value, "summary", path),
|
|
8458
|
+
metadata: { declared: value }
|
|
8462
8459
|
};
|
|
8463
8460
|
return { operation: { op: "upsert_entity", entity }, targetKind: "entity", targetId: entityId };
|
|
8464
8461
|
}
|
|
@@ -8466,12 +8463,12 @@ function yamlRecordToLedgerOperation(value, path, schemaVersion) {
|
|
|
8466
8463
|
const relationId = requireStringField(value, "id", path);
|
|
8467
8464
|
const relation = {
|
|
8468
8465
|
relationId,
|
|
8469
|
-
kind:
|
|
8466
|
+
kind: requireStringField(value, "kind", path),
|
|
8470
8467
|
sourceEntityId: requireStringField(value, "source", path),
|
|
8471
8468
|
targetEntityId: requireStringField(value, "target", path),
|
|
8472
|
-
status:
|
|
8473
|
-
|
|
8474
|
-
|
|
8469
|
+
status: "active",
|
|
8470
|
+
summary: requireStringField(value, "intent", path),
|
|
8471
|
+
metadata: { declared: value }
|
|
8475
8472
|
};
|
|
8476
8473
|
return { operation: { op: "upsert_relation", relation }, targetKind: "relation", targetId: relationId };
|
|
8477
8474
|
}
|
|
@@ -8481,25 +8478,28 @@ function yamlRecordToLedgerOperation(value, path, schemaVersion) {
|
|
|
8481
8478
|
const target = repoScopedTarget(value.target, path, "target");
|
|
8482
8479
|
const relation = {
|
|
8483
8480
|
relationId,
|
|
8484
|
-
kind:
|
|
8481
|
+
kind: requireStringField(value, "kind", path),
|
|
8485
8482
|
sourceEntityId: source,
|
|
8486
8483
|
targetEntityId: target,
|
|
8487
|
-
status:
|
|
8488
|
-
|
|
8489
|
-
|
|
8484
|
+
status: "active",
|
|
8485
|
+
summary: requireStringField(value, "intent", path),
|
|
8486
|
+
metadata: { declared: value }
|
|
8490
8487
|
};
|
|
8491
8488
|
return { operation: { op: "upsert_relation", relation }, targetKind: "relation", targetId: relationId };
|
|
8492
8489
|
}
|
|
8493
8490
|
if (schemaVersion === "archcontext.constraint/v1") {
|
|
8494
8491
|
const constraintId = requireStringField(value, "id", path);
|
|
8492
|
+
const scope = requiredRecordField(value, "scope", path);
|
|
8493
|
+
const rule = requiredRecordField(value, "rule", path);
|
|
8494
|
+
const subjectId = firstStringArrayValue(scope.nodes) ?? firstStringArrayValue(scope.relations) ?? "repository";
|
|
8495
8495
|
const constraint = {
|
|
8496
8496
|
constraintId,
|
|
8497
|
-
kind:
|
|
8498
|
-
subjectId
|
|
8499
|
-
status:
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8497
|
+
kind: requireStringField(rule, "type", path),
|
|
8498
|
+
subjectId,
|
|
8499
|
+
status: "active",
|
|
8500
|
+
severity: requiredSeverity(value.severity, path),
|
|
8501
|
+
summary: requireStringField(value, "rationale", path),
|
|
8502
|
+
metadata: { declared: value }
|
|
8503
8503
|
};
|
|
8504
8504
|
return { operation: { op: "upsert_constraint", constraint }, targetKind: "constraint", targetId: constraintId };
|
|
8505
8505
|
}
|
|
@@ -8636,19 +8636,30 @@ function isEvidenceOnlySchema(schemaVersion) {
|
|
|
8636
8636
|
function isGeneratedProjectionFile(file) {
|
|
8637
8637
|
return file.schemaVersion === "archcontext.generated/v1" || file.path === ".archcontext/generated" || file.path.startsWith(".archcontext/generated/") || file.body.includes("Generated by ArchContext");
|
|
8638
8638
|
}
|
|
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];
|
|
8639
|
+
function declaredProjectionRecord(metadata, allowedSchemaVersions, label) {
|
|
8640
|
+
const declared = metadata?.declared;
|
|
8641
|
+
if (!isRecord(declared))
|
|
8642
|
+
throw new Error(`architecture-ledger-projection-invalid: ${label} has no declared YAML record`);
|
|
8643
|
+
const schemaVersion = requireStringField(declared, "schemaVersion", label);
|
|
8644
|
+
if (!allowedSchemaVersions.includes(schemaVersion)) {
|
|
8645
|
+
throw new Error(`architecture-ledger-projection-invalid: ${label} has unsupported declared schema ${schemaVersion}`);
|
|
8650
8646
|
}
|
|
8651
|
-
return
|
|
8647
|
+
return declared;
|
|
8648
|
+
}
|
|
8649
|
+
function requiredRecordField(value, key, path) {
|
|
8650
|
+
const field = value[key];
|
|
8651
|
+
if (!isRecord(field))
|
|
8652
|
+
throw new Error(`${path}: ${key} is required`);
|
|
8653
|
+
return field;
|
|
8654
|
+
}
|
|
8655
|
+
function firstStringArrayValue(value) {
|
|
8656
|
+
return Array.isArray(value) ? value.find((item) => typeof item === "string" && item.length > 0) : undefined;
|
|
8657
|
+
}
|
|
8658
|
+
function requiredSeverity(value, path) {
|
|
8659
|
+
const severity = severityField(value);
|
|
8660
|
+
if (!severity)
|
|
8661
|
+
throw new Error(`${path}: severity is required`);
|
|
8662
|
+
return severity;
|
|
8652
8663
|
}
|
|
8653
8664
|
function declaredYamlSubject(value, path) {
|
|
8654
8665
|
const id = stringField(value, "id");
|
|
@@ -8681,8 +8692,10 @@ function requireStringField(value, key, path) {
|
|
|
8681
8692
|
function stringField(value, key) {
|
|
8682
8693
|
return typeof value[key] === "string" ? value[key] : undefined;
|
|
8683
8694
|
}
|
|
8684
|
-
function
|
|
8685
|
-
|
|
8695
|
+
function declaredStatus(value, path) {
|
|
8696
|
+
if (value === "active" || value === "planned" || value === "deprecated" || value === "removed")
|
|
8697
|
+
return value;
|
|
8698
|
+
throw new Error(`${path}: status is required`);
|
|
8686
8699
|
}
|
|
8687
8700
|
function severityField(value) {
|
|
8688
8701
|
return value === "notice" || value === "warning" || value === "error" || value === "critical" ? value : undefined;
|
|
@@ -8768,10 +8781,85 @@ function validateArchitectureLedgerEvent(event) {
|
|
|
8768
8781
|
if (event.worktree.workspaceId.length === 0 || event.worktree.storageWorkspaceId.length === 0 || event.worktree.headSha.length === 0) {
|
|
8769
8782
|
throw new Error(`architecture-ledger-invalid-event: worktree identity required for ${event.eventId}`);
|
|
8770
8783
|
}
|
|
8784
|
+
assertArchitectureLedgerPersistenceSafe(event.payload, `event.payload for ${event.eventId}`);
|
|
8785
|
+
if (event.extensions)
|
|
8786
|
+
assertArchitectureLedgerPersistenceSafe(event.extensions, `event.extensions for ${event.eventId}`);
|
|
8787
|
+
assertArchitectureLedgerPersistenceSafe(event.provenance, `event.provenance for ${event.eventId}`);
|
|
8771
8788
|
const payload = architectureLedgerPayload(event);
|
|
8772
8789
|
for (const operation of payload.operations ?? [])
|
|
8773
8790
|
validateArchitectureLedgerOperation(operation, event.eventId);
|
|
8774
8791
|
}
|
|
8792
|
+
var ARCHITECTURE_LEDGER_MAX_PERSISTED_JSON_BYTES = 262144;
|
|
8793
|
+
var ARCHITECTURE_LEDGER_MAX_PERSISTED_STRING_BYTES = 8192;
|
|
8794
|
+
var ARCHITECTURE_LEDGER_MAX_PERSISTED_DEPTH = 32;
|
|
8795
|
+
var ARCHITECTURE_LEDGER_FORBIDDEN_RAW_KEYS = new Set([
|
|
8796
|
+
"rawsource",
|
|
8797
|
+
"sourcebody",
|
|
8798
|
+
"sourcecode",
|
|
8799
|
+
"rawdiff",
|
|
8800
|
+
"diffbody",
|
|
8801
|
+
"rawpatch",
|
|
8802
|
+
"patchbody",
|
|
8803
|
+
"prompt",
|
|
8804
|
+
"promptbody",
|
|
8805
|
+
"completion",
|
|
8806
|
+
"completionbody",
|
|
8807
|
+
"codegraphoutput",
|
|
8808
|
+
"fullcodegraphoutput",
|
|
8809
|
+
"webhookbody",
|
|
8810
|
+
"rawwebhook",
|
|
8811
|
+
"secret",
|
|
8812
|
+
"secrets",
|
|
8813
|
+
"credential",
|
|
8814
|
+
"credentials",
|
|
8815
|
+
"privatekey",
|
|
8816
|
+
"accesstoken",
|
|
8817
|
+
"refreshtoken"
|
|
8818
|
+
]);
|
|
8819
|
+
var ARCHITECTURE_LEDGER_SAFE_SENSITIVE_KEY_SUFFIX = /(?:digest|id|ids|count|counts|ref|refs|path|paths|persisted)$/;
|
|
8820
|
+
var ARCHITECTURE_LEDGER_FORBIDDEN_STRING_PATTERNS = [
|
|
8821
|
+
/diff --git /,
|
|
8822
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
8823
|
+
/\bgh[pousr]_[A-Za-z0-9]{20,}\b/,
|
|
8824
|
+
/\bsk-[A-Za-z0-9_-]{20,}\b/,
|
|
8825
|
+
/\bAKIA[A-Z0-9]{16}\b/,
|
|
8826
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/i,
|
|
8827
|
+
/\b(?:api[_-]?key|secret|token|password|private[_-]?key)\s*[:=]\s*["']?[^\s"',;]{8,}/i
|
|
8828
|
+
];
|
|
8829
|
+
function assertArchitectureLedgerPersistenceSafe(value, label = "architecture-ledger-value") {
|
|
8830
|
+
const encoded = JSON.stringify(value);
|
|
8831
|
+
if (Buffer2.byteLength(encoded, "utf8") > ARCHITECTURE_LEDGER_MAX_PERSISTED_JSON_BYTES) {
|
|
8832
|
+
throw new Error(`architecture-ledger-privacy-denied: persisted JSON exceeds size limit at ${label}`);
|
|
8833
|
+
}
|
|
8834
|
+
visit(value, label, 0);
|
|
8835
|
+
function visit(current, path, depth) {
|
|
8836
|
+
if (depth > ARCHITECTURE_LEDGER_MAX_PERSISTED_DEPTH) {
|
|
8837
|
+
throw new Error(`architecture-ledger-privacy-denied: persisted JSON exceeds depth limit at ${path}`);
|
|
8838
|
+
}
|
|
8839
|
+
if (typeof current === "string") {
|
|
8840
|
+
if (Buffer2.byteLength(current, "utf8") > ARCHITECTURE_LEDGER_MAX_PERSISTED_STRING_BYTES) {
|
|
8841
|
+
throw new Error(`architecture-ledger-privacy-denied: persisted string exceeds size limit at ${path}`);
|
|
8842
|
+
}
|
|
8843
|
+
if (ARCHITECTURE_LEDGER_FORBIDDEN_STRING_PATTERNS.some((pattern) => pattern.test(current))) {
|
|
8844
|
+
throw new Error(`architecture-ledger-privacy-denied: forbidden raw or secret-shaped content at ${path}`);
|
|
8845
|
+
}
|
|
8846
|
+
return;
|
|
8847
|
+
}
|
|
8848
|
+
if (current === null || typeof current !== "object")
|
|
8849
|
+
return;
|
|
8850
|
+
if (Array.isArray(current)) {
|
|
8851
|
+
current.forEach((item, index) => visit(item, `${path}[${index}]`, depth + 1));
|
|
8852
|
+
return;
|
|
8853
|
+
}
|
|
8854
|
+
for (const [key, child] of Object.entries(current)) {
|
|
8855
|
+
const normalizedKey = key.replace(/[-_]/g, "").toLowerCase();
|
|
8856
|
+
if (ARCHITECTURE_LEDGER_FORBIDDEN_RAW_KEYS.has(normalizedKey) && !ARCHITECTURE_LEDGER_SAFE_SENSITIVE_KEY_SUFFIX.test(normalizedKey)) {
|
|
8857
|
+
throw new Error(`architecture-ledger-privacy-denied: forbidden persisted field at ${path}.${key}`);
|
|
8858
|
+
}
|
|
8859
|
+
visit(child, `${path}.${key}`, depth + 1);
|
|
8860
|
+
}
|
|
8861
|
+
}
|
|
8862
|
+
}
|
|
8775
8863
|
function validateArchitectureLedgerOperation(operation, eventId) {
|
|
8776
8864
|
if (!operation || typeof operation !== "object" || !("op" in operation)) {
|
|
8777
8865
|
throw new Error(`architecture-ledger-invalid-operation: ${eventId}`);
|
|
@@ -8894,7 +8982,7 @@ function requireNonEmpty(value, label, eventId) {
|
|
|
8894
8982
|
}
|
|
8895
8983
|
}
|
|
8896
8984
|
function requireActiveStatus(value, eventId) {
|
|
8897
|
-
if (!["active", "deprecated", "removed"].includes(value)) {
|
|
8985
|
+
if (!["active", "planned", "deprecated", "removed"].includes(value)) {
|
|
8898
8986
|
throw new Error(`architecture-ledger-invalid-operation: invalid status for ${eventId}`);
|
|
8899
8987
|
}
|
|
8900
8988
|
}
|
|
@@ -8943,6 +9031,7 @@ var REQUIRED_LOCAL_STORE_TABLES = [
|
|
|
8943
9031
|
];
|
|
8944
9032
|
var SQLITE_PRAGMAS = [
|
|
8945
9033
|
"PRAGMA journal_mode = WAL",
|
|
9034
|
+
"PRAGMA synchronous = FULL",
|
|
8946
9035
|
"PRAGMA foreign_keys = ON",
|
|
8947
9036
|
"PRAGMA busy_timeout = 5000"
|
|
8948
9037
|
];
|
|
@@ -9464,6 +9553,13 @@ var LOCAL_SQLITE_MIGRATIONS = [
|
|
|
9464
9553
|
)`,
|
|
9465
9554
|
"CREATE INDEX IF NOT EXISTS idx_audit_runs_status ON audit_runs(storage_repository_id, storage_workspace_id, status)"
|
|
9466
9555
|
]
|
|
9556
|
+
},
|
|
9557
|
+
{
|
|
9558
|
+
id: "0011_changeset_cleanup_cursor",
|
|
9559
|
+
statements: [
|
|
9560
|
+
"ALTER TABLE changeset_journal ADD COLUMN cleanup_completed_at TEXT",
|
|
9561
|
+
"CREATE INDEX IF NOT EXISTS idx_changeset_journal_cleanup_pending ON changeset_journal(status, cleanup_completed_at, updated_at)"
|
|
9562
|
+
]
|
|
9467
9563
|
}
|
|
9468
9564
|
];
|
|
9469
9565
|
var ARCHCONTEXT_STATE_DIR_ENV = "ARCHCONTEXT_STATE_DIR";
|
|
@@ -10041,17 +10137,18 @@ function readHeadSha(root) {
|
|
|
10041
10137
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
10042
10138
|
import { randomBytes } from "node:crypto";
|
|
10043
10139
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
10044
|
-
import { chmodSync as chmodSync3, closeSync as closeSync5, existsSync as
|
|
10140
|
+
import { chmodSync as chmodSync3, closeSync as closeSync5, existsSync as existsSync13, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, openSync as openSync5, readdirSync as readdirSync8, readFileSync as readFileSync11, rmSync as rmSync8, statSync as statSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10045
10141
|
import { createServer } from "node:http";
|
|
10046
10142
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
10047
10143
|
import { dirname as dirname8, join as join8, resolve as resolve15 } from "node:path";
|
|
10048
10144
|
|
|
10049
10145
|
// packages/core/changeset-engine/src/index.ts
|
|
10050
10146
|
init_src();
|
|
10051
|
-
import { closeSync as closeSync3, existsSync as
|
|
10147
|
+
import { closeSync as closeSync3, existsSync as existsSync5, fsyncSync as fsyncSync2, lstatSync as lstatSync2, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
10052
10148
|
import { dirname as dirname3, resolve as resolve7 } from "node:path";
|
|
10053
10149
|
|
|
10054
10150
|
// packages/core/policy-engine/src/index.ts
|
|
10151
|
+
import { existsSync as existsSync4, realpathSync as realpathSync5 } from "node:fs";
|
|
10055
10152
|
import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve6, sep as sep3 } from "node:path";
|
|
10056
10153
|
init_src();
|
|
10057
10154
|
var INVALID_COMPAT_REASONS = new Set(["just in case", "safer to keep", "many internal callers", "large diff", "old code already exists"]);
|
|
@@ -10062,6 +10159,7 @@ var ALLOWLIST = [
|
|
|
10062
10159
|
".archcontext/practices/",
|
|
10063
10160
|
".archcontext/waivers/",
|
|
10064
10161
|
".archcontext/decisions/",
|
|
10162
|
+
".archcontext/backups/",
|
|
10065
10163
|
".archcontext/generated/",
|
|
10066
10164
|
"docs/architecture/"
|
|
10067
10165
|
];
|
|
@@ -10098,6 +10196,21 @@ function assertAllowedArchContextPath(root, relativePath) {
|
|
|
10098
10196
|
if (targetFromRoot === "" || targetFromRoot === ".." || targetFromRoot.startsWith(`..${sep3}`) || isAbsolute3(targetFromRoot)) {
|
|
10099
10197
|
throw new Error(`Path escapes repository: ${relativePath}`);
|
|
10100
10198
|
}
|
|
10199
|
+
if (!existsSync4(absoluteRoot))
|
|
10200
|
+
return;
|
|
10201
|
+
const canonicalRoot = realpathSync5.native(absoluteRoot);
|
|
10202
|
+
let existingAncestor = absoluteTarget;
|
|
10203
|
+
while (!existsSync4(existingAncestor)) {
|
|
10204
|
+
const parent = resolve6(existingAncestor, "..");
|
|
10205
|
+
if (parent === existingAncestor)
|
|
10206
|
+
throw new Error(`Path has no existing repository ancestor: ${relativePath}`);
|
|
10207
|
+
existingAncestor = parent;
|
|
10208
|
+
}
|
|
10209
|
+
const canonicalAncestor = realpathSync5.native(existingAncestor);
|
|
10210
|
+
const ancestorFromRoot = relative4(canonicalRoot, canonicalAncestor);
|
|
10211
|
+
if (ancestorFromRoot === ".." || ancestorFromRoot.startsWith(`..${sep3}`) || isAbsolute3(ancestorFromRoot)) {
|
|
10212
|
+
throw new Error(`Path escapes repository through symlink: ${relativePath}`);
|
|
10213
|
+
}
|
|
10101
10214
|
}
|
|
10102
10215
|
function evaluateChangeSetPaths(root, paths) {
|
|
10103
10216
|
const findings = [];
|
|
@@ -10157,6 +10270,7 @@ class ChangeSetEngine {
|
|
|
10157
10270
|
if (!approved)
|
|
10158
10271
|
throw new Error("ChangeSet must be approved before apply");
|
|
10159
10272
|
const deps = this.requireDeps();
|
|
10273
|
+
await this.validateModel(root, draft, deps, "before");
|
|
10160
10274
|
const backups = [];
|
|
10161
10275
|
const journalId = await deps.journal?.beginChangeSet(root, draft);
|
|
10162
10276
|
let journalCommitted = false;
|
|
@@ -10171,10 +10285,7 @@ class ChangeSetEngine {
|
|
|
10171
10285
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10172
10286
|
throw new Error("fault-injection");
|
|
10173
10287
|
}
|
|
10174
|
-
} else {
|
|
10175
|
-
this.rebuildGeneratedProjection(root, deps);
|
|
10176
|
-
applied += 1;
|
|
10177
|
-
}
|
|
10288
|
+
} else {}
|
|
10178
10289
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10179
10290
|
throw new Error("fault-injection");
|
|
10180
10291
|
continue;
|
|
@@ -10186,15 +10297,24 @@ class ChangeSetEngine {
|
|
|
10186
10297
|
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10187
10298
|
throw new Error("fault-injection");
|
|
10188
10299
|
}
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10300
|
+
for (const projection of deps.projection.planGeneratedProjection(root)) {
|
|
10301
|
+
await this.applyFileOperation(root, projection.path, projection.expectedHash, projection.body, projection.operation, backups, journalId, applied + 1);
|
|
10302
|
+
applied += 1;
|
|
10303
|
+
if (options.faultAfterOperations && applied >= options.faultAfterOperations)
|
|
10304
|
+
throw new Error("fault-injection");
|
|
10305
|
+
}
|
|
10306
|
+
await this.validateModel(root, draft, deps, "after");
|
|
10307
|
+
const commit = await options.afterModelValidatedBeforeCommit?.({ root, draft, journalId });
|
|
10308
|
+
if (commit?.journalCommitted)
|
|
10309
|
+
journalCommitted = true;
|
|
10310
|
+
if (journalId && !journalCommitted) {
|
|
10193
10311
|
await deps.journal?.commitChangeSet(journalId);
|
|
10194
10312
|
journalCommitted = true;
|
|
10195
10313
|
}
|
|
10196
10314
|
try {
|
|
10197
10315
|
cleanupBackups(backups);
|
|
10316
|
+
if (journalId)
|
|
10317
|
+
await deps.journal?.completeChangeSetCleanup(journalId);
|
|
10198
10318
|
} catch {}
|
|
10199
10319
|
const appliedDraft = { ...draft, status: "applied" };
|
|
10200
10320
|
this.states.set(draft.id, appliedDraft);
|
|
@@ -10210,11 +10330,11 @@ class ChangeSetEngine {
|
|
|
10210
10330
|
throw error;
|
|
10211
10331
|
}
|
|
10212
10332
|
}
|
|
10213
|
-
|
|
10214
|
-
deps.
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10333
|
+
async validateModel(root, draft, deps, phase) {
|
|
10334
|
+
const result = await deps.modelStore.validateModel({ root, repositoryId: draft.reason.taskSessionId, headSha: draft.base.headSha });
|
|
10335
|
+
if (!result.valid) {
|
|
10336
|
+
throw new Error(`ChangeSet model validation failed ${phase} apply: ${result.errors.join("; ") || "unknown validation error"}`);
|
|
10337
|
+
}
|
|
10218
10338
|
}
|
|
10219
10339
|
requireDeps() {
|
|
10220
10340
|
if (!this.deps)
|
|
@@ -10225,19 +10345,16 @@ class ChangeSetEngine {
|
|
|
10225
10345
|
assertSafeTarget(root, path);
|
|
10226
10346
|
const deps = this.requireDeps();
|
|
10227
10347
|
const absolute = resolve7(root, path);
|
|
10228
|
-
const existed =
|
|
10348
|
+
const existed = existsSync5(absolute);
|
|
10229
10349
|
const backupPath = `${absolute}.archctx-backup`;
|
|
10230
10350
|
const tempPath = operation === "delete_entity" ? undefined : `${absolute}.archctx-tmp-${process.pid}-${sequence}`;
|
|
10231
|
-
if (
|
|
10351
|
+
if (existsSync5(backupPath))
|
|
10232
10352
|
throw new Error(`Backup path already exists: ${path}`);
|
|
10233
|
-
if (existed)
|
|
10353
|
+
if (existed)
|
|
10234
10354
|
assertExpectedHash(absolute, expectedHash);
|
|
10235
|
-
|
|
10236
|
-
fsyncDirectory2(dirname3(absolute));
|
|
10237
|
-
} else if (expectedHash !== "missing") {
|
|
10355
|
+
else if (expectedHash !== "missing")
|
|
10238
10356
|
throw new Error(`Expected missing file hash for new path: ${path}`);
|
|
10239
|
-
}
|
|
10240
|
-
backups.push({ path: absolute, backupPath, tempPath, existed });
|
|
10357
|
+
const backup = { path: absolute, backupPath, tempPath, existed };
|
|
10241
10358
|
if (journalId) {
|
|
10242
10359
|
await deps.journal?.recordChangeSetFile(journalId, {
|
|
10243
10360
|
path,
|
|
@@ -10247,6 +10364,11 @@ class ChangeSetEngine {
|
|
|
10247
10364
|
operation
|
|
10248
10365
|
});
|
|
10249
10366
|
}
|
|
10367
|
+
backups.push(backup);
|
|
10368
|
+
if (existed) {
|
|
10369
|
+
renameSync2(absolute, backupPath);
|
|
10370
|
+
fsyncDirectory2(dirname3(absolute));
|
|
10371
|
+
}
|
|
10250
10372
|
if (operation === "delete_entity") {
|
|
10251
10373
|
rmSync3(absolute, { force: true });
|
|
10252
10374
|
} else {
|
|
@@ -10257,7 +10379,7 @@ class ChangeSetEngine {
|
|
|
10257
10379
|
function assertSafeTarget(root, path) {
|
|
10258
10380
|
assertAllowedArchContextPath(root, path);
|
|
10259
10381
|
const absolute = resolve7(root, path);
|
|
10260
|
-
if (
|
|
10382
|
+
if (existsSync5(absolute) && lstatSync2(absolute).isSymbolicLink()) {
|
|
10261
10383
|
throw new Error(`Refusing to write symlink target: ${path}`);
|
|
10262
10384
|
}
|
|
10263
10385
|
}
|
|
@@ -10332,9 +10454,14 @@ function rollback(backups) {
|
|
|
10332
10454
|
for (const backup of backups.reverse()) {
|
|
10333
10455
|
if (backup.tempPath)
|
|
10334
10456
|
rmSync3(backup.tempPath, { recursive: true, force: true });
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10457
|
+
if (backup.existed) {
|
|
10458
|
+
if (existsSync5(backup.backupPath)) {
|
|
10459
|
+
rmSync3(backup.path, { recursive: true, force: true });
|
|
10460
|
+
renameSync2(backup.backupPath, backup.path);
|
|
10461
|
+
}
|
|
10462
|
+
} else {
|
|
10463
|
+
rmSync3(backup.path, { recursive: true, force: true });
|
|
10464
|
+
}
|
|
10338
10465
|
fsyncDirectory2(dirname3(backup.path));
|
|
10339
10466
|
}
|
|
10340
10467
|
}
|
|
@@ -10540,7 +10667,7 @@ function digestSuffix2(digest) {
|
|
|
10540
10667
|
}
|
|
10541
10668
|
|
|
10542
10669
|
// packages/core/application/src/index.ts
|
|
10543
|
-
import { existsSync as
|
|
10670
|
+
import { existsSync as existsSync8, statSync as statSync5 } from "node:fs";
|
|
10544
10671
|
import { extname, resolve as resolve10 } from "node:path";
|
|
10545
10672
|
|
|
10546
10673
|
// packages/core/context-compiler/src/index.ts
|
|
@@ -10548,7 +10675,7 @@ init_src();
|
|
|
10548
10675
|
|
|
10549
10676
|
// packages/core/practice-catalog/src/index.ts
|
|
10550
10677
|
init_src();
|
|
10551
|
-
import { existsSync as
|
|
10678
|
+
import { existsSync as existsSync6, lstatSync as lstatSync3, readdirSync as readdirSync4, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
|
|
10552
10679
|
import { dirname as dirname4, relative as relative5, resolve as resolve8, sep as sep4 } from "node:path";
|
|
10553
10680
|
import { fileURLToPath } from "node:url";
|
|
10554
10681
|
var PRACTICE_CATALOG_VERSION = "2026.06.0";
|
|
@@ -10797,7 +10924,7 @@ function loadProfileFiles(dir, errors) {
|
|
|
10797
10924
|
}
|
|
10798
10925
|
function loadRepoOverlayAssets(root, errors) {
|
|
10799
10926
|
const overlayRoot = resolve8(root, ".archcontext/practices");
|
|
10800
|
-
if (!
|
|
10927
|
+
if (!existsSync6(overlayRoot))
|
|
10801
10928
|
return [];
|
|
10802
10929
|
const out = [];
|
|
10803
10930
|
for (const path of listDataFiles(overlayRoot, overlayRoot, errors)) {
|
|
@@ -11140,7 +11267,7 @@ function validateProfile(value, path, errors) {
|
|
|
11140
11267
|
return invalid ? undefined : profile;
|
|
11141
11268
|
}
|
|
11142
11269
|
function listDataFiles(dir, allowedRoot, errors) {
|
|
11143
|
-
if (!
|
|
11270
|
+
if (!existsSync6(dir))
|
|
11144
11271
|
return [];
|
|
11145
11272
|
const out = [];
|
|
11146
11273
|
const rootReal = safeRealpath(allowedRoot);
|
|
@@ -11202,7 +11329,7 @@ function assertRealChild(root, path) {
|
|
|
11202
11329
|
}
|
|
11203
11330
|
function safeRealpath(path) {
|
|
11204
11331
|
try {
|
|
11205
|
-
return
|
|
11332
|
+
return realpathSync6.native(path);
|
|
11206
11333
|
} catch {
|
|
11207
11334
|
return resolve8(path);
|
|
11208
11335
|
}
|
|
@@ -11773,7 +11900,7 @@ function checkResult(input, result) {
|
|
|
11773
11900
|
}
|
|
11774
11901
|
// packages/core/practice-engine/src/enforcement.ts
|
|
11775
11902
|
init_src();
|
|
11776
|
-
import { existsSync as
|
|
11903
|
+
import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "node:fs";
|
|
11777
11904
|
import { basename as basename3, join as join4, relative as relative6, resolve as resolve9, sep as sep5 } from "node:path";
|
|
11778
11905
|
var ENFORCEMENT_RANK = { advisory: 0, checkpoint: 1, complete: 2 };
|
|
11779
11906
|
var POLICY_MODES = new Set(["advisory", "active", "fail-open", "fail-closed"]);
|
|
@@ -11798,7 +11925,7 @@ function shouldEvaluatePracticeEnforcement(policy) {
|
|
|
11798
11925
|
}
|
|
11799
11926
|
function loadPracticeEnforcementPolicy(root) {
|
|
11800
11927
|
const path = resolve9(root, ".archcontext/policies/practices.yaml");
|
|
11801
|
-
if (!
|
|
11928
|
+
if (!existsSync7(path))
|
|
11802
11929
|
return defaultPracticeEnforcementPolicy();
|
|
11803
11930
|
assertRepoPolicyFile(root, path, ".archcontext/policies/practices.yaml");
|
|
11804
11931
|
const parsed = parseJsonYamlFile(path);
|
|
@@ -11806,7 +11933,7 @@ function loadPracticeEnforcementPolicy(root) {
|
|
|
11806
11933
|
}
|
|
11807
11934
|
function loadPracticeWaivers(root) {
|
|
11808
11935
|
const dir = resolve9(root, ".archcontext/waivers");
|
|
11809
|
-
if (!
|
|
11936
|
+
if (!existsSync7(dir))
|
|
11810
11937
|
return [];
|
|
11811
11938
|
const stat = lstatSync4(dir);
|
|
11812
11939
|
if (stat.isSymbolicLink())
|
|
@@ -11829,7 +11956,7 @@ function loadPracticeWaiverOwnerRegistry(root) {
|
|
|
11829
11956
|
const modelDir = resolve9(root, ".archcontext/model/nodes");
|
|
11830
11957
|
const sources = [];
|
|
11831
11958
|
const subjects = [];
|
|
11832
|
-
if (
|
|
11959
|
+
if (existsSync7(modelDir)) {
|
|
11833
11960
|
if (lstatSync4(modelDir).isSymbolicLink())
|
|
11834
11961
|
throw new Error("practice-owner-registry-symlink-denied");
|
|
11835
11962
|
for (const path of collectFiles(root, ".archcontext/model/nodes")) {
|
|
@@ -13642,7 +13769,7 @@ function classifyCheckpointPath(root, path) {
|
|
|
13642
13769
|
if (isGeneratedCheckpointPath(path))
|
|
13643
13770
|
return "generated";
|
|
13644
13771
|
const absolute = resolve10(root, path);
|
|
13645
|
-
if (!
|
|
13772
|
+
if (!existsSync8(absolute))
|
|
13646
13773
|
return "deleted";
|
|
13647
13774
|
try {
|
|
13648
13775
|
if (!statSync5(absolute).isFile())
|
|
@@ -14848,7 +14975,7 @@ function uniqueSorted4(values) {
|
|
|
14848
14975
|
|
|
14849
14976
|
// packages/core/projection-engine/src/index.ts
|
|
14850
14977
|
init_src();
|
|
14851
|
-
import { existsSync as
|
|
14978
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync8 } from "node:fs";
|
|
14852
14979
|
import { basename as basename4, resolve as resolve11 } from "node:path";
|
|
14853
14980
|
function nativeNodeSource(node) {
|
|
14854
14981
|
const value = node.source;
|
|
@@ -14891,12 +15018,6 @@ function renderArchitectureDocumentationProjection(input) {
|
|
|
14891
15018
|
});
|
|
14892
15019
|
const targets = rendered.map((file) => file.target);
|
|
14893
15020
|
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
15021
|
const projectionDigest = digestJson({
|
|
14901
15022
|
rendererVersion,
|
|
14902
15023
|
sourceDigest: input.sourceDigest,
|
|
@@ -14907,6 +15028,38 @@ function renderArchitectureDocumentationProjection(input) {
|
|
|
14907
15028
|
generatedBodyDigest: file.generatedBodyDigest
|
|
14908
15029
|
})).sort((left, right) => left.path.localeCompare(right.path))
|
|
14909
15030
|
});
|
|
15031
|
+
const manifestValue = {
|
|
15032
|
+
schemaVersion: "archcontext.architecture-docs-projection-manifest/v1",
|
|
15033
|
+
rendererVersion,
|
|
15034
|
+
sourceDigest: input.sourceDigest,
|
|
15035
|
+
projectionDigest,
|
|
15036
|
+
targetCount: targets.length,
|
|
15037
|
+
fileCount: rendered.length,
|
|
15038
|
+
targets: targets.map((target) => ({
|
|
15039
|
+
targetId: target.targetId,
|
|
15040
|
+
type: target.type,
|
|
15041
|
+
scope: target.scope,
|
|
15042
|
+
path: target.path,
|
|
15043
|
+
ownership: target.ownership,
|
|
15044
|
+
rendererVersion: target.rendererVersion,
|
|
15045
|
+
format: target.format,
|
|
15046
|
+
sourceDigest: target.sourceDigest,
|
|
15047
|
+
outputDigest: target.outputDigest
|
|
15048
|
+
}))
|
|
15049
|
+
};
|
|
15050
|
+
const manifest = {
|
|
15051
|
+
path: "docs/architecture/.projection-manifest.json",
|
|
15052
|
+
body: `${JSON.stringify(manifestValue, null, 2)}
|
|
15053
|
+
`,
|
|
15054
|
+
digest: digestJson(manifestValue)
|
|
15055
|
+
};
|
|
15056
|
+
const drift = architectureDocumentationProjectionDrift({
|
|
15057
|
+
targets,
|
|
15058
|
+
expectedFiles: rendered,
|
|
15059
|
+
expectedManifest: manifest,
|
|
15060
|
+
existingFiles: input.existingFiles ?? []
|
|
15061
|
+
});
|
|
15062
|
+
const rejected = drift.diffs.filter((diff) => diff.reasonCode === "projection-ambiguous-ownership");
|
|
14910
15063
|
return {
|
|
14911
15064
|
schemaVersion: "archcontext.architecture-docs-projection-plan/v1",
|
|
14912
15065
|
rendererVersion,
|
|
@@ -14914,6 +15067,7 @@ function renderArchitectureDocumentationProjection(input) {
|
|
|
14914
15067
|
projectionDigest,
|
|
14915
15068
|
targets,
|
|
14916
15069
|
files: rendered.filter((file) => !rejected.some((diff) => diff.path === file.path && diff.targetId === file.target.targetId)),
|
|
15070
|
+
manifest,
|
|
14917
15071
|
drift: {
|
|
14918
15072
|
...drift,
|
|
14919
15073
|
diffs: drift.diffs.map((diff) => ({
|
|
@@ -14944,7 +15098,7 @@ function architectureDocumentationSourceDigest(input) {
|
|
|
14944
15098
|
}
|
|
14945
15099
|
function loadArchitectureDecisionRecords(root) {
|
|
14946
15100
|
const dir = resolve11(root, "docs/adr");
|
|
14947
|
-
if (!
|
|
15101
|
+
if (!existsSync9(dir))
|
|
14948
15102
|
return [];
|
|
14949
15103
|
return readdirSync6(dir).filter((file) => /^ADR-\d{4}-.+\.md$/.test(file)).sort().map((file) => {
|
|
14950
15104
|
const path = `docs/adr/${file}`;
|
|
@@ -14971,12 +15125,12 @@ function loadArchitectureDocumentationFiles(root) {
|
|
|
14971
15125
|
"docs/architecture/.projection-manifest.json"
|
|
14972
15126
|
]) {
|
|
14973
15127
|
const absolute = resolve11(root, entry);
|
|
14974
|
-
if (
|
|
15128
|
+
if (existsSync9(absolute))
|
|
14975
15129
|
files.push({ path: entry, body: readFileSync8(absolute, "utf8") });
|
|
14976
15130
|
}
|
|
14977
15131
|
for (const dir of ["docs/architecture/modules", "docs/architecture/relations"]) {
|
|
14978
15132
|
const absoluteDir = resolve11(root, dir);
|
|
14979
|
-
if (!
|
|
15133
|
+
if (!existsSync9(absoluteDir))
|
|
14980
15134
|
continue;
|
|
14981
15135
|
for (const file of readdirSync6(absoluteDir).filter((name) => name.endsWith(".md")).sort()) {
|
|
14982
15136
|
const path = `${dir}/${file}`;
|
|
@@ -15082,7 +15236,7 @@ function mermaidId(id) {
|
|
|
15082
15236
|
return stableId(id).replace(/-/g, "_").replace(/\./g, "_");
|
|
15083
15237
|
}
|
|
15084
15238
|
function readYamlObjects(dir) {
|
|
15085
|
-
if (!
|
|
15239
|
+
if (!existsSync9(dir))
|
|
15086
15240
|
return [];
|
|
15087
15241
|
return readdirSync6(dir).filter((file) => /\.ya?ml$/.test(file)).sort().map((file) => {
|
|
15088
15242
|
const path = resolve11(dir, file);
|
|
@@ -15317,6 +15471,34 @@ function architectureDocumentationProjectionDrift(input) {
|
|
|
15317
15471
|
const expectedByPath = new Map(input.expectedFiles.map((file) => [file.path, file]));
|
|
15318
15472
|
const targetIds = new Set(input.targets.map((target) => target.targetId));
|
|
15319
15473
|
const diffs = [];
|
|
15474
|
+
const existingManifest = existingByPath.get(input.expectedManifest.path);
|
|
15475
|
+
if (!existingManifest) {
|
|
15476
|
+
diffs.push({
|
|
15477
|
+
path: input.expectedManifest.path,
|
|
15478
|
+
reasonCode: "projection-manifest-missing",
|
|
15479
|
+
expectedDigest: input.expectedManifest.digest
|
|
15480
|
+
});
|
|
15481
|
+
} else {
|
|
15482
|
+
try {
|
|
15483
|
+
const parsed = JSON.parse(existingManifest.body);
|
|
15484
|
+
const actualDigest = digestJson(parsed);
|
|
15485
|
+
if (actualDigest !== input.expectedManifest.digest) {
|
|
15486
|
+
diffs.push({
|
|
15487
|
+
path: input.expectedManifest.path,
|
|
15488
|
+
reasonCode: "projection-manifest-stale",
|
|
15489
|
+
expectedDigest: input.expectedManifest.digest,
|
|
15490
|
+
actualDigest
|
|
15491
|
+
});
|
|
15492
|
+
}
|
|
15493
|
+
} catch {
|
|
15494
|
+
diffs.push({
|
|
15495
|
+
path: input.expectedManifest.path,
|
|
15496
|
+
reasonCode: "projection-manifest-invalid",
|
|
15497
|
+
expectedDigest: input.expectedManifest.digest,
|
|
15498
|
+
actualDigest: digestJson({ path: existingManifest.path, body: existingManifest.body })
|
|
15499
|
+
});
|
|
15500
|
+
}
|
|
15501
|
+
}
|
|
15320
15502
|
for (const expected of input.expectedFiles) {
|
|
15321
15503
|
const existing = existingByPath.get(expected.path);
|
|
15322
15504
|
if (!existing) {
|
|
@@ -15355,6 +15537,8 @@ function architectureDocumentationProjectionDrift(input) {
|
|
|
15355
15537
|
}
|
|
15356
15538
|
}
|
|
15357
15539
|
for (const existing of input.existingFiles) {
|
|
15540
|
+
if (existing.path === input.expectedManifest.path)
|
|
15541
|
+
continue;
|
|
15358
15542
|
if (!isManagedArchitectureDocumentationPath(existing.path) || expectedByPath.has(existing.path))
|
|
15359
15543
|
continue;
|
|
15360
15544
|
const region = findAnyGeneratedRegion(existing.body);
|
|
@@ -15403,7 +15587,7 @@ function generatedEndMarker(targetId) {
|
|
|
15403
15587
|
return `${ARCHITECTURE_DOCS_GENERATED_END_PREFIX} target="${targetId}" -->`;
|
|
15404
15588
|
}
|
|
15405
15589
|
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";
|
|
15590
|
+
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
15591
|
}
|
|
15408
15592
|
function pathSegment2(id) {
|
|
15409
15593
|
return stableId(id).replace(/\./g, "-");
|
|
@@ -16613,7 +16797,7 @@ init_src();
|
|
|
16613
16797
|
|
|
16614
16798
|
// packages/local-runtime/git-adapter/src/index.ts
|
|
16615
16799
|
import { execFileSync as execFileSync4, spawnSync as spawnSync2 } from "node:child_process";
|
|
16616
|
-
import { existsSync as
|
|
16800
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
|
|
16617
16801
|
import { dirname as dirname5, join as join5, resolve as resolve12 } from "node:path";
|
|
16618
16802
|
import { tmpdir } from "node:os";
|
|
16619
16803
|
init_src();
|
|
@@ -16627,7 +16811,7 @@ function findRepositoryRoot2(start) {
|
|
|
16627
16811
|
} catch {
|
|
16628
16812
|
let cursor = resolve12(start);
|
|
16629
16813
|
while (true) {
|
|
16630
|
-
if (
|
|
16814
|
+
if (existsSync10(resolve12(cursor, ".git")))
|
|
16631
16815
|
return cursor;
|
|
16632
16816
|
const parent = dirname5(cursor);
|
|
16633
16817
|
if (parent === cursor)
|
|
@@ -16898,7 +17082,7 @@ function isGitWorktreeError(error) {
|
|
|
16898
17082
|
// packages/local-runtime/local-store-sqlite/src/index.ts
|
|
16899
17083
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
16900
17084
|
import { createHash as createHash6, randomUUID as randomUUID2 } from "node:crypto";
|
|
16901
|
-
import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as
|
|
17085
|
+
import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as existsSync11, fsyncSync as fsyncSync3, lstatSync as lstatSync5, mkdirSync as mkdirSync5, openSync as openSync4, readFileSync as readFileSync9, realpathSync as realpathSync7, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
16902
17086
|
import { readdir, readFile } from "node:fs/promises";
|
|
16903
17087
|
import { createRequire as createRequire3 } from "node:module";
|
|
16904
17088
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -16941,6 +17125,7 @@ var REQUIRED_LOCAL_STORE_TABLES2 = [
|
|
|
16941
17125
|
];
|
|
16942
17126
|
var SQLITE_PRAGMAS2 = [
|
|
16943
17127
|
"PRAGMA journal_mode = WAL",
|
|
17128
|
+
"PRAGMA synchronous = FULL",
|
|
16944
17129
|
"PRAGMA foreign_keys = ON",
|
|
16945
17130
|
"PRAGMA busy_timeout = 5000"
|
|
16946
17131
|
];
|
|
@@ -17462,8 +17647,16 @@ var LOCAL_SQLITE_MIGRATIONS2 = [
|
|
|
17462
17647
|
)`,
|
|
17463
17648
|
"CREATE INDEX IF NOT EXISTS idx_audit_runs_status ON audit_runs(storage_repository_id, storage_workspace_id, status)"
|
|
17464
17649
|
]
|
|
17650
|
+
},
|
|
17651
|
+
{
|
|
17652
|
+
id: "0011_changeset_cleanup_cursor",
|
|
17653
|
+
statements: [
|
|
17654
|
+
"ALTER TABLE changeset_journal ADD COLUMN cleanup_completed_at TEXT",
|
|
17655
|
+
"CREATE INDEX IF NOT EXISTS idx_changeset_journal_cleanup_pending ON changeset_journal(status, cleanup_completed_at, updated_at)"
|
|
17656
|
+
]
|
|
17465
17657
|
}
|
|
17466
17658
|
];
|
|
17659
|
+
var CHANGESET_STARTUP_CLEANUP_LIMIT = 100;
|
|
17467
17660
|
var ARCHCONTEXT_STATE_DIR_ENV2 = "ARCHCONTEXT_STATE_DIR";
|
|
17468
17661
|
var ARCHCONTEXT_LOCAL_STORE_PATH_ENV2 = "ARCHCONTEXT_LOCAL_STORE_PATH";
|
|
17469
17662
|
function defaultArchContextStateRoot2(env = process.env, platform = process.platform, home = homedir2()) {
|
|
@@ -17522,10 +17715,10 @@ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.en
|
|
|
17522
17715
|
});
|
|
17523
17716
|
}
|
|
17524
17717
|
ensurePrivateDir2(dirname6(paths.localStorePath));
|
|
17525
|
-
const legacyExists =
|
|
17718
|
+
const legacyExists = existsSync11(paths.legacyLocalStorePath);
|
|
17526
17719
|
const integrityCheck = {};
|
|
17527
17720
|
const quarantinedFiles = [];
|
|
17528
|
-
const targetExists =
|
|
17721
|
+
const targetExists = existsSync11(paths.localStorePath);
|
|
17529
17722
|
if (targetExists) {
|
|
17530
17723
|
try {
|
|
17531
17724
|
integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
|
|
@@ -17989,6 +18182,11 @@ class SqliteLocalStore {
|
|
|
17989
18182
|
throw new Error(`ChangeSet journal not found: ${journalId}`);
|
|
17990
18183
|
db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("committed", nowIso2(), nowIso2(), journalId);
|
|
17991
18184
|
}
|
|
18185
|
+
async completeChangeSetCleanup(journalId) {
|
|
18186
|
+
const db = await this.database();
|
|
18187
|
+
const completedAt = nowIso2();
|
|
18188
|
+
db.prepare("UPDATE changeset_journal SET cleanup_completed_at = ?, updated_at = ? WHERE journal_id = ? AND status = ?").run(completedAt, completedAt, journalId, "committed");
|
|
18189
|
+
}
|
|
17992
18190
|
async abortChangeSet(journalId, reason) {
|
|
17993
18191
|
const db = await this.database();
|
|
17994
18192
|
const row = db.prepare("SELECT metadata_json FROM changeset_journal WHERE journal_id = ?").get(journalId);
|
|
@@ -17999,37 +18197,61 @@ class SqliteLocalStore {
|
|
|
17999
18197
|
}
|
|
18000
18198
|
recoverPendingChangeSets() {
|
|
18001
18199
|
const db = this.requireOpenDatabase();
|
|
18002
|
-
const committed = db.prepare(
|
|
18200
|
+
const committed = db.prepare(`SELECT journal_id, files_json FROM changeset_journal
|
|
18201
|
+
WHERE status = ? AND cleanup_completed_at IS NULL
|
|
18202
|
+
ORDER BY updated_at, journal_id
|
|
18203
|
+
LIMIT ?`).all("committed", CHANGESET_STARTUP_CLEANUP_LIMIT);
|
|
18003
18204
|
for (const row of committed) {
|
|
18004
|
-
|
|
18205
|
+
try {
|
|
18206
|
+
cleanupCommittedJournalFiles(JSON.parse(String(row.files_json)));
|
|
18207
|
+
const completedAt = nowIso2();
|
|
18208
|
+
db.prepare("UPDATE changeset_journal SET cleanup_completed_at = ?, updated_at = ? WHERE journal_id = ?").run(completedAt, completedAt, String(row.journal_id));
|
|
18209
|
+
} catch {}
|
|
18005
18210
|
}
|
|
18006
18211
|
const rows = db.prepare("SELECT journal_id, root, files_json, metadata_json FROM changeset_journal WHERE status = ?").all("pending");
|
|
18212
|
+
let recovered = 0;
|
|
18007
18213
|
for (const row of rows) {
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
const
|
|
18014
|
-
if (
|
|
18015
|
-
|
|
18214
|
+
let metadata = {};
|
|
18215
|
+
try {
|
|
18216
|
+
const files = JSON.parse(String(row.files_json));
|
|
18217
|
+
metadata = JSON.parse(String(row.metadata_json));
|
|
18218
|
+
const plannedLedgerEvent = changeSetJournalPlannedLedgerEvent(metadata);
|
|
18219
|
+
const existingLedgerEvent = plannedLedgerEvent ? architectureEventByIdempotency(db, plannedLedgerEvent) : undefined;
|
|
18220
|
+
if (plannedLedgerEvent && existingLedgerEvent) {
|
|
18221
|
+
const expectedEventHash = normalizeArchitectureLedgerEvent(plannedLedgerEvent, existingLedgerEvent.previousEventHash).eventHash;
|
|
18222
|
+
if (expectedEventHash !== existingLedgerEvent.event.eventHash) {
|
|
18223
|
+
throw new Error(`changeset-ledger-recovery-idempotency-conflict: ${plannedLedgerEvent.idempotencyKey}`);
|
|
18224
|
+
}
|
|
18225
|
+
cleanupCommittedJournalFiles(files);
|
|
18226
|
+
const completedAt2 = nowIso2();
|
|
18227
|
+
db.prepare("UPDATE changeset_journal SET status = ?, metadata_json = ?, updated_at = ?, completed_at = ?, cleanup_completed_at = ? WHERE journal_id = ?").run("committed", stableJson(withChangeSetJournalArchitectureLedger(metadata, {
|
|
18228
|
+
recovery: {
|
|
18229
|
+
schemaVersion: "archcontext.changeset-ledger-recovery/v1",
|
|
18230
|
+
status: "ledger-append-detected",
|
|
18231
|
+
eventId: existingLedgerEvent.event.eventId,
|
|
18232
|
+
eventHash: existingLedgerEvent.event.eventHash ?? "",
|
|
18233
|
+
recoveredAt: completedAt2
|
|
18234
|
+
}
|
|
18235
|
+
})), completedAt2, completedAt2, completedAt2, String(row.journal_id));
|
|
18236
|
+
recovered += 1;
|
|
18237
|
+
continue;
|
|
18016
18238
|
}
|
|
18017
|
-
|
|
18018
|
-
|
|
18019
|
-
|
|
18020
|
-
|
|
18021
|
-
|
|
18022
|
-
|
|
18023
|
-
|
|
18024
|
-
|
|
18239
|
+
recoverJournalFiles(String(row.root), files);
|
|
18240
|
+
const completedAt = nowIso2();
|
|
18241
|
+
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));
|
|
18242
|
+
recovered += 1;
|
|
18243
|
+
} catch (error) {
|
|
18244
|
+
db.prepare("UPDATE changeset_journal SET metadata_json = ?, updated_at = ? WHERE journal_id = ?").run(stableJson({
|
|
18245
|
+
...metadata,
|
|
18246
|
+
recoveryError: {
|
|
18247
|
+
schemaVersion: "archcontext.changeset-recovery-error/v1",
|
|
18248
|
+
message: error instanceof Error ? error.message : String(error),
|
|
18249
|
+
failedAt: nowIso2()
|
|
18025
18250
|
}
|
|
18026
|
-
})
|
|
18027
|
-
continue;
|
|
18251
|
+
}), nowIso2(), String(row.journal_id));
|
|
18028
18252
|
}
|
|
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
18253
|
}
|
|
18032
|
-
return
|
|
18254
|
+
return recovered;
|
|
18033
18255
|
}
|
|
18034
18256
|
async saveTaskState(taskSessionId, state) {
|
|
18035
18257
|
const db = await this.database();
|
|
@@ -18127,52 +18349,38 @@ class SqliteLocalStore {
|
|
|
18127
18349
|
for (const event of input.events)
|
|
18128
18350
|
validateArchitectureLedgerEvent(event);
|
|
18129
18351
|
const db = await this.database();
|
|
18130
|
-
const startedAt = Date.now();
|
|
18131
|
-
const appendedEvents = [];
|
|
18132
|
-
const duplicateEvents = [];
|
|
18133
18352
|
db.exec("BEGIN IMMEDIATE");
|
|
18134
18353
|
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
|
-
}
|
|
18354
|
+
const result = appendArchitectureEventsInOpenTransaction(db, input);
|
|
18167
18355
|
db.exec("COMMIT");
|
|
18168
|
-
return
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18175
|
-
|
|
18356
|
+
return result;
|
|
18357
|
+
} catch (error) {
|
|
18358
|
+
db.exec("ROLLBACK");
|
|
18359
|
+
throw error;
|
|
18360
|
+
}
|
|
18361
|
+
}
|
|
18362
|
+
async appendArchitectureEventsAndCommitChangeSet(journalId, input) {
|
|
18363
|
+
if (input.writer !== "runtime-daemon")
|
|
18364
|
+
throw new Error("architecture-ledger-writer-must-be-runtime-daemon");
|
|
18365
|
+
for (const event of input.events)
|
|
18366
|
+
validateArchitectureLedgerEvent(event);
|
|
18367
|
+
const db = await this.database();
|
|
18368
|
+
db.exec("BEGIN IMMEDIATE");
|
|
18369
|
+
try {
|
|
18370
|
+
const row = db.prepare("SELECT status, metadata_json FROM changeset_journal WHERE journal_id = ?").get(journalId);
|
|
18371
|
+
if (!row)
|
|
18372
|
+
throw new Error(`ChangeSet journal not found: ${journalId}`);
|
|
18373
|
+
if (String(row.status) !== "pending")
|
|
18374
|
+
throw new Error(`ChangeSet journal is not pending: ${journalId}`);
|
|
18375
|
+
const metadata = JSON.parse(String(row.metadata_json));
|
|
18376
|
+
const result = appendArchitectureEventsInOpenTransaction(db, input);
|
|
18377
|
+
const completedAt = nowIso2();
|
|
18378
|
+
db.prepare("UPDATE changeset_journal SET status = ?, metadata_json = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("committed", stableJson(withChangeSetJournalArchitectureLedger(metadata, {
|
|
18379
|
+
append: changeSetLedgerAppendSummary(result),
|
|
18380
|
+
appendedAt: completedAt
|
|
18381
|
+
})), completedAt, completedAt, journalId);
|
|
18382
|
+
db.exec("COMMIT");
|
|
18383
|
+
return result;
|
|
18176
18384
|
} catch (error) {
|
|
18177
18385
|
db.exec("ROLLBACK");
|
|
18178
18386
|
throw error;
|
|
@@ -18186,24 +18394,50 @@ class SqliteLocalStore {
|
|
|
18186
18394
|
WHERE storage_repository_id = ?
|
|
18187
18395
|
AND storage_workspace_id = ?
|
|
18188
18396
|
${statusClause}
|
|
18189
|
-
ORDER BY created_at DESC, run_id ASC`).all(input.repository.storageRepositoryId, input.worktree
|
|
18397
|
+
ORDER BY created_at DESC, run_id ASC`).all(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), ...statuses).map((row) => JSON.parse(String(row.run_json)));
|
|
18398
|
+
}
|
|
18399
|
+
async resolveArchitectureLedgerScope(input) {
|
|
18400
|
+
const db = await this.database();
|
|
18401
|
+
const rows = db.prepare(`SELECT event_json FROM architecture_events
|
|
18402
|
+
WHERE storage_repository_id = ? AND workspace_id = ? AND branch = ?
|
|
18403
|
+
ORDER BY event_sequence DESC`).all(input.repository.storageRepositoryId, input.worktree.workspaceId, input.worktree.branch);
|
|
18404
|
+
for (const row of rows) {
|
|
18405
|
+
const event = JSON.parse(String(row.event_json));
|
|
18406
|
+
if (event.worktree.storageWorkspaceId === input.worktree.storageWorkspaceId) {
|
|
18407
|
+
return architectureScopeFromEvent(event);
|
|
18408
|
+
}
|
|
18409
|
+
}
|
|
18410
|
+
return input;
|
|
18411
|
+
}
|
|
18412
|
+
async resolveLatestArchitectureLedgerScope(input) {
|
|
18413
|
+
const db = await this.database();
|
|
18414
|
+
const rows = db.prepare(`SELECT event_json FROM architecture_events
|
|
18415
|
+
WHERE storage_repository_id = ? AND workspace_id = ?
|
|
18416
|
+
ORDER BY event_sequence DESC`).all(input.repository.storageRepositoryId, input.worktree.workspaceId);
|
|
18417
|
+
for (const row of rows) {
|
|
18418
|
+
const event = JSON.parse(String(row.event_json));
|
|
18419
|
+
if (event.worktree.storageWorkspaceId === input.worktree.storageWorkspaceId) {
|
|
18420
|
+
return architectureScopeFromEvent(event);
|
|
18421
|
+
}
|
|
18422
|
+
}
|
|
18423
|
+
return input;
|
|
18190
18424
|
}
|
|
18191
18425
|
async getAuditRun(input) {
|
|
18192
18426
|
const db = await this.database();
|
|
18193
18427
|
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.
|
|
18428
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND run_id = ?`).get(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), architectureLedgerStorageId(input.worktree, input.runId));
|
|
18195
18429
|
return row ? JSON.parse(String(row.run_json)) : undefined;
|
|
18196
18430
|
}
|
|
18197
18431
|
async readArchitectureLedgerSourceCursor(input) {
|
|
18198
18432
|
const db = await this.database();
|
|
18199
18433
|
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.
|
|
18434
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND cursor_id = ?`).get(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), architectureLedgerStorageId(input.worktree, input.cursorId));
|
|
18201
18435
|
return row ? JSON.parse(String(row.cursor_json)) : undefined;
|
|
18202
18436
|
}
|
|
18203
18437
|
async createArchitectureLedgerSnapshot(input) {
|
|
18204
18438
|
const db = await this.database();
|
|
18205
18439
|
const startedAt = Date.now();
|
|
18206
|
-
const latest = latestArchitectureEvent(db, input.repository.storageRepositoryId, input.worktree
|
|
18440
|
+
const latest = latestArchitectureEvent(db, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18207
18441
|
if (!latest)
|
|
18208
18442
|
throw new Error("architecture-ledger-snapshot-requires-event");
|
|
18209
18443
|
const state = readArchitectureLedgerStateFromDb(db, input);
|
|
@@ -18217,7 +18451,7 @@ class SqliteLocalStore {
|
|
|
18217
18451
|
(snapshot_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, branch, head_sha, worktree_digest,
|
|
18218
18452
|
source_mode, last_event_id, last_event_hash, graph_digest, projection_digest, entity_count, relation_count,
|
|
18219
18453
|
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
|
|
18454
|
+
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
18455
|
recordArchitectureLedgerOperation(db, {
|
|
18222
18456
|
scope: input,
|
|
18223
18457
|
operationKind: "create_snapshot",
|
|
@@ -18286,16 +18520,16 @@ class SqliteLocalStore {
|
|
|
18286
18520
|
const db = await this.database();
|
|
18287
18521
|
const startedAt = Date.now();
|
|
18288
18522
|
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
|
|
18523
|
+
WHERE snapshot_id = ? AND storage_repository_id = ? AND storage_workspace_id = ?`).get(input.beforeSnapshotId, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18290
18524
|
if (!snapshot)
|
|
18291
18525
|
throw new Error(`architecture-ledger-snapshot-not-found: ${input.beforeSnapshotId}`);
|
|
18292
18526
|
const cursor = db.prepare("SELECT event_sequence FROM architecture_events WHERE event_id = ?").get(String(snapshot.last_event_id));
|
|
18293
18527
|
if (!cursor)
|
|
18294
18528
|
throw new Error(`architecture-ledger-snapshot-cursor-not-found: ${String(snapshot.last_event_id)}`);
|
|
18295
18529
|
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
|
|
18530
|
+
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
18531
|
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
|
|
18532
|
+
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
18533
|
recordArchitectureLedgerOperation(db, {
|
|
18300
18534
|
scope: input,
|
|
18301
18535
|
operationKind: "compact_events",
|
|
@@ -18315,7 +18549,7 @@ class SqliteLocalStore {
|
|
|
18315
18549
|
const replay = await this.verifyArchitectureLedgerReplay(input);
|
|
18316
18550
|
if (!replay.ok)
|
|
18317
18551
|
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
|
|
18552
|
+
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
18553
|
const result = {
|
|
18320
18554
|
ok: failures.length === 0,
|
|
18321
18555
|
graphDigest: replay.materializedDigest,
|
|
@@ -18335,7 +18569,7 @@ class SqliteLocalStore {
|
|
|
18335
18569
|
async backupArchitectureLedger(input) {
|
|
18336
18570
|
const db = await this.database();
|
|
18337
18571
|
ensurePrivateDir2(dirname6(input.backupPath));
|
|
18338
|
-
if (
|
|
18572
|
+
if (existsSync11(input.backupPath))
|
|
18339
18573
|
rmSync5(input.backupPath, { force: true });
|
|
18340
18574
|
db.exec(`VACUUM INTO ${sqliteStringLiteral2(input.backupPath)}`);
|
|
18341
18575
|
return { backupPath: input.backupPath, integrity: assertSqliteIntegrity2(input.backupPath) };
|
|
@@ -18366,9 +18600,80 @@ class SqliteLocalStore {
|
|
|
18366
18600
|
function architectureScopeFromEvent(event) {
|
|
18367
18601
|
return event ? { repository: event.repository, worktree: event.worktree } : undefined;
|
|
18368
18602
|
}
|
|
18603
|
+
function architectureLedgerWorkspaceKey(worktree) {
|
|
18604
|
+
return `ledger-scope:${digestJson({
|
|
18605
|
+
storageWorkspaceId: worktree.storageWorkspaceId,
|
|
18606
|
+
branch: worktree.branch,
|
|
18607
|
+
headSha: worktree.headSha,
|
|
18608
|
+
worktreeDigest: worktree.worktreeDigest
|
|
18609
|
+
}).slice("sha256:".length)}`;
|
|
18610
|
+
}
|
|
18611
|
+
function architectureLedgerStorageId(worktree, logicalId) {
|
|
18612
|
+
return `${architectureLedgerWorkspaceKey(worktree)}:${logicalId}`;
|
|
18613
|
+
}
|
|
18614
|
+
function appendArchitectureEventsInOpenTransaction(db, input) {
|
|
18615
|
+
const startedAt = Date.now();
|
|
18616
|
+
const appendedEvents = [];
|
|
18617
|
+
const duplicateEvents = [];
|
|
18618
|
+
let processed = 0;
|
|
18619
|
+
for (const event of input.events) {
|
|
18620
|
+
const duplicate = architectureEventByIdempotency(db, event);
|
|
18621
|
+
if (duplicate) {
|
|
18622
|
+
const expectedDuplicateHash = normalizeArchitectureLedgerEvent(event, duplicate.previousEventHash).eventHash;
|
|
18623
|
+
if (expectedDuplicateHash !== duplicate.event.eventHash) {
|
|
18624
|
+
throw new Error(`architecture-ledger-idempotency-conflict: ${event.idempotencyKey}`);
|
|
18625
|
+
}
|
|
18626
|
+
duplicateEvents.push(duplicate.event);
|
|
18627
|
+
continue;
|
|
18628
|
+
}
|
|
18629
|
+
const previousEventHash = latestArchitectureEventHash(db, event.repository.storageRepositoryId, architectureLedgerWorkspaceKey(event.worktree));
|
|
18630
|
+
const normalized = normalizeArchitectureLedgerEvent(event, previousEventHash);
|
|
18631
|
+
const operations = architectureLedgerPayload(normalized).operations ?? [];
|
|
18632
|
+
const scope2 = architectureScopeFromEvent(normalized);
|
|
18633
|
+
if (operations.length > 0) {
|
|
18634
|
+
const currentDigest = architectureLedgerStateDigest(readArchitectureLedgerStateFromDb(db, scope2));
|
|
18635
|
+
if (normalized.baseDigest !== currentDigest) {
|
|
18636
|
+
throw new Error(`architecture-ledger-base-digest-conflict: expected ${currentDigest}, received ${normalized.baseDigest}`);
|
|
18637
|
+
}
|
|
18638
|
+
}
|
|
18639
|
+
insertArchitectureEvent(db, normalized);
|
|
18640
|
+
persistArchitectureLedgerArtifacts(db, normalized);
|
|
18641
|
+
materializeArchitectureLedgerEvent(db, normalized);
|
|
18642
|
+
if (operations.length > 0) {
|
|
18643
|
+
const resultingDigest = architectureLedgerStateDigest(readArchitectureLedgerStateFromDb(db, scope2));
|
|
18644
|
+
if (normalized.resultingDigest !== resultingDigest) {
|
|
18645
|
+
throw new Error(`architecture-ledger-resulting-digest-conflict: expected ${resultingDigest}, received ${normalized.resultingDigest}`);
|
|
18646
|
+
}
|
|
18647
|
+
}
|
|
18648
|
+
appendedEvents.push(normalized);
|
|
18649
|
+
processed += 1;
|
|
18650
|
+
if (input.faultAfterEvents !== undefined && processed >= input.faultAfterEvents) {
|
|
18651
|
+
throw new Error("architecture-ledger-fault-injection");
|
|
18652
|
+
}
|
|
18653
|
+
}
|
|
18654
|
+
const scope = architectureScopeFromEvent(input.events[0] ?? duplicateEvents[0]);
|
|
18655
|
+
const state = scope ? readArchitectureLedgerStateFromDb(db, scope) : emptyArchitectureLedgerState();
|
|
18656
|
+
if (scope) {
|
|
18657
|
+
recordArchitectureLedgerOperation(db, {
|
|
18658
|
+
scope,
|
|
18659
|
+
operationKind: "append_events",
|
|
18660
|
+
durationMs: Date.now() - startedAt,
|
|
18661
|
+
rowCount: appendedEvents.length,
|
|
18662
|
+
rebuildReason: null
|
|
18663
|
+
});
|
|
18664
|
+
}
|
|
18665
|
+
return {
|
|
18666
|
+
appendedEvents,
|
|
18667
|
+
duplicateEvents,
|
|
18668
|
+
graphDigest: architectureLedgerStateDigest(state),
|
|
18669
|
+
entityCount: state.entities.length,
|
|
18670
|
+
relationCount: state.relations.length,
|
|
18671
|
+
constraintCount: state.constraints.length
|
|
18672
|
+
};
|
|
18673
|
+
}
|
|
18369
18674
|
function architectureEventByIdempotency(db, event) {
|
|
18370
18675
|
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
|
|
18676
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND idempotency_key = ?`).get(event.repository.storageRepositoryId, architectureLedgerWorkspaceKey(event.worktree), event.idempotencyKey);
|
|
18372
18677
|
return row ? {
|
|
18373
18678
|
event: JSON.parse(String(row.event_json)),
|
|
18374
18679
|
previousEventHash: row.previous_event_hash === null || row.previous_event_hash === undefined ? null : String(row.previous_event_hash)
|
|
@@ -18384,11 +18689,12 @@ function latestArchitectureEvent(db, storageRepositoryId, storageWorkspaceId) {
|
|
|
18384
18689
|
return row ? { event: JSON.parse(String(row.event_json)), eventHash: String(row.event_hash) } : undefined;
|
|
18385
18690
|
}
|
|
18386
18691
|
function insertArchitectureEvent(db, event) {
|
|
18692
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18387
18693
|
db.prepare(`INSERT INTO architecture_events
|
|
18388
18694
|
(event_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, branch, head_sha, worktree_digest,
|
|
18389
18695
|
event_type, payload_version, source, actor_kind, actor_id, base_digest, resulting_digest, previous_event_hash,
|
|
18390
18696
|
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,
|
|
18697
|
+
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
18698
|
insertArchitectureLedgerFts(db, "event", architectureLedgerPayload(event).summary ?? "", architectureLedgerPayload(event).rationale ?? "", architectureLedgerPayload(event).title ?? "", "");
|
|
18393
18699
|
const payload = architectureLedgerPayload(event);
|
|
18394
18700
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
@@ -18402,11 +18708,13 @@ function insertArchitectureEvent(db, event) {
|
|
|
18402
18708
|
}
|
|
18403
18709
|
function persistArchitectureLedgerArtifacts(db, event) {
|
|
18404
18710
|
const payload = architectureLedgerPayload(event);
|
|
18711
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18712
|
+
const storageEventId = architectureLedgerStorageId(event.worktree, event.eventId);
|
|
18405
18713
|
for (const evidence of payload.evidenceItems ?? []) {
|
|
18406
18714
|
db.prepare(`INSERT OR REPLACE INTO evidence_items
|
|
18407
18715
|
(evidence_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, kind, strength,
|
|
18408
18716
|
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,
|
|
18717
|
+
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
18718
|
insertArchitectureLedgerFts(db, "evidence", evidence.summary, "", "", evidence.summary);
|
|
18411
18719
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18412
18720
|
docId: `evidence:${evidence.evidenceId}`,
|
|
@@ -18421,7 +18729,7 @@ function persistArchitectureLedgerArtifacts(db, event) {
|
|
|
18421
18729
|
db.prepare(`INSERT OR REPLACE INTO evidence_bindings
|
|
18422
18730
|
(binding_id, evidence_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id,
|
|
18423
18731
|
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,
|
|
18732
|
+
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
18733
|
}
|
|
18426
18734
|
for (const run of payload.recommendationRuns ?? [])
|
|
18427
18735
|
persistRecommendationRun(db, event, run);
|
|
@@ -18441,17 +18749,19 @@ function persistArchitectureLedgerArtifacts(db, event) {
|
|
|
18441
18749
|
persistProjectionState(db, event, payload.projectionState);
|
|
18442
18750
|
}
|
|
18443
18751
|
function persistRecommendationRun(db, event, run) {
|
|
18752
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18444
18753
|
db.prepare(`INSERT OR REPLACE INTO recommendation_runs
|
|
18445
18754
|
(run_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, status, catalog_digest,
|
|
18446
18755
|
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
|
|
18756
|
+
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
18757
|
}
|
|
18449
18758
|
function persistRecommendation(db, event, recommendation) {
|
|
18759
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18450
18760
|
db.prepare(`INSERT OR REPLACE INTO recommendations
|
|
18451
18761
|
(recommendation_id, run_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, fingerprint,
|
|
18452
18762
|
subject, practice_id, status, confidence, enforcement, risk, uncertainty, evidence_binding_ids_json, explanation_json,
|
|
18453
18763
|
recommendation_json, created_at, updated_at)
|
|
18454
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(recommendation.recommendationId, recommendation.runId, event.repository.repositoryId, event.repository.storageRepositoryId, event.worktree.workspaceId, event.worktree
|
|
18764
|
+
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
18765
|
insertArchitectureLedgerFts(db, "recommendation", recommendation.explanation.join(`
|
|
18456
18766
|
`), "", recommendation.subject, recommendation.explanation.join(`
|
|
18457
18767
|
`));
|
|
@@ -18468,44 +18778,51 @@ function persistRecommendation(db, event, recommendation) {
|
|
|
18468
18778
|
});
|
|
18469
18779
|
}
|
|
18470
18780
|
function persistAgentJob(db, event, job) {
|
|
18781
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18471
18782
|
db.prepare(`INSERT OR REPLACE INTO agent_jobs
|
|
18472
18783
|
(job_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, status, runner_port,
|
|
18473
18784
|
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
|
|
18785
|
+
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
18786
|
}
|
|
18476
18787
|
function persistAuditRun(db, event, run) {
|
|
18788
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18477
18789
|
db.prepare(`INSERT OR REPLACE INTO audit_runs
|
|
18478
18790
|
(run_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, job_id, report_id, status,
|
|
18479
18791
|
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
|
|
18792
|
+
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
18793
|
}
|
|
18482
18794
|
function persistProjectionState(db, event, state) {
|
|
18483
18795
|
const path = String(state.path ?? "projection");
|
|
18484
18796
|
const projectionDigest = typeof state.projectionDigest === "string" ? state.projectionDigest : digestJson(state);
|
|
18797
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18485
18798
|
db.prepare(`INSERT OR REPLACE INTO projection_state
|
|
18486
18799
|
(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
|
|
18800
|
+
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
18801
|
}
|
|
18489
18802
|
function persistSourceCursor(db, event, cursor) {
|
|
18490
18803
|
const source = String(cursor.source ?? event.source);
|
|
18804
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18491
18805
|
db.prepare(`INSERT OR REPLACE INTO source_cursors
|
|
18492
18806
|
(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,
|
|
18807
|
+
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
18808
|
}
|
|
18495
18809
|
function persistGenericLedgerJson(db, event, table, idColumn, jsonColumn, value, prefix) {
|
|
18496
18810
|
const id = String(value[idColumn] ?? value.id ?? stableLedgerId(prefix, event.eventId, stableJson(value)));
|
|
18811
|
+
const storageId = architectureLedgerStorageId(event.worktree, id);
|
|
18812
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18497
18813
|
if (table === "recommendation_feedback") {
|
|
18498
18814
|
db.prepare(`INSERT OR REPLACE INTO recommendation_feedback
|
|
18499
18815
|
(feedback_id, recommendation_id, repository_id, storage_repository_id, workspace_id, storage_workspace_id, event_id, feedback_json, created_at)
|
|
18500
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
18816
|
+
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
18817
|
return;
|
|
18502
18818
|
}
|
|
18503
18819
|
db.prepare(`INSERT OR REPLACE INTO waivers
|
|
18504
18820
|
(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(
|
|
18821
|
+
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
18822
|
}
|
|
18507
18823
|
function materializeArchitectureLedgerEvent(db, event) {
|
|
18508
18824
|
const payload = architectureLedgerPayload(event);
|
|
18825
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18509
18826
|
for (const operation of payload.operations ?? []) {
|
|
18510
18827
|
switch (operation.op) {
|
|
18511
18828
|
case "upsert_entity":
|
|
@@ -18513,31 +18830,32 @@ function materializeArchitectureLedgerEvent(db, event) {
|
|
|
18513
18830
|
break;
|
|
18514
18831
|
case "delete_entity":
|
|
18515
18832
|
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,
|
|
18833
|
+
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);
|
|
18834
|
+
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
18835
|
break;
|
|
18519
18836
|
case "upsert_relation":
|
|
18520
18837
|
upsertArchitectureRelation(db, event, operation.relation);
|
|
18521
18838
|
break;
|
|
18522
18839
|
case "delete_relation":
|
|
18523
18840
|
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,
|
|
18841
|
+
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
18842
|
break;
|
|
18526
18843
|
case "upsert_constraint":
|
|
18527
18844
|
upsertArchitectureConstraint(db, event, operation.constraint);
|
|
18528
18845
|
break;
|
|
18529
18846
|
case "delete_constraint":
|
|
18530
18847
|
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,
|
|
18848
|
+
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
18849
|
break;
|
|
18533
18850
|
}
|
|
18534
18851
|
}
|
|
18535
18852
|
}
|
|
18536
18853
|
function upsertArchitectureEntity(db, event, entity) {
|
|
18854
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18537
18855
|
db.prepare(`INSERT OR REPLACE INTO architecture_entities_current
|
|
18538
18856
|
(storage_repository_id, storage_workspace_id, entity_id, repository_id, workspace_id, branch, head_sha, worktree_digest,
|
|
18539
18857
|
kind, canonical_name, status, path, summary, metadata_json, last_event_id, updated_at)
|
|
18540
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId,
|
|
18858
|
+
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
18859
|
insertArchitectureLedgerFts(db, "entity", entity.summary ?? "", "", entity.canonicalName, "");
|
|
18542
18860
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18543
18861
|
docId: `entity:${entity.entityId}`,
|
|
@@ -18550,10 +18868,11 @@ function upsertArchitectureEntity(db, event, entity) {
|
|
|
18550
18868
|
});
|
|
18551
18869
|
}
|
|
18552
18870
|
function upsertArchitectureRelation(db, event, relation) {
|
|
18871
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18553
18872
|
db.prepare(`INSERT OR REPLACE INTO architecture_relations_current
|
|
18554
18873
|
(storage_repository_id, storage_workspace_id, relation_id, repository_id, workspace_id, branch, head_sha, worktree_digest,
|
|
18555
18874
|
kind, source_entity_id, target_entity_id, status, summary, metadata_json, last_event_id, updated_at)
|
|
18556
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId,
|
|
18875
|
+
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
18876
|
insertArchitectureLedgerFts(db, "relation", relation.summary ?? "", "", relation.relationId, "");
|
|
18558
18877
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18559
18878
|
docId: `relation:${relation.relationId}`,
|
|
@@ -18566,10 +18885,11 @@ function upsertArchitectureRelation(db, event, relation) {
|
|
|
18566
18885
|
});
|
|
18567
18886
|
}
|
|
18568
18887
|
function upsertArchitectureConstraint(db, event, constraint) {
|
|
18888
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18569
18889
|
db.prepare(`INSERT OR REPLACE INTO architecture_constraints_current
|
|
18570
18890
|
(storage_repository_id, storage_workspace_id, constraint_id, repository_id, workspace_id, branch, head_sha, worktree_digest,
|
|
18571
18891
|
kind, subject_id, status, severity, summary, metadata_json, last_event_id, updated_at)
|
|
18572
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.repository.storageRepositoryId,
|
|
18892
|
+
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
18893
|
insertArchitectureLedgerFts(db, "constraint", constraint.summary ?? "", "", constraint.constraintId, "");
|
|
18574
18894
|
insertArchitectureLedgerSearchDoc(db, event, {
|
|
18575
18895
|
docId: `constraint:${constraint.constraintId}`,
|
|
@@ -18582,7 +18902,7 @@ function upsertArchitectureConstraint(db, event, constraint) {
|
|
|
18582
18902
|
});
|
|
18583
18903
|
}
|
|
18584
18904
|
function readArchitectureLedgerStateFromDb(db, scope) {
|
|
18585
|
-
const scopeParams = [scope.repository.storageRepositoryId, scope.worktree
|
|
18905
|
+
const scopeParams = [scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(scope.worktree)];
|
|
18586
18906
|
const entities = db.prepare(`SELECT entity_id, kind, canonical_name, status, path, summary, metadata_json
|
|
18587
18907
|
FROM architecture_entities_current
|
|
18588
18908
|
WHERE storage_repository_id = ? AND storage_workspace_id = ?
|
|
@@ -18623,7 +18943,7 @@ function readArchitectureLedgerStateFromDb(db, scope) {
|
|
|
18623
18943
|
}
|
|
18624
18944
|
function readArchitectureLedgerNeighborhoodFromDb(db, input) {
|
|
18625
18945
|
const depth = Math.max(0, Math.floor(input.depth));
|
|
18626
|
-
const scopeParams = [input.repository.storageRepositoryId, input.worktree
|
|
18946
|
+
const scopeParams = [input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree)];
|
|
18627
18947
|
const entityIds = [...new Set(db.prepare(`WITH RECURSIVE seed(entity_id) AS (
|
|
18628
18948
|
SELECT entity_id FROM architecture_entities_current
|
|
18629
18949
|
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND entity_id = ?
|
|
@@ -18704,42 +19024,43 @@ function architectureEventsForReplay(db, input) {
|
|
|
18704
19024
|
let untilEventId = input.untilEventId;
|
|
18705
19025
|
if (input.snapshotId) {
|
|
18706
19026
|
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
|
|
19027
|
+
WHERE snapshot_id = ? AND storage_repository_id = ? AND storage_workspace_id = ?`).get(input.snapshotId, input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18708
19028
|
if (!snapshot)
|
|
18709
19029
|
throw new Error(`architecture-ledger-snapshot-not-found: ${input.snapshotId}`);
|
|
18710
19030
|
untilEventId = String(snapshot.last_event_id);
|
|
18711
19031
|
}
|
|
18712
19032
|
const rows = db.prepare(`SELECT event_id, event_json FROM architecture_events
|
|
18713
19033
|
WHERE storage_repository_id = ? AND storage_workspace_id = ?
|
|
18714
|
-
ORDER BY event_sequence`).all(input.repository.storageRepositoryId, input.worktree
|
|
19034
|
+
ORDER BY event_sequence`).all(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree));
|
|
18715
19035
|
const events = [];
|
|
18716
19036
|
for (const row of rows) {
|
|
18717
19037
|
const event = JSON.parse(String(row.event_json));
|
|
18718
19038
|
events.push(event);
|
|
18719
|
-
if (untilEventId && String(row.event_id) === untilEventId)
|
|
19039
|
+
if (untilEventId && (String(row.event_id) === untilEventId || event.eventId === untilEventId))
|
|
18720
19040
|
break;
|
|
18721
19041
|
}
|
|
18722
19042
|
return events;
|
|
18723
19043
|
}
|
|
18724
19044
|
function deleteArchitectureCurrentState(db, scope) {
|
|
18725
19045
|
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
|
|
19046
|
+
db.prepare(`DELETE FROM ${table} WHERE storage_repository_id = ? AND storage_workspace_id = ?`).run(scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(scope.worktree));
|
|
18727
19047
|
}
|
|
18728
19048
|
}
|
|
18729
19049
|
function insertArchitectureLedgerFts(db, kind, summary, rationale, title, evidenceSummary) {
|
|
18730
19050
|
db.prepare("INSERT INTO architecture_ledger_fts(kind, summary, rationale, title, evidence_summary) VALUES (?, ?, ?, ?, ?)").run(kind, summary, rationale, title, evidenceSummary);
|
|
18731
19051
|
}
|
|
18732
19052
|
function insertArchitectureLedgerSearchDoc(db, event, doc) {
|
|
19053
|
+
const workspaceKey = architectureLedgerWorkspaceKey(event.worktree);
|
|
18733
19054
|
db.prepare(`DELETE FROM architecture_ledger_search_fts
|
|
18734
|
-
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND doc_id = ?`).run(event.repository.storageRepositoryId,
|
|
19055
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND doc_id = ?`).run(event.repository.storageRepositoryId, workspaceKey, doc.docId);
|
|
18735
19056
|
db.prepare(`INSERT INTO architecture_ledger_search_fts
|
|
18736
19057
|
(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,
|
|
19058
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(doc.docId, event.repository.storageRepositoryId, workspaceKey, doc.targetKind, doc.targetId, doc.subjectId ?? null, doc.title ?? "", doc.summary ?? "", doc.rationale ?? "", doc.evidenceSummary ?? "");
|
|
18738
19059
|
}
|
|
18739
19060
|
function deleteArchitectureLedgerSearchDocs(db, scope, ids) {
|
|
18740
19061
|
for (const id of ids) {
|
|
18741
19062
|
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
|
|
19063
|
+
WHERE storage_repository_id = ? AND storage_workspace_id = ? AND (target_id = ? OR subject_id = ?)`).run(scope.repository.storageRepositoryId, architectureLedgerWorkspaceKey(scope.worktree), id, id);
|
|
18743
19064
|
}
|
|
18744
19065
|
}
|
|
18745
19066
|
function queryArchitectureLedgerSearchFts(db, input) {
|
|
@@ -18753,7 +19074,7 @@ function queryArchitectureLedgerSearchFts(db, input) {
|
|
|
18753
19074
|
WHERE storage_repository_id = ? AND storage_workspace_id = ?
|
|
18754
19075
|
AND architecture_ledger_search_fts MATCH ?
|
|
18755
19076
|
ORDER BY rank, target_kind, target_id
|
|
18756
|
-
LIMIT ?`).all(input.repository.storageRepositoryId, input.worktree
|
|
19077
|
+
LIMIT ?`).all(input.repository.storageRepositoryId, architectureLedgerWorkspaceKey(input.worktree), matchQuery, limit);
|
|
18757
19078
|
return rows.map((row) => {
|
|
18758
19079
|
const title = String(row.title ?? "");
|
|
18759
19080
|
const summary = String(row.summary ?? "");
|
|
@@ -18797,7 +19118,7 @@ function ftsMatchKind(query, doc) {
|
|
|
18797
19118
|
function recordArchitectureLedgerOperation(db, input) {
|
|
18798
19119
|
db.prepare(`INSERT INTO architecture_ledger_operations
|
|
18799
19120
|
(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
|
|
19121
|
+
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
19122
|
}
|
|
18802
19123
|
function stableLedgerId(prefix, ...parts) {
|
|
18803
19124
|
return `${prefix}.${createHash6("sha256").update(parts.join("\x00")).digest("hex").slice(0, 24)}`;
|
|
@@ -18980,7 +19301,7 @@ function assertTrustedLegacyLocalStoreSource2(paths) {
|
|
|
18980
19301
|
if (!stat.isFile()) {
|
|
18981
19302
|
throw new Error(`Legacy SQLite source must be a regular file: ${paths.legacyLocalStorePath}`);
|
|
18982
19303
|
}
|
|
18983
|
-
const sourceRealPath =
|
|
19304
|
+
const sourceRealPath = realpathSync7.native(paths.legacyLocalStorePath);
|
|
18984
19305
|
if (!isPathInsideOrSame2(sourceRealPath, paths.repositoryRoot)) {
|
|
18985
19306
|
throw new Error(`Legacy SQLite source must stay inside the repository root: ${paths.legacyLocalStorePath}`);
|
|
18986
19307
|
}
|
|
@@ -19034,7 +19355,7 @@ function sqliteStringLiteral2(value) {
|
|
|
19034
19355
|
function publishStagedLocalStore2(stagingPath, targetPath) {
|
|
19035
19356
|
for (const suffix of SQLITE_SIDECAR_SUFFIXES2) {
|
|
19036
19357
|
const path = `${targetPath}${suffix}`;
|
|
19037
|
-
if (
|
|
19358
|
+
if (existsSync11(path))
|
|
19038
19359
|
throw new Error(`Cannot publish migrated SQLite over existing target file: ${path}`);
|
|
19039
19360
|
}
|
|
19040
19361
|
renameSync3(stagingPath, targetPath);
|
|
@@ -19106,14 +19427,14 @@ function quarantineExistingLocalStore2(paths) {
|
|
|
19106
19427
|
const quarantinedFiles = [];
|
|
19107
19428
|
for (const suffix of SQLITE_SIDECAR_SUFFIXES2) {
|
|
19108
19429
|
const source = `${paths.localStorePath}${suffix}`;
|
|
19109
|
-
if (!
|
|
19430
|
+
if (!existsSync11(source))
|
|
19110
19431
|
continue;
|
|
19111
19432
|
const target = join6(quarantineDir, `runtime.sqlite${suffix}`);
|
|
19112
19433
|
renameSync3(source, target);
|
|
19113
19434
|
quarantinedFiles.push(target);
|
|
19114
19435
|
}
|
|
19115
19436
|
const markerPath = legacyMigrationMarkerPath2(paths);
|
|
19116
|
-
if (
|
|
19437
|
+
if (existsSync11(markerPath)) {
|
|
19117
19438
|
const target = join6(quarantineDir, LEGACY_MIGRATION_MARKER_FILE2);
|
|
19118
19439
|
renameSync3(markerPath, target);
|
|
19119
19440
|
quarantinedFiles.push(target);
|
|
@@ -19173,7 +19494,7 @@ function resolveMaybeRelative2(base, path) {
|
|
|
19173
19494
|
function canonicalPath2(path) {
|
|
19174
19495
|
const resolved = resolve13(path);
|
|
19175
19496
|
try {
|
|
19176
|
-
return
|
|
19497
|
+
return realpathSync7.native(resolved);
|
|
19177
19498
|
} catch {
|
|
19178
19499
|
return resolved;
|
|
19179
19500
|
}
|
|
@@ -19363,18 +19684,22 @@ function changeSetLedgerAppendSummary(result) {
|
|
|
19363
19684
|
}
|
|
19364
19685
|
function changeSetJournalPlannedLedgerEvent(metadata) {
|
|
19365
19686
|
const architectureLedger = metadata.architectureLedger;
|
|
19366
|
-
if (
|
|
19687
|
+
if (architectureLedger === undefined)
|
|
19367
19688
|
return;
|
|
19689
|
+
if (!isJsonRecord(architectureLedger))
|
|
19690
|
+
throw new Error("changeset-ledger-recovery-metadata-malformed");
|
|
19368
19691
|
const plannedEvent = architectureLedger.plannedEvent;
|
|
19369
|
-
if (
|
|
19692
|
+
if (plannedEvent === undefined)
|
|
19370
19693
|
return;
|
|
19694
|
+
if (!isJsonRecord(plannedEvent))
|
|
19695
|
+
throw new Error("changeset-ledger-recovery-planned-event-malformed");
|
|
19696
|
+
const event = plannedEvent;
|
|
19371
19697
|
try {
|
|
19372
|
-
const event = plannedEvent;
|
|
19373
19698
|
validateArchitectureLedgerEvent(event);
|
|
19374
|
-
|
|
19375
|
-
|
|
19376
|
-
return;
|
|
19699
|
+
} catch (error) {
|
|
19700
|
+
throw new Error(`changeset-ledger-recovery-planned-event-invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
19377
19701
|
}
|
|
19702
|
+
return event;
|
|
19378
19703
|
}
|
|
19379
19704
|
function isJsonRecord(value) {
|
|
19380
19705
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -19384,9 +19709,13 @@ function recoverJournalFiles(root, files) {
|
|
|
19384
19709
|
const absolute = resolve13(root, file.path);
|
|
19385
19710
|
if (file.tempPath)
|
|
19386
19711
|
rmSync5(file.tempPath, { recursive: true, force: true });
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19712
|
+
if (file.existed) {
|
|
19713
|
+
if (file.backupPath && existsSync11(file.backupPath)) {
|
|
19714
|
+
rmSync5(absolute, { recursive: true, force: true });
|
|
19715
|
+
renameSync3(file.backupPath, absolute);
|
|
19716
|
+
}
|
|
19717
|
+
} else {
|
|
19718
|
+
rmSync5(absolute, { recursive: true, force: true });
|
|
19390
19719
|
}
|
|
19391
19720
|
fsyncDirectory3(dirname6(absolute));
|
|
19392
19721
|
}
|
|
@@ -19443,8 +19772,18 @@ async function readRelationFiles(root, relationsDir) {
|
|
|
19443
19772
|
|
|
19444
19773
|
// packages/local-runtime/model-store-yaml/src/index.ts
|
|
19445
19774
|
init_src();
|
|
19446
|
-
import { existsSync as
|
|
19775
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync7, readFileSync as readFileSync10, rmSync as rmSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
19447
19776
|
import { dirname as dirname7, resolve as resolve14 } from "node:path";
|
|
19777
|
+
var GENERATED_ARCHITECTURE_PATH = ".archcontext/generated/ARCHITECTURE.md";
|
|
19778
|
+
var GENERATED_ARCHITECTURE_BODY = [
|
|
19779
|
+
"<!-- Generated by ArchContext. Do not edit by hand. -->",
|
|
19780
|
+
"",
|
|
19781
|
+
"# Architecture",
|
|
19782
|
+
"",
|
|
19783
|
+
"Model projection is generated from `.archcontext/model`.",
|
|
19784
|
+
""
|
|
19785
|
+
].join(`
|
|
19786
|
+
`);
|
|
19448
19787
|
function createDefaultManifest(productId, productName) {
|
|
19449
19788
|
return {
|
|
19450
19789
|
schemaVersion: "archcontext.manifest/v1",
|
|
@@ -19594,16 +19933,50 @@ function initializeArchContextModel(root, productName = "ArchContext Project") {
|
|
|
19594
19933
|
rebuildGeneratedProjection(root);
|
|
19595
19934
|
}
|
|
19596
19935
|
function rebuildGeneratedProjection(root) {
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19936
|
+
for (const operation of planGeneratedProjection(root)) {
|
|
19937
|
+
if (operation.operation === "delete_entity") {
|
|
19938
|
+
rmSync6(resolve14(root, operation.path), { force: true });
|
|
19939
|
+
} else {
|
|
19940
|
+
writeFile(root, operation.path, operation.body);
|
|
19941
|
+
}
|
|
19942
|
+
}
|
|
19943
|
+
}
|
|
19944
|
+
function planGeneratedProjection(root) {
|
|
19945
|
+
const desiredBody = GENERATED_ARCHITECTURE_BODY;
|
|
19946
|
+
const desiredAbsolute = resolve14(root, GENERATED_ARCHITECTURE_PATH);
|
|
19947
|
+
const operations = [];
|
|
19948
|
+
if (!existsSync12(desiredAbsolute) || readFileSync10(desiredAbsolute, "utf8") !== desiredBody) {
|
|
19949
|
+
operations.push({
|
|
19950
|
+
path: GENERATED_ARCHITECTURE_PATH,
|
|
19951
|
+
expectedHash: existsSync12(desiredAbsolute) ? digestJson({ body: readFileSync10(desiredAbsolute, "utf8") }) : "missing",
|
|
19952
|
+
body: desiredBody,
|
|
19953
|
+
operation: "render_projection"
|
|
19954
|
+
});
|
|
19955
|
+
}
|
|
19956
|
+
for (const path of collectGeneratedProjectionFiles(root)) {
|
|
19957
|
+
if (path === GENERATED_ARCHITECTURE_PATH)
|
|
19958
|
+
continue;
|
|
19959
|
+
const body = readFileSync10(resolve14(root, path), "utf8");
|
|
19960
|
+
operations.push({
|
|
19961
|
+
path,
|
|
19962
|
+
expectedHash: digestJson({ body }),
|
|
19963
|
+
body: "",
|
|
19964
|
+
operation: "delete_entity"
|
|
19965
|
+
});
|
|
19966
|
+
}
|
|
19967
|
+
return operations.sort((left, right) => left.path.localeCompare(right.path));
|
|
19968
|
+
}
|
|
19969
|
+
function collectGeneratedProjectionFiles(root) {
|
|
19970
|
+
const generatedRoot = ".archcontext/generated";
|
|
19971
|
+
if (!existsSync12(resolve14(root, generatedRoot)))
|
|
19972
|
+
return [];
|
|
19973
|
+
const walk = (relativeDir) => readdirSync7(resolve14(root, relativeDir), { withFileTypes: true }).flatMap((entry) => {
|
|
19974
|
+
const child = `${relativeDir}/${entry.name}`;
|
|
19975
|
+
if (entry.isDirectory())
|
|
19976
|
+
return walk(child);
|
|
19977
|
+
return entry.isFile() ? [child] : [];
|
|
19978
|
+
});
|
|
19979
|
+
return walk(generatedRoot).sort();
|
|
19607
19980
|
}
|
|
19608
19981
|
|
|
19609
19982
|
class YamlModelStore {
|
|
@@ -19660,7 +20033,7 @@ function collectArchContextFiles(root, entries) {
|
|
|
19660
20033
|
const files = [];
|
|
19661
20034
|
for (const entry of entries) {
|
|
19662
20035
|
const absolute = resolve14(root, entry);
|
|
19663
|
-
if (!
|
|
20036
|
+
if (!existsSync12(absolute))
|
|
19664
20037
|
continue;
|
|
19665
20038
|
const stat = readdirOrFile(absolute);
|
|
19666
20039
|
if (stat === "file") {
|
|
@@ -20075,7 +20448,8 @@ class ArchitectureLedgerReadModelStore {
|
|
|
20075
20448
|
return this.fallback.writeChangeSetPreview(changeSet);
|
|
20076
20449
|
}
|
|
20077
20450
|
async loadLedgerModel(workspace) {
|
|
20078
|
-
const
|
|
20451
|
+
const scope = await this.localStore.resolveArchitectureLedgerScope(architectureLedgerScopeForWorkspace(workspace));
|
|
20452
|
+
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
20079
20453
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state).map((file) => ({
|
|
20080
20454
|
path: file.path,
|
|
20081
20455
|
body: file.body,
|
|
@@ -20159,7 +20533,7 @@ class ArchctxDaemon {
|
|
|
20159
20533
|
this.readModelStore = new ArchitectureLedgerReadModelStore(this.modelStore, this.localStore, this.architectureLedger);
|
|
20160
20534
|
this.changeSetEngine = deps.changeSetEngine ?? new ChangeSetEngine({
|
|
20161
20535
|
modelStore: this.modelStore,
|
|
20162
|
-
projection: {
|
|
20536
|
+
projection: { planGeneratedProjection },
|
|
20163
20537
|
journal: this.localStore
|
|
20164
20538
|
});
|
|
20165
20539
|
this.devicePrivateKeySigner = deps.devicePrivateKeySigner;
|
|
@@ -21111,7 +21485,7 @@ class ArchctxDaemon {
|
|
|
21111
21485
|
const absolute = resolve15(session.workspace.root, path);
|
|
21112
21486
|
const body = `${JSON.stringify(waiver, null, 2)}
|
|
21113
21487
|
`;
|
|
21114
|
-
const expectedHash =
|
|
21488
|
+
const expectedHash = existsSync13(absolute) ? digestJson({ body: readFileSync11(absolute, "utf8") }) : "missing";
|
|
21115
21489
|
const draft = this.changeSetEngine.plan({
|
|
21116
21490
|
id: input.id ?? `changeset.practice-waiver-${waiverId.replace(/[^A-Za-z0-9_-]/g, "-")}`,
|
|
21117
21491
|
base: {
|
|
@@ -21450,6 +21824,16 @@ class ArchctxDaemon {
|
|
|
21450
21824
|
const draft = this.changesets.get(input.id);
|
|
21451
21825
|
if (!draft)
|
|
21452
21826
|
throw new Error(`Unknown ChangeSet: ${input.id}`);
|
|
21827
|
+
if (draft.base.headSha !== session.workspace.headSha)
|
|
21828
|
+
throw new Error("ChangeSet HEAD changed before apply");
|
|
21829
|
+
if (draft.base.worktreeDigest !== current)
|
|
21830
|
+
throw new Error("ChangeSet worktree digest changed before apply");
|
|
21831
|
+
const currentModel = await this.readModelStore.validateModel(session.workspace);
|
|
21832
|
+
if (!currentModel.valid) {
|
|
21833
|
+
throw new Error(`ChangeSet base model is invalid: ${currentModel.errors.join("; ") || "unknown validation error"}`);
|
|
21834
|
+
}
|
|
21835
|
+
if (draft.base.modelDigest !== currentModel.modelDigest)
|
|
21836
|
+
throw new Error("ChangeSet model digest changed before apply");
|
|
21453
21837
|
const approved = input.approved ? this.changeSetEngine.approve(draft) : draft;
|
|
21454
21838
|
let ledgerAppend;
|
|
21455
21839
|
const writesLedger = architectureLedgerWriteAppendsEvents(this.architectureLedger.writeMode);
|
|
@@ -21466,6 +21850,7 @@ class ArchctxDaemon {
|
|
|
21466
21850
|
relationCount: appended.relationCount,
|
|
21467
21851
|
constraintCount: appended.constraintCount
|
|
21468
21852
|
};
|
|
21853
|
+
return { journalCommitted: Boolean(journalId) };
|
|
21469
21854
|
} : undefined
|
|
21470
21855
|
});
|
|
21471
21856
|
return okEnvelope("apply_update", {
|
|
@@ -21499,14 +21884,72 @@ class ArchctxDaemon {
|
|
|
21499
21884
|
});
|
|
21500
21885
|
if (journalId)
|
|
21501
21886
|
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 });
|
|
21887
|
+
const appendInput = { writer: "runtime-daemon", events: [plan.event] };
|
|
21888
|
+
const result = journalId ? await this.localStore.appendArchitectureEventsAndCommitChangeSet(journalId, appendInput) : await this.localStore.appendArchitectureEvents(appendInput);
|
|
21508
21889
|
return result;
|
|
21509
21890
|
}
|
|
21891
|
+
async applyArchitectureProjectionChangeSet(root, input) {
|
|
21892
|
+
const session = await this.openSession(root);
|
|
21893
|
+
const model = await this.modelStore.validateModel(session.workspace);
|
|
21894
|
+
if (!model.valid)
|
|
21895
|
+
throw new Error(`Architecture projection ChangeSet base model is invalid: ${model.errors.join("; ")}`);
|
|
21896
|
+
const projectionFiles = input.files.map((file) => ({
|
|
21897
|
+
path: file.path,
|
|
21898
|
+
body: file.body.endsWith(`
|
|
21899
|
+
`) ? file.body : `${file.body}
|
|
21900
|
+
`,
|
|
21901
|
+
expectedHash: expectedFileHash(root, file.path)
|
|
21902
|
+
}));
|
|
21903
|
+
const operations = [
|
|
21904
|
+
...projectionFiles.length > 0 ? [{ op: "render_projection", expectedHash: "missing", projectionFiles }] : [],
|
|
21905
|
+
...input.removedPaths.map((path) => ({
|
|
21906
|
+
op: "delete_entity",
|
|
21907
|
+
path,
|
|
21908
|
+
expectedHash: expectedFileHash(root, path)
|
|
21909
|
+
}))
|
|
21910
|
+
];
|
|
21911
|
+
const draft = this.changeSetEngine.approve(this.changeSetEngine.plan({
|
|
21912
|
+
id: input.id,
|
|
21913
|
+
base: {
|
|
21914
|
+
headSha: session.workspace.headSha,
|
|
21915
|
+
worktreeDigest: session.snapshot.worktreeDigest,
|
|
21916
|
+
modelDigest: model.modelDigest
|
|
21917
|
+
},
|
|
21918
|
+
reason: { taskSessionId: input.id },
|
|
21919
|
+
operations
|
|
21920
|
+
}));
|
|
21921
|
+
await this.changeSetEngine.apply(root, draft, { approved: true });
|
|
21922
|
+
}
|
|
21923
|
+
async applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentFiles, createdAt) {
|
|
21924
|
+
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
21925
|
+
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment(createdAt)}`;
|
|
21926
|
+
const backupRelativePath = uniqueBackupPath(root, backupBase);
|
|
21927
|
+
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
21928
|
+
const { backup, manifest } = architectureProjectionRollbackBackup(currentFiles, {
|
|
21929
|
+
createdAt,
|
|
21930
|
+
path: backupRelativePath,
|
|
21931
|
+
manifestPath
|
|
21932
|
+
});
|
|
21933
|
+
const removedPaths = currentFiles.filter((file) => !targetPaths.has(file.path)).map((file) => file.path);
|
|
21934
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
21935
|
+
id: `changeset.ledger-rollback-${shortDigest3(digestJson({ createdAt, projectionDigest: architectureLedgerProjectionDigest(projectedFiles) }))}`,
|
|
21936
|
+
files: [
|
|
21937
|
+
...currentFiles.map((file) => ({
|
|
21938
|
+
path: join8(backupRelativePath, archContextRelativePath(file.path)),
|
|
21939
|
+
body: file.body
|
|
21940
|
+
})),
|
|
21941
|
+
{ path: manifestPath, body: `${JSON.stringify(manifest, null, 2)}
|
|
21942
|
+
` },
|
|
21943
|
+
...projectedFiles.map(({ path, body }) => ({ path, body }))
|
|
21944
|
+
],
|
|
21945
|
+
removedPaths
|
|
21946
|
+
});
|
|
21947
|
+
return {
|
|
21948
|
+
backup,
|
|
21949
|
+
writtenPaths: projectedFiles.map((file) => file.path),
|
|
21950
|
+
removedPaths
|
|
21951
|
+
};
|
|
21952
|
+
}
|
|
21510
21953
|
async ledgerState(root) {
|
|
21511
21954
|
this.assertRunning();
|
|
21512
21955
|
return okEnvelope("ledger.state", await this.architectureLedgerReadback(root));
|
|
@@ -21860,8 +22303,13 @@ class ArchctxDaemon {
|
|
|
21860
22303
|
const scope = await this.architectureLedgerScope(root);
|
|
21861
22304
|
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
21862
22305
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
21863
|
-
if (writes)
|
|
21864
|
-
|
|
22306
|
+
if (writes) {
|
|
22307
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
22308
|
+
id: `changeset.ledger-project-${shortDigest3(architectureLedgerProjectionDigest(projectedFiles))}`,
|
|
22309
|
+
files: projectedFiles.map(({ path, body }) => ({ path, body })),
|
|
22310
|
+
removedPaths: []
|
|
22311
|
+
});
|
|
22312
|
+
}
|
|
21865
22313
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
21866
22314
|
state,
|
|
21867
22315
|
files: listModelFiles(root),
|
|
@@ -22011,7 +22459,7 @@ class ArchctxDaemon {
|
|
|
22011
22459
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
22012
22460
|
const currentManagedFiles = listModelFiles(root).filter((file) => isArchitectureLedgerManagedModelPath(file.path));
|
|
22013
22461
|
const backupPlan = architectureProjectionRollbackBackup(currentManagedFiles);
|
|
22014
|
-
const writeResult = writes ?
|
|
22462
|
+
const writeResult = writes ? await this.applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentManagedFiles, this.clock()) : { backup: backupPlan.backup, writtenPaths: [], removedPaths: [] };
|
|
22015
22463
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
22016
22464
|
state,
|
|
22017
22465
|
files: listModelFiles(root),
|
|
@@ -22050,9 +22498,12 @@ class ArchctxDaemon {
|
|
|
22050
22498
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild currently requires --from-git");
|
|
22051
22499
|
return this.withWriter(async () => {
|
|
22052
22500
|
this.assertFreshWorktree(root, input.expectedWorktreeDigest, "ledger rebuild --from-git");
|
|
22053
|
-
const scope = await this.
|
|
22501
|
+
const scope = await this.architectureLedgerGitScope(root);
|
|
22054
22502
|
const files = listModelFiles(root);
|
|
22055
|
-
const
|
|
22503
|
+
const exactReplay = await this.localStore.replayArchitectureLedger(scope);
|
|
22504
|
+
const exactScopeHasEvents = exactReplay.events.length > 0;
|
|
22505
|
+
const authorityScope = exactScopeHasEvents ? scope : await this.localStore.resolveLatestArchitectureLedgerScope(scope);
|
|
22506
|
+
const previousState = exactScopeHasEvents ? exactReplay.state : await this.localStore.readArchitectureLedgerState(authorityScope);
|
|
22056
22507
|
const previousGraphDigest = architectureLedgerStateDigest(previousState);
|
|
22057
22508
|
const rebuildCommand = input.acceptExternalProjection ? "archctx ledger rebuild --from-git --accept-external-projection" : "archctx ledger rebuild --from-git";
|
|
22058
22509
|
const plan = planYamlToArchitectureLedgerRebuild({
|
|
@@ -22062,12 +22513,18 @@ class ArchctxDaemon {
|
|
|
22062
22513
|
command: rebuildCommand,
|
|
22063
22514
|
previousState
|
|
22064
22515
|
});
|
|
22516
|
+
const importPlan = planYamlToArchitectureLedgerImport({
|
|
22517
|
+
...scope,
|
|
22518
|
+
files,
|
|
22519
|
+
createdAt: this.clock(),
|
|
22520
|
+
command: rebuildCommand
|
|
22521
|
+
});
|
|
22065
22522
|
if (plan.unsupportedFiles.length > 0) {
|
|
22066
22523
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild requires supported YAML model files");
|
|
22067
22524
|
}
|
|
22068
22525
|
const cursor = architectureLedgerGitCursorFromPlan({ ...scope, plan });
|
|
22069
22526
|
const previousCursor = await this.localStore.readArchitectureLedgerSourceCursor({
|
|
22070
|
-
...
|
|
22527
|
+
...authorityScope,
|
|
22071
22528
|
cursorId: ARCHITECTURE_LEDGER_GIT_CURSOR_ID
|
|
22072
22529
|
});
|
|
22073
22530
|
const cursorChanged = previousCursor?.cursorDigest !== cursor.cursorDigest;
|
|
@@ -22083,7 +22540,13 @@ class ArchctxDaemon {
|
|
|
22083
22540
|
let rebuildStatus = "unchanged";
|
|
22084
22541
|
let proposedExternalProjectionChange;
|
|
22085
22542
|
if (previousGraphDigest === plan.graphDigest) {
|
|
22086
|
-
if (
|
|
22543
|
+
if (!exactScopeHasEvents) {
|
|
22544
|
+
append = await this.localStore.appendArchitectureEvents({
|
|
22545
|
+
writer: "runtime-daemon",
|
|
22546
|
+
events: [importPlan.event]
|
|
22547
|
+
});
|
|
22548
|
+
rebuildStatus = isEmptyArchitectureLedgerState(previousState) ? "rebuilt" : "cursor-refreshed";
|
|
22549
|
+
} else if (cursorChanged) {
|
|
22087
22550
|
const cursorPlan = planGitCursorRefreshToArchitectureLedgerEvent({
|
|
22088
22551
|
...scope,
|
|
22089
22552
|
cursor,
|
|
@@ -22099,7 +22562,7 @@ class ArchctxDaemon {
|
|
|
22099
22562
|
}
|
|
22100
22563
|
} else if (!previousStateEmpty && !input.acceptExternalProjection) {
|
|
22101
22564
|
const proposal = planExternalProjectionChangeToArchitectureLedgerEvent({
|
|
22102
|
-
...
|
|
22565
|
+
...authorityScope,
|
|
22103
22566
|
files,
|
|
22104
22567
|
createdAt: this.clock(),
|
|
22105
22568
|
command: rebuildCommand,
|
|
@@ -22122,11 +22585,12 @@ class ArchctxDaemon {
|
|
|
22122
22585
|
} else {
|
|
22123
22586
|
append = await this.localStore.appendArchitectureEvents({
|
|
22124
22587
|
writer: "runtime-daemon",
|
|
22125
|
-
events: [plan.event]
|
|
22588
|
+
events: [exactScopeHasEvents ? plan.event : importPlan.event]
|
|
22126
22589
|
});
|
|
22127
22590
|
rebuildStatus = previousStateEmpty ? "rebuilt" : "external-projection-accepted";
|
|
22128
22591
|
}
|
|
22129
|
-
const
|
|
22592
|
+
const replayScope = rebuildStatus === "external-projection-proposed" ? authorityScope : scope;
|
|
22593
|
+
const replay = await this.localStore.rebuildArchitectureLedgerCurrentState(replayScope);
|
|
22130
22594
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
22131
22595
|
state: replay.state,
|
|
22132
22596
|
files: listModelFiles(root),
|
|
@@ -22272,6 +22736,9 @@ class ArchctxDaemon {
|
|
|
22272
22736
|
return this.running ? this.architectureLedgerContextPort(root) : undefined;
|
|
22273
22737
|
}
|
|
22274
22738
|
async architectureLedgerScope(root) {
|
|
22739
|
+
return this.localStore.resolveArchitectureLedgerScope(await this.architectureLedgerGitScope(root));
|
|
22740
|
+
}
|
|
22741
|
+
async architectureLedgerGitScope(root) {
|
|
22275
22742
|
const session = await this.openSession(root);
|
|
22276
22743
|
const paths = runtimeStatePaths2(root);
|
|
22277
22744
|
return {
|
|
@@ -22334,7 +22801,7 @@ class ArchctxDaemon {
|
|
|
22334
22801
|
cleanup: "remove-run-root"
|
|
22335
22802
|
}
|
|
22336
22803
|
};
|
|
22337
|
-
if (
|
|
22804
|
+
if (existsSync13(paths.lockPath) || existsSync13(paths.manifestPath)) {
|
|
22338
22805
|
removePathWithRetry(paths.runRoot);
|
|
22339
22806
|
throw new Error(`developer-review-run-already-active: ${input.challenge.challengeId}`);
|
|
22340
22807
|
}
|
|
@@ -22391,7 +22858,7 @@ class ArchctxDaemon {
|
|
|
22391
22858
|
const errors = [];
|
|
22392
22859
|
if (run.worktree) {
|
|
22393
22860
|
try {
|
|
22394
|
-
const hadWorktree =
|
|
22861
|
+
const hadWorktree = existsSync13(run.worktree.worktreeRoot);
|
|
22395
22862
|
removeDetachedReviewWorktree(run.worktree);
|
|
22396
22863
|
if (hadWorktree)
|
|
22397
22864
|
removed.push("worktree");
|
|
@@ -22405,7 +22872,7 @@ class ArchctxDaemon {
|
|
|
22405
22872
|
["lock", run.lockPath]
|
|
22406
22873
|
]) {
|
|
22407
22874
|
try {
|
|
22408
|
-
const existed =
|
|
22875
|
+
const existed = existsSync13(path);
|
|
22409
22876
|
removePathWithRetry(path);
|
|
22410
22877
|
if (existed)
|
|
22411
22878
|
removed.push(kind);
|
|
@@ -22434,7 +22901,7 @@ class ArchctxDaemon {
|
|
|
22434
22901
|
removedLocks: [],
|
|
22435
22902
|
skippedActive: []
|
|
22436
22903
|
};
|
|
22437
|
-
if (!
|
|
22904
|
+
if (!existsSync13(stateDir))
|
|
22438
22905
|
return recovery;
|
|
22439
22906
|
for (const entry of readdirSync8(stateDir).sort()) {
|
|
22440
22907
|
if (!entry.endsWith(".json"))
|
|
@@ -22802,7 +23269,7 @@ class ArchctxDaemon {
|
|
|
22802
23269
|
}
|
|
22803
23270
|
async restoreRepositorySessions() {
|
|
22804
23271
|
for (const record of await this.localStore.listRepositorySessions()) {
|
|
22805
|
-
if (!record.root || !
|
|
23272
|
+
if (!record.root || !existsSync13(record.root))
|
|
22806
23273
|
continue;
|
|
22807
23274
|
if (repositoryFingerprint2(record.root) !== record.repositoryId)
|
|
22808
23275
|
continue;
|
|
@@ -23595,7 +24062,7 @@ function recoverStaleDaemonControlFiles(root = process.cwd(), options = {}) {
|
|
|
23595
24062
|
rmSync8(connectionPath, { force: true });
|
|
23596
24063
|
removed.push(connectionReason);
|
|
23597
24064
|
}
|
|
23598
|
-
if (
|
|
24065
|
+
if (existsSync13(lockPath) && isStaleLock(lockPath)) {
|
|
23599
24066
|
rmSync8(lockPath, { force: true });
|
|
23600
24067
|
removed.push("stale-lock-file");
|
|
23601
24068
|
}
|
|
@@ -24043,14 +24510,14 @@ function expandWorkspacePackageJson(root, pattern) {
|
|
|
24043
24510
|
return [];
|
|
24044
24511
|
if (!pattern.includes("*")) {
|
|
24045
24512
|
const path = resolve15(root, pattern, "package.json");
|
|
24046
|
-
return
|
|
24513
|
+
return existsSync13(path) ? [path] : [];
|
|
24047
24514
|
}
|
|
24048
24515
|
if (!pattern.endsWith("/*"))
|
|
24049
24516
|
return [];
|
|
24050
24517
|
const base = resolve15(root, pattern.slice(0, -2));
|
|
24051
|
-
if (!
|
|
24518
|
+
if (!existsSync13(base) || !statSync6(base).isDirectory())
|
|
24052
24519
|
return [];
|
|
24053
|
-
return readdirSync8(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve15(base, entry.name, "package.json")).filter((path) =>
|
|
24520
|
+
return readdirSync8(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve15(base, entry.name, "package.json")).filter((path) => existsSync13(path));
|
|
24054
24521
|
}
|
|
24055
24522
|
function exactVersionFromManifest(manifest, packageName) {
|
|
24056
24523
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest))
|
|
@@ -24066,7 +24533,7 @@ function exactVersionFromManifest(manifest, packageName) {
|
|
|
24066
24533
|
return;
|
|
24067
24534
|
}
|
|
24068
24535
|
function readJsonFile(path) {
|
|
24069
|
-
if (!
|
|
24536
|
+
if (!existsSync13(path))
|
|
24070
24537
|
return;
|
|
24071
24538
|
try {
|
|
24072
24539
|
return JSON.parse(readFileSync11(path, "utf8"));
|
|
@@ -24079,7 +24546,7 @@ function isExactPackageVersion(value) {
|
|
|
24079
24546
|
}
|
|
24080
24547
|
function readContext7Lockfile(root) {
|
|
24081
24548
|
const path = resolve15(root, CONTEXT7_LOCKFILE);
|
|
24082
|
-
if (!
|
|
24549
|
+
if (!existsSync13(path)) {
|
|
24083
24550
|
return {
|
|
24084
24551
|
schemaVersion: CONTEXT7_LOCKFILE_SCHEMA_VERSION,
|
|
24085
24552
|
provider: "context7",
|
|
@@ -24328,48 +24795,9 @@ function auditApproveResultPayload(runId, status, totalCount, issuedIssues) {
|
|
|
24328
24795
|
issuedIssues
|
|
24329
24796
|
};
|
|
24330
24797
|
}
|
|
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
|
-
};
|
|
24798
|
+
function expectedFileHash(root, path) {
|
|
24799
|
+
const absolute = resolve15(root, path);
|
|
24800
|
+
return existsSync13(absolute) ? digestJson({ body: readFileSync11(absolute, "utf8") }) : "missing";
|
|
24373
24801
|
}
|
|
24374
24802
|
function architectureProjectionRollbackBackup(files, options = {}) {
|
|
24375
24803
|
const manifest = {
|
|
@@ -24396,7 +24824,7 @@ function architectureProjectionRollbackBackup(files, options = {}) {
|
|
|
24396
24824
|
function uniqueBackupPath(root, backupBase) {
|
|
24397
24825
|
let candidate = backupBase;
|
|
24398
24826
|
let suffix = 2;
|
|
24399
|
-
while (
|
|
24827
|
+
while (existsSync13(resolve15(root, candidate))) {
|
|
24400
24828
|
candidate = `${backupBase}-${suffix}`;
|
|
24401
24829
|
suffix += 1;
|
|
24402
24830
|
}
|
|
@@ -24405,7 +24833,7 @@ function uniqueBackupPath(root, backupBase) {
|
|
|
24405
24833
|
function uniqueRuntimeBackupPath(backupBase) {
|
|
24406
24834
|
let candidate = backupBase;
|
|
24407
24835
|
let suffix = 2;
|
|
24408
|
-
while (
|
|
24836
|
+
while (existsSync13(candidate)) {
|
|
24409
24837
|
candidate = backupBase.replace(/\.sqlite$/, `-${suffix}.sqlite`);
|
|
24410
24838
|
suffix += 1;
|
|
24411
24839
|
}
|
|
@@ -24450,7 +24878,7 @@ function isValidRuntimeRpcConnection(value) {
|
|
|
24450
24878
|
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
24879
|
}
|
|
24452
24880
|
function staleConnectionFileReason(path, removeUnhealthyConnection) {
|
|
24453
|
-
if (!
|
|
24881
|
+
if (!existsSync13(path))
|
|
24454
24882
|
return;
|
|
24455
24883
|
try {
|
|
24456
24884
|
if (!isPrivateControlFile(path))
|
|
@@ -24512,7 +24940,7 @@ function parsePracticeCheckpointBaselineState(state, repositoryId, taskSessionId
|
|
|
24512
24940
|
return record;
|
|
24513
24941
|
}
|
|
24514
24942
|
function completeTaskProjectionDrift(root) {
|
|
24515
|
-
if (!
|
|
24943
|
+
if (!existsSync13(resolve15(root, "docs/architecture/.projection-manifest.json")))
|
|
24516
24944
|
return;
|
|
24517
24945
|
const loaded = loadArchitectureDocumentationInputs(root);
|
|
24518
24946
|
const sourceDigest = architectureDocumentationSourceDigest({
|
|
@@ -24788,7 +25216,7 @@ init_src();
|
|
|
24788
25216
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
24789
25217
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
24790
25218
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
24791
|
-
import { chmodSync as chmodSync4, closeSync as closeSync6, existsSync as
|
|
25219
|
+
import { chmodSync as chmodSync4, closeSync as closeSync6, existsSync as existsSync14, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync5, openSync as openSync6, readdirSync as readdirSync9, readFileSync as readFileSync12, rmSync as rmSync9, statSync as statSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24792
25220
|
import { createServer as createServer2 } from "node:http";
|
|
24793
25221
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
24794
25222
|
import { dirname as dirname9, join as join9, resolve as resolve16 } from "node:path";
|
|
@@ -24901,7 +25329,8 @@ class ArchitectureLedgerReadModelStore2 {
|
|
|
24901
25329
|
return this.fallback.writeChangeSetPreview(changeSet);
|
|
24902
25330
|
}
|
|
24903
25331
|
async loadLedgerModel(workspace) {
|
|
24904
|
-
const
|
|
25332
|
+
const scope = await this.localStore.resolveArchitectureLedgerScope(architectureLedgerScopeForWorkspace2(workspace));
|
|
25333
|
+
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
24905
25334
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state).map((file) => ({
|
|
24906
25335
|
path: file.path,
|
|
24907
25336
|
body: file.body,
|
|
@@ -24985,7 +25414,7 @@ class ArchctxDaemon2 {
|
|
|
24985
25414
|
this.readModelStore = new ArchitectureLedgerReadModelStore2(this.modelStore, this.localStore, this.architectureLedger);
|
|
24986
25415
|
this.changeSetEngine = deps.changeSetEngine ?? new ChangeSetEngine({
|
|
24987
25416
|
modelStore: this.modelStore,
|
|
24988
|
-
projection: {
|
|
25417
|
+
projection: { planGeneratedProjection },
|
|
24989
25418
|
journal: this.localStore
|
|
24990
25419
|
});
|
|
24991
25420
|
this.devicePrivateKeySigner = deps.devicePrivateKeySigner;
|
|
@@ -25937,7 +26366,7 @@ class ArchctxDaemon2 {
|
|
|
25937
26366
|
const absolute = resolve16(session.workspace.root, path);
|
|
25938
26367
|
const body = `${JSON.stringify(waiver, null, 2)}
|
|
25939
26368
|
`;
|
|
25940
|
-
const expectedHash =
|
|
26369
|
+
const expectedHash = existsSync14(absolute) ? digestJson({ body: readFileSync12(absolute, "utf8") }) : "missing";
|
|
25941
26370
|
const draft = this.changeSetEngine.plan({
|
|
25942
26371
|
id: input.id ?? `changeset.practice-waiver-${waiverId.replace(/[^A-Za-z0-9_-]/g, "-")}`,
|
|
25943
26372
|
base: {
|
|
@@ -26276,6 +26705,16 @@ class ArchctxDaemon2 {
|
|
|
26276
26705
|
const draft = this.changesets.get(input.id);
|
|
26277
26706
|
if (!draft)
|
|
26278
26707
|
throw new Error(`Unknown ChangeSet: ${input.id}`);
|
|
26708
|
+
if (draft.base.headSha !== session.workspace.headSha)
|
|
26709
|
+
throw new Error("ChangeSet HEAD changed before apply");
|
|
26710
|
+
if (draft.base.worktreeDigest !== current)
|
|
26711
|
+
throw new Error("ChangeSet worktree digest changed before apply");
|
|
26712
|
+
const currentModel = await this.readModelStore.validateModel(session.workspace);
|
|
26713
|
+
if (!currentModel.valid) {
|
|
26714
|
+
throw new Error(`ChangeSet base model is invalid: ${currentModel.errors.join("; ") || "unknown validation error"}`);
|
|
26715
|
+
}
|
|
26716
|
+
if (draft.base.modelDigest !== currentModel.modelDigest)
|
|
26717
|
+
throw new Error("ChangeSet model digest changed before apply");
|
|
26279
26718
|
const approved = input.approved ? this.changeSetEngine.approve(draft) : draft;
|
|
26280
26719
|
let ledgerAppend;
|
|
26281
26720
|
const writesLedger = architectureLedgerWriteAppendsEvents2(this.architectureLedger.writeMode);
|
|
@@ -26292,6 +26731,7 @@ class ArchctxDaemon2 {
|
|
|
26292
26731
|
relationCount: appended.relationCount,
|
|
26293
26732
|
constraintCount: appended.constraintCount
|
|
26294
26733
|
};
|
|
26734
|
+
return { journalCommitted: Boolean(journalId) };
|
|
26295
26735
|
} : undefined
|
|
26296
26736
|
});
|
|
26297
26737
|
return okEnvelope("apply_update", {
|
|
@@ -26325,14 +26765,72 @@ class ArchctxDaemon2 {
|
|
|
26325
26765
|
});
|
|
26326
26766
|
if (journalId)
|
|
26327
26767
|
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 });
|
|
26768
|
+
const appendInput = { writer: "runtime-daemon", events: [plan.event] };
|
|
26769
|
+
const result = journalId ? await this.localStore.appendArchitectureEventsAndCommitChangeSet(journalId, appendInput) : await this.localStore.appendArchitectureEvents(appendInput);
|
|
26334
26770
|
return result;
|
|
26335
26771
|
}
|
|
26772
|
+
async applyArchitectureProjectionChangeSet(root, input) {
|
|
26773
|
+
const session = await this.openSession(root);
|
|
26774
|
+
const model = await this.modelStore.validateModel(session.workspace);
|
|
26775
|
+
if (!model.valid)
|
|
26776
|
+
throw new Error(`Architecture projection ChangeSet base model is invalid: ${model.errors.join("; ")}`);
|
|
26777
|
+
const projectionFiles = input.files.map((file) => ({
|
|
26778
|
+
path: file.path,
|
|
26779
|
+
body: file.body.endsWith(`
|
|
26780
|
+
`) ? file.body : `${file.body}
|
|
26781
|
+
`,
|
|
26782
|
+
expectedHash: expectedFileHash2(root, file.path)
|
|
26783
|
+
}));
|
|
26784
|
+
const operations = [
|
|
26785
|
+
...projectionFiles.length > 0 ? [{ op: "render_projection", expectedHash: "missing", projectionFiles }] : [],
|
|
26786
|
+
...input.removedPaths.map((path) => ({
|
|
26787
|
+
op: "delete_entity",
|
|
26788
|
+
path,
|
|
26789
|
+
expectedHash: expectedFileHash2(root, path)
|
|
26790
|
+
}))
|
|
26791
|
+
];
|
|
26792
|
+
const draft = this.changeSetEngine.approve(this.changeSetEngine.plan({
|
|
26793
|
+
id: input.id,
|
|
26794
|
+
base: {
|
|
26795
|
+
headSha: session.workspace.headSha,
|
|
26796
|
+
worktreeDigest: session.snapshot.worktreeDigest,
|
|
26797
|
+
modelDigest: model.modelDigest
|
|
26798
|
+
},
|
|
26799
|
+
reason: { taskSessionId: input.id },
|
|
26800
|
+
operations
|
|
26801
|
+
}));
|
|
26802
|
+
await this.changeSetEngine.apply(root, draft, { approved: true });
|
|
26803
|
+
}
|
|
26804
|
+
async applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentFiles, createdAt) {
|
|
26805
|
+
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
26806
|
+
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment2(createdAt)}`;
|
|
26807
|
+
const backupRelativePath = uniqueBackupPath2(root, backupBase);
|
|
26808
|
+
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
26809
|
+
const { backup, manifest } = architectureProjectionRollbackBackup2(currentFiles, {
|
|
26810
|
+
createdAt,
|
|
26811
|
+
path: backupRelativePath,
|
|
26812
|
+
manifestPath
|
|
26813
|
+
});
|
|
26814
|
+
const removedPaths = currentFiles.filter((file) => !targetPaths.has(file.path)).map((file) => file.path);
|
|
26815
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
26816
|
+
id: `changeset.ledger-rollback-${shortDigest4(digestJson({ createdAt, projectionDigest: architectureLedgerProjectionDigest(projectedFiles) }))}`,
|
|
26817
|
+
files: [
|
|
26818
|
+
...currentFiles.map((file) => ({
|
|
26819
|
+
path: join9(backupRelativePath, archContextRelativePath2(file.path)),
|
|
26820
|
+
body: file.body
|
|
26821
|
+
})),
|
|
26822
|
+
{ path: manifestPath, body: `${JSON.stringify(manifest, null, 2)}
|
|
26823
|
+
` },
|
|
26824
|
+
...projectedFiles.map(({ path, body }) => ({ path, body }))
|
|
26825
|
+
],
|
|
26826
|
+
removedPaths
|
|
26827
|
+
});
|
|
26828
|
+
return {
|
|
26829
|
+
backup,
|
|
26830
|
+
writtenPaths: projectedFiles.map((file) => file.path),
|
|
26831
|
+
removedPaths
|
|
26832
|
+
};
|
|
26833
|
+
}
|
|
26336
26834
|
async ledgerState(root) {
|
|
26337
26835
|
this.assertRunning();
|
|
26338
26836
|
return okEnvelope("ledger.state", await this.architectureLedgerReadback(root));
|
|
@@ -26686,8 +27184,13 @@ class ArchctxDaemon2 {
|
|
|
26686
27184
|
const scope = await this.architectureLedgerScope(root);
|
|
26687
27185
|
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
26688
27186
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
26689
|
-
if (writes)
|
|
26690
|
-
|
|
27187
|
+
if (writes) {
|
|
27188
|
+
await this.applyArchitectureProjectionChangeSet(root, {
|
|
27189
|
+
id: `changeset.ledger-project-${shortDigest4(architectureLedgerProjectionDigest(projectedFiles))}`,
|
|
27190
|
+
files: projectedFiles.map(({ path, body }) => ({ path, body })),
|
|
27191
|
+
removedPaths: []
|
|
27192
|
+
});
|
|
27193
|
+
}
|
|
26691
27194
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
26692
27195
|
state,
|
|
26693
27196
|
files: listModelFiles(root),
|
|
@@ -26837,7 +27340,7 @@ class ArchctxDaemon2 {
|
|
|
26837
27340
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
26838
27341
|
const currentManagedFiles = listModelFiles(root).filter((file) => isArchitectureLedgerManagedModelPath2(file.path));
|
|
26839
27342
|
const backupPlan = architectureProjectionRollbackBackup2(currentManagedFiles);
|
|
26840
|
-
const writeResult = writes ?
|
|
27343
|
+
const writeResult = writes ? await this.applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentManagedFiles, this.clock()) : { backup: backupPlan.backup, writtenPaths: [], removedPaths: [] };
|
|
26841
27344
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
26842
27345
|
state,
|
|
26843
27346
|
files: listModelFiles(root),
|
|
@@ -26876,9 +27379,12 @@ class ArchctxDaemon2 {
|
|
|
26876
27379
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild currently requires --from-git");
|
|
26877
27380
|
return this.withWriter(async () => {
|
|
26878
27381
|
this.assertFreshWorktree(root, input.expectedWorktreeDigest, "ledger rebuild --from-git");
|
|
26879
|
-
const scope = await this.
|
|
27382
|
+
const scope = await this.architectureLedgerGitScope(root);
|
|
26880
27383
|
const files = listModelFiles(root);
|
|
26881
|
-
const
|
|
27384
|
+
const exactReplay = await this.localStore.replayArchitectureLedger(scope);
|
|
27385
|
+
const exactScopeHasEvents = exactReplay.events.length > 0;
|
|
27386
|
+
const authorityScope = exactScopeHasEvents ? scope : await this.localStore.resolveLatestArchitectureLedgerScope(scope);
|
|
27387
|
+
const previousState = exactScopeHasEvents ? exactReplay.state : await this.localStore.readArchitectureLedgerState(authorityScope);
|
|
26882
27388
|
const previousGraphDigest = architectureLedgerStateDigest(previousState);
|
|
26883
27389
|
const rebuildCommand = input.acceptExternalProjection ? "archctx ledger rebuild --from-git --accept-external-projection" : "archctx ledger rebuild --from-git";
|
|
26884
27390
|
const plan = planYamlToArchitectureLedgerRebuild({
|
|
@@ -26888,12 +27394,18 @@ class ArchctxDaemon2 {
|
|
|
26888
27394
|
command: rebuildCommand,
|
|
26889
27395
|
previousState
|
|
26890
27396
|
});
|
|
27397
|
+
const importPlan = planYamlToArchitectureLedgerImport({
|
|
27398
|
+
...scope,
|
|
27399
|
+
files,
|
|
27400
|
+
createdAt: this.clock(),
|
|
27401
|
+
command: rebuildCommand
|
|
27402
|
+
});
|
|
26891
27403
|
if (plan.unsupportedFiles.length > 0) {
|
|
26892
27404
|
return errorEnvelope("ledger.rebuild", "AC_SCHEMA_INVALID", "ledger rebuild requires supported YAML model files");
|
|
26893
27405
|
}
|
|
26894
27406
|
const cursor = architectureLedgerGitCursorFromPlan({ ...scope, plan });
|
|
26895
27407
|
const previousCursor = await this.localStore.readArchitectureLedgerSourceCursor({
|
|
26896
|
-
...
|
|
27408
|
+
...authorityScope,
|
|
26897
27409
|
cursorId: ARCHITECTURE_LEDGER_GIT_CURSOR_ID
|
|
26898
27410
|
});
|
|
26899
27411
|
const cursorChanged = previousCursor?.cursorDigest !== cursor.cursorDigest;
|
|
@@ -26909,7 +27421,13 @@ class ArchctxDaemon2 {
|
|
|
26909
27421
|
let rebuildStatus = "unchanged";
|
|
26910
27422
|
let proposedExternalProjectionChange;
|
|
26911
27423
|
if (previousGraphDigest === plan.graphDigest) {
|
|
26912
|
-
if (
|
|
27424
|
+
if (!exactScopeHasEvents) {
|
|
27425
|
+
append = await this.localStore.appendArchitectureEvents({
|
|
27426
|
+
writer: "runtime-daemon",
|
|
27427
|
+
events: [importPlan.event]
|
|
27428
|
+
});
|
|
27429
|
+
rebuildStatus = isEmptyArchitectureLedgerState2(previousState) ? "rebuilt" : "cursor-refreshed";
|
|
27430
|
+
} else if (cursorChanged) {
|
|
26913
27431
|
const cursorPlan = planGitCursorRefreshToArchitectureLedgerEvent({
|
|
26914
27432
|
...scope,
|
|
26915
27433
|
cursor,
|
|
@@ -26925,7 +27443,7 @@ class ArchctxDaemon2 {
|
|
|
26925
27443
|
}
|
|
26926
27444
|
} else if (!previousStateEmpty && !input.acceptExternalProjection) {
|
|
26927
27445
|
const proposal = planExternalProjectionChangeToArchitectureLedgerEvent({
|
|
26928
|
-
...
|
|
27446
|
+
...authorityScope,
|
|
26929
27447
|
files,
|
|
26930
27448
|
createdAt: this.clock(),
|
|
26931
27449
|
command: rebuildCommand,
|
|
@@ -26948,11 +27466,12 @@ class ArchctxDaemon2 {
|
|
|
26948
27466
|
} else {
|
|
26949
27467
|
append = await this.localStore.appendArchitectureEvents({
|
|
26950
27468
|
writer: "runtime-daemon",
|
|
26951
|
-
events: [plan.event]
|
|
27469
|
+
events: [exactScopeHasEvents ? plan.event : importPlan.event]
|
|
26952
27470
|
});
|
|
26953
27471
|
rebuildStatus = previousStateEmpty ? "rebuilt" : "external-projection-accepted";
|
|
26954
27472
|
}
|
|
26955
|
-
const
|
|
27473
|
+
const replayScope = rebuildStatus === "external-projection-proposed" ? authorityScope : scope;
|
|
27474
|
+
const replay = await this.localStore.rebuildArchitectureLedgerCurrentState(replayScope);
|
|
26956
27475
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
26957
27476
|
state: replay.state,
|
|
26958
27477
|
files: listModelFiles(root),
|
|
@@ -27098,6 +27617,9 @@ class ArchctxDaemon2 {
|
|
|
27098
27617
|
return this.running ? this.architectureLedgerContextPort(root) : undefined;
|
|
27099
27618
|
}
|
|
27100
27619
|
async architectureLedgerScope(root) {
|
|
27620
|
+
return this.localStore.resolveArchitectureLedgerScope(await this.architectureLedgerGitScope(root));
|
|
27621
|
+
}
|
|
27622
|
+
async architectureLedgerGitScope(root) {
|
|
27101
27623
|
const session = await this.openSession(root);
|
|
27102
27624
|
const paths = runtimeStatePaths2(root);
|
|
27103
27625
|
return {
|
|
@@ -27160,7 +27682,7 @@ class ArchctxDaemon2 {
|
|
|
27160
27682
|
cleanup: "remove-run-root"
|
|
27161
27683
|
}
|
|
27162
27684
|
};
|
|
27163
|
-
if (
|
|
27685
|
+
if (existsSync14(paths.lockPath) || existsSync14(paths.manifestPath)) {
|
|
27164
27686
|
removePathWithRetry(paths.runRoot);
|
|
27165
27687
|
throw new Error(`developer-review-run-already-active: ${input.challenge.challengeId}`);
|
|
27166
27688
|
}
|
|
@@ -27217,7 +27739,7 @@ class ArchctxDaemon2 {
|
|
|
27217
27739
|
const errors = [];
|
|
27218
27740
|
if (run.worktree) {
|
|
27219
27741
|
try {
|
|
27220
|
-
const hadWorktree =
|
|
27742
|
+
const hadWorktree = existsSync14(run.worktree.worktreeRoot);
|
|
27221
27743
|
removeDetachedReviewWorktree(run.worktree);
|
|
27222
27744
|
if (hadWorktree)
|
|
27223
27745
|
removed.push("worktree");
|
|
@@ -27231,7 +27753,7 @@ class ArchctxDaemon2 {
|
|
|
27231
27753
|
["lock", run.lockPath]
|
|
27232
27754
|
]) {
|
|
27233
27755
|
try {
|
|
27234
|
-
const existed =
|
|
27756
|
+
const existed = existsSync14(path);
|
|
27235
27757
|
removePathWithRetry(path);
|
|
27236
27758
|
if (existed)
|
|
27237
27759
|
removed.push(kind);
|
|
@@ -27260,7 +27782,7 @@ class ArchctxDaemon2 {
|
|
|
27260
27782
|
removedLocks: [],
|
|
27261
27783
|
skippedActive: []
|
|
27262
27784
|
};
|
|
27263
|
-
if (!
|
|
27785
|
+
if (!existsSync14(stateDir))
|
|
27264
27786
|
return recovery;
|
|
27265
27787
|
for (const entry of readdirSync9(stateDir).sort()) {
|
|
27266
27788
|
if (!entry.endsWith(".json"))
|
|
@@ -27628,7 +28150,7 @@ class ArchctxDaemon2 {
|
|
|
27628
28150
|
}
|
|
27629
28151
|
async restoreRepositorySessions() {
|
|
27630
28152
|
for (const record of await this.localStore.listRepositorySessions()) {
|
|
27631
|
-
if (!record.root || !
|
|
28153
|
+
if (!record.root || !existsSync14(record.root))
|
|
27632
28154
|
continue;
|
|
27633
28155
|
if (repositoryFingerprint2(record.root) !== record.repositoryId)
|
|
27634
28156
|
continue;
|
|
@@ -28534,14 +29056,14 @@ function expandWorkspacePackageJson2(root, pattern) {
|
|
|
28534
29056
|
return [];
|
|
28535
29057
|
if (!pattern.includes("*")) {
|
|
28536
29058
|
const path = resolve16(root, pattern, "package.json");
|
|
28537
|
-
return
|
|
29059
|
+
return existsSync14(path) ? [path] : [];
|
|
28538
29060
|
}
|
|
28539
29061
|
if (!pattern.endsWith("/*"))
|
|
28540
29062
|
return [];
|
|
28541
29063
|
const base = resolve16(root, pattern.slice(0, -2));
|
|
28542
|
-
if (!
|
|
29064
|
+
if (!existsSync14(base) || !statSync7(base).isDirectory())
|
|
28543
29065
|
return [];
|
|
28544
|
-
return readdirSync9(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve16(base, entry.name, "package.json")).filter((path) =>
|
|
29066
|
+
return readdirSync9(base, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve16(base, entry.name, "package.json")).filter((path) => existsSync14(path));
|
|
28545
29067
|
}
|
|
28546
29068
|
function exactVersionFromManifest2(manifest, packageName) {
|
|
28547
29069
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest))
|
|
@@ -28557,7 +29079,7 @@ function exactVersionFromManifest2(manifest, packageName) {
|
|
|
28557
29079
|
return;
|
|
28558
29080
|
}
|
|
28559
29081
|
function readJsonFile2(path) {
|
|
28560
|
-
if (!
|
|
29082
|
+
if (!existsSync14(path))
|
|
28561
29083
|
return;
|
|
28562
29084
|
try {
|
|
28563
29085
|
return JSON.parse(readFileSync12(path, "utf8"));
|
|
@@ -28570,7 +29092,7 @@ function isExactPackageVersion2(value) {
|
|
|
28570
29092
|
}
|
|
28571
29093
|
function readContext7Lockfile2(root) {
|
|
28572
29094
|
const path = resolve16(root, CONTEXT7_LOCKFILE2);
|
|
28573
|
-
if (!
|
|
29095
|
+
if (!existsSync14(path)) {
|
|
28574
29096
|
return {
|
|
28575
29097
|
schemaVersion: CONTEXT7_LOCKFILE_SCHEMA_VERSION,
|
|
28576
29098
|
provider: "context7",
|
|
@@ -28799,48 +29321,9 @@ function auditApproveResultPayload2(runId, status, totalCount, issuedIssues) {
|
|
|
28799
29321
|
issuedIssues
|
|
28800
29322
|
};
|
|
28801
29323
|
}
|
|
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
|
-
};
|
|
29324
|
+
function expectedFileHash2(root, path) {
|
|
29325
|
+
const absolute = resolve16(root, path);
|
|
29326
|
+
return existsSync14(absolute) ? digestJson({ body: readFileSync12(absolute, "utf8") }) : "missing";
|
|
28844
29327
|
}
|
|
28845
29328
|
function architectureProjectionRollbackBackup2(files, options = {}) {
|
|
28846
29329
|
const manifest = {
|
|
@@ -28867,7 +29350,7 @@ function architectureProjectionRollbackBackup2(files, options = {}) {
|
|
|
28867
29350
|
function uniqueBackupPath2(root, backupBase) {
|
|
28868
29351
|
let candidate = backupBase;
|
|
28869
29352
|
let suffix = 2;
|
|
28870
|
-
while (
|
|
29353
|
+
while (existsSync14(resolve16(root, candidate))) {
|
|
28871
29354
|
candidate = `${backupBase}-${suffix}`;
|
|
28872
29355
|
suffix += 1;
|
|
28873
29356
|
}
|
|
@@ -28876,7 +29359,7 @@ function uniqueBackupPath2(root, backupBase) {
|
|
|
28876
29359
|
function uniqueRuntimeBackupPath2(backupBase) {
|
|
28877
29360
|
let candidate = backupBase;
|
|
28878
29361
|
let suffix = 2;
|
|
28879
|
-
while (
|
|
29362
|
+
while (existsSync14(candidate)) {
|
|
28880
29363
|
candidate = backupBase.replace(/\.sqlite$/, `-${suffix}.sqlite`);
|
|
28881
29364
|
suffix += 1;
|
|
28882
29365
|
}
|
|
@@ -28938,7 +29421,7 @@ function parsePracticeCheckpointBaselineState2(state, repositoryId, taskSessionI
|
|
|
28938
29421
|
return record;
|
|
28939
29422
|
}
|
|
28940
29423
|
function completeTaskProjectionDrift2(root) {
|
|
28941
|
-
if (!
|
|
29424
|
+
if (!existsSync14(resolve16(root, "docs/architecture/.projection-manifest.json")))
|
|
28942
29425
|
return;
|
|
28943
29426
|
const loaded = loadArchitectureDocumentationInputs(root);
|
|
28944
29427
|
const sourceDigest = architectureDocumentationSourceDigest({
|
|
@@ -30197,37 +30680,10 @@ function buildArchitectureDocsProjection(root, generatedAt) {
|
|
|
30197
30680
|
sourceDigest,
|
|
30198
30681
|
generatedAt
|
|
30199
30682
|
});
|
|
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
30683
|
return {
|
|
30228
30684
|
plan,
|
|
30229
|
-
manifest,
|
|
30230
|
-
files: [...plan.files, manifest]
|
|
30685
|
+
manifest: plan.manifest,
|
|
30686
|
+
files: [...plan.files, plan.manifest]
|
|
30231
30687
|
};
|
|
30232
30688
|
}
|
|
30233
30689
|
function architectureDocsRenderProjectionOperation(root, files) {
|
|
@@ -30243,7 +30699,7 @@ function architectureDocsRenderProjectionOperation(root, files) {
|
|
|
30243
30699
|
}
|
|
30244
30700
|
function currentBodyHash(root, path) {
|
|
30245
30701
|
const absolute = resolve17(root, path);
|
|
30246
|
-
return
|
|
30702
|
+
return existsSync15(absolute) ? digestJson({ body: readFileSync13(absolute, "utf8") }) : "missing";
|
|
30247
30703
|
}
|
|
30248
30704
|
async function runPracticesCommand(args2, cwd, daemon) {
|
|
30249
30705
|
const subcommand = args2[0] ?? "list";
|
|
@@ -30591,7 +31047,7 @@ function auditManifestGateRoot(cwd) {
|
|
|
30591
31047
|
}
|
|
30592
31048
|
function auditGithubIssuesEnabled(cwd) {
|
|
30593
31049
|
const manifestPath = resolve17(auditManifestGateRoot(cwd), ".archcontext/manifest.yaml");
|
|
30594
|
-
if (!
|
|
31050
|
+
if (!existsSync15(manifestPath))
|
|
30595
31051
|
return false;
|
|
30596
31052
|
let raw;
|
|
30597
31053
|
try {
|
|
@@ -31204,7 +31660,7 @@ async function writeGithubDeveloperReviewState(cwd, state) {
|
|
|
31204
31660
|
return { state, path };
|
|
31205
31661
|
}
|
|
31206
31662
|
function readGithubDeveloperReviewState(path) {
|
|
31207
|
-
if (!
|
|
31663
|
+
if (!existsSync15(path))
|
|
31208
31664
|
return;
|
|
31209
31665
|
try {
|
|
31210
31666
|
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
@@ -31256,7 +31712,7 @@ function defaultGithubConnectionPath(cwd) {
|
|
|
31256
31712
|
return join10(dirname10(defaultDaemonConnectionPath(cwd)), "github-connection.json");
|
|
31257
31713
|
}
|
|
31258
31714
|
function readGithubConnection(path) {
|
|
31259
|
-
if (!
|
|
31715
|
+
if (!existsSync15(path))
|
|
31260
31716
|
return;
|
|
31261
31717
|
try {
|
|
31262
31718
|
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
@@ -31770,10 +32226,10 @@ function doctorSqlite(cwd) {
|
|
|
31770
32226
|
const legacyLocalStore = inspectLegacyLocalStoreMigration(cwd);
|
|
31771
32227
|
return {
|
|
31772
32228
|
path,
|
|
31773
|
-
exists:
|
|
32229
|
+
exists: existsSync15(path),
|
|
31774
32230
|
migrations: productVersionManifest().runtime.sqliteMigrations,
|
|
31775
32231
|
legacyPath: paths.legacyLocalStorePath,
|
|
31776
|
-
legacyExists:
|
|
32232
|
+
legacyExists: existsSync15(paths.legacyLocalStorePath),
|
|
31777
32233
|
legacyLocalStore
|
|
31778
32234
|
};
|
|
31779
32235
|
}
|
|
@@ -31804,7 +32260,7 @@ function runtimePathsReport(cwd) {
|
|
|
31804
32260
|
};
|
|
31805
32261
|
}
|
|
31806
32262
|
function pathAccess(path) {
|
|
31807
|
-
const exists =
|
|
32263
|
+
const exists = existsSync15(path);
|
|
31808
32264
|
return {
|
|
31809
32265
|
path,
|
|
31810
32266
|
exists,
|