@inerrata-corporation/errata 2.0.7-dev.2797 → 2.0.7-dev.2822
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 +123 -12
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -79931,7 +79931,7 @@ function createWatchBreaker(deps) {
|
|
|
79931
79931
|
}
|
|
79932
79932
|
|
|
79933
79933
|
// src/engine.ts
|
|
79934
|
-
var DAEMON_VERSION = true ? "2.0.7-dev.
|
|
79934
|
+
var DAEMON_VERSION = true ? "2.0.7-dev.2822" : "2.0.0-alpha.0";
|
|
79935
79935
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
79936
79936
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
79937
79937
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -82219,6 +82219,14 @@ B: ${b}`,
|
|
|
82219
82219
|
const pending = existsSync25(paths.outbox) ? readdirSync10(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
|
|
82220
82220
|
return { uploaded: 0, failed: 0, remaining: pending };
|
|
82221
82221
|
}
|
|
82222
|
+
const onDisk = loadProfile(opts.workspaceRoot);
|
|
82223
|
+
if (!onDisk?.projectId && onDisk?.projectLinkHold) {
|
|
82224
|
+
console.log(
|
|
82225
|
+
"[errata] sync held \u2014 this repo is already on errata in another workspace; run `errata link` to join it or create your own project"
|
|
82226
|
+
);
|
|
82227
|
+
const pending = existsSync25(paths.outbox) ? readdirSync10(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
|
|
82228
|
+
return { uploaded: 0, failed: 0, remaining: pending };
|
|
82229
|
+
}
|
|
82222
82230
|
try {
|
|
82223
82231
|
const ignorePatterns = loadClaimIgnorePatterns(opts.workspaceRoot);
|
|
82224
82232
|
const claimPayload = buildClaimIngest(store, profile, DAEMON_VERSION, 1, ignorePatterns);
|
|
@@ -83715,6 +83723,11 @@ init_profile2();
|
|
|
83715
83723
|
import { execFile as execFile3 } from "node:child_process";
|
|
83716
83724
|
import { promisify } from "node:util";
|
|
83717
83725
|
var execFileAsync = promisify(execFile3);
|
|
83726
|
+
function isClaimedElsewhere(err2) {
|
|
83727
|
+
if (!err2 || typeof err2 !== "object") return false;
|
|
83728
|
+
const e = err2;
|
|
83729
|
+
return e.status === 409 && e.code === "claimed_elsewhere";
|
|
83730
|
+
}
|
|
83718
83731
|
async function readRootCommit(root) {
|
|
83719
83732
|
try {
|
|
83720
83733
|
const { stdout } = await execFileAsync("git", ["rev-list", "--max-parents=0", "HEAD"], {
|
|
@@ -83753,9 +83766,21 @@ async function ensureProjectLink(root, profile, client, rootCommit = readRootCom
|
|
|
83753
83766
|
profile.projectId = res.project.id;
|
|
83754
83767
|
profile.projectLocator = locator;
|
|
83755
83768
|
if (sha2) profile.rootCommitReportedFor = res.project.id;
|
|
83769
|
+
delete profile.projectLinkHold;
|
|
83756
83770
|
saveProfile(root, profile);
|
|
83757
83771
|
return { linked: true, projectId: res.project.id, created: res.created };
|
|
83758
83772
|
} catch (err2) {
|
|
83773
|
+
if (isClaimedElsewhere(err2)) {
|
|
83774
|
+
if (profile.projectLinkHold?.locator !== locator) {
|
|
83775
|
+
profile.projectLinkHold = { reason: "claimed-elsewhere", locator, since: Date.now() };
|
|
83776
|
+
saveProfile(root, profile);
|
|
83777
|
+
}
|
|
83778
|
+
return {
|
|
83779
|
+
linked: false,
|
|
83780
|
+
reason: "held",
|
|
83781
|
+
detail: "this repo is already on errata in another workspace \u2014 run `errata link` to join it or create your own project"
|
|
83782
|
+
};
|
|
83783
|
+
}
|
|
83759
83784
|
return {
|
|
83760
83785
|
linked: false,
|
|
83761
83786
|
reason: "error",
|
|
@@ -85034,16 +85059,28 @@ async function loginOAuthDevice(opts) {
|
|
|
85034
85059
|
if (approvedInstallation !== opts.installationId) {
|
|
85035
85060
|
throw new Error("approved installation does not match the terminal request");
|
|
85036
85061
|
}
|
|
85037
|
-
|
|
85062
|
+
return exchangeDeviceSession({
|
|
85063
|
+
fetchFn,
|
|
85064
|
+
resourceUrl: device.resource,
|
|
85065
|
+
deviceSession,
|
|
85066
|
+
installationId: approvedInstallation,
|
|
85067
|
+
clientId,
|
|
85068
|
+
scope
|
|
85069
|
+
});
|
|
85070
|
+
}
|
|
85071
|
+
async function exchangeDeviceSession(opts) {
|
|
85072
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
85073
|
+
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
85074
|
+
const resourceResponse = await fetchFn(opts.resourceUrl, {
|
|
85038
85075
|
method: "POST",
|
|
85039
85076
|
headers: {
|
|
85040
|
-
authorization: `Bearer ${deviceSession}`,
|
|
85077
|
+
authorization: `Bearer ${opts.deviceSession}`,
|
|
85041
85078
|
"content-type": "application/json",
|
|
85042
85079
|
accept: "application/json"
|
|
85043
85080
|
},
|
|
85044
85081
|
body: JSON.stringify({
|
|
85045
|
-
installationId:
|
|
85046
|
-
clientId,
|
|
85082
|
+
installationId: opts.installationId,
|
|
85083
|
+
clientId: opts.clientId,
|
|
85047
85084
|
scopes: scope.split(/\s+/).filter((value) => !["openid", "profile", "email", "offline_access"].includes(value))
|
|
85048
85085
|
})
|
|
85049
85086
|
});
|
|
@@ -85052,12 +85089,12 @@ async function loginOAuthDevice(opts) {
|
|
|
85052
85089
|
throw new Error(`device resource exchange failed: HTTP ${resourceResponse.status}`);
|
|
85053
85090
|
}
|
|
85054
85091
|
return {
|
|
85055
|
-
installationId:
|
|
85056
|
-
clientId,
|
|
85057
|
-
tokenEndpoint:
|
|
85092
|
+
installationId: opts.installationId,
|
|
85093
|
+
clientId: opts.clientId,
|
|
85094
|
+
tokenEndpoint: opts.resourceUrl,
|
|
85058
85095
|
tokens: {
|
|
85059
85096
|
accessToken: resource["access_token"],
|
|
85060
|
-
refreshToken: deviceSession,
|
|
85097
|
+
refreshToken: opts.deviceSession,
|
|
85061
85098
|
...typeof resource["expires_in"] === "number" ? { expiresInSec: resource["expires_in"] } : {}
|
|
85062
85099
|
}
|
|
85063
85100
|
};
|
|
@@ -85271,7 +85308,10 @@ async function linkThroughConsole(opts) {
|
|
|
85271
85308
|
return {
|
|
85272
85309
|
status: "approved",
|
|
85273
85310
|
decision,
|
|
85274
|
-
installationId: typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null
|
|
85311
|
+
installationId: typeof payload?.["installation_id"] === "string" ? payload["installation_id"] : null,
|
|
85312
|
+
deviceSession: typeof payload?.["access_token"] === "string" ? payload["access_token"] : null,
|
|
85313
|
+
resourceUrl: device.resource,
|
|
85314
|
+
clientId
|
|
85275
85315
|
};
|
|
85276
85316
|
}
|
|
85277
85317
|
return { status: "expired" };
|
|
@@ -86462,6 +86502,8 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86462
86502
|
);
|
|
86463
86503
|
} else if (out2.reason === "error") {
|
|
86464
86504
|
console.warn(`[errata] project link failed for ${r.engine.profile.name}: ${out2.detail}`);
|
|
86505
|
+
} else if (out2.reason === "held") {
|
|
86506
|
+
noteProjectHold(r.id, r.engine.profile.name, out2.detail);
|
|
86465
86507
|
}
|
|
86466
86508
|
let primeSalt = null;
|
|
86467
86509
|
if (r.engine.profile.projectId && !r.engine.profile.projectHydratedAt) {
|
|
@@ -86919,7 +86961,16 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86919
86961
|
const client = poolFor(recordIdentity);
|
|
86920
86962
|
const store = r.engine.store;
|
|
86921
86963
|
const projectName = r.engine.profile.name ?? r.engine.profile.id;
|
|
86922
|
-
const
|
|
86964
|
+
const onDisk = loadProfile(r.root);
|
|
86965
|
+
const onDiskProjectId = onDisk?.projectId;
|
|
86966
|
+
if (!onDiskProjectId && onDisk?.projectLinkHold) {
|
|
86967
|
+
noteProjectHold(
|
|
86968
|
+
r.id,
|
|
86969
|
+
r.entry.name,
|
|
86970
|
+
"this repo is already on errata in another workspace \u2014 run `errata link` to join it or create your own project"
|
|
86971
|
+
);
|
|
86972
|
+
continue;
|
|
86973
|
+
}
|
|
86923
86974
|
if (onDiskProjectId !== r.engine.profile.projectId) {
|
|
86924
86975
|
if (onDiskProjectId) r.engine.profile.projectId = onDiskProjectId;
|
|
86925
86976
|
else delete r.engine.profile.projectId;
|
|
@@ -88679,6 +88730,11 @@ async function cmdStatus() {
|
|
|
88679
88730
|
console.log(
|
|
88680
88731
|
` repo: ${profile.repoLocator ? `${profile.repoLocator}${link}` : "(no git remote \u2014 unlinked)"}`
|
|
88681
88732
|
);
|
|
88733
|
+
if (!profile.projectId && profile.projectLinkHold) {
|
|
88734
|
+
console.log(
|
|
88735
|
+
` HELD: this repo is already on errata in another workspace. Nothing syncs until you decide: run \`errata link\` to join it or create your own project.`
|
|
88736
|
+
);
|
|
88737
|
+
}
|
|
88682
88738
|
for (const h of await daemonHolds()) {
|
|
88683
88739
|
if (h.workspace !== profile.name && h.workspace !== profile.id) continue;
|
|
88684
88740
|
console.log(
|
|
@@ -89261,6 +89317,50 @@ async function linkRegisteredWorkspaces(cfg) {
|
|
|
89261
89317
|
}
|
|
89262
89318
|
}
|
|
89263
89319
|
}
|
|
89320
|
+
async function bindWorkspaceToLinkInstallation(cfg, out2, orgId) {
|
|
89321
|
+
const installationId = out2.installationId;
|
|
89322
|
+
if (!out2.deviceSession) {
|
|
89323
|
+
console.warn(
|
|
89324
|
+
` note: the project is in another org; run \`errata login --device --installation ${installationId} --profile <name>\` then \`errata workspace bind . --profile <name>\``
|
|
89325
|
+
);
|
|
89326
|
+
return null;
|
|
89327
|
+
}
|
|
89328
|
+
try {
|
|
89329
|
+
const minted = await exchangeDeviceSession({
|
|
89330
|
+
resourceUrl: out2.resourceUrl,
|
|
89331
|
+
deviceSession: out2.deviceSession,
|
|
89332
|
+
installationId,
|
|
89333
|
+
clientId: out2.clientId
|
|
89334
|
+
});
|
|
89335
|
+
const existing = Object.entries(cfg.installationProfiles).find(([, p]) => p.installationId === installationId)?.[0];
|
|
89336
|
+
let profileName = existing ?? `link-${orgId.slice(0, 8)}`;
|
|
89337
|
+
for (let i2 = 2; !existing && cfg.installationProfiles[profileName]; i2++) profileName = `link-${orgId.slice(0, 8)}-${i2}`;
|
|
89338
|
+
const next = {
|
|
89339
|
+
...cfg,
|
|
89340
|
+
installationProfiles: {
|
|
89341
|
+
...cfg.installationProfiles,
|
|
89342
|
+
[profileName]: {
|
|
89343
|
+
installationId,
|
|
89344
|
+
cloudUrl: cfg.cloudUrl,
|
|
89345
|
+
apiKey: null,
|
|
89346
|
+
accessToken: minted.tokens.accessToken,
|
|
89347
|
+
refreshToken: minted.tokens.refreshToken ?? null,
|
|
89348
|
+
tokenEndpoint: minted.tokenEndpoint,
|
|
89349
|
+
oauthClientId: minted.clientId,
|
|
89350
|
+
activeAgent: null
|
|
89351
|
+
}
|
|
89352
|
+
}
|
|
89353
|
+
};
|
|
89354
|
+
saveConfig(next);
|
|
89355
|
+
setWorkspaceBinding(workspaceEntryForPath(ROOT)?.id ?? ROOT, profileName);
|
|
89356
|
+
return { config: next, profileName };
|
|
89357
|
+
} catch (err2) {
|
|
89358
|
+
console.warn(
|
|
89359
|
+
` note: the project is linked, but this workspace could not take the other org's credential (${err2 instanceof Error ? err2.message : String(err2)}); run \`errata login --device --installation ${installationId} --profile <name>\` then \`errata workspace bind . --profile <name>\``
|
|
89360
|
+
);
|
|
89361
|
+
return null;
|
|
89362
|
+
}
|
|
89363
|
+
}
|
|
89264
89364
|
async function cmdLink(args2) {
|
|
89265
89365
|
const flag = (name2) => {
|
|
89266
89366
|
const i2 = args2.indexOf(name2);
|
|
@@ -89280,6 +89380,7 @@ async function cmdLink(args2) {
|
|
|
89280
89380
|
return;
|
|
89281
89381
|
}
|
|
89282
89382
|
delete profile.projectLinkDisabled;
|
|
89383
|
+
delete profile.projectLinkHold;
|
|
89283
89384
|
const remote = flag("--remote");
|
|
89284
89385
|
if (remote) {
|
|
89285
89386
|
const loc = detectRepoLocator(ROOT, remote);
|
|
@@ -89340,12 +89441,22 @@ async function cmdLink(args2) {
|
|
|
89340
89441
|
);
|
|
89341
89442
|
await refreshLinkedCodexHooks(args2);
|
|
89342
89443
|
if (applied.wroteIgnore) console.log("wrote .errataignore (starter) \u2014 edit it; it is your hard control");
|
|
89444
|
+
let reportClient = authedCloudClient(applied.config);
|
|
89445
|
+
if (out3.installationId && out3.installationId !== activeProfile?.installationId) {
|
|
89446
|
+
const bound = await bindWorkspaceToLinkInstallation(applied.config, out3, d.orgId);
|
|
89447
|
+
if (bound) {
|
|
89448
|
+
reportClient = authedCloudClientForProfile(bound.config, bound.profileName);
|
|
89449
|
+
console.log(
|
|
89450
|
+
`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`
|
|
89451
|
+
);
|
|
89452
|
+
}
|
|
89453
|
+
}
|
|
89343
89454
|
if (!hasCloudCredential(cfg)) {
|
|
89344
89455
|
console.log(" note: run `errata login` so this daemon can sync under the link and report the history stage.");
|
|
89345
89456
|
return;
|
|
89346
89457
|
}
|
|
89347
89458
|
const consents = historyConsents(applied.profile);
|
|
89348
|
-
const reported = await reportHistoryStage(
|
|
89459
|
+
const reported = await reportHistoryStage(reportClient, applied.profile, (line) => console.warn(line));
|
|
89349
89460
|
if (reported?.consents) {
|
|
89350
89461
|
const synced = applyConsents(applied.profile, applied.config, reported.consents, (/* @__PURE__ */ new Date()).toISOString());
|
|
89351
89462
|
if (synced.changed) {
|