archctx 0.4.6 → 0.4.8
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/bin/archctx.mjs
CHANGED
|
@@ -961,8 +961,123 @@ function projectionApplyReceiptInvariantIssues(input) {
|
|
|
961
961
|
if (digestJson(input.result.applyReceipt) !== digestJson(input.identity)) {
|
|
962
962
|
issues.push("projection apply receipt result must carry the same apply identity");
|
|
963
963
|
}
|
|
964
|
+
if (input.recovery)
|
|
965
|
+
issues.push(...projectionApplyRecoveryBindingInvariantIssues(input.recovery, input));
|
|
964
966
|
return issues;
|
|
965
967
|
}
|
|
968
|
+
function projectionApplyRecoveryBindingInvariantIssues(binding, receipt) {
|
|
969
|
+
const issues = [
|
|
970
|
+
...sortedUniqueIssues("recovery.targets", binding.targets),
|
|
971
|
+
...sortedUniqueIssues("recovery.changedPaths", binding.changedPaths)
|
|
972
|
+
];
|
|
973
|
+
if (binding.schemaVersion !== PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION) {
|
|
974
|
+
issues.push("recovery schemaVersion is invalid");
|
|
975
|
+
}
|
|
976
|
+
if (binding.targets.length === 0)
|
|
977
|
+
issues.push("recovery targets must contain at least one projection target");
|
|
978
|
+
if (receipt) {
|
|
979
|
+
if (binding.receiptDigest !== receipt.result.receiptDigest) {
|
|
980
|
+
issues.push("recovery receiptDigest must match the committed result receiptDigest");
|
|
981
|
+
}
|
|
982
|
+
if (binding.originalExpectedSnapshot.repositoryId !== receipt.result.inputSnapshot.repositoryId || binding.originalExpectedSnapshot.workspaceId !== receipt.result.inputSnapshot.workspaceId || binding.originalExpectedSnapshot.headSha !== receipt.result.inputSnapshot.headSha || binding.originalExpectedSnapshot.worktreeDigest !== receipt.result.inputSnapshot.worktreeDigest) {
|
|
983
|
+
issues.push("recovery originalExpectedSnapshot must match the committed input snapshot");
|
|
984
|
+
}
|
|
985
|
+
if (binding.rendererVersion !== receipt.result.outputSnapshot.rendererVersion || binding.layoutVersion !== receipt.result.outputSnapshot.layoutVersion || digestJson(binding.generatedFrom) !== digestJson(receipt.result.outputSnapshot.generatedFrom)) {
|
|
986
|
+
issues.push("recovery renderer, layout, and CodeGraph provenance must match the committed output snapshot");
|
|
987
|
+
}
|
|
988
|
+
const expectedDigests = projectionApplyReceiptResultingDigests(receipt);
|
|
989
|
+
if (!expectedDigests || digestJson(binding.expectedResultingDigests) !== digestJson(expectedDigests)) {
|
|
990
|
+
issues.push("recovery expectedResultingDigests must match committed refresh signals");
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return issues;
|
|
994
|
+
}
|
|
995
|
+
function projectionApplyRecoveryIntentInvariantIssues(input) {
|
|
996
|
+
const issues = [];
|
|
997
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION)
|
|
998
|
+
issues.push("recovery intent schemaVersion is invalid");
|
|
999
|
+
if (!/^[a-zA-Z0-9_.:-]+$/.test(input.requestId))
|
|
1000
|
+
issues.push("recovery intent requestId must use the stable identifier character set");
|
|
1001
|
+
if (input.profile !== "repo-harness/v1")
|
|
1002
|
+
issues.push("recovery intent profile is invalid");
|
|
1003
|
+
for (const field of ["lookupKey", "applyId"]) {
|
|
1004
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(input.receipt[field]))
|
|
1005
|
+
issues.push(`recovery intent receipt.${field} must be a SHA-256 digest`);
|
|
1006
|
+
}
|
|
1007
|
+
return issues;
|
|
1008
|
+
}
|
|
1009
|
+
function projectionApplyRecoveryProofDigest(input) {
|
|
1010
|
+
return digestJson(input);
|
|
1011
|
+
}
|
|
1012
|
+
function projectionApplyRecoveryProofInvariantIssues(input) {
|
|
1013
|
+
const issues = [
|
|
1014
|
+
...sortedUniqueIssues("acceptedChange.reasonCodes", input.acceptedChange.reasonCodes),
|
|
1015
|
+
...sortedUniqueIssues("acceptedChange.affectedNodeIds", input.acceptedChange.affectedNodeIds)
|
|
1016
|
+
];
|
|
1017
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION)
|
|
1018
|
+
issues.push("recovery proof schemaVersion is invalid");
|
|
1019
|
+
if (!/^[a-zA-Z0-9_.:-]+$/.test(input.requestId))
|
|
1020
|
+
issues.push("recovery proof requestId must use the stable identifier character set");
|
|
1021
|
+
if (input.current.snapshot.generatedFrom.codeGraphStatus !== "ready")
|
|
1022
|
+
issues.push("recovery proof requires a ready current CodeGraph snapshot");
|
|
1023
|
+
const { proofDigest: _proofDigest, deliveryStatus: _deliveryStatus, ...payload } = input;
|
|
1024
|
+
if (projectionApplyRecoveryProofDigest(payload) !== input.proofDigest) {
|
|
1025
|
+
issues.push("recovery proofDigest must bind the semantic proof payload");
|
|
1026
|
+
}
|
|
1027
|
+
return issues;
|
|
1028
|
+
}
|
|
1029
|
+
function projectionApplyRecoveryResultInvariantIssues(input) {
|
|
1030
|
+
const issues = [
|
|
1031
|
+
...projectionApplyRecoveryProofInvariantIssues(input.proof),
|
|
1032
|
+
...input.refreshSignals.flatMap((signal, index) => architectureRefreshSignalInvariantIssues(signal, `refreshSignals[${index}]`)),
|
|
1033
|
+
...sortedUniqueIssues("refreshSignals.signalId", input.refreshSignals.map((signal) => signal.signalId))
|
|
1034
|
+
];
|
|
1035
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION) {
|
|
1036
|
+
issues.push("recovery result schemaVersion is invalid");
|
|
1037
|
+
}
|
|
1038
|
+
if (input.proof.deliveryStatus === "already-delivered" && input.refreshSignals.length > 0) {
|
|
1039
|
+
issues.push("already-delivered recovery result cannot repeat refreshSignals");
|
|
1040
|
+
}
|
|
1041
|
+
for (const [index, signal] of input.refreshSignals.entries()) {
|
|
1042
|
+
const prefix = `refreshSignals[${index}]`;
|
|
1043
|
+
if (signal.projectionReceiptDigest !== input.proof.receipt.receiptDigest) {
|
|
1044
|
+
issues.push(`${prefix}.projectionReceiptDigest must match recovery proof receiptDigest`);
|
|
1045
|
+
}
|
|
1046
|
+
if (digestJson(signal.acceptedChange) !== digestJson(input.proof.acceptedChange)) {
|
|
1047
|
+
issues.push(`${prefix}.acceptedChange must match recovery proof approval`);
|
|
1048
|
+
}
|
|
1049
|
+
if (digestJson(signal.resultingDigests) !== digestJson(input.proof.expectedResultingDigests)) {
|
|
1050
|
+
issues.push(`${prefix}.resultingDigests must match recovery proof`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return issues;
|
|
1054
|
+
}
|
|
1055
|
+
function projectionApplyRecoveryProofReceiptInvariantIssues(proof, receipt) {
|
|
1056
|
+
const issues = [
|
|
1057
|
+
...projectionApplyRecoveryProofInvariantIssues(proof),
|
|
1058
|
+
...projectionApplyReceiptInvariantIssues(receipt)
|
|
1059
|
+
];
|
|
1060
|
+
const binding = receipt.recovery;
|
|
1061
|
+
if (!binding)
|
|
1062
|
+
return [...issues, "committed projection receipt does not support semantic recovery"];
|
|
1063
|
+
if (proof.receipt.lookupKey !== receipt.identity.lookupKey || proof.receipt.applyId !== receipt.identity.applyId || proof.receipt.receiptDigest !== receipt.result.receiptDigest) {
|
|
1064
|
+
issues.push("recovery proof receipt identity must match the committed receipt");
|
|
1065
|
+
}
|
|
1066
|
+
if (digestJson(proof.acceptedChange) !== digestJson(receipt.identity.acceptedChange) || digestJson(proof.expectedResultingDigests) !== digestJson(binding.expectedResultingDigests)) {
|
|
1067
|
+
issues.push("recovery proof approval binding must match the committed receipt");
|
|
1068
|
+
}
|
|
1069
|
+
if (digestJson(proof.current.resultingDigests) !== digestJson(binding.expectedResultingDigests) || proof.current.ownedOutputDigest !== binding.ownedOutputDigest || proof.current.snapshot.rendererVersion !== binding.rendererVersion || proof.current.snapshot.layoutVersion !== binding.layoutVersion || digestJson(proof.current.snapshot.generatedFrom) !== digestJson(binding.generatedFrom)) {
|
|
1070
|
+
issues.push("recovery proof current state must match the committed recovery binding");
|
|
1071
|
+
}
|
|
1072
|
+
return issues;
|
|
1073
|
+
}
|
|
1074
|
+
function projectionApplyReceiptResultingDigests(receipt) {
|
|
1075
|
+
const signals = receipt.result.refreshSignals;
|
|
1076
|
+
if (signals.length === 0)
|
|
1077
|
+
return;
|
|
1078
|
+
const [first] = signals;
|
|
1079
|
+
return signals.every((signal) => digestJson(signal.resultingDigests) === digestJson(first.resultingDigests)) ? first.resultingDigests : undefined;
|
|
1080
|
+
}
|
|
966
1081
|
function architectureRefreshSignalInvariantIssues(input, prefix = "signal") {
|
|
967
1082
|
const issues = [
|
|
968
1083
|
...sortedUniqueIssues(`${prefix}.reasonCodes`, input.reasonCodes),
|
|
@@ -1006,7 +1121,7 @@ function sortedUniqueIssues(label, values) {
|
|
|
1006
1121
|
const expected = [...new Set(values)].sort();
|
|
1007
1122
|
return expected.length === values.length && expected.every((value, index) => value === values[index]) ? [] : [`${label} must be sorted and unique`];
|
|
1008
1123
|
}
|
|
1009
|
-
var PROJECTION_REQUEST_SCHEMA_VERSION = "archcontext.projection-request/v1", PROJECTION_RESULT_SCHEMA_VERSION = "archcontext.projection-result/v2", PROJECTION_APPLY_IDENTITY_SCHEMA_VERSION = "archcontext.projection-apply-identity/v1", ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION = "archcontext.architecture-refresh-signal/v1", ARCHCTX_CAPABILITIES_SCHEMA_VERSION = "archcontext.capabilities/v1", ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v4", AGENT_CONTEXT_RENDERER_VERSION = "archcontext.agent-context-renderer/v1", PROJECTION_MODES, PROJECTION_TARGETS, ARCHITECTURE_MAJOR_CHANGE_REASON_CODES, ARCHCTX_FEATURES;
|
|
1124
|
+
var PROJECTION_REQUEST_SCHEMA_VERSION = "archcontext.projection-request/v1", PROJECTION_RESULT_SCHEMA_VERSION = "archcontext.projection-result/v2", PROJECTION_APPLY_IDENTITY_SCHEMA_VERSION = "archcontext.projection-apply-identity/v1", PROJECTION_APPLY_RECOVERY_BINDING_SCHEMA_VERSION = "archcontext.projection-apply-recovery-binding/v1", PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-intent/v1", PROJECTION_APPLY_RECOVERY_PROOF_SCHEMA_VERSION = "archcontext.projection-apply-recovery-proof/v1", PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION = "archcontext.projection-apply-recovery-result/v1", ARCHITECTURE_REFRESH_SIGNAL_SCHEMA_VERSION = "archcontext.architecture-refresh-signal/v1", ARCHCTX_CAPABILITIES_SCHEMA_VERSION = "archcontext.capabilities/v1", ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v4", AGENT_CONTEXT_RENDERER_VERSION = "archcontext.agent-context-renderer/v1", PROJECTION_MODES, PROJECTION_TARGETS, ARCHITECTURE_MAJOR_CHANGE_REASON_CODES, ARCHCTX_FEATURES;
|
|
1010
1125
|
var init_projection = __esm(() => {
|
|
1011
1126
|
init_schema();
|
|
1012
1127
|
PROJECTION_MODES = ["check", "plan", "apply", "adopt"];
|
|
@@ -1030,6 +1145,7 @@ var init_projection = __esm(() => {
|
|
|
1030
1145
|
"architecture-docs-renderer-v2",
|
|
1031
1146
|
"architecture-refresh-signal-v1",
|
|
1032
1147
|
"projection-apply-receipt-v1",
|
|
1148
|
+
"projection-apply-recovery-v1",
|
|
1033
1149
|
"projection-protocol-v2"
|
|
1034
1150
|
];
|
|
1035
1151
|
});
|
|
@@ -1088,7 +1204,7 @@ function productVersionManifest() {
|
|
|
1088
1204
|
}
|
|
1089
1205
|
};
|
|
1090
1206
|
}
|
|
1091
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.4.
|
|
1207
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.4.8", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.0", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
|
|
1092
1208
|
|
|
1093
1209
|
// packages/contracts/src/validator.ts
|
|
1094
1210
|
function validateJsonSchema(schema, value) {
|
|
@@ -1837,7 +1953,7 @@ var init_src2 = __esm(() => {
|
|
|
1837
1953
|
|
|
1838
1954
|
// node_modules/.bun/@colbymchenry+codegraph@1.5.0/node_modules/@colbymchenry/codegraph/npm-sdk.js
|
|
1839
1955
|
var require_npm_sdk = __commonJS(function(exports, module) {
|
|
1840
|
-
var __dirname = "/Users/ancienttwo/Projects/arch-context-wt-
|
|
1956
|
+
var __dirname = "/Users/ancienttwo/Projects/arch-context-wt-release-048/node_modules/.bun/@colbymchenry+codegraph@1.5.0/node_modules/@colbymchenry/codegraph";
|
|
1841
1957
|
var path = __require("path");
|
|
1842
1958
|
var os = __require("os");
|
|
1843
1959
|
var fs = __require("fs");
|
|
@@ -5623,7 +5739,7 @@ var init_src7 = __esm(() => {
|
|
|
5623
5739
|
|
|
5624
5740
|
// packages/surfaces/cli/src/main.ts
|
|
5625
5741
|
import { execFileSync as execFileSync8, spawn as spawn2, spawnSync as spawnSync3 } from "child_process";
|
|
5626
|
-
import { accessSync as accessSync3, chmodSync as
|
|
5742
|
+
import { accessSync as accessSync3, chmodSync as chmodSync6, closeSync as closeSync8, constants, existsSync as existsSync17, mkdirSync as mkdirSync9, openSync as openSync8, readFileSync as readFileSync16, rmSync as rmSync10, statSync as statSync11, writeFileSync as writeFileSync8 } from "fs";
|
|
5627
5743
|
import { dirname as dirname11, join as join10, resolve as resolve19 } from "path";
|
|
5628
5744
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5629
5745
|
|
|
@@ -8339,17 +8455,15 @@ function stickyArchitectureDocumentationProjectionProvenance(current, existingMa
|
|
|
8339
8455
|
if (!prior)
|
|
8340
8456
|
return current;
|
|
8341
8457
|
assertArchitectureDocumentationProjectionProvenance(prior, current.rendererVersion);
|
|
8342
|
-
return
|
|
8458
|
+
return architectureDocumentationStickyProvenanceDigest(prior) === architectureDocumentationStickyProvenanceDigest(current) ? prior : current;
|
|
8343
8459
|
} catch {
|
|
8344
8460
|
return current;
|
|
8345
8461
|
}
|
|
8346
8462
|
}
|
|
8347
|
-
function
|
|
8463
|
+
function architectureDocumentationStickyProvenanceDigest(provenance) {
|
|
8348
8464
|
return digestJson({
|
|
8349
8465
|
sourceTreeDigest: provenance.sourceTreeDigest,
|
|
8350
8466
|
modelDigest: provenance.modelDigest,
|
|
8351
|
-
codeGraphDigest: provenance.codeGraphDigest,
|
|
8352
|
-
indexedWorktreeDigest: provenance.indexedWorktreeDigest,
|
|
8353
8467
|
rendererVersion: provenance.rendererVersion,
|
|
8354
8468
|
layoutVersion: provenance.layoutVersion,
|
|
8355
8469
|
generatedFrom: provenance.generatedFrom
|
|
@@ -10397,13 +10511,21 @@ function diagnostics() {
|
|
|
10397
10511
|
const egress = localEgressStatus();
|
|
10398
10512
|
return {
|
|
10399
10513
|
node: process.version,
|
|
10400
|
-
supportedNode:
|
|
10514
|
+
supportedNode: isSupportedNodeVersion(process.version),
|
|
10401
10515
|
codeGraphVersion: REQUIRED_CODEGRAPH_VERSION,
|
|
10402
10516
|
privacyRouteDigest: controlPlaneRouteDigest(),
|
|
10403
10517
|
secureDefaults: secureDefaults(),
|
|
10404
10518
|
egress
|
|
10405
10519
|
};
|
|
10406
10520
|
}
|
|
10521
|
+
function isSupportedNodeVersion(version) {
|
|
10522
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
10523
|
+
if (!match)
|
|
10524
|
+
return false;
|
|
10525
|
+
const major = Number(match[1]);
|
|
10526
|
+
const minor = Number(match[2]);
|
|
10527
|
+
return major < 26 && (major > 22 || major === 22 && minor >= 22);
|
|
10528
|
+
}
|
|
10407
10529
|
function secureDefaults() {
|
|
10408
10530
|
return {
|
|
10409
10531
|
tunnelEnabledByDefault: false,
|
|
@@ -10449,8 +10571,9 @@ function uninstallMarker(content, host) {
|
|
|
10449
10571
|
function dependencyAudit(root) {
|
|
10450
10572
|
const packageJson = JSON.parse(readFileSync6(resolve6(root, "package.json"), "utf8"));
|
|
10451
10573
|
const issues = [];
|
|
10452
|
-
if (
|
|
10453
|
-
issues.push(
|
|
10574
|
+
if (packageJson.engines?.node !== ARCHCONTEXT_NODE_RANGE) {
|
|
10575
|
+
issues.push(`node engine must equal ${ARCHCONTEXT_NODE_RANGE}`);
|
|
10576
|
+
}
|
|
10454
10577
|
return { ok: issues.length === 0, issues };
|
|
10455
10578
|
}
|
|
10456
10579
|
function secretScan(root) {
|
|
@@ -13950,6 +14073,12 @@ var LOCAL_SQLITE_MIGRATIONS = [
|
|
|
13950
14073
|
)`,
|
|
13951
14074
|
"CREATE INDEX IF NOT EXISTS idx_projection_apply_receipts_journal ON projection_apply_receipts(journal_id)"
|
|
13952
14075
|
]
|
|
14076
|
+
},
|
|
14077
|
+
{
|
|
14078
|
+
id: "0020_projection_apply_recovery_proof",
|
|
14079
|
+
statements: [
|
|
14080
|
+
"ALTER TABLE projection_apply_receipts ADD COLUMN recovery_proof_json TEXT"
|
|
14081
|
+
]
|
|
13953
14082
|
}
|
|
13954
14083
|
];
|
|
13955
14084
|
var ARCHCONTEXT_STATE_DIR_ENV = "ARCHCONTEXT_STATE_DIR";
|
|
@@ -14119,7 +14248,6 @@ function recoverRuntimeStateTarget(input) {
|
|
|
14119
14248
|
ensurePrivateDir(stagingDir);
|
|
14120
14249
|
assertRuntimeStateRecoveryPrivatePermissions(stagingDir, 448);
|
|
14121
14250
|
migrateSqliteDatabaseSync(stagingPath);
|
|
14122
|
-
compactSqliteDatabase(stagingPath);
|
|
14123
14251
|
const stagingIntegrity = assertCurrentLocalStore(stagingPath);
|
|
14124
14252
|
receiptPath = join2(quarantineDirectory, RUNTIME_STATE_RECOVERY_RECEIPT_FILE);
|
|
14125
14253
|
writeRuntimeStateRecoveryReceipt(receiptPath, {
|
|
@@ -14248,7 +14376,6 @@ function migrateLegacyLocalStoreIfNeeded(root = process.cwd(), env = process.env
|
|
|
14248
14376
|
integrityCheck.legacy = vacuumLegacySqliteInto(paths.legacyLocalStorePath, stagingPath);
|
|
14249
14377
|
makePrivateFile(stagingPath);
|
|
14250
14378
|
migrateSqliteDatabaseSync(stagingPath);
|
|
14251
|
-
compactSqliteDatabase(stagingPath);
|
|
14252
14379
|
integrityCheck.staging = assertCurrentLocalStore(stagingPath);
|
|
14253
14380
|
publishStagedLocalStore(stagingPath, paths.localStorePath);
|
|
14254
14381
|
integrityCheck.target = assertCurrentLocalStore(paths.localStorePath);
|
|
@@ -14269,10 +14396,17 @@ function migrateLegacyLocalStoreIfNeeded(root = process.cwd(), env = process.env
|
|
|
14269
14396
|
function upgradeExistingLocalStoreTarget(paths, integrityCheck) {
|
|
14270
14397
|
const lock = acquireLegacyMigrationLock(paths);
|
|
14271
14398
|
try {
|
|
14272
|
-
|
|
14273
|
-
|
|
14274
|
-
|
|
14275
|
-
|
|
14399
|
+
const db = openSqliteDatabaseSync(paths.localStorePath);
|
|
14400
|
+
let compacted = false;
|
|
14401
|
+
try {
|
|
14402
|
+
integrityCheck.target = assertUpgradeableLocalStoreTarget(db, paths.localStorePath);
|
|
14403
|
+
migrateOpenedSqliteDatabase(db);
|
|
14404
|
+
compacted = true;
|
|
14405
|
+
} finally {
|
|
14406
|
+
db.close();
|
|
14407
|
+
}
|
|
14408
|
+
if (compacted)
|
|
14409
|
+
removeSqliteSidecars(paths.localStorePath);
|
|
14276
14410
|
integrityCheck.target = assertCurrentLocalStore(paths.localStorePath);
|
|
14277
14411
|
delete integrityCheck.error;
|
|
14278
14412
|
const markerPath = writeLegacyMigrationMarker(paths, integrityCheck, []);
|
|
@@ -14900,30 +15034,41 @@ function readAppliedLocalSqliteMigrations(db) {
|
|
|
14900
15034
|
return new Set;
|
|
14901
15035
|
return new Set(db.prepare("SELECT id FROM schema_migrations").all().map((row) => String(row.id)));
|
|
14902
15036
|
}
|
|
14903
|
-
function
|
|
14904
|
-
if (
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
14910
|
-
|
|
14911
|
-
prepare: (sql) => db2.prepare(sql),
|
|
14912
|
-
close: () => db2.close()
|
|
14913
|
-
};
|
|
14914
|
-
} catch (error) {
|
|
14915
|
-
if (error.code !== "ERR_UNKNOWN_BUILTIN_MODULE" && error.code !== "MODULE_NOT_FOUND") {
|
|
14916
|
-
throw error;
|
|
14917
|
-
}
|
|
14918
|
-
}
|
|
14919
|
-
const bunSqlite = runtimeRequire("bun:sqlite");
|
|
15037
|
+
function selectSqliteRuntime() {
|
|
15038
|
+
if (process.versions.bun)
|
|
15039
|
+
return "bun";
|
|
15040
|
+
if (process.versions.node)
|
|
15041
|
+
return "node";
|
|
15042
|
+
throw new Error("Unsupported SQLite runtime: archctx requires the Bun or Node runtime, but neither process.versions.bun nor process.versions.node is set.");
|
|
15043
|
+
}
|
|
15044
|
+
function adaptBunSqliteDatabase(bunSqlite, databasePath) {
|
|
14920
15045
|
const db = new bunSqlite.Database(databasePath);
|
|
15046
|
+
const releaseStatements = () => db.clearQueryCache();
|
|
14921
15047
|
return {
|
|
14922
15048
|
exec: (sql) => db.exec(sql),
|
|
14923
15049
|
prepare: (sql) => db.query(sql),
|
|
15050
|
+
releaseStatements,
|
|
15051
|
+
close: () => {
|
|
15052
|
+
releaseStatements();
|
|
15053
|
+
db.close();
|
|
15054
|
+
}
|
|
15055
|
+
};
|
|
15056
|
+
}
|
|
15057
|
+
function adaptNodeSqliteDatabase(nodeSqlite, databasePath) {
|
|
15058
|
+
const db = new nodeSqlite.DatabaseSync(databasePath);
|
|
15059
|
+
return {
|
|
15060
|
+
exec: (sql) => db.exec(sql),
|
|
15061
|
+
prepare: (sql) => db.prepare(sql),
|
|
14924
15062
|
close: () => db.close()
|
|
14925
15063
|
};
|
|
14926
15064
|
}
|
|
15065
|
+
function openSqliteDatabaseSync(databasePath) {
|
|
15066
|
+
if (databasePath !== ":memory:")
|
|
15067
|
+
ensurePrivateDir(dirname2(databasePath));
|
|
15068
|
+
if (selectSqliteRuntime() === "bun")
|
|
15069
|
+
return adaptBunSqliteDatabase(runtimeRequire("bun:sqlite"), databasePath);
|
|
15070
|
+
return adaptNodeSqliteDatabase(runtimeRequire("node:sqlite"), databasePath);
|
|
15071
|
+
}
|
|
14927
15072
|
function legacyMigrationResult(migrated, skippedReason, paths, copiedFiles, details) {
|
|
14928
15073
|
return {
|
|
14929
15074
|
schemaVersion: "archcontext.legacy-local-store-migration/v1",
|
|
@@ -14970,7 +15115,6 @@ function runtimeStateRecoveryStartupProbe(paths, sourceFiles) {
|
|
|
14970
15115
|
makePrivateFile(target);
|
|
14971
15116
|
}
|
|
14972
15117
|
migrateSqliteDatabaseSync(probePath);
|
|
14973
|
-
compactSqliteDatabase(probePath);
|
|
14974
15118
|
assertCurrentLocalStore(probePath);
|
|
14975
15119
|
return { ok: true };
|
|
14976
15120
|
} catch (error) {
|
|
@@ -15185,20 +15329,16 @@ function assertCurrentLocalStoreSchema(db, path) {
|
|
|
15185
15329
|
throw new Error(`SQLite local store schema incomplete for ${path}: missing migrations ${missingMigrations.join(", ")}`);
|
|
15186
15330
|
}
|
|
15187
15331
|
}
|
|
15188
|
-
function assertUpgradeableLocalStoreTarget(path) {
|
|
15189
|
-
const
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
if (!hasArchContextMarker) {
|
|
15195
|
-
throw new Error(`SQLite target is not an ArchContext local store candidate: ${path}`);
|
|
15196
|
-
}
|
|
15197
|
-
if (integrity !== "ok")
|
|
15198
|
-
throw new Error(`SQLite integrity_check failed for ${path}: ${integrity}`);
|
|
15199
|
-
} finally {
|
|
15200
|
-
db.close();
|
|
15332
|
+
function assertUpgradeableLocalStoreTarget(db, path) {
|
|
15333
|
+
const integrity = sqliteIntegrityCheckOpenDatabase(db, path);
|
|
15334
|
+
const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
|
|
15335
|
+
const hasArchContextMarker = ["schema_migrations", "task_states", "repository_sessions", "snapshots"].some((table) => tables.has(table));
|
|
15336
|
+
if (!hasArchContextMarker) {
|
|
15337
|
+
throw new Error(`SQLite target is not an ArchContext local store candidate: ${path}`);
|
|
15201
15338
|
}
|
|
15339
|
+
if (integrity !== "ok")
|
|
15340
|
+
throw new Error(`SQLite integrity_check failed for ${path}: ${integrity}`);
|
|
15341
|
+
return integrity;
|
|
15202
15342
|
}
|
|
15203
15343
|
function assertTrustedLegacyLocalStoreSource(paths) {
|
|
15204
15344
|
const stat = lstatSync2(paths.legacyLocalStorePath);
|
|
@@ -15227,23 +15367,29 @@ function vacuumLegacySqliteInto(sourcePath, targetPath) {
|
|
|
15227
15367
|
}
|
|
15228
15368
|
function migrateSqliteDatabaseSync(databasePath) {
|
|
15229
15369
|
const db = openSqliteDatabaseSync(databasePath);
|
|
15370
|
+
let compacted = false;
|
|
15230
15371
|
try {
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
backfillArchitectureChangeFeed(db);
|
|
15372
|
+
migrateOpenedSqliteDatabase(db);
|
|
15373
|
+
compacted = true;
|
|
15234
15374
|
} finally {
|
|
15235
15375
|
db.close();
|
|
15236
15376
|
}
|
|
15377
|
+
if (compacted)
|
|
15378
|
+
removeSqliteSidecars(databasePath);
|
|
15237
15379
|
}
|
|
15238
|
-
function
|
|
15239
|
-
|
|
15240
|
-
|
|
15241
|
-
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
|
|
15380
|
+
function migrateOpenedSqliteDatabase(db) {
|
|
15381
|
+
applyLocalSqliteMigrations(db);
|
|
15382
|
+
backfillArchitectureEventDirectScope(db);
|
|
15383
|
+
backfillArchitectureChangeFeed(db);
|
|
15384
|
+
compactMigratedSqliteDatabase(db);
|
|
15385
|
+
}
|
|
15386
|
+
function compactMigratedSqliteDatabase(db) {
|
|
15387
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
15388
|
+
db.releaseStatements?.();
|
|
15389
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
15390
|
+
db.exec("PRAGMA journal_mode = DELETE");
|
|
15391
|
+
}
|
|
15392
|
+
function removeSqliteSidecars(databasePath) {
|
|
15247
15393
|
for (const suffix of ["-wal", "-shm"])
|
|
15248
15394
|
rmSync(`${databasePath}${suffix}`, { force: true });
|
|
15249
15395
|
}
|
|
@@ -15930,15 +16076,15 @@ function runCodeGraphCli2(binary, workspaceRoot, args) {
|
|
|
15930
16076
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
15931
16077
|
import { randomBytes } from "node:crypto";
|
|
15932
16078
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
15933
|
-
import { chmodSync as
|
|
16079
|
+
import { chmodSync as chmodSync4, closeSync as closeSync6, existsSync as existsSync15, lstatSync as lstatSync7, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, openSync as openSync6, readdirSync as readdirSync9, readFileSync as readFileSync14, rmSync as rmSync8, statSync as statSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
15934
16080
|
import { createServer } from "node:http";
|
|
15935
16081
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
15936
|
-
import { dirname as dirname10, join as join9, resolve as resolve18 } from "node:path";
|
|
16082
|
+
import { basename as basename6, dirname as dirname10, join as join9, resolve as resolve18, sep as sep7 } from "node:path";
|
|
15937
16083
|
|
|
15938
16084
|
// packages/core/changeset-engine/src/index.ts
|
|
15939
16085
|
init_src();
|
|
15940
|
-
import { closeSync as closeSync4, existsSync as existsSync8, fsyncSync as fsyncSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync3, openSync as openSync4, readFileSync as readFileSync9, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
15941
|
-
import { dirname as dirname5, resolve as resolve11 } from "node:path";
|
|
16086
|
+
import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as existsSync8, fsyncSync as fsyncSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync3, openSync as openSync4, readFileSync as readFileSync9, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
16087
|
+
import { dirname as dirname5, isAbsolute as isAbsolute5, relative as relative6, resolve as resolve11, sep as sep4 } from "node:path";
|
|
15942
16088
|
|
|
15943
16089
|
// packages/core/policy-engine/src/index.ts
|
|
15944
16090
|
import { existsSync as existsSync7, realpathSync as realpathSync6 } from "node:fs";
|
|
@@ -16209,14 +16355,57 @@ function assertSafeTarget(root, path, scope) {
|
|
|
16209
16355
|
throw new Error(`Refusing to write symlink target: ${path}`);
|
|
16210
16356
|
}
|
|
16211
16357
|
}
|
|
16358
|
+
function writeFileWithoutFollowingSymlinks(request) {
|
|
16359
|
+
const absoluteRoot = resolve11(request.root);
|
|
16360
|
+
const absolute = assertPathHasNoSymlinkSegments(request.root, request.path);
|
|
16361
|
+
const segments = relative6(absoluteRoot, absolute).split(sep4);
|
|
16362
|
+
if (existsSync8(absolute))
|
|
16363
|
+
assertExpectedHash(absolute, request.expectedHash);
|
|
16364
|
+
else if (request.expectedHash !== "missing")
|
|
16365
|
+
throw new Error(`Expected missing file hash for new path: ${request.path}`);
|
|
16366
|
+
mkdirSync3(dirname5(absolute), { recursive: true });
|
|
16367
|
+
assertNoSymlinkSegments2(absoluteRoot, segments, request.path);
|
|
16368
|
+
atomicWriteFile(absolute, `${absolute}.archctx-tmp-${process.pid}-${nextNoFollowWriteSequence()}`, request.body, request.mode);
|
|
16369
|
+
}
|
|
16370
|
+
function assertPathHasNoSymlinkSegments(root, path) {
|
|
16371
|
+
const absoluteRoot = resolve11(root);
|
|
16372
|
+
const absolute = resolve11(absoluteRoot, path);
|
|
16373
|
+
const contained = relative6(absoluteRoot, absolute);
|
|
16374
|
+
if (contained === "" || contained === ".." || contained.startsWith(`..${sep4}`) || isAbsolute5(contained)) {
|
|
16375
|
+
throw new Error(`Path escapes repository: ${path}`);
|
|
16376
|
+
}
|
|
16377
|
+
assertNoSymlinkSegments2(absoluteRoot, contained.split(sep4), path);
|
|
16378
|
+
return absolute;
|
|
16379
|
+
}
|
|
16380
|
+
var noFollowWriteSequence = 0;
|
|
16381
|
+
function nextNoFollowWriteSequence() {
|
|
16382
|
+
noFollowWriteSequence += 1;
|
|
16383
|
+
return noFollowWriteSequence;
|
|
16384
|
+
}
|
|
16385
|
+
function assertNoSymlinkSegments2(absoluteRoot, segments, displayPath) {
|
|
16386
|
+
let current = absoluteRoot;
|
|
16387
|
+
for (const segment of segments) {
|
|
16388
|
+
current = resolve11(current, segment);
|
|
16389
|
+
let stat;
|
|
16390
|
+
try {
|
|
16391
|
+
stat = lstatSync3(current);
|
|
16392
|
+
} catch {
|
|
16393
|
+
return;
|
|
16394
|
+
}
|
|
16395
|
+
if (stat.isSymbolicLink())
|
|
16396
|
+
throw new Error(`Refusing to write through symlink: ${displayPath}`);
|
|
16397
|
+
}
|
|
16398
|
+
}
|
|
16212
16399
|
function assertExpectedHash(path, expectedHash) {
|
|
16213
16400
|
const actual = digestJson({ body: readFileSync9(path, "utf8") });
|
|
16214
16401
|
if (expectedHash !== actual)
|
|
16215
16402
|
throw new Error(`Expected hash mismatch: ${path}`);
|
|
16216
16403
|
}
|
|
16217
|
-
function atomicWriteFile(path, tempPath, body) {
|
|
16404
|
+
function atomicWriteFile(path, tempPath, body, mode) {
|
|
16218
16405
|
mkdirSync3(dirname5(path), { recursive: true });
|
|
16219
|
-
writeFileSync2(tempPath, body, "utf8");
|
|
16406
|
+
writeFileSync2(tempPath, body, mode === undefined ? "utf8" : { encoding: "utf8", mode, flag: "wx" });
|
|
16407
|
+
if (mode !== undefined)
|
|
16408
|
+
chmodSync2(tempPath, mode);
|
|
16220
16409
|
fsyncFile2(tempPath);
|
|
16221
16410
|
renameSync2(tempPath, path);
|
|
16222
16411
|
fsyncDirectory2(dirname5(path));
|
|
@@ -16502,7 +16691,7 @@ init_src();
|
|
|
16502
16691
|
// packages/core/practice-catalog/src/index.ts
|
|
16503
16692
|
init_src();
|
|
16504
16693
|
import { existsSync as existsSync9, lstatSync as lstatSync4, readdirSync as readdirSync6, readFileSync as readFileSync10, realpathSync as realpathSync7 } from "node:fs";
|
|
16505
|
-
import { dirname as dirname6, relative as
|
|
16694
|
+
import { dirname as dirname6, relative as relative7, resolve as resolve12, sep as sep5 } from "node:path";
|
|
16506
16695
|
import { fileURLToPath } from "node:url";
|
|
16507
16696
|
var PRACTICE_CATALOG_VERSION = "2026.06.0";
|
|
16508
16697
|
var BUILTIN_PRACTICE_ASSETS_DIR = resolve12(dirname6(fileURLToPath(import.meta.url)), "../assets");
|
|
@@ -16754,7 +16943,7 @@ function loadRepoOverlayAssets(root, errors) {
|
|
|
16754
16943
|
return [];
|
|
16755
16944
|
const out = [];
|
|
16756
16945
|
for (const path of listDataFiles(overlayRoot, overlayRoot, errors)) {
|
|
16757
|
-
const relativePath = `.archcontext/practices/${
|
|
16946
|
+
const relativePath = `.archcontext/practices/${relative7(overlayRoot, path).split(sep5).join("/")}`;
|
|
16758
16947
|
try {
|
|
16759
16948
|
assertRepoRelativePath(relativePath);
|
|
16760
16949
|
assertRealChild(root, path);
|
|
@@ -17161,11 +17350,11 @@ function safeRealpath(path) {
|
|
|
17161
17350
|
}
|
|
17162
17351
|
}
|
|
17163
17352
|
function isRealChild(rootReal, pathReal) {
|
|
17164
|
-
const rel =
|
|
17165
|
-
return rel === "" || !rel.startsWith("..") && !rel.includes(`..${
|
|
17353
|
+
const rel = relative7(rootReal, pathReal);
|
|
17354
|
+
return rel === "" || !rel.startsWith("..") && !rel.includes(`..${sep5}`) && !resolve12(rel).startsWith("..");
|
|
17166
17355
|
}
|
|
17167
17356
|
function displayPath(path) {
|
|
17168
|
-
return path.split(
|
|
17357
|
+
return path.split(sep5).join("/");
|
|
17169
17358
|
}
|
|
17170
17359
|
function isRecord2(value) {
|
|
17171
17360
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -17727,7 +17916,7 @@ function checkResult(input, result) {
|
|
|
17727
17916
|
// packages/core/practice-engine/src/enforcement.ts
|
|
17728
17917
|
init_src();
|
|
17729
17918
|
import { existsSync as existsSync10, lstatSync as lstatSync5, readdirSync as readdirSync7, readFileSync as readFileSync11 } from "node:fs";
|
|
17730
|
-
import { basename as basename5, join as join5, relative as
|
|
17919
|
+
import { basename as basename5, join as join5, relative as relative8, resolve as resolve13, sep as sep6 } from "node:path";
|
|
17731
17920
|
var ENFORCEMENT_RANK = { advisory: 0, checkpoint: 1, complete: 2 };
|
|
17732
17921
|
var POLICY_MODES = new Set(["advisory", "active", "fail-open", "fail-closed"]);
|
|
17733
17922
|
var DEFAULT_POLICY = {
|
|
@@ -18159,8 +18348,8 @@ function assertRepoPolicyFile(root, path, relativePath) {
|
|
|
18159
18348
|
throw new Error(`practice-policy-symlink-denied: ${relativePath}`);
|
|
18160
18349
|
const rootResolved = resolve13(root);
|
|
18161
18350
|
const pathResolved = resolve13(path);
|
|
18162
|
-
const rel =
|
|
18163
|
-
if (rel === "" || rel.startsWith("..") || rel.includes(`..${
|
|
18351
|
+
const rel = relative8(rootResolved, pathResolved);
|
|
18352
|
+
if (rel === "" || rel.startsWith("..") || rel.includes(`..${sep6}`))
|
|
18164
18353
|
throw new Error(`practice-policy-path-escape: ${relativePath}`);
|
|
18165
18354
|
if (basename5(pathResolved).startsWith("."))
|
|
18166
18355
|
throw new Error(`practice-policy-hidden-file-denied: ${relativePath}`);
|
|
@@ -18891,6 +19080,32 @@ function createInterventionProposal(input) {
|
|
|
18891
19080
|
}
|
|
18892
19081
|
|
|
18893
19082
|
// packages/core/context-compiler/src/index.ts
|
|
19083
|
+
var SELF_REFERENTIAL_CONTEXT_EXTENSION_KEYS = ["byteLength", "budgetExceeded", "digest"];
|
|
19084
|
+
function canonicalContextMeasurementForm(context) {
|
|
19085
|
+
const extensions = { ...context.extensions };
|
|
19086
|
+
for (const key of SELF_REFERENTIAL_CONTEXT_EXTENSION_KEYS)
|
|
19087
|
+
delete extensions[key];
|
|
19088
|
+
return { ...context, extensions };
|
|
19089
|
+
}
|
|
19090
|
+
function finalizeContextBudgetMetadata(context, maxBytes) {
|
|
19091
|
+
const canonical = canonicalContextMeasurementForm(context);
|
|
19092
|
+
const byteLength = Buffer.byteLength(JSON.stringify(canonical), "utf8");
|
|
19093
|
+
const withMetadata = {
|
|
19094
|
+
...canonical,
|
|
19095
|
+
extensions: {
|
|
19096
|
+
...canonical.extensions,
|
|
19097
|
+
byteLength,
|
|
19098
|
+
budgetExceeded: byteLength > maxBytes
|
|
19099
|
+
}
|
|
19100
|
+
};
|
|
19101
|
+
return {
|
|
19102
|
+
...withMetadata,
|
|
19103
|
+
extensions: {
|
|
19104
|
+
...withMetadata.extensions,
|
|
19105
|
+
digest: digestJson(withMetadata)
|
|
19106
|
+
}
|
|
19107
|
+
};
|
|
19108
|
+
}
|
|
18894
19109
|
async function compileTaskContext(input) {
|
|
18895
19110
|
const model = await input.modelStore.validateModel(input.workspace);
|
|
18896
19111
|
const ledgerReadback = await input.architectureLedger?.queryForTask({
|
|
@@ -19101,7 +19316,6 @@ async function compileLandscapeTaskContext(input) {
|
|
|
19101
19316
|
});
|
|
19102
19317
|
}
|
|
19103
19318
|
function finalizeContext(context, digests) {
|
|
19104
|
-
const byteLength = Buffer.byteLength(JSON.stringify(context), "utf8");
|
|
19105
19319
|
const withMetadata = {
|
|
19106
19320
|
...context,
|
|
19107
19321
|
extensions: {
|
|
@@ -19117,18 +19331,10 @@ function finalizeContext(context, digests) {
|
|
|
19117
19331
|
codeFactsMode: digests.codeFactsMode,
|
|
19118
19332
|
landscapeDigest: digests.landscapeDigest,
|
|
19119
19333
|
activeRepositories: digests.activeRepositories,
|
|
19120
|
-
crossRepoRelations: digests.crossRepoRelations
|
|
19121
|
-
byteLength,
|
|
19122
|
-
budgetExceeded: byteLength > digests.maxBytes
|
|
19123
|
-
}
|
|
19124
|
-
};
|
|
19125
|
-
return {
|
|
19126
|
-
...withMetadata,
|
|
19127
|
-
extensions: {
|
|
19128
|
-
...withMetadata.extensions,
|
|
19129
|
-
digest: digestJson(withMetadata)
|
|
19334
|
+
crossRepoRelations: digests.crossRepoRelations
|
|
19130
19335
|
}
|
|
19131
19336
|
};
|
|
19337
|
+
return finalizeContextBudgetMetadata(withMetadata, digests.maxBytes);
|
|
19132
19338
|
}
|
|
19133
19339
|
function trimPracticeGuidance(guidance, maxMatches) {
|
|
19134
19340
|
const matches2 = guidance.matches.slice(0, maxMatches);
|
|
@@ -21770,6 +21976,7 @@ function clampInteger(value, min, max) {
|
|
|
21770
21976
|
|
|
21771
21977
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
21772
21978
|
init_src();
|
|
21979
|
+
init_src();
|
|
21773
21980
|
|
|
21774
21981
|
// packages/local-runtime/git-adapter/src/index.ts
|
|
21775
21982
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
@@ -22058,11 +22265,11 @@ function isGitWorktreeError(error) {
|
|
|
22058
22265
|
// packages/local-runtime/local-store-sqlite/src/index.ts
|
|
22059
22266
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
22060
22267
|
import { createHash as createHash9, randomUUID as randomUUID2 } from "node:crypto";
|
|
22061
|
-
import { chmodSync as
|
|
22268
|
+
import { chmodSync as chmodSync3, closeSync as closeSync5, copyFileSync as copyFileSync2, existsSync as existsSync13, fsyncSync as fsyncSync3, lstatSync as lstatSync6, mkdirSync as mkdirSync5, openSync as openSync5, readFileSync as readFileSync12, readSync as readSync4, realpathSync as realpathSync8, renameSync as renameSync3, rmSync as rmSync5, statfsSync as statfsSync2, statSync as statSync8, writeFileSync as writeFileSync3 } from "node:fs";
|
|
22062
22269
|
import { readdir, readFile } from "node:fs/promises";
|
|
22063
22270
|
import { createRequire as createRequire5 } from "node:module";
|
|
22064
22271
|
import { homedir as homedir2 } from "node:os";
|
|
22065
|
-
import { dirname as dirname8, isAbsolute as
|
|
22272
|
+
import { dirname as dirname8, isAbsolute as isAbsolute6, join as join7, relative as relative9, resolve as resolve16 } from "node:path";
|
|
22066
22273
|
init_src();
|
|
22067
22274
|
var runtimeRequire2 = createRequire5(import.meta.url);
|
|
22068
22275
|
var SQLITE_SIDECAR_SUFFIXES2 = ["", "-wal", "-shm"];
|
|
@@ -22878,6 +23085,12 @@ var LOCAL_SQLITE_MIGRATIONS2 = [
|
|
|
22878
23085
|
)`,
|
|
22879
23086
|
"CREATE INDEX IF NOT EXISTS idx_projection_apply_receipts_journal ON projection_apply_receipts(journal_id)"
|
|
22880
23087
|
]
|
|
23088
|
+
},
|
|
23089
|
+
{
|
|
23090
|
+
id: "0020_projection_apply_recovery_proof",
|
|
23091
|
+
statements: [
|
|
23092
|
+
"ALTER TABLE projection_apply_receipts ADD COLUMN recovery_proof_json TEXT"
|
|
23093
|
+
]
|
|
22881
23094
|
}
|
|
22882
23095
|
];
|
|
22883
23096
|
var CHANGESET_STARTUP_CLEANUP_LIMIT = 100;
|
|
@@ -22975,7 +23188,6 @@ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.en
|
|
|
22975
23188
|
integrityCheck.legacy = vacuumLegacySqliteInto2(paths.legacyLocalStorePath, stagingPath);
|
|
22976
23189
|
makePrivateFile2(stagingPath);
|
|
22977
23190
|
migrateSqliteDatabaseSync2(stagingPath);
|
|
22978
|
-
compactSqliteDatabase2(stagingPath);
|
|
22979
23191
|
integrityCheck.staging = assertCurrentLocalStore2(stagingPath);
|
|
22980
23192
|
publishStagedLocalStore2(stagingPath, paths.localStorePath);
|
|
22981
23193
|
integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
|
|
@@ -22996,10 +23208,17 @@ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.en
|
|
|
22996
23208
|
function upgradeExistingLocalStoreTarget2(paths, integrityCheck) {
|
|
22997
23209
|
const lock = acquireLegacyMigrationLock2(paths);
|
|
22998
23210
|
try {
|
|
22999
|
-
|
|
23000
|
-
|
|
23001
|
-
|
|
23002
|
-
|
|
23211
|
+
const db = openSqliteDatabaseSync2(paths.localStorePath);
|
|
23212
|
+
let compacted = false;
|
|
23213
|
+
try {
|
|
23214
|
+
integrityCheck.target = assertUpgradeableLocalStoreTarget2(db, paths.localStorePath);
|
|
23215
|
+
migrateOpenedSqliteDatabase2(db);
|
|
23216
|
+
compacted = true;
|
|
23217
|
+
} finally {
|
|
23218
|
+
db.close();
|
|
23219
|
+
}
|
|
23220
|
+
if (compacted)
|
|
23221
|
+
removeSqliteSidecars2(paths.localStorePath);
|
|
23003
23222
|
integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
|
|
23004
23223
|
delete integrityCheck.error;
|
|
23005
23224
|
const markerPath = writeLegacyMigrationMarker2(paths, integrityCheck, []);
|
|
@@ -23082,6 +23301,14 @@ class SqliteLocalStore {
|
|
|
23082
23301
|
updatedAt: String(row.updated_at)
|
|
23083
23302
|
}));
|
|
23084
23303
|
}
|
|
23304
|
+
async deleteRepositorySession(repositoryId) {
|
|
23305
|
+
const db = await this.database();
|
|
23306
|
+
const existing = db.prepare("SELECT repository_id FROM repository_sessions WHERE repository_id = ?").get(repositoryId);
|
|
23307
|
+
if (!existing)
|
|
23308
|
+
return false;
|
|
23309
|
+
db.prepare("DELETE FROM repository_sessions WHERE repository_id = ?").run(repositoryId);
|
|
23310
|
+
return true;
|
|
23311
|
+
}
|
|
23085
23312
|
async enqueueRuntimeAgentJob(input) {
|
|
23086
23313
|
if (input.job.status !== "queued")
|
|
23087
23314
|
throw new Error("runtime-agent-job-enqueue-requires-queued-status");
|
|
@@ -23192,7 +23419,7 @@ class SqliteLocalStore {
|
|
|
23192
23419
|
maxAttempts,
|
|
23193
23420
|
debounceUntil: input.debounceUntil
|
|
23194
23421
|
});
|
|
23195
|
-
const inserted =
|
|
23422
|
+
const inserted = runtimeAgentJobInScope(db, runtimeAgentJobScope(input.job), input.job.jobId);
|
|
23196
23423
|
if (!inserted)
|
|
23197
23424
|
throw new Error(`runtime-agent-job-insert-failed: ${input.job.jobId}`);
|
|
23198
23425
|
const backpressure = maxQueuedJobs === undefined ? undefined : {
|
|
@@ -23276,21 +23503,15 @@ class SqliteLocalStore {
|
|
|
23276
23503
|
const nextAttempt = record2.attemptCount + 1;
|
|
23277
23504
|
if (nextAttempt > record2.maxAttempts) {
|
|
23278
23505
|
const failed = runtimeAgentJobWithPatch(record2.job, { status: "failed", updatedAt: input.now });
|
|
23279
|
-
db.
|
|
23280
|
-
|
|
23281
|
-
leased_at = NULL, lease_expires_at = NULL, last_error = ?, dead_lettered_at = ?
|
|
23282
|
-
WHERE job_id = ?`).run("failed", stableJson2(failed), input.now, nextAttempt, "max-attempts-exhausted", input.now, record2.job.jobId);
|
|
23506
|
+
updateRuntimeAgentJobInScope(db, input, record2.job.jobId, `status = ?, job_json = ?, updated_at = ?, attempt_count = ?, lease_owner = NULL,
|
|
23507
|
+
leased_at = NULL, lease_expires_at = NULL, last_error = ?, dead_lettered_at = ?`, ["failed", stableJson2(failed), input.now, nextAttempt, "max-attempts-exhausted", input.now]);
|
|
23283
23508
|
db.exec("COMMIT");
|
|
23284
23509
|
return;
|
|
23285
23510
|
}
|
|
23286
23511
|
const running = runtimeAgentJobWithPatch(record2.job, { status: "running", updatedAt: input.now });
|
|
23287
|
-
db.
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
WHERE job_id = ?`).run("running", stableJson2(running), input.now, nextAttempt, input.workerId, input.now, leaseExpiresAt, record2.job.jobId);
|
|
23291
|
-
const claimed = runtimeAgentJobById(db, record2.job.jobId);
|
|
23292
|
-
if (!claimed)
|
|
23293
|
-
throw new Error(`runtime-agent-job-not-found: ${record2.job.jobId}`);
|
|
23512
|
+
updateRuntimeAgentJobInScope(db, input, record2.job.jobId, `status = ?, job_json = ?, updated_at = ?, attempt_count = ?, lease_owner = ?,
|
|
23513
|
+
leased_at = ?, lease_expires_at = ?, last_error = NULL`, ["running", stableJson2(running), input.now, nextAttempt, input.workerId, input.now, leaseExpiresAt]);
|
|
23514
|
+
const claimed = requireRuntimeAgentJobInScope(db, input, record2.job.jobId);
|
|
23294
23515
|
db.exec("COMMIT");
|
|
23295
23516
|
return claimed;
|
|
23296
23517
|
} catch (error) {
|
|
@@ -23300,9 +23521,7 @@ class SqliteLocalStore {
|
|
|
23300
23521
|
}
|
|
23301
23522
|
async completeRuntimeAgentJob(input) {
|
|
23302
23523
|
const db = await this.database();
|
|
23303
|
-
const record2 =
|
|
23304
|
-
if (!record2)
|
|
23305
|
-
throw new Error(`runtime-agent-job-not-found: ${input.jobId}`);
|
|
23524
|
+
const record2 = requireRuntimeAgentJobInScope(db, input, input.jobId);
|
|
23306
23525
|
if (record2.job.status !== "running")
|
|
23307
23526
|
throw new Error(`runtime-agent-job-complete-requires-running: ${input.jobId}`);
|
|
23308
23527
|
if (input.workerId && record2.leaseOwner && record2.leaseOwner !== input.workerId) {
|
|
@@ -23315,52 +23534,31 @@ class SqliteLocalStore {
|
|
|
23315
23534
|
outputDigest: input.outputDigest,
|
|
23316
23535
|
runMetadata: input.runMetadata
|
|
23317
23536
|
});
|
|
23318
|
-
db.
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
WHERE job_id = ?`).run(input.status, stableJson2(job), input.now, input.outputDigest ?? record2.job.outputDigest ?? null, input.error ?? null, deadLetteredAt ?? null, input.jobId);
|
|
23322
|
-
const updated = runtimeAgentJobById(db, input.jobId);
|
|
23323
|
-
if (!updated)
|
|
23324
|
-
throw new Error(`runtime-agent-job-not-found: ${input.jobId}`);
|
|
23325
|
-
return updated;
|
|
23537
|
+
updateRuntimeAgentJobInScope(db, input, input.jobId, `status = ?, job_json = ?, updated_at = ?, output_digest = ?, lease_owner = NULL,
|
|
23538
|
+
leased_at = NULL, lease_expires_at = NULL, last_error = ?, dead_lettered_at = COALESCE(?, dead_lettered_at)`, [input.status, stableJson2(job), input.now, input.outputDigest ?? record2.job.outputDigest ?? null, input.error ?? null, deadLetteredAt ?? null]);
|
|
23539
|
+
return requireRuntimeAgentJobInScope(db, input, input.jobId);
|
|
23326
23540
|
}
|
|
23327
23541
|
async retryRuntimeAgentJob(input) {
|
|
23328
23542
|
const db = await this.database();
|
|
23329
|
-
const record2 =
|
|
23330
|
-
if (!record2)
|
|
23331
|
-
throw new Error(`runtime-agent-job-not-found: ${input.jobId}`);
|
|
23543
|
+
const record2 = requireRuntimeAgentJobInScope(db, input, input.jobId);
|
|
23332
23544
|
if (record2.attemptCount >= record2.maxAttempts) {
|
|
23333
23545
|
const failed = runtimeAgentJobWithPatch(record2.job, { status: "failed", updatedAt: input.now });
|
|
23334
|
-
db.
|
|
23335
|
-
|
|
23336
|
-
leased_at = NULL, lease_expires_at = NULL, last_error = ?, dead_lettered_at = ?
|
|
23337
|
-
WHERE job_id = ?`).run("failed", stableJson2(failed), input.now, input.reason ?? "max-attempts-exhausted", input.now, input.jobId);
|
|
23546
|
+
updateRuntimeAgentJobInScope(db, input, input.jobId, `status = ?, job_json = ?, updated_at = ?, lease_owner = NULL,
|
|
23547
|
+
leased_at = NULL, lease_expires_at = NULL, last_error = ?, dead_lettered_at = ?`, ["failed", stableJson2(failed), input.now, input.reason ?? "max-attempts-exhausted", input.now]);
|
|
23338
23548
|
} else {
|
|
23339
23549
|
const queued = runtimeAgentJobWithPatch(record2.job, { status: "queued", updatedAt: input.now });
|
|
23340
|
-
db.
|
|
23341
|
-
|
|
23342
|
-
|
|
23343
|
-
|
|
23344
|
-
}
|
|
23345
|
-
const updated = runtimeAgentJobById(db, input.jobId);
|
|
23346
|
-
if (!updated)
|
|
23347
|
-
throw new Error(`runtime-agent-job-not-found: ${input.jobId}`);
|
|
23348
|
-
return updated;
|
|
23550
|
+
updateRuntimeAgentJobInScope(db, input, input.jobId, `status = ?, job_json = ?, updated_at = ?, lease_owner = NULL,
|
|
23551
|
+
leased_at = NULL, lease_expires_at = NULL, last_error = ?, dead_lettered_at = NULL`, ["queued", stableJson2(queued), input.now, input.reason ?? null]);
|
|
23552
|
+
}
|
|
23553
|
+
return requireRuntimeAgentJobInScope(db, input, input.jobId);
|
|
23349
23554
|
}
|
|
23350
23555
|
async cancelRuntimeAgentJob(input) {
|
|
23351
23556
|
const db = await this.database();
|
|
23352
|
-
const record2 =
|
|
23353
|
-
if (!record2)
|
|
23354
|
-
throw new Error(`runtime-agent-job-not-found: ${input.jobId}`);
|
|
23557
|
+
const record2 = requireRuntimeAgentJobInScope(db, input, input.jobId);
|
|
23355
23558
|
const job = runtimeAgentJobWithPatch(record2.job, { status: input.status, updatedAt: input.now });
|
|
23356
|
-
db.
|
|
23357
|
-
|
|
23358
|
-
|
|
23359
|
-
WHERE job_id = ?`).run(input.status, stableJson2(job), input.now, input.reason ?? null, input.supersededByJobId ?? null, input.jobId);
|
|
23360
|
-
const updated = runtimeAgentJobById(db, input.jobId);
|
|
23361
|
-
if (!updated)
|
|
23362
|
-
throw new Error(`runtime-agent-job-not-found: ${input.jobId}`);
|
|
23363
|
-
return updated;
|
|
23559
|
+
updateRuntimeAgentJobInScope(db, input, input.jobId, `status = ?, job_json = ?, updated_at = ?, lease_owner = NULL,
|
|
23560
|
+
leased_at = NULL, lease_expires_at = NULL, last_error = ?, superseded_by_job_id = COALESCE(?, superseded_by_job_id)`, [input.status, stableJson2(job), input.now, input.reason ?? null, input.supersededByJobId ?? null]);
|
|
23561
|
+
return requireRuntimeAgentJobInScope(db, input, input.jobId);
|
|
23364
23562
|
}
|
|
23365
23563
|
async cancelStaleRuntimeAgentJobs(input) {
|
|
23366
23564
|
const db = await this.database();
|
|
@@ -23373,6 +23571,8 @@ class SqliteLocalStore {
|
|
|
23373
23571
|
const cancelled = [];
|
|
23374
23572
|
for (const record2 of staleRows) {
|
|
23375
23573
|
cancelled.push(await this.cancelRuntimeAgentJob({
|
|
23574
|
+
repository: input.repository,
|
|
23575
|
+
worktree: input.worktree,
|
|
23376
23576
|
jobId: record2.job.jobId,
|
|
23377
23577
|
status: "expired",
|
|
23378
23578
|
now: input.now,
|
|
@@ -23434,29 +23634,58 @@ class SqliteLocalStore {
|
|
|
23434
23634
|
(lookup_key, apply_id, journal_id, receipt_json, created_at, updated_at)
|
|
23435
23635
|
VALUES (?, ?, ?, ?, ?, ?)`).run(receipt.identity.lookupKey, receipt.identity.applyId, journalId, stableJson2(receipt), createdAt, createdAt);
|
|
23436
23636
|
}
|
|
23437
|
-
async
|
|
23637
|
+
async inspectProjectionApplyReceipt(lookupKey) {
|
|
23638
|
+
const db = await this.database();
|
|
23639
|
+
const row = db.prepare(`SELECT receipt.receipt_json, receipt.refresh_consumed_at, receipt.recovery_proof_json
|
|
23640
|
+
FROM projection_apply_receipts receipt
|
|
23641
|
+
JOIN changeset_journal journal ON journal.journal_id = receipt.journal_id
|
|
23642
|
+
WHERE receipt.lookup_key = ? AND journal.status = 'committed'`).get(lookupKey);
|
|
23643
|
+
if (!row?.receipt_json)
|
|
23644
|
+
return;
|
|
23645
|
+
const receipt = parseProjectionApplyReceipt(String(row.receipt_json));
|
|
23646
|
+
const recoveryProof = row.recovery_proof_json === null ? undefined : parseProjectionApplyRecoveryProof(String(row.recovery_proof_json), receipt);
|
|
23647
|
+
return {
|
|
23648
|
+
receipt,
|
|
23649
|
+
deliveryStatus: row.refresh_consumed_at === null ? "pending" : "delivered",
|
|
23650
|
+
...recoveryProof ? { recoveryProof } : {}
|
|
23651
|
+
};
|
|
23652
|
+
}
|
|
23653
|
+
async consumeProjectionApplyReceiptRecovery(proof) {
|
|
23438
23654
|
const db = await this.database();
|
|
23439
23655
|
db.exec("BEGIN IMMEDIATE");
|
|
23440
23656
|
try {
|
|
23441
|
-
const row = db.prepare(`SELECT receipt.receipt_json, receipt.refresh_consumed_at
|
|
23657
|
+
const row = db.prepare(`SELECT receipt.receipt_json, receipt.refresh_consumed_at, receipt.recovery_proof_json
|
|
23442
23658
|
FROM projection_apply_receipts receipt
|
|
23443
23659
|
JOIN changeset_journal journal ON journal.journal_id = receipt.journal_id
|
|
23444
|
-
WHERE receipt.lookup_key = ? AND journal.status = 'committed'`).get(lookupKey);
|
|
23660
|
+
WHERE receipt.lookup_key = ? AND journal.status = 'committed'`).get(proof.receipt.lookupKey);
|
|
23445
23661
|
if (!row?.receipt_json) {
|
|
23446
23662
|
db.exec("COMMIT");
|
|
23447
23663
|
return;
|
|
23448
23664
|
}
|
|
23449
|
-
const receipt =
|
|
23450
|
-
const
|
|
23451
|
-
if (
|
|
23452
|
-
throw new Error(`projection-apply-
|
|
23453
|
-
|
|
23454
|
-
|
|
23455
|
-
|
|
23456
|
-
|
|
23665
|
+
const receipt = parseProjectionApplyReceipt(String(row.receipt_json));
|
|
23666
|
+
const proofIssues = projectionApplyRecoveryProofReceiptInvariantIssues(proof, receipt);
|
|
23667
|
+
if (proofIssues.length > 0)
|
|
23668
|
+
throw new Error(`projection-apply-recovery-proof-invalid: ${proofIssues.join("; ")}`);
|
|
23669
|
+
if (row.refresh_consumed_at !== null) {
|
|
23670
|
+
const stored = row.recovery_proof_json === null ? undefined : parseProjectionApplyRecoveryProof(String(row.recovery_proof_json), receipt);
|
|
23671
|
+
if (!stored)
|
|
23672
|
+
throw new Error("projection-apply-receipt-delivered-without-recovery-proof");
|
|
23673
|
+
db.exec("COMMIT");
|
|
23674
|
+
return {
|
|
23675
|
+
receipt,
|
|
23676
|
+
proof: { ...stored, deliveryStatus: "already-delivered" },
|
|
23677
|
+
refreshSignalsDelivered: false
|
|
23678
|
+
};
|
|
23457
23679
|
}
|
|
23680
|
+
const deliveredProof = { ...proof, deliveryStatus: "delivered" };
|
|
23681
|
+
const updatedAt = nowIso2();
|
|
23682
|
+
const update = db.prepare(`UPDATE projection_apply_receipts
|
|
23683
|
+
SET refresh_consumed_at = ?, recovery_proof_json = ?, updated_at = ?
|
|
23684
|
+
WHERE lookup_key = ? AND apply_id = ? AND refresh_consumed_at IS NULL AND recovery_proof_json IS NULL`).run(updatedAt, stableJson2(deliveredProof), updatedAt, proof.receipt.lookupKey, proof.receipt.applyId);
|
|
23685
|
+
if (update.changes !== 1)
|
|
23686
|
+
throw new Error("projection-apply-recovery-consume-race");
|
|
23458
23687
|
db.exec("COMMIT");
|
|
23459
|
-
return { receipt, refreshSignalsDelivered };
|
|
23688
|
+
return { receipt, proof: deliveredProof, refreshSignalsDelivered: true };
|
|
23460
23689
|
} catch (error) {
|
|
23461
23690
|
db.exec("ROLLBACK");
|
|
23462
23691
|
throw error;
|
|
@@ -26527,51 +26756,48 @@ async function rebuildDerivedLandscapeState(store, input) {
|
|
|
26527
26756
|
digest: landscapeDigest(landscape, scopedRelations)
|
|
26528
26757
|
};
|
|
26529
26758
|
}
|
|
26530
|
-
|
|
26531
|
-
if (
|
|
26532
|
-
|
|
26533
|
-
|
|
26534
|
-
|
|
26535
|
-
|
|
26536
|
-
return {
|
|
26537
|
-
exec: (sql) => db.exec(sql),
|
|
26538
|
-
prepare: (sql) => db.prepare(sql),
|
|
26539
|
-
close: () => db.close()
|
|
26540
|
-
};
|
|
26541
|
-
} catch {
|
|
26542
|
-
const bunSqlite = await import("bun:sqlite");
|
|
26543
|
-
const db = new bunSqlite.Database(databasePath);
|
|
26544
|
-
return {
|
|
26545
|
-
exec: (sql) => db.exec(sql),
|
|
26546
|
-
prepare: (sql) => db.query(sql),
|
|
26547
|
-
close: () => db.close()
|
|
26548
|
-
};
|
|
26549
|
-
}
|
|
26759
|
+
function selectSqliteRuntime2() {
|
|
26760
|
+
if (process.versions.bun)
|
|
26761
|
+
return "bun";
|
|
26762
|
+
if (process.versions.node)
|
|
26763
|
+
return "node";
|
|
26764
|
+
throw new Error("Unsupported SQLite runtime: archctx requires the Bun or Node runtime, but neither process.versions.bun nor process.versions.node is set.");
|
|
26550
26765
|
}
|
|
26551
|
-
function
|
|
26552
|
-
if (databasePath !== ":memory:")
|
|
26553
|
-
ensurePrivateDir2(dirname8(databasePath));
|
|
26554
|
-
try {
|
|
26555
|
-
const nodeSqlite = runtimeRequire2("node:sqlite");
|
|
26556
|
-
const db2 = new nodeSqlite.DatabaseSync(databasePath);
|
|
26557
|
-
return {
|
|
26558
|
-
exec: (sql) => db2.exec(sql),
|
|
26559
|
-
prepare: (sql) => db2.prepare(sql),
|
|
26560
|
-
close: () => db2.close()
|
|
26561
|
-
};
|
|
26562
|
-
} catch (error) {
|
|
26563
|
-
if (error.code !== "ERR_UNKNOWN_BUILTIN_MODULE" && error.code !== "MODULE_NOT_FOUND") {
|
|
26564
|
-
throw error;
|
|
26565
|
-
}
|
|
26566
|
-
}
|
|
26567
|
-
const bunSqlite = runtimeRequire2("bun:sqlite");
|
|
26766
|
+
function adaptBunSqliteDatabase2(bunSqlite, databasePath) {
|
|
26568
26767
|
const db = new bunSqlite.Database(databasePath);
|
|
26768
|
+
const releaseStatements = () => db.clearQueryCache();
|
|
26569
26769
|
return {
|
|
26570
26770
|
exec: (sql) => db.exec(sql),
|
|
26571
26771
|
prepare: (sql) => db.query(sql),
|
|
26772
|
+
releaseStatements,
|
|
26773
|
+
close: () => {
|
|
26774
|
+
releaseStatements();
|
|
26775
|
+
db.close();
|
|
26776
|
+
}
|
|
26777
|
+
};
|
|
26778
|
+
}
|
|
26779
|
+
function adaptNodeSqliteDatabase2(nodeSqlite, databasePath) {
|
|
26780
|
+
const db = new nodeSqlite.DatabaseSync(databasePath);
|
|
26781
|
+
return {
|
|
26782
|
+
exec: (sql) => db.exec(sql),
|
|
26783
|
+
prepare: (sql) => db.prepare(sql),
|
|
26572
26784
|
close: () => db.close()
|
|
26573
26785
|
};
|
|
26574
26786
|
}
|
|
26787
|
+
async function openSqliteDatabase(databasePath) {
|
|
26788
|
+
if (databasePath !== ":memory:")
|
|
26789
|
+
ensurePrivateDir2(dirname8(databasePath));
|
|
26790
|
+
if (selectSqliteRuntime2() === "bun")
|
|
26791
|
+
return adaptBunSqliteDatabase2(await import("bun:sqlite"), databasePath);
|
|
26792
|
+
return adaptNodeSqliteDatabase2(await import("node:sqlite"), databasePath);
|
|
26793
|
+
}
|
|
26794
|
+
function openSqliteDatabaseSync2(databasePath) {
|
|
26795
|
+
if (databasePath !== ":memory:")
|
|
26796
|
+
ensurePrivateDir2(dirname8(databasePath));
|
|
26797
|
+
if (selectSqliteRuntime2() === "bun")
|
|
26798
|
+
return adaptBunSqliteDatabase2(runtimeRequire2("bun:sqlite"), databasePath);
|
|
26799
|
+
return adaptNodeSqliteDatabase2(runtimeRequire2("node:sqlite"), databasePath);
|
|
26800
|
+
}
|
|
26575
26801
|
function legacyMigrationResult2(migrated, skippedReason, paths, copiedFiles, details) {
|
|
26576
26802
|
return {
|
|
26577
26803
|
schemaVersion: "archcontext.legacy-local-store-migration/v1",
|
|
@@ -26623,20 +26849,16 @@ function assertCurrentLocalStoreSchema2(db, path) {
|
|
|
26623
26849
|
throw new Error(`SQLite local store schema incomplete for ${path}: missing migrations ${missingMigrations.join(", ")}`);
|
|
26624
26850
|
}
|
|
26625
26851
|
}
|
|
26626
|
-
function assertUpgradeableLocalStoreTarget2(path) {
|
|
26627
|
-
const
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
if (!hasArchContextMarker) {
|
|
26633
|
-
throw new Error(`SQLite target is not an ArchContext local store candidate: ${path}`);
|
|
26634
|
-
}
|
|
26635
|
-
if (integrity !== "ok")
|
|
26636
|
-
throw new Error(`SQLite integrity_check failed for ${path}: ${integrity}`);
|
|
26637
|
-
} finally {
|
|
26638
|
-
db.close();
|
|
26852
|
+
function assertUpgradeableLocalStoreTarget2(db, path) {
|
|
26853
|
+
const integrity = sqliteIntegrityCheckOpenDatabase2(db, path);
|
|
26854
|
+
const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
|
|
26855
|
+
const hasArchContextMarker = ["schema_migrations", "task_states", "repository_sessions", "snapshots"].some((table) => tables.has(table));
|
|
26856
|
+
if (!hasArchContextMarker) {
|
|
26857
|
+
throw new Error(`SQLite target is not an ArchContext local store candidate: ${path}`);
|
|
26639
26858
|
}
|
|
26859
|
+
if (integrity !== "ok")
|
|
26860
|
+
throw new Error(`SQLite integrity_check failed for ${path}: ${integrity}`);
|
|
26861
|
+
return integrity;
|
|
26640
26862
|
}
|
|
26641
26863
|
function assertTrustedLegacyLocalStoreSource2(paths) {
|
|
26642
26864
|
const stat = lstatSync6(paths.legacyLocalStorePath);
|
|
@@ -26665,23 +26887,29 @@ function vacuumLegacySqliteInto2(sourcePath, targetPath) {
|
|
|
26665
26887
|
}
|
|
26666
26888
|
function migrateSqliteDatabaseSync2(databasePath) {
|
|
26667
26889
|
const db = openSqliteDatabaseSync2(databasePath);
|
|
26890
|
+
let compacted = false;
|
|
26668
26891
|
try {
|
|
26669
|
-
|
|
26670
|
-
|
|
26671
|
-
backfillArchitectureChangeFeed2(db);
|
|
26892
|
+
migrateOpenedSqliteDatabase2(db);
|
|
26893
|
+
compacted = true;
|
|
26672
26894
|
} finally {
|
|
26673
26895
|
db.close();
|
|
26674
26896
|
}
|
|
26897
|
+
if (compacted)
|
|
26898
|
+
removeSqliteSidecars2(databasePath);
|
|
26675
26899
|
}
|
|
26676
|
-
function
|
|
26677
|
-
|
|
26678
|
-
|
|
26679
|
-
|
|
26680
|
-
|
|
26681
|
-
|
|
26682
|
-
|
|
26683
|
-
|
|
26684
|
-
|
|
26900
|
+
function migrateOpenedSqliteDatabase2(db) {
|
|
26901
|
+
applyLocalSqliteMigrations2(db);
|
|
26902
|
+
backfillArchitectureEventDirectScope2(db);
|
|
26903
|
+
backfillArchitectureChangeFeed2(db);
|
|
26904
|
+
compactMigratedSqliteDatabase2(db);
|
|
26905
|
+
}
|
|
26906
|
+
function compactMigratedSqliteDatabase2(db) {
|
|
26907
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
26908
|
+
db.releaseStatements?.();
|
|
26909
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
26910
|
+
db.exec("PRAGMA journal_mode = DELETE");
|
|
26911
|
+
}
|
|
26912
|
+
function removeSqliteSidecars2(databasePath) {
|
|
26685
26913
|
for (const suffix of ["-wal", "-shm"])
|
|
26686
26914
|
rmSync5(`${databasePath}${suffix}`, { force: true });
|
|
26687
26915
|
}
|
|
@@ -26812,14 +27040,14 @@ function ensurePrivateDir2(path) {
|
|
|
26812
27040
|
mkdirSync5(path, { recursive: true, mode: 448 });
|
|
26813
27041
|
if (process.platform !== "win32") {
|
|
26814
27042
|
try {
|
|
26815
|
-
|
|
27043
|
+
chmodSync3(path, 448);
|
|
26816
27044
|
} catch {}
|
|
26817
27045
|
}
|
|
26818
27046
|
}
|
|
26819
27047
|
function makePrivateFile2(path) {
|
|
26820
27048
|
if (process.platform !== "win32") {
|
|
26821
27049
|
try {
|
|
26822
|
-
|
|
27050
|
+
chmodSync3(path, 384);
|
|
26823
27051
|
} catch {}
|
|
26824
27052
|
}
|
|
26825
27053
|
}
|
|
@@ -26836,7 +27064,7 @@ function readGitPath2(root, args) {
|
|
|
26836
27064
|
}
|
|
26837
27065
|
}
|
|
26838
27066
|
function resolveMaybeRelative2(base, path) {
|
|
26839
|
-
return
|
|
27067
|
+
return isAbsolute6(path) ? resolve16(path) : resolve16(base, path);
|
|
26840
27068
|
}
|
|
26841
27069
|
function canonicalPath2(path) {
|
|
26842
27070
|
const resolved = resolve16(path);
|
|
@@ -26849,8 +27077,8 @@ function canonicalPath2(path) {
|
|
|
26849
27077
|
function isPathInsideOrSame2(path, parent) {
|
|
26850
27078
|
const child = resolve16(path);
|
|
26851
27079
|
const base = resolve16(parent);
|
|
26852
|
-
const fromBase =
|
|
26853
|
-
return fromBase === "" || !!fromBase && !fromBase.startsWith("..") && !
|
|
27080
|
+
const fromBase = relative9(base, child);
|
|
27081
|
+
return fromBase === "" || !!fromBase && !fromBase.startsWith("..") && !isAbsolute6(fromBase);
|
|
26854
27082
|
}
|
|
26855
27083
|
function stableStorageId2(prefix, value) {
|
|
26856
27084
|
return `${prefix}.${createHash9("sha256").update(value).digest("hex").slice(0, 16)}`;
|
|
@@ -26942,10 +27170,29 @@ function insertRuntimeAgentJob(db, input) {
|
|
|
26942
27170
|
lease_expires_at, last_error, dead_lettered_at, debounce_until, superseded_by_job_id)
|
|
26943
27171
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, ?, NULL)`).run(input.job.jobId, input.job.repository.repositoryId, input.job.repository.storageRepositoryId, input.job.worktree.workspaceId, input.job.worktree.storageWorkspaceId, input.analysisKind, input.coalesceKey, input.priority, input.job.status, input.job.runnerPort, input.job.fingerprint, input.job.inputDigest, input.job.promptTemplateDigest, input.job.outputDigest ?? null, input.job.stalePolicy, stableJson2(input.job), input.job.queuedAt, input.job.updatedAt, 0, input.maxAttempts, input.debounceUntil ?? null);
|
|
26944
27172
|
}
|
|
26945
|
-
function
|
|
26946
|
-
const row = db.prepare(
|
|
27173
|
+
function runtimeAgentJobInScope(db, scope, jobId) {
|
|
27174
|
+
const row = db.prepare(`SELECT * FROM runtime_job_queue
|
|
27175
|
+
WHERE job_id = ?
|
|
27176
|
+
AND storage_repository_id = ?
|
|
27177
|
+
AND storage_workspace_id = ?`).get(jobId, scope.repository.storageRepositoryId, scope.worktree.storageWorkspaceId);
|
|
26947
27178
|
return row ? runtimeAgentJobRecordFromRow(row) : undefined;
|
|
26948
27179
|
}
|
|
27180
|
+
function requireRuntimeAgentJobInScope(db, scope, jobId) {
|
|
27181
|
+
const record2 = runtimeAgentJobInScope(db, scope, jobId);
|
|
27182
|
+
if (!record2)
|
|
27183
|
+
throw new Error(`runtime-agent-job-not-found-in-scope: ${jobId}`);
|
|
27184
|
+
return record2;
|
|
27185
|
+
}
|
|
27186
|
+
function updateRuntimeAgentJobInScope(db, scope, jobId, assignments, params) {
|
|
27187
|
+
db.prepare(`UPDATE runtime_job_queue
|
|
27188
|
+
SET ${assignments}
|
|
27189
|
+
WHERE job_id = ?
|
|
27190
|
+
AND storage_repository_id = ?
|
|
27191
|
+
AND storage_workspace_id = ?`).run(...params, jobId, scope.repository.storageRepositoryId, scope.worktree.storageWorkspaceId);
|
|
27192
|
+
}
|
|
27193
|
+
function runtimeAgentJobScope(job) {
|
|
27194
|
+
return { repository: job.repository, worktree: job.worktree };
|
|
27195
|
+
}
|
|
26949
27196
|
function runtimeAgentJobRecordFromRow(row) {
|
|
26950
27197
|
return {
|
|
26951
27198
|
job: JSON.parse(String(row.job_json)),
|
|
@@ -26982,6 +27229,30 @@ function runtimeAgentJobWithPatch(job, patch) {
|
|
|
26982
27229
|
function nullableString(value) {
|
|
26983
27230
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
26984
27231
|
}
|
|
27232
|
+
function parseProjectionApplyReceipt(raw) {
|
|
27233
|
+
let receipt;
|
|
27234
|
+
try {
|
|
27235
|
+
receipt = JSON.parse(raw);
|
|
27236
|
+
} catch (error) {
|
|
27237
|
+
throw new Error(`projection-apply-receipt-invalid-json: ${error instanceof Error ? error.message : String(error)}`);
|
|
27238
|
+
}
|
|
27239
|
+
const issues = projectionApplyReceiptInvariantIssues(receipt);
|
|
27240
|
+
if (issues.length > 0)
|
|
27241
|
+
throw new Error(`projection-apply-receipt-invalid: ${issues.join("; ")}`);
|
|
27242
|
+
return receipt;
|
|
27243
|
+
}
|
|
27244
|
+
function parseProjectionApplyRecoveryProof(raw, receipt) {
|
|
27245
|
+
let proof;
|
|
27246
|
+
try {
|
|
27247
|
+
proof = JSON.parse(raw);
|
|
27248
|
+
} catch (error) {
|
|
27249
|
+
throw new Error(`projection-apply-recovery-proof-invalid-json: ${error instanceof Error ? error.message : String(error)}`);
|
|
27250
|
+
}
|
|
27251
|
+
const issues = projectionApplyRecoveryProofReceiptInvariantIssues(proof, receipt);
|
|
27252
|
+
if (issues.length > 0)
|
|
27253
|
+
throw new Error(`projection-apply-recovery-proof-invalid: ${issues.join("; ")}`);
|
|
27254
|
+
return proof;
|
|
27255
|
+
}
|
|
26985
27256
|
function nowIso2() {
|
|
26986
27257
|
return new Date().toISOString();
|
|
26987
27258
|
}
|
|
@@ -27641,13 +27912,13 @@ async function withGithubIssueBodyFile(body, fn, deps = {}) {
|
|
|
27641
27912
|
rmSync7(dir, { recursive: true, force: true });
|
|
27642
27913
|
}
|
|
27643
27914
|
}
|
|
27644
|
-
var
|
|
27645
|
-
/gh[opsu]_[A-Za-z0-9_]
|
|
27646
|
-
/Bearer\s+[A-Za-z0-9._-]+/i,
|
|
27647
|
-
/-----BEGIN [A-Z ]*PRIVATE KEY
|
|
27648
|
-
/GITHUB_WEBHOOK_SECRET/i,
|
|
27649
|
-
/installation[_-]?token/i,
|
|
27650
|
-
|
|
27915
|
+
var SECRET_DETECTORS = [
|
|
27916
|
+
{ id: "github-token-prefix", pattern: /gh[opsu]_[A-Za-z0-9_]+/ },
|
|
27917
|
+
{ id: "bearer-credential", pattern: /Bearer\s+[A-Za-z0-9._-]+/i },
|
|
27918
|
+
{ id: "private-key-header", pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
27919
|
+
{ id: "github-webhook-secret", pattern: /GITHUB_WEBHOOK_SECRET/i },
|
|
27920
|
+
{ id: "installation-token-value", pattern: /installation[_-]?token["']?\s*[:=]\s*["']?[A-Za-z0-9._-]{16,}/i },
|
|
27921
|
+
{ id: "compact-jwt-value", pattern: /\beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}/ }
|
|
27651
27922
|
];
|
|
27652
27923
|
var GITHUB_ISSUE_BODY_MAX_LENGTH = 65536;
|
|
27653
27924
|
function githubIssueFooterMarker(runId, draftDigest) {
|
|
@@ -27665,11 +27936,19 @@ function preflightGithubIssueDrafts(runId, drafts) {
|
|
|
27665
27936
|
|
|
27666
27937
|
${footer}
|
|
27667
27938
|
`;
|
|
27668
|
-
const
|
|
27669
|
-
|
|
27670
|
-
|
|
27671
|
-
|
|
27672
|
-
|
|
27939
|
+
const scanned = [
|
|
27940
|
+
{ field: "title", text: draft.title },
|
|
27941
|
+
{ field: "body", text: body },
|
|
27942
|
+
...draft.labels.map((label) => ({ field: "label", text: label }))
|
|
27943
|
+
];
|
|
27944
|
+
for (const { field, text } of scanned) {
|
|
27945
|
+
for (const detector of SECRET_DETECTORS) {
|
|
27946
|
+
if (detector.pattern.test(text)) {
|
|
27947
|
+
return {
|
|
27948
|
+
ok: false,
|
|
27949
|
+
reason: `github issue draft ${draft.draftId} matched a secret-shaped pattern (detector ${detector.id}) in its ${field}; publishing aborted for the entire run`
|
|
27950
|
+
};
|
|
27951
|
+
}
|
|
27673
27952
|
}
|
|
27674
27953
|
}
|
|
27675
27954
|
if (body.length > GITHUB_ISSUE_BODY_MAX_LENGTH) {
|
|
@@ -28491,6 +28770,8 @@ function auditGithubIssuesEnabledInManifestText(manifestText) {
|
|
|
28491
28770
|
return false;
|
|
28492
28771
|
}
|
|
28493
28772
|
var RUNTIME_RPC_VERSION = LOCAL_RUNTIME_RPC_SCHEMA_VERSION;
|
|
28773
|
+
var RUNTIME_RPC_MAX_REQUEST_BODY_BYTES = 16 * 1024 * 1024;
|
|
28774
|
+
var RUNTIME_RPC_REQUEST_BODY_TIMEOUT_MS = 30000;
|
|
28494
28775
|
|
|
28495
28776
|
class RuntimeUpdateInputError extends Error {
|
|
28496
28777
|
}
|
|
@@ -29074,12 +29355,15 @@ class ArchctxDaemon {
|
|
|
29074
29355
|
const scope = await this.architectureLedgerScope(repositoryRoot);
|
|
29075
29356
|
const jobs = await this.localStore.listRuntimeAgentJobs(scope);
|
|
29076
29357
|
const record2 = jobs.find((candidate) => candidate.job.jobId === input.jobId);
|
|
29077
|
-
if (record2
|
|
29358
|
+
if (!record2)
|
|
29359
|
+
return runtimeAgentJobOutOfScopeEnvelope("jobs.complete", input.jobId);
|
|
29360
|
+
if (record2.job.status !== "running") {
|
|
29078
29361
|
return errorEnvelope("jobs.complete", "AC_PRECONDITION_FAILED", `runtime agent job completion requires a running job: ${input.jobId}`);
|
|
29079
29362
|
}
|
|
29080
29363
|
if (input.status === "succeeded") {
|
|
29081
|
-
if (record2
|
|
29364
|
+
if (record2.job.stalePolicy === "cancel-on-head-change" && isRuntimeAgentJobCursorStale(record2.job, scope)) {
|
|
29082
29365
|
await this.localStore.cancelRuntimeAgentJob({
|
|
29366
|
+
...scope,
|
|
29083
29367
|
jobId: input.jobId,
|
|
29084
29368
|
status: "expired",
|
|
29085
29369
|
now: input.now ?? this.clock(),
|
|
@@ -29091,7 +29375,7 @@ class ArchctxDaemon {
|
|
|
29091
29375
|
if (input.proposalPlan) {
|
|
29092
29376
|
const validation = validateRuntimeAgentProposalPlan({
|
|
29093
29377
|
proposalPlan: input.proposalPlan,
|
|
29094
|
-
job: record2
|
|
29378
|
+
job: record2.job,
|
|
29095
29379
|
jobId: input.jobId,
|
|
29096
29380
|
outputDigest: input.outputDigest
|
|
29097
29381
|
});
|
|
@@ -29103,6 +29387,7 @@ class ArchctxDaemon {
|
|
|
29103
29387
|
proposalPlan: input.proposalPlan
|
|
29104
29388
|
} : input.runMetadata;
|
|
29105
29389
|
const job = await this.localStore.completeRuntimeAgentJob({
|
|
29390
|
+
...scope,
|
|
29106
29391
|
jobId: input.jobId,
|
|
29107
29392
|
status: input.status,
|
|
29108
29393
|
workerId: input.workerId,
|
|
@@ -29115,8 +29400,12 @@ class ArchctxDaemon {
|
|
|
29115
29400
|
}
|
|
29116
29401
|
async jobsRetry(root, input) {
|
|
29117
29402
|
this.assertRunning();
|
|
29118
|
-
await this.architectureLedgerScope(findRepositoryRoot2(root));
|
|
29403
|
+
const scope = await this.architectureLedgerScope(findRepositoryRoot2(root));
|
|
29404
|
+
if (!await this.runtimeAgentJobInScope(scope, input.jobId)) {
|
|
29405
|
+
return runtimeAgentJobOutOfScopeEnvelope("jobs.retry", input.jobId);
|
|
29406
|
+
}
|
|
29119
29407
|
const job = await this.localStore.retryRuntimeAgentJob({
|
|
29408
|
+
...scope,
|
|
29120
29409
|
jobId: input.jobId,
|
|
29121
29410
|
reason: input.reason,
|
|
29122
29411
|
now: input.now ?? this.clock()
|
|
@@ -29125,8 +29414,12 @@ class ArchctxDaemon {
|
|
|
29125
29414
|
}
|
|
29126
29415
|
async jobsCancel(root, input) {
|
|
29127
29416
|
this.assertRunning();
|
|
29128
|
-
await this.architectureLedgerScope(findRepositoryRoot2(root));
|
|
29417
|
+
const scope = await this.architectureLedgerScope(findRepositoryRoot2(root));
|
|
29418
|
+
if (!await this.runtimeAgentJobInScope(scope, input.jobId)) {
|
|
29419
|
+
return runtimeAgentJobOutOfScopeEnvelope("jobs.cancel", input.jobId);
|
|
29420
|
+
}
|
|
29129
29421
|
const job = await this.localStore.cancelRuntimeAgentJob({
|
|
29422
|
+
...scope,
|
|
29130
29423
|
jobId: input.jobId,
|
|
29131
29424
|
status: input.status ?? "cancelled",
|
|
29132
29425
|
reason: input.reason,
|
|
@@ -29135,6 +29428,10 @@ class ArchctxDaemon {
|
|
|
29135
29428
|
});
|
|
29136
29429
|
return okEnvelope("jobs.cancel", { job });
|
|
29137
29430
|
}
|
|
29431
|
+
async runtimeAgentJobInScope(scope, jobId) {
|
|
29432
|
+
const jobs = await this.localStore.listRuntimeAgentJobs(scope);
|
|
29433
|
+
return jobs.find((candidate) => candidate.job.jobId === jobId);
|
|
29434
|
+
}
|
|
29138
29435
|
async auditRun(root, input = {}) {
|
|
29139
29436
|
this.assertRunning();
|
|
29140
29437
|
const repositoryRoot = findRepositoryRoot2(root);
|
|
@@ -29358,14 +29655,22 @@ class ArchctxDaemon {
|
|
|
29358
29655
|
return typeof manifestRaw === "string" && auditGithubIssuesEnabledInManifestText(manifestRaw);
|
|
29359
29656
|
}
|
|
29360
29657
|
async canFileGithubIssues(root) {
|
|
29361
|
-
const
|
|
29362
|
-
if (
|
|
29658
|
+
const target = readGitRemoteTarget(root);
|
|
29659
|
+
if (!target) {
|
|
29363
29660
|
return {
|
|
29364
29661
|
ok: false,
|
|
29365
29662
|
code: "AC_PRECONDITION_FAILED",
|
|
29366
29663
|
message: "audit approve requires a resolvable GitHub owner/repo; git remote 'origin' is missing or is not a parseable GitHub URL"
|
|
29367
29664
|
};
|
|
29368
29665
|
}
|
|
29666
|
+
if (target.host !== SUPPORTED_GITHUB_REMOTE_HOST) {
|
|
29667
|
+
return {
|
|
29668
|
+
ok: false,
|
|
29669
|
+
code: "AC_PRECONDITION_FAILED",
|
|
29670
|
+
message: `audit approve supports ${SUPPORTED_GITHUB_REMOTE_HOST} remotes only (ADR-0042); git remote 'origin' resolves to host "${target.host}", and ${target.owner}/${target.repo} there is not the same repository as ${target.owner}/${target.repo} on ${SUPPORTED_GITHUB_REMOTE_HOST}`
|
|
29671
|
+
};
|
|
29672
|
+
}
|
|
29673
|
+
const repoNameWithOwner = `${target.owner}/${target.repo}`;
|
|
29369
29674
|
const token = process.env[AUDIT_APPROVE_GH_TOKEN_ENV];
|
|
29370
29675
|
if (!token) {
|
|
29371
29676
|
return {
|
|
@@ -29393,7 +29698,7 @@ class ArchctxDaemon {
|
|
|
29393
29698
|
message: `audit approve received an unrecognized visibility "${probedVisibility}" for ${repoNameWithOwner}; refusing to guess whether it is safe to publish`
|
|
29394
29699
|
};
|
|
29395
29700
|
}
|
|
29396
|
-
return { ok: true, repoNameWithOwner, visibility, token };
|
|
29701
|
+
return { ok: true, host: target.host, repoNameWithOwner, visibility, token };
|
|
29397
29702
|
}
|
|
29398
29703
|
async auditList(root, input = {}) {
|
|
29399
29704
|
this.assertRunning();
|
|
@@ -29468,9 +29773,9 @@ class ArchctxDaemon {
|
|
|
29468
29773
|
const capability = await this.canFileGithubIssues(repositoryRoot);
|
|
29469
29774
|
if (!capability.ok)
|
|
29470
29775
|
return errorEnvelope("audit.approve", capability.code, capability.message);
|
|
29471
|
-
const expectedConfirmToken = `public:${capability.repoNameWithOwner}:${run.baseSha}:${run.runId}`;
|
|
29776
|
+
const expectedConfirmToken = `public:${capability.host}/${capability.repoNameWithOwner}:${run.baseSha}:${run.runId}`;
|
|
29472
29777
|
if (capability.visibility !== "private" && input.confirmPublicToken !== expectedConfirmToken) {
|
|
29473
|
-
return errorEnvelope("audit.approve", "AC_USER_CONFIRMATION_REQUIRED", `audit run ${run.runId} targets a ${capability.visibility} repository (${capability.repoNameWithOwner}); rerun with explicit confirmation: archctx audit approve ${run.runId} --confirm-public-repo ${expectedConfirmToken}`);
|
|
29778
|
+
return errorEnvelope("audit.approve", "AC_USER_CONFIRMATION_REQUIRED", `audit run ${run.runId} targets a ${capability.visibility} repository (${capability.host}/${capability.repoNameWithOwner}); rerun with explicit confirmation: archctx audit approve ${run.runId} --confirm-public-repo ${expectedConfirmToken}`);
|
|
29474
29779
|
}
|
|
29475
29780
|
const preflight = preflightGithubIssueDrafts(run.runId, drafts);
|
|
29476
29781
|
if (!preflight.ok)
|
|
@@ -29701,7 +30006,8 @@ class ArchctxDaemon {
|
|
|
29701
30006
|
return errorEnvelope("docs.pin", "AC_SCHEMA_INVALID", "docs pin requires --library-id and --version");
|
|
29702
30007
|
assertContext7LibraryId(input.libraryId);
|
|
29703
30008
|
assertContext7Version(input.version);
|
|
29704
|
-
const
|
|
30009
|
+
const current = readContext7LockfileState(session.workspace.root);
|
|
30010
|
+
const lock = upsertContext7Pin(current.lock, {
|
|
29705
30011
|
libraryId: input.libraryId,
|
|
29706
30012
|
version: input.version,
|
|
29707
30013
|
pinnedAt: this.clock(),
|
|
@@ -29715,7 +30021,7 @@ class ArchctxDaemon {
|
|
|
29715
30021
|
lock
|
|
29716
30022
|
});
|
|
29717
30023
|
}
|
|
29718
|
-
writeContext7Lockfile(session.workspace.root, lock);
|
|
30024
|
+
writeContext7Lockfile(session.workspace.root, lock, current.expectedHash);
|
|
29719
30025
|
return okEnvelope("docs.pin", {
|
|
29720
30026
|
schemaVersion: "archcontext.context7-pin/v1",
|
|
29721
30027
|
approved: true,
|
|
@@ -30057,12 +30363,55 @@ class ArchctxDaemon {
|
|
|
30057
30363
|
});
|
|
30058
30364
|
});
|
|
30059
30365
|
}
|
|
30060
|
-
async
|
|
30366
|
+
async inspectProjectionApplyReceipt(root, lookupKey) {
|
|
30367
|
+
this.assertRunning();
|
|
30368
|
+
await this.openSession(root);
|
|
30369
|
+
const inspection = await this.localStore.inspectProjectionApplyReceipt(lookupKey);
|
|
30370
|
+
return okEnvelope("projection.inspect-receipt", {
|
|
30371
|
+
found: inspection !== undefined,
|
|
30372
|
+
...inspection ?? {}
|
|
30373
|
+
});
|
|
30374
|
+
}
|
|
30375
|
+
async recoverProjectionApply(root, intent) {
|
|
30061
30376
|
this.assertRunning();
|
|
30377
|
+
const intentIssues = projectionApplyRecoveryIntentInvariantIssues(intent);
|
|
30378
|
+
if (intentIssues.length > 0) {
|
|
30379
|
+
return errorEnvelope("projection.recover", "AC_SCHEMA_INVALID", `projection recovery intent invariant failed: ${intentIssues.join("; ")}`);
|
|
30380
|
+
}
|
|
30062
30381
|
return this.withWriter(async () => {
|
|
30063
|
-
await this.openSession(root);
|
|
30064
|
-
const
|
|
30065
|
-
|
|
30382
|
+
const session = await this.openSession(root);
|
|
30383
|
+
const inspection = await this.localStore.inspectProjectionApplyReceipt(intent.receipt.lookupKey);
|
|
30384
|
+
if (!inspection || inspection.receipt.identity.applyId !== intent.receipt.applyId) {
|
|
30385
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", "committed projection apply receipt was not found");
|
|
30386
|
+
}
|
|
30387
|
+
if (inspection.deliveryStatus === "delivered") {
|
|
30388
|
+
if (!inspection.recoveryProof) {
|
|
30389
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", "committed projection receipt was delivered without a recovery proof");
|
|
30390
|
+
}
|
|
30391
|
+
return okEnvelope("projection.recover", {
|
|
30392
|
+
found: true,
|
|
30393
|
+
receipt: inspection.receipt,
|
|
30394
|
+
proof: { ...inspection.recoveryProof, deliveryStatus: "already-delivered" },
|
|
30395
|
+
refreshSignalsDelivered: false
|
|
30396
|
+
});
|
|
30397
|
+
}
|
|
30398
|
+
let fixedPoint;
|
|
30399
|
+
try {
|
|
30400
|
+
fixedPoint = buildRuntimeProjectionRecoveryFixedPoint(root);
|
|
30401
|
+
} catch (error) {
|
|
30402
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
30403
|
+
}
|
|
30404
|
+
const issues = runtimeProjectionRecoveryFixedPointIssues(inspection.receipt, fixedPoint);
|
|
30405
|
+
if (issues.length > 0) {
|
|
30406
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", `projection recovery proof failed: ${issues.join("; ")}`);
|
|
30407
|
+
}
|
|
30408
|
+
const proof = createRuntimeProjectionRecoveryProof(intent, inspection.receipt, fixedPoint);
|
|
30409
|
+
const currentWorktreeDigest = runtimeWorktreeDigest(root, "architecture-documentation-projection");
|
|
30410
|
+
if (session.workspace.repositoryId !== proof.current.snapshot.repositoryId || session.workspace.headSha !== proof.current.snapshot.headSha || currentWorktreeDigest !== proof.current.snapshot.worktreeDigest) {
|
|
30411
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", "projection recovery authority changed before delivery");
|
|
30412
|
+
}
|
|
30413
|
+
const consumption = await this.localStore.consumeProjectionApplyReceiptRecovery(proof);
|
|
30414
|
+
return okEnvelope("projection.recover", {
|
|
30066
30415
|
found: consumption !== undefined,
|
|
30067
30416
|
...consumption ?? {}
|
|
30068
30417
|
});
|
|
@@ -30131,7 +30480,6 @@ class ArchctxDaemon {
|
|
|
30131
30480
|
await this.changeSetEngine.apply(root, draft, { approved: true });
|
|
30132
30481
|
}
|
|
30133
30482
|
async applyArchitectureProjectionRollbackChangeSet(root, projectedFiles, currentFiles, createdAt) {
|
|
30134
|
-
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
30135
30483
|
const backupBase = `.archcontext/backups/ledger-rollback/${safePathSegment(createdAt)}`;
|
|
30136
30484
|
const backupRelativePath = uniqueBackupPath(root, backupBase);
|
|
30137
30485
|
const manifestPath = `${backupRelativePath}/manifest.json`;
|
|
@@ -30140,7 +30488,7 @@ class ArchctxDaemon {
|
|
|
30140
30488
|
path: backupRelativePath,
|
|
30141
30489
|
manifestPath
|
|
30142
30490
|
});
|
|
30143
|
-
const removedPaths = currentFiles
|
|
30491
|
+
const removedPaths = obsoleteManagedProjectionPaths(currentFiles, projectedFiles);
|
|
30144
30492
|
await this.applyArchitectureProjectionChangeSet(root, {
|
|
30145
30493
|
id: `changeset.ledger-rollback-${shortDigest3(digestJson({ createdAt, projectionDigest: architectureLedgerProjectionDigest(projectedFiles) }))}`,
|
|
30146
30494
|
files: [
|
|
@@ -30514,11 +30862,12 @@ class ArchctxDaemon {
|
|
|
30514
30862
|
const scope = await this.architectureLedgerScope(root);
|
|
30515
30863
|
const state = await this.localStore.readArchitectureLedgerState(scope);
|
|
30516
30864
|
const projectedFiles = projectArchitectureLedgerStateToYamlFiles(state);
|
|
30865
|
+
const removedPaths = obsoleteManagedProjectionPaths(listModelFiles(root).filter((file) => isArchitectureLedgerManagedModelPath(file.path)), projectedFiles);
|
|
30517
30866
|
if (writes) {
|
|
30518
30867
|
await this.applyArchitectureProjectionChangeSet(root, {
|
|
30519
30868
|
id: `changeset.ledger-project-${shortDigest3(architectureLedgerProjectionDigest(projectedFiles))}`,
|
|
30520
30869
|
files: projectedFiles.map(({ path, body }) => ({ path, body })),
|
|
30521
|
-
removedPaths
|
|
30870
|
+
removedPaths
|
|
30522
30871
|
});
|
|
30523
30872
|
}
|
|
30524
30873
|
const drift = compareArchitectureLedgerStateToYaml({
|
|
@@ -30539,6 +30888,7 @@ class ArchctxDaemon {
|
|
|
30539
30888
|
projectionDigest: architectureLedgerProjectionDigest(projectedFiles),
|
|
30540
30889
|
graphDigest: architectureLedgerStateDigest(state),
|
|
30541
30890
|
writtenPaths: writes ? projectedFiles.map((file) => file.path) : [],
|
|
30891
|
+
removedPaths: writes ? removedPaths : [],
|
|
30542
30892
|
projectedFiles: writes ? undefined : projectedFiles,
|
|
30543
30893
|
drift,
|
|
30544
30894
|
reconcile
|
|
@@ -31015,12 +31365,21 @@ class ArchctxDaemon {
|
|
|
31015
31365
|
const paths = createDeveloperReviewRunPaths({
|
|
31016
31366
|
sourceRoot,
|
|
31017
31367
|
challengeId: input.challenge.challengeId,
|
|
31018
|
-
tempRoot: input.tempRoot
|
|
31019
|
-
stateDir: input.stateDir
|
|
31368
|
+
tempRoot: input.tempRoot
|
|
31020
31369
|
});
|
|
31021
31370
|
mkdirSync7(paths.stateDir, { recursive: true });
|
|
31022
31371
|
mkdirSync7(paths.runRoot, { recursive: true });
|
|
31023
31372
|
mkdirSync7(paths.worktreeTempRoot, { recursive: true });
|
|
31373
|
+
const createdAt = this.clock();
|
|
31374
|
+
writeDeveloperReviewRunOwnerMarker({
|
|
31375
|
+
runRoot: paths.runRoot,
|
|
31376
|
+
runId: paths.runId,
|
|
31377
|
+
challengeId: input.challenge.challengeId,
|
|
31378
|
+
stateDir: paths.stateDir,
|
|
31379
|
+
manifestPath: paths.manifestPath,
|
|
31380
|
+
lockPath: paths.lockPath,
|
|
31381
|
+
createdAt
|
|
31382
|
+
});
|
|
31024
31383
|
const preparing = {
|
|
31025
31384
|
schemaVersion: "archcontext.developer-review-run/v1",
|
|
31026
31385
|
runId: paths.runId,
|
|
@@ -31032,7 +31391,7 @@ class ArchctxDaemon {
|
|
|
31032
31391
|
manifestPath: paths.manifestPath,
|
|
31033
31392
|
lockPath: paths.lockPath,
|
|
31034
31393
|
pid: process.pid,
|
|
31035
|
-
createdAt
|
|
31394
|
+
createdAt,
|
|
31036
31395
|
status: "preparing",
|
|
31037
31396
|
codeGraphTemporaryState: {
|
|
31038
31397
|
root: paths.runRoot,
|
|
@@ -31092,12 +31451,13 @@ class ArchctxDaemon {
|
|
|
31092
31451
|
}
|
|
31093
31452
|
}
|
|
31094
31453
|
cleanupDeveloperReviewRun(run) {
|
|
31454
|
+
const targets = resolveOwnedDeveloperReviewRunTargets(run);
|
|
31095
31455
|
const removed = [];
|
|
31096
31456
|
const errors = [];
|
|
31097
|
-
if (
|
|
31457
|
+
if (targets.worktree) {
|
|
31098
31458
|
try {
|
|
31099
|
-
const hadWorktree = existsSync15(
|
|
31100
|
-
removeDetachedReviewWorktree(
|
|
31459
|
+
const hadWorktree = existsSync15(targets.worktree.worktreeRoot);
|
|
31460
|
+
removeDetachedReviewWorktree(targets.worktree);
|
|
31101
31461
|
if (hadWorktree)
|
|
31102
31462
|
removed.push("worktree");
|
|
31103
31463
|
} catch (error) {
|
|
@@ -31105,10 +31465,12 @@ class ArchctxDaemon {
|
|
|
31105
31465
|
}
|
|
31106
31466
|
}
|
|
31107
31467
|
for (const [kind, path] of [
|
|
31108
|
-
["run-root",
|
|
31109
|
-
["manifest",
|
|
31110
|
-
["lock",
|
|
31468
|
+
["run-root", targets.runRoot],
|
|
31469
|
+
["manifest", targets.manifestPath],
|
|
31470
|
+
["lock", targets.lockPath]
|
|
31111
31471
|
]) {
|
|
31472
|
+
if (!path)
|
|
31473
|
+
continue;
|
|
31112
31474
|
try {
|
|
31113
31475
|
const existed = existsSync15(path);
|
|
31114
31476
|
removePathWithRetry(path);
|
|
@@ -31130,14 +31492,15 @@ class ArchctxDaemon {
|
|
|
31130
31492
|
recoverDeveloperReviewRuns(input) {
|
|
31131
31493
|
this.assertRunning();
|
|
31132
31494
|
const sourceRoot = findRepositoryRoot2(input.repositoryRoot);
|
|
31133
|
-
const stateDir =
|
|
31495
|
+
const stateDir = defaultDeveloperReviewRunStateDir(sourceRoot);
|
|
31134
31496
|
const recovery = {
|
|
31135
31497
|
schemaVersion: "archcontext.developer-review-run-recovery/v1",
|
|
31136
31498
|
sourceRoot,
|
|
31137
31499
|
stateDir,
|
|
31138
31500
|
recovered: [],
|
|
31139
31501
|
removedLocks: [],
|
|
31140
|
-
skippedActive: []
|
|
31502
|
+
skippedActive: [],
|
|
31503
|
+
rejected: []
|
|
31141
31504
|
};
|
|
31142
31505
|
if (!existsSync15(stateDir))
|
|
31143
31506
|
return recovery;
|
|
@@ -31145,21 +31508,39 @@ class ArchctxDaemon {
|
|
|
31145
31508
|
if (!entry.endsWith(".json"))
|
|
31146
31509
|
continue;
|
|
31147
31510
|
const manifestPath = join9(stateDir, entry);
|
|
31511
|
+
const stats = lstatIfExists(manifestPath);
|
|
31512
|
+
if (!stats || !stats.isFile()) {
|
|
31513
|
+
recovery.rejected.push(`${entry}: not-a-regular-file`);
|
|
31514
|
+
continue;
|
|
31515
|
+
}
|
|
31148
31516
|
const manifest = readDeveloperReviewRunManifest(manifestPath);
|
|
31149
31517
|
if (!manifest) {
|
|
31150
31518
|
rmSync8(manifestPath, { force: true });
|
|
31151
31519
|
continue;
|
|
31152
31520
|
}
|
|
31521
|
+
if (resolve18(manifest.manifestPath) !== manifestPath) {
|
|
31522
|
+
recovery.rejected.push(`${entry}: manifest-path-mismatch`);
|
|
31523
|
+
continue;
|
|
31524
|
+
}
|
|
31153
31525
|
if (!input.force && isDeveloperReviewPidAlive(manifest.pid)) {
|
|
31154
31526
|
recovery.skippedActive.push(manifest.runId);
|
|
31155
31527
|
continue;
|
|
31156
31528
|
}
|
|
31157
|
-
|
|
31529
|
+
try {
|
|
31530
|
+
recovery.recovered.push(this.cleanupDeveloperReviewRun(manifest));
|
|
31531
|
+
} catch (error) {
|
|
31532
|
+
recovery.rejected.push(`${entry}: ${error instanceof Error ? error.message : String(error)}`);
|
|
31533
|
+
}
|
|
31158
31534
|
}
|
|
31159
31535
|
for (const entry of readdirSync9(stateDir).sort()) {
|
|
31160
31536
|
if (!entry.endsWith(".lock"))
|
|
31161
31537
|
continue;
|
|
31162
31538
|
const lockPath = join9(stateDir, entry);
|
|
31539
|
+
const stats = lstatIfExists(lockPath);
|
|
31540
|
+
if (!stats || !stats.isFile()) {
|
|
31541
|
+
recovery.rejected.push(`${entry}: not-a-regular-file`);
|
|
31542
|
+
continue;
|
|
31543
|
+
}
|
|
31163
31544
|
const lock = readJsonObject(lockPath);
|
|
31164
31545
|
const pid = typeof lock?.pid === "number" ? lock.pid : undefined;
|
|
31165
31546
|
const runId = typeof lock?.runId === "string" ? lock.runId : entry;
|
|
@@ -31321,16 +31702,46 @@ class ArchctxDaemon {
|
|
|
31321
31702
|
}
|
|
31322
31703
|
async repoRemove(repositoryId) {
|
|
31323
31704
|
this.assertRunning();
|
|
31324
|
-
this.sessions.
|
|
31705
|
+
const hadOpenSession = this.sessions.has(repositoryId);
|
|
31706
|
+
const hadPersistedSession = (await this.localStore.listRepositorySessions()).some((session) => session.repositoryId === repositoryId);
|
|
31707
|
+
const registered = this.landscape?.repositories.some((repo) => repo.repositoryId === repositoryId) ?? false;
|
|
31708
|
+
if (!registered && !hadOpenSession && !hadPersistedSession) {
|
|
31709
|
+
return errorEnvelope("repo.remove", "AC_REPO_NOT_FOUND", `repository is not registered: ${repositoryId}`);
|
|
31710
|
+
}
|
|
31711
|
+
let detachedRelationIds = [];
|
|
31712
|
+
let nextLandscape;
|
|
31325
31713
|
if (this.landscape) {
|
|
31326
|
-
this.landscape
|
|
31714
|
+
detachedRelationIds = (await this.localStore.listCrossRepoRelations(this.landscape)).filter((relation) => relation.source.repositoryId === repositoryId || relation.target.repositoryId === repositoryId).map((relation) => relation.id).sort();
|
|
31715
|
+
const detached = new Set(detachedRelationIds);
|
|
31716
|
+
const next = {
|
|
31327
31717
|
...this.landscape,
|
|
31328
31718
|
repositories: this.landscape.repositories.filter((repo) => repo.repositoryId !== repositoryId),
|
|
31329
|
-
relations: this.landscape.relations
|
|
31719
|
+
relations: this.landscape.relations.filter((relationId) => !detached.has(relationId)),
|
|
31720
|
+
...this.landscape.scope === undefined ? {} : {
|
|
31721
|
+
scope: {
|
|
31722
|
+
...this.landscape.scope,
|
|
31723
|
+
defaultActiveRepositories: (this.landscape.scope.defaultActiveRepositories ?? []).filter((activeId) => activeId !== repositoryId)
|
|
31724
|
+
}
|
|
31725
|
+
}
|
|
31330
31726
|
};
|
|
31331
|
-
await this.localStore.
|
|
31727
|
+
const validation = validateLandscape(next, await this.localStore.listCrossRepoRelations(next));
|
|
31728
|
+
if (!validation.valid) {
|
|
31729
|
+
return errorEnvelope("repo.remove", "AC_SCHEMA_INVALID", validation.errors.join("; "));
|
|
31730
|
+
}
|
|
31731
|
+
nextLandscape = next;
|
|
31732
|
+
}
|
|
31733
|
+
this.sessions.delete(repositoryId);
|
|
31734
|
+
await this.localStore.deleteRepositorySession(repositoryId);
|
|
31735
|
+
if (nextLandscape) {
|
|
31736
|
+
this.landscape = nextLandscape;
|
|
31737
|
+
await this.localStore.saveLandscape(nextLandscape);
|
|
31332
31738
|
}
|
|
31333
|
-
return okEnvelope("repo.remove", {
|
|
31739
|
+
return okEnvelope("repo.remove", {
|
|
31740
|
+
repositoryId,
|
|
31741
|
+
removed: true,
|
|
31742
|
+
sessionRemoved: hadOpenSession || hadPersistedSession,
|
|
31743
|
+
detachedRelationIds
|
|
31744
|
+
});
|
|
31334
31745
|
}
|
|
31335
31746
|
async loadLandscape(landscape) {
|
|
31336
31747
|
this.assertRunning();
|
|
@@ -32186,16 +32597,76 @@ data: ${payload}
|
|
|
32186
32597
|
}
|
|
32187
32598
|
}
|
|
32188
32599
|
|
|
32600
|
+
class RuntimeRpcTransportError extends Error {
|
|
32601
|
+
code;
|
|
32602
|
+
method;
|
|
32603
|
+
timeoutMs;
|
|
32604
|
+
elapsedMs;
|
|
32605
|
+
constructor(code, method, timeoutMs, elapsedMs) {
|
|
32606
|
+
super(code === "RPC_TIMEOUT" ? `runtime RPC timeout: ${method} exceeded ${timeoutMs}ms` : `runtime RPC cancelled: ${method} aborted after ${elapsedMs}ms`);
|
|
32607
|
+
this.code = code;
|
|
32608
|
+
this.method = method;
|
|
32609
|
+
this.timeoutMs = timeoutMs;
|
|
32610
|
+
this.elapsedMs = elapsedMs;
|
|
32611
|
+
this.name = "RuntimeRpcTransportError";
|
|
32612
|
+
}
|
|
32613
|
+
}
|
|
32614
|
+
var RUNTIME_RPC_CLIENT_TIMEOUT_POLICY = {
|
|
32615
|
+
health: 5000,
|
|
32616
|
+
short: 15000,
|
|
32617
|
+
normal: 120000,
|
|
32618
|
+
long: 900000
|
|
32619
|
+
};
|
|
32620
|
+
var RUNTIME_RPC_SHORT_METHODS = new Set([
|
|
32621
|
+
"shutdown",
|
|
32622
|
+
"runtimeStatus",
|
|
32623
|
+
"landscapeStatus",
|
|
32624
|
+
"repoList",
|
|
32625
|
+
"explorerStatus",
|
|
32626
|
+
"explorerServiceContract",
|
|
32627
|
+
"jobsList",
|
|
32628
|
+
"jobsStats",
|
|
32629
|
+
"ledgerState",
|
|
32630
|
+
"ledgerDrift",
|
|
32631
|
+
"stopExplorer",
|
|
32632
|
+
"revokeExplorerToken"
|
|
32633
|
+
]);
|
|
32634
|
+
var RUNTIME_RPC_LONG_METHODS = new Set([
|
|
32635
|
+
"init",
|
|
32636
|
+
"sync",
|
|
32637
|
+
"prepare",
|
|
32638
|
+
"context",
|
|
32639
|
+
"checkpoint",
|
|
32640
|
+
"auditRun",
|
|
32641
|
+
"auditApprove",
|
|
32642
|
+
"recommendations",
|
|
32643
|
+
"book",
|
|
32644
|
+
"ledgerRebuild",
|
|
32645
|
+
"ledgerMigrate",
|
|
32646
|
+
"startDeveloperReviewRun",
|
|
32647
|
+
"runSignedDeveloperReviewAttestation"
|
|
32648
|
+
]);
|
|
32649
|
+
function runtimeRpcMethodTimeout(method, policy) {
|
|
32650
|
+
if (RUNTIME_RPC_SHORT_METHODS.has(method))
|
|
32651
|
+
return policy.short;
|
|
32652
|
+
if (RUNTIME_RPC_LONG_METHODS.has(method))
|
|
32653
|
+
return policy.long;
|
|
32654
|
+
return policy.normal;
|
|
32655
|
+
}
|
|
32656
|
+
|
|
32189
32657
|
class RuntimeRpcClient {
|
|
32190
32658
|
connection;
|
|
32191
|
-
|
|
32659
|
+
options;
|
|
32660
|
+
timeouts;
|
|
32661
|
+
constructor(connection, options = {}) {
|
|
32192
32662
|
this.connection = connection;
|
|
32663
|
+
this.options = options;
|
|
32664
|
+
this.timeouts = { ...RUNTIME_RPC_CLIENT_TIMEOUT_POLICY, ...options.timeouts };
|
|
32193
32665
|
}
|
|
32194
32666
|
async health() {
|
|
32195
|
-
|
|
32667
|
+
return await this.request("health", this.timeouts.health, `${this.connection.url}health`, {
|
|
32196
32668
|
headers: { "X-ArchContext-RPC-Version": RUNTIME_RPC_VERSION }
|
|
32197
32669
|
});
|
|
32198
|
-
return await response.json();
|
|
32199
32670
|
}
|
|
32200
32671
|
async shutdown() {
|
|
32201
32672
|
return this.call("shutdown", []);
|
|
@@ -32279,8 +32750,11 @@ class RuntimeRpcClient {
|
|
|
32279
32750
|
applyUpdate(root, input) {
|
|
32280
32751
|
return this.call("applyUpdate", [root, input]);
|
|
32281
32752
|
}
|
|
32282
|
-
|
|
32283
|
-
return this.call("
|
|
32753
|
+
inspectProjectionApplyReceipt(root, lookupKey) {
|
|
32754
|
+
return this.call("inspectProjectionApplyReceipt", [root, lookupKey]);
|
|
32755
|
+
}
|
|
32756
|
+
recoverProjectionApply(root, intent) {
|
|
32757
|
+
return this.call("recoverProjectionApply", [root, intent]);
|
|
32284
32758
|
}
|
|
32285
32759
|
ledgerState(root) {
|
|
32286
32760
|
return this.call("ledgerState", [root]);
|
|
@@ -32358,7 +32832,7 @@ class RuntimeRpcClient {
|
|
|
32358
32832
|
return unwrapRpcData(await this.call("recoverDeveloperReviewRuns", [input]));
|
|
32359
32833
|
}
|
|
32360
32834
|
async call(method, params) {
|
|
32361
|
-
|
|
32835
|
+
return await this.request(method, runtimeRpcMethodTimeout(method, this.timeouts), `${this.connection.url}rpc`, {
|
|
32362
32836
|
method: "POST",
|
|
32363
32837
|
headers: {
|
|
32364
32838
|
Authorization: `Bearer ${this.connection.token}`,
|
|
@@ -32367,7 +32841,35 @@ class RuntimeRpcClient {
|
|
|
32367
32841
|
},
|
|
32368
32842
|
body: JSON.stringify({ schemaVersion: RUNTIME_RPC_VERSION, method, params })
|
|
32369
32843
|
});
|
|
32370
|
-
|
|
32844
|
+
}
|
|
32845
|
+
async request(method, timeoutMs, url, init) {
|
|
32846
|
+
const controller = new AbortController;
|
|
32847
|
+
const startedAt = Date.now();
|
|
32848
|
+
let timedOut = false;
|
|
32849
|
+
const timer = setTimeout(() => {
|
|
32850
|
+
timedOut = true;
|
|
32851
|
+
controller.abort();
|
|
32852
|
+
}, timeoutMs);
|
|
32853
|
+
const callerSignal = this.options.signal;
|
|
32854
|
+
const onCallerAbort = () => controller.abort();
|
|
32855
|
+
if (callerSignal?.aborted)
|
|
32856
|
+
controller.abort();
|
|
32857
|
+
else
|
|
32858
|
+
callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
32859
|
+
try {
|
|
32860
|
+
const response = await fetch(url, { ...init, signal: controller.signal });
|
|
32861
|
+
return await response.json();
|
|
32862
|
+
} catch (error) {
|
|
32863
|
+
const elapsedMs = Date.now() - startedAt;
|
|
32864
|
+
if (timedOut)
|
|
32865
|
+
throw new RuntimeRpcTransportError("RPC_TIMEOUT", method, timeoutMs, elapsedMs);
|
|
32866
|
+
if (callerSignal?.aborted)
|
|
32867
|
+
throw new RuntimeRpcTransportError("RPC_ABORTED", method, timeoutMs, elapsedMs);
|
|
32868
|
+
throw error;
|
|
32869
|
+
} finally {
|
|
32870
|
+
clearTimeout(timer);
|
|
32871
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
32872
|
+
}
|
|
32371
32873
|
}
|
|
32372
32874
|
}
|
|
32373
32875
|
|
|
@@ -32418,7 +32920,7 @@ class ArchctxRuntimeRpcServer {
|
|
|
32418
32920
|
startedAt: (this.options.clock ?? (() => new Date().toISOString()))()
|
|
32419
32921
|
};
|
|
32420
32922
|
writeFileSync6(connectionPath, JSON.stringify(this.connection, null, 2), { mode: 384 });
|
|
32421
|
-
|
|
32923
|
+
chmodSync4(connectionPath, 384);
|
|
32422
32924
|
this.armIdleTimer();
|
|
32423
32925
|
return this.connection;
|
|
32424
32926
|
}
|
|
@@ -32512,13 +33014,26 @@ class ArchctxRuntimeRpcServer {
|
|
|
32512
33014
|
writeJson(response, 401, { schemaVersion: RUNTIME_RPC_VERSION, ok: false, error: "runtime RPC token required" });
|
|
32513
33015
|
return;
|
|
32514
33016
|
}
|
|
32515
|
-
const body = await readRequestJson(request);
|
|
32516
|
-
if (body.schemaVersion !== RUNTIME_RPC_VERSION) {
|
|
32517
|
-
writeJson(response, 400, { schemaVersion: RUNTIME_RPC_VERSION, ok: false, error: "runtime RPC version mismatch" });
|
|
32518
|
-
return;
|
|
32519
|
-
}
|
|
32520
33017
|
this.inFlightRpcRequests += 1;
|
|
32521
33018
|
try {
|
|
33019
|
+
const read = await readRpcRequestBody(request, {
|
|
33020
|
+
maxBytes: this.options.maxRequestBodyBytes ?? RUNTIME_RPC_MAX_REQUEST_BODY_BYTES,
|
|
33021
|
+
timeoutMs: this.options.requestBodyTimeoutMs ?? RUNTIME_RPC_REQUEST_BODY_TIMEOUT_MS
|
|
33022
|
+
});
|
|
33023
|
+
if (!read.ok) {
|
|
33024
|
+
if (read.kind === "rejected")
|
|
33025
|
+
writeJson(response, read.status, { schemaVersion: RUNTIME_RPC_VERSION, ok: false, error: read.error });
|
|
33026
|
+
return;
|
|
33027
|
+
}
|
|
33028
|
+
if (!read.value || typeof read.value !== "object" || Array.isArray(read.value)) {
|
|
33029
|
+
writeJson(response, 400, { schemaVersion: RUNTIME_RPC_VERSION, ok: false, error: "runtime RPC request body must be an object" });
|
|
33030
|
+
return;
|
|
33031
|
+
}
|
|
33032
|
+
const body = read.value;
|
|
33033
|
+
if (body.schemaVersion !== RUNTIME_RPC_VERSION) {
|
|
33034
|
+
writeJson(response, 400, { schemaVersion: RUNTIME_RPC_VERSION, ok: false, error: "runtime RPC version mismatch" });
|
|
33035
|
+
return;
|
|
33036
|
+
}
|
|
32522
33037
|
const result = await this.dispatch(body.method ?? "", body.params ?? []);
|
|
32523
33038
|
writeJson(response, 200, result);
|
|
32524
33039
|
if (body.method === "shutdown")
|
|
@@ -32585,8 +33100,10 @@ class ArchctxRuntimeRpcServer {
|
|
|
32585
33100
|
return this.daemon.completeTask(params[0], params[1]);
|
|
32586
33101
|
case "applyUpdate":
|
|
32587
33102
|
return this.daemon.applyUpdate(params[0], params[1]);
|
|
32588
|
-
case "
|
|
32589
|
-
return this.daemon.
|
|
33103
|
+
case "inspectProjectionApplyReceipt":
|
|
33104
|
+
return this.daemon.inspectProjectionApplyReceipt(params[0], params[1]);
|
|
33105
|
+
case "recoverProjectionApply":
|
|
33106
|
+
return this.daemon.recoverProjectionApply(params[0], params[1]);
|
|
32590
33107
|
case "ledgerState":
|
|
32591
33108
|
return this.daemon.ledgerState(params[0]);
|
|
32592
33109
|
case "ledgerDrift":
|
|
@@ -32630,13 +33147,13 @@ class ArchctxRuntimeRpcServer {
|
|
|
32630
33147
|
case "runtimeStatus":
|
|
32631
33148
|
return this.daemon.runtimeStatus(params[0]);
|
|
32632
33149
|
case "startDeveloperReviewRun":
|
|
32633
|
-
return okEnvelope("developerReview.startRun", this.daemon.startDeveloperReviewRun(params
|
|
33150
|
+
return okEnvelope("developerReview.startRun", this.daemon.startDeveloperReviewRun(decodeStartDeveloperReviewRunParams(params)));
|
|
32634
33151
|
case "runSignedDeveloperReviewAttestation":
|
|
32635
|
-
return okEnvelope("developerReview.attestation", await this.daemon.runSignedDeveloperReviewAttestation(params
|
|
33152
|
+
return okEnvelope("developerReview.attestation", await this.daemon.runSignedDeveloperReviewAttestation(decodeSignedDeveloperReviewAttestationParams(params)));
|
|
32636
33153
|
case "cleanupDeveloperReviewRun":
|
|
32637
|
-
return okEnvelope("developerReview.cleanupRun", this.daemon.cleanupDeveloperReviewRun(params[0]));
|
|
33154
|
+
return okEnvelope("developerReview.cleanupRun", this.daemon.cleanupDeveloperReviewRun(decodeDeveloperReviewRunManifest(params[0], "cleanupDeveloperReviewRun")));
|
|
32638
33155
|
case "recoverDeveloperReviewRuns":
|
|
32639
|
-
return okEnvelope("developerReview.recoverRuns", this.daemon.recoverDeveloperReviewRuns(params
|
|
33156
|
+
return okEnvelope("developerReview.recoverRuns", this.daemon.recoverDeveloperReviewRuns(decodeRecoverDeveloperReviewRunsParams(params)));
|
|
32640
33157
|
case "shutdown":
|
|
32641
33158
|
return okEnvelope("daemon.stop", { stopping: true });
|
|
32642
33159
|
default:
|
|
@@ -32814,6 +33331,9 @@ function shouldSkipGeneratedProjectionJob(metadata, input) {
|
|
|
32814
33331
|
function isRuntimeAgentJobCursorStale(job, scope) {
|
|
32815
33332
|
return job.worktree.headSha !== scope.worktree.headSha || job.worktree.worktreeDigest !== scope.worktree.worktreeDigest;
|
|
32816
33333
|
}
|
|
33334
|
+
function runtimeAgentJobOutOfScopeEnvelope(requestId, jobId) {
|
|
33335
|
+
return errorEnvelope(requestId, "AC_PRECONDITION_FAILED", `runtime agent job does not belong to this repository/worktree: ${jobId}`, "runtime-agent-job-out-of-scope");
|
|
33336
|
+
}
|
|
32817
33337
|
function runtimeWorktreeDigest(root, profile) {
|
|
32818
33338
|
switch (profile) {
|
|
32819
33339
|
case "repository":
|
|
@@ -32824,6 +33344,137 @@ function runtimeWorktreeDigest(root, profile) {
|
|
|
32824
33344
|
throw new RuntimeUpdateInputError(`unsupported worktree digest profile: ${String(profile)}`);
|
|
32825
33345
|
}
|
|
32826
33346
|
}
|
|
33347
|
+
function buildRuntimeProjectionRecoveryFixedPoint(root) {
|
|
33348
|
+
const loaded = loadArchitectureDocumentationInputs(root, REPO_HARNESS_PROJECTION_PROFILE);
|
|
33349
|
+
const sourceDigest = digestJson({
|
|
33350
|
+
model: loaded.model,
|
|
33351
|
+
profile: REPO_HARNESS_PROJECTION_PROFILE,
|
|
33352
|
+
decisions: loaded.decisions.map((decision) => ({ id: decision.id, path: decision.path, title: decision.title, status: decision.status }))
|
|
33353
|
+
});
|
|
33354
|
+
const codeGraphInputs = prepareArchitectureDocumentationProjectionSnapshot(root, loaded.model);
|
|
33355
|
+
const provenance = codeGraphInputs.provenance;
|
|
33356
|
+
const projection3 = renderArchitectureDocumentationProjection({
|
|
33357
|
+
model: loaded.model,
|
|
33358
|
+
profile: REPO_HARNESS_PROJECTION_PROFILE,
|
|
33359
|
+
decisions: loaded.decisions,
|
|
33360
|
+
existingFiles: loaded.existingFiles,
|
|
33361
|
+
verifiedAgainst: assertArchitectureProjectionVerifiedAgainst({
|
|
33362
|
+
branch: readCurrentBranch(root),
|
|
33363
|
+
commit: readHeadSha2(root),
|
|
33364
|
+
committedAt: readHeadCommittedAt(root)
|
|
33365
|
+
}),
|
|
33366
|
+
sourceChangesSinceStamp: loadCapabilitySourceChangesSinceStamps(root, loaded.model),
|
|
33367
|
+
sourceScaleSignals: loadCapabilitySourceScaleSignals(root, loaded.model),
|
|
33368
|
+
importGraphs: codeGraphInputs.importGraphs,
|
|
33369
|
+
selectorEvidence: codeGraphInputs.selectorEvidence,
|
|
33370
|
+
provenance,
|
|
33371
|
+
sourceDigest,
|
|
33372
|
+
generatedAt: new Date(0).toISOString(),
|
|
33373
|
+
refreshContext: {
|
|
33374
|
+
repositoryId: repositoryFingerprint2(root),
|
|
33375
|
+
workspaceId: runtimeProjectionWorkspaceId(root),
|
|
33376
|
+
headSha: provenance.baseHeadSha,
|
|
33377
|
+
worktreeDigest: provenance.worktreeDigest
|
|
33378
|
+
}
|
|
33379
|
+
});
|
|
33380
|
+
const snapshot = {
|
|
33381
|
+
repositoryId: repositoryFingerprint2(root),
|
|
33382
|
+
workspaceId: runtimeProjectionWorkspaceId(root),
|
|
33383
|
+
headSha: readHeadSha2(root),
|
|
33384
|
+
worktreeDigest: architectureDocumentationProjectionWorktreeDigest(root, loaded.model),
|
|
33385
|
+
baseHeadSha: projection3.provenance.baseHeadSha,
|
|
33386
|
+
sourceTreeDigest: projection3.provenance.sourceTreeDigest,
|
|
33387
|
+
modelDigest: projection3.provenance.modelDigest,
|
|
33388
|
+
codeGraphDigest: projection3.provenance.codeGraphDigest,
|
|
33389
|
+
indexedWorktreeDigest: projection3.provenance.indexedWorktreeDigest,
|
|
33390
|
+
projectionInputDigest: projection3.provenance.projectionInputDigest,
|
|
33391
|
+
rendererVersion: projection3.provenance.rendererVersion,
|
|
33392
|
+
layoutVersion: projection3.provenance.layoutVersion,
|
|
33393
|
+
generatedFrom: projection3.provenance.generatedFrom
|
|
33394
|
+
};
|
|
33395
|
+
return {
|
|
33396
|
+
projection: projection3,
|
|
33397
|
+
snapshot,
|
|
33398
|
+
ownedOutputDigest: runtimeProjectionOwnedOutputDigest({ files: [...projection3.files, projection3.manifest] })
|
|
33399
|
+
};
|
|
33400
|
+
}
|
|
33401
|
+
function runtimeProjectionRecoveryFixedPointIssues(receipt, fixedPoint) {
|
|
33402
|
+
const binding = receipt.recovery;
|
|
33403
|
+
if (!binding)
|
|
33404
|
+
return ["committed projection receipt does not support semantic recovery"];
|
|
33405
|
+
const issues = [];
|
|
33406
|
+
const projection3 = fixedPoint.projection;
|
|
33407
|
+
if (!projection3.drift.ok || projection3.rejected.length > 0)
|
|
33408
|
+
issues.push("projection owned outputs are not a clean fixed point");
|
|
33409
|
+
if (projection3.majorChange.mode !== "none" || projection3.majorChange.reasonCodes.length > 0 || projection3.majorChange.affectedNodeIds.length > 0) {
|
|
33410
|
+
issues.push("current architecture state contains an unresolved major change");
|
|
33411
|
+
}
|
|
33412
|
+
if (projection3.refreshSignals.length > 0)
|
|
33413
|
+
issues.push("current architecture state has unresolved refresh signals");
|
|
33414
|
+
for (const field of ["repositoryId", "workspaceId", "headSha", "worktreeDigest"]) {
|
|
33415
|
+
if (fixedPoint.snapshot[field] !== binding.originalExpectedSnapshot[field]) {
|
|
33416
|
+
issues.push(`current projection snapshot differs from the approved snapshot: ${field}`);
|
|
33417
|
+
}
|
|
33418
|
+
}
|
|
33419
|
+
if (binding.generatedFrom.codeGraphStatus !== "ready")
|
|
33420
|
+
issues.push("approved CodeGraph snapshot is unavailable");
|
|
33421
|
+
if (projection3.provenance.generatedFrom.codeGraphStatus !== "ready")
|
|
33422
|
+
issues.push("current CodeGraph snapshot is unavailable");
|
|
33423
|
+
if (digestJson(projection3.architectureDigests) !== digestJson(binding.expectedResultingDigests)) {
|
|
33424
|
+
issues.push("current model, source, flow-proof, or projection digest differs from the approved result");
|
|
33425
|
+
}
|
|
33426
|
+
if (projection3.provenance.projectionInputDigest !== receipt.result.outputSnapshot.projectionInputDigest || projection3.provenance.codeGraphDigest !== receipt.result.outputSnapshot.codeGraphDigest || projection3.provenance.rendererVersion !== binding.rendererVersion || projection3.provenance.layoutVersion !== binding.layoutVersion || digestJson(projection3.provenance.generatedFrom) !== digestJson(binding.generatedFrom)) {
|
|
33427
|
+
issues.push("current renderer, layout, or CodeGraph provenance differs from the approved result");
|
|
33428
|
+
}
|
|
33429
|
+
if (fixedPoint.ownedOutputDigest !== binding.ownedOutputDigest)
|
|
33430
|
+
issues.push("current projection-owned output bytes differ from the approved result");
|
|
33431
|
+
if (fixedPoint.snapshot.generatedFrom.codeGraphStatus !== "ready")
|
|
33432
|
+
issues.push("current proof snapshot requires CodeGraph ready");
|
|
33433
|
+
return issues;
|
|
33434
|
+
}
|
|
33435
|
+
function createRuntimeProjectionRecoveryProof(intent, receipt, fixedPoint) {
|
|
33436
|
+
const current = {
|
|
33437
|
+
snapshot: fixedPoint.snapshot,
|
|
33438
|
+
resultingDigests: fixedPoint.projection.architectureDigests,
|
|
33439
|
+
ownedOutputDigest: fixedPoint.ownedOutputDigest,
|
|
33440
|
+
fixedPointDigest: digestJson({
|
|
33441
|
+
schemaVersion: "archcontext.projection-apply-recovery-fixed-point/v1",
|
|
33442
|
+
snapshot: fixedPoint.snapshot,
|
|
33443
|
+
resultingDigests: fixedPoint.projection.architectureDigests,
|
|
33444
|
+
ownedOutputDigest: fixedPoint.ownedOutputDigest,
|
|
33445
|
+
drift: fixedPoint.projection.drift,
|
|
33446
|
+
majorChange: fixedPoint.projection.majorChange,
|
|
33447
|
+
refreshSignalIds: fixedPoint.projection.refreshSignals.map((signal) => signal.signalId)
|
|
33448
|
+
})
|
|
33449
|
+
};
|
|
33450
|
+
const payload = {
|
|
33451
|
+
schemaVersion: "archcontext.projection-apply-recovery-proof/v1",
|
|
33452
|
+
requestId: intent.requestId,
|
|
33453
|
+
requestDigest: digestJson(intent),
|
|
33454
|
+
receipt: {
|
|
33455
|
+
lookupKey: receipt.identity.lookupKey,
|
|
33456
|
+
applyId: receipt.identity.applyId,
|
|
33457
|
+
receiptDigest: receipt.result.receiptDigest
|
|
33458
|
+
},
|
|
33459
|
+
acceptedChange: receipt.identity.acceptedChange,
|
|
33460
|
+
expectedResultingDigests: receipt.recovery.expectedResultingDigests,
|
|
33461
|
+
current
|
|
33462
|
+
};
|
|
33463
|
+
return {
|
|
33464
|
+
...payload,
|
|
33465
|
+
proofDigest: projectionApplyRecoveryProofDigest(payload),
|
|
33466
|
+
deliveryStatus: "delivered"
|
|
33467
|
+
};
|
|
33468
|
+
}
|
|
33469
|
+
function runtimeProjectionOwnedOutputDigest(projection3) {
|
|
33470
|
+
return digestJson({
|
|
33471
|
+
schemaVersion: "archcontext.projection-owned-output/v1",
|
|
33472
|
+
files: projection3.files.map((file) => ({ path: file.path, body: file.body })).sort((left, right) => left.path.localeCompare(right.path))
|
|
33473
|
+
});
|
|
33474
|
+
}
|
|
33475
|
+
function runtimeProjectionWorkspaceId(root) {
|
|
33476
|
+
return `workspace.${digestJson({ root: canonicalRepositoryRoot2(root) }).replace(/^sha256:/, "").slice(0, 16)}`;
|
|
33477
|
+
}
|
|
32827
33478
|
function isArchContextGeneratedProjectionPath(path) {
|
|
32828
33479
|
return path.replace(/\\/g, "/").startsWith(".archcontext/generated/");
|
|
32829
33480
|
}
|
|
@@ -33175,13 +33826,18 @@ function runtimeAttestationIdentity(snapshot, composition) {
|
|
|
33175
33826
|
})
|
|
33176
33827
|
};
|
|
33177
33828
|
}
|
|
33829
|
+
var DEVELOPER_REVIEW_RUN_ROOT_PREFIX = "archctx-developer-review-";
|
|
33830
|
+
var DEVELOPER_REVIEW_RUN_OWNER_MARKER_FILE = ".archctx-developer-review-run.json";
|
|
33831
|
+
var DEVELOPER_REVIEW_RUN_OWNER_SCHEMA_VERSION = "archcontext.developer-review-run-owner/v1";
|
|
33832
|
+
var DEVELOPER_REVIEW_RUN_ROOT_SUFFIX = /^[A-Za-z0-9]{6}$/;
|
|
33833
|
+
var DEVELOPER_REVIEW_RUN_ID_SUFFIX = /^[0-9a-f]{12}$/;
|
|
33178
33834
|
function createDeveloperReviewRunPaths(input) {
|
|
33179
33835
|
const safeChallengeId = safeControlFileSegment(input.challengeId);
|
|
33180
33836
|
const runId = `${safeChallengeId}-${randomBytes(6).toString("hex")}`;
|
|
33181
|
-
const stateDir =
|
|
33837
|
+
const stateDir = defaultDeveloperReviewRunStateDir(input.sourceRoot);
|
|
33182
33838
|
const tempParent = input.tempRoot ? resolve18(input.tempRoot) : tmpdir3();
|
|
33183
33839
|
mkdirSync7(tempParent, { recursive: true });
|
|
33184
|
-
const runRoot = mkdtempSync4(join9(tempParent,
|
|
33840
|
+
const runRoot = mkdtempSync4(join9(tempParent, `${DEVELOPER_REVIEW_RUN_ROOT_PREFIX}${safeChallengeId.slice(0, 32)}-`));
|
|
33185
33841
|
return {
|
|
33186
33842
|
runId,
|
|
33187
33843
|
stateDir,
|
|
@@ -33191,6 +33847,92 @@ function createDeveloperReviewRunPaths(input) {
|
|
|
33191
33847
|
lockPath: join9(stateDir, `${safeChallengeId}.lock`)
|
|
33192
33848
|
};
|
|
33193
33849
|
}
|
|
33850
|
+
function writeDeveloperReviewRunOwnerMarker(input) {
|
|
33851
|
+
const marker = {
|
|
33852
|
+
schemaVersion: DEVELOPER_REVIEW_RUN_OWNER_SCHEMA_VERSION,
|
|
33853
|
+
runId: input.runId,
|
|
33854
|
+
challengeId: input.challengeId,
|
|
33855
|
+
stateDir: input.stateDir,
|
|
33856
|
+
manifestPath: input.manifestPath,
|
|
33857
|
+
lockPath: input.lockPath,
|
|
33858
|
+
pid: process.pid,
|
|
33859
|
+
createdAt: input.createdAt
|
|
33860
|
+
};
|
|
33861
|
+
writePrivateJson3(join9(input.runRoot, DEVELOPER_REVIEW_RUN_OWNER_MARKER_FILE), marker, "wx");
|
|
33862
|
+
}
|
|
33863
|
+
function readDeveloperReviewRunOwnerMarker(path) {
|
|
33864
|
+
const stats = lstatIfExists(path);
|
|
33865
|
+
if (!stats || !stats.isFile())
|
|
33866
|
+
return;
|
|
33867
|
+
const parsed = readJsonObject(path);
|
|
33868
|
+
if (!parsed || parsed.schemaVersion !== DEVELOPER_REVIEW_RUN_OWNER_SCHEMA_VERSION)
|
|
33869
|
+
return;
|
|
33870
|
+
if (typeof parsed.runId !== "string" || typeof parsed.challengeId !== "string")
|
|
33871
|
+
return;
|
|
33872
|
+
if (typeof parsed.manifestPath !== "string" || typeof parsed.lockPath !== "string")
|
|
33873
|
+
return;
|
|
33874
|
+
return parsed;
|
|
33875
|
+
}
|
|
33876
|
+
function developerReviewRunNotOwned(reason) {
|
|
33877
|
+
return new Error(`developer-review-run-not-owned: ${reason}`);
|
|
33878
|
+
}
|
|
33879
|
+
function resolveOwnedDeveloperReviewRunTargets(run) {
|
|
33880
|
+
const safeChallengeId = safeControlFileSegment(run.challengeId);
|
|
33881
|
+
const runIdSuffix = run.runId.startsWith(`${safeChallengeId}-`) ? run.runId.slice(safeChallengeId.length + 1) : undefined;
|
|
33882
|
+
if (!runIdSuffix || !DEVELOPER_REVIEW_RUN_ID_SUFFIX.test(runIdSuffix))
|
|
33883
|
+
throw developerReviewRunNotOwned("run-id");
|
|
33884
|
+
const stateDir = defaultDeveloperReviewRunStateDir(run.sourceRoot);
|
|
33885
|
+
const manifestPath = join9(stateDir, `${safeChallengeId}.json`);
|
|
33886
|
+
const lockPath = join9(stateDir, `${safeChallengeId}.lock`);
|
|
33887
|
+
if (resolve18(run.manifestPath) !== manifestPath)
|
|
33888
|
+
throw developerReviewRunNotOwned("manifest-path");
|
|
33889
|
+
if (resolve18(run.lockPath) !== lockPath)
|
|
33890
|
+
throw developerReviewRunNotOwned("lock-path");
|
|
33891
|
+
const runRoot = resolve18(run.runRoot);
|
|
33892
|
+
const runRootPrefix = `${DEVELOPER_REVIEW_RUN_ROOT_PREFIX}${safeChallengeId.slice(0, 32)}-`;
|
|
33893
|
+
const runRootName = basename6(runRoot);
|
|
33894
|
+
if (!runRootName.startsWith(runRootPrefix) || !DEVELOPER_REVIEW_RUN_ROOT_SUFFIX.test(runRootName.slice(runRootPrefix.length))) {
|
|
33895
|
+
throw developerReviewRunNotOwned("run-root-name");
|
|
33896
|
+
}
|
|
33897
|
+
const worktreeTempRoot = join9(runRoot, "worktrees");
|
|
33898
|
+
if (resolve18(run.worktreeTempRoot) !== worktreeTempRoot)
|
|
33899
|
+
throw developerReviewRunNotOwned("worktree-temp-root");
|
|
33900
|
+
if (resolve18(run.codeGraphTemporaryState.root) !== runRoot)
|
|
33901
|
+
throw developerReviewRunNotOwned("codegraph-temporary-state-root");
|
|
33902
|
+
const runRootStats = lstatIfExists(runRoot);
|
|
33903
|
+
if (!runRootStats)
|
|
33904
|
+
return { stateDir, manifestPath, lockPath };
|
|
33905
|
+
if (!runRootStats.isDirectory())
|
|
33906
|
+
throw developerReviewRunNotOwned("run-root-not-a-directory");
|
|
33907
|
+
const marker = readDeveloperReviewRunOwnerMarker(join9(runRoot, DEVELOPER_REVIEW_RUN_OWNER_MARKER_FILE));
|
|
33908
|
+
if (!marker)
|
|
33909
|
+
throw developerReviewRunNotOwned("run-root-owner-marker-missing");
|
|
33910
|
+
if (marker.runId !== run.runId || marker.challengeId !== run.challengeId)
|
|
33911
|
+
throw developerReviewRunNotOwned("run-root-owner-marker-mismatch");
|
|
33912
|
+
if (marker.manifestPath !== manifestPath || marker.lockPath !== lockPath)
|
|
33913
|
+
throw developerReviewRunNotOwned("run-root-owner-marker-mismatch");
|
|
33914
|
+
if (!run.worktree)
|
|
33915
|
+
return { stateDir, manifestPath, lockPath, runRoot };
|
|
33916
|
+
const temporaryRoot = resolve18(run.worktree.temporaryRoot);
|
|
33917
|
+
const worktreeRoot = resolve18(run.worktree.worktreeRoot);
|
|
33918
|
+
if (!isContainedPath(worktreeTempRoot, temporaryRoot))
|
|
33919
|
+
throw developerReviewRunNotOwned("worktree-temporary-root");
|
|
33920
|
+
if (!isContainedPath(temporaryRoot, worktreeRoot))
|
|
33921
|
+
throw developerReviewRunNotOwned("worktree-root");
|
|
33922
|
+
if (defaultDeveloperReviewRunStateDir(run.worktree.sourceRoot) !== stateDir)
|
|
33923
|
+
throw developerReviewRunNotOwned("worktree-source-root");
|
|
33924
|
+
return { stateDir, manifestPath, lockPath, runRoot, worktree: { ...run.worktree, temporaryRoot, worktreeRoot } };
|
|
33925
|
+
}
|
|
33926
|
+
function isContainedPath(parent, child) {
|
|
33927
|
+
return child === parent || child.startsWith(parent.endsWith(sep7) ? parent : `${parent}${sep7}`);
|
|
33928
|
+
}
|
|
33929
|
+
function lstatIfExists(path) {
|
|
33930
|
+
try {
|
|
33931
|
+
return lstatSync7(path);
|
|
33932
|
+
} catch {
|
|
33933
|
+
return;
|
|
33934
|
+
}
|
|
33935
|
+
}
|
|
33194
33936
|
function safeControlFileSegment(value) {
|
|
33195
33937
|
const sanitized = value.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 80);
|
|
33196
33938
|
return sanitized.length > 0 ? sanitized : "developer-review";
|
|
@@ -33257,9 +33999,7 @@ function appendExternalDocumentationToContext(context, resource, candidate, maxB
|
|
|
33257
33999
|
const resources = context.resources.some((entry) => entry.uri === resource.uri) ? context.resources : [...context.resources, externalResource];
|
|
33258
34000
|
const unknown = `External documentation is advisory and untrusted for ${candidate.packageName}@${candidate.version}: ${candidate.intent}`;
|
|
33259
34001
|
const unknowns = context.unknowns.includes(unknown) ? context.unknowns : [...context.unknowns, unknown];
|
|
33260
|
-
const
|
|
33261
|
-
delete extensionWithoutDigest.digest;
|
|
33262
|
-
const withoutDigest = {
|
|
34002
|
+
const augmented = {
|
|
33263
34003
|
...context,
|
|
33264
34004
|
unknowns,
|
|
33265
34005
|
resources,
|
|
@@ -33278,7 +34018,7 @@ function appendExternalDocumentationToContext(context, resource, candidate, maxB
|
|
|
33278
34018
|
}
|
|
33279
34019
|
},
|
|
33280
34020
|
extensions: {
|
|
33281
|
-
...
|
|
34021
|
+
...context.extensions,
|
|
33282
34022
|
externalDocumentationDigest: digestJson({
|
|
33283
34023
|
provider: resource.provider,
|
|
33284
34024
|
libraryId: candidate.libraryId,
|
|
@@ -33289,22 +34029,7 @@ function appendExternalDocumentationToContext(context, resource, candidate, maxB
|
|
|
33289
34029
|
})
|
|
33290
34030
|
}
|
|
33291
34031
|
};
|
|
33292
|
-
|
|
33293
|
-
const withMetadata = {
|
|
33294
|
-
...withoutDigest,
|
|
33295
|
-
extensions: {
|
|
33296
|
-
...withoutDigest.extensions,
|
|
33297
|
-
byteLength,
|
|
33298
|
-
budgetExceeded: byteLength > maxBytes
|
|
33299
|
-
}
|
|
33300
|
-
};
|
|
33301
|
-
return {
|
|
33302
|
-
...withMetadata,
|
|
33303
|
-
extensions: {
|
|
33304
|
-
...withMetadata.extensions,
|
|
33305
|
-
digest: digestJson(withMetadata)
|
|
33306
|
-
}
|
|
33307
|
-
};
|
|
34032
|
+
return finalizeContextBudgetMetadata(augmented, maxBytes);
|
|
33308
34033
|
}
|
|
33309
34034
|
function prepareContextHasVersionRelatedUnknown(context) {
|
|
33310
34035
|
const unknowns = context.unknowns.join(" ").toLowerCase();
|
|
@@ -33402,15 +34127,22 @@ function isExactPackageVersion(value) {
|
|
|
33402
34127
|
return /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(value);
|
|
33403
34128
|
}
|
|
33404
34129
|
function readContext7Lockfile(root) {
|
|
33405
|
-
|
|
34130
|
+
return readContext7LockfileState(root).lock;
|
|
34131
|
+
}
|
|
34132
|
+
function readContext7LockfileState(root) {
|
|
34133
|
+
const path = assertPathHasNoSymlinkSegments(root, CONTEXT7_LOCKFILE);
|
|
33406
34134
|
if (!existsSync15(path)) {
|
|
33407
34135
|
return {
|
|
33408
|
-
|
|
33409
|
-
|
|
33410
|
-
|
|
34136
|
+
lock: {
|
|
34137
|
+
schemaVersion: CONTEXT7_LOCKFILE_SCHEMA_VERSION,
|
|
34138
|
+
provider: "context7",
|
|
34139
|
+
libraries: []
|
|
34140
|
+
},
|
|
34141
|
+
expectedHash: "missing"
|
|
33411
34142
|
};
|
|
33412
34143
|
}
|
|
33413
|
-
const
|
|
34144
|
+
const body = readFileSync14(path, "utf8");
|
|
34145
|
+
const parsed = JSON.parse(body);
|
|
33414
34146
|
if (parsed.schemaVersion !== CONTEXT7_LOCKFILE_SCHEMA_VERSION || parsed.provider !== "context7" || !Array.isArray(parsed.libraries)) {
|
|
33415
34147
|
throw new Error("Invalid Context7 lockfile");
|
|
33416
34148
|
}
|
|
@@ -33419,8 +34151,11 @@ function readContext7Lockfile(root) {
|
|
|
33419
34151
|
assertContext7Version(library.version);
|
|
33420
34152
|
}
|
|
33421
34153
|
return {
|
|
33422
|
-
|
|
33423
|
-
|
|
34154
|
+
lock: {
|
|
34155
|
+
...parsed,
|
|
34156
|
+
libraries: [...parsed.libraries].sort((a, b) => a.libraryId.localeCompare(b.libraryId))
|
|
34157
|
+
},
|
|
34158
|
+
expectedHash: digestJson({ body })
|
|
33424
34159
|
};
|
|
33425
34160
|
}
|
|
33426
34161
|
function upsertContext7Pin(lock, pin) {
|
|
@@ -33430,8 +34165,14 @@ function upsertContext7Pin(lock, pin) {
|
|
|
33430
34165
|
libraries: [...lock.libraries.filter((library) => library.libraryId !== pin.libraryId), pin].sort((a, b) => a.libraryId.localeCompare(b.libraryId))
|
|
33431
34166
|
};
|
|
33432
34167
|
}
|
|
33433
|
-
function writeContext7Lockfile(root, lock) {
|
|
33434
|
-
|
|
34168
|
+
function writeContext7Lockfile(root, lock, expectedHash) {
|
|
34169
|
+
writeFileWithoutFollowingSymlinks({
|
|
34170
|
+
root,
|
|
34171
|
+
path: CONTEXT7_LOCKFILE,
|
|
34172
|
+
body: JSON.stringify(lock, null, 2),
|
|
34173
|
+
mode: 384,
|
|
34174
|
+
expectedHash
|
|
34175
|
+
});
|
|
33435
34176
|
}
|
|
33436
34177
|
function writeDeveloperReviewRunManifest(manifest) {
|
|
33437
34178
|
writePrivateJson3(manifest.manifestPath, manifest);
|
|
@@ -33439,25 +34180,192 @@ function writeDeveloperReviewRunManifest(manifest) {
|
|
|
33439
34180
|
function writePrivateJson3(path, value, flag = "w") {
|
|
33440
34181
|
mkdirSync7(dirname10(path), { recursive: true });
|
|
33441
34182
|
writeFileSync6(path, JSON.stringify(value, null, 2), { mode: 384, flag });
|
|
33442
|
-
|
|
34183
|
+
chmodSync4(path, 384);
|
|
33443
34184
|
}
|
|
33444
34185
|
function readDeveloperReviewRunManifest(path) {
|
|
33445
|
-
|
|
33446
|
-
|
|
33447
|
-
|
|
33448
|
-
if (typeof parsed.runId !== "string" || typeof parsed.challengeId !== "string")
|
|
33449
|
-
return;
|
|
33450
|
-
if (typeof parsed.repositoryId !== "number" || typeof parsed.sourceRoot !== "string")
|
|
33451
|
-
return;
|
|
33452
|
-
if (typeof parsed.runRoot !== "string" || typeof parsed.worktreeTempRoot !== "string")
|
|
33453
|
-
return;
|
|
33454
|
-
if (typeof parsed.manifestPath !== "string" || typeof parsed.lockPath !== "string")
|
|
33455
|
-
return;
|
|
33456
|
-
if (typeof parsed.pid !== "number" || typeof parsed.createdAt !== "string")
|
|
33457
|
-
return;
|
|
33458
|
-
if (parsed.status !== "preparing" && parsed.status !== "running")
|
|
34186
|
+
try {
|
|
34187
|
+
return decodeDeveloperReviewRunManifest(readJsonObject(path), "developer-review-run-manifest");
|
|
34188
|
+
} catch {
|
|
33459
34189
|
return;
|
|
33460
|
-
|
|
34190
|
+
}
|
|
34191
|
+
}
|
|
34192
|
+
function rpcInputInvalid(context, detail) {
|
|
34193
|
+
return new Error(`runtime-rpc-input-invalid: ${context} ${detail}`);
|
|
34194
|
+
}
|
|
34195
|
+
function decodeRpcRecord(value, context, label, allowedKeys) {
|
|
34196
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
34197
|
+
throw rpcInputInvalid(context, `${label} must be an object`);
|
|
34198
|
+
const record2 = value;
|
|
34199
|
+
for (const key of Object.keys(record2)) {
|
|
34200
|
+
if (!allowedKeys.includes(key))
|
|
34201
|
+
throw rpcInputInvalid(context, `${label} has unknown field ${key}`);
|
|
34202
|
+
}
|
|
34203
|
+
return record2;
|
|
34204
|
+
}
|
|
34205
|
+
function rpcString(record2, context, label) {
|
|
34206
|
+
const value = record2[label];
|
|
34207
|
+
if (typeof value !== "string" || value.length === 0)
|
|
34208
|
+
throw rpcInputInvalid(context, `${label} must be a non-empty string`);
|
|
34209
|
+
return value;
|
|
34210
|
+
}
|
|
34211
|
+
function rpcOptionalString(record2, context, label) {
|
|
34212
|
+
return record2[label] === undefined ? undefined : rpcString(record2, context, label);
|
|
34213
|
+
}
|
|
34214
|
+
function rpcNumber(record2, context, label) {
|
|
34215
|
+
const value = record2[label];
|
|
34216
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
34217
|
+
throw rpcInputInvalid(context, `${label} must be a number`);
|
|
34218
|
+
return value;
|
|
34219
|
+
}
|
|
34220
|
+
function rpcLiteral(record2, context, label, allowed) {
|
|
34221
|
+
const value = record2[label];
|
|
34222
|
+
if (typeof value !== "string" || !allowed.includes(value))
|
|
34223
|
+
throw rpcInputInvalid(context, `${label} is not an accepted value`);
|
|
34224
|
+
return value;
|
|
34225
|
+
}
|
|
34226
|
+
function decodeRpcReviewChallengeV2(value, context) {
|
|
34227
|
+
const record2 = decodeRpcRecord(value, context, "challenge", [
|
|
34228
|
+
"schemaVersion",
|
|
34229
|
+
"challengeId",
|
|
34230
|
+
"installationId",
|
|
34231
|
+
"repositoryId",
|
|
34232
|
+
"pullRequestNumber",
|
|
34233
|
+
"headSha",
|
|
34234
|
+
"baseSha",
|
|
34235
|
+
"nonce",
|
|
34236
|
+
"requiredTrust",
|
|
34237
|
+
"policyProfileId",
|
|
34238
|
+
"createdAt",
|
|
34239
|
+
"expiresAt",
|
|
34240
|
+
"status"
|
|
34241
|
+
]);
|
|
34242
|
+
return {
|
|
34243
|
+
schemaVersion: rpcLiteral(record2, context, "schemaVersion", ["archcontext.review-challenge/v2"]),
|
|
34244
|
+
challengeId: rpcString(record2, context, "challengeId"),
|
|
34245
|
+
installationId: rpcNumber(record2, context, "installationId"),
|
|
34246
|
+
repositoryId: rpcNumber(record2, context, "repositoryId"),
|
|
34247
|
+
pullRequestNumber: rpcNumber(record2, context, "pullRequestNumber"),
|
|
34248
|
+
headSha: rpcString(record2, context, "headSha"),
|
|
34249
|
+
baseSha: rpcString(record2, context, "baseSha"),
|
|
34250
|
+
nonce: rpcString(record2, context, "nonce"),
|
|
34251
|
+
requiredTrust: rpcLiteral(record2, context, "requiredTrust", ["developer", "organization"]),
|
|
34252
|
+
policyProfileId: rpcString(record2, context, "policyProfileId"),
|
|
34253
|
+
createdAt: rpcString(record2, context, "createdAt"),
|
|
34254
|
+
expiresAt: rpcString(record2, context, "expiresAt"),
|
|
34255
|
+
status: rpcLiteral(record2, context, "status", ["PENDING", "LEASED", "SUBMITTED", "VERIFIED", "REJECTED", "SUPERSEDED", "EXPIRED"])
|
|
34256
|
+
};
|
|
34257
|
+
}
|
|
34258
|
+
function decodeRpcDetachedReviewWorktree(value, context, label = "worktree") {
|
|
34259
|
+
const record2 = decodeRpcRecord(value, context, label, [
|
|
34260
|
+
"schemaVersion",
|
|
34261
|
+
"sourceRoot",
|
|
34262
|
+
"worktreeRoot",
|
|
34263
|
+
"temporaryRoot",
|
|
34264
|
+
"headSha",
|
|
34265
|
+
"headTreeOid",
|
|
34266
|
+
"detached",
|
|
34267
|
+
"clean"
|
|
34268
|
+
]);
|
|
34269
|
+
if (record2.detached !== true)
|
|
34270
|
+
throw rpcInputInvalid(context, `${label}.detached must be true`);
|
|
34271
|
+
if (record2.clean !== true)
|
|
34272
|
+
throw rpcInputInvalid(context, `${label}.clean must be true`);
|
|
34273
|
+
return {
|
|
34274
|
+
schemaVersion: rpcLiteral(record2, context, "schemaVersion", ["archcontext.detached-review-worktree/v1"]),
|
|
34275
|
+
sourceRoot: rpcString(record2, context, "sourceRoot"),
|
|
34276
|
+
worktreeRoot: rpcString(record2, context, "worktreeRoot"),
|
|
34277
|
+
temporaryRoot: rpcString(record2, context, "temporaryRoot"),
|
|
34278
|
+
headSha: rpcString(record2, context, "headSha"),
|
|
34279
|
+
headTreeOid: rpcString(record2, context, "headTreeOid"),
|
|
34280
|
+
detached: true,
|
|
34281
|
+
clean: true
|
|
34282
|
+
};
|
|
34283
|
+
}
|
|
34284
|
+
function decodeDeveloperReviewRunManifest(value, context) {
|
|
34285
|
+
const record2 = decodeRpcRecord(value, context, "run", [
|
|
34286
|
+
"schemaVersion",
|
|
34287
|
+
"runId",
|
|
34288
|
+
"challengeId",
|
|
34289
|
+
"repositoryId",
|
|
34290
|
+
"sourceRoot",
|
|
34291
|
+
"runRoot",
|
|
34292
|
+
"worktreeTempRoot",
|
|
34293
|
+
"manifestPath",
|
|
34294
|
+
"lockPath",
|
|
34295
|
+
"pid",
|
|
34296
|
+
"createdAt",
|
|
34297
|
+
"status",
|
|
34298
|
+
"codeGraphTemporaryState",
|
|
34299
|
+
"worktree"
|
|
34300
|
+
]);
|
|
34301
|
+
const codeGraphTemporaryState = decodeRpcRecord(record2.codeGraphTemporaryState, context, "run.codeGraphTemporaryState", ["root", "cleanup"]);
|
|
34302
|
+
return {
|
|
34303
|
+
schemaVersion: rpcLiteral(record2, context, "schemaVersion", ["archcontext.developer-review-run/v1"]),
|
|
34304
|
+
runId: rpcString(record2, context, "runId"),
|
|
34305
|
+
challengeId: rpcString(record2, context, "challengeId"),
|
|
34306
|
+
repositoryId: rpcNumber(record2, context, "repositoryId"),
|
|
34307
|
+
sourceRoot: rpcString(record2, context, "sourceRoot"),
|
|
34308
|
+
runRoot: rpcString(record2, context, "runRoot"),
|
|
34309
|
+
worktreeTempRoot: rpcString(record2, context, "worktreeTempRoot"),
|
|
34310
|
+
manifestPath: rpcString(record2, context, "manifestPath"),
|
|
34311
|
+
lockPath: rpcString(record2, context, "lockPath"),
|
|
34312
|
+
pid: rpcNumber(record2, context, "pid"),
|
|
34313
|
+
createdAt: rpcString(record2, context, "createdAt"),
|
|
34314
|
+
status: rpcLiteral(record2, context, "status", ["preparing", "running"]),
|
|
34315
|
+
codeGraphTemporaryState: {
|
|
34316
|
+
root: rpcString(codeGraphTemporaryState, context, "root"),
|
|
34317
|
+
cleanup: rpcLiteral(codeGraphTemporaryState, context, "cleanup", ["remove-run-root"])
|
|
34318
|
+
},
|
|
34319
|
+
...record2.worktree === undefined ? {} : { worktree: decodeRpcDetachedReviewWorktree(record2.worktree, context, "run.worktree") }
|
|
34320
|
+
};
|
|
34321
|
+
}
|
|
34322
|
+
function decodeStartDeveloperReviewRunParams(params) {
|
|
34323
|
+
const context = "startDeveloperReviewRun";
|
|
34324
|
+
const record2 = decodeRpcRecord(params[0], context, "params[0]", ["repositoryRoot", "challenge", "expectedHeadTreeOid"]);
|
|
34325
|
+
const expectedHeadTreeOid = rpcOptionalString(record2, context, "expectedHeadTreeOid");
|
|
34326
|
+
return {
|
|
34327
|
+
repositoryRoot: rpcString(record2, context, "repositoryRoot"),
|
|
34328
|
+
challenge: decodeRpcReviewChallengeV2(record2.challenge, context),
|
|
34329
|
+
...expectedHeadTreeOid === undefined ? {} : { expectedHeadTreeOid }
|
|
34330
|
+
};
|
|
34331
|
+
}
|
|
34332
|
+
function decodeSignedDeveloperReviewAttestationParams(params) {
|
|
34333
|
+
const context = "runSignedDeveloperReviewAttestation";
|
|
34334
|
+
const record2 = decodeRpcRecord(params[0], context, "params[0]", [
|
|
34335
|
+
"challenge",
|
|
34336
|
+
"worktree",
|
|
34337
|
+
"keyRef",
|
|
34338
|
+
"principalId",
|
|
34339
|
+
"publicKeyId",
|
|
34340
|
+
"taskSessionId",
|
|
34341
|
+
"mergeBaseSha",
|
|
34342
|
+
"startedAt",
|
|
34343
|
+
"completedAt"
|
|
34344
|
+
]);
|
|
34345
|
+
const optional = {
|
|
34346
|
+
taskSessionId: rpcOptionalString(record2, context, "taskSessionId"),
|
|
34347
|
+
mergeBaseSha: rpcOptionalString(record2, context, "mergeBaseSha"),
|
|
34348
|
+
startedAt: rpcOptionalString(record2, context, "startedAt"),
|
|
34349
|
+
completedAt: rpcOptionalString(record2, context, "completedAt")
|
|
34350
|
+
};
|
|
34351
|
+
return {
|
|
34352
|
+
challenge: decodeRpcReviewChallengeV2(record2.challenge, context),
|
|
34353
|
+
worktree: decodeRpcDetachedReviewWorktree(record2.worktree, context),
|
|
34354
|
+
keyRef: rpcString(record2, context, "keyRef"),
|
|
34355
|
+
principalId: rpcString(record2, context, "principalId"),
|
|
34356
|
+
publicKeyId: rpcString(record2, context, "publicKeyId"),
|
|
34357
|
+
...Object.fromEntries(Object.entries(optional).filter(([, value]) => value !== undefined))
|
|
34358
|
+
};
|
|
34359
|
+
}
|
|
34360
|
+
function decodeRecoverDeveloperReviewRunsParams(params) {
|
|
34361
|
+
const context = "recoverDeveloperReviewRuns";
|
|
34362
|
+
const record2 = decodeRpcRecord(params[0], context, "params[0]", ["repositoryRoot", "force"]);
|
|
34363
|
+
if (record2.force !== undefined && typeof record2.force !== "boolean")
|
|
34364
|
+
throw rpcInputInvalid(context, "force must be a boolean");
|
|
34365
|
+
return {
|
|
34366
|
+
repositoryRoot: rpcString(record2, context, "repositoryRoot"),
|
|
34367
|
+
...record2.force === undefined ? {} : { force: record2.force }
|
|
34368
|
+
};
|
|
33461
34369
|
}
|
|
33462
34370
|
function readJsonObject(path) {
|
|
33463
34371
|
try {
|
|
@@ -33642,33 +34550,42 @@ function readCurrentBranch(root) {
|
|
|
33642
34550
|
}
|
|
33643
34551
|
}
|
|
33644
34552
|
function repositoryNameWithOwner(root) {
|
|
34553
|
+
const target = readGitRemoteTarget(root);
|
|
34554
|
+
return target ? `${target.owner}/${target.repo}` : "local/unknown";
|
|
34555
|
+
}
|
|
34556
|
+
var SUPPORTED_GITHUB_REMOTE_HOST = "github.com";
|
|
34557
|
+
function readGitRemoteTarget(root) {
|
|
33645
34558
|
try {
|
|
33646
34559
|
const url = execFileSync7("git", ["remote", "get-url", "origin"], {
|
|
33647
34560
|
cwd: root,
|
|
33648
34561
|
encoding: "utf8",
|
|
33649
34562
|
stdio: ["ignore", "pipe", "ignore"]
|
|
33650
34563
|
}).trim();
|
|
33651
|
-
return
|
|
34564
|
+
return parseGitRemoteTarget(url);
|
|
33652
34565
|
} catch {
|
|
33653
|
-
return
|
|
34566
|
+
return;
|
|
33654
34567
|
}
|
|
33655
34568
|
}
|
|
33656
|
-
function
|
|
34569
|
+
function parseGitRemoteTarget(url) {
|
|
33657
34570
|
const stripped = url.trim().replace(/\.git$/, "");
|
|
33658
|
-
const scpMatch = /^[^/@]+@[^:/]
|
|
34571
|
+
const scpMatch = /^[^/@]+@([^:/]+):(.+)$/.exec(stripped);
|
|
33659
34572
|
if (scpMatch)
|
|
33660
|
-
return
|
|
34573
|
+
return gitRemoteTarget(scpMatch[1], scpMatch[2]);
|
|
33661
34574
|
try {
|
|
33662
|
-
|
|
34575
|
+
const parsed = new URL(stripped);
|
|
34576
|
+
return gitRemoteTarget(parsed.hostname, parsed.pathname);
|
|
33663
34577
|
} catch {
|
|
33664
34578
|
return;
|
|
33665
34579
|
}
|
|
33666
34580
|
}
|
|
33667
|
-
function
|
|
34581
|
+
function gitRemoteTarget(host, path) {
|
|
34582
|
+
const canonicalHost = host.trim().toLowerCase();
|
|
34583
|
+
if (!canonicalHost)
|
|
34584
|
+
return;
|
|
33668
34585
|
const segments = path.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
33669
34586
|
if (segments.length < 2)
|
|
33670
34587
|
return;
|
|
33671
|
-
return segments.
|
|
34588
|
+
return { host: canonicalHost, owner: segments[segments.length - 2], repo: segments[segments.length - 1] };
|
|
33672
34589
|
}
|
|
33673
34590
|
function normalizeGithubRepoVisibility(value) {
|
|
33674
34591
|
const lowered = value.trim().toLowerCase();
|
|
@@ -33684,6 +34601,10 @@ function auditApproveResultPayload(runId, status, totalCount, issuedIssues) {
|
|
|
33684
34601
|
issuedIssues
|
|
33685
34602
|
};
|
|
33686
34603
|
}
|
|
34604
|
+
function obsoleteManagedProjectionPaths(currentFiles, projectedFiles) {
|
|
34605
|
+
const targetPaths = new Set(projectedFiles.map((file) => file.path));
|
|
34606
|
+
return currentFiles.filter((file) => !targetPaths.has(file.path)).map((file) => file.path);
|
|
34607
|
+
}
|
|
33687
34608
|
function expectedFileHash(root, path) {
|
|
33688
34609
|
const absolute = resolve18(root, path);
|
|
33689
34610
|
return existsSync15(absolute) ? digestJson({ body: readFileSync14(absolute, "utf8") }) : "missing";
|
|
@@ -33978,13 +34899,63 @@ function isRpcVersionHeaderCompatible(request) {
|
|
|
33978
34899
|
const header = requestRpcVersionHeader(request);
|
|
33979
34900
|
return header === undefined || header === RUNTIME_RPC_VERSION;
|
|
33980
34901
|
}
|
|
33981
|
-
async function
|
|
33982
|
-
const
|
|
33983
|
-
|
|
33984
|
-
|
|
33985
|
-
|
|
33986
|
-
|
|
33987
|
-
return
|
|
34902
|
+
async function readRpcRequestBody(request, limits) {
|
|
34903
|
+
const declaredLength = Number(request.headers["content-length"]);
|
|
34904
|
+
if (Number.isFinite(declaredLength) && declaredLength > limits.maxBytes) {
|
|
34905
|
+
request.pause();
|
|
34906
|
+
return { ok: false, kind: "rejected", status: 413, error: "runtime RPC request body exceeds the configured limit" };
|
|
34907
|
+
}
|
|
34908
|
+
return await new Promise((resolveBody) => {
|
|
34909
|
+
let chunks = [];
|
|
34910
|
+
let size = 0;
|
|
34911
|
+
let settled = false;
|
|
34912
|
+
const timer = setTimeout(() => {
|
|
34913
|
+
settle({ ok: false, kind: "rejected", status: 408, error: "runtime RPC request body read timeout" });
|
|
34914
|
+
}, limits.timeoutMs);
|
|
34915
|
+
const settle = (result) => {
|
|
34916
|
+
if (settled)
|
|
34917
|
+
return;
|
|
34918
|
+
settled = true;
|
|
34919
|
+
clearTimeout(timer);
|
|
34920
|
+
chunks = [];
|
|
34921
|
+
request.off("data", onData);
|
|
34922
|
+
request.off("end", onEnd);
|
|
34923
|
+
request.off("aborted", onAborted);
|
|
34924
|
+
request.off("error", onAborted);
|
|
34925
|
+
request.off("close", onClose);
|
|
34926
|
+
if (!result.ok)
|
|
34927
|
+
request.pause();
|
|
34928
|
+
resolveBody(result);
|
|
34929
|
+
};
|
|
34930
|
+
const onData = (chunk) => {
|
|
34931
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
34932
|
+
size += buffer.length;
|
|
34933
|
+
if (size > limits.maxBytes) {
|
|
34934
|
+
settle({ ok: false, kind: "rejected", status: 413, error: "runtime RPC request body exceeds the configured limit" });
|
|
34935
|
+
return;
|
|
34936
|
+
}
|
|
34937
|
+
chunks.push(buffer);
|
|
34938
|
+
};
|
|
34939
|
+
const onEnd = () => {
|
|
34940
|
+
if (size === 0) {
|
|
34941
|
+
settle({ ok: true, value: {} });
|
|
34942
|
+
return;
|
|
34943
|
+
}
|
|
34944
|
+
const body = Buffer.concat(chunks).toString("utf8");
|
|
34945
|
+
try {
|
|
34946
|
+
settle({ ok: true, value: JSON.parse(body) });
|
|
34947
|
+
} catch {
|
|
34948
|
+
settle({ ok: false, kind: "rejected", status: 400, error: "runtime RPC request body is not valid JSON" });
|
|
34949
|
+
}
|
|
34950
|
+
};
|
|
34951
|
+
const onAborted = () => settle({ ok: false, kind: "aborted" });
|
|
34952
|
+
const onClose = () => settle({ ok: false, kind: "aborted" });
|
|
34953
|
+
request.on("data", onData);
|
|
34954
|
+
request.on("end", onEnd);
|
|
34955
|
+
request.on("aborted", onAborted);
|
|
34956
|
+
request.on("error", onAborted);
|
|
34957
|
+
request.on("close", onClose);
|
|
34958
|
+
});
|
|
33988
34959
|
}
|
|
33989
34960
|
function writeJson(response, statusCode, body) {
|
|
33990
34961
|
response.writeHead(statusCode, { "Content-Type": "application/json; charset=utf-8" });
|
|
@@ -34140,20 +35111,82 @@ function structurizrElementType(kind) {
|
|
|
34140
35111
|
init_src();
|
|
34141
35112
|
|
|
34142
35113
|
// packages/local-runtime/runtime-daemon/src/index.ts
|
|
34143
|
-
import { chmodSync as
|
|
35114
|
+
import { chmodSync as chmodSync5, closeSync as closeSync7, existsSync as existsSync16, lstatSync as lstatSync8, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync5, openSync as openSync7, readdirSync as readdirSync10, readFileSync as readFileSync15, rmSync as rmSync9, statSync as statSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
35115
|
+
init_src();
|
|
34144
35116
|
init_src();
|
|
34145
35117
|
var DEFAULT_DAEMON_IDLE_TIMEOUT_MS2 = 30 * 60000;
|
|
34146
35118
|
var RUNTIME_RPC_VERSION2 = LOCAL_RUNTIME_RPC_SCHEMA_VERSION;
|
|
35119
|
+
var RUNTIME_RPC_MAX_REQUEST_BODY_BYTES2 = 16 * 1024 * 1024;
|
|
35120
|
+
class RuntimeRpcTransportError2 extends Error {
|
|
35121
|
+
code;
|
|
35122
|
+
method;
|
|
35123
|
+
timeoutMs;
|
|
35124
|
+
elapsedMs;
|
|
35125
|
+
constructor(code, method, timeoutMs, elapsedMs) {
|
|
35126
|
+
super(code === "RPC_TIMEOUT" ? `runtime RPC timeout: ${method} exceeded ${timeoutMs}ms` : `runtime RPC cancelled: ${method} aborted after ${elapsedMs}ms`);
|
|
35127
|
+
this.code = code;
|
|
35128
|
+
this.method = method;
|
|
35129
|
+
this.timeoutMs = timeoutMs;
|
|
35130
|
+
this.elapsedMs = elapsedMs;
|
|
35131
|
+
this.name = "RuntimeRpcTransportError";
|
|
35132
|
+
}
|
|
35133
|
+
}
|
|
35134
|
+
var RUNTIME_RPC_CLIENT_TIMEOUT_POLICY2 = {
|
|
35135
|
+
health: 5000,
|
|
35136
|
+
short: 15000,
|
|
35137
|
+
normal: 120000,
|
|
35138
|
+
long: 900000
|
|
35139
|
+
};
|
|
35140
|
+
var RUNTIME_RPC_SHORT_METHODS2 = new Set([
|
|
35141
|
+
"shutdown",
|
|
35142
|
+
"runtimeStatus",
|
|
35143
|
+
"landscapeStatus",
|
|
35144
|
+
"repoList",
|
|
35145
|
+
"explorerStatus",
|
|
35146
|
+
"explorerServiceContract",
|
|
35147
|
+
"jobsList",
|
|
35148
|
+
"jobsStats",
|
|
35149
|
+
"ledgerState",
|
|
35150
|
+
"ledgerDrift",
|
|
35151
|
+
"stopExplorer",
|
|
35152
|
+
"revokeExplorerToken"
|
|
35153
|
+
]);
|
|
35154
|
+
var RUNTIME_RPC_LONG_METHODS2 = new Set([
|
|
35155
|
+
"init",
|
|
35156
|
+
"sync",
|
|
35157
|
+
"prepare",
|
|
35158
|
+
"context",
|
|
35159
|
+
"checkpoint",
|
|
35160
|
+
"auditRun",
|
|
35161
|
+
"auditApprove",
|
|
35162
|
+
"recommendations",
|
|
35163
|
+
"book",
|
|
35164
|
+
"ledgerRebuild",
|
|
35165
|
+
"ledgerMigrate",
|
|
35166
|
+
"startDeveloperReviewRun",
|
|
35167
|
+
"runSignedDeveloperReviewAttestation"
|
|
35168
|
+
]);
|
|
35169
|
+
function runtimeRpcMethodTimeout2(method, policy) {
|
|
35170
|
+
if (RUNTIME_RPC_SHORT_METHODS2.has(method))
|
|
35171
|
+
return policy.short;
|
|
35172
|
+
if (RUNTIME_RPC_LONG_METHODS2.has(method))
|
|
35173
|
+
return policy.long;
|
|
35174
|
+
return policy.normal;
|
|
35175
|
+
}
|
|
35176
|
+
|
|
34147
35177
|
class RuntimeRpcClient2 {
|
|
34148
35178
|
connection;
|
|
34149
|
-
|
|
35179
|
+
options;
|
|
35180
|
+
timeouts;
|
|
35181
|
+
constructor(connection, options = {}) {
|
|
34150
35182
|
this.connection = connection;
|
|
35183
|
+
this.options = options;
|
|
35184
|
+
this.timeouts = { ...RUNTIME_RPC_CLIENT_TIMEOUT_POLICY2, ...options.timeouts };
|
|
34151
35185
|
}
|
|
34152
35186
|
async health() {
|
|
34153
|
-
|
|
35187
|
+
return await this.request("health", this.timeouts.health, `${this.connection.url}health`, {
|
|
34154
35188
|
headers: { "X-ArchContext-RPC-Version": RUNTIME_RPC_VERSION2 }
|
|
34155
35189
|
});
|
|
34156
|
-
return await response.json();
|
|
34157
35190
|
}
|
|
34158
35191
|
async shutdown() {
|
|
34159
35192
|
return this.call("shutdown", []);
|
|
@@ -34237,8 +35270,11 @@ class RuntimeRpcClient2 {
|
|
|
34237
35270
|
applyUpdate(root, input) {
|
|
34238
35271
|
return this.call("applyUpdate", [root, input]);
|
|
34239
35272
|
}
|
|
34240
|
-
|
|
34241
|
-
return this.call("
|
|
35273
|
+
inspectProjectionApplyReceipt(root, lookupKey) {
|
|
35274
|
+
return this.call("inspectProjectionApplyReceipt", [root, lookupKey]);
|
|
35275
|
+
}
|
|
35276
|
+
recoverProjectionApply(root, intent) {
|
|
35277
|
+
return this.call("recoverProjectionApply", [root, intent]);
|
|
34242
35278
|
}
|
|
34243
35279
|
ledgerState(root) {
|
|
34244
35280
|
return this.call("ledgerState", [root]);
|
|
@@ -34316,7 +35352,7 @@ class RuntimeRpcClient2 {
|
|
|
34316
35352
|
return unwrapRpcData2(await this.call("recoverDeveloperReviewRuns", [input]));
|
|
34317
35353
|
}
|
|
34318
35354
|
async call(method, params) {
|
|
34319
|
-
|
|
35355
|
+
return await this.request(method, runtimeRpcMethodTimeout2(method, this.timeouts), `${this.connection.url}rpc`, {
|
|
34320
35356
|
method: "POST",
|
|
34321
35357
|
headers: {
|
|
34322
35358
|
Authorization: `Bearer ${this.connection.token}`,
|
|
@@ -34325,7 +35361,35 @@ class RuntimeRpcClient2 {
|
|
|
34325
35361
|
},
|
|
34326
35362
|
body: JSON.stringify({ schemaVersion: RUNTIME_RPC_VERSION2, method, params })
|
|
34327
35363
|
});
|
|
34328
|
-
|
|
35364
|
+
}
|
|
35365
|
+
async request(method, timeoutMs, url, init) {
|
|
35366
|
+
const controller = new AbortController;
|
|
35367
|
+
const startedAt = Date.now();
|
|
35368
|
+
let timedOut = false;
|
|
35369
|
+
const timer = setTimeout(() => {
|
|
35370
|
+
timedOut = true;
|
|
35371
|
+
controller.abort();
|
|
35372
|
+
}, timeoutMs);
|
|
35373
|
+
const callerSignal = this.options.signal;
|
|
35374
|
+
const onCallerAbort = () => controller.abort();
|
|
35375
|
+
if (callerSignal?.aborted)
|
|
35376
|
+
controller.abort();
|
|
35377
|
+
else
|
|
35378
|
+
callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
35379
|
+
try {
|
|
35380
|
+
const response = await fetch(url, { ...init, signal: controller.signal });
|
|
35381
|
+
return await response.json();
|
|
35382
|
+
} catch (error) {
|
|
35383
|
+
const elapsedMs = Date.now() - startedAt;
|
|
35384
|
+
if (timedOut)
|
|
35385
|
+
throw new RuntimeRpcTransportError2("RPC_TIMEOUT", method, timeoutMs, elapsedMs);
|
|
35386
|
+
if (callerSignal?.aborted)
|
|
35387
|
+
throw new RuntimeRpcTransportError2("RPC_ABORTED", method, timeoutMs, elapsedMs);
|
|
35388
|
+
throw error;
|
|
35389
|
+
} finally {
|
|
35390
|
+
clearTimeout(timer);
|
|
35391
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
35392
|
+
}
|
|
34329
35393
|
}
|
|
34330
35394
|
}
|
|
34331
35395
|
function defaultDaemonConnectionPath2(root = process.cwd()) {
|
|
@@ -35100,7 +36164,7 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
|
|
|
35100
36164
|
requestId: "help",
|
|
35101
36165
|
data: {
|
|
35102
36166
|
commands: ["capabilities", "projection", "init", "sync", "validate", "context", "status", "daemon", "state", "repo", "landscape", "ledger", "book", "recommendations", "explore", "prepare", "practices", "checkpoint", "hook", "hooks", "investigate", "agents", "jobs", "audit", "plan", "apply", "review", "complete", "github", "config", "mcp", "install", "uninstall", "doctor", "update", "paths", "privacy-audit", "export", "import", "resolve", "tunnel"],
|
|
35103
|
-
examples: ["archctx init --name MyApp", "archctx state recover --from-git", "archctx ledger migrate --from-yaml --dry-run", "archctx ledger promote --mode authoritative --preflight --rollback-plan", "archctx book recommendations --open --explain", "archctx recommendations accept --id recommendation.<id> --reason 'Accepted after local readback.'", "archctx recommendations metrics", "archctx practices validate --strict", "archctx practices list --json", "archctx practices waivers", "archctx practices waive --practice-id modularity.no-new-cycle --owner team-architecture --reason 'External migration window requires this edge until cutover.' --review-at 2026-07-10T00:00:00.000Z --expires-at 2026-07-24T00:00:00.000Z --evidence-digest sha256:<64-hex> --subject module.a->module.b", "archctx checkpoint --task-session-id task_cli", "archctx investigate --runner-port codex", "archctx agents status --status queued,running", "archctx agents budget", "archctx hook enqueue --event post-edit --path src/app.ts", "archctx jobs list --status queued", "archctx audit run --reason 'quarterly architecture audit'", "archctx audit run --no-wait", "archctx audit list --status pending", "archctx audit show audit_run.<id>", "archctx audit approve audit_run.<id>", "archctx audit approve audit_run.<id> --confirm-public-repo public:<owner
|
|
36167
|
+
examples: ["archctx init --name MyApp", "archctx state recover --from-git", "archctx ledger migrate --from-yaml --dry-run", "archctx ledger promote --mode authoritative --preflight --rollback-plan", "archctx book recommendations --open --explain", "archctx recommendations accept --id recommendation.<id> --reason 'Accepted after local readback.'", "archctx recommendations metrics", "archctx practices validate --strict", "archctx practices list --json", "archctx practices waivers", "archctx practices waive --practice-id modularity.no-new-cycle --owner team-architecture --reason 'External migration window requires this edge until cutover.' --review-at 2026-07-10T00:00:00.000Z --expires-at 2026-07-24T00:00:00.000Z --evidence-digest sha256:<64-hex> --subject module.a->module.b", "archctx checkpoint --task-session-id task_cli", "archctx investigate --runner-port codex", "archctx agents status --status queued,running", "archctx agents budget", "archctx hook enqueue --event post-edit --path src/app.ts", "archctx jobs list --status queued", "archctx audit run --reason 'quarterly architecture audit'", "archctx audit run --no-wait", "archctx audit list --status pending", "archctx audit show audit_run.<id>", "archctx audit approve audit_run.<id>", "archctx audit approve audit_run.<id> --confirm-public-repo public:<host>/<owner>/<repo>:<baseSha>:<runId>", "archctx audit approve audit_run.<id> --resume", "archctx hooks install --host codex", "archctx paths", "archctx update --check", "archctx doctor --check-updates", "archctx github connect", "archctx github status", "archctx daemon start", "archctx explore start --foreground", "archctx export likec4", "archctx import structurizr --content '<json>'", "archctx resolve --path packages/core/projection-engine/src/index.ts", "archctx tunnel"]
|
|
35104
36168
|
}
|
|
35105
36169
|
};
|
|
35106
36170
|
}
|
|
@@ -35792,9 +36856,11 @@ async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projectio
|
|
|
35792
36856
|
});
|
|
35793
36857
|
}
|
|
35794
36858
|
async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
35795
|
-
|
|
35796
|
-
|
|
35797
|
-
|
|
36859
|
+
const subcommand = args2[0] ?? "run";
|
|
36860
|
+
if (subcommand === "recover")
|
|
36861
|
+
return runProjectionApplyRecoveryCommand(args2.slice(1), cwd, daemon);
|
|
36862
|
+
if (subcommand !== "run")
|
|
36863
|
+
return errorEnvelope("projection", "AC_SCHEMA_INVALID", "projection requires run|recover --request-json <request>");
|
|
35798
36864
|
const raw = readFlag(args2, "--request-json");
|
|
35799
36865
|
if (!raw)
|
|
35800
36866
|
return errorEnvelope("projection.run", "AC_SCHEMA_INVALID", "projection run requires --request-json");
|
|
@@ -35809,21 +36875,19 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
35809
36875
|
if (request.mode === "apply" && request.acceptedChange) {
|
|
35810
36876
|
try {
|
|
35811
36877
|
assertProjectionExpectedSnapshotAgainstModel(request, root, loadNativeModelFromArchContext(root));
|
|
36878
|
+
const inspected = await daemon.inspectProjectionApplyReceipt(root, projectionApplyLookupKey({
|
|
36879
|
+
repositoryId: request.expected.repositoryId,
|
|
36880
|
+
workspaceId: request.expected.workspaceId,
|
|
36881
|
+
acceptedChange: request.acceptedChange
|
|
36882
|
+
}));
|
|
36883
|
+
if (!inspected.ok)
|
|
36884
|
+
return inspected;
|
|
36885
|
+
if (inspected.data.found === true) {
|
|
36886
|
+
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", "committed projection receipt requires explicit projection recover");
|
|
36887
|
+
}
|
|
35812
36888
|
} catch (error) {
|
|
35813
36889
|
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
35814
36890
|
}
|
|
35815
|
-
const reconciled = await daemon.reconcileProjectionApply(root, projectionApplyLookupKey({
|
|
35816
|
-
repositoryId: request.expected.repositoryId,
|
|
35817
|
-
workspaceId: request.expected.workspaceId,
|
|
35818
|
-
acceptedChange: request.acceptedChange
|
|
35819
|
-
}));
|
|
35820
|
-
if (!reconciled.ok)
|
|
35821
|
-
return reconciled;
|
|
35822
|
-
const data = reconciled.data;
|
|
35823
|
-
if (data.found === true) {
|
|
35824
|
-
const receipt = data.receipt;
|
|
35825
|
-
return projectionProtocolResultEnvelope(data.refreshSignalsDelivered === true ? projectionResultDelivery(receipt.result, "applied", receipt.result.refreshSignals, request.requestId) : projectionResultDelivery(receipt.result, "noop", [], request.requestId));
|
|
35826
|
-
}
|
|
35827
36891
|
}
|
|
35828
36892
|
let projection3;
|
|
35829
36893
|
try {
|
|
@@ -35864,21 +36928,51 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
35864
36928
|
}
|
|
35865
36929
|
if (request.mode === "apply" && !projection3.plan.drift.ok) {
|
|
35866
36930
|
const changeSetId = `changeset.docs-projection-${projection3.plan.projectionDigest.replace(/^sha256:/, "").slice(0, 16)}`;
|
|
36931
|
+
let fixedPointProjection;
|
|
36932
|
+
try {
|
|
36933
|
+
fixedPointProjection = request.acceptedChange ? buildArchitectureDocsProjection(root, generatedAt, REPO_HARNESS_PROJECTION_PROFILE, projection3.files) : projection3;
|
|
36934
|
+
if (request.acceptedChange && (fixedPointProjection.plan.rejected.length > 0 || fixedPointProjection.plan.majorChange.mode !== "none" || fixedPointProjection.plan.refreshSignals.length > 0)) {
|
|
36935
|
+
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", "accepted projection did not produce a no-accepted-change semantic fixed point");
|
|
36936
|
+
}
|
|
36937
|
+
} catch (error) {
|
|
36938
|
+
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
36939
|
+
}
|
|
36940
|
+
const committedFiles = projectionProtocolFilesForExpectedOutput(root, fixedPointProjection);
|
|
36941
|
+
const committedSignals = request.acceptedChange ? projection3.plan.refreshSignals.map((signal) => ({
|
|
36942
|
+
...signal,
|
|
36943
|
+
resultingDigests: fixedPointProjection.plan.architectureDigests
|
|
36944
|
+
})) : fixedPointProjection.plan.refreshSignals;
|
|
35867
36945
|
const applyIdentity = request.acceptedChange ? createProjectionApplyIdentity({
|
|
35868
36946
|
repositoryId: request.expected.repositoryId,
|
|
35869
36947
|
workspaceId: request.expected.workspaceId,
|
|
35870
36948
|
acceptedChange: request.acceptedChange,
|
|
35871
36949
|
changeSetId,
|
|
35872
36950
|
idempotencyKey: `idem_${changeSetId}`,
|
|
35873
|
-
files:
|
|
35874
|
-
refreshSignals:
|
|
36951
|
+
files: committedFiles,
|
|
36952
|
+
refreshSignals: committedSignals
|
|
35875
36953
|
}) : undefined;
|
|
35876
|
-
const appliedResult = projectionProtocolResult(request, projection3, "applied",
|
|
35877
|
-
|
|
36954
|
+
const appliedResult = projectionProtocolResult(request, projection3, "applied", fixedPointProjection, applyIdentity, {
|
|
36955
|
+
files: committedFiles,
|
|
36956
|
+
refreshSignals: committedSignals
|
|
36957
|
+
});
|
|
36958
|
+
let recoveryBinding;
|
|
36959
|
+
if (applyIdentity) {
|
|
36960
|
+
try {
|
|
36961
|
+
recoveryBinding = createProjectionApplyRecoveryBinding(request, fixedPointProjection, appliedResult);
|
|
36962
|
+
} catch (error) {
|
|
36963
|
+
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
36964
|
+
}
|
|
36965
|
+
}
|
|
36966
|
+
const applyReceipt = applyIdentity ? {
|
|
36967
|
+
schemaVersion: "archcontext.projection-apply-receipt/v1",
|
|
36968
|
+
identity: applyIdentity,
|
|
36969
|
+
result: appliedResult,
|
|
36970
|
+
recovery: recoveryBinding
|
|
36971
|
+
} : undefined;
|
|
35878
36972
|
const planned = await daemon.planUpdate(root, {
|
|
35879
36973
|
id: changeSetId,
|
|
35880
36974
|
reason: { taskSessionId: request.requestId },
|
|
35881
|
-
operations: [architectureDocsRenderProjectionOperation(root,
|
|
36975
|
+
operations: [architectureDocsRenderProjectionOperation(root, fixedPointProjection.files)],
|
|
35882
36976
|
worktreeDigestPrecondition: {
|
|
35883
36977
|
profile: "architecture-documentation-projection",
|
|
35884
36978
|
expectedDigest: request.expected.worktreeDigest
|
|
@@ -35912,18 +37006,120 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
35912
37006
|
if (!postApplyMatches) {
|
|
35913
37007
|
return projectionProtocolResultEnvelope(projectionResultDelivery(appliedResult, "applied-reconcile-required", []));
|
|
35914
37008
|
}
|
|
35915
|
-
const
|
|
35916
|
-
|
|
35917
|
-
|
|
35918
|
-
|
|
35919
|
-
|
|
37009
|
+
const delivery = await daemon.recoverProjectionApply(root, {
|
|
37010
|
+
schemaVersion: PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION,
|
|
37011
|
+
requestId: request.requestId,
|
|
37012
|
+
profile: REPO_HARNESS_PROJECTION_PROFILE,
|
|
37013
|
+
receipt: {
|
|
37014
|
+
lookupKey: applyReceipt.identity.lookupKey,
|
|
37015
|
+
applyId: applyReceipt.identity.applyId
|
|
37016
|
+
}
|
|
37017
|
+
});
|
|
37018
|
+
if (!delivery.ok)
|
|
37019
|
+
return delivery;
|
|
37020
|
+
const delivered = delivery.data;
|
|
37021
|
+
if (delivered.found !== true || delivered.refreshSignalsDelivered !== true) {
|
|
35920
37022
|
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", "committed projection apply receipt was not available for first delivery");
|
|
35921
37023
|
}
|
|
35922
|
-
return projectionProtocolResultEnvelope(
|
|
37024
|
+
return projectionProtocolResultEnvelope(projectionResultDelivery(appliedResult, "applied", delivered.receipt.result.refreshSignals, request.requestId));
|
|
35923
37025
|
}
|
|
35924
37026
|
const status = projection3.plan.drift.ok ? "noop" : "planned";
|
|
35925
37027
|
return projectionProtocolEnvelope(request, projection3, status);
|
|
35926
37028
|
}
|
|
37029
|
+
async function runProjectionApplyRecoveryCommand(args2, cwd, daemon) {
|
|
37030
|
+
const raw = readFlag(args2, "--request-json");
|
|
37031
|
+
if (!raw)
|
|
37032
|
+
return errorEnvelope("projection.recover", "AC_SCHEMA_INVALID", "projection recover requires --request-json");
|
|
37033
|
+
let intent;
|
|
37034
|
+
try {
|
|
37035
|
+
intent = parseProjectionApplyRecoveryIntent(raw);
|
|
37036
|
+
} catch (error) {
|
|
37037
|
+
return errorEnvelope("projection.recover", "AC_SCHEMA_INVALID", error instanceof Error ? error.message : String(error));
|
|
37038
|
+
}
|
|
37039
|
+
return recoverProjectionApplyIntent(intent, findRepositoryRoot(cwd), daemon);
|
|
37040
|
+
}
|
|
37041
|
+
async function recoverProjectionApplyIntent(intent, root, daemon) {
|
|
37042
|
+
let recovered;
|
|
37043
|
+
try {
|
|
37044
|
+
recovered = await daemon.recoverProjectionApply(root, intent);
|
|
37045
|
+
} catch (error) {
|
|
37046
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
37047
|
+
}
|
|
37048
|
+
if (!recovered.ok)
|
|
37049
|
+
return recovered;
|
|
37050
|
+
const consumption = recovered.data;
|
|
37051
|
+
if (consumption.found !== true || !consumption.receipt || !consumption.proof) {
|
|
37052
|
+
return errorEnvelope("projection.recover", "AC_PRECONDITION_FAILED", "committed projection apply receipt was unavailable for recovery delivery");
|
|
37053
|
+
}
|
|
37054
|
+
return projectionApplyRecoveryResultEnvelope({
|
|
37055
|
+
schemaVersion: PROJECTION_APPLY_RECOVERY_RESULT_SCHEMA_VERSION,
|
|
37056
|
+
proof: consumption.proof,
|
|
37057
|
+
refreshSignals: consumption.refreshSignalsDelivered ? consumption.receipt.result.refreshSignals : []
|
|
37058
|
+
});
|
|
37059
|
+
}
|
|
37060
|
+
function createProjectionApplyRecoveryBinding(request, projection3, result) {
|
|
37061
|
+
const provenance = projection3.plan.provenance;
|
|
37062
|
+
return {
|
|
37063
|
+
schemaVersion: "archcontext.projection-apply-recovery-binding/v1",
|
|
37064
|
+
targets: [...request.targets],
|
|
37065
|
+
changedPaths: [...request.changedPaths],
|
|
37066
|
+
originalExpectedSnapshot: { ...request.expected },
|
|
37067
|
+
expectedResultingDigests: projection3.plan.architectureDigests,
|
|
37068
|
+
rendererVersion: provenance.rendererVersion,
|
|
37069
|
+
layoutVersion: provenance.layoutVersion,
|
|
37070
|
+
generatedFrom: provenance.generatedFrom,
|
|
37071
|
+
ownedOutputDigest: projectionOwnedOutputDigest(projection3),
|
|
37072
|
+
receiptDigest: result.receiptDigest
|
|
37073
|
+
};
|
|
37074
|
+
}
|
|
37075
|
+
function projectionOwnedOutputDigest(projection3) {
|
|
37076
|
+
return digestJson({
|
|
37077
|
+
schemaVersion: "archcontext.projection-owned-output/v1",
|
|
37078
|
+
files: projection3.files.map((file) => ({ path: file.path, body: file.body })).sort((left, right) => left.path.localeCompare(right.path))
|
|
37079
|
+
});
|
|
37080
|
+
}
|
|
37081
|
+
function projectionApplyRecoveryResultEnvelope(result) {
|
|
37082
|
+
const issues = projectionApplyRecoveryResultInvariantIssues(result);
|
|
37083
|
+
return issues.length === 0 ? okEnvelope("projection.recover", result) : errorEnvelope("projection.recover", "AC_SCHEMA_INVALID", `projection recovery result invariant failed: ${issues.join("; ")}`);
|
|
37084
|
+
}
|
|
37085
|
+
function parseProjectionApplyRecoveryIntent(raw) {
|
|
37086
|
+
let value;
|
|
37087
|
+
try {
|
|
37088
|
+
value = JSON.parse(raw);
|
|
37089
|
+
} catch {
|
|
37090
|
+
throw new Error("projection recovery intent is not valid JSON");
|
|
37091
|
+
}
|
|
37092
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
37093
|
+
throw new Error("projection recovery intent must be an object");
|
|
37094
|
+
const input = value;
|
|
37095
|
+
const allowedKeys = new Set(["schemaVersion", "requestId", "profile", "receipt"]);
|
|
37096
|
+
const unsupported = Object.keys(input).find((key) => !allowedKeys.has(key));
|
|
37097
|
+
if (unsupported)
|
|
37098
|
+
throw new Error(`projection recovery intent contains unsupported property: ${unsupported}`);
|
|
37099
|
+
if (input.schemaVersion !== PROJECTION_APPLY_RECOVERY_INTENT_SCHEMA_VERSION)
|
|
37100
|
+
throw new Error("projection recovery intent schemaVersion mismatch");
|
|
37101
|
+
if (input.profile !== REPO_HARNESS_PROJECTION_PROFILE)
|
|
37102
|
+
throw new Error(`projection recovery intent profile must be ${REPO_HARNESS_PROJECTION_PROFILE}`);
|
|
37103
|
+
if (typeof input.requestId !== "string")
|
|
37104
|
+
throw new Error("projection recovery intent requestId is required");
|
|
37105
|
+
const receipt = input.receipt;
|
|
37106
|
+
if (!receipt || typeof receipt !== "object" || Array.isArray(receipt))
|
|
37107
|
+
throw new Error("projection recovery intent receipt must be an object");
|
|
37108
|
+
const receiptInput = receipt;
|
|
37109
|
+
const receiptUnsupported = Object.keys(receiptInput).find((key) => key !== "lookupKey" && key !== "applyId");
|
|
37110
|
+
if (receiptUnsupported)
|
|
37111
|
+
throw new Error(`projection recovery intent receipt contains unsupported property: ${receiptUnsupported}`);
|
|
37112
|
+
for (const field of ["lookupKey", "applyId"]) {
|
|
37113
|
+
if (typeof receiptInput[field] !== "string" || !/^sha256:[a-f0-9]{64}$/.test(receiptInput[field])) {
|
|
37114
|
+
throw new Error(`projection recovery intent receipt.${field} is invalid`);
|
|
37115
|
+
}
|
|
37116
|
+
}
|
|
37117
|
+
const intent = input;
|
|
37118
|
+
const issues = projectionApplyRecoveryIntentInvariantIssues(intent);
|
|
37119
|
+
if (issues.length > 0)
|
|
37120
|
+
throw new Error(`projection recovery intent invariant failed: ${issues.join("; ")}`);
|
|
37121
|
+
return intent;
|
|
37122
|
+
}
|
|
35927
37123
|
function parseProjectionProtocolRequest(raw) {
|
|
35928
37124
|
let value;
|
|
35929
37125
|
try {
|
|
@@ -36019,10 +37215,10 @@ function projectionProtocolHumanStatus(request, projection3) {
|
|
|
36019
37215
|
function projectionProtocolEnvelope(request, input, status, output = input) {
|
|
36020
37216
|
return projectionProtocolResultEnvelope(projectionProtocolResult(request, input, status, output));
|
|
36021
37217
|
}
|
|
36022
|
-
function projectionProtocolResult(request, input, status, output = input, applyReceipt) {
|
|
37218
|
+
function projectionProtocolResult(request, input, status, output = input, applyReceipt, overrides) {
|
|
36023
37219
|
const inputSnapshot = projectionProtocolSnapshot(request, input.plan.provenance);
|
|
36024
37220
|
const outputSnapshot = projectionProtocolSnapshot(request, output.plan.provenance);
|
|
36025
|
-
const files = projectionProtocolFiles(input);
|
|
37221
|
+
const files = overrides?.files ?? projectionProtocolFiles(input);
|
|
36026
37222
|
const affectedNodeIds = projectionProtocolAffectedNodes(input);
|
|
36027
37223
|
const requestPayloadDigest = digestJson(request);
|
|
36028
37224
|
const humanActions = [];
|
|
@@ -36035,7 +37231,7 @@ function projectionProtocolResult(request, input, status, output = input, applyR
|
|
|
36035
37231
|
requestPayloadDigest
|
|
36036
37232
|
});
|
|
36037
37233
|
}
|
|
36038
|
-
const refreshSignals = [...output.plan.refreshSignals].sort((left, right) => left.signalId < right.signalId ? -1 : left.signalId > right.signalId ? 1 : 0);
|
|
37234
|
+
const refreshSignals = [...overrides?.refreshSignals ?? output.plan.refreshSignals].sort((left, right) => left.signalId < right.signalId ? -1 : left.signalId > right.signalId ? 1 : 0);
|
|
36039
37235
|
const withoutReceipt = {
|
|
36040
37236
|
schemaVersion: "archcontext.projection-result/v2",
|
|
36041
37237
|
requestId: request.requestId,
|
|
@@ -36103,6 +37299,19 @@ function projectionProtocolFiles(projection3) {
|
|
|
36103
37299
|
return [];
|
|
36104
37300
|
}).sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
36105
37301
|
}
|
|
37302
|
+
function projectionProtocolFilesForExpectedOutput(root, projection3) {
|
|
37303
|
+
return projection3.files.flatMap((file) => {
|
|
37304
|
+
const preimageDigest = currentProjectionFileDigest(root, file.path);
|
|
37305
|
+
const outputDigest = digestJson({ path: file.path, body: file.body });
|
|
37306
|
+
if (preimageDigest === outputDigest)
|
|
37307
|
+
return [];
|
|
37308
|
+
return preimageDigest === "missing" ? [{ path: file.path, action: "create", preimageDigest: null, outputDigest }] : [{ path: file.path, action: "update", preimageDigest, outputDigest }];
|
|
37309
|
+
}).sort((left, right) => left.path.localeCompare(right.path));
|
|
37310
|
+
}
|
|
37311
|
+
function currentProjectionFileDigest(root, path) {
|
|
37312
|
+
const absolute = resolve19(root, path);
|
|
37313
|
+
return existsSync17(absolute) ? digestJson({ path, body: readFileSync16(absolute, "utf8") }) : "missing";
|
|
37314
|
+
}
|
|
36106
37315
|
function projectionProtocolAffectedNodes(projection3) {
|
|
36107
37316
|
const targetNodes = new Map(projection3.plan.targets.flatMap((target) => target.scope.kind === "entity" ? [[target.targetId, target.scope.id]] : []));
|
|
36108
37317
|
return [...new Set([
|
|
@@ -37148,7 +38357,7 @@ async function writeGithubDeveloperReviewState(cwd, state) {
|
|
|
37148
38357
|
assertNoCliSecretMaterial(serialized);
|
|
37149
38358
|
writeFileSync8(path, serialized, { mode: 384 });
|
|
37150
38359
|
if (process.platform !== "win32")
|
|
37151
|
-
|
|
38360
|
+
chmodSync6(path, 384);
|
|
37152
38361
|
return { state, path };
|
|
37153
38362
|
}
|
|
37154
38363
|
function readGithubDeveloperReviewState(path) {
|
|
@@ -37222,7 +38431,7 @@ function writeGithubConnection(path, record2) {
|
|
|
37222
38431
|
assertNoCliSecretMaterial(serialized);
|
|
37223
38432
|
writeFileSync8(path, serialized, { mode: 384 });
|
|
37224
38433
|
if (process.platform !== "win32")
|
|
37225
|
-
|
|
38434
|
+
chmodSync6(path, 384);
|
|
37226
38435
|
}
|
|
37227
38436
|
function sanitizeGithubConnection(record2, connectionPath) {
|
|
37228
38437
|
return {
|