archctx 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/catalog.yaml +2 -2
- package/bin/archctx.mjs +78 -31
- package/package.json +1 -1
package/assets/catalog.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "archcontext.practice-catalog-manifest/v1",
|
|
3
3
|
"catalogVersion": "2026.06.0",
|
|
4
|
-
"productVersion": "0.9.
|
|
4
|
+
"productVersion": "0.9.1",
|
|
5
5
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
6
6
|
"entries": [
|
|
7
7
|
{
|
|
@@ -389,5 +389,5 @@
|
|
|
389
389
|
"structurizr.dsl",
|
|
390
390
|
"twelve-factor"
|
|
391
391
|
],
|
|
392
|
-
"catalogDigest": "sha256:
|
|
392
|
+
"catalogDigest": "sha256:d23b231c9623d6594abcceb22ce08bb74e81c157ce8dca59e3efaef5f961c264"
|
|
393
393
|
}
|
package/bin/archctx.mjs
CHANGED
|
@@ -53,6 +53,9 @@ function stableYaml(value, indent = 0) {
|
|
|
53
53
|
return `[]
|
|
54
54
|
`;
|
|
55
55
|
return value.map((item) => {
|
|
56
|
+
if (Array.isArray(item))
|
|
57
|
+
return `${pad}- ${canonicalize(item)}
|
|
58
|
+
`;
|
|
56
59
|
if (item !== null && typeof item === "object") {
|
|
57
60
|
return `${pad}- ${stableYaml(item, indent + 2).trimStart()}`;
|
|
58
61
|
}
|
|
@@ -3873,7 +3876,7 @@ function compareVersionTriples(left, right) {
|
|
|
3873
3876
|
}
|
|
3874
3877
|
return 0;
|
|
3875
3878
|
}
|
|
3876
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.9.
|
|
3879
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.9.1", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v2", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
|
|
3877
3880
|
|
|
3878
3881
|
// packages/contracts/src/refactor.ts
|
|
3879
3882
|
function refactorNamespaceIssues(value, label = "product.id") {
|
|
@@ -27311,7 +27314,7 @@ function listModelFiles(root) {
|
|
|
27311
27314
|
return {
|
|
27312
27315
|
path,
|
|
27313
27316
|
body,
|
|
27314
|
-
schemaVersion: extractSchemaVersion(body),
|
|
27317
|
+
schemaVersion: extractSchemaVersion(body, path),
|
|
27315
27318
|
digest: digestJson({ path, body })
|
|
27316
27319
|
};
|
|
27317
27320
|
});
|
|
@@ -27357,7 +27360,15 @@ function readdirOrFile(path) {
|
|
|
27357
27360
|
return "file";
|
|
27358
27361
|
}
|
|
27359
27362
|
}
|
|
27360
|
-
function extractSchemaVersion(body) {
|
|
27363
|
+
function extractSchemaVersion(body, path) {
|
|
27364
|
+
if (path.startsWith(".archcontext/model/") && /\.ya?ml$/.test(path)) {
|
|
27365
|
+
try {
|
|
27366
|
+
const parsed = parseJsonOrStableYaml(body, path);
|
|
27367
|
+
return typeof parsed?.schemaVersion === "string" ? parsed.schemaVersion : "";
|
|
27368
|
+
} catch {
|
|
27369
|
+
return "";
|
|
27370
|
+
}
|
|
27371
|
+
}
|
|
27361
27372
|
const match = body.match(/schemaVersion:\s*"?([^"\n]+)"?/);
|
|
27362
27373
|
if (match)
|
|
27363
27374
|
return match[1].trim();
|
|
@@ -39648,6 +39659,7 @@ class AgentJobService {
|
|
|
39648
39659
|
supersededByJobId: input.supersededByJobId,
|
|
39649
39660
|
now: input.now ?? this.context.clock()
|
|
39650
39661
|
});
|
|
39662
|
+
this.context.abortOwnedAudit(job.job.jobId);
|
|
39651
39663
|
return okEnvelope("jobs.cancel", { job });
|
|
39652
39664
|
}
|
|
39653
39665
|
async runtimeAgentJobInScope(scope, jobId) {
|
|
@@ -54391,7 +54403,7 @@ class ProjectionWriterFailure extends Error {
|
|
|
54391
54403
|
function projectionWriterPaths(repositoryRoot, remote, base, env = process.env) {
|
|
54392
54404
|
const key = createHash13("sha256").update(`${remote}\x00${base}`, "utf8").digest("hex").slice(0, 16);
|
|
54393
54405
|
const dir = join23(runtimeStatePaths(repositoryRoot, env).repositoryStateDir, "projection-writer", key);
|
|
54394
|
-
return { dir, worktree: join23(dir, "worktree"), state: join23(dir, "state.json"), lock: join23(dir, "lock") };
|
|
54406
|
+
return { dir, baseRef: `refs/archctx/projection-writer/${key}/base`, worktree: join23(dir, "worktree"), state: join23(dir, "state.json"), lock: join23(dir, "lock") };
|
|
54395
54407
|
}
|
|
54396
54408
|
async function runProjectionPublishCommand(options) {
|
|
54397
54409
|
const env = options.env ?? process.env;
|
|
@@ -54483,10 +54495,21 @@ async function runLockedProjectionPublish(input) {
|
|
|
54483
54495
|
const failed = (failure, fields = {}, extra = {}) => finish("failed", { ...fields, error: writerError(failure) }, extra);
|
|
54484
54496
|
try {
|
|
54485
54497
|
const pushRemote = projectionWriterPushUrl(repositoryRoot, remote);
|
|
54498
|
+
const fetchUrls = git(repositoryRoot, ["remote", "get-url", "--all", "--", remote]).trim().split(`
|
|
54499
|
+
`).filter(Boolean);
|
|
54500
|
+
const tracksPublication = fetchUrls.length === 1 && fetchUrls[0] === pushRemote;
|
|
54486
54501
|
while (iterations < PROJECTION_WRITER_MAX_ITERATIONS) {
|
|
54487
54502
|
iterations += 1;
|
|
54488
|
-
remoteGit(repositoryRoot, [
|
|
54489
|
-
|
|
54503
|
+
remoteGit(repositoryRoot, [
|
|
54504
|
+
"fetch",
|
|
54505
|
+
"--no-tags",
|
|
54506
|
+
"--no-write-fetch-head",
|
|
54507
|
+
"--",
|
|
54508
|
+
pushRemote,
|
|
54509
|
+
`+refs/heads/${base}:${paths.baseRef}`,
|
|
54510
|
+
...tracksPublication ? [`+refs/heads/${base}:refs/remotes/${remote}/${base}`] : []
|
|
54511
|
+
], env);
|
|
54512
|
+
baseSha = git(repositoryRoot, ["rev-parse", "--verify", `${paths.baseRef}^{commit}`]).trim();
|
|
54490
54513
|
const successMatches = state.lastSuccessfulBranch === branch && state.lastSuccessfulSha === baseSha;
|
|
54491
54514
|
const pending = state.publisherPending?.branch === branch && state.publisherPending.baseSha === baseSha ? state.publisherPending : successMatches && state.lastSuccessfulCommit && state.lastSuccessfulPublisher !== publisherIdentity ? { branch, baseSha, commitSha: state.lastSuccessfulCommit, files: state.lastSuccessfulFiles } : null;
|
|
54492
54515
|
if (!pending && successMatches && state.lastSuccessfulPublisher === publisherIdentity && (state.lastSuccessfulCommit === null || lsRemoteBranch(repositoryRoot, pushRemote, branch, env) === state.lastSuccessfulCommit)) {
|
|
@@ -54535,8 +54558,15 @@ async function runLockedProjectionPublish(input) {
|
|
|
54535
54558
|
throw new ProjectionWriterFailure("AC_PRECONDITION_FAILED", "projection-apply-status-unsupported", `projection apply ended with status ${projectionStatus}; the writer publishes only noop, applied and applied-partial results`);
|
|
54536
54559
|
}
|
|
54537
54560
|
const changed = worktreeChangedPaths(paths.worktree);
|
|
54538
|
-
if (changed.length === 0)
|
|
54561
|
+
if (changed.length === 0) {
|
|
54562
|
+
const tip = lsRemoteBranch(repositoryRoot, pushRemote, base, env);
|
|
54563
|
+
if (tip === null) {
|
|
54564
|
+
return failed(new ProjectionWriterFailure("AC_PRECONDITION_FAILED", "projection-writer-base-missing", `${remote} has no branch ${base}`), { projectionStatus });
|
|
54565
|
+
}
|
|
54566
|
+
if (tip !== baseSha)
|
|
54567
|
+
continue;
|
|
54539
54568
|
return finish("up-to-date", { projectionStatus });
|
|
54569
|
+
}
|
|
54540
54570
|
const written = new Set(result.files.filter((file) => file.action !== "unchanged").map((file) => file.path));
|
|
54541
54571
|
const offending = changed.filter((path) => !written.has(path) || !isProjectionOwnedPath(path, ownedPatterns));
|
|
54542
54572
|
if (offending.length > 0) {
|
|
@@ -54551,7 +54581,7 @@ async function runLockedProjectionPublish(input) {
|
|
|
54551
54581
|
return failed(new ProjectionWriterFailure("AC_PRECONDITION_FAILED", "projection-writer-commit-failed", `git commit failed in the writer worktree; configure a git identity (user.name, user.email) for the repository or set GIT_AUTHOR_*/GIT_COMMITTER_*: ${errorMessage2(error)}`), { projectionStatus, files: changed });
|
|
54552
54582
|
}
|
|
54553
54583
|
const commitSha = git(paths.worktree, ["rev-parse", "HEAD"]).trim();
|
|
54554
|
-
const tip = lsRemoteBranch(repositoryRoot,
|
|
54584
|
+
const tip = lsRemoteBranch(repositoryRoot, pushRemote, base, env);
|
|
54555
54585
|
if (tip === null) {
|
|
54556
54586
|
return failed(new ProjectionWriterFailure("AC_PRECONDITION_FAILED", "projection-writer-base-missing", `${remote} has no branch ${base}`), { projectionStatus, files: changed });
|
|
54557
54587
|
}
|
|
@@ -54900,8 +54930,8 @@ function createGhProjectionPublisher(options = {}) {
|
|
|
54900
54930
|
const env = { ...stringEnv(process.env), GH_PROMPT_DISABLED: "1" };
|
|
54901
54931
|
delete env.GH_REPO;
|
|
54902
54932
|
const gh = (args) => withLocalEgress2("projection-publishing", () => exec("gh", [...args, "--repo", repository], { cwd: input.worktree, env, timeoutMs }), admissionEnv);
|
|
54903
|
-
const listed = await gh(["pr", "list", "--head", input.branch, "--base", input.base, "--state", "open", "--json", "number,url", "--limit", "
|
|
54904
|
-
const open = parseGhPullRequestList(listed.stdout);
|
|
54933
|
+
const listed = await gh(["pr", "list", "--head", input.branch, "--base", input.base, "--state", "open", "--json", "number,url,isCrossRepository,headRefName,baseRefName", "--limit", "100"]);
|
|
54934
|
+
const open = parseGhPullRequestList(listed.stdout, input.branch, input.base);
|
|
54905
54935
|
if (open) {
|
|
54906
54936
|
await gh(["pr", "edit", String(open.number), "--title", input.title, "--body-file", input.bodyFile]);
|
|
54907
54937
|
return { number: open.number, ...open.url ? { url: open.url } : {} };
|
|
@@ -55049,16 +55079,24 @@ function readCommandFirstLine(command) {
|
|
|
55049
55079
|
closeSync9(fd);
|
|
55050
55080
|
}
|
|
55051
55081
|
}
|
|
55052
|
-
function parseGhPullRequestList(stdout) {
|
|
55053
|
-
const parsed = JSON.parse(stdout
|
|
55082
|
+
function parseGhPullRequestList(stdout, branch, base) {
|
|
55083
|
+
const parsed = JSON.parse(stdout);
|
|
55054
55084
|
if (!Array.isArray(parsed))
|
|
55055
55085
|
throw new Error("gh pr list returned an unexpected shape");
|
|
55056
|
-
|
|
55057
|
-
|
|
55058
|
-
|
|
55059
|
-
|
|
55060
|
-
|
|
55061
|
-
|
|
55086
|
+
if (parsed.length >= 100)
|
|
55087
|
+
throw new Error("gh pr list reached the 100-result limit; resolve rolling PR ambiguity manually");
|
|
55088
|
+
const matches = [];
|
|
55089
|
+
for (const row of parsed) {
|
|
55090
|
+
if (!row || typeof row !== "object" || Array.isArray(row) || typeof row.isCrossRepository !== "boolean" || row.headRefName !== branch || row.baseRefName !== base || typeof row.number !== "number" || !Number.isInteger(row.number) || row.number <= 0) {
|
|
55091
|
+
throw new Error("gh pr list returned a pull request without verified identity");
|
|
55092
|
+
}
|
|
55093
|
+
if (!row.isCrossRepository) {
|
|
55094
|
+
matches.push({ number: row.number, ...typeof row.url === "string" && row.url !== "" ? { url: row.url } : {} });
|
|
55095
|
+
}
|
|
55096
|
+
}
|
|
55097
|
+
if (matches.length > 1)
|
|
55098
|
+
throw new Error("gh pr list returned multiple same-repository rolling pull requests");
|
|
55099
|
+
return matches[0];
|
|
55062
55100
|
}
|
|
55063
55101
|
function parsePublisherCommandOutput(stdout) {
|
|
55064
55102
|
let parsed;
|
|
@@ -57954,23 +57992,31 @@ class ArchctxRuntimeRpcServer {
|
|
|
57954
57992
|
this.server = undefined;
|
|
57955
57993
|
const connection = this.connection;
|
|
57956
57994
|
this.connection = undefined;
|
|
57995
|
+
const errors = [];
|
|
57996
|
+
const cleanup = async (action) => {
|
|
57997
|
+
try {
|
|
57998
|
+
await action();
|
|
57999
|
+
} catch (error) {
|
|
58000
|
+
errors.push(error);
|
|
58001
|
+
}
|
|
58002
|
+
};
|
|
57957
58003
|
if (server) {
|
|
57958
|
-
await new Promise((resolveClose, rejectClose) => {
|
|
58004
|
+
await cleanup(() => new Promise((resolveClose, rejectClose) => {
|
|
57959
58005
|
server.close((error) => error ? rejectClose(error) : resolveClose());
|
|
57960
|
-
});
|
|
57961
|
-
}
|
|
57962
|
-
await this.daemon.stop();
|
|
57963
|
-
try {
|
|
57964
|
-
if (connection)
|
|
57965
|
-
await removePrivateControlFile(connection.connectionPath);
|
|
57966
|
-
} finally {
|
|
57967
|
-
if (this.lockFd !== undefined)
|
|
57968
|
-
closeSync11(this.lockFd);
|
|
57969
|
-
this.lockFd = undefined;
|
|
58006
|
+
}));
|
|
57970
58007
|
}
|
|
58008
|
+
await cleanup(() => this.daemon.stop());
|
|
58009
|
+
if (connection)
|
|
58010
|
+
await cleanup(() => removePrivateControlFile(connection.connectionPath));
|
|
58011
|
+
const lockFd = this.lockFd;
|
|
58012
|
+
this.lockFd = undefined;
|
|
58013
|
+
if (lockFd !== undefined)
|
|
58014
|
+
await cleanup(() => closeSync11(lockFd));
|
|
57971
58015
|
if (connection)
|
|
57972
|
-
await removePrivateControlFile(connection.lockPath);
|
|
57973
|
-
this.options.onStop?.();
|
|
58016
|
+
await cleanup(() => removePrivateControlFile(connection.lockPath));
|
|
58017
|
+
await cleanup(() => this.options.onStop?.());
|
|
58018
|
+
if (errors.length > 0)
|
|
58019
|
+
throw errors[0];
|
|
57974
58020
|
}
|
|
57975
58021
|
armIdleTimer() {
|
|
57976
58022
|
if (this.idleTimeoutMs <= 0 || !this.server)
|
|
@@ -58486,6 +58532,7 @@ class ArchctxDaemon {
|
|
|
58486
58532
|
localStore: this.localStore
|
|
58487
58533
|
});
|
|
58488
58534
|
this.agentJobs = new AgentJobService({
|
|
58535
|
+
abortOwnedAudit: (jobId) => this.auditRunAbortControllers.get(jobId)?.abort(),
|
|
58489
58536
|
assertRunning: () => this.assertRunning(),
|
|
58490
58537
|
openSession: (root) => this.openSession(root),
|
|
58491
58538
|
architectureLedgerScope: (root) => this.architectureLedgerScope(root),
|