@inerrata-corporation/errata 2.0.0-dev.97 → 2.0.0-dev.98
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 +678 -65
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -21786,11 +21786,24 @@ var init_client = __esm({
|
|
|
21786
21786
|
async actableAgents() {
|
|
21787
21787
|
return this.json("GET", "/api/gate/actable-agents");
|
|
21788
21788
|
}
|
|
21789
|
+
/** Resolve the exact installation and credential context used by this client. */
|
|
21790
|
+
async context() {
|
|
21791
|
+
return this.json("GET", "/api/gate/context");
|
|
21792
|
+
}
|
|
21793
|
+
/** Resolve context after an audited, sessionless act-as re-mint. Useful for
|
|
21794
|
+
* CLI diagnostics that must report the same identity a selected agent uses. */
|
|
21795
|
+
async contextAs(handle2, teamId) {
|
|
21796
|
+
const acting = await this.actAs(handle2, teamId);
|
|
21797
|
+
return this.json("GET", "/api/gate/context", void 0, { bearerToken: acting.token });
|
|
21798
|
+
}
|
|
21789
21799
|
/** Mint a fresh gateway JWT stamped with `handle` (authz-checked + audited
|
|
21790
21800
|
* server-side). The returned `token` bears the acting-agent identity for
|
|
21791
21801
|
* subsequent cloud calls. Authenticated with the caller's base JWT. */
|
|
21792
|
-
async actAs(handle2) {
|
|
21793
|
-
return this.json("POST", "/api/gate/act-as", {
|
|
21802
|
+
async actAs(handle2, teamId) {
|
|
21803
|
+
return this.json("POST", "/api/gate/act-as", {
|
|
21804
|
+
handle: handle2,
|
|
21805
|
+
...teamId !== void 0 ? { teamId } : {}
|
|
21806
|
+
});
|
|
21794
21807
|
}
|
|
21795
21808
|
/** Resolve-or-create the org's project for a repo locator (ambient link,
|
|
21796
21809
|
* PJ-entity). Requires user identity on the JWT — login-gated like actAs. */
|
|
@@ -22163,7 +22176,7 @@ var init_client = __esm({
|
|
|
22163
22176
|
...provenanceHeaders(this.provenance)
|
|
22164
22177
|
};
|
|
22165
22178
|
if (!opts?.skipAuth) {
|
|
22166
|
-
const token = await this.authToken();
|
|
22179
|
+
const token = opts?.bearerToken ?? await this.authToken();
|
|
22167
22180
|
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
22168
22181
|
}
|
|
22169
22182
|
const ac = new AbortController();
|
|
@@ -22377,7 +22390,9 @@ function defaultConfig() {
|
|
|
22377
22390
|
onboardedAt: null,
|
|
22378
22391
|
machineId: null,
|
|
22379
22392
|
updateChannel: "dev",
|
|
22380
|
-
activeAgent: null
|
|
22393
|
+
activeAgent: null,
|
|
22394
|
+
installationProfiles: {},
|
|
22395
|
+
activeInstallationProfile: null
|
|
22381
22396
|
};
|
|
22382
22397
|
}
|
|
22383
22398
|
function loadConfig() {
|
|
@@ -22402,14 +22417,89 @@ function loadConfig() {
|
|
|
22402
22417
|
cloudUrl: envCloudUrl ?? (migrateLegacyDefault ? DEFAULT_CLOUD_URL : parsed.cloudUrl ?? base.cloudUrl),
|
|
22403
22418
|
// Deep-merge consent so an old/partial config keeps the opt-in defaults
|
|
22404
22419
|
// for any channel it doesn't mention.
|
|
22405
|
-
consent: { ...base.consent, ...parsed.consent ?? {} }
|
|
22420
|
+
consent: { ...base.consent, ...parsed.consent ?? {} },
|
|
22421
|
+
installationProfiles: { ...parsed.installationProfiles ?? {} }
|
|
22406
22422
|
};
|
|
22407
22423
|
if (migrateLegacyDefault && !envCloudUrl) saveConfig(resolved);
|
|
22408
22424
|
return resolved;
|
|
22409
22425
|
}
|
|
22410
22426
|
function saveConfig(cfg) {
|
|
22411
22427
|
ensureDir(globalDir());
|
|
22412
|
-
|
|
22428
|
+
const normalized = snapshotActiveInstallationProfile(cfg);
|
|
22429
|
+
writeFileSync5(globalConfigPath(), JSON.stringify(normalized, null, 2), { encoding: "utf8", mode: 384 });
|
|
22430
|
+
}
|
|
22431
|
+
function profileFromCurrent(cfg, installationId) {
|
|
22432
|
+
return {
|
|
22433
|
+
installationId,
|
|
22434
|
+
cloudUrl: cfg.cloudUrl,
|
|
22435
|
+
apiKey: cfg.apiKey,
|
|
22436
|
+
accessToken: cfg.accessToken,
|
|
22437
|
+
refreshToken: cfg.refreshToken,
|
|
22438
|
+
tokenEndpoint: cfg.tokenEndpoint,
|
|
22439
|
+
oauthClientId: cfg.oauthClientId,
|
|
22440
|
+
activeAgent: cfg.activeAgent
|
|
22441
|
+
};
|
|
22442
|
+
}
|
|
22443
|
+
function snapshotActiveInstallationProfile(cfg) {
|
|
22444
|
+
const name2 = cfg.activeInstallationProfile;
|
|
22445
|
+
if (!name2) return cfg;
|
|
22446
|
+
const existing = cfg.installationProfiles[name2];
|
|
22447
|
+
if (!existing) return { ...cfg, activeInstallationProfile: null };
|
|
22448
|
+
return {
|
|
22449
|
+
...cfg,
|
|
22450
|
+
installationProfiles: {
|
|
22451
|
+
...cfg.installationProfiles,
|
|
22452
|
+
[name2]: profileFromCurrent(cfg, existing.installationId)
|
|
22453
|
+
}
|
|
22454
|
+
};
|
|
22455
|
+
}
|
|
22456
|
+
function saveInstallationProfile(name2, installationId, cfg = loadConfig()) {
|
|
22457
|
+
const normalizedName = name2.trim();
|
|
22458
|
+
if (!normalizedName || normalizedName.length > 80) {
|
|
22459
|
+
throw new Error("profile name must be 1\u201380 characters");
|
|
22460
|
+
}
|
|
22461
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(installationId)) {
|
|
22462
|
+
throw new Error("installation id must be a UUID");
|
|
22463
|
+
}
|
|
22464
|
+
const next = {
|
|
22465
|
+
...cfg,
|
|
22466
|
+
installationProfiles: {
|
|
22467
|
+
...cfg.installationProfiles,
|
|
22468
|
+
[normalizedName]: profileFromCurrent(cfg, installationId)
|
|
22469
|
+
},
|
|
22470
|
+
activeInstallationProfile: normalizedName
|
|
22471
|
+
};
|
|
22472
|
+
saveConfig(next);
|
|
22473
|
+
return next;
|
|
22474
|
+
}
|
|
22475
|
+
function useInstallationProfile(name2, cfg = loadConfig()) {
|
|
22476
|
+
const profile = cfg.installationProfiles[name2];
|
|
22477
|
+
if (!profile) throw new Error(`installation profile not found: ${name2}`);
|
|
22478
|
+
const next = {
|
|
22479
|
+
...cfg,
|
|
22480
|
+
cloudUrl: profile.cloudUrl,
|
|
22481
|
+
apiKey: profile.apiKey,
|
|
22482
|
+
accessToken: profile.accessToken,
|
|
22483
|
+
refreshToken: profile.refreshToken,
|
|
22484
|
+
tokenEndpoint: profile.tokenEndpoint,
|
|
22485
|
+
oauthClientId: profile.oauthClientId,
|
|
22486
|
+
activeAgent: profile.activeAgent,
|
|
22487
|
+
activeInstallationProfile: name2
|
|
22488
|
+
};
|
|
22489
|
+
saveConfig(next);
|
|
22490
|
+
return next;
|
|
22491
|
+
}
|
|
22492
|
+
function removeInstallationProfile(name2, cfg = loadConfig()) {
|
|
22493
|
+
if (!cfg.installationProfiles[name2]) return cfg;
|
|
22494
|
+
const installationProfiles = { ...cfg.installationProfiles };
|
|
22495
|
+
delete installationProfiles[name2];
|
|
22496
|
+
const next = {
|
|
22497
|
+
...cfg,
|
|
22498
|
+
installationProfiles,
|
|
22499
|
+
activeInstallationProfile: cfg.activeInstallationProfile === name2 ? null : cfg.activeInstallationProfile
|
|
22500
|
+
};
|
|
22501
|
+
saveConfig(next);
|
|
22502
|
+
return next;
|
|
22413
22503
|
}
|
|
22414
22504
|
function machineId() {
|
|
22415
22505
|
const fromEnv = process.env["ERRATA_MACHINE_ID"];
|
|
@@ -22444,12 +22534,30 @@ var init_config = __esm({
|
|
|
22444
22534
|
});
|
|
22445
22535
|
|
|
22446
22536
|
// src/cloud-endpoint-policy.ts
|
|
22537
|
+
function warnDirectV1OverrideOnce() {
|
|
22538
|
+
if (warnedDirectV1Override) return;
|
|
22539
|
+
warnedDirectV1Override = true;
|
|
22540
|
+
console.error(
|
|
22541
|
+
[
|
|
22542
|
+
"",
|
|
22543
|
+
"!!! DIRECT V1 OVERRIDE ACTIVE !!!",
|
|
22544
|
+
`${DIRECT_V1_OVERRIDE_ENV} + ${DIRECT_V1_ACK_ENV} are set: this daemon is talking`,
|
|
22545
|
+
"straight to the legacy v1 data plane, BYPASSING the Console Gateway \u2014",
|
|
22546
|
+
"no metering, no signed context enforcement, no write-target binding.",
|
|
22547
|
+
"Staff testing only. This escape hatch is removed at v1 EOL.",
|
|
22548
|
+
""
|
|
22549
|
+
].join("\n")
|
|
22550
|
+
);
|
|
22551
|
+
}
|
|
22552
|
+
function isDirectV1OverrideRequested() {
|
|
22553
|
+
const raw2 = process.env[DIRECT_V1_OVERRIDE_ENV]?.trim().toLowerCase();
|
|
22554
|
+
return raw2 === "1" || raw2 === "true" || raw2 === "yes" || raw2 === "on";
|
|
22555
|
+
}
|
|
22447
22556
|
function normalizeCloudUrl(url2) {
|
|
22448
22557
|
return url2.replace(/\/+$/, "");
|
|
22449
22558
|
}
|
|
22450
22559
|
function isDirectV1OverrideEnabled() {
|
|
22451
|
-
|
|
22452
|
-
return raw2 === "1" || raw2 === "true" || raw2 === "yes" || raw2 === "on";
|
|
22560
|
+
return isDirectV1OverrideRequested() && process.env[DIRECT_V1_ACK_ENV]?.trim() === DIRECT_V1_ACK_VALUE;
|
|
22453
22561
|
}
|
|
22454
22562
|
function isLocalCloudUrl(url2) {
|
|
22455
22563
|
try {
|
|
@@ -22481,18 +22589,20 @@ function evaluateCloudEndpoint(url2, inspection) {
|
|
|
22481
22589
|
return { allowed: true, label: "gateway-configured" };
|
|
22482
22590
|
}
|
|
22483
22591
|
if (isDirectV1OverrideEnabled()) {
|
|
22592
|
+
warnDirectV1OverrideOnce();
|
|
22484
22593
|
return {
|
|
22485
22594
|
allowed: true,
|
|
22486
22595
|
label: "legacy-direct (override)",
|
|
22487
|
-
reason: `${DIRECT_V1_OVERRIDE_ENV}
|
|
22596
|
+
reason: `${DIRECT_V1_OVERRIDE_ENV} acknowledged via ${DIRECT_V1_ACK_ENV}`
|
|
22488
22597
|
};
|
|
22489
22598
|
}
|
|
22490
22599
|
const service = inspection?.service ? ` (${inspection.service})` : "";
|
|
22600
|
+
const unacked = isDirectV1OverrideRequested() ? ` ${DIRECT_V1_OVERRIDE_ENV} is set but unacknowledged \u2014 staff testing additionally requires ${DIRECT_V1_ACK_ENV}=${DIRECT_V1_ACK_VALUE}.` : "";
|
|
22491
22601
|
return {
|
|
22492
22602
|
allowed: false,
|
|
22493
22603
|
label: "legacy-direct blocked",
|
|
22494
22604
|
reason: `non-local cloud endpoint is not the Console Gateway${service}`,
|
|
22495
|
-
guidance: `Point ERRATA_CLOUD_URL at the Console Gateway
|
|
22605
|
+
guidance: `Point ERRATA_CLOUD_URL at the Console Gateway.${unacked}`
|
|
22496
22606
|
};
|
|
22497
22607
|
}
|
|
22498
22608
|
function formatCloudEndpointBlock(url2, decision) {
|
|
@@ -22634,13 +22744,16 @@ async function fetchHealthJson(fetchFn, url2, timeoutMs) {
|
|
|
22634
22744
|
clearTimeout(tid);
|
|
22635
22745
|
}
|
|
22636
22746
|
}
|
|
22637
|
-
var DIRECT_V1_OVERRIDE_ENV, GATEWAY_SERVICE, PROBE_TIMEOUT_MS, CloudEndpointPolicyError, BLOCKED_RECHECK_MS;
|
|
22747
|
+
var DIRECT_V1_OVERRIDE_ENV, DIRECT_V1_ACK_ENV, DIRECT_V1_ACK_VALUE, GATEWAY_SERVICE, PROBE_TIMEOUT_MS, warnedDirectV1Override, CloudEndpointPolicyError, BLOCKED_RECHECK_MS;
|
|
22638
22748
|
var init_cloud_endpoint_policy = __esm({
|
|
22639
22749
|
"src/cloud-endpoint-policy.ts"() {
|
|
22640
22750
|
"use strict";
|
|
22641
22751
|
DIRECT_V1_OVERRIDE_ENV = "ERRATA_ALLOW_DIRECT_V1_CLOUD";
|
|
22752
|
+
DIRECT_V1_ACK_ENV = "ERRATA_DIRECT_V1_ACK";
|
|
22753
|
+
DIRECT_V1_ACK_VALUE = "I_ACCEPT_UNMETERED_DIRECT_V1";
|
|
22642
22754
|
GATEWAY_SERVICE = "console-gateway";
|
|
22643
22755
|
PROBE_TIMEOUT_MS = 2e3;
|
|
22756
|
+
warnedDirectV1Override = false;
|
|
22644
22757
|
CloudEndpointPolicyError = class extends Error {
|
|
22645
22758
|
decision;
|
|
22646
22759
|
constructor(message, decision) {
|
|
@@ -22678,6 +22791,7 @@ function authedCloudClient(cfg, opts = {}) {
|
|
|
22678
22791
|
const versionOpts = opts.daemonVersion ? { daemonVersion: opts.daemonVersion, daemonChannel: cfg.updateChannel } : {};
|
|
22679
22792
|
if (cfg.accessToken) {
|
|
22680
22793
|
const tokenEndpoint = cfg.tokenEndpoint;
|
|
22794
|
+
const installationId = cfg.activeInstallationProfile ? cfg.installationProfiles[cfg.activeInstallationProfile]?.installationId : void 0;
|
|
22681
22795
|
return new CloudClient({
|
|
22682
22796
|
baseUrl,
|
|
22683
22797
|
accessToken: cfg.accessToken,
|
|
@@ -22687,7 +22801,11 @@ function authedCloudClient(cfg, opts = {}) {
|
|
|
22687
22801
|
provenance: daemonProvenance(),
|
|
22688
22802
|
...opts.timeoutMs ? { timeoutMs: opts.timeoutMs } : {},
|
|
22689
22803
|
...tokenEndpoint && cfg.refreshToken ? {
|
|
22690
|
-
refreshFn: (rt) =>
|
|
22804
|
+
refreshFn: (rt) => tokenEndpoint.endsWith("/api/gate/session-token") && installationId ? refreshDeviceSessionToken(opts.fetchFn ?? fetch, tokenEndpoint, {
|
|
22805
|
+
sessionToken: rt,
|
|
22806
|
+
installationId,
|
|
22807
|
+
clientId: cfg.oauthClientId ?? oauthClientId()
|
|
22808
|
+
}) : refreshAccessToken(opts.fetchFn ?? fetch, tokenEndpoint, {
|
|
22691
22809
|
refreshToken: rt,
|
|
22692
22810
|
clientId: cfg.oauthClientId ?? oauthClientId()
|
|
22693
22811
|
}),
|
|
@@ -22710,6 +22828,30 @@ function authedCloudClient(cfg, opts = {}) {
|
|
|
22710
22828
|
...opts.timeoutMs ? { timeoutMs: opts.timeoutMs } : {}
|
|
22711
22829
|
});
|
|
22712
22830
|
}
|
|
22831
|
+
async function refreshDeviceSessionToken(fetchFn, endpoint, input) {
|
|
22832
|
+
const response = await fetchFn(endpoint, {
|
|
22833
|
+
method: "POST",
|
|
22834
|
+
headers: {
|
|
22835
|
+
authorization: `Bearer ${input.sessionToken}`,
|
|
22836
|
+
"content-type": "application/json",
|
|
22837
|
+
accept: "application/json"
|
|
22838
|
+
},
|
|
22839
|
+
body: JSON.stringify({
|
|
22840
|
+
installationId: input.installationId,
|
|
22841
|
+
clientId: input.clientId,
|
|
22842
|
+
scopes: ["graph:read", "graph:write", "mcp:tools"]
|
|
22843
|
+
})
|
|
22844
|
+
});
|
|
22845
|
+
const body2 = await response.json().catch(() => null);
|
|
22846
|
+
if (!response.ok || typeof body2?.["access_token"] !== "string") {
|
|
22847
|
+
throw new Error(`device session refresh failed: HTTP ${response.status}`);
|
|
22848
|
+
}
|
|
22849
|
+
return {
|
|
22850
|
+
accessToken: body2["access_token"],
|
|
22851
|
+
refreshToken: input.sessionToken,
|
|
22852
|
+
...typeof body2["expires_in"] === "number" ? { expiresInSec: body2["expires_in"] } : {}
|
|
22853
|
+
};
|
|
22854
|
+
}
|
|
22713
22855
|
function hasCloudCredential(cfg) {
|
|
22714
22856
|
return Boolean(cfg.accessToken || cfg.apiKey);
|
|
22715
22857
|
}
|
|
@@ -36701,14 +36843,15 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
36701
36843
|
};
|
|
36702
36844
|
}
|
|
36703
36845
|
function buildToolContext() {
|
|
36846
|
+
const base = { switchInstallationProfile: useInstallationProfile };
|
|
36704
36847
|
try {
|
|
36705
36848
|
const cfg = loadConfig();
|
|
36706
36849
|
if (cfg.consent.sync && hasCloudCredential(cfg) && cfg.cloudUrl) {
|
|
36707
|
-
return { cloud: authedCloudClient(cfg) };
|
|
36850
|
+
return { ...base, cloud: authedCloudClient(cfg) };
|
|
36708
36851
|
}
|
|
36709
36852
|
} catch {
|
|
36710
36853
|
}
|
|
36711
|
-
return
|
|
36854
|
+
return base;
|
|
36712
36855
|
}
|
|
36713
36856
|
async function runMcpServer(workspaceRoot) {
|
|
36714
36857
|
const paths = workspacePaths(workspaceRoot);
|
|
@@ -36817,6 +36960,41 @@ var init_mcp = __esm({
|
|
|
36817
36960
|
AUDIT_NUDGE_COOLDOWN = 12;
|
|
36818
36961
|
AUDIT_FLAG_NUDGE = "\u26A1 errata \u2014 reading/auditing? anything you notice that's off, flag it inline as `[!one line]` (`[?\u2026]` = TODO) \u2014 no tool call, we harvest it.";
|
|
36819
36962
|
TOOLS = [
|
|
36963
|
+
{
|
|
36964
|
+
name: "errata.switch_context",
|
|
36965
|
+
description: "Switch this daemon to an already-installed Personal, organization, or Team profile. The profile's full credential set changes with the selection; this never widens the current token or carries consent between installations. Returns the selected installation descriptor so the caller can verify what changed.",
|
|
36966
|
+
inputSchema: {
|
|
36967
|
+
type: "object",
|
|
36968
|
+
properties: {
|
|
36969
|
+
profile: {
|
|
36970
|
+
type: "string",
|
|
36971
|
+
minLength: 1,
|
|
36972
|
+
maxLength: 80,
|
|
36973
|
+
description: "Exact name from `errata profile list`."
|
|
36974
|
+
}
|
|
36975
|
+
},
|
|
36976
|
+
required: ["profile"],
|
|
36977
|
+
additionalProperties: false
|
|
36978
|
+
},
|
|
36979
|
+
handler: (args2, _store, ctx) => {
|
|
36980
|
+
const profileName = typeof args2["profile"] === "string" ? args2["profile"].trim() : "";
|
|
36981
|
+
if (!profileName) throw new Error("profile is required");
|
|
36982
|
+
const next = (ctx.switchInstallationProfile ?? useInstallationProfile)(profileName);
|
|
36983
|
+
const profile = next.installationProfiles[profileName];
|
|
36984
|
+
if (!profile) throw new Error(`installation profile not found: ${profileName}`);
|
|
36985
|
+
return {
|
|
36986
|
+
switched: true,
|
|
36987
|
+
profile: profileName,
|
|
36988
|
+
installation_id: profile.installationId,
|
|
36989
|
+
cloud_url: profile.cloudUrl,
|
|
36990
|
+
credential_type: profile.accessToken ? "oauth" : profile.apiKey ? "api_key" : "none",
|
|
36991
|
+
actor: profile.activeAgent,
|
|
36992
|
+
authority_changed: true,
|
|
36993
|
+
standing_consent_carried: false,
|
|
36994
|
+
note: "Live graph visibility and write target are resolved server-side for each request."
|
|
36995
|
+
};
|
|
36996
|
+
}
|
|
36997
|
+
},
|
|
36820
36998
|
{
|
|
36821
36999
|
name: "errata.search",
|
|
36822
37000
|
description: "Find a symbol, string, or comment across the live code graph \u2014 reaches matches by structure, not just text. Multi-word queries are tokenized and OR'd (more terms matched ranks higher, then pageRank), so word order and punctuation don't matter. Returns up to `limit` hits with id, label, description, and pageRank (higher pageRank = more central \u2014 start there). A comment that documents a symbol resolves to that SYMBOL (the comment rides along as `via` \u2014 it's the why, not the destination); test scaffolding and floating comments sort below production code. When the collective is reachable, results BLEND cross-project knowledge, each tagged `provenance` (local | collective | corroborated) with `usageCount`.",
|
|
@@ -49644,8 +49822,8 @@ function tagEdgeCorroborated(targetAnchorIds, sessionTouchedNodeIds, independent
|
|
|
49644
49822
|
for (const a of targetAnchorIds) if (sessionTouchedNodeIds.has(a)) return true;
|
|
49645
49823
|
return false;
|
|
49646
49824
|
}
|
|
49647
|
-
function typePriorEdge(sourceLabel,
|
|
49648
|
-
const direct = LABEL_PAIR[`${sourceLabel}>${
|
|
49825
|
+
function typePriorEdge(sourceLabel, targetLabel2, sentence = "") {
|
|
49826
|
+
const direct = LABEL_PAIR[`${sourceLabel}>${targetLabel2}`];
|
|
49649
49827
|
if (direct) return direct;
|
|
49650
49828
|
if (sentence && !NEG.test(sentence)) {
|
|
49651
49829
|
const t = TIEBREAK.find((c) => c.re.test(sentence));
|
|
@@ -51471,7 +51649,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
51471
51649
|
}
|
|
51472
51650
|
|
|
51473
51651
|
// src/engine.ts
|
|
51474
|
-
var DAEMON_VERSION = true ? "2.0.0-dev.
|
|
51652
|
+
var DAEMON_VERSION = true ? "2.0.0-dev.98" : "2.0.0-alpha.0";
|
|
51475
51653
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
51476
51654
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
51477
51655
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -54629,6 +54807,102 @@ init_cloud_auth();
|
|
|
54629
54807
|
import { createServer } from "node:http";
|
|
54630
54808
|
var DEFAULT_OAUTH_SCOPE = "openid profile graph:read graph:write mcp:tools";
|
|
54631
54809
|
var strip = (u) => u.replace(/\/+$/, "");
|
|
54810
|
+
function deviceEndpoints(tokenEndpoint) {
|
|
54811
|
+
const token = new URL(tokenEndpoint);
|
|
54812
|
+
const authRoot = token.pathname.replace(/\/(?:oauth2|mcp)\/token\/?$/, "");
|
|
54813
|
+
if (authRoot === token.pathname) throw new Error("authorization server exposes no device endpoint");
|
|
54814
|
+
const prefix = authRoot.replace(/\/api\/auth\/?$/, "");
|
|
54815
|
+
const at = (path2) => new URL(`${path2}`, `${token.origin}${prefix || "/"}`).toString();
|
|
54816
|
+
return {
|
|
54817
|
+
code: at(`${prefix}/api/auth/device/code`),
|
|
54818
|
+
token: at(`${prefix}/api/auth/device/token`),
|
|
54819
|
+
resource: at(`${prefix}/api/gate/session-token`)
|
|
54820
|
+
};
|
|
54821
|
+
}
|
|
54822
|
+
async function loginOAuthDevice(opts) {
|
|
54823
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
54824
|
+
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
54825
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
54826
|
+
const clientId = oauthClientId();
|
|
54827
|
+
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
54828
|
+
const codeResponse = await fetchFn(device.code, {
|
|
54829
|
+
method: "POST",
|
|
54830
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
54831
|
+
body: JSON.stringify({ client_id: clientId, scope })
|
|
54832
|
+
});
|
|
54833
|
+
if (!codeResponse.ok) {
|
|
54834
|
+
throw new Error(`device authorization failed: HTTP ${codeResponse.status} ${(await codeResponse.text()).slice(0, 200)}`);
|
|
54835
|
+
}
|
|
54836
|
+
const code = await codeResponse.json();
|
|
54837
|
+
if (!code.device_code || !code.user_code || !code.verification_uri || !code.expires_in) {
|
|
54838
|
+
throw new Error("device authorization returned an incomplete response");
|
|
54839
|
+
}
|
|
54840
|
+
opts.onVerification?.({
|
|
54841
|
+
url: code.verification_uri_complete ?? code.verification_uri,
|
|
54842
|
+
userCode: code.user_code,
|
|
54843
|
+
expiresInSec: code.expires_in
|
|
54844
|
+
});
|
|
54845
|
+
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
54846
|
+
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
54847
|
+
let deviceSession = null;
|
|
54848
|
+
let approvedInstallation = null;
|
|
54849
|
+
while (Date.now() < deadline) {
|
|
54850
|
+
await (opts.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms))))(intervalMs);
|
|
54851
|
+
const poll = await fetchFn(device.token, {
|
|
54852
|
+
method: "POST",
|
|
54853
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
54854
|
+
body: JSON.stringify({
|
|
54855
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
54856
|
+
device_code: code.device_code,
|
|
54857
|
+
client_id: clientId
|
|
54858
|
+
})
|
|
54859
|
+
});
|
|
54860
|
+
const payload = await poll.json().catch(() => null);
|
|
54861
|
+
if (!poll.ok) {
|
|
54862
|
+
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
54863
|
+
if (error48 === "authorization_pending") continue;
|
|
54864
|
+
if (error48 === "slow_down") {
|
|
54865
|
+
intervalMs += 5e3;
|
|
54866
|
+
continue;
|
|
54867
|
+
}
|
|
54868
|
+
throw new Error(`device authorization failed: ${error48}`);
|
|
54869
|
+
}
|
|
54870
|
+
deviceSession = typeof payload?.["access_token"] === "string" ? payload["access_token"] : null;
|
|
54871
|
+
approvedInstallation = typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null;
|
|
54872
|
+
break;
|
|
54873
|
+
}
|
|
54874
|
+
if (!deviceSession || !approvedInstallation) throw new Error("device authorization expired");
|
|
54875
|
+
if (approvedInstallation !== opts.installationId) {
|
|
54876
|
+
throw new Error("approved installation does not match the terminal request");
|
|
54877
|
+
}
|
|
54878
|
+
const resourceResponse = await fetchFn(device.resource, {
|
|
54879
|
+
method: "POST",
|
|
54880
|
+
headers: {
|
|
54881
|
+
authorization: `Bearer ${deviceSession}`,
|
|
54882
|
+
"content-type": "application/json",
|
|
54883
|
+
accept: "application/json"
|
|
54884
|
+
},
|
|
54885
|
+
body: JSON.stringify({
|
|
54886
|
+
installationId: approvedInstallation,
|
|
54887
|
+
clientId,
|
|
54888
|
+
scopes: scope.split(/\s+/).filter((value) => !["openid", "profile", "email", "offline_access"].includes(value))
|
|
54889
|
+
})
|
|
54890
|
+
});
|
|
54891
|
+
const resource = await resourceResponse.json().catch(() => null);
|
|
54892
|
+
if (!resourceResponse.ok || typeof resource?.["access_token"] !== "string") {
|
|
54893
|
+
throw new Error(`device resource exchange failed: HTTP ${resourceResponse.status}`);
|
|
54894
|
+
}
|
|
54895
|
+
return {
|
|
54896
|
+
installationId: approvedInstallation,
|
|
54897
|
+
clientId,
|
|
54898
|
+
tokenEndpoint: device.resource,
|
|
54899
|
+
tokens: {
|
|
54900
|
+
accessToken: resource["access_token"],
|
|
54901
|
+
refreshToken: deviceSession,
|
|
54902
|
+
...typeof resource["expires_in"] === "number" ? { expiresInSec: resource["expires_in"] } : {}
|
|
54903
|
+
}
|
|
54904
|
+
};
|
|
54905
|
+
}
|
|
54632
54906
|
async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
|
|
54633
54907
|
let consoleUrl = cloudUrl;
|
|
54634
54908
|
try {
|
|
@@ -54998,6 +55272,116 @@ function shouldUseOAuthLogin(flags2, env2 = process.env) {
|
|
|
54998
55272
|
return Boolean(flags2.oauth || !flags2.device && isDaemonOAuthDefaultEnabled(env2));
|
|
54999
55273
|
}
|
|
55000
55274
|
|
|
55275
|
+
// src/doctor.ts
|
|
55276
|
+
async function diagnoseInstallation(cfg, dependencies) {
|
|
55277
|
+
const checks = [];
|
|
55278
|
+
const profileName = cfg.activeInstallationProfile;
|
|
55279
|
+
const profile = profileName ? cfg.installationProfiles[profileName] : void 0;
|
|
55280
|
+
checks.push(
|
|
55281
|
+
profile ? { id: "installation_profile", status: "pass", detail: `${profileName} is selected` } : {
|
|
55282
|
+
id: "installation_profile",
|
|
55283
|
+
status: "fail",
|
|
55284
|
+
detail: "No installation profile is selected"
|
|
55285
|
+
}
|
|
55286
|
+
);
|
|
55287
|
+
const credentialType = cfg.accessToken ? "oauth" : cfg.apiKey ? "api_key" : "none";
|
|
55288
|
+
checks.push(
|
|
55289
|
+
credentialType === "none" ? { id: "credential", status: "fail", detail: "No credential is installed" } : { id: "credential", status: "pass", detail: `${credentialType} credential is present` }
|
|
55290
|
+
);
|
|
55291
|
+
const authorityMatches = !profile || profile.cloudUrl === cfg.cloudUrl && profile.apiKey === cfg.apiKey && profile.accessToken === cfg.accessToken && profile.refreshToken === cfg.refreshToken;
|
|
55292
|
+
checks.push(
|
|
55293
|
+
authorityMatches ? {
|
|
55294
|
+
id: "profile_authority",
|
|
55295
|
+
status: profile ? "pass" : "warn",
|
|
55296
|
+
detail: profile ? "Selected profile and active credential set match" : "Cannot compare authority without a selected profile"
|
|
55297
|
+
} : {
|
|
55298
|
+
id: "profile_authority",
|
|
55299
|
+
status: "fail",
|
|
55300
|
+
detail: "Selected profile and active credential set differ; reselect the profile"
|
|
55301
|
+
}
|
|
55302
|
+
);
|
|
55303
|
+
if (credentialType === "oauth") {
|
|
55304
|
+
checks.push(
|
|
55305
|
+
cfg.refreshToken && cfg.tokenEndpoint ? { id: "renewal", status: "pass", detail: "OAuth renewal is configured" } : {
|
|
55306
|
+
id: "renewal",
|
|
55307
|
+
status: "fail",
|
|
55308
|
+
detail: "OAuth access exists without a refresh credential or token endpoint"
|
|
55309
|
+
}
|
|
55310
|
+
);
|
|
55311
|
+
}
|
|
55312
|
+
try {
|
|
55313
|
+
const inspection = await dependencies.inspect();
|
|
55314
|
+
checks.push(
|
|
55315
|
+
inspection.reachable ? {
|
|
55316
|
+
id: "endpoint",
|
|
55317
|
+
status: "pass",
|
|
55318
|
+
detail: `Cloud is reachable via ${inspection.probe}`
|
|
55319
|
+
} : {
|
|
55320
|
+
id: "endpoint",
|
|
55321
|
+
status: "fail",
|
|
55322
|
+
detail: inspection.error ?? "Cloud endpoint is unreachable"
|
|
55323
|
+
}
|
|
55324
|
+
);
|
|
55325
|
+
} catch (cause) {
|
|
55326
|
+
checks.push({
|
|
55327
|
+
id: "endpoint",
|
|
55328
|
+
status: "fail",
|
|
55329
|
+
detail: cause instanceof Error ? cause.message : String(cause)
|
|
55330
|
+
});
|
|
55331
|
+
}
|
|
55332
|
+
if (credentialType !== "none") {
|
|
55333
|
+
try {
|
|
55334
|
+
const identity = await dependencies.authenticate();
|
|
55335
|
+
checks.push({
|
|
55336
|
+
id: "authentication",
|
|
55337
|
+
status: "pass",
|
|
55338
|
+
detail: `Authenticated as ${identity.handle} (${identity.tier})`
|
|
55339
|
+
});
|
|
55340
|
+
} catch (cause) {
|
|
55341
|
+
checks.push({
|
|
55342
|
+
id: "authentication",
|
|
55343
|
+
status: "fail",
|
|
55344
|
+
detail: cause instanceof Error ? cause.message : String(cause)
|
|
55345
|
+
});
|
|
55346
|
+
}
|
|
55347
|
+
}
|
|
55348
|
+
return {
|
|
55349
|
+
ok: checks.every((check2) => check2.status !== "fail"),
|
|
55350
|
+
profile: profileName,
|
|
55351
|
+
installationId: profile?.installationId ?? null,
|
|
55352
|
+
credentialType,
|
|
55353
|
+
checks
|
|
55354
|
+
};
|
|
55355
|
+
}
|
|
55356
|
+
|
|
55357
|
+
// src/whoami.ts
|
|
55358
|
+
async function resolveWhoami(client, actingHandle) {
|
|
55359
|
+
return actingHandle ? client.contextAs(actingHandle) : client.context();
|
|
55360
|
+
}
|
|
55361
|
+
function targetLabel(context) {
|
|
55362
|
+
const target = context.default_write_target;
|
|
55363
|
+
if (!target) return "read-only";
|
|
55364
|
+
if (target.visibility === "public") return "public graph";
|
|
55365
|
+
if (target.visibility === "org") return `organization graph (${target.org_id})`;
|
|
55366
|
+
return `private Team graph (${target.team_id})`;
|
|
55367
|
+
}
|
|
55368
|
+
function formatWhoami(response, localProfile) {
|
|
55369
|
+
const { context, identity } = response;
|
|
55370
|
+
return [
|
|
55371
|
+
`inErrata context \u2014 ${context.profile_name ?? localProfile ?? "unbound credential"}`,
|
|
55372
|
+
` workspace: ${context.workspace_kind} \xB7 ${context.org_id}`,
|
|
55373
|
+
` team: ${context.team_id ?? "(none)"}`,
|
|
55374
|
+
` agent: ${context.agent_id ?? "(default identity)"}`,
|
|
55375
|
+
` installation: ${context.installation_id ?? "(unbound)"}`,
|
|
55376
|
+
` environment: ${context.environment} \xB7 ${context.client_kind}`,
|
|
55377
|
+
` reads: ${context.read_visibilities.join(" + ")}`,
|
|
55378
|
+
` contributes: ${targetLabel(context)}`,
|
|
55379
|
+
` policy: ${context.policy_version ?? "(legacy)"}`,
|
|
55380
|
+
` credential: ${identity.credential_type} \xB7 ${identity.credential_id}`,
|
|
55381
|
+
` actor: ${identity.actor_type} \xB7 ${identity.actor_id}`
|
|
55382
|
+
];
|
|
55383
|
+
}
|
|
55384
|
+
|
|
55001
55385
|
// src/consolidation-trigger.ts
|
|
55002
55386
|
var DEFAULT_CONSOLIDATION_POLICY = {
|
|
55003
55387
|
baseFloorMs: 6e4,
|
|
@@ -55055,8 +55439,13 @@ async function main() {
|
|
|
55055
55439
|
return cmdStop();
|
|
55056
55440
|
case "status":
|
|
55057
55441
|
return cmdStatus();
|
|
55442
|
+
case "doctor":
|
|
55443
|
+
case "verify":
|
|
55444
|
+
return cmdDoctor(rest);
|
|
55058
55445
|
case "usage":
|
|
55059
55446
|
return cmdUsage();
|
|
55447
|
+
case "whoami":
|
|
55448
|
+
return cmdWhoami(rest);
|
|
55060
55449
|
case "login":
|
|
55061
55450
|
return cmdLogin();
|
|
55062
55451
|
case "logout":
|
|
@@ -55067,6 +55456,8 @@ async function main() {
|
|
|
55067
55456
|
return cmdUnlink();
|
|
55068
55457
|
case "use":
|
|
55069
55458
|
return cmdUse(rest);
|
|
55459
|
+
case "profile":
|
|
55460
|
+
return cmdInstallationProfile(rest);
|
|
55070
55461
|
case "review":
|
|
55071
55462
|
return cmdReview();
|
|
55072
55463
|
case "tick":
|
|
@@ -55145,6 +55536,8 @@ Commands:
|
|
|
55145
55536
|
status Print workspace + cloud status (incl. version + pending update)
|
|
55146
55537
|
usage Show current cloud plan, units remaining, estimated cost,
|
|
55147
55538
|
and per-tool usage (reads the gateway's batched Hono ledger)
|
|
55539
|
+
whoami [--json] Show the Console-resolved Personal/org/Team, agent,
|
|
55540
|
+
read visibility, and exact default contribution target.
|
|
55148
55541
|
update [--channel dev|latest] [--check]
|
|
55149
55542
|
Pull the newest build on this machine's channel via npm.
|
|
55150
55543
|
--check only reports; --channel switches + persists channel.
|
|
@@ -55193,8 +55586,12 @@ Commands:
|
|
|
55193
55586
|
surface (navigation, problems, claims, burst, health)
|
|
55194
55587
|
login Sign in with the cloud. Default: short verification URL +
|
|
55195
55588
|
typeable code (device-bridged OAuth). Flags: --browser
|
|
55196
|
-
(loopback code flow) \xB7 --token <key> \xB7
|
|
55589
|
+
(loopback code flow) \xB7 --token <key> \xB7
|
|
55590
|
+
--device --installation <uuid> [--profile <name>]
|
|
55591
|
+
(headless, installation-bound console device authorization)
|
|
55197
55592
|
logout Clear local cloud credentials
|
|
55593
|
+
doctor [--json] Verify profile, credential authority, renewal, endpoint,
|
|
55594
|
+
and authentication without printing secrets (alias: verify)
|
|
55198
55595
|
link Corrective project link (ambient linking covers the happy path).
|
|
55199
55596
|
Flags: --project <id> adopt an existing project (fork\u2192upstream);
|
|
55200
55597
|
--remote <name> derive the locator from a non-origin remote;
|
|
@@ -55203,6 +55600,12 @@ Commands:
|
|
|
55203
55600
|
use [<handle>] Set the sticky session active agent the daemon acts as.
|
|
55204
55601
|
No arg lists the agents you can act as + the current one;
|
|
55205
55602
|
--none (or --clear) reverts to your default identity.
|
|
55603
|
+
profile List named installation profiles and the active one.
|
|
55604
|
+
profile save <name> --installation <uuid>
|
|
55605
|
+
Bind the current credential to a named Console installation.
|
|
55606
|
+
profile use <name> Switch credential + agent context to an installed profile.
|
|
55607
|
+
profile remove <name>
|
|
55608
|
+
Remove a local profile (does not revoke it in the Console).
|
|
55206
55609
|
sync now Flush outbox to the cloud once
|
|
55207
55610
|
privacy Show what is collected/scrubbed + your consent state
|
|
55208
55611
|
consent <channel> <on|off>
|
|
@@ -55215,7 +55618,8 @@ Commands:
|
|
|
55215
55618
|
|
|
55216
55619
|
Environment:
|
|
55217
55620
|
ERRATA_CLOUD_URL Cloud base URL (default ${DEFAULT_CLOUD_URL})
|
|
55218
|
-
ERRATA_ALLOW_DIRECT_V1_CLOUD=1
|
|
55621
|
+
ERRATA_ALLOW_DIRECT_V1_CLOUD=1 Staff-only: request direct legacy v1 (bypasses the gateway;
|
|
55622
|
+
also requires ERRATA_DIRECT_V1_ACK=I_ACCEPT_UNMETERED_DIRECT_V1)
|
|
55219
55623
|
${OAUTH_DEFAULT_ENV}=0 Test/dev escape hatch: plain \`errata login\` uses legacy device-code
|
|
55220
55624
|
`);
|
|
55221
55625
|
}
|
|
@@ -55237,9 +55641,7 @@ function resolveHookPort(explicit) {
|
|
|
55237
55641
|
async function cmdInit() {
|
|
55238
55642
|
const skipHooks = rest.includes("--skip-hooks");
|
|
55239
55643
|
const portIdx = rest.indexOf("--port");
|
|
55240
|
-
const port = resolveHookPort(
|
|
55241
|
-
portIdx >= 0 && rest[portIdx + 1] ? Number(rest[portIdx + 1]) : void 0
|
|
55242
|
-
);
|
|
55644
|
+
const port = resolveHookPort(portIdx >= 0 && rest[portIdx + 1] ? Number(rest[portIdx + 1]) : void 0);
|
|
55243
55645
|
const existing = loadProfile(ROOT);
|
|
55244
55646
|
if (existing) {
|
|
55245
55647
|
console.log(`already initialized: ${existing.id} (${existing.name})`);
|
|
@@ -55356,9 +55758,7 @@ async function cmdStart() {
|
|
|
55356
55758
|
if (claimed) {
|
|
55357
55759
|
const adopted = autodetectProfile(ROOT);
|
|
55358
55760
|
saveProfile(ROOT, adopted);
|
|
55359
|
-
console.log(
|
|
55360
|
-
`adopted: ${locator} is claimed by your org (project ${claimed.id}) \u2014 workspace initialized`
|
|
55361
|
-
);
|
|
55761
|
+
console.log(`adopted: ${locator} is claimed by your org (project ${claimed.id}) \u2014 workspace initialized`);
|
|
55362
55762
|
}
|
|
55363
55763
|
} catch {
|
|
55364
55764
|
}
|
|
@@ -55423,7 +55823,9 @@ async function cmdStatus() {
|
|
|
55423
55823
|
console.log(` workspace: ${profile ? `${profile.name} (${profile.id})` : "(not initialized)"}`);
|
|
55424
55824
|
if (profile) {
|
|
55425
55825
|
const link = profile.projectId ? ` \u2192 project ${profile.projectId.slice(0, 8)}` : " (unlinked)";
|
|
55426
|
-
console.log(
|
|
55826
|
+
console.log(
|
|
55827
|
+
` repo: ${profile.repoLocator ? `${profile.repoLocator}${link}` : "(no git remote \u2014 unlinked)"}`
|
|
55828
|
+
);
|
|
55427
55829
|
console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
|
|
55428
55830
|
console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
|
|
55429
55831
|
}
|
|
@@ -55445,12 +55847,13 @@ async function cmdStatus() {
|
|
|
55445
55847
|
);
|
|
55446
55848
|
console.log(` cloud:`);
|
|
55447
55849
|
console.log(` url: ${cfg.cloudUrl}`);
|
|
55850
|
+
console.log(` profile: ${cfg.activeInstallationProfile ?? "(unbound legacy credential)"}`);
|
|
55448
55851
|
if (!hasCloudCredential(cfg)) {
|
|
55449
55852
|
console.log(` logged in: no`);
|
|
55450
55853
|
} else if (cfg.accessToken) {
|
|
55451
55854
|
console.log(` logged in: yes (${cfg.email}) \u2014 attested daemon, can contribute`);
|
|
55452
55855
|
} else {
|
|
55453
|
-
console.log(` logged in: yes (${cfg.email}) \u2014
|
|
55856
|
+
console.log(` logged in: yes (${cfg.email}) \u2014 key capability enforced by Console installation/scopes`);
|
|
55454
55857
|
}
|
|
55455
55858
|
const active = getActiveAgent(cfg);
|
|
55456
55859
|
console.log(
|
|
@@ -55490,6 +55893,53 @@ async function cmdStatus() {
|
|
|
55490
55893
|
\u26A1 update available: ${upd.current} \u2192 ${upd.latest} \u2014 run: errata update`);
|
|
55491
55894
|
}
|
|
55492
55895
|
}
|
|
55896
|
+
async function cmdWhoami(args2) {
|
|
55897
|
+
const cfg = loadConfig();
|
|
55898
|
+
if (!hasCloudCredential(cfg)) {
|
|
55899
|
+
console.error("not logged in \u2014 run `errata login` or select an installation profile");
|
|
55900
|
+
process.exitCode = 1;
|
|
55901
|
+
return;
|
|
55902
|
+
}
|
|
55903
|
+
try {
|
|
55904
|
+
const active = getActiveAgent(cfg);
|
|
55905
|
+
const response = await resolveWhoami(authedCloudClient(cfg), active?.handle ?? null);
|
|
55906
|
+
if (args2.includes("--json")) {
|
|
55907
|
+
console.log(JSON.stringify(response, null, 2));
|
|
55908
|
+
return;
|
|
55909
|
+
}
|
|
55910
|
+
for (const line of formatWhoami(response, cfg.activeInstallationProfile)) console.log(line);
|
|
55911
|
+
} catch (err2) {
|
|
55912
|
+
console.error(`could not resolve context: ${err2 instanceof Error ? err2.message : err2}`);
|
|
55913
|
+
process.exitCode = 1;
|
|
55914
|
+
}
|
|
55915
|
+
}
|
|
55916
|
+
async function cmdDoctor(args2) {
|
|
55917
|
+
const cfg = loadConfig();
|
|
55918
|
+
const report = await diagnoseInstallation(cfg, {
|
|
55919
|
+
inspect: () => inspectCloudEndpoint(cfg.cloudUrl),
|
|
55920
|
+
authenticate: async () => {
|
|
55921
|
+
const me = await authedCloudClient(cfg).me();
|
|
55922
|
+
return { handle: me.handle, tier: me.tier };
|
|
55923
|
+
}
|
|
55924
|
+
});
|
|
55925
|
+
if (args2.includes("--json")) {
|
|
55926
|
+
console.log(JSON.stringify(report, null, 2));
|
|
55927
|
+
} else {
|
|
55928
|
+
console.log(`inErrata doctor \u2014 ${report.ok ? "ready" : "needs attention"}`);
|
|
55929
|
+
console.log(` profile: ${report.profile ?? "(none)"}`);
|
|
55930
|
+
console.log(` installation: ${report.installationId ?? "(none)"}`);
|
|
55931
|
+
for (const check2 of report.checks) {
|
|
55932
|
+
const marker = check2.status === "pass" ? "\u2713" : check2.status === "warn" ? "!" : "\u2717";
|
|
55933
|
+
console.log(` ${marker} ${check2.id}: ${check2.detail}`);
|
|
55934
|
+
}
|
|
55935
|
+
if (!report.ok) {
|
|
55936
|
+
console.log(
|
|
55937
|
+
" recovery: `errata profile list`, then `errata profile use <name>`; re-login if authentication still fails."
|
|
55938
|
+
);
|
|
55939
|
+
}
|
|
55940
|
+
}
|
|
55941
|
+
if (!report.ok) process.exitCode = 1;
|
|
55942
|
+
}
|
|
55493
55943
|
async function cmdUpdate(args2) {
|
|
55494
55944
|
const cfg = loadConfig();
|
|
55495
55945
|
let channel = cfg.updateChannel;
|
|
@@ -55550,6 +56000,10 @@ function parseFlags(args2) {
|
|
|
55550
56000
|
else if (a === "--oauth") out2.oauth = true;
|
|
55551
56001
|
else if (a === "--device") out2.device = true;
|
|
55552
56002
|
else if (a === "--browser") out2.browser = true;
|
|
56003
|
+
else if (a === "--installation") out2.installation = args2[++i2];
|
|
56004
|
+
else if (a.startsWith("--installation=")) out2.installation = a.slice("--installation=".length);
|
|
56005
|
+
else if (a === "--profile") out2.profile = args2[++i2];
|
|
56006
|
+
else if (a.startsWith("--profile=")) out2.profile = a.slice("--profile=".length);
|
|
55553
56007
|
else if (!a.startsWith("--")) out2._.push(a);
|
|
55554
56008
|
}
|
|
55555
56009
|
return out2;
|
|
@@ -55580,14 +56034,20 @@ async function cmdUsage() {
|
|
|
55580
56034
|
console.log(` held: ${status.quota.units_reserved.toLocaleString()} units reserved by in-flight calls`);
|
|
55581
56035
|
}
|
|
55582
56036
|
console.log(` cost: $${(status.quota.estimated_cents_current / 100).toFixed(2)} estimated`);
|
|
55583
|
-
console.log(
|
|
56037
|
+
console.log(
|
|
56038
|
+
` rate: $${(status.pricing.cents_per_1000_units / 100).toFixed(2)} / 1,000 units${status.pricing.estimate_only ? " (estimate, not an invoice)" : ""}`
|
|
56039
|
+
);
|
|
55584
56040
|
if (status.by_tool.length > 0) {
|
|
55585
56041
|
console.log(" tools:");
|
|
55586
56042
|
for (const row of [...status.by_tool].sort((a, b) => b.units - a.units).slice(0, 10)) {
|
|
55587
|
-
console.log(
|
|
56043
|
+
console.log(
|
|
56044
|
+
` ${row.tool.padEnd(24)} ${row.units.toLocaleString().padStart(8)} units ${row.event_count.toLocaleString().padStart(6)} calls`
|
|
56045
|
+
);
|
|
55588
56046
|
}
|
|
55589
56047
|
}
|
|
55590
|
-
console.log(
|
|
56048
|
+
console.log(
|
|
56049
|
+
` as of: ${status.as_of} (ledger + live reservations; poll again after ${Math.ceil(status.poll_after_ms / 1e3)}s)`
|
|
56050
|
+
);
|
|
55591
56051
|
} catch (err2) {
|
|
55592
56052
|
console.error(`usage unavailable: ${err2 instanceof Error ? err2.message : err2}`);
|
|
55593
56053
|
process.exitCode = 1;
|
|
@@ -55647,6 +56107,7 @@ async function cmdLoginOAuth(cfg, useBrowserLoopback = false) {
|
|
|
55647
56107
|
} catch (err2) {
|
|
55648
56108
|
console.error(`oauth login failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
55649
56109
|
if (!useBrowserLoopback) console.error(` try the browser flow: errata login --browser`);
|
|
56110
|
+
console.error(` use headless device login: errata login --device --installation <uuid>`);
|
|
55650
56111
|
console.error(` or paste a key: errata login --token <key>`);
|
|
55651
56112
|
process.exitCode = 1;
|
|
55652
56113
|
return;
|
|
@@ -55672,6 +56133,68 @@ async function cmdLoginOAuth(cfg, useBrowserLoopback = false) {
|
|
|
55672
56133
|
process.exitCode = 1;
|
|
55673
56134
|
}
|
|
55674
56135
|
}
|
|
56136
|
+
async function cmdLoginOAuthDevice(cfg, input) {
|
|
56137
|
+
const profileName = input.profileName?.trim() || `device-${input.installationId.slice(0, 8)}`;
|
|
56138
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(input.installationId)) {
|
|
56139
|
+
console.error("--installation must be a UUID from Console \u2192 Connect");
|
|
56140
|
+
process.exitCode = 1;
|
|
56141
|
+
return;
|
|
56142
|
+
}
|
|
56143
|
+
const inspection = await inspectCloudEndpoint(cfg.cloudUrl);
|
|
56144
|
+
try {
|
|
56145
|
+
assertCloudEndpointAllowed(cfg.cloudUrl, inspection);
|
|
56146
|
+
} catch (err2) {
|
|
56147
|
+
console.error(err2 instanceof Error ? err2.message : cloudPolicyMessage(cfg, inspection));
|
|
56148
|
+
process.exitCode = 1;
|
|
56149
|
+
return;
|
|
56150
|
+
}
|
|
56151
|
+
try {
|
|
56152
|
+
const result = await loginOAuthDevice({
|
|
56153
|
+
cloudUrl: cfg.cloudUrl,
|
|
56154
|
+
installationId: input.installationId,
|
|
56155
|
+
timeoutMs: 15 * 6e4,
|
|
56156
|
+
onVerification: ({ url: url2, userCode, expiresInSec }) => {
|
|
56157
|
+
console.log(`approve this device in the Console:
|
|
56158
|
+
${url2}`);
|
|
56159
|
+
console.log(`code: ${userCode} \xB7 expires in ${Math.round(expiresInSec / 60)} minutes`);
|
|
56160
|
+
}
|
|
56161
|
+
});
|
|
56162
|
+
const nextCfg = {
|
|
56163
|
+
...cfg,
|
|
56164
|
+
apiKey: null,
|
|
56165
|
+
accessToken: result.tokens.accessToken,
|
|
56166
|
+
refreshToken: result.tokens.refreshToken ?? null,
|
|
56167
|
+
tokenEndpoint: result.tokenEndpoint,
|
|
56168
|
+
oauthClientId: result.clientId,
|
|
56169
|
+
activeInstallationProfile: profileName,
|
|
56170
|
+
installationProfiles: {
|
|
56171
|
+
...cfg.installationProfiles,
|
|
56172
|
+
[profileName]: {
|
|
56173
|
+
installationId: result.installationId,
|
|
56174
|
+
cloudUrl: cfg.cloudUrl,
|
|
56175
|
+
apiKey: null,
|
|
56176
|
+
accessToken: result.tokens.accessToken,
|
|
56177
|
+
refreshToken: result.tokens.refreshToken ?? null,
|
|
56178
|
+
tokenEndpoint: result.tokenEndpoint,
|
|
56179
|
+
oauthClientId: result.clientId,
|
|
56180
|
+
activeAgent: cfg.activeAgent
|
|
56181
|
+
}
|
|
56182
|
+
}
|
|
56183
|
+
};
|
|
56184
|
+
const me = await authedCloudClient(nextCfg).me();
|
|
56185
|
+
nextCfg.userId = me.agentId;
|
|
56186
|
+
nextCfg.email = me.handle;
|
|
56187
|
+
saveConfig(nextCfg);
|
|
56188
|
+
console.log(
|
|
56189
|
+
`logged in as ${me.handle} (${me.tier}) \xB7 profile ${profileName} \xB7 installation ${result.installationId}`
|
|
56190
|
+
);
|
|
56191
|
+
await linkRegisteredWorkspaces(nextCfg);
|
|
56192
|
+
} catch (err2) {
|
|
56193
|
+
console.error(`device login failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56194
|
+
console.error(" no credential was stored; retry from Console \u2192 Connect");
|
|
56195
|
+
process.exitCode = 1;
|
|
56196
|
+
}
|
|
56197
|
+
}
|
|
55675
56198
|
async function linkRegisteredWorkspaces(cfg) {
|
|
55676
56199
|
if (!cfg.consent.sync) return;
|
|
55677
56200
|
const client = authedCloudClient(cfg);
|
|
@@ -55682,9 +56205,7 @@ async function linkRegisteredWorkspaces(cfg) {
|
|
|
55682
56205
|
refreshRepoLocator(w.path, profile);
|
|
55683
56206
|
const out2 = await ensureProjectLink(w.path, profile, client);
|
|
55684
56207
|
if (out2.linked) {
|
|
55685
|
-
console.log(
|
|
55686
|
-
` linked ${profile.name} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""}`
|
|
55687
|
-
);
|
|
56208
|
+
console.log(` linked ${profile.name} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""}`);
|
|
55688
56209
|
}
|
|
55689
56210
|
} catch {
|
|
55690
56211
|
}
|
|
@@ -55766,7 +56287,9 @@ async function cmdUnlink() {
|
|
|
55766
56287
|
delete profile.projectLocator;
|
|
55767
56288
|
profile.projectLinkDisabled = true;
|
|
55768
56289
|
saveProfile(ROOT, profile);
|
|
55769
|
-
console.log(
|
|
56290
|
+
console.log(
|
|
56291
|
+
had ? `unlinked from project ${had} (ambient linking disabled \u2014 re-enable with \`errata link\`)` : "already unlinked (ambient linking disabled)"
|
|
56292
|
+
);
|
|
55770
56293
|
}
|
|
55771
56294
|
async function cmdLogin() {
|
|
55772
56295
|
const cfg = loadConfig();
|
|
@@ -55776,6 +56299,18 @@ async function cmdLogin() {
|
|
|
55776
56299
|
await applyToken(cfg, flags2.token);
|
|
55777
56300
|
return;
|
|
55778
56301
|
}
|
|
56302
|
+
if (flags2.device) {
|
|
56303
|
+
if (!flags2.installation) {
|
|
56304
|
+
console.error("device login requires --installation <uuid> from Console \u2192 Connect");
|
|
56305
|
+
process.exitCode = 1;
|
|
56306
|
+
return;
|
|
56307
|
+
}
|
|
56308
|
+
await cmdLoginOAuthDevice(cfg, {
|
|
56309
|
+
installationId: flags2.installation,
|
|
56310
|
+
...flags2.profile ? { profileName: flags2.profile } : {}
|
|
56311
|
+
});
|
|
56312
|
+
return;
|
|
56313
|
+
}
|
|
55779
56314
|
if (shouldUseOAuthLogin(flags2)) {
|
|
55780
56315
|
await cmdLoginOAuth(cfg, flags2.browser ?? false);
|
|
55781
56316
|
return;
|
|
@@ -55810,7 +56345,9 @@ async function cmdLogin() {
|
|
|
55810
56345
|
await warnIfApprovalUnreachable(dc.verificationUrl);
|
|
55811
56346
|
console.log(`approve this device in your browser:
|
|
55812
56347
|
${dc.verificationUrl}`);
|
|
55813
|
-
console.log(
|
|
56348
|
+
console.log(
|
|
56349
|
+
`(code expires in ${Math.round(dc.expiresIn / 60)} minutes \u2014 or paste a key: errata login --token <key>)`
|
|
56350
|
+
);
|
|
55814
56351
|
const deadline = Date.now() + dc.expiresIn * 1e3;
|
|
55815
56352
|
const intervalMs = Math.max(2, dc.interval) * 1e3;
|
|
55816
56353
|
for (; ; ) {
|
|
@@ -55879,6 +56416,48 @@ async function cmdUse(args2) {
|
|
|
55879
56416
|
const code = await runUse(action, ctx);
|
|
55880
56417
|
if (code !== 0) process.exitCode = code;
|
|
55881
56418
|
}
|
|
56419
|
+
function cmdInstallationProfile(args2) {
|
|
56420
|
+
const cfg = loadConfig();
|
|
56421
|
+
const action = args2[0] ?? "list";
|
|
56422
|
+
if (action === "list") {
|
|
56423
|
+
const entries = Object.entries(cfg.installationProfiles).sort(([a], [b]) => a.localeCompare(b));
|
|
56424
|
+
if (entries.length === 0) {
|
|
56425
|
+
console.log("(no installation profiles \u2014 create one in the Console, then run profile save)");
|
|
56426
|
+
return;
|
|
56427
|
+
}
|
|
56428
|
+
for (const [name3, profile] of entries) {
|
|
56429
|
+
const marker = cfg.activeInstallationProfile === name3 ? "*" : " ";
|
|
56430
|
+
console.log(`${marker} ${name3} \xB7 ${profile.installationId} \xB7 ${profile.cloudUrl}`);
|
|
56431
|
+
}
|
|
56432
|
+
return;
|
|
56433
|
+
}
|
|
56434
|
+
const name2 = args2[1]?.trim();
|
|
56435
|
+
if (!name2) throw new Error(`usage: errata profile ${action} <name>`);
|
|
56436
|
+
if (action === "use") {
|
|
56437
|
+
const selected = useInstallationProfile(name2, cfg);
|
|
56438
|
+
const profile = selected.installationProfiles[name2];
|
|
56439
|
+
console.log(`profile active: ${name2} \xB7 installation ${profile.installationId}`);
|
|
56440
|
+
return;
|
|
56441
|
+
}
|
|
56442
|
+
if (action === "remove") {
|
|
56443
|
+
removeInstallationProfile(name2, cfg);
|
|
56444
|
+
console.log(`profile removed locally: ${name2}`);
|
|
56445
|
+
return;
|
|
56446
|
+
}
|
|
56447
|
+
if (action === "save") {
|
|
56448
|
+
const direct = args2.find((arg) => arg.startsWith("--installation="))?.slice("--installation=".length);
|
|
56449
|
+
const flag = args2.indexOf("--installation");
|
|
56450
|
+
const installationId = direct ?? (flag >= 0 ? args2[flag + 1] : void 0);
|
|
56451
|
+
if (!installationId) throw new Error("usage: errata profile save <name> --installation <uuid>");
|
|
56452
|
+
if (!hasCloudCredential(cfg)) {
|
|
56453
|
+
throw new Error("not logged in \u2014 install the Console credential before saving a profile");
|
|
56454
|
+
}
|
|
56455
|
+
saveInstallationProfile(name2, installationId, cfg);
|
|
56456
|
+
console.log(`profile saved: ${name2} \xB7 installation ${installationId}`);
|
|
56457
|
+
return;
|
|
56458
|
+
}
|
|
56459
|
+
throw new Error(`unknown profile action: ${action}`);
|
|
56460
|
+
}
|
|
55882
56461
|
async function cmdReview() {
|
|
55883
56462
|
const paths = workspacePaths(ROOT);
|
|
55884
56463
|
if (!existsSync24(paths.reviewQueue)) {
|
|
@@ -55959,9 +56538,7 @@ async function cmdLocate(relPath) {
|
|
|
55959
56538
|
const file2 = findFileByPath2(store, relPath);
|
|
55960
56539
|
if (!file2) {
|
|
55961
56540
|
console.error(`not indexed: ${relPath}`);
|
|
55962
|
-
console.error(
|
|
55963
|
-
" \u2192 did you run `errata reindex --clean`? did you spell the relative path right?"
|
|
55964
|
-
);
|
|
56541
|
+
console.error(" \u2192 did you run `errata reindex --clean`? did you spell the relative path right?");
|
|
55965
56542
|
process.exit(2);
|
|
55966
56543
|
}
|
|
55967
56544
|
const symbols = store.outEdges(file2.id, ["DEFINES", "CONTAINS"]).map((e) => store.getNode(e.to)).filter((n) => n != null);
|
|
@@ -56209,9 +56786,7 @@ async function cmdSearch(args2) {
|
|
|
56209
56786
|
for (const h of dual.results) {
|
|
56210
56787
|
console.log(`${h.id}`);
|
|
56211
56788
|
console.log(` [${h.label}] ${h.name.slice(0, 100)}`);
|
|
56212
|
-
console.log(
|
|
56213
|
-
` score ${Number(h.score).toFixed(4)}${h.provenance ? ` \xB7 ${h.provenance}` : ""}`
|
|
56214
|
-
);
|
|
56789
|
+
console.log(` score ${Number(h.score).toFixed(4)}${h.provenance ? ` \xB7 ${h.provenance}` : ""}`);
|
|
56215
56790
|
}
|
|
56216
56791
|
return;
|
|
56217
56792
|
}
|
|
@@ -56321,9 +56896,7 @@ async function cmdSimilar(args2) {
|
|
|
56321
56896
|
}
|
|
56322
56897
|
console.log(`seed: ${r.seedId}`);
|
|
56323
56898
|
for (const h of r.hits) {
|
|
56324
|
-
console.log(
|
|
56325
|
-
` ${h.score.toFixed(4)} [${h.label}] ${h.name.slice(0, 80)} (${h.id})`
|
|
56326
|
-
);
|
|
56899
|
+
console.log(` ${h.score.toFixed(4)} [${h.label}] ${h.name.slice(0, 80)} (${h.id})`);
|
|
56327
56900
|
}
|
|
56328
56901
|
});
|
|
56329
56902
|
}
|
|
@@ -56355,7 +56928,10 @@ unresolved \u2014 no node matched "${seed}". Try \`errata search ${seed}\` for f
|
|
|
56355
56928
|
return;
|
|
56356
56929
|
}
|
|
56357
56930
|
process.stdout.write(
|
|
56358
|
-
formatBurstMd2(result, {
|
|
56931
|
+
formatBurstMd2(result, {
|
|
56932
|
+
limit,
|
|
56933
|
+
seedLabel: seed
|
|
56934
|
+
})
|
|
56359
56935
|
);
|
|
56360
56936
|
});
|
|
56361
56937
|
}
|
|
@@ -56433,8 +57009,18 @@ async function gatherRepo(store, ws) {
|
|
|
56433
57009
|
const sol = firstHop(store, p.id, ["SOLVED_BY", "FIXED_BY"]);
|
|
56434
57010
|
const cause = firstHop(store, p.id, ["CAUSED_BY", "MANIFESTS_AS"]);
|
|
56435
57011
|
const pi = addSpine(p, "Problem");
|
|
56436
|
-
if (cause)
|
|
56437
|
-
|
|
57012
|
+
if (cause)
|
|
57013
|
+
spineEdges.push({
|
|
57014
|
+
a: pi,
|
|
57015
|
+
b: addSpine(cause, spineType(cause.label, "RootCause")),
|
|
57016
|
+
kind: "causal"
|
|
57017
|
+
});
|
|
57018
|
+
if (sol)
|
|
57019
|
+
spineEdges.push({
|
|
57020
|
+
a: pi,
|
|
57021
|
+
b: addSpine(sol, spineType(sol.label, "Solution")),
|
|
57022
|
+
kind: "causal"
|
|
57023
|
+
});
|
|
56438
57024
|
if (pIdx >= LEARNED_MAX) continue;
|
|
56439
57025
|
const srcCount = Array.isArray(p.attrs["sources"]) ? p.attrs["sources"].length : p.attrs["sources"] ? 1 : 0;
|
|
56440
57026
|
const agents = Math.max(1, srcCount + Number(p.attrs["corroborations"] ?? 0));
|
|
@@ -56499,11 +57085,21 @@ async function gatherRepo(store, ws) {
|
|
|
56499
57085
|
if (byFile.size > 0) {
|
|
56500
57086
|
const ranked = [...byFile].sort((a, b) => b[1] - a[1]).slice(0, 6);
|
|
56501
57087
|
const maxC = ranked[0]?.[1] ?? 1;
|
|
56502
|
-
hotspots = ranked.map(([file2, c]) => ({
|
|
57088
|
+
hotspots = ranked.map(([file2, c]) => ({
|
|
57089
|
+
file: file2.split(/[\\/]/).pop() ?? file2,
|
|
57090
|
+
problemCount: c,
|
|
57091
|
+
weight: c / maxC,
|
|
57092
|
+
unit: "probs"
|
|
57093
|
+
}));
|
|
56503
57094
|
} else {
|
|
56504
57095
|
const fan = await runTool2("errata.hotspots", { kind: "fan-in", limit: 6 }, store);
|
|
56505
57096
|
const maxF = fan.items[0]?.fanIn ?? 1;
|
|
56506
|
-
hotspots = fan.items.map((h) => ({
|
|
57097
|
+
hotspots = fan.items.map((h) => ({
|
|
57098
|
+
file: h.name.split(/[\\/]/).pop() ?? h.name,
|
|
57099
|
+
problemCount: h.fanIn,
|
|
57100
|
+
weight: (h.fanIn ?? 0) / maxF,
|
|
57101
|
+
unit: "fan-in"
|
|
57102
|
+
}));
|
|
56507
57103
|
}
|
|
56508
57104
|
const revisit = await runTool2("errata.needs_revisit", {}, store);
|
|
56509
57105
|
const machineOnly = SEMANTIC_LABELS2.reduce((sum, l) => sum + store.findNodesByLabel(l).length, 0);
|
|
@@ -56594,14 +57190,14 @@ async function cmdReport(args2) {
|
|
|
56594
57190
|
for (const f of files) writeFileSync18(join26(outDir, f.name), f.html, "utf8");
|
|
56595
57191
|
const indexPath = join26(outDir, "report.html");
|
|
56596
57192
|
console.log(`report \u2192 ${indexPath}`);
|
|
56597
|
-
console.log(
|
|
57193
|
+
console.log(
|
|
57194
|
+
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
57195
|
+
);
|
|
56598
57196
|
console.log(` open: file://${indexPath.replace(/\\/g, "/")}`);
|
|
56599
57197
|
}
|
|
56600
57198
|
async function cmdStop() {
|
|
56601
57199
|
const { unlinkSync: unlinkSync4 } = await import("node:fs");
|
|
56602
|
-
const lockPath = [globalDaemonLock(), workspacePaths(ROOT).daemonLock].find(
|
|
56603
|
-
(p) => readDaemonLock(p) !== null
|
|
56604
|
-
);
|
|
57200
|
+
const lockPath = [globalDaemonLock(), workspacePaths(ROOT).daemonLock].find((p) => readDaemonLock(p) !== null);
|
|
56605
57201
|
if (!lockPath) {
|
|
56606
57202
|
console.log(`no daemon lock found \u2014 nothing to stop`);
|
|
56607
57203
|
return;
|
|
@@ -56676,9 +57272,7 @@ function ensureSingletonRunning() {
|
|
|
56676
57272
|
async function cmdInstallHooks(args2) {
|
|
56677
57273
|
const harness = (args2[0] && !args2[0].startsWith("-") ? args2[0] : "claude").toLowerCase();
|
|
56678
57274
|
const portIdx = args2.indexOf("--port");
|
|
56679
|
-
const port = resolveHookPort(
|
|
56680
|
-
portIdx >= 0 && args2[portIdx + 1] ? Number(args2[portIdx + 1]) : void 0
|
|
56681
|
-
);
|
|
57275
|
+
const port = resolveHookPort(portIdx >= 0 && args2[portIdx + 1] ? Number(args2[portIdx + 1]) : void 0);
|
|
56682
57276
|
switch (harness) {
|
|
56683
57277
|
case "claude":
|
|
56684
57278
|
await installClaudeHooks(port);
|
|
@@ -56984,7 +57578,13 @@ async function cmdDash(args2) {
|
|
|
56984
57578
|
const reindexOnStart = !args2.includes("--no-reindex");
|
|
56985
57579
|
const skipEmbed = !args2.includes("--embed");
|
|
56986
57580
|
const skipWatchers = args2.includes("--no-watch");
|
|
56987
|
-
const handle2 = await startMultiDaemon({
|
|
57581
|
+
const handle2 = await startMultiDaemon({
|
|
57582
|
+
webPort: port,
|
|
57583
|
+
reindexOnStart,
|
|
57584
|
+
skipEmbed,
|
|
57585
|
+
skipWatchers,
|
|
57586
|
+
updateCheck: true
|
|
57587
|
+
});
|
|
56988
57588
|
console.log(`errata multi-daemon running`);
|
|
56989
57589
|
console.log(` endpoint: ${handle2.url} (JSON \u2014 the human view is \`errata report\`)`);
|
|
56990
57590
|
console.log(` projects: ${handle2.records.length}`);
|
|
@@ -57041,7 +57641,10 @@ async function cmdDash(args2) {
|
|
|
57041
57641
|
scheduleQuiescenceFlush();
|
|
57042
57642
|
}
|
|
57043
57643
|
if (notifyEnabled && (r.problemsResolved || r.reviewsTriggered)) {
|
|
57044
|
-
notifyTick({
|
|
57644
|
+
notifyTick({
|
|
57645
|
+
problemsResolved: r.problemsResolved,
|
|
57646
|
+
reviewsTriggered: r.reviewsTriggered
|
|
57647
|
+
});
|
|
57045
57648
|
}
|
|
57046
57649
|
}
|
|
57047
57650
|
}).finally(() => {
|
|
@@ -57067,7 +57670,10 @@ async function cmdDash(args2) {
|
|
|
57067
57670
|
}
|
|
57068
57671
|
}
|
|
57069
57672
|
if (skillsLearned > 0) {
|
|
57070
|
-
notifyEvent(
|
|
57673
|
+
notifyEvent(
|
|
57674
|
+
"skill-learned",
|
|
57675
|
+
skillsLearned === 1 ? "Distilled a new reusable skill from your work." : `Distilled ${skillsLearned} new skills from your work.`
|
|
57676
|
+
);
|
|
57071
57677
|
}
|
|
57072
57678
|
const p = await handle2.percolateAll();
|
|
57073
57679
|
const touched = /* @__PURE__ */ new Set();
|
|
@@ -57158,7 +57764,9 @@ async function cmdDash(args2) {
|
|
|
57158
57764
|
const fanIn = wStore.inEdges(anchor.to, [...CODE_REACH_EDGES]).length;
|
|
57159
57765
|
if (fanIn < HOTSPOT_FANIN) continue;
|
|
57160
57766
|
const sym = wStore.getNode(anchor.to)?.description ?? "a symbol";
|
|
57161
|
-
notifyEvent("hotspot-problem", `"${p2.description.slice(0, 60)}" touches ${sym} (${fanIn} dependents).`, {
|
|
57767
|
+
notifyEvent("hotspot-problem", `"${p2.description.slice(0, 60)}" touches ${sym} (${fanIn} dependents).`, {
|
|
57768
|
+
key: p2.id
|
|
57769
|
+
});
|
|
57162
57770
|
}
|
|
57163
57771
|
}
|
|
57164
57772
|
void handle2.syncPrinciplesPublic().then((r) => {
|
|
@@ -57188,7 +57796,9 @@ async function cmdDash(args2) {
|
|
|
57188
57796
|
try {
|
|
57189
57797
|
await materializeOverview2(r.root, r.engine.store);
|
|
57190
57798
|
} catch (err2) {
|
|
57191
|
-
console.warn(
|
|
57799
|
+
console.warn(
|
|
57800
|
+
`[errata] overview refresh failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`
|
|
57801
|
+
);
|
|
57192
57802
|
}
|
|
57193
57803
|
}
|
|
57194
57804
|
maybeFlushDigests();
|
|
@@ -57203,7 +57813,12 @@ async function cmdDash(args2) {
|
|
|
57203
57813
|
if (consolidating) return;
|
|
57204
57814
|
if (process.uptime() < CONSOLIDATE_BOOT_GRACE_S) return;
|
|
57205
57815
|
consolidationState.momentum = totalMutations() - consolidatedAtMutations;
|
|
57206
|
-
if (!shouldConsolidate({
|
|
57816
|
+
if (!shouldConsolidate({
|
|
57817
|
+
now: Date.now(),
|
|
57818
|
+
state: consolidationState,
|
|
57819
|
+
policy: consolidationPolicy,
|
|
57820
|
+
force
|
|
57821
|
+
})) {
|
|
57207
57822
|
return;
|
|
57208
57823
|
}
|
|
57209
57824
|
consolidating = true;
|
|
@@ -57301,9 +57916,7 @@ async function cmdFeedback(args2) {
|
|
|
57301
57916
|
}
|
|
57302
57917
|
async function ensureProfile() {
|
|
57303
57918
|
if (!loadProfile(ROOT)) {
|
|
57304
|
-
console.error(
|
|
57305
|
-
`no errata workspace in ${ROOT}. Run 'errata init' first.`
|
|
57306
|
-
);
|
|
57919
|
+
console.error(`no errata workspace in ${ROOT}. Run 'errata init' first.`);
|
|
57307
57920
|
process.exit(2);
|
|
57308
57921
|
}
|
|
57309
57922
|
}
|