archctx 0.8.0 → 0.8.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 +372 -70
- package/package.json +1 -1
- package/schemas/runtime/native-model-issue.schema.json +18 -0
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.8.
|
|
4
|
+
"productVersion": "0.8.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:abdff8c6f9f2ffc75fe35295b097884ec2996b179628bb81966f62cbb29ad75a"
|
|
393
393
|
}
|
package/bin/archctx.mjs
CHANGED
|
@@ -96,6 +96,7 @@ var init_schema = __esm(() => {
|
|
|
96
96
|
AC_NODE_VERSION_UNSUPPORTED: { code: "AC_NODE_VERSION_UNSUPPORTED", severity: "error", retryable: false, action: "use-supported-node-version" },
|
|
97
97
|
AC_CODEGRAPH_UNAVAILABLE: { code: "AC_CODEGRAPH_UNAVAILABLE", severity: "error", retryable: true, action: "run-diagnostics" },
|
|
98
98
|
AC_CODE_FACTS_UNAVAILABLE: { code: "AC_CODE_FACTS_UNAVAILABLE", severity: "error", retryable: true, action: "codegraph-init" },
|
|
99
|
+
AC_CODE_FACTS_NOT_READY: { code: "AC_CODE_FACTS_NOT_READY", severity: "error", retryable: false, action: "codegraph-index" },
|
|
99
100
|
AC_INDEX_STALE: { code: "AC_INDEX_STALE", severity: "warning", retryable: true, action: "sync-codefacts" },
|
|
100
101
|
AC_CONTEXT_STALE: { code: "AC_CONTEXT_STALE", severity: "warning", retryable: true, action: "prepare-task-again" },
|
|
101
102
|
AC_SCHEMA_INVALID: { code: "AC_SCHEMA_INVALID", severity: "error", retryable: false, action: "repair-model" },
|
|
@@ -2031,6 +2032,23 @@ function dataRecord(value) {
|
|
|
2031
2032
|
return fields;
|
|
2032
2033
|
}
|
|
2033
2034
|
function localFactValue(rule, value) {
|
|
2035
|
+
if (rule === "codeFactsIssues") {
|
|
2036
|
+
if (!Array.isArray(value))
|
|
2037
|
+
throw new Error("Code facts issues must be a list");
|
|
2038
|
+
const length = Object.getOwnPropertyDescriptor(value, "length")?.value;
|
|
2039
|
+
if (!Number.isSafeInteger(length) || length < 1 || length > 32 || Reflect.ownKeys(value).length !== length + 1)
|
|
2040
|
+
throw new Error("Code facts issues exceed their closed budget");
|
|
2041
|
+
return Array.from({ length }, (_, index) => {
|
|
2042
|
+
const entry = Object.getOwnPropertyDescriptor(value, String(index));
|
|
2043
|
+
if (!entry || !("value" in entry))
|
|
2044
|
+
throw new Error("Code facts issues must use own data");
|
|
2045
|
+
const fields = dataRecord(entry.value);
|
|
2046
|
+
const code = fields.code?.value, message = fields.message?.value;
|
|
2047
|
+
if (Object.keys(fields).length !== 2 || typeof code !== "string" || !Object.hasOwn(CODE_FACTS_ISSUE_MESSAGES, code) || message !== CODE_FACTS_ISSUE_MESSAGES[code])
|
|
2048
|
+
throw new Error("Unknown code facts diagnostic");
|
|
2049
|
+
return { code, message };
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2034
2052
|
if (rule === "commandSuggestion" && (value === null || typeof value === "string" && bytes(value) <= 1024 && /^archctx (recommendations |refactor verify )[^\r\n]*$/.test(value)))
|
|
2035
2053
|
return value;
|
|
2036
2054
|
if (rule === "publicConfirmationToken" && typeof value === "string" && bytes(value) <= 1024 && /^public:github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+:[a-f0-9]{40}:[A-Za-z0-9_.:-]+$/.test(value))
|
|
@@ -2130,7 +2148,7 @@ function nativeFactsFor(policy, input) {
|
|
|
2130
2148
|
}
|
|
2131
2149
|
const item = dataRecord(value);
|
|
2132
2150
|
if (type === "issues") {
|
|
2133
|
-
if (
|
|
2151
|
+
if (!["entityId", "field", "invariant"].every((key) => Object.hasOwn(item, key)) || Object.keys(item).some((key) => !["entityId", "field", "invariant", "path"].includes(key)))
|
|
2134
2152
|
throw new Error("Native issue schema is invalid");
|
|
2135
2153
|
const clean = Object.fromEntries(Object.entries(item).map(([key, data]) => [key, text(data.value)]));
|
|
2136
2154
|
if (Object.values(clean).some((v) => bytes(v) > 256)) {
|
|
@@ -2202,6 +2220,8 @@ function nativeFactsFor(policy, input) {
|
|
|
2202
2220
|
}
|
|
2203
2221
|
result[key] = values;
|
|
2204
2222
|
}
|
|
2223
|
+
const sourceIssues = Array.isArray(result.issues) ? result.issues : [];
|
|
2224
|
+
const summarizePath = sourceIssues.some((issue) => typeof issue.path === "string");
|
|
2205
2225
|
const counts = () => {
|
|
2206
2226
|
if (!Number.isSafeInteger(omitted) || !Number.isSafeInteger(characters))
|
|
2207
2227
|
throw new Error("Native diagnostic counts exceed schema");
|
|
@@ -2211,6 +2231,13 @@ function nativeFactsFor(policy, input) {
|
|
|
2211
2231
|
result.omittedDiagnosticCharacters = characters;
|
|
2212
2232
|
};
|
|
2213
2233
|
const fits = () => {
|
|
2234
|
+
if (summarizePath) {
|
|
2235
|
+
const path = sourceIssues[0]?.path;
|
|
2236
|
+
if (typeof path === "string" && sourceIssues.every((issue) => issue.path === path))
|
|
2237
|
+
result.path = path;
|
|
2238
|
+
else
|
|
2239
|
+
delete result.path;
|
|
2240
|
+
}
|
|
2214
2241
|
counts();
|
|
2215
2242
|
const base = catalogDefaults[policy.code];
|
|
2216
2243
|
const error = { code: policy.code, message: policy.message, severity: base.severity, retryable: policy.retryable ?? base.retryable, action: policy.action ?? base.action, reasonCode: Object.entries(policies).find(([, p]) => p === policy)?.[0], details: result };
|
|
@@ -2325,12 +2352,21 @@ function normalizeFailureResult(result, stage, requestId = "failure") {
|
|
|
2325
2352
|
return toEnvelope(requestId, undefined, "failure-metadata");
|
|
2326
2353
|
}
|
|
2327
2354
|
}
|
|
2328
|
-
var FAILURE_STAGES, policies, FAILURE_POLICIES, catalogDefaults, actions, bytes = (value) => new TextEncoder().encode(value).byteLength, record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), finiteNonnegative = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0, criticalKey = (key) => /id$|digest|receipt|binding|readback|lookupkey/i.test(key), localEnums, nativeEnums, nativeDiagnosticKinds, FailureError;
|
|
2355
|
+
var FAILURE_STAGES, CODE_FACTS_ISSUE_MESSAGES, policies, FAILURE_POLICIES, catalogDefaults, actions, bytes = (value) => new TextEncoder().encode(value).byteLength, record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), finiteNonnegative = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0, criticalKey = (key) => /id$|digest|receipt|binding|readback|lookupkey/i.test(key), localEnums, nativeEnums, nativeDiagnosticKinds, FailureError;
|
|
2329
2356
|
var init_failure = __esm(() => {
|
|
2330
2357
|
init_changeset_recovery();
|
|
2331
2358
|
init_projection_recovery();
|
|
2332
2359
|
init_schema();
|
|
2333
2360
|
FAILURE_STAGES = Object.freeze(["debt", "complete", "practice-checkpoint", "cli", "mcp", "hook-checkpoint", "failure-metadata", "public-operation", "native-export", "docs-anchors", "flows-check"]);
|
|
2361
|
+
CODE_FACTS_ISSUE_MESSAGES = Object.freeze({
|
|
2362
|
+
"not-initialized": "CodeGraph repository status is not initialized",
|
|
2363
|
+
"version-mismatch": "CodeGraph repository status version mismatch",
|
|
2364
|
+
"project-path-mismatch": "CodeGraph repository project path mismatch",
|
|
2365
|
+
"index-incomplete": "CodeGraph repository index is not complete and compatible",
|
|
2366
|
+
"extraction-version-mismatch": "CodeGraph repository extraction version mismatch",
|
|
2367
|
+
"worktree-mismatch": "CodeGraph repository worktree mismatch",
|
|
2368
|
+
"pending-source-changes": "CodeGraph repository index has pending or unreported source changes"
|
|
2369
|
+
});
|
|
2334
2370
|
policies = {
|
|
2335
2371
|
"git-worktree-required": { code: "AC_REPO_NOT_FOUND", message: "This operation requires a Git worktree.", fields: ["checks"] },
|
|
2336
2372
|
"model-missing": { code: "AC_MODEL_ADOPTION_REQUIRED", message: "Architecture debt requires an adopted model.", fields: ["checks"] },
|
|
@@ -2340,6 +2376,7 @@ var init_failure = __esm(() => {
|
|
|
2340
2376
|
"projection-manifest-invalid": { code: "AC_PRECONDITION_FAILED", message: "The committed projection manifest violates its contract." },
|
|
2341
2377
|
"projection-footprint-uncovered": { code: "AC_PRECONDITION_FAILED", message: "Declared source footprints lack a projection target." },
|
|
2342
2378
|
"index-missing": { code: "AC_CODE_FACTS_UNAVAILABLE", message: "Required code facts have no available index. Run codegraph init." },
|
|
2379
|
+
"code-facts-not-ready": { code: "AC_CODE_FACTS_NOT_READY", message: "Repository code facts are not ready. Run archctx doctor --json and follow the reported action.", facts: { issues: "codeFactsIssues" } },
|
|
2343
2380
|
"checkpoint-input-invalid": { code: "AC_SCHEMA_INVALID", message: "Checkpoint arguments violate the declared input schema.", fields: ["issueCount"], action: "correct-command-arguments" },
|
|
2344
2381
|
"cli-input-invalid": { code: "AC_SCHEMA_INVALID", message: "Command arguments violate the declared input contract.", action: "correct-command-arguments" },
|
|
2345
2382
|
"complete-input-invalid": { code: "AC_SCHEMA_INVALID", message: "Completion input violates the caller authority contract.", action: "correct-command-arguments" },
|
|
@@ -2348,7 +2385,7 @@ var init_failure = __esm(() => {
|
|
|
2348
2385
|
"runtime-version-unsupported": { code: "AC_RUNTIME_VERSION_UNSUPPORTED", message: "The connected runtime version is unsupported." },
|
|
2349
2386
|
"rpc-timeout": { code: "RPC_TIMEOUT", message: "The runtime RPC deadline elapsed without a response; a mutation outcome is unknown.", fields: ["method", "timeoutMs", "elapsedMs", "mutationOutcome"], action: "reconcile-before-retry" },
|
|
2350
2387
|
"rpc-aborted": { code: "RPC_ABORTED", message: "The runtime RPC caller aborted without a response; a mutation outcome is unknown.", fields: ["method", "timeoutMs", "elapsedMs", "mutationOutcome"], action: "reconcile-before-retry" },
|
|
2351
|
-
"failure-unclassified": { code: "AC_UNCLASSIFIED_FAILURE", message: "The operation failed without a classified cause.
|
|
2388
|
+
"failure-unclassified": { code: "AC_UNCLASSIFIED_FAILURE", message: "The operation failed without a classified cause. Run archctx doctor --json before retrying.", action: "inspect-diagnostics" }
|
|
2352
2389
|
};
|
|
2353
2390
|
Object.assign(policies, {
|
|
2354
2391
|
"developer-review-run-not-owned": { code: "AC_PRECONDITION_FAILED", message: "developer-review-run-not-owned", facts: { refusal: "reviewOwnershipRefusal" } },
|
|
@@ -2585,7 +2622,7 @@ var init_failure = __esm(() => {
|
|
|
2585
2622
|
}
|
|
2586
2623
|
FAILURE_POLICIES = Object.freeze(policies);
|
|
2587
2624
|
catalogDefaults = Object.fromEntries(Object.entries(ERROR_CATALOG).map(([code, value]) => [code, Object.freeze({ severity: value.severity, retryable: value.retryable, action: value.action })]));
|
|
2588
|
-
actions = new Set([...Object.values(catalogDefaults).map((value) => value.action), "correct-command-arguments", "inspect-diagnostics", "reconcile-before-retry", ...Object.values(policies).flatMap((policy) => policy.action ? [policy.action] : [])]);
|
|
2625
|
+
actions = new Set([...Object.values(catalogDefaults).map((value) => value.action), "correct-command-arguments", "inspect-diagnostics", "reconcile-before-retry", "install-compatible-codegraph", ...Object.values(policies).flatMap((policy) => policy.action ? [policy.action] : [])]);
|
|
2589
2626
|
localEnums = {
|
|
2590
2627
|
reviewWorktreeRefusal: ["UNKNOWN", "HEAD_UNAVAILABLE", "HEAD_SHA_MISMATCH", "TREE_OID_MISMATCH", "WORKTREE_NOT_DETACHED", "WORKTREE_NOT_CLEAN"],
|
|
2591
2628
|
reviewOwnershipRefusal: ["persisted-manifest-missing", "persisted-manifest-identity-mismatch", "run-id", "manifest-path", "lock-path", "persisted-manifest-mismatch", "persisted-lock-mismatch", "run-root-name", "worktree-temp-root", "codegraph-temporary-state-root", "run-root-not-a-directory", "run-root-owner-marker-missing", "run-root-owner-marker-mismatch", "worktree-temporary-root", "worktree-root", "worktree-source-root"],
|
|
@@ -2992,9 +3029,13 @@ function nativeAllowedNodeKinds(schemas) {
|
|
|
2992
3029
|
throw new Error("canonical-node-kind-enum-unavailable");
|
|
2993
3030
|
return [...kinds];
|
|
2994
3031
|
}
|
|
2995
|
-
function nativeContextModelIssues(model, schemas) {
|
|
3032
|
+
function nativeContextModelIssues(model, schemas, recordPaths) {
|
|
2996
3033
|
const issues = [];
|
|
2997
|
-
const add = (
|
|
3034
|
+
const add = (record, field, invariant) => {
|
|
3035
|
+
const entityId = typeof record === "string" ? record : typeof record.id === "string" ? record.id : "(undeclared)";
|
|
3036
|
+
const path = typeof record === "string" ? undefined : recordPaths?.get(record);
|
|
3037
|
+
issues.push({ entityId, field, invariant, ...path === undefined ? {} : { path } });
|
|
3038
|
+
};
|
|
2998
3039
|
const resolveSchema = nativeContextSchemaResolver(schemas);
|
|
2999
3040
|
const ids = new Set;
|
|
3000
3041
|
for (const [kind, records] of [["node", model.nodes], ["relation", model.relations], ["flow", model.flows]]) {
|
|
@@ -3013,14 +3054,14 @@ function nativeContextModelIssues(model, schemas) {
|
|
|
3013
3054
|
continue;
|
|
3014
3055
|
}
|
|
3015
3056
|
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
3016
|
-
add(
|
|
3057
|
+
add(record, item.field, "non-json-number");
|
|
3017
3058
|
jsonInvalid = true;
|
|
3018
3059
|
break;
|
|
3019
3060
|
}
|
|
3020
3061
|
if (value === null || typeof value !== "object")
|
|
3021
3062
|
continue;
|
|
3022
3063
|
if (active.has(value)) {
|
|
3023
|
-
add(
|
|
3064
|
+
add(record, item.field, "non-json-cycle");
|
|
3024
3065
|
jsonInvalid = true;
|
|
3025
3066
|
break;
|
|
3026
3067
|
}
|
|
@@ -3028,7 +3069,7 @@ function nativeContextModelIssues(model, schemas) {
|
|
|
3028
3069
|
continue;
|
|
3029
3070
|
const prototype = Object.getPrototypeOf(value);
|
|
3030
3071
|
if (Array.isArray(value) ? prototype !== Array.prototype : prototype !== Object.prototype) {
|
|
3031
|
-
add(
|
|
3072
|
+
add(record, item.field, "non-json-prototype");
|
|
3032
3073
|
jsonInvalid = true;
|
|
3033
3074
|
break;
|
|
3034
3075
|
}
|
|
@@ -3041,36 +3082,35 @@ function nativeContextModelIssues(model, schemas) {
|
|
|
3041
3082
|
continue;
|
|
3042
3083
|
const schema = kind === "node" ? schemas.node : kind === "relation" ? schemas.relation : schemas.flow;
|
|
3043
3084
|
for (const issue of validateJsonSchema(schema, record, { resolveSchema }).issues)
|
|
3044
|
-
add(
|
|
3085
|
+
add(record, issue.path, issue.message);
|
|
3045
3086
|
if (ids.has(id))
|
|
3046
|
-
add(
|
|
3087
|
+
add(record, "id", "duplicate-entity-id");
|
|
3047
3088
|
ids.add(id);
|
|
3048
3089
|
}
|
|
3049
3090
|
}
|
|
3050
3091
|
if (issues.length > 0)
|
|
3051
3092
|
return issues;
|
|
3052
3093
|
for (const kind of ["nodes", "relations", "flows"]) {
|
|
3053
|
-
const expected = new
|
|
3054
|
-
for (const id of expected)
|
|
3094
|
+
const expected = new Map(model[kind].map((entity) => [entity.id, entity]));
|
|
3095
|
+
for (const [id, entity] of expected)
|
|
3055
3096
|
if (!Object.hasOwn(model.sourcePaths[kind], id))
|
|
3056
|
-
add(
|
|
3097
|
+
add(entity, `sourcePaths.${kind}`, "source-path-index-incomplete");
|
|
3057
3098
|
for (const [id, path] of Object.entries(model.sourcePaths[kind])) {
|
|
3058
3099
|
if (!expected.has(id))
|
|
3059
3100
|
add(id, `sourcePaths.${kind}`, "source-path-index-unknown-entity");
|
|
3060
3101
|
if (!isNativeContextPath(path))
|
|
3061
|
-
add(id, `sourcePaths.${kind}`, "path-unsafe");
|
|
3102
|
+
add(expected.get(id) ?? id, `sourcePaths.${kind}`, "path-unsafe");
|
|
3062
3103
|
}
|
|
3063
3104
|
}
|
|
3064
3105
|
const nodes = new Map(model.nodes.map((node) => [node.id, node]));
|
|
3065
3106
|
const checked = new Set;
|
|
3066
3107
|
for (const node of model.nodes) {
|
|
3067
|
-
const id = node.id;
|
|
3068
3108
|
const chain = new Set;
|
|
3069
3109
|
let cursor = node;
|
|
3070
3110
|
while (cursor) {
|
|
3071
3111
|
const current = cursor.id;
|
|
3072
3112
|
if (chain.has(current)) {
|
|
3073
|
-
add(
|
|
3113
|
+
add(node, "parent", "parent-cycle");
|
|
3074
3114
|
break;
|
|
3075
3115
|
}
|
|
3076
3116
|
if (checked.has(current))
|
|
@@ -3080,7 +3120,7 @@ function nativeContextModelIssues(model, schemas) {
|
|
|
3080
3120
|
break;
|
|
3081
3121
|
const parent = nodes.get(cursor.parent);
|
|
3082
3122
|
if (!parent) {
|
|
3083
|
-
add(
|
|
3123
|
+
add(cursor, "parent", "parent-node-missing");
|
|
3084
3124
|
break;
|
|
3085
3125
|
}
|
|
3086
3126
|
cursor = parent;
|
|
@@ -3093,17 +3133,17 @@ function nativeContextModelIssues(model, schemas) {
|
|
|
3093
3133
|
const source = node.source;
|
|
3094
3134
|
for (const path of [...source?.include ?? [], ...source?.exclude ?? []])
|
|
3095
3135
|
if (!isNativeContextPath(path))
|
|
3096
|
-
add(node
|
|
3136
|
+
add(node, "source", "path-unsafe");
|
|
3097
3137
|
for (const entry of source?.entrypoints ?? []) {
|
|
3098
3138
|
if (!isNativeContextPath(entry.path))
|
|
3099
|
-
add(node
|
|
3139
|
+
add(node, "source.entrypoints.path", "path-unsafe");
|
|
3100
3140
|
for (const symbol of entry.symbols) {
|
|
3101
3141
|
for (const sink of symbol.sinks) {
|
|
3102
3142
|
if (!isNativeContextPath(sink.path))
|
|
3103
|
-
add(node
|
|
3143
|
+
add(node, "source.entrypoints.symbols.sinks.path", "path-unsafe");
|
|
3104
3144
|
const selector = JSON.stringify([entry.id, symbol.name, sink.id]);
|
|
3105
3145
|
if (selectors.has(selector))
|
|
3106
|
-
add(node
|
|
3146
|
+
add(node, "source.entrypoints.symbols.sinks.id", "selector-ambiguous");
|
|
3107
3147
|
selectors.add(selector);
|
|
3108
3148
|
}
|
|
3109
3149
|
}
|
|
@@ -3112,43 +3152,42 @@ function nativeContextModelIssues(model, schemas) {
|
|
|
3112
3152
|
for (const relation of model.relations) {
|
|
3113
3153
|
for (const field of ["source", "target", "via"])
|
|
3114
3154
|
if (relation[field] !== undefined && !nodes.has(relation[field]))
|
|
3115
|
-
add(relation
|
|
3155
|
+
add(relation, field, "relation-node-missing");
|
|
3116
3156
|
}
|
|
3117
3157
|
for (const flow of model.flows) {
|
|
3118
|
-
const id = flow.id;
|
|
3119
3158
|
if (nodes.get(flow.capabilityId)?.kind !== "capability")
|
|
3120
|
-
add(
|
|
3159
|
+
add(flow, "capabilityId", "flow-capability-missing");
|
|
3121
3160
|
if (flow.applicability !== "required")
|
|
3122
3161
|
continue;
|
|
3123
3162
|
const participants = flow.participants;
|
|
3124
3163
|
const participantIds = new Set;
|
|
3125
3164
|
for (const participant of participants) {
|
|
3126
3165
|
if (participantIds.has(participant.id))
|
|
3127
|
-
add(
|
|
3166
|
+
add(flow, "participants.id", "participant-id-ambiguous");
|
|
3128
3167
|
participantIds.add(participant.id);
|
|
3129
3168
|
if (!nodes.has(participant.nodeId))
|
|
3130
|
-
add(
|
|
3169
|
+
add(flow, "participants.nodeId", "participant-node-missing");
|
|
3131
3170
|
}
|
|
3132
3171
|
const definitions = new Map;
|
|
3133
3172
|
const outcomes = flow.outcomes;
|
|
3134
3173
|
const outcomeIds = new Set;
|
|
3135
3174
|
for (const outcome of outcomes) {
|
|
3136
3175
|
if (outcomeIds.has(outcome.id))
|
|
3137
|
-
add(
|
|
3176
|
+
add(flow, "outcomes.id", "outcome-id-ambiguous");
|
|
3138
3177
|
outcomeIds.add(outcome.id);
|
|
3139
3178
|
if (!participantIds.has(outcome.terminal.participant))
|
|
3140
|
-
add(
|
|
3179
|
+
add(flow, "outcomes.terminal", "terminal-participant-missing");
|
|
3141
3180
|
}
|
|
3142
3181
|
for (const step of [...flow.steps, ...outcomes.flatMap((outcome) => outcome.steps)]) {
|
|
3143
3182
|
if (!participantIds.has(step.from) || !participantIds.has(step.to))
|
|
3144
|
-
add(
|
|
3183
|
+
add(flow, "steps", "step-participant-missing");
|
|
3145
3184
|
const definition = canonicalize(step);
|
|
3146
3185
|
if (definitions.has(step.id) && definitions.get(step.id) !== definition)
|
|
3147
|
-
add(
|
|
3186
|
+
add(flow, "steps.id", "step-definition-ambiguous");
|
|
3148
3187
|
definitions.set(step.id, definition);
|
|
3149
3188
|
const selector = step.evidence;
|
|
3150
3189
|
if (!selectors.has(JSON.stringify([selector.entrypointId, selector.sourceSymbol, selector.sinkId])))
|
|
3151
|
-
add(
|
|
3190
|
+
add(flow, "steps.evidence", "selector-missing");
|
|
3152
3191
|
}
|
|
3153
3192
|
}
|
|
3154
3193
|
return issues;
|
|
@@ -3828,7 +3867,7 @@ function compareVersionTriples(left, right) {
|
|
|
3828
3867
|
}
|
|
3829
3868
|
return 0;
|
|
3830
3869
|
}
|
|
3831
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.8.
|
|
3870
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.8.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";
|
|
3832
3871
|
|
|
3833
3872
|
// packages/contracts/src/refactor.ts
|
|
3834
3873
|
function refactorNamespaceIssues(value, label = "product.id") {
|
|
@@ -15748,10 +15787,10 @@ function sourceIncludeAnchors(patterns) {
|
|
|
15748
15787
|
init_src();
|
|
15749
15788
|
|
|
15750
15789
|
// packages/core/architecture-domain/src/index.ts
|
|
15751
|
-
init_src();
|
|
15752
15790
|
import { createHash as createHash2 } from "node:crypto";
|
|
15753
15791
|
import { readFileSync, realpathSync, statSync } from "node:fs";
|
|
15754
15792
|
import { resolve } from "node:path";
|
|
15793
|
+
init_src();
|
|
15755
15794
|
var LANDSCAPE_FILE = ".archcontext/landscape.yaml";
|
|
15756
15795
|
var ADAPTER_PROTECTED_NATIVE_FIELDS = ["evidence", "verification", "constraint", "intervention"];
|
|
15757
15796
|
var DEFAULT_IGNORES = new Set([
|
|
@@ -15980,7 +16019,7 @@ function parseJsonOrStableYaml(body, path) {
|
|
|
15980
16019
|
if (!trimmed)
|
|
15981
16020
|
throw new Error(`${path}: empty model file`);
|
|
15982
16021
|
if (trimmed.startsWith("{") || trimmed.startsWith("["))
|
|
15983
|
-
return
|
|
16022
|
+
return checkedJsonOrFlowYaml(trimmed, path, "json-document");
|
|
15984
16023
|
return new StableYamlParser(body, path).parse();
|
|
15985
16024
|
}
|
|
15986
16025
|
var ADR_FILE_PATH = /^docs\/adr\/ADR-\d{4}-.+\.md$/;
|
|
@@ -16361,7 +16400,7 @@ function parseScalar(value, path) {
|
|
|
16361
16400
|
if (/^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/.test(value))
|
|
16362
16401
|
return Number(value);
|
|
16363
16402
|
if (/^["[{]/.test(value))
|
|
16364
|
-
return
|
|
16403
|
+
return checkedJsonOrFlowYaml(value, path, "json-scalar");
|
|
16365
16404
|
return value;
|
|
16366
16405
|
}
|
|
16367
16406
|
|
|
@@ -16379,6 +16418,54 @@ class DuplicateModelKeyError extends Error {
|
|
|
16379
16418
|
this.name = "DuplicateModelKeyError";
|
|
16380
16419
|
}
|
|
16381
16420
|
}
|
|
16421
|
+
function checkedJsonOrFlowYaml(source, path, branch) {
|
|
16422
|
+
try {
|
|
16423
|
+
return checkedJsonDecode(source, path, branch);
|
|
16424
|
+
} catch (error) {
|
|
16425
|
+
if (!(error instanceof SyntaxError) || !(source.startsWith("{") || source.startsWith("[")))
|
|
16426
|
+
throw error;
|
|
16427
|
+
}
|
|
16428
|
+
return checkedFlowYamlDecode(source, path);
|
|
16429
|
+
}
|
|
16430
|
+
function checkedFlowYamlDecode(source, path) {
|
|
16431
|
+
const document = $parseDocument(source, { version: "1.2", schema: "core", uniqueKeys: false, prettyErrors: false });
|
|
16432
|
+
const invalid = (reason) => {
|
|
16433
|
+
throw new SyntaxError(`${path}: invalid YAML flow collection (${reason})`);
|
|
16434
|
+
};
|
|
16435
|
+
if (document.errors.length || document.warnings.length)
|
|
16436
|
+
invalid("parse error or warning");
|
|
16437
|
+
if (!$isMap(document.contents) && !$isSeq(document.contents) || !document.contents.flow)
|
|
16438
|
+
invalid("expected flow collection");
|
|
16439
|
+
const decode = (node) => {
|
|
16440
|
+
if (node === null)
|
|
16441
|
+
return null;
|
|
16442
|
+
if (!$isScalar(node) && !$isMap(node) && !$isSeq(node))
|
|
16443
|
+
return invalid("unsupported node or alias");
|
|
16444
|
+
if (node.anchor || node.tag)
|
|
16445
|
+
return invalid("anchor or explicit tag");
|
|
16446
|
+
if ($isScalar(node)) {
|
|
16447
|
+
const value = node.value;
|
|
16448
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
16449
|
+
return value;
|
|
16450
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
16451
|
+
return value;
|
|
16452
|
+
return invalid("non-JSON scalar");
|
|
16453
|
+
}
|
|
16454
|
+
if ($isSeq(node))
|
|
16455
|
+
return node.items.map(decode);
|
|
16456
|
+
const keys = new Set;
|
|
16457
|
+
return Object.fromEntries(node.items.map((pair) => {
|
|
16458
|
+
if (!$isScalar(pair.key))
|
|
16459
|
+
return invalid("non-scalar key");
|
|
16460
|
+
const key = String(decode(pair.key));
|
|
16461
|
+
if (keys.has(key))
|
|
16462
|
+
throw new DuplicateModelKeyError(path, "yaml-flow", key, pair.key.range[0]);
|
|
16463
|
+
keys.add(key);
|
|
16464
|
+
return [key, decode(pair.value)];
|
|
16465
|
+
}));
|
|
16466
|
+
};
|
|
16467
|
+
return decode(document.contents);
|
|
16468
|
+
}
|
|
16382
16469
|
function checkedJsonDecode(source, path, branch) {
|
|
16383
16470
|
let offset = 0;
|
|
16384
16471
|
const whitespace = () => {
|
|
@@ -16968,6 +17055,12 @@ function renderAdrReferenceUpdate(body, references) {
|
|
|
16968
17055
|
return rendered;
|
|
16969
17056
|
}
|
|
16970
17057
|
// packages/core/changeset-engine/src/index.ts
|
|
17058
|
+
function changeSetBaseModelBlockingErrors(result, draft) {
|
|
17059
|
+
const repairedPaths = new Set(draft.operations.filter((operation) => operation.op === "update_entity_fields" || operation.op === "delete_entity").map((operation) => operation.path));
|
|
17060
|
+
const repairedErrors = new Set((result.nodeSchemaErrors ?? []).filter((issue) => repairedPaths.has(issue.path)).map((issue) => issue.error));
|
|
17061
|
+
return baseModelBlockingErrors(result).filter((error) => !repairedErrors.has(error));
|
|
17062
|
+
}
|
|
17063
|
+
|
|
16971
17064
|
class ChangeSetEngine {
|
|
16972
17065
|
deps;
|
|
16973
17066
|
states = new Map;
|
|
@@ -17190,10 +17283,16 @@ class ChangeSetEngine {
|
|
|
17190
17283
|
}
|
|
17191
17284
|
async validateModel(root, draft, deps, phase) {
|
|
17192
17285
|
const result = await deps.modelStore.validateModel({ root, repositoryId: draft.reason.taskSessionId, headSha: draft.base.headSha });
|
|
17193
|
-
const
|
|
17286
|
+
const errors = phase === "before" ? changeSetBaseModelBlockingErrors(result, draft) : result.errors;
|
|
17287
|
+
const blocked = phase === "before" ? errors.length > 0 : !result.valid;
|
|
17194
17288
|
if (blocked) {
|
|
17195
|
-
const
|
|
17196
|
-
|
|
17289
|
+
const path = errors[0]?.match(/^(\.archcontext\/.+?): /)?.[1];
|
|
17290
|
+
const error = new FailureError("AC_SCHEMA_INVALID", "native-context-model-invalid", {
|
|
17291
|
+
invariant: `model-validation-${phase}-apply`,
|
|
17292
|
+
...path ? { path } : {}
|
|
17293
|
+
});
|
|
17294
|
+
error.message = `ChangeSet model validation failed ${phase} apply: ${errors.join("; ") || "unknown validation error"}`;
|
|
17295
|
+
throw error;
|
|
17197
17296
|
}
|
|
17198
17297
|
}
|
|
17199
17298
|
requireDeps() {
|
|
@@ -22897,9 +22996,6 @@ function isGitWorktreeError(error) {
|
|
|
22897
22996
|
return error instanceof Error && /git|Command failed/.test(error.message);
|
|
22898
22997
|
}
|
|
22899
22998
|
|
|
22900
|
-
// packages/local-runtime/runtime-daemon/src/producer-failure.ts
|
|
22901
|
-
init_src();
|
|
22902
|
-
|
|
22903
22999
|
// packages/local-runtime/egress-admission/src/index.ts
|
|
22904
23000
|
var LOCAL_EGRESS_MODE_ENV2 = "ARCHCONTEXT_EGRESS_MODE";
|
|
22905
23001
|
var LOCAL_EGRESS_CHANNELS2 = ["context7", "agent-audit", "github-issue-publishing", "npm-update-check", "codegraph-telemetry"];
|
|
@@ -22931,6 +23027,7 @@ function withLocalEgress2(channel, operation, env = process.env) {
|
|
|
22931
23027
|
}
|
|
22932
23028
|
|
|
22933
23029
|
// packages/local-runtime/codegraph-adapter/src/index.ts
|
|
23030
|
+
init_src();
|
|
22934
23031
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
22935
23032
|
import { createHash as createHash5 } from "node:crypto";
|
|
22936
23033
|
import { accessSync, closeSync as closeSync3, constants as fsConstants2, existsSync as existsSync6, openSync as openSync3, readFileSync as readFileSync7, readSync, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
@@ -23932,10 +24029,15 @@ class CodeGraphCliProvider {
|
|
|
23932
24029
|
}
|
|
23933
24030
|
async indexAll(workspaceRoot) {
|
|
23934
24031
|
this.workspaceRoot = workspaceRoot;
|
|
23935
|
-
|
|
23936
|
-
throw new Error(`CodeGraph index missing at ${workspaceRoot}; run codegraph init before using archctxd`);
|
|
23937
|
-
}
|
|
24032
|
+
this.assertCanSync(workspaceRoot);
|
|
23938
24033
|
this.run(["sync", workspaceRoot]);
|
|
24034
|
+
this.assertReady(workspaceRoot);
|
|
24035
|
+
}
|
|
24036
|
+
assertReady(workspaceRoot) {
|
|
24037
|
+
assertRepositoryCodeFactsReady(workspaceRoot, this.binary === DEFAULT_CODEGRAPH_BINARY ? {} : { binary: this.binary });
|
|
24038
|
+
}
|
|
24039
|
+
assertCanSync(workspaceRoot) {
|
|
24040
|
+
this.assertReady(workspaceRoot);
|
|
23939
24041
|
}
|
|
23940
24042
|
async buildContext(task, options) {
|
|
23941
24043
|
const query = scopedTaskQuery(task, options.changedPaths ?? []);
|
|
@@ -23998,7 +24100,7 @@ class CodeGraphCliProvider {
|
|
|
23998
24100
|
}
|
|
23999
24101
|
run(args) {
|
|
24000
24102
|
disableCodeGraphTelemetryByDefault();
|
|
24001
|
-
const invocation = codeGraphCliInvocation(this.binary, this.workspaceRoot);
|
|
24103
|
+
const invocation = this.binary === DEFAULT_CODEGRAPH_BINARY ? packagedCodeGraphCliInvocation() : codeGraphCliInvocation(this.binary, this.workspaceRoot);
|
|
24002
24104
|
try {
|
|
24003
24105
|
return execFileSync2(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
24004
24106
|
cwd: this.workspaceRoot,
|
|
@@ -24129,8 +24231,14 @@ class CodeGraphAdapter {
|
|
|
24129
24231
|
this.provider = provider;
|
|
24130
24232
|
disableCodeGraphTelemetryByDefault();
|
|
24131
24233
|
}
|
|
24234
|
+
assertCanSync(workspaceRoot) {
|
|
24235
|
+
this.assertCompatible();
|
|
24236
|
+
this.provider.assertCanSync?.(workspaceRoot);
|
|
24237
|
+
}
|
|
24132
24238
|
async ensureReady(workspace) {
|
|
24133
24239
|
this.assertCompatible();
|
|
24240
|
+
if (this.#snapshot)
|
|
24241
|
+
this.provider.assertReady?.(workspace.root);
|
|
24134
24242
|
this.#snapshot ??= await this.sync({ workspace });
|
|
24135
24243
|
return this.#snapshot;
|
|
24136
24244
|
}
|
|
@@ -24594,7 +24702,7 @@ function readProjectionHeadSha(root) {
|
|
|
24594
24702
|
function projectionCodeGraphStatusIssues(status, root, phase) {
|
|
24595
24703
|
const issue = (code, text) => ({
|
|
24596
24704
|
code,
|
|
24597
|
-
message: `CodeGraph ${phase} ${text}`
|
|
24705
|
+
message: phase === "repository" ? CODE_FACTS_ISSUE_MESSAGES[code] : `CodeGraph ${phase} ${text}`
|
|
24598
24706
|
});
|
|
24599
24707
|
if (!status.initialized)
|
|
24600
24708
|
return [issue("not-initialized", "status is not initialized")];
|
|
@@ -24703,7 +24811,7 @@ function inspectRepositoryCodeFacts(root, options = {}) {
|
|
|
24703
24811
|
message: (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim().slice(0, 400)
|
|
24704
24812
|
};
|
|
24705
24813
|
}
|
|
24706
|
-
const versionIssues = codeGraphVersion === REQUIRED_CODEGRAPH_VERSION ? [] : [{ code: "version-mismatch", message:
|
|
24814
|
+
const versionIssues = codeGraphVersion === REQUIRED_CODEGRAPH_VERSION ? [] : [{ code: "version-mismatch", message: CODE_FACTS_ISSUE_MESSAGES["version-mismatch"] }];
|
|
24707
24815
|
if (!indexPresent) {
|
|
24708
24816
|
return { schemaVersion, state: "index-missing", indexPresent: false, requiredVersion: REQUIRED_CODEGRAPH_VERSION, codeGraphVersion, issues: versionIssues };
|
|
24709
24817
|
}
|
|
@@ -24733,12 +24841,25 @@ function inspectRepositoryCodeFacts(root, options = {}) {
|
|
|
24733
24841
|
current: status.index?.currentExtractionVersion ?? null
|
|
24734
24842
|
},
|
|
24735
24843
|
indexState: status.index?.state ?? null,
|
|
24736
|
-
reindexRecommended:
|
|
24844
|
+
reindexRecommended: issues.some((issue) => issue.code !== "pending-source-changes"),
|
|
24737
24845
|
pendingRefs: status.index?.pendingRefs ?? null,
|
|
24738
24846
|
pendingChanges: pending ? { added: pending.added, modified: pending.modified, removed: pending.removed } : null,
|
|
24739
24847
|
issues
|
|
24740
24848
|
};
|
|
24741
24849
|
}
|
|
24850
|
+
function assertRepositoryCodeFactsReady(root, options = {}) {
|
|
24851
|
+
const facts = inspectRepositoryCodeFacts(root, options);
|
|
24852
|
+
if (facts.state === "index-missing")
|
|
24853
|
+
throw new ProjectionCodeFactsUnavailableError("index-missing");
|
|
24854
|
+
if (facts.state === "unavailable")
|
|
24855
|
+
throw new FailureError("AC_CODE_FACTS_UNAVAILABLE", "code-facts-unavailable", {}, { action: "inspect-diagnostics", retryable: false });
|
|
24856
|
+
if (facts.state === "not-ready") {
|
|
24857
|
+
if (facts.issues.every((issue) => issue.code === "pending-source-changes"))
|
|
24858
|
+
return;
|
|
24859
|
+
const action = facts.codeGraphVersion !== REQUIRED_CODEGRAPH_VERSION ? "install-compatible-codegraph" : "codegraph-index";
|
|
24860
|
+
throw new FailureError("AC_CODE_FACTS_NOT_READY", "code-facts-not-ready", { issues: facts.issues }, { action });
|
|
24861
|
+
}
|
|
24862
|
+
}
|
|
24742
24863
|
function codeGraphIndexAvailable(workspaceRoot) {
|
|
24743
24864
|
return existsSync6(join3(workspaceRoot, ".codegraph"));
|
|
24744
24865
|
}
|
|
@@ -25061,6 +25182,7 @@ function parseExploreSymbols(output, maxSymbols) {
|
|
|
25061
25182
|
}
|
|
25062
25183
|
|
|
25063
25184
|
// packages/local-runtime/runtime-daemon/src/producer-failure.ts
|
|
25185
|
+
init_src();
|
|
25064
25186
|
function selectedProducerData(error, key) {
|
|
25065
25187
|
const descriptor = Object.getOwnPropertyDescriptor(error, key);
|
|
25066
25188
|
if (!descriptor || !("value" in descriptor))
|
|
@@ -26151,12 +26273,6 @@ function isPresent2(value) {
|
|
|
26151
26273
|
init_src();
|
|
26152
26274
|
import { existsSync as existsSync7, lstatSync as lstatSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync8, rmSync as rmSync4 } from "node:fs";
|
|
26153
26275
|
import { dirname as dirname5, resolve as resolve11 } from "node:path";
|
|
26154
|
-
|
|
26155
|
-
// packages/local-runtime/model-store-yaml/src/native-context.ts
|
|
26156
|
-
init_src();
|
|
26157
|
-
import { createHash as createHash6 } from "node:crypto";
|
|
26158
|
-
import { constants, closeSync as closeSync4, fstatSync as fstatSync2, lstatSync as lstatSync4, openSync as openSync4, readSync as readSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
26159
|
-
import { join as join4, resolve as resolve10 } from "node:path";
|
|
26160
26276
|
// schemas/repo/architecture-node.schema.json
|
|
26161
26277
|
var architecture_node_schema_default = {
|
|
26162
26278
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -26245,6 +26361,12 @@ var architecture_node_schema_default = {
|
|
|
26245
26361
|
extensions: { type: "object", additionalProperties: true }
|
|
26246
26362
|
}
|
|
26247
26363
|
};
|
|
26364
|
+
|
|
26365
|
+
// packages/local-runtime/model-store-yaml/src/native-context.ts
|
|
26366
|
+
init_src();
|
|
26367
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
26368
|
+
import { constants, closeSync as closeSync4, fstatSync as fstatSync2, lstatSync as lstatSync4, openSync as openSync4, readSync as readSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
26369
|
+
import { join as join4, resolve as resolve10 } from "node:path";
|
|
26248
26370
|
// schemas/repo/architecture-relation.schema.json
|
|
26249
26371
|
var architecture_relation_schema_default = {
|
|
26250
26372
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -26751,6 +26873,7 @@ function capture(source, snapshot) {
|
|
|
26751
26873
|
if (typeof budget !== "number" || !Number.isSafeInteger(budget) || budget <= 0)
|
|
26752
26874
|
throw new NativeContextError("native-context-budget-invalid", { path: MANIFEST, field: "runtime.contextBudgetBytes" });
|
|
26753
26875
|
const model = { nodes: [], relations: [], flows: [], sourcePaths: { nodes: {}, relations: {}, flows: {} } };
|
|
26876
|
+
const recordPaths = new Map;
|
|
26754
26877
|
for (const spec of specs)
|
|
26755
26878
|
if (spec.role !== "manifest") {
|
|
26756
26879
|
const value = record5(parseInput(source, spec.path));
|
|
@@ -26758,10 +26881,11 @@ function capture(source, snapshot) {
|
|
|
26758
26881
|
throw new NativeContextError("native-context-model-invalid", { path: spec.path, invariant: "entity-object-required" });
|
|
26759
26882
|
const kind = spec.role === "node" ? "nodes" : spec.role === "relation" ? "relations" : "flows";
|
|
26760
26883
|
model[kind].push(value);
|
|
26884
|
+
recordPaths.set(value, spec.path);
|
|
26761
26885
|
if (typeof value.id === "string")
|
|
26762
26886
|
model.sourcePaths[kind][value.id] = spec.path;
|
|
26763
26887
|
}
|
|
26764
|
-
const issues = nativeContextModelIssues(model, SCHEMAS);
|
|
26888
|
+
const issues = nativeContextModelIssues(model, SCHEMAS, recordPaths);
|
|
26765
26889
|
if (issues.length > 0)
|
|
26766
26890
|
throw new NativeContextError(issues.some((issue) => issue.invariant === "path-unsafe") ? "native-context-path-unsafe" : "native-context-model-invalid", { issues: issues.slice(0, 32), omittedDiagnosticCount: Math.max(0, issues.length - 32) });
|
|
26767
26891
|
for (const kind of MODEL_KINDS)
|
|
@@ -27100,6 +27224,7 @@ class YamlModelStore {
|
|
|
27100
27224
|
}
|
|
27101
27225
|
async validateModel(workspace) {
|
|
27102
27226
|
const errors = [];
|
|
27227
|
+
const nodeSchemaErrors = [];
|
|
27103
27228
|
for (const required of [".archcontext/manifest.yaml", ".archcontext/product.yaml"]) {
|
|
27104
27229
|
try {
|
|
27105
27230
|
readFileSync8(resolve11(workspace.root, required), "utf8");
|
|
@@ -27109,11 +27234,25 @@ class YamlModelStore {
|
|
|
27109
27234
|
}
|
|
27110
27235
|
const files = listModelFiles(workspace.root);
|
|
27111
27236
|
for (const file of files) {
|
|
27237
|
+
if (file.path.startsWith(".archcontext/model/") && /\.ya?ml$/.test(file.path)) {
|
|
27238
|
+
try {
|
|
27239
|
+
const value = parseJsonOrStableYaml(file.body, file.path);
|
|
27240
|
+
if (file.path.startsWith(".archcontext/model/nodes/")) {
|
|
27241
|
+
const { issues } = validateJsonSchema(architecture_node_schema_default, value);
|
|
27242
|
+
for (const issue of issues) {
|
|
27243
|
+
const error = `${file.path}: ${issue.path}: ${issue.message}`;
|
|
27244
|
+
errors.push(error);
|
|
27245
|
+
nodeSchemaErrors.push({ path: file.path, error });
|
|
27246
|
+
}
|
|
27247
|
+
continue;
|
|
27248
|
+
}
|
|
27249
|
+
} catch (error) {
|
|
27250
|
+
errors.push(`${file.path}: invalid model YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
27251
|
+
continue;
|
|
27252
|
+
}
|
|
27253
|
+
}
|
|
27112
27254
|
if (!file.schemaVersion.startsWith("archcontext."))
|
|
27113
27255
|
errors.push(`${file.path}: missing schemaVersion`);
|
|
27114
|
-
if (file.path.startsWith(".archcontext/model/nodes/") && file.schemaVersion !== "archcontext.node/v2") {
|
|
27115
|
-
errors.push(`${file.path}: expected archcontext.node/v2, got ${file.schemaVersion || "missing"}`);
|
|
27116
|
-
}
|
|
27117
27256
|
if (file.path.startsWith(".archcontext/model/flows/") && file.schemaVersion !== "archcontext.flow/v1") {
|
|
27118
27257
|
errors.push(`${file.path}: expected archcontext.flow/v1, got ${file.schemaVersion || "missing"}`);
|
|
27119
27258
|
}
|
|
@@ -27129,6 +27268,7 @@ class YamlModelStore {
|
|
|
27129
27268
|
valid: errors.length === 0,
|
|
27130
27269
|
errors,
|
|
27131
27270
|
...referenceErrors.length > 0 ? { referenceErrors } : {},
|
|
27271
|
+
...nodeSchemaErrors.length > 0 ? { nodeSchemaErrors } : {},
|
|
27132
27272
|
...warnings.length > 0 ? { warnings } : {},
|
|
27133
27273
|
modelDigest
|
|
27134
27274
|
};
|
|
@@ -34042,7 +34182,7 @@ function readArchitectureDebtEvidence(root, input) {
|
|
|
34042
34182
|
capabilityByNodeId
|
|
34043
34183
|
} };
|
|
34044
34184
|
}
|
|
34045
|
-
function runArchitectureDebtCommand(cwd, input = {}) {
|
|
34185
|
+
function runArchitectureDebtCommand(cwd, input = {}, codeFactsOptions = {}) {
|
|
34046
34186
|
let root;
|
|
34047
34187
|
try {
|
|
34048
34188
|
root = findRepositoryRoot(cwd);
|
|
@@ -34050,6 +34190,8 @@ function runArchitectureDebtCommand(cwd, input = {}) {
|
|
|
34050
34190
|
return failureEnvelope("debt", knownFailure("AC_REPO_NOT_FOUND", "git-worktree-required", { checks: ["ownership", "anchors"] }));
|
|
34051
34191
|
}
|
|
34052
34192
|
try {
|
|
34193
|
+
if (codeGraphIndexAvailable(root))
|
|
34194
|
+
assertRepositoryCodeFactsReady(root, codeFactsOptions);
|
|
34053
34195
|
return okEnvelope("debt", readArchitectureDebt(root, input));
|
|
34054
34196
|
} catch (error) {
|
|
34055
34197
|
return selectedProducerFailureEnvelope("debt", error, "debt");
|
|
@@ -34596,10 +34738,10 @@ function assertAllowedArchContextPath2(root, relativePath, scope) {
|
|
|
34596
34738
|
}
|
|
34597
34739
|
|
|
34598
34740
|
// packages/core/architecture-domain/src/index.ts
|
|
34599
|
-
init_src();
|
|
34600
34741
|
import { createHash as createHash9 } from "node:crypto";
|
|
34601
34742
|
import { readFileSync as readFileSync14, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
|
|
34602
34743
|
import { resolve as resolve18 } from "node:path";
|
|
34744
|
+
init_src();
|
|
34603
34745
|
var DEFAULT_IGNORES2 = new Set([
|
|
34604
34746
|
".git",
|
|
34605
34747
|
".codegraph",
|
|
@@ -34818,7 +34960,10 @@ var WINDOWS_CREATE_TIMEOUT_MS = 60000;
|
|
|
34818
34960
|
var WINDOWS_READ_TIMEOUT_MS = 1e4;
|
|
34819
34961
|
var REMOVE_HANDLE_RELEASE_MARGIN_MS = 2000;
|
|
34820
34962
|
var REMOVE_RETRY_DELAY_MS = 25;
|
|
34963
|
+
var WINDOWS_CONTROL_FILE_PHASES = ["script", "input", "parsed", "opened", "verified", "done"];
|
|
34964
|
+
var WINDOWS_CONTROL_FILE_PHASE_MARKER = /^archctx-acl-phase:([a-z]+)\r?$/;
|
|
34821
34965
|
var WINDOWS_CONTROL_FILE_SCRIPT = String.raw`
|
|
34966
|
+
[Console]::Error.WriteLine('archctx-acl-phase:script')
|
|
34822
34967
|
$ErrorActionPreference = 'Stop'
|
|
34823
34968
|
# A pwsh -> Node/Bun -> powershell.exe launch inherits incompatible PS7 module paths.
|
|
34824
34969
|
$env:PSModulePath = "$PSHOME\Modules"
|
|
@@ -34840,7 +34985,10 @@ function Test-PrivateAcl($stream, $sid) {
|
|
|
34840
34985
|
$rule.PropagationFlags -eq [System.Security.AccessControl.PropagationFlags]::None)
|
|
34841
34986
|
}
|
|
34842
34987
|
try {
|
|
34843
|
-
$
|
|
34988
|
+
$text = [Console]::In.ReadToEnd()
|
|
34989
|
+
[Console]::Error.WriteLine('archctx-acl-phase:input')
|
|
34990
|
+
$request = $text | ConvertFrom-Json
|
|
34991
|
+
[Console]::Error.WriteLine('archctx-acl-phase:parsed')
|
|
34844
34992
|
$sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
34845
34993
|
if ($request.operation -eq 'create') {
|
|
34846
34994
|
$acl = New-Object System.Security.AccessControl.FileSecurity
|
|
@@ -34850,18 +34998,24 @@ try {
|
|
|
34850
34998
|
$acl.AddAccessRule($rule)
|
|
34851
34999
|
$stream = New-Object System.IO.FileStream($request.path, [System.IO.FileMode]::CreateNew, [System.Security.AccessControl.FileSystemRights]::FullControl, [System.IO.FileShare]::None, 4096, [System.IO.FileOptions]::None, $acl)
|
|
34852
35000
|
$created = $true
|
|
35001
|
+
[Console]::Error.WriteLine('archctx-acl-phase:opened')
|
|
34853
35002
|
if (-not (Test-PrivateAcl $stream $sid)) { throw 'private ACL readback failed' }
|
|
35003
|
+
[Console]::Error.WriteLine('archctx-acl-phase:verified')
|
|
34854
35004
|
$bytes = [System.Text.Encoding]::UTF8.GetBytes([string]$request.body)
|
|
34855
35005
|
$stream.Write($bytes, 0, $bytes.Length)
|
|
34856
35006
|
$stream.Flush($true)
|
|
35007
|
+
[Console]::Error.WriteLine('archctx-acl-phase:done')
|
|
34857
35008
|
$result = @{ ok = $true }
|
|
34858
35009
|
} elseif ($request.operation -eq 'read') {
|
|
34859
35010
|
# Deny concurrent write/delete, validate the opened file, then read that same handle.
|
|
34860
35011
|
$stream = New-Object System.IO.FileStream($request.path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read)
|
|
35012
|
+
[Console]::Error.WriteLine('archctx-acl-phase:opened')
|
|
34861
35013
|
if (-not (Test-PrivateAcl $stream $sid)) { throw 'private ACL readback failed' }
|
|
35014
|
+
[Console]::Error.WriteLine('archctx-acl-phase:verified')
|
|
34862
35015
|
if ($stream.Length -gt 1048576) { throw 'control file exceeds read budget' }
|
|
34863
35016
|
$reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::UTF8, $true, 4096, $true)
|
|
34864
35017
|
try { $body = $reader.ReadToEnd() } finally { $reader.Dispose() }
|
|
35018
|
+
[Console]::Error.WriteLine('archctx-acl-phase:done')
|
|
34865
35019
|
$result = @{ ok = $true; body = $body }
|
|
34866
35020
|
} else { throw 'unsupported operation' }
|
|
34867
35021
|
[Console]::Out.Write(($result | ConvertTo-Json -Compress))
|
|
@@ -34903,8 +35057,9 @@ function windowsControlFile(operation, path, body) {
|
|
|
34903
35057
|
const code = ["ETIMEDOUT", "ENOENT", "EACCES", "EPERM", "ENOBUFS"].includes(String(failure?.code)) ? String(failure?.code) : "UNKNOWN";
|
|
34904
35058
|
const signal = ["SIGTERM", "SIGKILL", "SIGABRT", "SIGINT"].includes(String(failure?.signal)) ? String(failure?.signal) : null;
|
|
34905
35059
|
const status = typeof failure?.status === "number" && Number.isInteger(failure.status) ? failure.status : null;
|
|
35060
|
+
const phase = lastWindowsControlFilePhase(failure?.stderr);
|
|
34906
35061
|
const elapsedMs = Math.round(performance.now() - startedAt);
|
|
34907
|
-
throw new Error(`Windows native ACL operation failed: ${JSON.stringify({ operation, code, status, signal, elapsedMs })}`);
|
|
35062
|
+
throw new Error(`Windows native ACL operation failed: ${JSON.stringify({ operation, code, status, signal, phase, elapsedMs })}`);
|
|
34908
35063
|
}
|
|
34909
35064
|
const result = JSON.parse(output);
|
|
34910
35065
|
if (!result || typeof result !== "object" || !("ok" in result))
|
|
@@ -34919,6 +35074,18 @@ function windowsControlFile(operation, path, body) {
|
|
|
34919
35074
|
return result.body;
|
|
34920
35075
|
}
|
|
34921
35076
|
}
|
|
35077
|
+
function lastWindowsControlFilePhase(stderr) {
|
|
35078
|
+
let phase = "none";
|
|
35079
|
+
if (typeof stderr !== "string")
|
|
35080
|
+
return phase;
|
|
35081
|
+
for (const line of stderr.split(`
|
|
35082
|
+
`)) {
|
|
35083
|
+
const name = WINDOWS_CONTROL_FILE_PHASE_MARKER.exec(line)?.[1];
|
|
35084
|
+
if (name && WINDOWS_CONTROL_FILE_PHASES.includes(name))
|
|
35085
|
+
phase = name;
|
|
35086
|
+
}
|
|
35087
|
+
return phase;
|
|
35088
|
+
}
|
|
34922
35089
|
function createPrivateControlFile(path, body) {
|
|
34923
35090
|
if (process.platform === "win32") {
|
|
34924
35091
|
windowsControlFile("create", path, body);
|
|
@@ -37988,7 +38155,7 @@ function readArchitectureDebtEvidence2(root, input) {
|
|
|
37988
38155
|
capabilityByNodeId
|
|
37989
38156
|
} };
|
|
37990
38157
|
}
|
|
37991
|
-
function runArchitectureDebtCommand2(cwd, input = {}) {
|
|
38158
|
+
function runArchitectureDebtCommand2(cwd, input = {}, codeFactsOptions = {}) {
|
|
37992
38159
|
let root;
|
|
37993
38160
|
try {
|
|
37994
38161
|
root = findRepositoryRoot(cwd);
|
|
@@ -37996,6 +38163,8 @@ function runArchitectureDebtCommand2(cwd, input = {}) {
|
|
|
37996
38163
|
return failureEnvelope("debt", knownFailure("AC_REPO_NOT_FOUND", "git-worktree-required", { checks: ["ownership", "anchors"] }));
|
|
37997
38164
|
}
|
|
37998
38165
|
try {
|
|
38166
|
+
if (codeGraphIndexAvailable(root))
|
|
38167
|
+
assertRepositoryCodeFactsReady(root, codeFactsOptions);
|
|
37999
38168
|
return okEnvelope("debt", readArchitectureDebt2(root, input));
|
|
38000
38169
|
} catch (error) {
|
|
38001
38170
|
return selectedProducerFailureEnvelope("debt", error, "debt");
|
|
@@ -42988,7 +43157,13 @@ class PracticeCheckpointService {
|
|
|
42988
43157
|
}
|
|
42989
43158
|
async prepareUnchecked(root, task, maxBytes = 12288, maxItems = 12, taskSessionId = "task_runtime") {
|
|
42990
43159
|
this.assertRunning();
|
|
43160
|
+
if (this.codeFacts.assertCanSync) {
|
|
43161
|
+
root = findRepositoryRoot(root);
|
|
43162
|
+
this.codeFacts.assertCanSync(root);
|
|
43163
|
+
}
|
|
42991
43164
|
const session = await this.openSession(root);
|
|
43165
|
+
if (this.codeFacts.assertCanSync)
|
|
43166
|
+
await this.codeFacts.ensureReady(session.workspace);
|
|
42992
43167
|
const result = await prepareTask({
|
|
42993
43168
|
workspace: session.workspace,
|
|
42994
43169
|
task,
|
|
@@ -56409,7 +56584,7 @@ class ChangeSetAuthorityService {
|
|
|
56409
56584
|
if (draft.base.worktreeDigest !== current)
|
|
56410
56585
|
throw new FailureError("AC_PRECONDITION_FAILED", "apply-worktree-changed", { expectedWorktreeDigest: draft.base.worktreeDigest, actualWorktreeDigest: current });
|
|
56411
56586
|
const currentModel = await this.readModelStore.validateModel(session.workspace);
|
|
56412
|
-
const baseErrors =
|
|
56587
|
+
const baseErrors = changeSetBaseModelBlockingErrors(currentModel, draft);
|
|
56413
56588
|
if (baseErrors.length > 0) {
|
|
56414
56589
|
throw new FailureError("AC_PRECONDITION_FAILED", "apply-model-invalid", { issueCount: baseErrors.length });
|
|
56415
56590
|
}
|
|
@@ -57684,6 +57859,10 @@ class ArchctxDaemon {
|
|
|
57684
57859
|
async completeTaskUnchecked(root, input) {
|
|
57685
57860
|
this.assertRunning();
|
|
57686
57861
|
assertNoCallerProvidedAttestationFields(input, "complete-task");
|
|
57862
|
+
if (this.codeFacts.assertCanSync) {
|
|
57863
|
+
root = findRepositoryRoot(root);
|
|
57864
|
+
this.codeFacts.assertCanSync(root);
|
|
57865
|
+
}
|
|
57687
57866
|
const session = await this.openSession(root);
|
|
57688
57867
|
let currentHeadSha = input.headSha;
|
|
57689
57868
|
try {
|
|
@@ -58554,6 +58733,7 @@ function completeTaskProjectionFreshness(root) {
|
|
|
58554
58733
|
}
|
|
58555
58734
|
|
|
58556
58735
|
// packages/local-runtime/codegraph-adapter/src/index.ts
|
|
58736
|
+
init_src();
|
|
58557
58737
|
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
58558
58738
|
import { accessSync as accessSync2, closeSync as closeSync11, constants as fsConstants4, existsSync as existsSync33, openSync as openSync11, readFileSync as readFileSync30, readSync as readSync5, realpathSync as realpathSync12, statSync as statSync10 } from "node:fs";
|
|
58559
58739
|
import { createRequire as createRequire5 } from "node:module";
|
|
@@ -58662,7 +58842,7 @@ function readProjectionCodeGraphStatus2(invocation, root, timeout, envOverrides)
|
|
|
58662
58842
|
function projectionCodeGraphStatusIssues2(status, root, phase) {
|
|
58663
58843
|
const issue = (code, text) => ({
|
|
58664
58844
|
code,
|
|
58665
|
-
message: `CodeGraph ${phase} ${text}`
|
|
58845
|
+
message: phase === "repository" ? CODE_FACTS_ISSUE_MESSAGES[code] : `CodeGraph ${phase} ${text}`
|
|
58666
58846
|
});
|
|
58667
58847
|
if (!status.initialized)
|
|
58668
58848
|
return [issue("not-initialized", "status is not initialized")];
|
|
@@ -58738,7 +58918,7 @@ function inspectRepositoryCodeFacts2(root, options = {}) {
|
|
|
58738
58918
|
message: (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim().slice(0, 400)
|
|
58739
58919
|
};
|
|
58740
58920
|
}
|
|
58741
|
-
const versionIssues = codeGraphVersion === REQUIRED_CODEGRAPH_VERSION2 ? [] : [{ code: "version-mismatch", message:
|
|
58921
|
+
const versionIssues = codeGraphVersion === REQUIRED_CODEGRAPH_VERSION2 ? [] : [{ code: "version-mismatch", message: CODE_FACTS_ISSUE_MESSAGES["version-mismatch"] }];
|
|
58742
58922
|
if (!indexPresent) {
|
|
58743
58923
|
return { schemaVersion, state: "index-missing", indexPresent: false, requiredVersion: REQUIRED_CODEGRAPH_VERSION2, codeGraphVersion, issues: versionIssues };
|
|
58744
58924
|
}
|
|
@@ -58768,7 +58948,7 @@ function inspectRepositoryCodeFacts2(root, options = {}) {
|
|
|
58768
58948
|
current: status.index?.currentExtractionVersion ?? null
|
|
58769
58949
|
},
|
|
58770
58950
|
indexState: status.index?.state ?? null,
|
|
58771
|
-
reindexRecommended:
|
|
58951
|
+
reindexRecommended: issues.some((issue) => issue.code !== "pending-source-changes"),
|
|
58772
58952
|
pendingRefs: status.index?.pendingRefs ?? null,
|
|
58773
58953
|
pendingChanges: pending ? { added: pending.added, modified: pending.modified, removed: pending.removed } : null,
|
|
58774
58954
|
issues
|
|
@@ -59571,6 +59751,95 @@ function isExternalDocumentationResourceUri(uri) {
|
|
|
59571
59751
|
function architectureBookResourceInput(uri) {
|
|
59572
59752
|
return ARCHITECTURE_BOOK_RESOURCES.find((resource) => resource.uri === uri)?.input;
|
|
59573
59753
|
}
|
|
59754
|
+
// schemas/repo/architecture-node.schema.json
|
|
59755
|
+
var architecture_node_schema_default2 = {
|
|
59756
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
59757
|
+
$id: "https://archctx.repoharness.com/schemas/repo/architecture-node.schema.json",
|
|
59758
|
+
title: "ArchitectureNode",
|
|
59759
|
+
type: "object",
|
|
59760
|
+
additionalProperties: false,
|
|
59761
|
+
required: ["schemaVersion", "id", "kind", "name", "status", "summary"],
|
|
59762
|
+
properties: {
|
|
59763
|
+
schemaVersion: { const: "archcontext.node/v2" },
|
|
59764
|
+
id: { type: "string", pattern: "^([a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)*::)?[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
59765
|
+
kind: {
|
|
59766
|
+
type: "string",
|
|
59767
|
+
enum: ["capability", "module", "component", "interface", "event", "datastore", "external-system", "deployment"]
|
|
59768
|
+
},
|
|
59769
|
+
name: { type: "string" },
|
|
59770
|
+
status: { type: "string", enum: ["active", "planned", "deprecated", "removed"] },
|
|
59771
|
+
parent: { type: "string", pattern: "^([a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)*::)?[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
59772
|
+
summary: { type: "string" },
|
|
59773
|
+
responsibilities: { type: "array", items: { type: "string" }, minItems: 1 },
|
|
59774
|
+
source: {
|
|
59775
|
+
type: "object",
|
|
59776
|
+
additionalProperties: false,
|
|
59777
|
+
properties: {
|
|
59778
|
+
include: { type: "array", items: { type: "string" } },
|
|
59779
|
+
exclude: { type: "array", items: { type: "string" } },
|
|
59780
|
+
entrypoints: {
|
|
59781
|
+
type: "array",
|
|
59782
|
+
items: {
|
|
59783
|
+
type: "object",
|
|
59784
|
+
additionalProperties: false,
|
|
59785
|
+
required: ["id", "path", "symbols"],
|
|
59786
|
+
properties: {
|
|
59787
|
+
id: { type: "string", pattern: "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
59788
|
+
path: { type: "string", minLength: 1 },
|
|
59789
|
+
symbols: {
|
|
59790
|
+
type: "array",
|
|
59791
|
+
minItems: 1,
|
|
59792
|
+
items: {
|
|
59793
|
+
type: "object",
|
|
59794
|
+
additionalProperties: false,
|
|
59795
|
+
required: ["name", "sinks"],
|
|
59796
|
+
properties: {
|
|
59797
|
+
name: { type: "string", minLength: 1 },
|
|
59798
|
+
sinks: {
|
|
59799
|
+
type: "array",
|
|
59800
|
+
minItems: 1,
|
|
59801
|
+
items: {
|
|
59802
|
+
type: "object",
|
|
59803
|
+
additionalProperties: false,
|
|
59804
|
+
required: ["id", "path", "symbol"],
|
|
59805
|
+
properties: {
|
|
59806
|
+
id: { type: "string", pattern: "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+$" },
|
|
59807
|
+
path: { type: "string", minLength: 1 },
|
|
59808
|
+
symbol: { type: "string", minLength: 1 }
|
|
59809
|
+
}
|
|
59810
|
+
}
|
|
59811
|
+
}
|
|
59812
|
+
}
|
|
59813
|
+
}
|
|
59814
|
+
}
|
|
59815
|
+
}
|
|
59816
|
+
}
|
|
59817
|
+
}
|
|
59818
|
+
}
|
|
59819
|
+
},
|
|
59820
|
+
ownership: {
|
|
59821
|
+
type: "object",
|
|
59822
|
+
additionalProperties: false,
|
|
59823
|
+
properties: {
|
|
59824
|
+
lifecycle: { type: "array", items: { type: "string" } },
|
|
59825
|
+
data: { type: "array", items: { type: "string" } }
|
|
59826
|
+
}
|
|
59827
|
+
},
|
|
59828
|
+
interfaces: {
|
|
59829
|
+
type: "object",
|
|
59830
|
+
additionalProperties: false,
|
|
59831
|
+
properties: {
|
|
59832
|
+
provides: { type: "array", items: { type: "string" } },
|
|
59833
|
+
consumes: { type: "array", items: { type: "string" } }
|
|
59834
|
+
}
|
|
59835
|
+
},
|
|
59836
|
+
criticality: { type: "string", enum: ["low", "medium", "high", "critical"] },
|
|
59837
|
+
riskDomains: { type: "array", items: { type: "string" } },
|
|
59838
|
+
notes: { type: "array", items: { type: "string" } },
|
|
59839
|
+
extensions: { type: "object", additionalProperties: true }
|
|
59840
|
+
}
|
|
59841
|
+
};
|
|
59842
|
+
|
|
59574
59843
|
// packages/surfaces/cli/src/main.ts
|
|
59575
59844
|
var [, , command, ...args] = process.argv;
|
|
59576
59845
|
var CLI_ENTRY = fileURLToPath2(import.meta.url);
|
|
@@ -60244,7 +60513,7 @@ async function runCliUnchecked(command = "help", args = [], cwd, deps = {}) {
|
|
|
60244
60513
|
const read = await readResolvePathsFrom(args, cwd, deps);
|
|
60245
60514
|
if ("problem" in read)
|
|
60246
60515
|
return errorEnvelope("resolve", "AC_SCHEMA_INVALID", read.problem);
|
|
60247
|
-
const model =
|
|
60516
|
+
const model = loadResolveModel(cwd);
|
|
60248
60517
|
const outcomes = resolveArchitectureOwnersForPaths(model.nodes, read.paths);
|
|
60249
60518
|
return okEnvelope("resolve", { results: outcomes.map((outcome, index) => resolveResultData(read.paths[index], outcome)) });
|
|
60250
60519
|
}
|
|
@@ -60254,7 +60523,7 @@ async function runCliUnchecked(command = "help", args = [], cwd, deps = {}) {
|
|
|
60254
60523
|
if (!isRepoRelativePosixPath(path)) {
|
|
60255
60524
|
return errorEnvelope("resolve", "AC_SCHEMA_INVALID", "resolve --path must be a repository-relative POSIX path");
|
|
60256
60525
|
}
|
|
60257
|
-
const model =
|
|
60526
|
+
const model = loadResolveModel(cwd);
|
|
60258
60527
|
return okEnvelope("resolve", resolveResultData(path, resolveArchitectureOwnerForPath(model.nodes, path)));
|
|
60259
60528
|
}
|
|
60260
60529
|
case "help":
|
|
@@ -63267,6 +63536,37 @@ var CLI_RESOLVE_HELP = {
|
|
|
63267
63536
|
result: "Each result carries path, matched, ambiguous and owningCapabilityId. A match adds stableId, kind, name, source and extensions of the most specific node. An ambiguous result adds candidates. owningCapabilityId is the nearest kind: capability node on the owner's parent chain (the owner itself when it is a capability), or null. For an ambiguous result it is set only when all candidates share one owning capability.",
|
|
63268
63537
|
exitCodes: "--path: 0 matched, 1 no match or error, 2 ambiguous. --paths-from: 0 when no path is ambiguous (unowned paths included), 2 when any path is ambiguous, 1 on error."
|
|
63269
63538
|
};
|
|
63539
|
+
function loadResolveModel(cwd) {
|
|
63540
|
+
if (!existsSync34(join26(cwd, ".archcontext/manifest.yaml"))) {
|
|
63541
|
+
throw new NativeContextError("native-context-model-missing", { path: ".archcontext/manifest.yaml" });
|
|
63542
|
+
}
|
|
63543
|
+
let model;
|
|
63544
|
+
try {
|
|
63545
|
+
model = loadNativeModelFromArchContext(cwd);
|
|
63546
|
+
} catch (error) {
|
|
63547
|
+
const cause = error;
|
|
63548
|
+
if (typeof cause?.code === "string") {
|
|
63549
|
+
throw new NativeContextError("native-context-input-unreadable", {
|
|
63550
|
+
category: "open-or-read",
|
|
63551
|
+
...typeof cause.path === "string" ? { path: cause.path } : {}
|
|
63552
|
+
});
|
|
63553
|
+
}
|
|
63554
|
+
throw new NativeContextError("native-context-model-invalid", { invariant: "model-parse" });
|
|
63555
|
+
}
|
|
63556
|
+
if (model.nodes.length === 0) {
|
|
63557
|
+
throw new NativeContextError("native-context-model-missing", { category: "no-native-nodes" });
|
|
63558
|
+
}
|
|
63559
|
+
for (const node of model.nodes) {
|
|
63560
|
+
const { issues } = validateJsonSchema(architecture_node_schema_default2, node);
|
|
63561
|
+
if (issues.length > 0) {
|
|
63562
|
+
throw new NativeContextError("native-context-model-invalid", {
|
|
63563
|
+
issues: issues.slice(0, 32).map((issue) => ({ entityId: typeof node.id === "string" ? node.id : "(undeclared)", field: issue.path, invariant: issue.message })),
|
|
63564
|
+
omittedDiagnosticCount: Math.max(0, issues.length - 32)
|
|
63565
|
+
});
|
|
63566
|
+
}
|
|
63567
|
+
}
|
|
63568
|
+
return model;
|
|
63569
|
+
}
|
|
63270
63570
|
function resolveResultData(path, outcome) {
|
|
63271
63571
|
if (outcome.status === "matched") {
|
|
63272
63572
|
const node = outcome.node;
|
|
@@ -63579,6 +63879,8 @@ if (__require.main == __require.module) {
|
|
|
63579
63879
|
`);
|
|
63580
63880
|
if (result.ok === false)
|
|
63581
63881
|
process.exitCode = 1;
|
|
63882
|
+
if (command === "validate" && result.ok && result.data?.valid === false)
|
|
63883
|
+
process.exitCode = 1;
|
|
63582
63884
|
if (command === "resolve")
|
|
63583
63885
|
process.exitCode = resolveCommandExitCode(result);
|
|
63584
63886
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://archctx.repoharness.com/schemas/runtime/native-model-issue.schema.json",
|
|
4
|
+
"title": "NativeModelIssue",
|
|
5
|
+
"description": "A native model schema or reference issue. Source paths are optional for callers that do not supply parsed record paths.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["entityId", "field", "invariant"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"entityId": { "type": "string" },
|
|
11
|
+
"field": { "type": "string" },
|
|
12
|
+
"invariant": { "type": "string" },
|
|
13
|
+
"path": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "The repository-relative path of the parsed source file that holds this record. It is not derived from the entity ID."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|