@inerrata-corporation/errata 2.0.14-dev.3125 → 2.0.14-dev.3128
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/errata.mjs +266 -173
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -81027,7 +81027,7 @@ function createWatchBreaker(deps) {
|
|
|
81027
81027
|
}
|
|
81028
81028
|
|
|
81029
81029
|
// src/engine.ts
|
|
81030
|
-
var DAEMON_VERSION = true ? "2.0.14-dev.
|
|
81030
|
+
var DAEMON_VERSION = true ? "2.0.14-dev.3128" : "2.0.0-alpha.0";
|
|
81031
81031
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
81032
81032
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
81033
81033
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -83521,6 +83521,151 @@ async function listenServer(fetchFn, port) {
|
|
|
83521
83521
|
init_registry();
|
|
83522
83522
|
init_identity2();
|
|
83523
83523
|
|
|
83524
|
+
// src/cli-identity.ts
|
|
83525
|
+
init_cloud_auth();
|
|
83526
|
+
init_config();
|
|
83527
|
+
init_consent();
|
|
83528
|
+
init_identity2();
|
|
83529
|
+
init_profile2();
|
|
83530
|
+
|
|
83531
|
+
// src/project-link.ts
|
|
83532
|
+
init_profile2();
|
|
83533
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
83534
|
+
import { promisify } from "node:util";
|
|
83535
|
+
var execFileAsync = promisify(execFile3);
|
|
83536
|
+
function isClaimedElsewhere(err2) {
|
|
83537
|
+
if (!err2 || typeof err2 !== "object") return false;
|
|
83538
|
+
const e = err2;
|
|
83539
|
+
return e.status === 409 && e.code === "claimed_elsewhere";
|
|
83540
|
+
}
|
|
83541
|
+
function claimHoldStands(onDisk) {
|
|
83542
|
+
return Boolean(onDisk && !onDisk.projectId && onDisk.projectLinkHold);
|
|
83543
|
+
}
|
|
83544
|
+
var LINK_FIELDS = [
|
|
83545
|
+
"projectId",
|
|
83546
|
+
"projectLocator",
|
|
83547
|
+
"projectLinkHold",
|
|
83548
|
+
"projectLinkDisabled",
|
|
83549
|
+
"rootCommitReportedFor"
|
|
83550
|
+
];
|
|
83551
|
+
function adoptLinkFields(into, from) {
|
|
83552
|
+
for (const k of LINK_FIELDS) {
|
|
83553
|
+
if (from[k] === void 0) delete into[k];
|
|
83554
|
+
else into[k] = from[k];
|
|
83555
|
+
}
|
|
83556
|
+
}
|
|
83557
|
+
async function readRootCommit(root) {
|
|
83558
|
+
try {
|
|
83559
|
+
const { stdout } = await execFileAsync("git", ["rev-list", "--max-parents=0", "HEAD"], {
|
|
83560
|
+
cwd: root,
|
|
83561
|
+
encoding: "utf8",
|
|
83562
|
+
timeout: 15e3,
|
|
83563
|
+
windowsHide: true
|
|
83564
|
+
});
|
|
83565
|
+
const sha2 = stdout.split(/\s+/).filter(Boolean).pop();
|
|
83566
|
+
return sha2 && /^[0-9a-f]{40,64}$/i.test(sha2) ? sha2.toLowerCase() : null;
|
|
83567
|
+
} catch {
|
|
83568
|
+
return null;
|
|
83569
|
+
}
|
|
83570
|
+
}
|
|
83571
|
+
async function ensureProjectLink(root, profile, client, rootCommit = readRootCommit) {
|
|
83572
|
+
if (profile.projectLinkDisabled) return { linked: false, reason: "disabled" };
|
|
83573
|
+
const locator = profile.repoLocator;
|
|
83574
|
+
if (!locator) return { linked: false, reason: "no-locator" };
|
|
83575
|
+
if (profile.projectId && profile.projectLocator === locator) {
|
|
83576
|
+
if (profile.rootCommitReportedFor !== profile.projectId && client.recordProjectRootCommit) {
|
|
83577
|
+
const sha2 = await rootCommit(root);
|
|
83578
|
+
if (sha2) {
|
|
83579
|
+
try {
|
|
83580
|
+
await client.recordProjectRootCommit(profile.projectId, sha2);
|
|
83581
|
+
profile.rootCommitReportedFor = profile.projectId;
|
|
83582
|
+
saveProfile(root, profile);
|
|
83583
|
+
} catch {
|
|
83584
|
+
}
|
|
83585
|
+
}
|
|
83586
|
+
}
|
|
83587
|
+
return { linked: false, reason: "already-linked" };
|
|
83588
|
+
}
|
|
83589
|
+
try {
|
|
83590
|
+
const sha2 = await rootCommit(root);
|
|
83591
|
+
const res = await client.resolveProject(locator, profile.name, sha2 ?? void 0);
|
|
83592
|
+
profile.projectId = res.project.id;
|
|
83593
|
+
profile.projectLocator = locator;
|
|
83594
|
+
if (sha2) profile.rootCommitReportedFor = res.project.id;
|
|
83595
|
+
delete profile.projectLinkHold;
|
|
83596
|
+
saveProfile(root, profile);
|
|
83597
|
+
return { linked: true, projectId: res.project.id, created: res.created };
|
|
83598
|
+
} catch (err2) {
|
|
83599
|
+
if (isClaimedElsewhere(err2)) {
|
|
83600
|
+
if (profile.projectLinkHold?.locator !== locator) {
|
|
83601
|
+
profile.projectLinkHold = { reason: "claimed-elsewhere", locator, since: Date.now() };
|
|
83602
|
+
saveProfile(root, profile);
|
|
83603
|
+
}
|
|
83604
|
+
return {
|
|
83605
|
+
linked: false,
|
|
83606
|
+
reason: "held",
|
|
83607
|
+
detail: "this repo is already on errata in another workspace \u2014 run `errata link` to join it or create your own project"
|
|
83608
|
+
};
|
|
83609
|
+
}
|
|
83610
|
+
return {
|
|
83611
|
+
linked: false,
|
|
83612
|
+
reason: "error",
|
|
83613
|
+
detail: err2 instanceof Error ? err2.message : String(err2)
|
|
83614
|
+
};
|
|
83615
|
+
}
|
|
83616
|
+
}
|
|
83617
|
+
|
|
83618
|
+
// src/cli-identity.ts
|
|
83619
|
+
init_registry();
|
|
83620
|
+
function workspaceCloud(cfg, entry, env2 = process.env) {
|
|
83621
|
+
if (registryCorrupt() && !env2["ERRATA_CONFIG_PATH"]) throw new IdentityBlockedError("workspace registry is unreadable");
|
|
83622
|
+
const identity = resolveWorkspaceIdentity(cfg, entry, env2);
|
|
83623
|
+
if (identity.invalid) throw new IdentityBlockedError(identity.reason);
|
|
83624
|
+
const name2 = identity.profileName ?? cfg.activeInstallationProfile;
|
|
83625
|
+
const profile = name2 ? cfg.installationProfiles[name2] : void 0;
|
|
83626
|
+
if (name2 && !profile) throw new IdentityBlockedError(`installation profile not found: ${name2}`);
|
|
83627
|
+
const config2 = profile ? { ...cfg, ...profile, activeInstallationProfile: name2 } : cfg;
|
|
83628
|
+
return {
|
|
83629
|
+
identity,
|
|
83630
|
+
config: config2,
|
|
83631
|
+
profile,
|
|
83632
|
+
hasCredential: hasCloudCredential(config2),
|
|
83633
|
+
client: name2 ? authedCloudClientForProfile(cfg, name2) : authedCloudClient(cfg),
|
|
83634
|
+
profileName: name2
|
|
83635
|
+
};
|
|
83636
|
+
}
|
|
83637
|
+
function configWithDeviceLogin(cfg, input) {
|
|
83638
|
+
const name2 = input.profileName.trim();
|
|
83639
|
+
if (!name2 || name2.length > 80) throw new Error("profile name must be 1\u201380 characters");
|
|
83640
|
+
const selected = input.makeDefault || cfg.activeInstallationProfile === name2;
|
|
83641
|
+
return {
|
|
83642
|
+
...cfg,
|
|
83643
|
+
...selected ? { ...input.profile, activeInstallationProfile: name2 } : {},
|
|
83644
|
+
installationProfiles: { ...cfg.installationProfiles, [name2]: input.profile }
|
|
83645
|
+
};
|
|
83646
|
+
}
|
|
83647
|
+
async function saveVerifiedInstallationProfile(name2, installationId, cfg) {
|
|
83648
|
+
const result = await authedCloudClient(cfg).context();
|
|
83649
|
+
if (result.context.installation_id?.toLowerCase() !== installationId.toLowerCase()) {
|
|
83650
|
+
throw new Error("credential belongs to a different installation (or is unbound); use login --device for the requested installation");
|
|
83651
|
+
}
|
|
83652
|
+
return saveInstallationProfile(name2, installationId, cfg);
|
|
83653
|
+
}
|
|
83654
|
+
async function linkRegisteredWorkspaces(cfg, loggedInProfile = cfg.activeInstallationProfile, log = console.log, env2 = process.env) {
|
|
83655
|
+
for (const entry of listWorkspaces()) {
|
|
83656
|
+
try {
|
|
83657
|
+
const cloud = workspaceCloud(cfg, entry, env2);
|
|
83658
|
+
if (cloud.profileName !== loggedInProfile || !cloud.hasCredential) continue;
|
|
83659
|
+
const profile = loadProfile(entry.path);
|
|
83660
|
+
if (!profile || !effectiveConsent(cloud.config, profile).sync) continue;
|
|
83661
|
+
refreshRepoLocator(entry.path, profile);
|
|
83662
|
+
const out2 = await ensureProjectLink(entry.path, profile, cloud.client);
|
|
83663
|
+
if (out2.linked) log(` linked ${profile.name} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""} \xB7 profile ${cloud.profileName ?? "default"}`);
|
|
83664
|
+
} catch {
|
|
83665
|
+
}
|
|
83666
|
+
}
|
|
83667
|
+
}
|
|
83668
|
+
|
|
83524
83669
|
// src/instance-receipts.ts
|
|
83525
83670
|
import { createHash as createHash18 } from "node:crypto";
|
|
83526
83671
|
var FIELDS = ["contributedAtSeq", "cloudNodeId", "anchorsContributedDigest", "projectAnchorsContributedDigest", "semanticEdgesContributedDigest", "shipRefusedSinceSeq", "shipRefusedCount", "shipRefusedReason", "shipRefusedFingerprint"];
|
|
@@ -84825,12 +84970,12 @@ function startUpdatePoller(opts) {
|
|
|
84825
84970
|
const check2 = opts.check ?? (() => checkForUpdate(opts.channel));
|
|
84826
84971
|
const base = opts.intervalMs ?? POLL_INTERVAL_MS[opts.channel];
|
|
84827
84972
|
let pending = null;
|
|
84828
|
-
let
|
|
84973
|
+
let inFlight2 = false;
|
|
84829
84974
|
let timer = null;
|
|
84830
84975
|
let stopped = false;
|
|
84831
84976
|
const runOnce = async () => {
|
|
84832
|
-
if (
|
|
84833
|
-
|
|
84977
|
+
if (inFlight2) return;
|
|
84978
|
+
inFlight2 = true;
|
|
84834
84979
|
try {
|
|
84835
84980
|
const status = await check2();
|
|
84836
84981
|
if (status.latest === null) return;
|
|
@@ -84840,7 +84985,7 @@ function startUpdatePoller(opts) {
|
|
|
84840
84985
|
if (changed) opts.onChange?.(pending);
|
|
84841
84986
|
} catch {
|
|
84842
84987
|
} finally {
|
|
84843
|
-
|
|
84988
|
+
inFlight2 = false;
|
|
84844
84989
|
}
|
|
84845
84990
|
};
|
|
84846
84991
|
const schedule = () => {
|
|
@@ -84912,93 +85057,6 @@ function liveCloudClient(src) {
|
|
|
84912
85057
|
// src/multi.ts
|
|
84913
85058
|
init_identity2();
|
|
84914
85059
|
|
|
84915
|
-
// src/project-link.ts
|
|
84916
|
-
init_profile2();
|
|
84917
|
-
import { execFile as execFile3 } from "node:child_process";
|
|
84918
|
-
import { promisify } from "node:util";
|
|
84919
|
-
var execFileAsync = promisify(execFile3);
|
|
84920
|
-
function isClaimedElsewhere(err2) {
|
|
84921
|
-
if (!err2 || typeof err2 !== "object") return false;
|
|
84922
|
-
const e = err2;
|
|
84923
|
-
return e.status === 409 && e.code === "claimed_elsewhere";
|
|
84924
|
-
}
|
|
84925
|
-
function claimHoldStands(onDisk) {
|
|
84926
|
-
return Boolean(onDisk && !onDisk.projectId && onDisk.projectLinkHold);
|
|
84927
|
-
}
|
|
84928
|
-
var LINK_FIELDS = [
|
|
84929
|
-
"projectId",
|
|
84930
|
-
"projectLocator",
|
|
84931
|
-
"projectLinkHold",
|
|
84932
|
-
"projectLinkDisabled",
|
|
84933
|
-
"rootCommitReportedFor"
|
|
84934
|
-
];
|
|
84935
|
-
function adoptLinkFields(into, from) {
|
|
84936
|
-
for (const k of LINK_FIELDS) {
|
|
84937
|
-
if (from[k] === void 0) delete into[k];
|
|
84938
|
-
else into[k] = from[k];
|
|
84939
|
-
}
|
|
84940
|
-
}
|
|
84941
|
-
async function readRootCommit(root) {
|
|
84942
|
-
try {
|
|
84943
|
-
const { stdout } = await execFileAsync("git", ["rev-list", "--max-parents=0", "HEAD"], {
|
|
84944
|
-
cwd: root,
|
|
84945
|
-
encoding: "utf8",
|
|
84946
|
-
timeout: 15e3,
|
|
84947
|
-
windowsHide: true
|
|
84948
|
-
});
|
|
84949
|
-
const sha2 = stdout.split(/\s+/).filter(Boolean).pop();
|
|
84950
|
-
return sha2 && /^[0-9a-f]{40,64}$/i.test(sha2) ? sha2.toLowerCase() : null;
|
|
84951
|
-
} catch {
|
|
84952
|
-
return null;
|
|
84953
|
-
}
|
|
84954
|
-
}
|
|
84955
|
-
async function ensureProjectLink(root, profile, client, rootCommit = readRootCommit) {
|
|
84956
|
-
if (profile.projectLinkDisabled) return { linked: false, reason: "disabled" };
|
|
84957
|
-
const locator = profile.repoLocator;
|
|
84958
|
-
if (!locator) return { linked: false, reason: "no-locator" };
|
|
84959
|
-
if (profile.projectId && profile.projectLocator === locator) {
|
|
84960
|
-
if (profile.rootCommitReportedFor !== profile.projectId && client.recordProjectRootCommit) {
|
|
84961
|
-
const sha2 = await rootCommit(root);
|
|
84962
|
-
if (sha2) {
|
|
84963
|
-
try {
|
|
84964
|
-
await client.recordProjectRootCommit(profile.projectId, sha2);
|
|
84965
|
-
profile.rootCommitReportedFor = profile.projectId;
|
|
84966
|
-
saveProfile(root, profile);
|
|
84967
|
-
} catch {
|
|
84968
|
-
}
|
|
84969
|
-
}
|
|
84970
|
-
}
|
|
84971
|
-
return { linked: false, reason: "already-linked" };
|
|
84972
|
-
}
|
|
84973
|
-
try {
|
|
84974
|
-
const sha2 = await rootCommit(root);
|
|
84975
|
-
const res = await client.resolveProject(locator, profile.name, sha2 ?? void 0);
|
|
84976
|
-
profile.projectId = res.project.id;
|
|
84977
|
-
profile.projectLocator = locator;
|
|
84978
|
-
if (sha2) profile.rootCommitReportedFor = res.project.id;
|
|
84979
|
-
delete profile.projectLinkHold;
|
|
84980
|
-
saveProfile(root, profile);
|
|
84981
|
-
return { linked: true, projectId: res.project.id, created: res.created };
|
|
84982
|
-
} catch (err2) {
|
|
84983
|
-
if (isClaimedElsewhere(err2)) {
|
|
84984
|
-
if (profile.projectLinkHold?.locator !== locator) {
|
|
84985
|
-
profile.projectLinkHold = { reason: "claimed-elsewhere", locator, since: Date.now() };
|
|
84986
|
-
saveProfile(root, profile);
|
|
84987
|
-
}
|
|
84988
|
-
return {
|
|
84989
|
-
linked: false,
|
|
84990
|
-
reason: "held",
|
|
84991
|
-
detail: "this repo is already on errata in another workspace \u2014 run `errata link` to join it or create your own project"
|
|
84992
|
-
};
|
|
84993
|
-
}
|
|
84994
|
-
return {
|
|
84995
|
-
linked: false,
|
|
84996
|
-
reason: "error",
|
|
84997
|
-
detail: err2 instanceof Error ? err2.message : String(err2)
|
|
84998
|
-
};
|
|
84999
|
-
}
|
|
85000
|
-
}
|
|
85001
|
-
|
|
85002
85060
|
// src/project-hydrate.ts
|
|
85003
85061
|
init_src11();
|
|
85004
85062
|
init_profile2();
|
|
@@ -85409,7 +85467,31 @@ import { extname as extname3 } from "node:path";
|
|
|
85409
85467
|
init_profile2();
|
|
85410
85468
|
var exec = promisify2(execFile4);
|
|
85411
85469
|
var KINDS = { function: "Function", class: "Class", method: "Method", interface: "Interface", const: "Const", enum: "Enum", typealias: "TypeAlias", namespace: "Namespace", property: "Property" };
|
|
85470
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
85412
85471
|
async function syncHistoryRevision(opts) {
|
|
85472
|
+
const current = inFlight.get(opts.root);
|
|
85473
|
+
if (current) return current;
|
|
85474
|
+
const work = (async () => {
|
|
85475
|
+
const started2 = Date.now();
|
|
85476
|
+
let changed = 0, remaining = false;
|
|
85477
|
+
const pages = Math.min(20, Math.max(1, opts.maxPages ?? 10));
|
|
85478
|
+
for (let i2 = 0; i2 < pages; i2++) {
|
|
85479
|
+
const result = await syncHistoryRevisionPage(opts);
|
|
85480
|
+
changed += result.changed;
|
|
85481
|
+
remaining = result.remaining;
|
|
85482
|
+
if (!remaining || Date.now() - started2 >= (opts.budgetMs ?? 45e3)) break;
|
|
85483
|
+
await new Promise((resolve7) => setImmediate(resolve7));
|
|
85484
|
+
}
|
|
85485
|
+
return { changed, remaining };
|
|
85486
|
+
})();
|
|
85487
|
+
inFlight.set(opts.root, work);
|
|
85488
|
+
try {
|
|
85489
|
+
return await work;
|
|
85490
|
+
} finally {
|
|
85491
|
+
if (inFlight.get(opts.root) === work) inFlight.delete(opts.root);
|
|
85492
|
+
}
|
|
85493
|
+
}
|
|
85494
|
+
async function syncHistoryRevisionPage(opts) {
|
|
85413
85495
|
const { root, profile, store, cloud, salt } = opts;
|
|
85414
85496
|
if (!profile.projectId) return { changed: 0, remaining: false };
|
|
85415
85497
|
const projectId = profile.projectId;
|
|
@@ -85419,7 +85501,8 @@ async function syncHistoryRevision(opts) {
|
|
|
85419
85501
|
const oldCursor = profile.historyRevisionCursor;
|
|
85420
85502
|
const same = oldCursor?.atCommit === atCommit;
|
|
85421
85503
|
if (same && oldCursor.complete && Date.now() - oldCursor.updatedAt < 60 * 6e4) return { changed: 0, remaining: false };
|
|
85422
|
-
const after =
|
|
85504
|
+
const after = oldCursor && !oldCursor.complete ? oldCursor.after : void 0;
|
|
85505
|
+
const sweepCommit = after ? oldCursor.atCommit : atCommit;
|
|
85423
85506
|
const page = await cloud.getHistoryOccurrences(projectId, atCommit, after);
|
|
85424
85507
|
if (!Array.isArray(page.occurrences) || page.occurrences.length > 50 || page.occurrences.some((o, i2) => o.occurrenceId <= (page.occurrences[i2 - 1]?.occurrenceId ?? after ?? "")) || page.cursor !== null && page.cursor !== page.occurrences.at(-1)?.occurrenceId) throw new Error("invalid history occurrence page");
|
|
85425
85508
|
const parents = (await git3(["rev-list", "--parents", "--max-count=8192", atCommit])).trim().split("\n").filter(Boolean).map((row) => {
|
|
@@ -85475,7 +85558,7 @@ async function syncHistoryRevision(opts) {
|
|
|
85475
85558
|
}
|
|
85476
85559
|
const response = page.occurrences.length ? await cloud.reconcileHistory(projectId, { atCommit, parents, observations }) : { atCommit, receipts: [] };
|
|
85477
85560
|
if (response.atCommit !== atCommit || response.receipts.length !== page.occurrences.length || new Set(response.receipts.map((r) => r.occurrenceId)).size !== response.receipts.length || response.receipts.some((r) => r.atCommit !== atCommit || !observations.some((o) => o.occurrenceId === r.occurrenceId))) throw new Error("incomplete history reconciliation response");
|
|
85478
|
-
|
|
85561
|
+
const headChanged = (await git3(["rev-parse", "--verify", "HEAD"])).trim() !== atCommit;
|
|
85479
85562
|
let changed = 0;
|
|
85480
85563
|
for (const occurrence of page.occurrences) {
|
|
85481
85564
|
const node2 = store.getNode(occurrence.canonicalId) ?? (occurrence.nodeId ? store.getNode(occurrence.nodeId) : null);
|
|
@@ -85491,9 +85574,9 @@ async function syncHistoryRevision(opts) {
|
|
|
85491
85574
|
} } });
|
|
85492
85575
|
changed++;
|
|
85493
85576
|
}
|
|
85494
|
-
profile.historyRevisionCursor = { atCommit, ...page.cursor ? { after: page.cursor } : {}, complete: page.cursor === null, updatedAt: Date.now() };
|
|
85577
|
+
profile.historyRevisionCursor = { atCommit: sweepCommit, ...page.cursor ? { after: page.cursor } : {}, complete: page.cursor === null, updatedAt: Date.now() };
|
|
85495
85578
|
(opts.save ?? ((p) => saveProfile(root, p)))(profile);
|
|
85496
|
-
return { changed, remaining: page.cursor !== null };
|
|
85579
|
+
return { changed, remaining: page.cursor !== null || headChanged || sweepCommit !== atCommit };
|
|
85497
85580
|
}
|
|
85498
85581
|
|
|
85499
85582
|
// src/project-history.ts
|
|
@@ -88054,6 +88137,8 @@ async function startMultiDaemon(opts = {}) {
|
|
|
88054
88137
|
// eslint-disable-next-line no-console
|
|
88055
88138
|
log: (line) => console.log(line)
|
|
88056
88139
|
});
|
|
88140
|
+
const revisionBacklog = /* @__PURE__ */ new Set();
|
|
88141
|
+
const lastAnchorPull = /* @__PURE__ */ new Map();
|
|
88057
88142
|
const pullProjectAnchors = async (r, client, salt) => {
|
|
88058
88143
|
const donePass = markPass(`anchor-pull:${r.engine.profile.name}`);
|
|
88059
88144
|
const beforeCorrections = r.engine.profile.projectHistoryCorrectionCursor ?? 0;
|
|
@@ -88070,6 +88155,8 @@ async function startMultiDaemon(opts = {}) {
|
|
|
88070
88155
|
}
|
|
88071
88156
|
try {
|
|
88072
88157
|
const revision = await syncHistoryRevision({ root: r.root, profile: r.engine.profile, store: r.engine.store, cloud: client, salt });
|
|
88158
|
+
if (revision.remaining) revisionBacklog.add(r.root);
|
|
88159
|
+
else revisionBacklog.delete(r.root);
|
|
88073
88160
|
if (revision.changed) r.engine.markContextDirty();
|
|
88074
88161
|
} catch (err2) {
|
|
88075
88162
|
console.warn(`[errata] history revision reconciliation failed for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
@@ -88086,30 +88173,39 @@ async function startMultiDaemon(opts = {}) {
|
|
|
88086
88173
|
}
|
|
88087
88174
|
};
|
|
88088
88175
|
const ANCHOR_PULL_INTERVAL_MS = 10 * 60 * 1e3;
|
|
88176
|
+
let anchorPullRunning = false;
|
|
88089
88177
|
const anchorPullAll = async () => {
|
|
88090
|
-
|
|
88091
|
-
|
|
88092
|
-
|
|
88093
|
-
const
|
|
88094
|
-
if (
|
|
88095
|
-
const
|
|
88096
|
-
|
|
88097
|
-
|
|
88098
|
-
continue;
|
|
88099
|
-
|
|
88100
|
-
|
|
88101
|
-
|
|
88102
|
-
|
|
88103
|
-
|
|
88104
|
-
|
|
88105
|
-
|
|
88106
|
-
|
|
88178
|
+
if (anchorPullRunning) return;
|
|
88179
|
+
anchorPullRunning = true;
|
|
88180
|
+
try {
|
|
88181
|
+
const c = loadConfig();
|
|
88182
|
+
if (registryCorrupt()) return;
|
|
88183
|
+
for (const r of records) {
|
|
88184
|
+
if (!revisionBacklog.has(r.root) && Date.now() - (lastAnchorPull.get(r.root) ?? 0) < ANCHOR_PULL_INTERVAL_MS) continue;
|
|
88185
|
+
const projectId = r.engine.profile.projectId;
|
|
88186
|
+
if (!projectId || !effectiveConsent(c, r.engine.profile).sync) continue;
|
|
88187
|
+
const identity = identityFor(liveWorkspaceEntry(r.entry));
|
|
88188
|
+
if (identity.invalid) {
|
|
88189
|
+
noteIdentityBlock(r.id, r.entry.name, identity);
|
|
88190
|
+
continue;
|
|
88191
|
+
}
|
|
88192
|
+
if (identity.rule !== "workspace-binding" && !hasCloudCredential(c)) continue;
|
|
88193
|
+
const client = cloudForIdentity(identity);
|
|
88194
|
+
try {
|
|
88195
|
+
const { salt } = await resolveProjectSymbolSalt(client, projectId);
|
|
88196
|
+
await pullProjectAnchors(r, client, salt);
|
|
88197
|
+
lastAnchorPull.set(r.root, Date.now());
|
|
88198
|
+
} catch (err2) {
|
|
88199
|
+
console.warn(`[errata] anchor pull skipped for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
88200
|
+
}
|
|
88107
88201
|
}
|
|
88202
|
+
} finally {
|
|
88203
|
+
anchorPullRunning = false;
|
|
88108
88204
|
}
|
|
88109
88205
|
};
|
|
88110
88206
|
const anchorPull = setInterval(() => {
|
|
88111
88207
|
void anchorPullAll();
|
|
88112
|
-
},
|
|
88208
|
+
}, 6e4);
|
|
88113
88209
|
const ambientLinkAll = async () => {
|
|
88114
88210
|
const c = loadConfig();
|
|
88115
88211
|
if (registryCorrupt()) return;
|
|
@@ -89024,7 +89120,6 @@ async function startMultiDaemon(opts = {}) {
|
|
|
89024
89120
|
// src/cli.ts
|
|
89025
89121
|
init_src5();
|
|
89026
89122
|
init_profile2();
|
|
89027
|
-
init_consent();
|
|
89028
89123
|
init_git_remote();
|
|
89029
89124
|
init_config();
|
|
89030
89125
|
init_src7();
|
|
@@ -90222,7 +90317,7 @@ Commands:
|
|
|
90222
90317
|
login Sign in with the cloud. Default: short verification URL +
|
|
90223
90318
|
typeable code (device-bridged OAuth). Flags: --browser
|
|
90224
90319
|
(loopback code flow) \xB7 --token <key> \xB7
|
|
90225
|
-
--device --installation <uuid> [--profile <name>]
|
|
90320
|
+
--device --installation <uuid> [--profile <name>] [--make-default]
|
|
90226
90321
|
(headless, installation-bound console device authorization)
|
|
90227
90322
|
logout Clear local cloud credentials
|
|
90228
90323
|
doctor [--json] Verify profile, credential authority, renewal, endpoint,
|
|
@@ -90852,6 +90947,7 @@ function parseFlags(args2) {
|
|
|
90852
90947
|
else if (a.startsWith("--token=")) out2.token = a.slice("--token=".length);
|
|
90853
90948
|
else if (a === "--oauth") out2.oauth = true;
|
|
90854
90949
|
else if (a === "--device") out2.device = true;
|
|
90950
|
+
else if (a === "--make-default") out2.makeDefault = true;
|
|
90855
90951
|
else if (a === "--browser") out2.browser = true;
|
|
90856
90952
|
else if (a === "--installation") out2.installation = args2[++i2];
|
|
90857
90953
|
else if (a.startsWith("--installation=")) out2.installation = a.slice("--installation=".length);
|
|
@@ -90925,6 +91021,8 @@ async function applyToken(cfg, token) {
|
|
|
90925
91021
|
cfg.oauthClientId = null;
|
|
90926
91022
|
cfg.userId = me.agentId;
|
|
90927
91023
|
cfg.email = me.handle;
|
|
91024
|
+
cfg.activeInstallationProfile = null;
|
|
91025
|
+
cfg.activeAgent = null;
|
|
90928
91026
|
saveConfig(cfg);
|
|
90929
91027
|
console.log(`logged in as ${me.handle} (${me.tier}) \u2014 key stored`);
|
|
90930
91028
|
return true;
|
|
@@ -90975,7 +91073,9 @@ async function cmdLoginOAuth(cfg, useBrowserLoopback = false) {
|
|
|
90975
91073
|
refreshToken: result.tokens.refreshToken ?? null,
|
|
90976
91074
|
tokenEndpoint: result.tokenEndpoint,
|
|
90977
91075
|
oauthClientId: result.clientId,
|
|
90978
|
-
apiKey: null
|
|
91076
|
+
apiKey: null,
|
|
91077
|
+
activeInstallationProfile: null,
|
|
91078
|
+
activeAgent: null
|
|
90979
91079
|
};
|
|
90980
91080
|
try {
|
|
90981
91081
|
const me = await authedCloudClient(nextCfg).me();
|
|
@@ -91016,58 +91116,38 @@ async function cmdLoginOAuthDevice(cfg, input) {
|
|
|
91016
91116
|
console.log(`code: ${userCode} \xB7 expires in ${Math.round(expiresInSec / 60)} minutes`);
|
|
91017
91117
|
}
|
|
91018
91118
|
});
|
|
91019
|
-
const nextCfg = {
|
|
91020
|
-
|
|
91021
|
-
|
|
91022
|
-
|
|
91023
|
-
|
|
91024
|
-
|
|
91025
|
-
|
|
91026
|
-
|
|
91027
|
-
|
|
91028
|
-
|
|
91029
|
-
|
|
91030
|
-
|
|
91031
|
-
cloudUrl: cfg.cloudUrl,
|
|
91032
|
-
apiKey: null,
|
|
91033
|
-
accessToken: result.tokens.accessToken,
|
|
91034
|
-
refreshToken: result.tokens.refreshToken ?? null,
|
|
91035
|
-
tokenEndpoint: result.tokenEndpoint,
|
|
91036
|
-
oauthClientId: result.clientId,
|
|
91037
|
-
activeAgent: cfg.activeAgent
|
|
91038
|
-
}
|
|
91119
|
+
const nextCfg = configWithDeviceLogin(loadConfig(), {
|
|
91120
|
+
profileName,
|
|
91121
|
+
makeDefault: input.makeDefault ?? !input.profileName,
|
|
91122
|
+
profile: {
|
|
91123
|
+
installationId: result.installationId,
|
|
91124
|
+
cloudUrl: cfg.cloudUrl,
|
|
91125
|
+
apiKey: null,
|
|
91126
|
+
accessToken: result.tokens.accessToken,
|
|
91127
|
+
refreshToken: result.tokens.refreshToken ?? null,
|
|
91128
|
+
tokenEndpoint: result.tokenEndpoint,
|
|
91129
|
+
oauthClientId: result.clientId,
|
|
91130
|
+
activeAgent: null
|
|
91039
91131
|
}
|
|
91040
|
-
};
|
|
91041
|
-
const me = await
|
|
91042
|
-
nextCfg.
|
|
91043
|
-
|
|
91132
|
+
});
|
|
91133
|
+
const me = await authedCloudClientForProfile(nextCfg, profileName).me();
|
|
91134
|
+
if (nextCfg.activeInstallationProfile === profileName) {
|
|
91135
|
+
nextCfg.userId = me.agentId;
|
|
91136
|
+
nextCfg.email = me.handle;
|
|
91137
|
+
}
|
|
91044
91138
|
saveConfig(nextCfg);
|
|
91045
91139
|
console.log(
|
|
91046
91140
|
`logged in as ${me.handle} (${me.tier}) \xB7 profile ${profileName} \xB7 installation ${result.installationId}`
|
|
91047
91141
|
);
|
|
91048
|
-
await linkRegisteredWorkspaces(nextCfg);
|
|
91142
|
+
await linkRegisteredWorkspaces(nextCfg, profileName);
|
|
91143
|
+
console.log(`machine default: ${nextCfg.activeInstallationProfile ?? "top-level credential"}; workspaces using this profile: ${listWorkspaces().filter((w) => w.installationProfile === profileName || !w.installationProfile && nextCfg.activeInstallationProfile === profileName).map((w) => w.name).join(", ") || "none (bind a workspace to use it)"}`);
|
|
91049
91144
|
} catch (err2) {
|
|
91050
91145
|
console.error(`device login failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
91051
91146
|
console.error(" no credential was stored; retry from Console \u2192 Connect");
|
|
91052
91147
|
process.exitCode = 1;
|
|
91053
91148
|
}
|
|
91054
91149
|
}
|
|
91055
|
-
async function
|
|
91056
|
-
const client = authedCloudClient(cfg);
|
|
91057
|
-
for (const w of listWorkspaces()) {
|
|
91058
|
-
try {
|
|
91059
|
-
const profile = loadProfile(w.path);
|
|
91060
|
-
if (!profile || !effectiveConsent(cfg, profile).sync) continue;
|
|
91061
|
-
refreshRepoLocator(w.path, profile);
|
|
91062
|
-
const out2 = await ensureProjectLink(w.path, profile, client);
|
|
91063
|
-
if (out2.linked) {
|
|
91064
|
-
console.log(` linked ${profile.name} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""}`);
|
|
91065
|
-
}
|
|
91066
|
-
} catch {
|
|
91067
|
-
}
|
|
91068
|
-
}
|
|
91069
|
-
}
|
|
91070
|
-
async function bindWorkspaceToLinkInstallation(cfg, out2, orgId) {
|
|
91150
|
+
async function bindWorkspaceToLinkInstallation(cfg, out2, orgId, cloudUrl) {
|
|
91071
91151
|
const installationId = out2.installationId;
|
|
91072
91152
|
if (!out2.deviceSession) {
|
|
91073
91153
|
console.warn(
|
|
@@ -91091,7 +91171,7 @@ async function bindWorkspaceToLinkInstallation(cfg, out2, orgId) {
|
|
|
91091
91171
|
...cfg.installationProfiles,
|
|
91092
91172
|
[profileName]: {
|
|
91093
91173
|
installationId,
|
|
91094
|
-
cloudUrl
|
|
91174
|
+
cloudUrl,
|
|
91095
91175
|
apiKey: null,
|
|
91096
91176
|
accessToken: minted.tokens.accessToken,
|
|
91097
91177
|
refreshToken: minted.tokens.refreshToken ?? null,
|
|
@@ -91123,8 +91203,9 @@ async function cmdLink(args2) {
|
|
|
91123
91203
|
return;
|
|
91124
91204
|
}
|
|
91125
91205
|
const cfg = loadConfig();
|
|
91206
|
+
const cloud = workspaceCloud(cfg, workspaceEntryForPath(ROOT));
|
|
91126
91207
|
const wantsLocal = args2.includes("--local") || Boolean(flag("--project")) || Boolean(flag("--name"));
|
|
91127
|
-
if (wantsLocal && !
|
|
91208
|
+
if (wantsLocal && !cloud.hasCredential) {
|
|
91128
91209
|
console.error("not logged in \u2014 run `errata login` first (linking needs your cloud identity)");
|
|
91129
91210
|
process.exitCode = 1;
|
|
91130
91211
|
return;
|
|
@@ -91149,7 +91230,7 @@ async function cmdLink(args2) {
|
|
|
91149
91230
|
return;
|
|
91150
91231
|
}
|
|
91151
91232
|
saveProfile(ROOT, profile);
|
|
91152
|
-
const activeProfile =
|
|
91233
|
+
const activeProfile = cloud.profile;
|
|
91153
91234
|
const facts = {
|
|
91154
91235
|
locator: profile.repoLocator,
|
|
91155
91236
|
name: profile.name,
|
|
@@ -91158,7 +91239,7 @@ async function cmdLink(args2) {
|
|
|
91158
91239
|
};
|
|
91159
91240
|
try {
|
|
91160
91241
|
const out3 = await linkThroughConsole({
|
|
91161
|
-
cloudUrl:
|
|
91242
|
+
cloudUrl: cloud.config.cloudUrl,
|
|
91162
91243
|
facts,
|
|
91163
91244
|
timeoutMs: 15 * 6e4,
|
|
91164
91245
|
onVerification: ({ url: url2, userCode, expiresInSec }) => {
|
|
@@ -91191,24 +91272,28 @@ async function cmdLink(args2) {
|
|
|
91191
91272
|
);
|
|
91192
91273
|
await refreshLinkedCodexHooks(args2);
|
|
91193
91274
|
if (applied.wroteIgnore) console.log("wrote .errataignore (starter) \u2014 edit it; it is your hard control");
|
|
91194
|
-
let
|
|
91275
|
+
let reportCloud = workspaceCloud(applied.config, workspaceEntryForPath(ROOT));
|
|
91276
|
+
let reportClient = reportCloud.client;
|
|
91195
91277
|
if (out3.installationId && out3.installationId !== activeProfile?.installationId) {
|
|
91196
|
-
const bound = await bindWorkspaceToLinkInstallation(applied.config, out3, d.orgId);
|
|
91278
|
+
const bound = await bindWorkspaceToLinkInstallation(applied.config, out3, d.orgId, cloud.config.cloudUrl);
|
|
91197
91279
|
if (bound) {
|
|
91198
|
-
|
|
91280
|
+
reportCloud = workspaceCloud(bound.config, workspaceEntryForPath(ROOT));
|
|
91281
|
+
reportClient = reportCloud.client;
|
|
91199
91282
|
console.log(
|
|
91200
91283
|
`this workspace now uses installation ${out3.installationId.slice(0, 8)} (profile ${bound.profileName}) in org ${d.orgId.slice(0, 8)}; your machine default is unchanged`
|
|
91201
91284
|
);
|
|
91285
|
+
} else {
|
|
91286
|
+
return;
|
|
91202
91287
|
}
|
|
91203
91288
|
}
|
|
91204
|
-
if (!
|
|
91289
|
+
if (!reportCloud.hasCredential) {
|
|
91205
91290
|
console.log(" note: run `errata login` so this daemon can sync under the link and report the history stage.");
|
|
91206
91291
|
return;
|
|
91207
91292
|
}
|
|
91208
91293
|
const consents = historyConsents(applied.profile);
|
|
91209
91294
|
const reported = await reportHistoryStage(reportClient, applied.profile, (line) => console.warn(line));
|
|
91210
91295
|
if (reported?.consents) {
|
|
91211
|
-
const synced = applyConsents(applied.profile,
|
|
91296
|
+
const synced = applyConsents(applied.profile, loadConfig(), reported.consents, (/* @__PURE__ */ new Date()).toISOString());
|
|
91212
91297
|
if (synced.changed) {
|
|
91213
91298
|
saveProfile(ROOT, synced.profile);
|
|
91214
91299
|
saveConfig(synced.config);
|
|
@@ -91220,7 +91305,7 @@ async function cmdLink(args2) {
|
|
|
91220
91305
|
return;
|
|
91221
91306
|
} catch (err2) {
|
|
91222
91307
|
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
91223
|
-
if (!/does not offer the link flow/.test(message2) || !
|
|
91308
|
+
if (!/does not offer the link flow/.test(message2) || !cloud.hasCredential) {
|
|
91224
91309
|
console.error(`link failed: ${message2}`);
|
|
91225
91310
|
process.exitCode = 1;
|
|
91226
91311
|
return;
|
|
@@ -91228,7 +91313,7 @@ async function cmdLink(args2) {
|
|
|
91228
91313
|
console.log(`${message2}; falling back to the ambient resolve`);
|
|
91229
91314
|
}
|
|
91230
91315
|
}
|
|
91231
|
-
const client =
|
|
91316
|
+
const client = cloud.client;
|
|
91232
91317
|
const adoptId = flag("--project");
|
|
91233
91318
|
if (adoptId) {
|
|
91234
91319
|
if (!profile.repoLocator) {
|
|
@@ -91285,7 +91370,12 @@ async function cmdUnlink() {
|
|
|
91285
91370
|
async function cmdLogin() {
|
|
91286
91371
|
const cfg = loadConfig();
|
|
91287
91372
|
const flags2 = parseFlags(rest);
|
|
91288
|
-
if (flags2.
|
|
91373
|
+
if (flags2.profile && (!flags2.device || flags2.token)) {
|
|
91374
|
+
console.error("--profile requires --device --installation <uuid>; the machine default was not changed");
|
|
91375
|
+
process.exitCode = 1;
|
|
91376
|
+
return;
|
|
91377
|
+
}
|
|
91378
|
+
if (flags2.cloud) cfg.cloudUrl = normalizeCloudUrl(flags2.cloud);
|
|
91289
91379
|
if (flags2.token) {
|
|
91290
91380
|
await applyToken(cfg, flags2.token);
|
|
91291
91381
|
printBoundWorkspaceNotice();
|
|
@@ -91299,7 +91389,8 @@ async function cmdLogin() {
|
|
|
91299
91389
|
}
|
|
91300
91390
|
await cmdLoginOAuthDevice(cfg, {
|
|
91301
91391
|
installationId: flags2.installation,
|
|
91302
|
-
...flags2.profile ? { profileName: flags2.profile } : {}
|
|
91392
|
+
...flags2.profile ? { profileName: flags2.profile } : {},
|
|
91393
|
+
...flags2.makeDefault ? { makeDefault: true } : {}
|
|
91303
91394
|
});
|
|
91304
91395
|
printBoundWorkspaceNotice();
|
|
91305
91396
|
return;
|
|
@@ -91361,6 +91452,8 @@ async function cmdLogin() {
|
|
|
91361
91452
|
cfg.oauthClientId = null;
|
|
91362
91453
|
cfg.userId = poll.agentId ?? null;
|
|
91363
91454
|
cfg.email = poll.handle ?? handle2;
|
|
91455
|
+
cfg.activeInstallationProfile = null;
|
|
91456
|
+
cfg.activeAgent = null;
|
|
91364
91457
|
saveConfig(cfg);
|
|
91365
91458
|
try {
|
|
91366
91459
|
const me = await authedCloudClient(cfg).me();
|
|
@@ -91421,7 +91514,7 @@ function printBoundWorkspaceNotice() {
|
|
|
91421
91514
|
} catch {
|
|
91422
91515
|
}
|
|
91423
91516
|
}
|
|
91424
|
-
function cmdInstallationProfile(args2) {
|
|
91517
|
+
async function cmdInstallationProfile(args2) {
|
|
91425
91518
|
const cfg = loadConfig();
|
|
91426
91519
|
const action = args2[0] ?? "list";
|
|
91427
91520
|
if (action === "list") {
|
|
@@ -91458,7 +91551,7 @@ function cmdInstallationProfile(args2) {
|
|
|
91458
91551
|
if (!hasCloudCredential(cfg)) {
|
|
91459
91552
|
throw new Error("not logged in \u2014 install the Console credential before saving a profile");
|
|
91460
91553
|
}
|
|
91461
|
-
|
|
91554
|
+
await saveVerifiedInstallationProfile(name2, installationId, cfg);
|
|
91462
91555
|
console.log(`profile saved: ${name2} \xB7 installation ${installationId}`);
|
|
91463
91556
|
return;
|
|
91464
91557
|
}
|