@inerrata-corporation/errata 2.0.6-dev.1989 → 2.0.6-dev.2028
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/consolidate-worker.mjs +5 -3
- package/errata.mjs +455 -423
- package/package.json +1 -1
- package/pass-worker.mjs +5 -3
package/consolidate-worker.mjs
CHANGED
|
@@ -15267,7 +15267,7 @@ var init_symbol_intent = __esm({
|
|
|
15267
15267
|
});
|
|
15268
15268
|
|
|
15269
15269
|
// ../../packages/shared/src/wire.ts
|
|
15270
|
-
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15270
|
+
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15271
15271
|
var init_wire = __esm({
|
|
15272
15272
|
"../../packages/shared/src/wire.ts"() {
|
|
15273
15273
|
"use strict";
|
|
@@ -15368,6 +15368,8 @@ var init_wire = __esm({
|
|
|
15368
15368
|
independent: external_exports.number().int().min(0).optional(),
|
|
15369
15369
|
inferredIndependent: external_exports.number().int().min(0).optional()
|
|
15370
15370
|
});
|
|
15371
|
+
ANCHOR_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/;
|
|
15372
|
+
ANCHOR_BODY_HASH_RE = /^[0-9a-f]{8,64}$/;
|
|
15371
15373
|
CastaliaIngestEdgeSchema = external_exports.object({
|
|
15372
15374
|
fromCanonicalId: external_exports.string().min(6).max(160),
|
|
15373
15375
|
toCanonicalId: external_exports.string().min(6).max(160),
|
|
@@ -15386,8 +15388,8 @@ var init_wire = __esm({
|
|
|
15386
15388
|
* (reanchor) compares the hash with its local symbol's `bodyHash` to
|
|
15387
15389
|
* classify the anchor current / pre-change; absent ⇒ the pre-versioning
|
|
15388
15390
|
* contract, unverified. Only meaningful on `ANCHORED_AT`. */
|
|
15389
|
-
observedAtCommit: external_exports.string().regex(
|
|
15390
|
-
symbolContentHash: external_exports.string().regex(
|
|
15391
|
+
observedAtCommit: external_exports.string().regex(ANCHOR_COMMIT_SHA_RE).optional(),
|
|
15392
|
+
symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional()
|
|
15391
15393
|
}).optional()
|
|
15392
15394
|
});
|
|
15393
15395
|
SymbolSummarySidecarSchema = external_exports.record(
|
package/errata.mjs
CHANGED
|
@@ -15711,6 +15711,15 @@ function provenanceBand(source) {
|
|
|
15711
15711
|
function isSeedProvenance(source) {
|
|
15712
15712
|
return provenanceBand(source) === "seed";
|
|
15713
15713
|
}
|
|
15714
|
+
function anchorVersionAttrs(attrs) {
|
|
15715
|
+
if (!attrs) return {};
|
|
15716
|
+
const commit = attrs["observedAtCommit"];
|
|
15717
|
+
const hash2 = attrs["symbolContentHash"];
|
|
15718
|
+
return {
|
|
15719
|
+
...typeof commit === "string" && ANCHOR_COMMIT_SHA_RE.test(commit) ? { observedAtCommit: commit } : {},
|
|
15720
|
+
...typeof hash2 === "string" && ANCHOR_BODY_HASH_RE.test(hash2) ? { symbolContentHash: hash2 } : {}
|
|
15721
|
+
};
|
|
15722
|
+
}
|
|
15714
15723
|
function validateCastaliaPayload(p) {
|
|
15715
15724
|
const errors = [];
|
|
15716
15725
|
const labelByCid = /* @__PURE__ */ new Map();
|
|
@@ -15740,7 +15749,7 @@ function summarizeIngestResult(r) {
|
|
|
15740
15749
|
...r.patternReconciliation ? { patternReconciliation: r.patternReconciliation } : {}
|
|
15741
15750
|
};
|
|
15742
15751
|
}
|
|
15743
|
-
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, QUARANTINE_EXTRACTION_SOURCE_PREFIX, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15752
|
+
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, QUARANTINE_EXTRACTION_SOURCE_PREFIX, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15744
15753
|
var init_wire = __esm({
|
|
15745
15754
|
"../../packages/shared/src/wire.ts"() {
|
|
15746
15755
|
"use strict";
|
|
@@ -15844,6 +15853,8 @@ var init_wire = __esm({
|
|
|
15844
15853
|
independent: external_exports.number().int().min(0).optional(),
|
|
15845
15854
|
inferredIndependent: external_exports.number().int().min(0).optional()
|
|
15846
15855
|
});
|
|
15856
|
+
ANCHOR_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/;
|
|
15857
|
+
ANCHOR_BODY_HASH_RE = /^[0-9a-f]{8,64}$/;
|
|
15847
15858
|
CastaliaIngestEdgeSchema = external_exports.object({
|
|
15848
15859
|
fromCanonicalId: external_exports.string().min(6).max(160),
|
|
15849
15860
|
toCanonicalId: external_exports.string().min(6).max(160),
|
|
@@ -15862,8 +15873,8 @@ var init_wire = __esm({
|
|
|
15862
15873
|
* (reanchor) compares the hash with its local symbol's `bodyHash` to
|
|
15863
15874
|
* classify the anchor current / pre-change; absent ⇒ the pre-versioning
|
|
15864
15875
|
* contract, unverified. Only meaningful on `ANCHORED_AT`. */
|
|
15865
|
-
observedAtCommit: external_exports.string().regex(
|
|
15866
|
-
symbolContentHash: external_exports.string().regex(
|
|
15876
|
+
observedAtCommit: external_exports.string().regex(ANCHOR_COMMIT_SHA_RE).optional(),
|
|
15877
|
+
symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional()
|
|
15867
15878
|
}).optional()
|
|
15868
15879
|
});
|
|
15869
15880
|
SymbolSummarySidecarSchema = external_exports.record(
|
|
@@ -16334,6 +16345,8 @@ __export(src_exports, {
|
|
|
16334
16345
|
ALL_EDGE_TYPES: () => ALL_EDGE_TYPES,
|
|
16335
16346
|
ALL_NODE_LABELS: () => ALL_NODE_LABELS,
|
|
16336
16347
|
AMBIGUOUS_ALIASES: () => AMBIGUOUS_ALIASES,
|
|
16348
|
+
ANCHOR_BODY_HASH_RE: () => ANCHOR_BODY_HASH_RE,
|
|
16349
|
+
ANCHOR_COMMIT_SHA_RE: () => ANCHOR_COMMIT_SHA_RE,
|
|
16337
16350
|
ANCHOR_REFUSAL_REASONS: () => ANCHOR_REFUSAL_REASONS,
|
|
16338
16351
|
BELIEF_EDGES: () => BELIEF_EDGES,
|
|
16339
16352
|
BRIDGE_EDGES: () => BRIDGE_EDGES,
|
|
@@ -16392,6 +16405,7 @@ __export(src_exports, {
|
|
|
16392
16405
|
VALIDATION_SOURCES: () => VALIDATION_SOURCES,
|
|
16393
16406
|
aliasesLongestFirst: () => aliasesLongestFirst,
|
|
16394
16407
|
allEntities: () => allEntities,
|
|
16408
|
+
anchorVersionAttrs: () => anchorVersionAttrs,
|
|
16395
16409
|
assertGraphEventVocabulary: () => assertGraphEventVocabulary,
|
|
16396
16410
|
buildSpine: () => buildSpine,
|
|
16397
16411
|
canonicalClaimId: () => canonicalClaimId,
|
|
@@ -24536,7 +24550,7 @@ function toWirePayload(batch, runId) {
|
|
|
24536
24550
|
...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {},
|
|
24537
24551
|
...perContext ? { perContext } : {},
|
|
24538
24552
|
// PJ-anchor-version: the two opaque version stamps ride on anchors only.
|
|
24539
|
-
...e.type === "ANCHORED_AT" ?
|
|
24553
|
+
...e.type === "ANCHORED_AT" ? anchorVersionAttrs(e.attrs) : {}
|
|
24540
24554
|
}
|
|
24541
24555
|
};
|
|
24542
24556
|
});
|
|
@@ -24572,15 +24586,6 @@ function textOrThrow(value, field) {
|
|
|
24572
24586
|
if (!text) throw new TypeError(`${field} must be a non-empty string`);
|
|
24573
24587
|
return text;
|
|
24574
24588
|
}
|
|
24575
|
-
function wireAnchorVersion(attrs) {
|
|
24576
|
-
if (!attrs) return {};
|
|
24577
|
-
const commit = attrs["observedAtCommit"];
|
|
24578
|
-
const hash2 = attrs["symbolContentHash"];
|
|
24579
|
-
return {
|
|
24580
|
-
...typeof commit === "string" && HEX_SHA.test(commit) ? { observedAtCommit: commit } : {},
|
|
24581
|
-
...typeof hash2 === "string" && HEX_BODY.test(hash2) ? { symbolContentHash: hash2 } : {}
|
|
24582
|
-
};
|
|
24583
|
-
}
|
|
24584
24589
|
function optionalEdgeAttrs(confidence) {
|
|
24585
24590
|
return typeof confidence === "number" ? { confidence: clamp012(confidence) } : void 0;
|
|
24586
24591
|
}
|
|
@@ -24706,15 +24711,13 @@ function provenanceHeaders(provenance) {
|
|
|
24706
24711
|
...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
|
|
24707
24712
|
};
|
|
24708
24713
|
}
|
|
24709
|
-
var asWireCount,
|
|
24714
|
+
var asWireCount, INGEST_NODE_CHUNK, E6B_PUBLIC_CONTEXT_SENTINEL, CloudClient, CloudError;
|
|
24710
24715
|
var init_client = __esm({
|
|
24711
24716
|
"../../packages/cloud-client/src/client.ts"() {
|
|
24712
24717
|
"use strict";
|
|
24713
24718
|
init_oauth();
|
|
24714
24719
|
init_src();
|
|
24715
24720
|
asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
|
|
24716
|
-
HEX_SHA = /^[0-9a-f]{7,40}$/;
|
|
24717
|
-
HEX_BODY = /^[0-9a-f]{8,64}$/;
|
|
24718
24721
|
INGEST_NODE_CHUNK = 8;
|
|
24719
24722
|
E6B_PUBLIC_CONTEXT_SENTINEL = "00000000-0000-4e6b-8000-000000000e6b";
|
|
24720
24723
|
CloudClient = class {
|
|
@@ -77005,7 +77008,7 @@ function createWatchBreaker(deps) {
|
|
|
77005
77008
|
}
|
|
77006
77009
|
|
|
77007
77010
|
// src/engine.ts
|
|
77008
|
-
var DAEMON_VERSION = true ? "2.0.6-dev.
|
|
77011
|
+
var DAEMON_VERSION = true ? "2.0.6-dev.2028" : "2.0.0-alpha.0";
|
|
77009
77012
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
77010
77013
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
77011
77014
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -79334,7 +79337,7 @@ init_identity2();
|
|
|
79334
79337
|
// src/multi.ts
|
|
79335
79338
|
init_dist();
|
|
79336
79339
|
init_src5();
|
|
79337
|
-
import { existsSync as
|
|
79340
|
+
import { existsSync as existsSync31, readFileSync as readFileSync30, unlinkSync as unlinkSync3, writeFileSync as writeFileSync23 } from "node:fs";
|
|
79338
79341
|
|
|
79339
79342
|
// src/principle-sync.ts
|
|
79340
79343
|
init_src5();
|
|
@@ -79729,15 +79732,6 @@ function contributedWireId(n) {
|
|
|
79729
79732
|
}
|
|
79730
79733
|
var WIRE_CANONICAL_ID_MIN = 6;
|
|
79731
79734
|
var SHIP_TERMINAL_REFUSALS = 3;
|
|
79732
|
-
function anchorVersionAttrs(attrs) {
|
|
79733
|
-
if (!attrs) return {};
|
|
79734
|
-
const commit = attrs["observedAtCommit"];
|
|
79735
|
-
const hash2 = attrs["symbolContentHash"];
|
|
79736
|
-
return {
|
|
79737
|
-
...typeof commit === "string" && /^[0-9a-f]{7,40}$/.test(commit) ? { observedAtCommit: commit } : {},
|
|
79738
|
-
...typeof hash2 === "string" && /^[0-9a-f]{8,64}$/.test(hash2) ? { symbolContentHash: hash2 } : {}
|
|
79739
|
-
};
|
|
79740
|
-
}
|
|
79741
79735
|
function refusalFingerprint(reason, description) {
|
|
79742
79736
|
return digest(`${reason}\0${description}`);
|
|
79743
79737
|
}
|
|
@@ -82299,10 +82293,14 @@ function applyStopRequest(profile, now = () => /* @__PURE__ */ new Date()) {
|
|
|
82299
82293
|
}
|
|
82300
82294
|
};
|
|
82301
82295
|
}
|
|
82302
|
-
async function startHistoryStage(root,
|
|
82296
|
+
async function startHistoryStage(root, input, client, walk10 = {}) {
|
|
82297
|
+
let profile = input;
|
|
82303
82298
|
if (!profile.projectId) return { started: false, reason: "no-project", profile };
|
|
82304
|
-
const consents = historyConsents(profile);
|
|
82305
82299
|
const response = await reportHistoryStage(client, profile);
|
|
82300
|
+
if (response?.consents && walk10.applyConsents) {
|
|
82301
|
+
profile = walk10.applyConsents(profile, response.consents);
|
|
82302
|
+
}
|
|
82303
|
+
const consents = historyConsents(profile);
|
|
82306
82304
|
if (response?.stopRequested && profile.historyStage && profile.historyStage.state !== "refused") {
|
|
82307
82305
|
const stopped = applyStopRequest(profile);
|
|
82308
82306
|
await reportHistoryStage(client, stopped);
|
|
@@ -82313,17 +82311,414 @@ async function startHistoryStage(root, profile, client, walk10 = {}) {
|
|
|
82313
82311
|
return { started: true, profile: outcome.profile };
|
|
82314
82312
|
}
|
|
82315
82313
|
|
|
82314
|
+
// src/link-flow.ts
|
|
82315
|
+
init_cloud_auth();
|
|
82316
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
82317
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
82318
|
+
import { existsSync as existsSync29, writeFileSync as writeFileSync22 } from "node:fs";
|
|
82319
|
+
import { join as join34 } from "node:path";
|
|
82320
|
+
|
|
82321
|
+
// src/oauth-login.ts
|
|
82322
|
+
init_src7();
|
|
82323
|
+
init_cloud_auth();
|
|
82324
|
+
import { createServer } from "node:http";
|
|
82325
|
+
var DEFAULT_OAUTH_SCOPE = "openid profile graph:read graph:write mcp:tools";
|
|
82326
|
+
var strip = (u) => u.replace(/\/+$/, "");
|
|
82327
|
+
function deviceEndpoints(tokenEndpoint) {
|
|
82328
|
+
const token = new URL(tokenEndpoint);
|
|
82329
|
+
const authRoot = token.pathname.replace(/\/(?:oauth2|mcp)\/token\/?$/, "");
|
|
82330
|
+
if (authRoot === token.pathname) throw new Error("authorization server exposes no device endpoint");
|
|
82331
|
+
const prefix = authRoot.replace(/\/api\/auth\/?$/, "");
|
|
82332
|
+
const at = (path2) => new URL(`${path2}`, `${token.origin}${prefix || "/"}`).toString();
|
|
82333
|
+
return {
|
|
82334
|
+
code: at(`${prefix}/api/auth/device/code`),
|
|
82335
|
+
token: at(`${prefix}/api/auth/device/token`),
|
|
82336
|
+
resource: at(`${prefix}/api/gate/session-token`)
|
|
82337
|
+
};
|
|
82338
|
+
}
|
|
82339
|
+
async function loginOAuthDevice(opts) {
|
|
82340
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
82341
|
+
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82342
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
82343
|
+
const clientId = oauthClientId();
|
|
82344
|
+
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
82345
|
+
const codeResponse = await fetchFn(device.code, {
|
|
82346
|
+
method: "POST",
|
|
82347
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
82348
|
+
body: JSON.stringify({ client_id: clientId, scope })
|
|
82349
|
+
});
|
|
82350
|
+
if (!codeResponse.ok) {
|
|
82351
|
+
throw new Error(`device authorization failed: HTTP ${codeResponse.status} ${(await codeResponse.text()).slice(0, 200)}`);
|
|
82352
|
+
}
|
|
82353
|
+
const code = await codeResponse.json();
|
|
82354
|
+
if (!code.device_code || !code.user_code || !code.verification_uri || !code.expires_in) {
|
|
82355
|
+
throw new Error("device authorization returned an incomplete response");
|
|
82356
|
+
}
|
|
82357
|
+
opts.onVerification?.({
|
|
82358
|
+
url: code.verification_uri_complete ?? code.verification_uri,
|
|
82359
|
+
userCode: code.user_code,
|
|
82360
|
+
expiresInSec: code.expires_in
|
|
82361
|
+
});
|
|
82362
|
+
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
82363
|
+
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
82364
|
+
let deviceSession = null;
|
|
82365
|
+
let approvedInstallation = null;
|
|
82366
|
+
while (Date.now() < deadline) {
|
|
82367
|
+
await (opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(intervalMs);
|
|
82368
|
+
const poll = await fetchFn(device.token, {
|
|
82369
|
+
method: "POST",
|
|
82370
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
82371
|
+
body: JSON.stringify({
|
|
82372
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
82373
|
+
device_code: code.device_code,
|
|
82374
|
+
client_id: clientId
|
|
82375
|
+
})
|
|
82376
|
+
});
|
|
82377
|
+
const payload = await poll.json().catch(() => null);
|
|
82378
|
+
if (!poll.ok) {
|
|
82379
|
+
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
82380
|
+
if (error48 === "authorization_pending") continue;
|
|
82381
|
+
if (error48 === "slow_down") {
|
|
82382
|
+
intervalMs += 5e3;
|
|
82383
|
+
continue;
|
|
82384
|
+
}
|
|
82385
|
+
throw new Error(`device authorization failed: ${error48}`);
|
|
82386
|
+
}
|
|
82387
|
+
deviceSession = typeof payload?.["access_token"] === "string" ? payload["access_token"] : null;
|
|
82388
|
+
approvedInstallation = typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null;
|
|
82389
|
+
break;
|
|
82390
|
+
}
|
|
82391
|
+
if (!deviceSession || !approvedInstallation) throw new Error("device authorization expired");
|
|
82392
|
+
if (approvedInstallation !== opts.installationId) {
|
|
82393
|
+
throw new Error("approved installation does not match the terminal request");
|
|
82394
|
+
}
|
|
82395
|
+
const resourceResponse = await fetchFn(device.resource, {
|
|
82396
|
+
method: "POST",
|
|
82397
|
+
headers: {
|
|
82398
|
+
authorization: `Bearer ${deviceSession}`,
|
|
82399
|
+
"content-type": "application/json",
|
|
82400
|
+
accept: "application/json"
|
|
82401
|
+
},
|
|
82402
|
+
body: JSON.stringify({
|
|
82403
|
+
installationId: approvedInstallation,
|
|
82404
|
+
clientId,
|
|
82405
|
+
scopes: scope.split(/\s+/).filter((value) => !["openid", "profile", "email", "offline_access"].includes(value))
|
|
82406
|
+
})
|
|
82407
|
+
});
|
|
82408
|
+
const resource = await resourceResponse.json().catch(() => null);
|
|
82409
|
+
if (!resourceResponse.ok || typeof resource?.["access_token"] !== "string") {
|
|
82410
|
+
throw new Error(`device resource exchange failed: HTTP ${resourceResponse.status}`);
|
|
82411
|
+
}
|
|
82412
|
+
return {
|
|
82413
|
+
installationId: approvedInstallation,
|
|
82414
|
+
clientId,
|
|
82415
|
+
tokenEndpoint: device.resource,
|
|
82416
|
+
tokens: {
|
|
82417
|
+
accessToken: resource["access_token"],
|
|
82418
|
+
refreshToken: deviceSession,
|
|
82419
|
+
...typeof resource["expires_in"] === "number" ? { expiresInSec: resource["expires_in"] } : {}
|
|
82420
|
+
}
|
|
82421
|
+
};
|
|
82422
|
+
}
|
|
82423
|
+
async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
|
|
82424
|
+
let consoleUrl = cloudUrl;
|
|
82425
|
+
try {
|
|
82426
|
+
const prm = await fetchFn(`${strip(cloudUrl)}/.well-known/oauth-protected-resource`);
|
|
82427
|
+
if (prm.ok) {
|
|
82428
|
+
const j = await prm.json();
|
|
82429
|
+
if (j.authorization_servers?.[0]) consoleUrl = j.authorization_servers[0];
|
|
82430
|
+
}
|
|
82431
|
+
} catch {
|
|
82432
|
+
}
|
|
82433
|
+
try {
|
|
82434
|
+
const asm = await fetchFn(`${strip(consoleUrl)}/.well-known/oauth-authorization-server`);
|
|
82435
|
+
if (asm.ok) {
|
|
82436
|
+
const j = await asm.json();
|
|
82437
|
+
if (j.authorization_endpoint && j.token_endpoint) {
|
|
82438
|
+
return {
|
|
82439
|
+
authorizationEndpoint: j.authorization_endpoint,
|
|
82440
|
+
tokenEndpoint: j.token_endpoint,
|
|
82441
|
+
...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {}
|
|
82442
|
+
};
|
|
82443
|
+
}
|
|
82444
|
+
}
|
|
82445
|
+
} catch {
|
|
82446
|
+
}
|
|
82447
|
+
const base = strip(consoleUrl);
|
|
82448
|
+
return {
|
|
82449
|
+
authorizationEndpoint: `${base}/api/auth/oauth2/authorize`,
|
|
82450
|
+
tokenEndpoint: `${base}/api/auth/oauth2/token`
|
|
82451
|
+
};
|
|
82452
|
+
}
|
|
82453
|
+
function buildAuthorizeUrl(endpoint, p) {
|
|
82454
|
+
const u = new URL(endpoint);
|
|
82455
|
+
u.searchParams.set("response_type", "code");
|
|
82456
|
+
u.searchParams.set("client_id", p.clientId);
|
|
82457
|
+
u.searchParams.set("redirect_uri", p.redirectUri);
|
|
82458
|
+
u.searchParams.set("scope", p.scope);
|
|
82459
|
+
u.searchParams.set("state", p.state);
|
|
82460
|
+
u.searchParams.set("code_challenge", p.challenge);
|
|
82461
|
+
u.searchParams.set("code_challenge_method", p.method);
|
|
82462
|
+
return u.toString();
|
|
82463
|
+
}
|
|
82464
|
+
async function loginOAuthLoopback(opts) {
|
|
82465
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
82466
|
+
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82467
|
+
const pkce = generatePkce();
|
|
82468
|
+
const state = randomState();
|
|
82469
|
+
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
82470
|
+
const { code, redirectUri, clientId } = await new Promise(
|
|
82471
|
+
(resolve7, reject) => {
|
|
82472
|
+
const server = createServer((req, res) => {
|
|
82473
|
+
const u = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
82474
|
+
if (u.pathname !== "/callback") {
|
|
82475
|
+
res.writeHead(404);
|
|
82476
|
+
res.end();
|
|
82477
|
+
return;
|
|
82478
|
+
}
|
|
82479
|
+
const addr2 = server.address();
|
|
82480
|
+
const port = typeof addr2 === "object" && addr2 ? addr2.port : 0;
|
|
82481
|
+
const err2 = u.searchParams.get("error");
|
|
82482
|
+
const code2 = u.searchParams.get("code");
|
|
82483
|
+
const returnedState = u.searchParams.get("state");
|
|
82484
|
+
if (err2 || !code2 || returnedState !== state) {
|
|
82485
|
+
res.writeHead(400, { "content-type": "text/plain" });
|
|
82486
|
+
res.end(`login failed: ${err2 ?? (returnedState !== state ? "state_mismatch" : "no_code")}`);
|
|
82487
|
+
server.close();
|
|
82488
|
+
reject(new Error(err2 ?? "invalid_callback"));
|
|
82489
|
+
return;
|
|
82490
|
+
}
|
|
82491
|
+
res.writeHead(200, { "content-type": "text/html" });
|
|
82492
|
+
res.end("<html><body>inErrata: you're logged in. You can close this tab.</body></html>");
|
|
82493
|
+
server.close();
|
|
82494
|
+
resolve7({ code: code2, redirectUri: `http://127.0.0.1:${port}/callback`, clientId: activeClientId });
|
|
82495
|
+
});
|
|
82496
|
+
let activeClientId = oauthClientId();
|
|
82497
|
+
server.on("error", reject);
|
|
82498
|
+
server.listen(0, "127.0.0.1", () => {
|
|
82499
|
+
void (async () => {
|
|
82500
|
+
try {
|
|
82501
|
+
const addr2 = server.address();
|
|
82502
|
+
const port = typeof addr2 === "object" && addr2 ? addr2.port : 0;
|
|
82503
|
+
const redirectUri2 = `http://127.0.0.1:${port}/callback`;
|
|
82504
|
+
if (endpoints.registrationEndpoint) {
|
|
82505
|
+
const registered = await registerOAuthClient(fetchFn, endpoints.registrationEndpoint, {
|
|
82506
|
+
redirectUri: redirectUri2,
|
|
82507
|
+
scope,
|
|
82508
|
+
clientName: "errata daemon"
|
|
82509
|
+
});
|
|
82510
|
+
activeClientId = registered.clientId;
|
|
82511
|
+
}
|
|
82512
|
+
const url2 = buildAuthorizeUrl(endpoints.authorizationEndpoint, {
|
|
82513
|
+
clientId: activeClientId,
|
|
82514
|
+
redirectUri: redirectUri2,
|
|
82515
|
+
scope,
|
|
82516
|
+
state,
|
|
82517
|
+
challenge: pkce.challenge,
|
|
82518
|
+
method: pkce.method
|
|
82519
|
+
});
|
|
82520
|
+
if (opts.open) opts.open(url2);
|
|
82521
|
+
else console.log(`approve this login in your browser:
|
|
82522
|
+
${url2}`);
|
|
82523
|
+
} catch (err2) {
|
|
82524
|
+
server.close();
|
|
82525
|
+
reject(err2);
|
|
82526
|
+
}
|
|
82527
|
+
})();
|
|
82528
|
+
});
|
|
82529
|
+
if (opts.timeoutMs) {
|
|
82530
|
+
setTimeout(() => {
|
|
82531
|
+
server.close();
|
|
82532
|
+
reject(new Error("login timed out \u2014 run `errata login` again"));
|
|
82533
|
+
}, opts.timeoutMs).unref?.();
|
|
82534
|
+
}
|
|
82535
|
+
}
|
|
82536
|
+
);
|
|
82537
|
+
const tokens = await exchangeAuthorizationCode(fetchFn, endpoints.tokenEndpoint, {
|
|
82538
|
+
code,
|
|
82539
|
+
codeVerifier: pkce.verifier,
|
|
82540
|
+
redirectUri,
|
|
82541
|
+
clientId
|
|
82542
|
+
});
|
|
82543
|
+
return { tokens, tokenEndpoint: endpoints.tokenEndpoint, clientId };
|
|
82544
|
+
}
|
|
82545
|
+
|
|
82546
|
+
// src/link-flow.ts
|
|
82547
|
+
function remoteFingerprint(locator) {
|
|
82548
|
+
return createHash15("sha256").update(locator).digest("hex");
|
|
82549
|
+
}
|
|
82550
|
+
function isDecision(value) {
|
|
82551
|
+
if (!value || typeof value !== "object") return false;
|
|
82552
|
+
const v = value;
|
|
82553
|
+
return typeof v["projectId"] === "string" && typeof v["locator"] === "string" && (v["visibility"] === "public" || v["visibility"] === "private") && typeof v["consents"] === "object" && v["consents"] !== null;
|
|
82554
|
+
}
|
|
82555
|
+
async function linkThroughConsole(opts) {
|
|
82556
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
82557
|
+
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82558
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
82559
|
+
const clientId = oauthClientId();
|
|
82560
|
+
const link = {
|
|
82561
|
+
locator: opts.facts.locator,
|
|
82562
|
+
remoteFingerprint: remoteFingerprint(opts.facts.locator),
|
|
82563
|
+
...opts.facts.name ? { name: opts.facts.name } : {},
|
|
82564
|
+
...opts.facts.rootCommitSha ? { rootCommitSha: opts.facts.rootCommitSha } : {},
|
|
82565
|
+
...opts.facts.installationId ? { installationId: opts.facts.installationId } : {},
|
|
82566
|
+
...opts.facts.agents && opts.facts.agents.length > 0 ? { agents: opts.facts.agents.slice(0, 12) } : {},
|
|
82567
|
+
...typeof opts.facts.commitCount === "number" ? { commitCount: opts.facts.commitCount } : {}
|
|
82568
|
+
};
|
|
82569
|
+
const codeResponse = await fetchFn(device.code, {
|
|
82570
|
+
method: "POST",
|
|
82571
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
82572
|
+
body: JSON.stringify({ client_id: clientId, scope: "project:link", link })
|
|
82573
|
+
});
|
|
82574
|
+
if (!codeResponse.ok) {
|
|
82575
|
+
const text = (await codeResponse.text()).slice(0, 200);
|
|
82576
|
+
if (codeResponse.status === 404) {
|
|
82577
|
+
throw new Error("this console does not offer the link flow yet (device authorization is off)");
|
|
82578
|
+
}
|
|
82579
|
+
throw new Error(`link request failed: HTTP ${codeResponse.status} ${text}`);
|
|
82580
|
+
}
|
|
82581
|
+
const code = await codeResponse.json();
|
|
82582
|
+
if (!code.device_code || !code.user_code || !code.verification_uri || !code.expires_in) {
|
|
82583
|
+
throw new Error("link request returned an incomplete response");
|
|
82584
|
+
}
|
|
82585
|
+
opts.onVerification?.({
|
|
82586
|
+
url: code.verification_uri_complete ?? code.verification_uri,
|
|
82587
|
+
userCode: code.user_code,
|
|
82588
|
+
expiresInSec: code.expires_in
|
|
82589
|
+
});
|
|
82590
|
+
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
82591
|
+
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
82592
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
82593
|
+
while (Date.now() < deadline) {
|
|
82594
|
+
await sleep(intervalMs);
|
|
82595
|
+
const poll = await fetchFn(device.token, {
|
|
82596
|
+
method: "POST",
|
|
82597
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
82598
|
+
body: JSON.stringify({
|
|
82599
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
82600
|
+
device_code: code.device_code,
|
|
82601
|
+
client_id: clientId
|
|
82602
|
+
})
|
|
82603
|
+
});
|
|
82604
|
+
const payload = await poll.json().catch(() => null);
|
|
82605
|
+
if (!poll.ok) {
|
|
82606
|
+
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
82607
|
+
if (error48 === "authorization_pending") continue;
|
|
82608
|
+
if (error48 === "slow_down") {
|
|
82609
|
+
intervalMs += 5e3;
|
|
82610
|
+
continue;
|
|
82611
|
+
}
|
|
82612
|
+
if (error48 === "access_denied") return { status: "denied" };
|
|
82613
|
+
if (error48 === "expired_token") return { status: "expired" };
|
|
82614
|
+
throw new Error(`link approval failed: ${error48}`);
|
|
82615
|
+
}
|
|
82616
|
+
const decision = payload?.["link"];
|
|
82617
|
+
if (!isDecision(decision)) {
|
|
82618
|
+
throw new Error("the console approved the device but returned no link decision");
|
|
82619
|
+
}
|
|
82620
|
+
return {
|
|
82621
|
+
status: "approved",
|
|
82622
|
+
decision,
|
|
82623
|
+
installationId: typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null
|
|
82624
|
+
};
|
|
82625
|
+
}
|
|
82626
|
+
return { status: "expired" };
|
|
82627
|
+
}
|
|
82628
|
+
function collectRepoFacts(root) {
|
|
82629
|
+
const git3 = (args2) => {
|
|
82630
|
+
try {
|
|
82631
|
+
return execFileSync4("git", args2, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
82632
|
+
} catch {
|
|
82633
|
+
return null;
|
|
82634
|
+
}
|
|
82635
|
+
};
|
|
82636
|
+
const roots = git3(["rev-list", "--max-parents=0", "HEAD"]);
|
|
82637
|
+
const count = git3(["rev-list", "--count", "HEAD"]);
|
|
82638
|
+
const rootCommitSha = roots?.split(/\s+/).filter(Boolean).pop();
|
|
82639
|
+
const commitCount = count && /^\d+$/.test(count) ? Number(count) : void 0;
|
|
82640
|
+
return {
|
|
82641
|
+
...rootCommitSha && /^[0-9a-f]{40,64}$/i.test(rootCommitSha) ? { rootCommitSha } : {},
|
|
82642
|
+
...typeof commitCount === "number" ? { commitCount } : {}
|
|
82643
|
+
};
|
|
82644
|
+
}
|
|
82645
|
+
var IGNORE_STARTER = `# .errataignore \u2014 the hard control over what errata may read or send.
|
|
82646
|
+
# Paths, content keywords and tags listed here are dropped from hunks and
|
|
82647
|
+
# narrative before anything leaves this machine, and an ignored path yields no
|
|
82648
|
+
# symbol anchor at all. Scrubbing is best effort; this list is absolute.
|
|
82649
|
+
# A personal list can only add to the organization's list, never weaken it.
|
|
82650
|
+
|
|
82651
|
+
# secrets and environment
|
|
82652
|
+
.env
|
|
82653
|
+
.env.*
|
|
82654
|
+
*.pem
|
|
82655
|
+
*.key
|
|
82656
|
+
*.p12
|
|
82657
|
+
secrets/
|
|
82658
|
+
credentials*
|
|
82659
|
+
|
|
82660
|
+
# fixtures and captured data
|
|
82661
|
+
fixtures/
|
|
82662
|
+
**/testdata/
|
|
82663
|
+
*.dump
|
|
82664
|
+
*.sql.gz
|
|
82665
|
+
`;
|
|
82666
|
+
function applyConsents(profile, config2, c, decidedAt, now = Date.now) {
|
|
82667
|
+
const nextConfig = {
|
|
82668
|
+
...config2,
|
|
82669
|
+
consent: {
|
|
82670
|
+
...config2.consent,
|
|
82671
|
+
sync: c.sync !== "off",
|
|
82672
|
+
telemetry: c.telemetry,
|
|
82673
|
+
contributePackages: c.packages && c.sync !== "off"
|
|
82674
|
+
},
|
|
82675
|
+
onboardedAt: config2.onboardedAt ?? now()
|
|
82676
|
+
};
|
|
82677
|
+
const nextProfile = {
|
|
82678
|
+
...profile,
|
|
82679
|
+
syncConsent: c.sync === "automatic" ? "automatic" : c.sync === "ask" ? "ask-each-time" : "disabled",
|
|
82680
|
+
linkConsents: {
|
|
82681
|
+
structure: c.structure,
|
|
82682
|
+
mineHistory: c.mineHistory,
|
|
82683
|
+
contributeHistory: c.contributeHistory && c.mineHistory && c.sync !== "off",
|
|
82684
|
+
decidedAt
|
|
82685
|
+
}
|
|
82686
|
+
};
|
|
82687
|
+
const prev = profile.linkConsents;
|
|
82688
|
+
const changed = profile.syncConsent !== nextProfile.syncConsent || config2.consent.sync !== nextConfig.consent.sync || config2.consent.telemetry !== nextConfig.consent.telemetry || config2.consent.contributePackages !== nextConfig.consent.contributePackages || !prev || prev.structure !== nextProfile.linkConsents.structure || prev.mineHistory !== nextProfile.linkConsents.mineHistory || prev.contributeHistory !== nextProfile.linkConsents.contributeHistory;
|
|
82689
|
+
return { profile: nextProfile, config: nextConfig, changed };
|
|
82690
|
+
}
|
|
82691
|
+
function applyLinkDecision(root, profile, config2, decision, now = Date.now) {
|
|
82692
|
+
const applied = applyConsents(profile, config2, decision.consents, decision.approvedAt, now);
|
|
82693
|
+
const nextConfig = applied.config;
|
|
82694
|
+
const nextProfile = {
|
|
82695
|
+
...applied.profile,
|
|
82696
|
+
projectId: decision.projectId,
|
|
82697
|
+
projectLocator: decision.locator
|
|
82698
|
+
};
|
|
82699
|
+
delete nextProfile.projectLinkDisabled;
|
|
82700
|
+
let wroteIgnore = false;
|
|
82701
|
+
if (decision.writeIgnoreStarter !== false) {
|
|
82702
|
+
const target = join34(root, ".errataignore");
|
|
82703
|
+
if (!existsSync29(target)) {
|
|
82704
|
+
writeFileSync22(target, IGNORE_STARTER, "utf8");
|
|
82705
|
+
wroteIgnore = true;
|
|
82706
|
+
}
|
|
82707
|
+
}
|
|
82708
|
+
return { profile: nextProfile, config: nextConfig, wroteIgnore };
|
|
82709
|
+
}
|
|
82710
|
+
|
|
82316
82711
|
// src/multi.ts
|
|
82317
82712
|
init_registry();
|
|
82318
82713
|
|
|
82319
82714
|
// src/adopt.ts
|
|
82320
82715
|
init_git_remote();
|
|
82321
|
-
import { existsSync as
|
|
82322
|
-
import { dirname as dirname12, join as
|
|
82716
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
82717
|
+
import { dirname as dirname12, join as join35 } from "node:path";
|
|
82323
82718
|
function findGitRoot(absPath) {
|
|
82324
82719
|
let dir = absPath;
|
|
82325
82720
|
for (let depth = 0; depth < 64; depth++) {
|
|
82326
|
-
if (
|
|
82721
|
+
if (existsSync30(join35(dir, ".git"))) return dir;
|
|
82327
82722
|
const parent = dirname12(dir);
|
|
82328
82723
|
if (parent === dir) return null;
|
|
82329
82724
|
dir = parent;
|
|
@@ -82843,7 +83238,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
82843
83238
|
records.push(rec);
|
|
82844
83239
|
void ambientLinkAll();
|
|
82845
83240
|
try {
|
|
82846
|
-
|
|
83241
|
+
writeFileSync23(
|
|
82847
83242
|
rec.engine.paths.daemonLock,
|
|
82848
83243
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
82849
83244
|
"utf8"
|
|
@@ -83056,7 +83451,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83056
83451
|
lastActiveAt = Math.max(lastActiveAt, rec.engine.lastActivityAt());
|
|
83057
83452
|
} catch {
|
|
83058
83453
|
}
|
|
83059
|
-
const reason = retireDecision({ exists:
|
|
83454
|
+
const reason = retireDecision({ exists: existsSync31(rec.root), lastActiveAt, now });
|
|
83060
83455
|
if (reason) void retireWorkspace(rec, reason);
|
|
83061
83456
|
}
|
|
83062
83457
|
};
|
|
@@ -83124,7 +83519,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83124
83519
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
83125
83520
|
try {
|
|
83126
83521
|
ensureDir(globalDir());
|
|
83127
|
-
|
|
83522
|
+
writeFileSync23(
|
|
83128
83523
|
lockPath,
|
|
83129
83524
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
83130
83525
|
"utf8"
|
|
@@ -83133,7 +83528,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83133
83528
|
}
|
|
83134
83529
|
for (const r of records) {
|
|
83135
83530
|
try {
|
|
83136
|
-
|
|
83531
|
+
writeFileSync23(
|
|
83137
83532
|
r.engine.paths.daemonLock,
|
|
83138
83533
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
83139
83534
|
"utf8"
|
|
@@ -83209,7 +83604,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83209
83604
|
} else if (re.reason === "error") {
|
|
83210
83605
|
console.warn(`[errata] project reanchor failed for ${r.engine.profile.name}: ${re.detail}`);
|
|
83211
83606
|
}
|
|
83212
|
-
if (r.engine.profile.
|
|
83607
|
+
if (r.engine.profile.projectHydratedAt && !historyInFlight.has(r.root)) {
|
|
83213
83608
|
historyInFlight.add(r.root);
|
|
83214
83609
|
const engine = r.engine;
|
|
83215
83610
|
const root = r.root;
|
|
@@ -83223,6 +83618,22 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83223
83618
|
};
|
|
83224
83619
|
void startHistoryStage(root, engine.profile, client, {
|
|
83225
83620
|
anchors: { index: anchorIndex, salt },
|
|
83621
|
+
// PS-web projects: the console's consents (Privacy tab) win over
|
|
83622
|
+
// the profile's memory; applied to config and profile here, with
|
|
83623
|
+
// the change printed so a flipped switch is visible in the log.
|
|
83624
|
+
applyConsents: (p, consents) => {
|
|
83625
|
+
const cfg2 = loadConfig();
|
|
83626
|
+
const applied = applyConsents(p, cfg2, consents, (/* @__PURE__ */ new Date()).toISOString());
|
|
83627
|
+
if (applied.changed) {
|
|
83628
|
+
saveConfig(applied.config);
|
|
83629
|
+
Object.assign(engine.profile, applied.profile);
|
|
83630
|
+
saveProfile(root, engine.profile);
|
|
83631
|
+
console.log(
|
|
83632
|
+
`[errata] consents applied from the console for ${engine.profile.name}: sync=${consents.sync} telemetry=${consents.telemetry ? "on" : "off"} packages=${consents.packages ? "on" : "off"} structure=${consents.structure ? "on" : "off"} history=${consents.mineHistory ? consents.contributeHistory ? "mine+contribute" : "mine" : "off"}`
|
|
83633
|
+
);
|
|
83634
|
+
}
|
|
83635
|
+
return applied.profile;
|
|
83636
|
+
},
|
|
83226
83637
|
saveProfile: (p) => {
|
|
83227
83638
|
Object.assign(engine.profile, p);
|
|
83228
83639
|
saveProfile(root, engine.profile);
|
|
@@ -84008,392 +84419,6 @@ function errText(err2) {
|
|
|
84008
84419
|
// src/cli.ts
|
|
84009
84420
|
init_cloud_endpoint_policy();
|
|
84010
84421
|
|
|
84011
|
-
// src/oauth-login.ts
|
|
84012
|
-
init_src7();
|
|
84013
|
-
init_cloud_auth();
|
|
84014
|
-
import { createServer } from "node:http";
|
|
84015
|
-
var DEFAULT_OAUTH_SCOPE = "openid profile graph:read graph:write mcp:tools";
|
|
84016
|
-
var strip = (u) => u.replace(/\/+$/, "");
|
|
84017
|
-
function deviceEndpoints(tokenEndpoint) {
|
|
84018
|
-
const token = new URL(tokenEndpoint);
|
|
84019
|
-
const authRoot = token.pathname.replace(/\/(?:oauth2|mcp)\/token\/?$/, "");
|
|
84020
|
-
if (authRoot === token.pathname) throw new Error("authorization server exposes no device endpoint");
|
|
84021
|
-
const prefix = authRoot.replace(/\/api\/auth\/?$/, "");
|
|
84022
|
-
const at = (path2) => new URL(`${path2}`, `${token.origin}${prefix || "/"}`).toString();
|
|
84023
|
-
return {
|
|
84024
|
-
code: at(`${prefix}/api/auth/device/code`),
|
|
84025
|
-
token: at(`${prefix}/api/auth/device/token`),
|
|
84026
|
-
resource: at(`${prefix}/api/gate/session-token`)
|
|
84027
|
-
};
|
|
84028
|
-
}
|
|
84029
|
-
async function loginOAuthDevice(opts) {
|
|
84030
|
-
const fetchFn = opts.fetchFn ?? fetch;
|
|
84031
|
-
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
84032
|
-
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
84033
|
-
const clientId = oauthClientId();
|
|
84034
|
-
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
84035
|
-
const codeResponse = await fetchFn(device.code, {
|
|
84036
|
-
method: "POST",
|
|
84037
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
84038
|
-
body: JSON.stringify({ client_id: clientId, scope })
|
|
84039
|
-
});
|
|
84040
|
-
if (!codeResponse.ok) {
|
|
84041
|
-
throw new Error(`device authorization failed: HTTP ${codeResponse.status} ${(await codeResponse.text()).slice(0, 200)}`);
|
|
84042
|
-
}
|
|
84043
|
-
const code = await codeResponse.json();
|
|
84044
|
-
if (!code.device_code || !code.user_code || !code.verification_uri || !code.expires_in) {
|
|
84045
|
-
throw new Error("device authorization returned an incomplete response");
|
|
84046
|
-
}
|
|
84047
|
-
opts.onVerification?.({
|
|
84048
|
-
url: code.verification_uri_complete ?? code.verification_uri,
|
|
84049
|
-
userCode: code.user_code,
|
|
84050
|
-
expiresInSec: code.expires_in
|
|
84051
|
-
});
|
|
84052
|
-
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
84053
|
-
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
84054
|
-
let deviceSession = null;
|
|
84055
|
-
let approvedInstallation = null;
|
|
84056
|
-
while (Date.now() < deadline) {
|
|
84057
|
-
await (opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(intervalMs);
|
|
84058
|
-
const poll = await fetchFn(device.token, {
|
|
84059
|
-
method: "POST",
|
|
84060
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
84061
|
-
body: JSON.stringify({
|
|
84062
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
84063
|
-
device_code: code.device_code,
|
|
84064
|
-
client_id: clientId
|
|
84065
|
-
})
|
|
84066
|
-
});
|
|
84067
|
-
const payload = await poll.json().catch(() => null);
|
|
84068
|
-
if (!poll.ok) {
|
|
84069
|
-
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
84070
|
-
if (error48 === "authorization_pending") continue;
|
|
84071
|
-
if (error48 === "slow_down") {
|
|
84072
|
-
intervalMs += 5e3;
|
|
84073
|
-
continue;
|
|
84074
|
-
}
|
|
84075
|
-
throw new Error(`device authorization failed: ${error48}`);
|
|
84076
|
-
}
|
|
84077
|
-
deviceSession = typeof payload?.["access_token"] === "string" ? payload["access_token"] : null;
|
|
84078
|
-
approvedInstallation = typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null;
|
|
84079
|
-
break;
|
|
84080
|
-
}
|
|
84081
|
-
if (!deviceSession || !approvedInstallation) throw new Error("device authorization expired");
|
|
84082
|
-
if (approvedInstallation !== opts.installationId) {
|
|
84083
|
-
throw new Error("approved installation does not match the terminal request");
|
|
84084
|
-
}
|
|
84085
|
-
const resourceResponse = await fetchFn(device.resource, {
|
|
84086
|
-
method: "POST",
|
|
84087
|
-
headers: {
|
|
84088
|
-
authorization: `Bearer ${deviceSession}`,
|
|
84089
|
-
"content-type": "application/json",
|
|
84090
|
-
accept: "application/json"
|
|
84091
|
-
},
|
|
84092
|
-
body: JSON.stringify({
|
|
84093
|
-
installationId: approvedInstallation,
|
|
84094
|
-
clientId,
|
|
84095
|
-
scopes: scope.split(/\s+/).filter((value) => !["openid", "profile", "email", "offline_access"].includes(value))
|
|
84096
|
-
})
|
|
84097
|
-
});
|
|
84098
|
-
const resource = await resourceResponse.json().catch(() => null);
|
|
84099
|
-
if (!resourceResponse.ok || typeof resource?.["access_token"] !== "string") {
|
|
84100
|
-
throw new Error(`device resource exchange failed: HTTP ${resourceResponse.status}`);
|
|
84101
|
-
}
|
|
84102
|
-
return {
|
|
84103
|
-
installationId: approvedInstallation,
|
|
84104
|
-
clientId,
|
|
84105
|
-
tokenEndpoint: device.resource,
|
|
84106
|
-
tokens: {
|
|
84107
|
-
accessToken: resource["access_token"],
|
|
84108
|
-
refreshToken: deviceSession,
|
|
84109
|
-
...typeof resource["expires_in"] === "number" ? { expiresInSec: resource["expires_in"] } : {}
|
|
84110
|
-
}
|
|
84111
|
-
};
|
|
84112
|
-
}
|
|
84113
|
-
async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
|
|
84114
|
-
let consoleUrl = cloudUrl;
|
|
84115
|
-
try {
|
|
84116
|
-
const prm = await fetchFn(`${strip(cloudUrl)}/.well-known/oauth-protected-resource`);
|
|
84117
|
-
if (prm.ok) {
|
|
84118
|
-
const j = await prm.json();
|
|
84119
|
-
if (j.authorization_servers?.[0]) consoleUrl = j.authorization_servers[0];
|
|
84120
|
-
}
|
|
84121
|
-
} catch {
|
|
84122
|
-
}
|
|
84123
|
-
try {
|
|
84124
|
-
const asm = await fetchFn(`${strip(consoleUrl)}/.well-known/oauth-authorization-server`);
|
|
84125
|
-
if (asm.ok) {
|
|
84126
|
-
const j = await asm.json();
|
|
84127
|
-
if (j.authorization_endpoint && j.token_endpoint) {
|
|
84128
|
-
return {
|
|
84129
|
-
authorizationEndpoint: j.authorization_endpoint,
|
|
84130
|
-
tokenEndpoint: j.token_endpoint,
|
|
84131
|
-
...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {}
|
|
84132
|
-
};
|
|
84133
|
-
}
|
|
84134
|
-
}
|
|
84135
|
-
} catch {
|
|
84136
|
-
}
|
|
84137
|
-
const base = strip(consoleUrl);
|
|
84138
|
-
return {
|
|
84139
|
-
authorizationEndpoint: `${base}/api/auth/oauth2/authorize`,
|
|
84140
|
-
tokenEndpoint: `${base}/api/auth/oauth2/token`
|
|
84141
|
-
};
|
|
84142
|
-
}
|
|
84143
|
-
function buildAuthorizeUrl(endpoint, p) {
|
|
84144
|
-
const u = new URL(endpoint);
|
|
84145
|
-
u.searchParams.set("response_type", "code");
|
|
84146
|
-
u.searchParams.set("client_id", p.clientId);
|
|
84147
|
-
u.searchParams.set("redirect_uri", p.redirectUri);
|
|
84148
|
-
u.searchParams.set("scope", p.scope);
|
|
84149
|
-
u.searchParams.set("state", p.state);
|
|
84150
|
-
u.searchParams.set("code_challenge", p.challenge);
|
|
84151
|
-
u.searchParams.set("code_challenge_method", p.method);
|
|
84152
|
-
return u.toString();
|
|
84153
|
-
}
|
|
84154
|
-
async function loginOAuthLoopback(opts) {
|
|
84155
|
-
const fetchFn = opts.fetchFn ?? fetch;
|
|
84156
|
-
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
84157
|
-
const pkce = generatePkce();
|
|
84158
|
-
const state = randomState();
|
|
84159
|
-
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
84160
|
-
const { code, redirectUri, clientId } = await new Promise(
|
|
84161
|
-
(resolve7, reject) => {
|
|
84162
|
-
const server = createServer((req, res) => {
|
|
84163
|
-
const u = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
84164
|
-
if (u.pathname !== "/callback") {
|
|
84165
|
-
res.writeHead(404);
|
|
84166
|
-
res.end();
|
|
84167
|
-
return;
|
|
84168
|
-
}
|
|
84169
|
-
const addr2 = server.address();
|
|
84170
|
-
const port = typeof addr2 === "object" && addr2 ? addr2.port : 0;
|
|
84171
|
-
const err2 = u.searchParams.get("error");
|
|
84172
|
-
const code2 = u.searchParams.get("code");
|
|
84173
|
-
const returnedState = u.searchParams.get("state");
|
|
84174
|
-
if (err2 || !code2 || returnedState !== state) {
|
|
84175
|
-
res.writeHead(400, { "content-type": "text/plain" });
|
|
84176
|
-
res.end(`login failed: ${err2 ?? (returnedState !== state ? "state_mismatch" : "no_code")}`);
|
|
84177
|
-
server.close();
|
|
84178
|
-
reject(new Error(err2 ?? "invalid_callback"));
|
|
84179
|
-
return;
|
|
84180
|
-
}
|
|
84181
|
-
res.writeHead(200, { "content-type": "text/html" });
|
|
84182
|
-
res.end("<html><body>inErrata: you're logged in. You can close this tab.</body></html>");
|
|
84183
|
-
server.close();
|
|
84184
|
-
resolve7({ code: code2, redirectUri: `http://127.0.0.1:${port}/callback`, clientId: activeClientId });
|
|
84185
|
-
});
|
|
84186
|
-
let activeClientId = oauthClientId();
|
|
84187
|
-
server.on("error", reject);
|
|
84188
|
-
server.listen(0, "127.0.0.1", () => {
|
|
84189
|
-
void (async () => {
|
|
84190
|
-
try {
|
|
84191
|
-
const addr2 = server.address();
|
|
84192
|
-
const port = typeof addr2 === "object" && addr2 ? addr2.port : 0;
|
|
84193
|
-
const redirectUri2 = `http://127.0.0.1:${port}/callback`;
|
|
84194
|
-
if (endpoints.registrationEndpoint) {
|
|
84195
|
-
const registered = await registerOAuthClient(fetchFn, endpoints.registrationEndpoint, {
|
|
84196
|
-
redirectUri: redirectUri2,
|
|
84197
|
-
scope,
|
|
84198
|
-
clientName: "errata daemon"
|
|
84199
|
-
});
|
|
84200
|
-
activeClientId = registered.clientId;
|
|
84201
|
-
}
|
|
84202
|
-
const url2 = buildAuthorizeUrl(endpoints.authorizationEndpoint, {
|
|
84203
|
-
clientId: activeClientId,
|
|
84204
|
-
redirectUri: redirectUri2,
|
|
84205
|
-
scope,
|
|
84206
|
-
state,
|
|
84207
|
-
challenge: pkce.challenge,
|
|
84208
|
-
method: pkce.method
|
|
84209
|
-
});
|
|
84210
|
-
if (opts.open) opts.open(url2);
|
|
84211
|
-
else console.log(`approve this login in your browser:
|
|
84212
|
-
${url2}`);
|
|
84213
|
-
} catch (err2) {
|
|
84214
|
-
server.close();
|
|
84215
|
-
reject(err2);
|
|
84216
|
-
}
|
|
84217
|
-
})();
|
|
84218
|
-
});
|
|
84219
|
-
if (opts.timeoutMs) {
|
|
84220
|
-
setTimeout(() => {
|
|
84221
|
-
server.close();
|
|
84222
|
-
reject(new Error("login timed out \u2014 run `errata login` again"));
|
|
84223
|
-
}, opts.timeoutMs).unref?.();
|
|
84224
|
-
}
|
|
84225
|
-
}
|
|
84226
|
-
);
|
|
84227
|
-
const tokens = await exchangeAuthorizationCode(fetchFn, endpoints.tokenEndpoint, {
|
|
84228
|
-
code,
|
|
84229
|
-
codeVerifier: pkce.verifier,
|
|
84230
|
-
redirectUri,
|
|
84231
|
-
clientId
|
|
84232
|
-
});
|
|
84233
|
-
return { tokens, tokenEndpoint: endpoints.tokenEndpoint, clientId };
|
|
84234
|
-
}
|
|
84235
|
-
|
|
84236
|
-
// src/link-flow.ts
|
|
84237
|
-
init_cloud_auth();
|
|
84238
|
-
import { createHash as createHash15 } from "node:crypto";
|
|
84239
|
-
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
84240
|
-
import { existsSync as existsSync31, writeFileSync as writeFileSync23 } from "node:fs";
|
|
84241
|
-
import { join as join35 } from "node:path";
|
|
84242
|
-
function remoteFingerprint(locator) {
|
|
84243
|
-
return createHash15("sha256").update(locator).digest("hex");
|
|
84244
|
-
}
|
|
84245
|
-
function isDecision(value) {
|
|
84246
|
-
if (!value || typeof value !== "object") return false;
|
|
84247
|
-
const v = value;
|
|
84248
|
-
return typeof v["projectId"] === "string" && typeof v["locator"] === "string" && (v["visibility"] === "public" || v["visibility"] === "private") && typeof v["consents"] === "object" && v["consents"] !== null;
|
|
84249
|
-
}
|
|
84250
|
-
async function linkThroughConsole(opts) {
|
|
84251
|
-
const fetchFn = opts.fetchFn ?? fetch;
|
|
84252
|
-
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
84253
|
-
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
84254
|
-
const clientId = oauthClientId();
|
|
84255
|
-
const link = {
|
|
84256
|
-
locator: opts.facts.locator,
|
|
84257
|
-
remoteFingerprint: remoteFingerprint(opts.facts.locator),
|
|
84258
|
-
...opts.facts.name ? { name: opts.facts.name } : {},
|
|
84259
|
-
...opts.facts.rootCommitSha ? { rootCommitSha: opts.facts.rootCommitSha } : {},
|
|
84260
|
-
...opts.facts.installationId ? { installationId: opts.facts.installationId } : {},
|
|
84261
|
-
...opts.facts.agents && opts.facts.agents.length > 0 ? { agents: opts.facts.agents.slice(0, 12) } : {},
|
|
84262
|
-
...typeof opts.facts.commitCount === "number" ? { commitCount: opts.facts.commitCount } : {}
|
|
84263
|
-
};
|
|
84264
|
-
const codeResponse = await fetchFn(device.code, {
|
|
84265
|
-
method: "POST",
|
|
84266
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
84267
|
-
body: JSON.stringify({ client_id: clientId, scope: "project:link", link })
|
|
84268
|
-
});
|
|
84269
|
-
if (!codeResponse.ok) {
|
|
84270
|
-
const text = (await codeResponse.text()).slice(0, 200);
|
|
84271
|
-
if (codeResponse.status === 404) {
|
|
84272
|
-
throw new Error("this console does not offer the link flow yet (device authorization is off)");
|
|
84273
|
-
}
|
|
84274
|
-
throw new Error(`link request failed: HTTP ${codeResponse.status} ${text}`);
|
|
84275
|
-
}
|
|
84276
|
-
const code = await codeResponse.json();
|
|
84277
|
-
if (!code.device_code || !code.user_code || !code.verification_uri || !code.expires_in) {
|
|
84278
|
-
throw new Error("link request returned an incomplete response");
|
|
84279
|
-
}
|
|
84280
|
-
opts.onVerification?.({
|
|
84281
|
-
url: code.verification_uri_complete ?? code.verification_uri,
|
|
84282
|
-
userCode: code.user_code,
|
|
84283
|
-
expiresInSec: code.expires_in
|
|
84284
|
-
});
|
|
84285
|
-
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
84286
|
-
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
84287
|
-
const sleep = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
84288
|
-
while (Date.now() < deadline) {
|
|
84289
|
-
await sleep(intervalMs);
|
|
84290
|
-
const poll = await fetchFn(device.token, {
|
|
84291
|
-
method: "POST",
|
|
84292
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
84293
|
-
body: JSON.stringify({
|
|
84294
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
84295
|
-
device_code: code.device_code,
|
|
84296
|
-
client_id: clientId
|
|
84297
|
-
})
|
|
84298
|
-
});
|
|
84299
|
-
const payload = await poll.json().catch(() => null);
|
|
84300
|
-
if (!poll.ok) {
|
|
84301
|
-
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
84302
|
-
if (error48 === "authorization_pending") continue;
|
|
84303
|
-
if (error48 === "slow_down") {
|
|
84304
|
-
intervalMs += 5e3;
|
|
84305
|
-
continue;
|
|
84306
|
-
}
|
|
84307
|
-
if (error48 === "access_denied") return { status: "denied" };
|
|
84308
|
-
if (error48 === "expired_token") return { status: "expired" };
|
|
84309
|
-
throw new Error(`link approval failed: ${error48}`);
|
|
84310
|
-
}
|
|
84311
|
-
const decision = payload?.["link"];
|
|
84312
|
-
if (!isDecision(decision)) {
|
|
84313
|
-
throw new Error("the console approved the device but returned no link decision");
|
|
84314
|
-
}
|
|
84315
|
-
return {
|
|
84316
|
-
status: "approved",
|
|
84317
|
-
decision,
|
|
84318
|
-
installationId: typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null
|
|
84319
|
-
};
|
|
84320
|
-
}
|
|
84321
|
-
return { status: "expired" };
|
|
84322
|
-
}
|
|
84323
|
-
function collectRepoFacts(root) {
|
|
84324
|
-
const git3 = (args2) => {
|
|
84325
|
-
try {
|
|
84326
|
-
return execFileSync4("git", args2, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
84327
|
-
} catch {
|
|
84328
|
-
return null;
|
|
84329
|
-
}
|
|
84330
|
-
};
|
|
84331
|
-
const roots = git3(["rev-list", "--max-parents=0", "HEAD"]);
|
|
84332
|
-
const count = git3(["rev-list", "--count", "HEAD"]);
|
|
84333
|
-
const rootCommitSha = roots?.split(/\s+/).filter(Boolean).pop();
|
|
84334
|
-
const commitCount = count && /^\d+$/.test(count) ? Number(count) : void 0;
|
|
84335
|
-
return {
|
|
84336
|
-
...rootCommitSha && /^[0-9a-f]{40,64}$/i.test(rootCommitSha) ? { rootCommitSha } : {},
|
|
84337
|
-
...typeof commitCount === "number" ? { commitCount } : {}
|
|
84338
|
-
};
|
|
84339
|
-
}
|
|
84340
|
-
var IGNORE_STARTER = `# .errataignore \u2014 the hard control over what errata may read or send.
|
|
84341
|
-
# Paths, content keywords and tags listed here are dropped from hunks and
|
|
84342
|
-
# narrative before anything leaves this machine, and an ignored path yields no
|
|
84343
|
-
# symbol anchor at all. Scrubbing is best effort; this list is absolute.
|
|
84344
|
-
# A personal list can only add to the organization's list, never weaken it.
|
|
84345
|
-
|
|
84346
|
-
# secrets and environment
|
|
84347
|
-
.env
|
|
84348
|
-
.env.*
|
|
84349
|
-
*.pem
|
|
84350
|
-
*.key
|
|
84351
|
-
*.p12
|
|
84352
|
-
secrets/
|
|
84353
|
-
credentials*
|
|
84354
|
-
|
|
84355
|
-
# fixtures and captured data
|
|
84356
|
-
fixtures/
|
|
84357
|
-
**/testdata/
|
|
84358
|
-
*.dump
|
|
84359
|
-
*.sql.gz
|
|
84360
|
-
`;
|
|
84361
|
-
function applyLinkDecision(root, profile, config2, decision, now = Date.now) {
|
|
84362
|
-
const c = decision.consents;
|
|
84363
|
-
const nextConfig = {
|
|
84364
|
-
...config2,
|
|
84365
|
-
consent: {
|
|
84366
|
-
...config2.consent,
|
|
84367
|
-
sync: c.sync !== "off",
|
|
84368
|
-
telemetry: c.telemetry,
|
|
84369
|
-
contributePackages: c.packages && c.sync !== "off"
|
|
84370
|
-
},
|
|
84371
|
-
onboardedAt: config2.onboardedAt ?? now()
|
|
84372
|
-
};
|
|
84373
|
-
const nextProfile = {
|
|
84374
|
-
...profile,
|
|
84375
|
-
syncConsent: c.sync === "automatic" ? "automatic" : c.sync === "ask" ? "ask-each-time" : "disabled",
|
|
84376
|
-
projectId: decision.projectId,
|
|
84377
|
-
projectLocator: decision.locator,
|
|
84378
|
-
linkConsents: {
|
|
84379
|
-
structure: c.structure,
|
|
84380
|
-
mineHistory: c.mineHistory,
|
|
84381
|
-
contributeHistory: c.contributeHistory && c.sync !== "off",
|
|
84382
|
-
decidedAt: decision.approvedAt
|
|
84383
|
-
}
|
|
84384
|
-
};
|
|
84385
|
-
delete nextProfile.projectLinkDisabled;
|
|
84386
|
-
let wroteIgnore = false;
|
|
84387
|
-
if (decision.writeIgnoreStarter !== false) {
|
|
84388
|
-
const target = join35(root, ".errataignore");
|
|
84389
|
-
if (!existsSync31(target)) {
|
|
84390
|
-
writeFileSync23(target, IGNORE_STARTER, "utf8");
|
|
84391
|
-
wroteIgnore = true;
|
|
84392
|
-
}
|
|
84393
|
-
}
|
|
84394
|
-
return { profile: nextProfile, config: nextConfig, wroteIgnore };
|
|
84395
|
-
}
|
|
84396
|
-
|
|
84397
84422
|
// src/device-login.ts
|
|
84398
84423
|
init_src7();
|
|
84399
84424
|
var DEFAULT_SCOPE = "openid profile graph:read graph:write mcp:tools";
|
|
@@ -86076,6 +86101,13 @@ async function cmdLink(args2) {
|
|
|
86076
86101
|
}
|
|
86077
86102
|
const consents = historyConsents(applied.profile);
|
|
86078
86103
|
const reported = await reportHistoryStage(authedCloudClient(applied.config), applied.profile, (line) => console.warn(line));
|
|
86104
|
+
if (reported?.consents) {
|
|
86105
|
+
const synced = applyConsents(applied.profile, applied.config, reported.consents, (/* @__PURE__ */ new Date()).toISOString());
|
|
86106
|
+
if (synced.changed) {
|
|
86107
|
+
saveProfile(ROOT, synced.profile);
|
|
86108
|
+
saveConfig(synced.config);
|
|
86109
|
+
}
|
|
86110
|
+
}
|
|
86079
86111
|
if (!consents.mineHistory) console.log("history: not mined (consent off)");
|
|
86080
86112
|
else if (reported?.stopRequested) console.log("history: a stop request is standing in the console; the daemon honours it");
|
|
86081
86113
|
else console.log(`history: consents recorded${consents.contributeHistory ? "" : " (mine only)"} \xB7 the daemon walks the repo on its next pass`);
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -15140,7 +15140,7 @@ var init_symbol_intent = __esm({
|
|
|
15140
15140
|
});
|
|
15141
15141
|
|
|
15142
15142
|
// ../../packages/shared/src/wire.ts
|
|
15143
|
-
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15143
|
+
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15144
15144
|
var init_wire = __esm({
|
|
15145
15145
|
"../../packages/shared/src/wire.ts"() {
|
|
15146
15146
|
"use strict";
|
|
@@ -15241,6 +15241,8 @@ var init_wire = __esm({
|
|
|
15241
15241
|
independent: external_exports.number().int().min(0).optional(),
|
|
15242
15242
|
inferredIndependent: external_exports.number().int().min(0).optional()
|
|
15243
15243
|
});
|
|
15244
|
+
ANCHOR_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/;
|
|
15245
|
+
ANCHOR_BODY_HASH_RE = /^[0-9a-f]{8,64}$/;
|
|
15244
15246
|
CastaliaIngestEdgeSchema = external_exports.object({
|
|
15245
15247
|
fromCanonicalId: external_exports.string().min(6).max(160),
|
|
15246
15248
|
toCanonicalId: external_exports.string().min(6).max(160),
|
|
@@ -15259,8 +15261,8 @@ var init_wire = __esm({
|
|
|
15259
15261
|
* (reanchor) compares the hash with its local symbol's `bodyHash` to
|
|
15260
15262
|
* classify the anchor current / pre-change; absent ⇒ the pre-versioning
|
|
15261
15263
|
* contract, unverified. Only meaningful on `ANCHORED_AT`. */
|
|
15262
|
-
observedAtCommit: external_exports.string().regex(
|
|
15263
|
-
symbolContentHash: external_exports.string().regex(
|
|
15264
|
+
observedAtCommit: external_exports.string().regex(ANCHOR_COMMIT_SHA_RE).optional(),
|
|
15265
|
+
symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional()
|
|
15264
15266
|
}).optional()
|
|
15265
15267
|
});
|
|
15266
15268
|
SymbolSummarySidecarSchema = external_exports.record(
|