@usepowerplant/cli 0.4.20 → 0.4.22
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/dist/cli.js +794 -302
- package/dist/hooks/powerplant-cloud-capture.mjs +747 -0
- package/dist/menubar/Powerplant.app.zip +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="91b4b5e6-fdd5-5127-9372-913ad2bc7af5")}catch(e){}}();
|
|
4
4
|
const __cliNodeMajor = Number(process.versions.node.split('.')[0]);
|
|
5
5
|
if (__cliNodeMajor < 20) {
|
|
6
6
|
console.error(`powerplant needs Node 20 or newer — this is Node ${process.versions.node}.`);
|
|
@@ -23886,7 +23886,7 @@ var require_mock_interceptor = __commonJS({
|
|
|
23886
23886
|
var require_mock_client = __commonJS({
|
|
23887
23887
|
"../../node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/mock/mock-client.js"(exports, module2) {
|
|
23888
23888
|
"use strict";
|
|
23889
|
-
var { promisify:
|
|
23889
|
+
var { promisify: promisify3 } = __require("node:util");
|
|
23890
23890
|
var Client2 = require_client();
|
|
23891
23891
|
var { buildMockDispatch } = require_mock_utils();
|
|
23892
23892
|
var {
|
|
@@ -23934,7 +23934,7 @@ var require_mock_client = __commonJS({
|
|
|
23934
23934
|
this[kDispatches] = [];
|
|
23935
23935
|
}
|
|
23936
23936
|
async [kClose]() {
|
|
23937
|
-
await
|
|
23937
|
+
await promisify3(this[kOriginalClose])();
|
|
23938
23938
|
this[kConnected] = 0;
|
|
23939
23939
|
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
|
23940
23940
|
}
|
|
@@ -24147,7 +24147,7 @@ var require_mock_call_history = __commonJS({
|
|
|
24147
24147
|
var require_mock_pool = __commonJS({
|
|
24148
24148
|
"../../node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/mock/mock-pool.js"(exports, module2) {
|
|
24149
24149
|
"use strict";
|
|
24150
|
-
var { promisify:
|
|
24150
|
+
var { promisify: promisify3 } = __require("node:util");
|
|
24151
24151
|
var Pool = require_pool();
|
|
24152
24152
|
var { buildMockDispatch } = require_mock_utils();
|
|
24153
24153
|
var {
|
|
@@ -24195,7 +24195,7 @@ var require_mock_pool = __commonJS({
|
|
|
24195
24195
|
this[kDispatches] = [];
|
|
24196
24196
|
}
|
|
24197
24197
|
async [kClose]() {
|
|
24198
|
-
await
|
|
24198
|
+
await promisify3(this[kOriginalClose])();
|
|
24199
24199
|
this[kConnected] = 0;
|
|
24200
24200
|
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
|
24201
24201
|
}
|
|
@@ -56051,7 +56051,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
56051
56051
|
return h ? h(node3, rewritten) : node3;
|
|
56052
56052
|
};
|
|
56053
56053
|
const cache = /* @__PURE__ */ new Map();
|
|
56054
|
-
function
|
|
56054
|
+
function run2(s) {
|
|
56055
56055
|
const cached3 = cache.get(s);
|
|
56056
56056
|
if (cached3 === RESOLVING) {
|
|
56057
56057
|
return new $ZodLazy({
|
|
@@ -56077,21 +56077,21 @@ function visit(schema, fnOrHandlers) {
|
|
|
56077
56077
|
let changed = false;
|
|
56078
56078
|
const newShape = {};
|
|
56079
56079
|
for (const k2 of keys) {
|
|
56080
|
-
const mapped =
|
|
56080
|
+
const mapped = run2(oldShape[k2]);
|
|
56081
56081
|
if (mapped !== oldShape[k2])
|
|
56082
56082
|
changed = true;
|
|
56083
56083
|
newShape[k2] = mapped;
|
|
56084
56084
|
}
|
|
56085
56085
|
let newCatchall = def.catchall;
|
|
56086
56086
|
if (def.catchall) {
|
|
56087
|
-
newCatchall =
|
|
56087
|
+
newCatchall = run2(def.catchall);
|
|
56088
56088
|
if (newCatchall !== def.catchall)
|
|
56089
56089
|
changed = true;
|
|
56090
56090
|
}
|
|
56091
56091
|
return changed ? clone(s, { ...def, shape: newShape, catchall: newCatchall }) : s;
|
|
56092
56092
|
}
|
|
56093
56093
|
case "array": {
|
|
56094
|
-
const mapped =
|
|
56094
|
+
const mapped = run2(def.element);
|
|
56095
56095
|
return mapped === def.element ? s : clone(s, { ...def, element: mapped });
|
|
56096
56096
|
}
|
|
56097
56097
|
case "tuple": {
|
|
@@ -56099,14 +56099,14 @@ function visit(schema, fnOrHandlers) {
|
|
|
56099
56099
|
let changed = false;
|
|
56100
56100
|
const newItems = [];
|
|
56101
56101
|
for (const item of oldItems) {
|
|
56102
|
-
const mapped =
|
|
56102
|
+
const mapped = run2(item);
|
|
56103
56103
|
if (mapped !== item)
|
|
56104
56104
|
changed = true;
|
|
56105
56105
|
newItems.push(mapped);
|
|
56106
56106
|
}
|
|
56107
56107
|
let newRest = def.rest;
|
|
56108
56108
|
if (def.rest) {
|
|
56109
|
-
newRest =
|
|
56109
|
+
newRest = run2(def.rest);
|
|
56110
56110
|
if (newRest !== def.rest)
|
|
56111
56111
|
changed = true;
|
|
56112
56112
|
}
|
|
@@ -56114,12 +56114,12 @@ function visit(schema, fnOrHandlers) {
|
|
|
56114
56114
|
}
|
|
56115
56115
|
case "record":
|
|
56116
56116
|
case "map": {
|
|
56117
|
-
const newKey =
|
|
56118
|
-
const newVal =
|
|
56117
|
+
const newKey = run2(def.keyType);
|
|
56118
|
+
const newVal = run2(def.valueType);
|
|
56119
56119
|
return newKey === def.keyType && newVal === def.valueType ? s : clone(s, { ...def, keyType: newKey, valueType: newVal });
|
|
56120
56120
|
}
|
|
56121
56121
|
case "set": {
|
|
56122
|
-
const newVal =
|
|
56122
|
+
const newVal = run2(def.valueType);
|
|
56123
56123
|
return newVal === def.valueType ? s : clone(s, { ...def, valueType: newVal });
|
|
56124
56124
|
}
|
|
56125
56125
|
case "union": {
|
|
@@ -56127,7 +56127,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
56127
56127
|
let changed = false;
|
|
56128
56128
|
const newOptions = [];
|
|
56129
56129
|
for (const opt of oldOptions) {
|
|
56130
|
-
const mapped =
|
|
56130
|
+
const mapped = run2(opt);
|
|
56131
56131
|
if (mapped !== opt)
|
|
56132
56132
|
changed = true;
|
|
56133
56133
|
newOptions.push(mapped);
|
|
@@ -56135,8 +56135,8 @@ function visit(schema, fnOrHandlers) {
|
|
|
56135
56135
|
return changed ? clone(s, { ...def, options: newOptions }) : s;
|
|
56136
56136
|
}
|
|
56137
56137
|
case "intersection": {
|
|
56138
|
-
const newLeft =
|
|
56139
|
-
const newRight =
|
|
56138
|
+
const newLeft = run2(def.left);
|
|
56139
|
+
const newRight = run2(def.right);
|
|
56140
56140
|
return newLeft === def.left && newRight === def.right ? s : clone(s, { ...def, left: newLeft, right: newRight });
|
|
56141
56141
|
}
|
|
56142
56142
|
case "optional":
|
|
@@ -56148,23 +56148,23 @@ function visit(schema, fnOrHandlers) {
|
|
|
56148
56148
|
case "nonoptional":
|
|
56149
56149
|
case "promise":
|
|
56150
56150
|
case "success": {
|
|
56151
|
-
const newInner =
|
|
56151
|
+
const newInner = run2(def.innerType);
|
|
56152
56152
|
return newInner === def.innerType ? s : clone(s, { ...def, innerType: newInner });
|
|
56153
56153
|
}
|
|
56154
56154
|
case "pipe": {
|
|
56155
|
-
const newIn =
|
|
56156
|
-
const newOut =
|
|
56155
|
+
const newIn = run2(def.in);
|
|
56156
|
+
const newOut = run2(def.out);
|
|
56157
56157
|
return newIn === def.in && newOut === def.out ? s : clone(s, { ...def, in: newIn, out: newOut });
|
|
56158
56158
|
}
|
|
56159
56159
|
case "function": {
|
|
56160
|
-
const newInput =
|
|
56161
|
-
const newOutput =
|
|
56160
|
+
const newInput = run2(def.input);
|
|
56161
|
+
const newOutput = run2(def.output);
|
|
56162
56162
|
return newInput === def.input && newOutput === def.output ? s : clone(s, { ...def, input: newInput, output: newOutput });
|
|
56163
56163
|
}
|
|
56164
56164
|
case "lazy": {
|
|
56165
56165
|
const original = def.getter;
|
|
56166
56166
|
const { _cachedInner, ...rest } = def;
|
|
56167
|
-
return clone(s, { ...rest, getter: () =>
|
|
56167
|
+
return clone(s, { ...rest, getter: () => run2(original()) });
|
|
56168
56168
|
}
|
|
56169
56169
|
// A leaf by choice: `parts` are regex fragments, not data positions.
|
|
56170
56170
|
case "template_literal":
|
|
@@ -56195,7 +56195,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
56195
56195
|
}
|
|
56196
56196
|
}
|
|
56197
56197
|
}
|
|
56198
|
-
return
|
|
56198
|
+
return run2(schema);
|
|
56199
56199
|
}
|
|
56200
56200
|
|
|
56201
56201
|
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/deep-partial.js
|
|
@@ -56630,9 +56630,9 @@ function isImageBase64Payload(record2, key) {
|
|
|
56630
56630
|
if (key === "base64") return isEncodedImage(data, record2.type);
|
|
56631
56631
|
return false;
|
|
56632
56632
|
}
|
|
56633
|
-
function describeImageBlock(
|
|
56634
|
-
if (
|
|
56635
|
-
const source = asRecord(
|
|
56633
|
+
function describeImageBlock(block2) {
|
|
56634
|
+
if (block2.type !== "image") return null;
|
|
56635
|
+
const source = asRecord(block2.source);
|
|
56636
56636
|
const mediaType = typeof source?.media_type === "string" ? source.media_type : null;
|
|
56637
56637
|
if (source?.type === "base64" && typeof source.data === "string") {
|
|
56638
56638
|
return { mediaType, bytes: base64ByteLength(source.data) };
|
|
@@ -56805,7 +56805,7 @@ function jsonTokens(text) {
|
|
|
56805
56805
|
let backslashes = 0;
|
|
56806
56806
|
while (text[index - backslashes - 1] === "\\") backslashes += 1;
|
|
56807
56807
|
let level = 0;
|
|
56808
|
-
for (let
|
|
56808
|
+
for (let run2 = backslashes + 1; run2 % 2 === 0; run2 /= 2) level += 1;
|
|
56809
56809
|
tokens.push({ index, level });
|
|
56810
56810
|
}
|
|
56811
56811
|
return tokens;
|
|
@@ -57641,8 +57641,8 @@ function createDigestTurnParser(options = {}) {
|
|
|
57641
57641
|
}
|
|
57642
57642
|
const model = typeof message2.model === "string" ? message2.model : null;
|
|
57643
57643
|
const facts = originFacts(record2);
|
|
57644
|
-
for (const
|
|
57645
|
-
const part =
|
|
57644
|
+
for (const block2 of message2.content) {
|
|
57645
|
+
const part = block2;
|
|
57646
57646
|
if (part.type === "tool_use" && typeof part.name === "string") {
|
|
57647
57647
|
const call = { name: part.name, ...toolFilePath(part.input) };
|
|
57648
57648
|
if (options.keepToolInputs === true && isRecord(part.input)) {
|
|
@@ -57757,19 +57757,19 @@ function toolResults(record2, evidence, tasks, line) {
|
|
|
57757
57757
|
const result = isRecord(record2.toolUseResult) ? record2.toolUseResult : {};
|
|
57758
57758
|
const file2 = isRecord(result.file) ? result.file : {};
|
|
57759
57759
|
const task = isRecord(result.task) ? result.task : {};
|
|
57760
|
-
for (const
|
|
57761
|
-
if (!isRecord(
|
|
57762
|
-
if (!evidence.watching(
|
|
57763
|
-
const reads = tasks.reads.get(
|
|
57764
|
-
tasks.reads.delete(
|
|
57760
|
+
for (const block2 of content) {
|
|
57761
|
+
if (!isRecord(block2) || block2.type !== "tool_result" || typeof block2.tool_use_id !== "string") continue;
|
|
57762
|
+
if (!evidence.watching(block2.tool_use_id)) continue;
|
|
57763
|
+
const reads = tasks.reads.get(block2.tool_use_id);
|
|
57764
|
+
tasks.reads.delete(block2.tool_use_id);
|
|
57765
57765
|
const started = typeof result.backgroundTaskId === "string" ? result.backgroundTaskId : null;
|
|
57766
57766
|
if (started !== null) keepBounded(tasks.started, started, reads ?? started);
|
|
57767
|
-
const failed2 =
|
|
57767
|
+
const failed2 = block2.is_error === true || result.interrupted === true;
|
|
57768
57768
|
const taskExited = typeof task.exitCode === "number" && task.task_id === reads;
|
|
57769
57769
|
const status = reads !== void 0 ? { succeeded: taskExited ? task.exitCode === 0 : null, running: taskExited ? null : reads } : { succeeded: failed2 ? false : started !== null ? null : true, running: started };
|
|
57770
|
-
evidence.result(
|
|
57770
|
+
evidence.result(block2.tool_use_id, {
|
|
57771
57771
|
...status,
|
|
57772
|
-
text: [result.stdout, result.stderr, file2.content, task.output].filter((part) => typeof part === "string").concat(contentText(
|
|
57772
|
+
text: [result.stdout, result.stderr, file2.content, task.output].filter((part) => typeof part === "string").concat(contentText(block2.content)).join("\n"),
|
|
57773
57773
|
at: recordTime(record2),
|
|
57774
57774
|
line
|
|
57775
57775
|
});
|
|
@@ -57778,7 +57778,7 @@ function toolResults(record2, evidence, tasks, line) {
|
|
|
57778
57778
|
function contentText(content) {
|
|
57779
57779
|
if (typeof content === "string") return content;
|
|
57780
57780
|
if (!Array.isArray(content)) return "";
|
|
57781
|
-
return content.map((
|
|
57781
|
+
return content.map((block2) => isRecord(block2) && typeof block2.text === "string" ? block2.text : "").join("\n");
|
|
57782
57782
|
}
|
|
57783
57783
|
function messageIdOf(record2, message2) {
|
|
57784
57784
|
if (typeof message2.id === "string") return message2.id;
|
|
@@ -57845,13 +57845,13 @@ function userText(record2) {
|
|
|
57845
57845
|
if (typeof content === "string") return content.trim() === "" ? null : content;
|
|
57846
57846
|
if (!Array.isArray(content)) return null;
|
|
57847
57847
|
const parts = [];
|
|
57848
|
-
for (const
|
|
57849
|
-
if (!isRecord(
|
|
57850
|
-
if (
|
|
57851
|
-
parts.push(
|
|
57848
|
+
for (const block2 of content) {
|
|
57849
|
+
if (!isRecord(block2)) continue;
|
|
57850
|
+
if (block2.type === "text" && typeof block2.text === "string" && block2.text.trim() !== "") {
|
|
57851
|
+
parts.push(block2.text);
|
|
57852
57852
|
continue;
|
|
57853
57853
|
}
|
|
57854
|
-
const image = describeImageBlock(
|
|
57854
|
+
const image = describeImageBlock(block2);
|
|
57855
57855
|
if (image) parts.push(imageLabel(image));
|
|
57856
57856
|
}
|
|
57857
57857
|
return parts.length > 0 ? parts.join("\n") : null;
|
|
@@ -58374,6 +58374,7 @@ var MACHINE_ENROLL_CALLBACK_URL = `http://127.0.0.1:${MACHINE_ENROLL_CALLBACK_PO
|
|
|
58374
58374
|
|
|
58375
58375
|
// ../core/src/sessionRooms.ts
|
|
58376
58376
|
var ROOM_QUIET_AFTER_MS = 7 * 24 * 36e5;
|
|
58377
|
+
var RECENT_ACTIVITY_WINDOW_MS = 5 * 24 * 36e5;
|
|
58377
58378
|
function capturedSessionEvents(turns, anchor2) {
|
|
58378
58379
|
const events = [];
|
|
58379
58380
|
const base = {
|
|
@@ -58459,22 +58460,22 @@ function safeJsonRecord(text) {
|
|
|
58459
58460
|
function outputTextBlocks(content) {
|
|
58460
58461
|
if (!Array.isArray(content)) return [];
|
|
58461
58462
|
return content.filter(
|
|
58462
|
-
(
|
|
58463
|
-
).map((
|
|
58463
|
+
(block2) => typeof block2 === "object" && block2 !== null && block2.type === "output_text" && typeof block2.text === "string"
|
|
58464
|
+
).map((block2) => block2.text);
|
|
58464
58465
|
}
|
|
58465
58466
|
function promptText(content) {
|
|
58466
58467
|
if (!Array.isArray(content)) return null;
|
|
58467
58468
|
const kept = [];
|
|
58468
58469
|
const textOrigins = [];
|
|
58469
58470
|
for (const raw of content) {
|
|
58470
|
-
const
|
|
58471
|
-
if (!
|
|
58472
|
-
if (
|
|
58473
|
-
kept.push(imageLabel(describeImageUrl(
|
|
58471
|
+
const block2 = asRecord2(raw);
|
|
58472
|
+
if (!block2) continue;
|
|
58473
|
+
if (block2.type === "input_image") {
|
|
58474
|
+
kept.push(imageLabel(describeImageUrl(block2.image_url)));
|
|
58474
58475
|
continue;
|
|
58475
58476
|
}
|
|
58476
|
-
if (
|
|
58477
|
-
const parsed = codexPromptBlock(
|
|
58477
|
+
if (block2.type !== "input_text" || typeof block2.text !== "string") continue;
|
|
58478
|
+
const parsed = codexPromptBlock(block2.text);
|
|
58478
58479
|
if (parsed.origin === "harness") continue;
|
|
58479
58480
|
textOrigins.push(parsed.origin);
|
|
58480
58481
|
if (parsed.ask !== "") kept.push(parsed.ask);
|
|
@@ -58689,8 +58690,8 @@ function scriptResult(evidence, script, header, blocks, at, line) {
|
|
|
58689
58690
|
function outputBlocks(output2) {
|
|
58690
58691
|
if (typeof output2 === "string") return [output2];
|
|
58691
58692
|
if (!Array.isArray(output2)) return [];
|
|
58692
|
-
return output2.map((
|
|
58693
|
-
const text = asRecord2(
|
|
58693
|
+
return output2.map((block2) => {
|
|
58694
|
+
const text = asRecord2(block2)?.text;
|
|
58694
58695
|
return typeof text === "string" ? text : "";
|
|
58695
58696
|
});
|
|
58696
58697
|
}
|
|
@@ -58818,9 +58819,9 @@ function parseCursorRunEventsDetailed(runs, options = {}) {
|
|
|
58818
58819
|
pendingTools = [];
|
|
58819
58820
|
pendingTokens = 0;
|
|
58820
58821
|
};
|
|
58821
|
-
for (const
|
|
58822
|
+
for (const run2 of runs) {
|
|
58822
58823
|
const openCalls = /* @__PURE__ */ new Map();
|
|
58823
|
-
for (const raw of
|
|
58824
|
+
for (const raw of run2.events) {
|
|
58824
58825
|
const evt = asRawEvent(raw);
|
|
58825
58826
|
if (!evt) continue;
|
|
58826
58827
|
if (evt.event === "tool_call") {
|
|
@@ -59110,9 +59111,9 @@ function envelopeRuns(transcript) {
|
|
|
59110
59111
|
if (!parsed || !Array.isArray(parsed.runs)) return [];
|
|
59111
59112
|
const runs = [];
|
|
59112
59113
|
for (const item of parsed.runs) {
|
|
59113
|
-
const
|
|
59114
|
-
if (typeof
|
|
59115
|
-
runs.push({ runId:
|
|
59114
|
+
const run2 = item;
|
|
59115
|
+
if (typeof run2?.runId !== "string" || typeof run2.sse !== "string") continue;
|
|
59116
|
+
runs.push({ runId: run2.runId, events: redactCursorRunEvents(parseSseEvents(run2.sse), { servedOnly: true }) });
|
|
59116
59117
|
}
|
|
59117
59118
|
return runs;
|
|
59118
59119
|
}
|
|
@@ -59131,30 +59132,104 @@ var SECRET_QUERY_PARAM_PATTERN = /^(?:token|access_token|refresh_token|id_token|
|
|
|
59131
59132
|
var BEARER_TOKEN_PATTERN = /\bBearer\s+[\w\-._~+/=]+/gi;
|
|
59132
59133
|
var JWT_PATTERN = /\b[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
|
|
59133
59134
|
var EMBEDDED_QUERY_SECRET_PATTERN = /([?&](?:token|access_token|refresh_token|id_token|api_key|apikey|key|code|signature|password|secret|client_secret|state)=)[^&\s#]+/gi;
|
|
59134
|
-
var
|
|
59135
|
+
var URL_USER_INFO_PATTERN = /(:\/\/)(?:[^\s/?#@"<>:[]+:(?!\d*(?:[/?#\s"<>]|$))[^\s"<>]{0,256}|[^\s/?#"<>]+)@/g;
|
|
59136
|
+
var URL_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
59137
|
+
"url",
|
|
59138
|
+
"to",
|
|
59139
|
+
"from",
|
|
59140
|
+
"href",
|
|
59141
|
+
"request_url",
|
|
59142
|
+
"referer",
|
|
59143
|
+
"url.full",
|
|
59144
|
+
"http.url",
|
|
59145
|
+
"http.target",
|
|
59146
|
+
"url.path"
|
|
59147
|
+
]);
|
|
59148
|
+
var KEPT_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
59149
|
+
"accept",
|
|
59150
|
+
"content-encoding",
|
|
59151
|
+
"content-length",
|
|
59152
|
+
"content-type",
|
|
59153
|
+
"host",
|
|
59154
|
+
"mcp-protocol-version",
|
|
59155
|
+
"referer",
|
|
59156
|
+
"user-agent",
|
|
59157
|
+
"x-github-event",
|
|
59158
|
+
"x-powerplant-cli-version"
|
|
59159
|
+
]);
|
|
59160
|
+
var KEPT_HTTP_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
59161
|
+
"http.method",
|
|
59162
|
+
"http.request.method",
|
|
59163
|
+
"http.request.method_original",
|
|
59164
|
+
"http.route",
|
|
59165
|
+
"http.status_code",
|
|
59166
|
+
"http.status_text",
|
|
59167
|
+
"http.response.status_code",
|
|
59168
|
+
"http.scheme",
|
|
59169
|
+
"http.host",
|
|
59170
|
+
"http.flavor",
|
|
59171
|
+
"http.request_content_length_uncompressed",
|
|
59172
|
+
"url.scheme",
|
|
59173
|
+
"url.full",
|
|
59174
|
+
"http.url",
|
|
59175
|
+
"http.target",
|
|
59176
|
+
"url.path"
|
|
59177
|
+
]);
|
|
59178
|
+
var HTTP_ATTRIBUTE_PREFIX = /^(?:http|url)\./;
|
|
59179
|
+
var URL_PARTS = /^([a-z][a-z\d+.-]*:\/\/)([^/?#]*)([^?#]*)/i;
|
|
59180
|
+
var PATH_KEPT_HOSTS = /(?:^|\.)(?:supabase\.co|usepowerplant\.com)$/i;
|
|
59181
|
+
var OUTGOING_ROUTES = [
|
|
59182
|
+
// GitHub REST API
|
|
59183
|
+
"/app/installations/{installation_id}/access_tokens",
|
|
59184
|
+
"/app/installations/{installation_id}",
|
|
59185
|
+
"/installation/repositories",
|
|
59186
|
+
"/orgs/{org}/memberships/{username}",
|
|
59187
|
+
"/repos/{owner}/{repo}/contents/{path}",
|
|
59188
|
+
"/user/installations",
|
|
59189
|
+
"/user/{account_id}",
|
|
59190
|
+
// GitHub sign-in
|
|
59191
|
+
"/login/oauth/access_token",
|
|
59192
|
+
// Cursor API
|
|
59193
|
+
"/v1/agents",
|
|
59194
|
+
"/v1/agents/{agent_id}",
|
|
59195
|
+
"/v1/agents/{agent_id}/runs",
|
|
59196
|
+
"/v1/agents/{agent_id}/runs/{run_id}",
|
|
59197
|
+
"/v1/agents/{agent_id}/runs/{run_id}/stream",
|
|
59198
|
+
"/teams/filtered-usage-events"
|
|
59199
|
+
];
|
|
59200
|
+
var OUTGOING_URL_FIELD_NAMES = ["url", "url.full", "http.url"];
|
|
59201
|
+
var OUTGOING_PATH_FIELD_NAMES = ["url.path", "http.target"];
|
|
59135
59202
|
var MAX_DEPTH = 10;
|
|
59136
59203
|
function scrubString(value) {
|
|
59137
|
-
return value.replace(POWERPLANT_TOKEN_PATTERN, REDACTED3).replace(BEARER_TOKEN_PATTERN, `Bearer ${REDACTED3}`).replace(JWT_PATTERN, REDACTED3).replace(EMBEDDED_QUERY_SECRET_PATTERN, `$1${REDACTED3}`);
|
|
59204
|
+
return scrubUserInfo(value).replace(POWERPLANT_TOKEN_PATTERN, REDACTED3).replace(BEARER_TOKEN_PATTERN, `Bearer ${REDACTED3}`).replace(JWT_PATTERN, REDACTED3).replace(EMBEDDED_QUERY_SECRET_PATTERN, `$1${REDACTED3}`);
|
|
59138
59205
|
}
|
|
59139
59206
|
function scrubUrl(url2) {
|
|
59140
|
-
|
|
59141
|
-
const
|
|
59142
|
-
|
|
59143
|
-
|
|
59144
|
-
|
|
59145
|
-
|
|
59146
|
-
|
|
59147
|
-
|
|
59148
|
-
|
|
59149
|
-
|
|
59150
|
-
|
|
59151
|
-
|
|
59152
|
-
|
|
59153
|
-
|
|
59154
|
-
|
|
59155
|
-
|
|
59156
|
-
|
|
59157
|
-
|
|
59207
|
+
const scrubbed = scrubUserInfo(url2);
|
|
59208
|
+
const queryStart = scrubbed.search(/[?#]/);
|
|
59209
|
+
return queryStart === -1 ? scrubbed : scrubbed.slice(0, queryStart);
|
|
59210
|
+
}
|
|
59211
|
+
function scrubUserInfo(value) {
|
|
59212
|
+
return value.replace(URL_USER_INFO_PATTERN, `$1${REDACTED3}@`);
|
|
59213
|
+
}
|
|
59214
|
+
function scrubOutgoingUrl(url2) {
|
|
59215
|
+
const parts = URL_PARTS.exec(url2);
|
|
59216
|
+
if (!parts) return REDACTED3;
|
|
59217
|
+
const [, scheme = "", authority = "", path38 = ""] = parts;
|
|
59218
|
+
const host = authority.slice(authority.lastIndexOf("@") + 1);
|
|
59219
|
+
const origin = `${scheme}${host}`;
|
|
59220
|
+
if (PATH_KEPT_HOSTS.test(host.replace(/:\d*$/, ""))) return `${origin}${path38}`;
|
|
59221
|
+
const route = OUTGOING_ROUTES.find((template) => fitsRoute(path38, template));
|
|
59222
|
+
return `${origin}${route ?? ""}`;
|
|
59223
|
+
}
|
|
59224
|
+
function fitsRoute(path38, template) {
|
|
59225
|
+
const segments = path38.replace(/(.)\/$/, "$1").split("/");
|
|
59226
|
+
const route = template.split("/");
|
|
59227
|
+
const hasRest = route.at(-1) === "{path}";
|
|
59228
|
+
const fixed = hasRest ? route.slice(0, -1) : route;
|
|
59229
|
+
if (hasRest ? segments.length < fixed.length : segments.length !== fixed.length) return false;
|
|
59230
|
+
return fixed.every(
|
|
59231
|
+
(part, index) => part.startsWith("{") ? segments[index] !== "" : part === segments[index]
|
|
59232
|
+
);
|
|
59158
59233
|
}
|
|
59159
59234
|
function scrubValue(value, depth = 0) {
|
|
59160
59235
|
if (depth > MAX_DEPTH || value == null) return value;
|
|
@@ -59163,9 +59238,10 @@ function scrubValue(value, depth = 0) {
|
|
|
59163
59238
|
if (typeof value !== "object") return value;
|
|
59164
59239
|
const out = {};
|
|
59165
59240
|
for (const [key, child] of Object.entries(value)) {
|
|
59166
|
-
|
|
59241
|
+
const name = key.toLowerCase();
|
|
59242
|
+
if (SECRET_KEY_PATTERN.test(key) || SECRET_QUERY_PARAM_PATTERN.test(key) || HTTP_ATTRIBUTE_PREFIX.test(name) && !KEPT_HTTP_ATTRIBUTES.has(name)) {
|
|
59167
59243
|
out[key] = REDACTED3;
|
|
59168
|
-
} else if (URL_FIELD_NAMES.has(
|
|
59244
|
+
} else if (URL_FIELD_NAMES.has(name) && typeof child === "string") {
|
|
59169
59245
|
out[key] = scrubUrl(child);
|
|
59170
59246
|
} else {
|
|
59171
59247
|
out[key] = scrubValue(child, depth + 1);
|
|
@@ -59178,17 +59254,21 @@ function scrubSentryEvent(event) {
|
|
|
59178
59254
|
if (typeof event.request.url === "string") {
|
|
59179
59255
|
event.request.url = scrubUrl(event.request.url);
|
|
59180
59256
|
}
|
|
59181
|
-
if (
|
|
59182
|
-
event.request.query_string =
|
|
59257
|
+
if (event.request.query_string !== void 0) {
|
|
59258
|
+
event.request.query_string = REDACTED3;
|
|
59183
59259
|
}
|
|
59184
59260
|
if (event.request.headers) {
|
|
59185
|
-
|
|
59261
|
+
const headers = Object.entries(event.request.headers).map(([name, value]) => [
|
|
59262
|
+
name,
|
|
59263
|
+
KEPT_HEADER_NAMES.has(name.toLowerCase()) ? value : REDACTED3
|
|
59264
|
+
]);
|
|
59265
|
+
event.request.headers = scrubValue(Object.fromEntries(headers));
|
|
59186
59266
|
}
|
|
59187
59267
|
if (event.request.cookies !== void 0) {
|
|
59188
59268
|
event.request.cookies = REDACTED3;
|
|
59189
59269
|
}
|
|
59190
59270
|
if (event.request.data !== void 0) {
|
|
59191
|
-
event.request.data =
|
|
59271
|
+
event.request.data = REDACTED3;
|
|
59192
59272
|
}
|
|
59193
59273
|
}
|
|
59194
59274
|
if (event.exception?.values) {
|
|
@@ -59210,14 +59290,45 @@ function scrubSentryEvent(event) {
|
|
|
59210
59290
|
if (Array.isArray(event.breadcrumbs)) {
|
|
59211
59291
|
event.breadcrumbs = event.breadcrumbs.map(scrubBreadcrumb);
|
|
59212
59292
|
}
|
|
59293
|
+
for (const span of event.spans ?? []) {
|
|
59294
|
+
if (typeof span.description === "string") {
|
|
59295
|
+
span.description = scrubString(span.description);
|
|
59296
|
+
}
|
|
59297
|
+
if (span.data) {
|
|
59298
|
+
span.data = scrubValue(span.data);
|
|
59299
|
+
}
|
|
59300
|
+
if (span.op === "http.client") {
|
|
59301
|
+
scrubOutgoingRequestSpan(span);
|
|
59302
|
+
}
|
|
59303
|
+
}
|
|
59213
59304
|
return event;
|
|
59214
59305
|
}
|
|
59306
|
+
function scrubOutgoingRequestSpan(span) {
|
|
59307
|
+
if (typeof span.description === "string") {
|
|
59308
|
+
const [method, ...target] = span.description.split(" ");
|
|
59309
|
+
if (target.length > 0) {
|
|
59310
|
+
span.description = `${method} ${scrubOutgoingUrl(target.join(" "))}`;
|
|
59311
|
+
}
|
|
59312
|
+
}
|
|
59313
|
+
const data = span.data;
|
|
59314
|
+
if (!data) return;
|
|
59315
|
+
for (const name of OUTGOING_URL_FIELD_NAMES) {
|
|
59316
|
+
const value = data[name];
|
|
59317
|
+
if (typeof value === "string") data[name] = scrubOutgoingUrl(value);
|
|
59318
|
+
}
|
|
59319
|
+
for (const name of OUTGOING_PATH_FIELD_NAMES) {
|
|
59320
|
+
if (name in data) data[name] = REDACTED3;
|
|
59321
|
+
}
|
|
59322
|
+
}
|
|
59215
59323
|
function scrubBreadcrumb(breadcrumb) {
|
|
59216
59324
|
if (typeof breadcrumb.message === "string") {
|
|
59217
59325
|
breadcrumb.message = scrubString(breadcrumb.message);
|
|
59218
59326
|
}
|
|
59219
59327
|
if (breadcrumb.data) {
|
|
59220
59328
|
breadcrumb.data = scrubValue(breadcrumb.data);
|
|
59329
|
+
if (breadcrumb.category === "http" && typeof breadcrumb.data.url === "string") {
|
|
59330
|
+
breadcrumb.data.url = scrubOutgoingUrl(breadcrumb.data.url);
|
|
59331
|
+
}
|
|
59221
59332
|
}
|
|
59222
59333
|
return breadcrumb;
|
|
59223
59334
|
}
|
|
@@ -59256,11 +59367,15 @@ function addLocalSessionEvent(evidence, event) {
|
|
|
59256
59367
|
const writes = writesAfterTurnEndMs.includes(event.atMs) ? writesAfterTurnEndMs : [...writesAfterTurnEndMs, event.atMs].sort((a, b2) => a - b2).slice(-WRITES_KEPT_AFTER_TURN_END);
|
|
59257
59368
|
return { ...evidence, lastWriteMs, writesAfterTurnEndMs: writes };
|
|
59258
59369
|
}
|
|
59259
|
-
case "turn-end":
|
|
59370
|
+
case "turn-end":
|
|
59371
|
+
case "transcript-turn-end": {
|
|
59372
|
+
const inTranscript = event.kind === "transcript-turn-end";
|
|
59373
|
+
if (event.atMs === lastTurnEndMs && inTranscript) return { ...evidence, lastTurnEndInTranscript: true };
|
|
59260
59374
|
if (lastTurnEndMs !== void 0 && event.atMs <= lastTurnEndMs) return evidence;
|
|
59261
59375
|
return {
|
|
59262
59376
|
...evidence,
|
|
59263
59377
|
lastTurnEndMs: event.atMs,
|
|
59378
|
+
lastTurnEndInTranscript: inTranscript,
|
|
59264
59379
|
lastWriteByTurnEndMs: latest(evidence.lastWriteByTurnEndMs, writesAfterTurnEndMs.findLast((ms) => ms <= event.atMs)),
|
|
59265
59380
|
writesAfterTurnEndMs: writesAfterTurnEndMs.filter((ms) => ms > event.atMs)
|
|
59266
59381
|
};
|
|
@@ -59284,16 +59399,19 @@ function deadlineAfterLastEvent({ lastWriteMs, lastTurnEndMs, lastBoundary }) {
|
|
|
59284
59399
|
function statusFromEvents({
|
|
59285
59400
|
lastWriteMs,
|
|
59286
59401
|
lastTurnEndMs,
|
|
59402
|
+
lastTurnEndInTranscript,
|
|
59287
59403
|
lastWriteByTurnEndMs,
|
|
59288
59404
|
lastBoundary
|
|
59289
59405
|
}) {
|
|
59290
|
-
const isNewWork = (writeMs, eventMs) => writeMs !== void 0 && writeMs > eventMs +
|
|
59406
|
+
const isNewWork = (writeMs, eventMs, slackMs2 = END_OBSERVATION_WRITE_SLACK_MS) => writeMs !== void 0 && writeMs > eventMs + slackMs2;
|
|
59291
59407
|
const endMs = lastBoundary?.event === "session-end" ? lastBoundary.atMs : void 0;
|
|
59292
59408
|
const startMs = lastBoundary?.event === "session-start" ? lastBoundary.atMs : void 0;
|
|
59293
59409
|
if (endMs !== void 0 && !isNewWork(lastWriteMs, endMs)) return "ended";
|
|
59294
59410
|
const turnEndCounts = endMs === void 0 || isNewWork(lastWriteByTurnEndMs, endMs);
|
|
59295
|
-
const
|
|
59296
|
-
|
|
59411
|
+
const turnEndMs = turnEndCounts ? lastTurnEndMs : void 0;
|
|
59412
|
+
const waitingSinceMs = latest(turnEndMs, startMs);
|
|
59413
|
+
const slackMs = waitingSinceMs === turnEndMs && lastTurnEndInTranscript === true ? 0 : END_OBSERVATION_WRITE_SLACK_MS;
|
|
59414
|
+
if (waitingSinceMs !== void 0 && !isNewWork(lastWriteMs, waitingSinceMs, slackMs)) return "waiting";
|
|
59297
59415
|
return lastWriteMs === void 0 ? "unknown" : "working";
|
|
59298
59416
|
}
|
|
59299
59417
|
function latest(a, b2) {
|
|
@@ -59416,9 +59534,10 @@ function parseCodexChildThread(sessionMeta) {
|
|
|
59416
59534
|
// ../core/src/recentSessionPage.ts
|
|
59417
59535
|
var RECENT_SESSION_WINDOW_MS = 72 * 60 * 60 * 1e3;
|
|
59418
59536
|
var RECENT_SESSION_VISIBLE_LIMIT = 12;
|
|
59537
|
+
var RECENT_SESSION_PAGE_MAX = 40;
|
|
59419
59538
|
var recentSessionOptionsSchema = external_exports.object({
|
|
59420
59539
|
windowHours: external_exports.coerce.number().int().min(1).max(120).default(72),
|
|
59421
|
-
limit: external_exports.coerce.number().int().min(1).max(
|
|
59540
|
+
limit: external_exports.coerce.number().int().min(1).max(RECENT_SESSION_PAGE_MAX).default(12)
|
|
59422
59541
|
});
|
|
59423
59542
|
var recentSessionCursorSchema = external_exports.object({
|
|
59424
59543
|
at: external_exports.iso.datetime({ offset: true }),
|
|
@@ -78610,10 +78729,10 @@ function dispatchEngineSpan(engineSpan, allSpans, linkIds, ignoreSpanTypes) {
|
|
|
78610
78729
|
}
|
|
78611
78730
|
);
|
|
78612
78731
|
}
|
|
78613
|
-
function endSpan2(span,
|
|
78732
|
+
function endSpan2(span, run2) {
|
|
78614
78733
|
let result;
|
|
78615
78734
|
try {
|
|
78616
|
-
result =
|
|
78735
|
+
result = run2();
|
|
78617
78736
|
} catch (reason) {
|
|
78618
78737
|
span.end();
|
|
78619
78738
|
throw reason;
|
|
@@ -80582,7 +80701,7 @@ var KafkaJsInstrumentation = class extends import_instrumentation9.Instrumentati
|
|
|
80582
80701
|
_getConsumerRunPatch() {
|
|
80583
80702
|
const instrumentation = this;
|
|
80584
80703
|
return (original) => {
|
|
80585
|
-
return function
|
|
80704
|
+
return function run2(...args) {
|
|
80586
80705
|
const config2 = args[0];
|
|
80587
80706
|
if (config2?.eachMessage) {
|
|
80588
80707
|
if ((0, import_instrumentation9.isWrapped)(config2.eachMessage)) {
|
|
@@ -86582,40 +86701,45 @@ function readCodexTranscriptDiscoveryRecords(home, roots) {
|
|
|
86582
86701
|
} catch {
|
|
86583
86702
|
return [];
|
|
86584
86703
|
}
|
|
86585
|
-
|
|
86586
|
-
|
|
86587
|
-
|
|
86704
|
+
return files.flatMap((file2) => {
|
|
86705
|
+
if (!/^[a-f0-9]{64}\.json$/.test(file2)) return [];
|
|
86706
|
+
const record2 = readRecord(path2.join(dir, file2), roots);
|
|
86707
|
+
return record2 === null ? [] : [record2];
|
|
86708
|
+
});
|
|
86709
|
+
}
|
|
86710
|
+
function readCodexTranscriptDiscoveryRecord(home, sessionId, roots) {
|
|
86711
|
+
return readRecord(codexTranscriptRecordPath(home, sessionId), roots);
|
|
86712
|
+
}
|
|
86713
|
+
function readRecord(recordPath, roots) {
|
|
86714
|
+
try {
|
|
86715
|
+
if (!lstatSync(recordPath).isFile()) return null;
|
|
86716
|
+
const fd = openSync(recordPath, "r");
|
|
86717
|
+
let text;
|
|
86588
86718
|
try {
|
|
86589
|
-
const
|
|
86590
|
-
|
|
86591
|
-
|
|
86592
|
-
|
|
86593
|
-
|
|
86594
|
-
|
|
86595
|
-
|
|
86596
|
-
|
|
86597
|
-
|
|
86598
|
-
|
|
86599
|
-
|
|
86600
|
-
|
|
86601
|
-
|
|
86602
|
-
|
|
86603
|
-
|
|
86604
|
-
|
|
86605
|
-
|
|
86606
|
-
|
|
86607
|
-
|
|
86608
|
-
|
|
86609
|
-
|
|
86610
|
-
|
|
86611
|
-
|
|
86612
|
-
if (realpathSync(rolloutPath) !== path2.join(realpathSync(root), path2.relative(root, rolloutPath)))
|
|
86613
|
-
continue;
|
|
86614
|
-
result.push({ rolloutPath, sessionId: record2.sessionId, archived: rootIndex === 1 });
|
|
86615
|
-
} catch {
|
|
86616
|
-
}
|
|
86719
|
+
const buffer = Buffer.alloc(32 * 1024 + 1);
|
|
86720
|
+
const read = readSync(fd, buffer, 0, buffer.length, null);
|
|
86721
|
+
if (read === buffer.length) return null;
|
|
86722
|
+
text = buffer.subarray(0, read).toString("utf8");
|
|
86723
|
+
} finally {
|
|
86724
|
+
closeSync(fd);
|
|
86725
|
+
}
|
|
86726
|
+
const record2 = transcriptDiscoveryRecordSchema.parse(JSON.parse(text));
|
|
86727
|
+
if (path2.basename(recordPath) !== `${createHash("sha256").update(record2.sessionId).digest("hex")}.json`) return null;
|
|
86728
|
+
if (record2.transcriptPath === null || !path2.isAbsolute(record2.transcriptPath)) return null;
|
|
86729
|
+
const rolloutPath = path2.normalize(record2.transcriptPath);
|
|
86730
|
+
if (path2.extname(rolloutPath) !== ".jsonl") return null;
|
|
86731
|
+
const rootIndex = roots.findIndex((root2) => {
|
|
86732
|
+
const relative2 = path2.relative(root2, rolloutPath);
|
|
86733
|
+
return relative2 !== "" && relative2 !== ".." && !relative2.startsWith(`..${path2.sep}`) && !path2.isAbsolute(relative2);
|
|
86734
|
+
});
|
|
86735
|
+
if (rootIndex < 0 || !lstatSync(rolloutPath).isFile()) return null;
|
|
86736
|
+
const root = roots[rootIndex];
|
|
86737
|
+
if (realpathSync(rolloutPath) !== path2.join(realpathSync(root), path2.relative(root, rolloutPath)))
|
|
86738
|
+
return null;
|
|
86739
|
+
return { rolloutPath, sessionId: record2.sessionId, archived: rootIndex === 1 };
|
|
86740
|
+
} catch {
|
|
86741
|
+
return null;
|
|
86617
86742
|
}
|
|
86618
|
-
return result;
|
|
86619
86743
|
}
|
|
86620
86744
|
|
|
86621
86745
|
// ../../apps/syncservice/src/diagnostics.ts
|
|
@@ -86624,7 +86748,7 @@ import { createHmac } from "node:crypto";
|
|
|
86624
86748
|
// ../../apps/syncservice/src/http.ts
|
|
86625
86749
|
var import_undici = __toESM(require_undici(), 1);
|
|
86626
86750
|
var CLI_VERSION_HEADER = "x-powerplant-cli-version";
|
|
86627
|
-
var cliVersion = true ? "0.4.
|
|
86751
|
+
var cliVersion = true ? "0.4.22" : "0.0.0-checkout";
|
|
86628
86752
|
function cliVersionHeaders() {
|
|
86629
86753
|
return { [CLI_VERSION_HEADER]: cliVersion, "user-agent": `powerplant-cli/${cliVersion}` };
|
|
86630
86754
|
}
|
|
@@ -87717,7 +87841,7 @@ function mayBeParentOf(parent, childMadeMs) {
|
|
|
87717
87841
|
function mayBeChildOf(threadTimeMs, parentTimeMs) {
|
|
87718
87842
|
return threadTimeMs === void 0 || parentTimeMs === void 0 || threadTimeMs + THREAD_ID_TIME_MARGIN_MS >= parentTimeMs;
|
|
87719
87843
|
}
|
|
87720
|
-
var CodexThreadLinks = class {
|
|
87844
|
+
var CodexThreadLinks = class _CodexThreadLinks {
|
|
87721
87845
|
/** `readLink` is a test seam for the first-record read. */
|
|
87722
87846
|
constructor(readLink = readThreadLink) {
|
|
87723
87847
|
this.readLink = readLink;
|
|
@@ -87743,6 +87867,19 @@ var CodexThreadLinks = class {
|
|
|
87743
87867
|
* (settleRecoveries), with the session the last pass made of it and how
|
|
87744
87868
|
* many uploads of it failed. */
|
|
87745
87869
|
recovering = /* @__PURE__ */ new Map();
|
|
87870
|
+
/** A copy for a pass that runs beside the watcher's own passes (the
|
|
87871
|
+
* new-session pass), so neither changes what the other knows. It keeps
|
|
87872
|
+
* what each rollout's first record showed, and leaves out the rollouts
|
|
87873
|
+
* and threads owed another read or a corrected capture, which only the
|
|
87874
|
+
* watcher's own passes settle. */
|
|
87875
|
+
copyForSidePass() {
|
|
87876
|
+
const copy = new _CodexThreadLinks(this.readLink);
|
|
87877
|
+
for (const [rolloutPath, link] of this.byPath) copy.byPath.set(rolloutPath, link);
|
|
87878
|
+
for (const [rolloutPath, changedMs] of this.failedAt) copy.failedAt.set(rolloutPath, changedMs);
|
|
87879
|
+
for (const [rolloutPath, state] of this.incomplete) copy.incomplete.set(rolloutPath, { ...state });
|
|
87880
|
+
for (const rolloutPath of this.faulted) copy.faulted.add(rolloutPath);
|
|
87881
|
+
return copy;
|
|
87882
|
+
}
|
|
87746
87883
|
/** Keeps what another read of the same first record found. */
|
|
87747
87884
|
remember(rolloutPath, link) {
|
|
87748
87885
|
this.byPath.set(rolloutPath, link);
|
|
@@ -87980,7 +88117,7 @@ var CodexThreadLinks = class {
|
|
|
87980
88117
|
return true;
|
|
87981
88118
|
}
|
|
87982
88119
|
};
|
|
87983
|
-
var CodexThreadReads = class {
|
|
88120
|
+
var CodexThreadReads = class _CodexThreadReads {
|
|
87984
88121
|
byThread = /* @__PURE__ */ new Map();
|
|
87985
88122
|
/** What a full read found when the thread's files were `files`
|
|
87986
88123
|
* (threadFilesKey): its summary and prefix, null for a thread holding no
|
|
@@ -87992,6 +88129,14 @@ var CodexThreadReads = class {
|
|
|
87992
88129
|
set(threadId2, files, read) {
|
|
87993
88130
|
this.byThread.set(threadId2, { files, read });
|
|
87994
88131
|
}
|
|
88132
|
+
/** A copy for a pass that runs beside the watcher's own passes. Each read
|
|
88133
|
+
* is kept for exactly the files it was made from, so a copy never serves
|
|
88134
|
+
* a read of files that have since changed. */
|
|
88135
|
+
copyForSidePass() {
|
|
88136
|
+
const copy = new _CodexThreadReads();
|
|
88137
|
+
for (const [threadId2, kept] of this.byThread) copy.byThread.set(threadId2, kept);
|
|
88138
|
+
return copy;
|
|
88139
|
+
}
|
|
87995
88140
|
/** Forgets the threads no longer on this machine. */
|
|
87996
88141
|
keepOnly(threadIds) {
|
|
87997
88142
|
for (const threadId2 of this.byThread.keys()) if (!threadIds.has(threadId2)) this.byThread.delete(threadId2);
|
|
@@ -90295,8 +90440,10 @@ var collectorStatusSchema = external_exports.object({
|
|
|
90295
90440
|
/** Last pass that completed without error — everything eligible had been
|
|
90296
90441
|
* uploaded as of this time. */
|
|
90297
90442
|
lastSyncAt: external_exports.string().optional(),
|
|
90298
|
-
/**
|
|
90299
|
-
*
|
|
90443
|
+
/** When the server last stored a changed session record, from any pass,
|
|
90444
|
+
* a recent catch-up inside one included. The next run of the same
|
|
90445
|
+
* enrollment carries it (carriedUploadClock). Missing: no upload in this
|
|
90446
|
+
* run or the one before it, not "never". */
|
|
90300
90447
|
lastUploadAt: external_exports.string().optional(),
|
|
90301
90448
|
consecutiveFailures: external_exports.number().int().nonnegative(),
|
|
90302
90449
|
/** Whether the hooks this daemon installed are firing, per harness
|
|
@@ -90867,7 +91014,7 @@ function saveCredentials(appEnv, credentials) {
|
|
|
90867
91014
|
function loadCredentials(appEnv) {
|
|
90868
91015
|
if (process.platform === "darwin") {
|
|
90869
91016
|
const raw2 = new MacosCredentialStore(appEnv).load();
|
|
90870
|
-
return raw2 === null ? null : parseStoredCredentials(raw2, appEnv);
|
|
91017
|
+
return raw2 === null ? null : withCurrentApiUrl(appEnv, parseStoredCredentials(raw2, appEnv));
|
|
90871
91018
|
}
|
|
90872
91019
|
let raw;
|
|
90873
91020
|
try {
|
|
@@ -90879,7 +91026,19 @@ function loadCredentials(appEnv) {
|
|
|
90879
91026
|
{ cause }
|
|
90880
91027
|
);
|
|
90881
91028
|
}
|
|
90882
|
-
return parseStoredCredentials(raw, appEnv);
|
|
91029
|
+
return withCurrentApiUrl(appEnv, parseStoredCredentials(raw, appEnv));
|
|
91030
|
+
}
|
|
91031
|
+
var RETIRED_API_URLS = {
|
|
91032
|
+
production: { retired: "https://api.powerplant.sh", replacement: "https://api.usepowerplant.com" },
|
|
91033
|
+
staging: {
|
|
91034
|
+
retired: "https://staging.api.powerplant.sh",
|
|
91035
|
+
replacement: "https://staging.api.usepowerplant.com"
|
|
91036
|
+
}
|
|
91037
|
+
};
|
|
91038
|
+
function withCurrentApiUrl(appEnv, credentials) {
|
|
91039
|
+
const moved = RETIRED_API_URLS[appEnv];
|
|
91040
|
+
if (moved === void 0 || credentials.apiUrl !== moved.retired) return credentials;
|
|
91041
|
+
return { ...credentials, apiUrl: moved.replacement };
|
|
90883
91042
|
}
|
|
90884
91043
|
function isCredentialStoreAbsent(cause) {
|
|
90885
91044
|
return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
@@ -90912,7 +91071,9 @@ import os14 from "node:os";
|
|
|
90912
91071
|
|
|
90913
91072
|
// ../../apps/syncservice/src/upload.ts
|
|
90914
91073
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
90915
|
-
import {
|
|
91074
|
+
import { setImmediate as yieldToEventLoop3 } from "node:timers/promises";
|
|
91075
|
+
import { promisify as promisify2 } from "node:util";
|
|
91076
|
+
import { gzip } from "node:zlib";
|
|
90916
91077
|
|
|
90917
91078
|
// ../../apps/syncservice/src/claudeCode.ts
|
|
90918
91079
|
import { readdirSync as readdirSync6 } from "node:fs";
|
|
@@ -90929,7 +91090,9 @@ function parseClaudeCodeTranscript(text) {
|
|
|
90929
91090
|
let entrypoint;
|
|
90930
91091
|
let anonCounter = 0;
|
|
90931
91092
|
let speedMode;
|
|
91093
|
+
let endsWithAbortedTurn = false;
|
|
90932
91094
|
for (const record2 of parseJsonl(text)) {
|
|
91095
|
+
endsWithAbortedTurn = abortedTurnOf(record2) ?? endsWithAbortedTurn;
|
|
90933
91096
|
if (record2.type === "custom-title" && typeof record2.customTitle === "string") {
|
|
90934
91097
|
title = record2.customTitle;
|
|
90935
91098
|
continue;
|
|
@@ -90990,8 +91153,38 @@ function parseClaudeCodeTranscript(text) {
|
|
|
90990
91153
|
turnCount: usageByMessage.size,
|
|
90991
91154
|
cwd,
|
|
90992
91155
|
gitBranch,
|
|
90993
|
-
entrypoint
|
|
90994
|
-
|
|
91156
|
+
entrypoint,
|
|
91157
|
+
endsWithAbortedTurn
|
|
91158
|
+
};
|
|
91159
|
+
}
|
|
91160
|
+
var STOPPED_TURN_TEXT = "[Request interrupted by user";
|
|
91161
|
+
var LOCAL_COMMAND_TEXT = /^\s*<(?:local-command-caveat|command-name|local-command-stdout|local-command-stderr)>/;
|
|
91162
|
+
var messageContentSchema = external_exports.object({ content: external_exports.union([external_exports.string(), external_exports.array(external_exports.unknown())]) });
|
|
91163
|
+
var textBlockSchema = external_exports.object({ type: external_exports.literal("text"), text: external_exports.string() });
|
|
91164
|
+
function abortedTurnOf(record2) {
|
|
91165
|
+
if (record2.type !== "user" && record2.type !== "assistant" || record2.isSidechain === true) return void 0;
|
|
91166
|
+
if (record2.type === "assistant") return record2.isApiErrorMessage === true;
|
|
91167
|
+
const text = firstText(record2.message);
|
|
91168
|
+
return LOCAL_COMMAND_TEXT.test(text) ? void 0 : text.startsWith(STOPPED_TURN_TEXT);
|
|
91169
|
+
}
|
|
91170
|
+
function claudeCodeEndsWithAbortedTurn(tail) {
|
|
91171
|
+
const records = [...parseJsonl(tail)];
|
|
91172
|
+
for (let index = records.length - 1; index >= 0; index -= 1) {
|
|
91173
|
+
const aborted2 = abortedTurnOf(records[index]);
|
|
91174
|
+
if (aborted2 !== void 0) return aborted2;
|
|
91175
|
+
}
|
|
91176
|
+
return false;
|
|
91177
|
+
}
|
|
91178
|
+
function firstText(message2) {
|
|
91179
|
+
const parsed = messageContentSchema.safeParse(message2);
|
|
91180
|
+
if (!parsed.success) return "";
|
|
91181
|
+
const { content } = parsed.data;
|
|
91182
|
+
if (typeof content === "string") return content;
|
|
91183
|
+
for (const block2 of content) {
|
|
91184
|
+
const text = textBlockSchema.safeParse(block2);
|
|
91185
|
+
if (text.success) return text.data.text;
|
|
91186
|
+
}
|
|
91187
|
+
return "";
|
|
90995
91188
|
}
|
|
90996
91189
|
var AGENT_SDK_ENTRYPOINTS = /* @__PURE__ */ new Set(["sdk-py", "sdk-ts"]);
|
|
90997
91190
|
function isAutomationEntrypoint(entrypoint) {
|
|
@@ -91101,6 +91294,7 @@ async function collectClaudeCodeSessions(options = {}) {
|
|
|
91101
91294
|
const endedAt = endObservedAt ?? laterTimestamp(summary.endedAt, usage.endedAt);
|
|
91102
91295
|
items.push({
|
|
91103
91296
|
mtimeMs,
|
|
91297
|
+
endsWithAbortedTurn: summary.endsWithAbortedTurn,
|
|
91104
91298
|
transcriptPath,
|
|
91105
91299
|
transcriptPrefix: transcript.prefix,
|
|
91106
91300
|
subagents: {
|
|
@@ -91219,9 +91413,9 @@ function listWorkflowTranscripts(workflowsDir) {
|
|
|
91219
91413
|
failedToRead();
|
|
91220
91414
|
return [];
|
|
91221
91415
|
};
|
|
91222
|
-
for (const
|
|
91223
|
-
if (!
|
|
91224
|
-
const runDir = path15.join(workflowsDir,
|
|
91416
|
+
for (const run2 of list(workflowsDir)) {
|
|
91417
|
+
if (!run2.isDirectory()) continue;
|
|
91418
|
+
const runDir = path15.join(workflowsDir, run2.name);
|
|
91225
91419
|
for (const file2 of list(runDir)) {
|
|
91226
91420
|
if (!file2.isFile() || !file2.name.endsWith(".jsonl")) continue;
|
|
91227
91421
|
try {
|
|
@@ -91490,8 +91684,20 @@ async function uploadPreviewRegistration(apiUrl, machineToken, registration) {
|
|
|
91490
91684
|
}
|
|
91491
91685
|
return "registered";
|
|
91492
91686
|
}
|
|
91493
|
-
|
|
91494
|
-
|
|
91687
|
+
var gzipAsync = promisify2(gzip);
|
|
91688
|
+
var REDACT_SLICE_CHARS = 64 * 1024;
|
|
91689
|
+
async function encodeRawTranscript(text) {
|
|
91690
|
+
const lines = text.split("\n");
|
|
91691
|
+
let sliceChars = 0;
|
|
91692
|
+
for (const [index, line] of lines.entries()) {
|
|
91693
|
+
lines[index] = redactJsonl(line);
|
|
91694
|
+
sliceChars += line.length;
|
|
91695
|
+
if (sliceChars >= REDACT_SLICE_CHARS) {
|
|
91696
|
+
await yieldToEventLoop3();
|
|
91697
|
+
sliceChars = 0;
|
|
91698
|
+
}
|
|
91699
|
+
}
|
|
91700
|
+
return gzipAsync(lines.join("\n"));
|
|
91495
91701
|
}
|
|
91496
91702
|
function readCollectedTranscript(file2, prefix) {
|
|
91497
91703
|
return prefix === void 0 ? readFileSync10(file2, "utf8") : readTranscriptPrefix(file2, prefix, false);
|
|
@@ -91501,8 +91707,8 @@ function readUnchangedTranscript(file2, prefix) {
|
|
|
91501
91707
|
}
|
|
91502
91708
|
var BUNDLE_HEADER_BYTES = 256;
|
|
91503
91709
|
var BUNDLE_HEADER_BYTES_PER_PART = 256;
|
|
91504
|
-
function rawUploadBody(session, readTranscript, maxBytes = MAX_RAW_UPLOAD_BYTES) {
|
|
91505
|
-
const main2 = encodeRawTranscript(readTranscript(session.transcriptPath, session.transcriptPrefix));
|
|
91710
|
+
async function rawUploadBody(session, readTranscript, maxBytes = MAX_RAW_UPLOAD_BYTES) {
|
|
91711
|
+
const main2 = await encodeRawTranscript(readTranscript(session.transcriptPath, session.transcriptPrefix));
|
|
91506
91712
|
if (session.subagents === void 0) {
|
|
91507
91713
|
return main2.byteLength > maxBytes ? "too-large" : { body: main2, main: main2, contentType: "application/gzip", skippedSubagentFiles: 0, unreadableSubagentFiles: 0 };
|
|
91508
91714
|
}
|
|
@@ -91514,7 +91720,7 @@ function rawUploadBody(session, readTranscript, maxBytes = MAX_RAW_UPLOAD_BYTES)
|
|
|
91514
91720
|
for (const file2 of session.subagents.files) {
|
|
91515
91721
|
let body;
|
|
91516
91722
|
try {
|
|
91517
|
-
body = encodeRawTranscript(readTranscript(file2.path, file2.prefix));
|
|
91723
|
+
body = await encodeRawTranscript(readTranscript(file2.path, file2.prefix));
|
|
91518
91724
|
} catch (error63) {
|
|
91519
91725
|
if (error63 instanceof TranscriptChangedError) throw error63;
|
|
91520
91726
|
skipped += 1;
|
|
@@ -91588,7 +91794,7 @@ async function uploadRawSessions(apiUrl, machineToken, transcriptUploadSources,
|
|
|
91588
91794
|
continue;
|
|
91589
91795
|
}
|
|
91590
91796
|
try {
|
|
91591
|
-
const encoded = rawUploadBody(session, readTranscript);
|
|
91797
|
+
const encoded = await rawUploadBody(session, readTranscript);
|
|
91592
91798
|
if (encoded === "too-large") {
|
|
91593
91799
|
summary.skippedTooLarge += 1;
|
|
91594
91800
|
summary.outcomes.set(key, "too-large");
|
|
@@ -92478,7 +92684,9 @@ var claudeLocal = {
|
|
|
92478
92684
|
},
|
|
92479
92685
|
registration: jsonServerEntry,
|
|
92480
92686
|
// <project folder>/<session id>.jsonl
|
|
92481
|
-
transcriptSession: (transcriptPath) => ({ externalId: path18.basename(transcriptPath, ".jsonl") })
|
|
92687
|
+
transcriptSession: (transcriptPath) => ({ externalId: path18.basename(transcriptPath, ".jsonl") }),
|
|
92688
|
+
// No Stop hook runs when a person stops a turn or the API fails it.
|
|
92689
|
+
endsWithAbortedTurn: claudeCodeEndsWithAbortedTurn
|
|
92482
92690
|
};
|
|
92483
92691
|
var codexLocal = {
|
|
92484
92692
|
harness: "codex-local",
|
|
@@ -92523,7 +92731,16 @@ var codexLocal = {
|
|
|
92523
92731
|
transcriptSession(transcriptPath) {
|
|
92524
92732
|
const identity = rolloutIdentity(transcriptPath);
|
|
92525
92733
|
return identity.page ? { hookId: identity.threadId } : { externalId: path18.basename(transcriptPath, ".jsonl") };
|
|
92526
|
-
}
|
|
92734
|
+
},
|
|
92735
|
+
// The hook records the rollout of each thread before it appends the
|
|
92736
|
+
// journal line (.claude/hooks/powerplant-codex-transcript.mjs).
|
|
92737
|
+
hookTranscriptPath(threadId2, homeDir) {
|
|
92738
|
+
const sessionsDir = path18.join(homeDir, ".codex", "sessions");
|
|
92739
|
+
return readCodexTranscriptDiscoveryRecord(homeDir, threadId2, [sessionsDir, codexArchivedSessionsDir(sessionsDir)])?.rolloutPath;
|
|
92740
|
+
},
|
|
92741
|
+
// The Codex app holds the rollout of each open thread for writing
|
|
92742
|
+
// (lsof, 2026-09-27), and macOS reports a write to it only on close.
|
|
92743
|
+
holdsTranscriptOpen: true
|
|
92527
92744
|
};
|
|
92528
92745
|
var cursorLocal = {
|
|
92529
92746
|
harness: "cursor-local",
|
|
@@ -93204,7 +93421,7 @@ function watchHarnessConnections(deps) {
|
|
|
93204
93421
|
}
|
|
93205
93422
|
}
|
|
93206
93423
|
};
|
|
93207
|
-
const
|
|
93424
|
+
const run2 = async (harnesses) => {
|
|
93208
93425
|
running = true;
|
|
93209
93426
|
try {
|
|
93210
93427
|
const before = /* @__PURE__ */ new Map();
|
|
@@ -93226,7 +93443,7 @@ function watchHarnessConnections(deps) {
|
|
|
93226
93443
|
if (queued !== null && !stopped) {
|
|
93227
93444
|
const next = queued === "all" ? void 0 : [...queued];
|
|
93228
93445
|
queued = null;
|
|
93229
|
-
void
|
|
93446
|
+
void run2(next);
|
|
93230
93447
|
}
|
|
93231
93448
|
};
|
|
93232
93449
|
const request2 = (harnesses) => {
|
|
@@ -93235,7 +93452,7 @@ function watchHarnessConnections(deps) {
|
|
|
93235
93452
|
queued = harnesses === void 0 || queued === "all" ? "all" : /* @__PURE__ */ new Set([...queued ?? [], ...harnesses]);
|
|
93236
93453
|
return;
|
|
93237
93454
|
}
|
|
93238
|
-
void
|
|
93455
|
+
void run2(harnesses);
|
|
93239
93456
|
};
|
|
93240
93457
|
request2(void 0);
|
|
93241
93458
|
const timer = setInterval(() => request2(void 0), SIGN_IN_CHECK_INTERVAL_MS);
|
|
@@ -93311,14 +93528,14 @@ function startHarnessConnectionChecks(options) {
|
|
|
93311
93528
|
}
|
|
93312
93529
|
|
|
93313
93530
|
// ../../apps/syncservice/src/recentCatchup.ts
|
|
93314
|
-
function createRecentCatchup(
|
|
93531
|
+
function createRecentCatchup(run2, now = Date.now) {
|
|
93315
93532
|
let coveredSince = now();
|
|
93316
93533
|
let nextCheck = coveredSince + 15e3;
|
|
93317
93534
|
return async () => {
|
|
93318
93535
|
const started = now();
|
|
93319
93536
|
if (started < nextCheck) return;
|
|
93320
93537
|
try {
|
|
93321
|
-
const result = await
|
|
93538
|
+
const result = await run2(coveredSince - 1e3);
|
|
93322
93539
|
if (result === false) return;
|
|
93323
93540
|
const diagnostic = result.diagnostic;
|
|
93324
93541
|
if (diagnostic?.rawFailed !== 0 || diagnostic.rawMissingMetadata !== 0 || diagnostic.deferred !== 0 || diagnostic.rawUnconfigured !== false) return;
|
|
@@ -93429,6 +93646,7 @@ function readIfExists2(p) {
|
|
|
93429
93646
|
}
|
|
93430
93647
|
|
|
93431
93648
|
// ../../apps/syncservice/src/previewRegistration.ts
|
|
93649
|
+
import { setImmediate as yieldToEventLoop4 } from "node:timers/promises";
|
|
93432
93650
|
async function registerAnnouncedPreviews(apiUrl, machineToken, collected, memo2, deps = {}) {
|
|
93433
93651
|
const readTranscript = deps.readTranscript ?? readIfExists;
|
|
93434
93652
|
const upload = deps.upload ?? uploadPreviewRegistration;
|
|
@@ -93444,6 +93662,7 @@ async function registerAnnouncedPreviews(apiUrl, machineToken, collected, memo2,
|
|
|
93444
93662
|
const state = memo2.get(key);
|
|
93445
93663
|
if (state?.foreignOwner || state?.previewsOff) continue;
|
|
93446
93664
|
if (state?.examinedMtimeMs === session.mtimeMs) continue;
|
|
93665
|
+
await yieldToEventLoop4();
|
|
93447
93666
|
try {
|
|
93448
93667
|
const text = readTranscript(session.transcriptPath);
|
|
93449
93668
|
if (text === null) continue;
|
|
@@ -93489,6 +93708,22 @@ async function registerAnnouncedPreviews(apiUrl, machineToken, collected, memo2,
|
|
|
93489
93708
|
}
|
|
93490
93709
|
|
|
93491
93710
|
// ../../apps/syncservice/src/sync.ts
|
|
93711
|
+
var RecordTurns = class {
|
|
93712
|
+
last = Promise.resolve();
|
|
93713
|
+
/** Waits for the passes ahead, then returns `end`, which lets the next
|
|
93714
|
+
* pass take its turn. Calling `end` again does nothing. */
|
|
93715
|
+
async take() {
|
|
93716
|
+
let end = () => {
|
|
93717
|
+
};
|
|
93718
|
+
const ended = new Promise((resolve2) => {
|
|
93719
|
+
end = resolve2;
|
|
93720
|
+
});
|
|
93721
|
+
const ahead = this.last;
|
|
93722
|
+
this.last = ahead.then(() => ended);
|
|
93723
|
+
await ahead;
|
|
93724
|
+
return end;
|
|
93725
|
+
}
|
|
93726
|
+
};
|
|
93492
93727
|
var defaultPolicyDeps = {
|
|
93493
93728
|
fetchPolicy: fetchCapturePolicy,
|
|
93494
93729
|
load: loadCredentials,
|
|
@@ -93590,7 +93825,17 @@ async function resolveCapturePolicy(config2, credentials, log3, deps = defaultPo
|
|
|
93590
93825
|
environment
|
|
93591
93826
|
};
|
|
93592
93827
|
}
|
|
93593
|
-
|
|
93828
|
+
function recordTurn(turns) {
|
|
93829
|
+
let end = () => {
|
|
93830
|
+
};
|
|
93831
|
+
return {
|
|
93832
|
+
start: async () => {
|
|
93833
|
+
if (turns) end = await turns.take();
|
|
93834
|
+
},
|
|
93835
|
+
end: () => end()
|
|
93836
|
+
};
|
|
93837
|
+
}
|
|
93838
|
+
async function runSyncPassInternal(config2, options, diagnostic, turn) {
|
|
93594
93839
|
const log3 = options.log ?? console.log;
|
|
93595
93840
|
const credentials = loadCredentials(config2.appEnv);
|
|
93596
93841
|
if (!credentials) {
|
|
@@ -93616,6 +93861,7 @@ async function runSyncPassInternal(config2, options, diagnostic) {
|
|
|
93616
93861
|
diagnostic.sinceMs = sinceMs;
|
|
93617
93862
|
diagnostic.deepSweep = window2.deepSweep;
|
|
93618
93863
|
const maxSessions = window2.deepSweep ? DEEP_FIRST_SYNC_MAX_SESSIONS : void 0;
|
|
93864
|
+
await turn.start();
|
|
93619
93865
|
diagnostic.stage = "claude";
|
|
93620
93866
|
const claude = await collectClaudeCodeSessions({
|
|
93621
93867
|
sinceMs,
|
|
@@ -93726,12 +93972,14 @@ async function runSyncPassInternal(config2, options, diagnostic) {
|
|
|
93726
93972
|
credentials.token,
|
|
93727
93973
|
items
|
|
93728
93974
|
);
|
|
93975
|
+
turn.end();
|
|
93729
93976
|
const foreignKeys = new Set(foreignOwned.map(sessionKey));
|
|
93730
93977
|
const writable = collected.filter(({ item }) => !foreignKeys.has(sessionKey(item)));
|
|
93731
93978
|
for (const { harness, harnessSessionId } of foreignOwned) {
|
|
93732
93979
|
log3(`Skipped ${harness} session ${harnessSessionId}: already synced from another machine.`);
|
|
93733
93980
|
}
|
|
93734
93981
|
Object.assign(diagnostic, { upserted, unchanged, outOfPolicy, deferred });
|
|
93982
|
+
if (upserted > 0) options.onRecordsUpserted?.();
|
|
93735
93983
|
log3(
|
|
93736
93984
|
`Uploaded: ${upserted} session(s) upserted` + (unchanged > 0 ? `, ${unchanged} unchanged (no writes issued)` : "") + "."
|
|
93737
93985
|
);
|
|
@@ -93863,8 +94111,9 @@ async function runSyncPass(config2, options = {}) {
|
|
|
93863
94111
|
}
|
|
93864
94112
|
};
|
|
93865
94113
|
notify();
|
|
94114
|
+
const turn = recordTurn(options.recordTurns);
|
|
93866
94115
|
try {
|
|
93867
|
-
const result = await runSyncPassInternal(config2, options, diagnostic);
|
|
94116
|
+
const result = await runSyncPassInternal(config2, options, diagnostic, turn);
|
|
93868
94117
|
diagnostic.outcome = "complete";
|
|
93869
94118
|
diagnostic.stage = "complete";
|
|
93870
94119
|
diagnostic.upserted = result.upserted;
|
|
@@ -93877,6 +94126,7 @@ async function runSyncPass(config2, options = {}) {
|
|
|
93877
94126
|
if (error63 instanceof Error) failedPasses.set(error63, diagnostic);
|
|
93878
94127
|
throw error63;
|
|
93879
94128
|
} finally {
|
|
94129
|
+
turn.end();
|
|
93880
94130
|
diagnostic.durationMs = Math.max(0, Date.now() - start);
|
|
93881
94131
|
notify();
|
|
93882
94132
|
}
|
|
@@ -93939,7 +94189,7 @@ function unsupportedVersionNotice(cliVersion2, oldestSupportedVersion) {
|
|
|
93939
94189
|
}
|
|
93940
94190
|
|
|
93941
94191
|
// ../../apps/syncservice/src/watch.ts
|
|
93942
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync11, watch as
|
|
94192
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync11, watch as fsWatch3 } from "node:fs";
|
|
93943
94193
|
import os19 from "node:os";
|
|
93944
94194
|
import path21 from "node:path";
|
|
93945
94195
|
|
|
@@ -93973,7 +94223,7 @@ function defaultStat(file2) {
|
|
|
93973
94223
|
}
|
|
93974
94224
|
|
|
93975
94225
|
// ../../apps/syncservice/src/sessionStatusFeed.ts
|
|
93976
|
-
import { statSync as statSync5 } from "node:fs";
|
|
94226
|
+
import { closeSync as closeSync7, fstatSync as fstatSync3, openSync as openSync7, readSync as readSync5, statSync as statSync5, watch as fsWatch2 } from "node:fs";
|
|
93977
94227
|
|
|
93978
94228
|
// ../../apps/syncservice/src/sessionStatusModel.ts
|
|
93979
94229
|
function createSessionStatusModel(now = Date.now) {
|
|
@@ -93992,6 +94242,7 @@ function createSessionStatusModel(now = Date.now) {
|
|
|
93992
94242
|
return {
|
|
93993
94243
|
applyLifecycleEntry: (entry) => apply(entry.harness, entry.sessionId, { kind: entry.event, atMs: Date.parse(entry.at) }),
|
|
93994
94244
|
applyTranscriptWrite: (write) => apply(write.harness, write.sessionId, { kind: "transcript-write", atMs: write.atMs }),
|
|
94245
|
+
applyTranscriptTurnEnd: (turnEnd) => apply(turnEnd.harness, turnEnd.sessionId, { kind: "transcript-turn-end", atMs: turnEnd.atMs }),
|
|
93995
94246
|
expireDeadlines() {
|
|
93996
94247
|
const nowMs = now();
|
|
93997
94248
|
const changes = [];
|
|
@@ -94024,11 +94275,14 @@ function createSessionStatusModel(now = Date.now) {
|
|
|
94024
94275
|
// ../../apps/syncservice/src/sessionStatusFeed.ts
|
|
94025
94276
|
var TRANSCRIPT_WRITE_DELAY_MS = 500;
|
|
94026
94277
|
var HELD_HOOK_ENTRIES_MAX = 500;
|
|
94278
|
+
var TRANSCRIPT_FILE_WATCHES_MAX = 32;
|
|
94279
|
+
var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
|
|
94027
94280
|
var HOOK_ID_PAIRS_MAX = 1e4;
|
|
94028
94281
|
var MAX_TIMER_MS = 2 ** 31 - 1;
|
|
94029
94282
|
function createSessionStatusFeed(deps) {
|
|
94030
94283
|
const now = deps.now ?? Date.now;
|
|
94031
94284
|
const adapters = deps.adapters ?? HARNESS_ADAPTERS;
|
|
94285
|
+
const watchFile = deps.watchFile ?? watchFileWrites;
|
|
94032
94286
|
const model = createSessionStatusModel(now);
|
|
94033
94287
|
const adapterOf = (harness) => adapters.find((adapter) => adapter.harness === harness);
|
|
94034
94288
|
const hookIdOf = (harness) => adapterOf(harness)?.hookSessionId;
|
|
@@ -94040,8 +94294,35 @@ function createSessionStatusFeed(deps) {
|
|
|
94040
94294
|
let readQueued = false;
|
|
94041
94295
|
let readFailing = false;
|
|
94042
94296
|
let statFailing = false;
|
|
94297
|
+
let tailFailing = false;
|
|
94298
|
+
let watchFailing = false;
|
|
94043
94299
|
const writeTimers = /* @__PURE__ */ new Map();
|
|
94300
|
+
const hookFilesRead = /* @__PURE__ */ new Set();
|
|
94301
|
+
const reportedFiles = /* @__PURE__ */ new Map();
|
|
94302
|
+
const fileWatches = /* @__PURE__ */ new Map();
|
|
94044
94303
|
let stopped = false;
|
|
94304
|
+
function applyJournalEntry(entry) {
|
|
94305
|
+
if (learnFromHookFile(entry.harness, entry.sessionId)) releaseHeld();
|
|
94306
|
+
apply(entry);
|
|
94307
|
+
}
|
|
94308
|
+
function learnFromHookFile(harness, hookId) {
|
|
94309
|
+
const adapter = adapterOf(harness);
|
|
94310
|
+
const hookIdOfStored = adapter?.hookSessionId;
|
|
94311
|
+
const key = pairKey(harness, hookId);
|
|
94312
|
+
if (adapter?.hookTranscriptPath === void 0 || hookIdOfStored === void 0 || hookFilesRead.has(key)) {
|
|
94313
|
+
return false;
|
|
94314
|
+
}
|
|
94315
|
+
hookFilesRead.add(key);
|
|
94316
|
+
const file2 = adapter.hookTranscriptPath(hookId, deps.home);
|
|
94317
|
+
const session = file2 === void 0 ? void 0 : adapter.transcriptSession?.(file2);
|
|
94318
|
+
if (file2 === void 0 || session === void 0) return false;
|
|
94319
|
+
const fileHookId = "externalId" in session ? hookIdOfStored(session.externalId) : session.hookId;
|
|
94320
|
+
if (pairKey(harness, fileHookId) !== key) return false;
|
|
94321
|
+
const externalId = "externalId" in session ? session.externalId : storedIds.get(key);
|
|
94322
|
+
if (externalId === void 0) return false;
|
|
94323
|
+
reportFile(file2, { harness, externalId });
|
|
94324
|
+
return "externalId" in session && learnPair(harness, externalId);
|
|
94325
|
+
}
|
|
94045
94326
|
function stored(entry) {
|
|
94046
94327
|
if (hookIdOf(entry.harness) === void 0) return entry;
|
|
94047
94328
|
const storedId = storedIds.get(pairKey(entry.harness, entry.sessionId));
|
|
@@ -94071,8 +94352,20 @@ function createSessionStatusFeed(deps) {
|
|
|
94071
94352
|
held = [];
|
|
94072
94353
|
for (const entry of waiting) apply(entry);
|
|
94073
94354
|
}
|
|
94074
|
-
function applyWrite(harness, sessionId, atMs) {
|
|
94075
|
-
|
|
94355
|
+
function applyWrite(harness, sessionId, atMs, endsWithAbortedTurn) {
|
|
94356
|
+
const before = model.status(harness, sessionId);
|
|
94357
|
+
model.applyTranscriptWrite({ harness, sessionId, atMs });
|
|
94358
|
+
const status = model.status(harness, sessionId);
|
|
94359
|
+
if ((status === "working" || status === "unknown") && endsWithAbortedTurn()) {
|
|
94360
|
+
model.applyTranscriptTurnEnd({ harness, sessionId, atMs });
|
|
94361
|
+
}
|
|
94362
|
+
if (model.status(harness, sessionId) !== before) changedInBatch = true;
|
|
94363
|
+
}
|
|
94364
|
+
function fileEndsWithAbortedTurn(harness, transcriptPath) {
|
|
94365
|
+
const endsWithAbortedTurn = adapterOf(harness)?.endsWithAbortedTurn;
|
|
94366
|
+
if (endsWithAbortedTurn === void 0) return false;
|
|
94367
|
+
const tail = transcriptTail(transcriptPath);
|
|
94368
|
+
return tail !== null && endsWithAbortedTurn(tail);
|
|
94076
94369
|
}
|
|
94077
94370
|
function applyWatchedWrite(harness, transcriptPath) {
|
|
94078
94371
|
const session = adapterOf(harness)?.transcriptSession?.(transcriptPath);
|
|
@@ -94082,9 +94375,69 @@ function createSessionStatusFeed(deps) {
|
|
|
94082
94375
|
const mtimeMs = modifiedMs(transcriptPath);
|
|
94083
94376
|
if (mtimeMs === null) return;
|
|
94084
94377
|
const learned = "externalId" in session && learnPair(harness, externalId);
|
|
94085
|
-
applyWrite(harness, externalId, mtimeMs);
|
|
94378
|
+
applyWrite(harness, externalId, mtimeMs, () => fileEndsWithAbortedTurn(harness, transcriptPath));
|
|
94379
|
+
reportFile(transcriptPath, { harness, externalId });
|
|
94086
94380
|
if (learned) releaseHeld();
|
|
94087
94381
|
}
|
|
94382
|
+
function reportFile(file2, session) {
|
|
94383
|
+
if (adapterOf(session.harness)?.holdsTranscriptOpen !== true) return;
|
|
94384
|
+
reportedFiles.delete(file2);
|
|
94385
|
+
reportedFiles.set(file2, session);
|
|
94386
|
+
}
|
|
94387
|
+
function needsFileWatch(session) {
|
|
94388
|
+
const status = model.status(session.harness, session.externalId);
|
|
94389
|
+
return status !== void 0 && status !== "ended";
|
|
94390
|
+
}
|
|
94391
|
+
function watchReportedFiles() {
|
|
94392
|
+
for (const [file2, watched] of fileWatches) {
|
|
94393
|
+
if (!needsFileWatch(watched)) closeFileWatch(file2);
|
|
94394
|
+
}
|
|
94395
|
+
const newest = [...reportedFiles].filter(([, session]) => needsFileWatch(session)).slice(-TRANSCRIPT_FILE_WATCHES_MAX);
|
|
94396
|
+
reportedFiles.clear();
|
|
94397
|
+
for (const [file2, session] of newest) {
|
|
94398
|
+
const watched = fileWatches.get(file2);
|
|
94399
|
+
if (watched === void 0) {
|
|
94400
|
+
openFileWatch(file2, session);
|
|
94401
|
+
} else {
|
|
94402
|
+
fileWatches.delete(file2);
|
|
94403
|
+
fileWatches.set(file2, watched);
|
|
94404
|
+
}
|
|
94405
|
+
}
|
|
94406
|
+
while (fileWatches.size > TRANSCRIPT_FILE_WATCHES_MAX) closeFileWatch(fileWatches.keys().next().value);
|
|
94407
|
+
}
|
|
94408
|
+
function openFileWatch(file2, session) {
|
|
94409
|
+
let close2;
|
|
94410
|
+
try {
|
|
94411
|
+
close2 = watchFile(
|
|
94412
|
+
file2,
|
|
94413
|
+
() => noteWrite(session.harness, file2),
|
|
94414
|
+
(error63) => {
|
|
94415
|
+
closeFileWatch(file2);
|
|
94416
|
+
noteWatchFailure(error63);
|
|
94417
|
+
}
|
|
94418
|
+
);
|
|
94419
|
+
} catch (error63) {
|
|
94420
|
+
if (errorCode(error63) !== "ENOENT") noteWatchFailure(error63);
|
|
94421
|
+
return;
|
|
94422
|
+
}
|
|
94423
|
+
if (watchFailing) deps.log("transcript files watched again");
|
|
94424
|
+
watchFailing = false;
|
|
94425
|
+
fileWatches.set(file2, { ...session, close: close2 });
|
|
94426
|
+
const mtimeMs = modifiedMs(file2);
|
|
94427
|
+
if (mtimeMs !== null) {
|
|
94428
|
+
applyWrite(session.harness, session.externalId, mtimeMs, () => fileEndsWithAbortedTurn(session.harness, file2));
|
|
94429
|
+
}
|
|
94430
|
+
}
|
|
94431
|
+
function closeFileWatch(file2) {
|
|
94432
|
+
fileWatches.get(file2)?.close();
|
|
94433
|
+
fileWatches.delete(file2);
|
|
94434
|
+
}
|
|
94435
|
+
function noteWatchFailure(error63) {
|
|
94436
|
+
if (!watchFailing) {
|
|
94437
|
+
deps.log(`\u26A0 transcript file not watched (${errorCode(error63)}), its status waits for hook events and sync passes`);
|
|
94438
|
+
}
|
|
94439
|
+
watchFailing = true;
|
|
94440
|
+
}
|
|
94088
94441
|
function modifiedMs(transcriptPath) {
|
|
94089
94442
|
try {
|
|
94090
94443
|
const mtimeMs = statSync5(transcriptPath).mtimeMs;
|
|
@@ -94092,7 +94445,10 @@ function createSessionStatusFeed(deps) {
|
|
|
94092
94445
|
statFailing = false;
|
|
94093
94446
|
return mtimeMs;
|
|
94094
94447
|
} catch (error63) {
|
|
94095
|
-
if (errorCode(error63) === "ENOENT")
|
|
94448
|
+
if (errorCode(error63) === "ENOENT") {
|
|
94449
|
+
closeFileWatch(transcriptPath);
|
|
94450
|
+
return null;
|
|
94451
|
+
}
|
|
94096
94452
|
if (!statFailing) {
|
|
94097
94453
|
deps.log(`\u26A0 transcript file not read (${errorCode(error63)}), its status waits for the next sync pass`);
|
|
94098
94454
|
}
|
|
@@ -94100,6 +94456,27 @@ function createSessionStatusFeed(deps) {
|
|
|
94100
94456
|
return null;
|
|
94101
94457
|
}
|
|
94102
94458
|
}
|
|
94459
|
+
function transcriptTail(transcriptPath) {
|
|
94460
|
+
let fd;
|
|
94461
|
+
try {
|
|
94462
|
+
fd = openSync7(transcriptPath, "r");
|
|
94463
|
+
const size = fstatSync3(fd).size;
|
|
94464
|
+
const buffer = Buffer.alloc(Math.min(size, TRANSCRIPT_TAIL_BYTES));
|
|
94465
|
+
const bytes = readSync5(fd, buffer, 0, buffer.length, size - buffer.length);
|
|
94466
|
+
if (tailFailing) deps.log("transcript ends readable again");
|
|
94467
|
+
tailFailing = false;
|
|
94468
|
+
return buffer.toString("utf8", 0, bytes);
|
|
94469
|
+
} catch (error63) {
|
|
94470
|
+
if (errorCode(error63) === "ENOENT") return null;
|
|
94471
|
+
if (!tailFailing) {
|
|
94472
|
+
deps.log(`\u26A0 transcript end not read (${errorCode(error63)}), a stopped turn shows as working until its deadline`);
|
|
94473
|
+
}
|
|
94474
|
+
tailFailing = true;
|
|
94475
|
+
return null;
|
|
94476
|
+
} finally {
|
|
94477
|
+
if (fd !== void 0) closeSync7(fd);
|
|
94478
|
+
}
|
|
94479
|
+
}
|
|
94103
94480
|
function noteWrite(harness, transcriptPath) {
|
|
94104
94481
|
if (writeTimers.has(transcriptPath)) return;
|
|
94105
94482
|
const timer = setTimeout(() => {
|
|
@@ -94111,8 +94488,10 @@ function createSessionStatusFeed(deps) {
|
|
|
94111
94488
|
timer.unref?.();
|
|
94112
94489
|
writeTimers.set(transcriptPath, timer);
|
|
94113
94490
|
}
|
|
94114
|
-
const journal = createLifecycleJournalReader(deps.home, void 0,
|
|
94491
|
+
const journal = createLifecycleJournalReader(deps.home, void 0, applyJournalEntry);
|
|
94115
94492
|
function settle2() {
|
|
94493
|
+
watchReportedFiles();
|
|
94494
|
+
hookFilesRead.clear();
|
|
94116
94495
|
armDeadline();
|
|
94117
94496
|
if (!changedInBatch) return;
|
|
94118
94497
|
changedInBatch = false;
|
|
@@ -94158,9 +94537,9 @@ function createSessionStatusFeed(deps) {
|
|
|
94158
94537
|
onEvent(change);
|
|
94159
94538
|
},
|
|
94160
94539
|
observeSessions(sessions) {
|
|
94161
|
-
for (const { item, mtimeMs } of sessions) {
|
|
94540
|
+
for (const { item, mtimeMs, endsWithAbortedTurn } of sessions) {
|
|
94162
94541
|
learnPair(item.harness, item.harnessSessionId);
|
|
94163
|
-
applyWrite(item.harness, item.harnessSessionId, mtimeMs);
|
|
94542
|
+
applyWrite(item.harness, item.harnessSessionId, mtimeMs, () => endsWithAbortedTurn === true);
|
|
94164
94543
|
}
|
|
94165
94544
|
releaseHeld();
|
|
94166
94545
|
settle2();
|
|
@@ -94169,6 +94548,7 @@ function createSessionStatusFeed(deps) {
|
|
|
94169
94548
|
const floorMs = lifecycleJournalRetentionFloorMs(now());
|
|
94170
94549
|
model.forgetBefore(floorMs);
|
|
94171
94550
|
held = held.filter((entry) => Date.parse(entry.at) >= floorMs);
|
|
94551
|
+
settle2();
|
|
94172
94552
|
journal.deleteExpired(now());
|
|
94173
94553
|
},
|
|
94174
94554
|
status: (harness, externalId) => model.status(harness, externalId),
|
|
@@ -94177,9 +94557,17 @@ function createSessionStatusFeed(deps) {
|
|
|
94177
94557
|
if (deadlineTimer) clearTimeout(deadlineTimer);
|
|
94178
94558
|
for (const timer of writeTimers.values()) clearTimeout(timer);
|
|
94179
94559
|
writeTimers.clear();
|
|
94560
|
+
for (const watched of fileWatches.values()) watched.close();
|
|
94561
|
+
fileWatches.clear();
|
|
94180
94562
|
}
|
|
94181
94563
|
};
|
|
94182
94564
|
}
|
|
94565
|
+
function watchFileWrites(file2, onWrite, onError2) {
|
|
94566
|
+
const watcher = fsWatch2(file2, onWrite);
|
|
94567
|
+
watcher.on("error", onError2);
|
|
94568
|
+
watcher.unref();
|
|
94569
|
+
return () => watcher.close();
|
|
94570
|
+
}
|
|
94183
94571
|
function errorCode(error63) {
|
|
94184
94572
|
return error63 instanceof Error && "code" in error63 && typeof error63.code === "string" ? error63.code : "unknown";
|
|
94185
94573
|
}
|
|
@@ -94238,6 +94626,8 @@ function createWatchLoop(deps) {
|
|
|
94238
94626
|
const newTranscripts = /* @__PURE__ */ new Map();
|
|
94239
94627
|
let newSessionTimer = null;
|
|
94240
94628
|
let newSessionPassDue = false;
|
|
94629
|
+
let newSessionRunning = false;
|
|
94630
|
+
let failedBesidePass = null;
|
|
94241
94631
|
function onEvent(change) {
|
|
94242
94632
|
if (stopped) return;
|
|
94243
94633
|
if (change === "lifecycle") lifecycleChanged = true;
|
|
@@ -94269,12 +94659,19 @@ function createWatchLoop(deps) {
|
|
|
94269
94659
|
newSessionPassDue = false;
|
|
94270
94660
|
return;
|
|
94271
94661
|
}
|
|
94272
|
-
if (
|
|
94662
|
+
if (newSessionRunning) return;
|
|
94663
|
+
if (now() < retryNotBefore) {
|
|
94664
|
+
newSessionTimer ??= setTimeout(() => {
|
|
94665
|
+
newSessionTimer = null;
|
|
94666
|
+
void newSessionPass();
|
|
94667
|
+
}, retryNotBefore - now());
|
|
94668
|
+
return;
|
|
94669
|
+
}
|
|
94273
94670
|
newSessionPassDue = false;
|
|
94274
94671
|
const transcripts = [...newTranscripts];
|
|
94275
94672
|
newTranscripts.clear();
|
|
94276
94673
|
if (transcripts.length === 0) return;
|
|
94277
|
-
|
|
94674
|
+
newSessionRunning = true;
|
|
94278
94675
|
deps.log(`${transcripts.length} new transcript file(s), uploading new session records now`);
|
|
94279
94676
|
const startedAt = now();
|
|
94280
94677
|
const known = new Set(knownSessions);
|
|
@@ -94284,21 +94681,22 @@ function createWatchLoop(deps) {
|
|
|
94284
94681
|
isNew: (session) => !known.has(sessionKey(session.item))
|
|
94285
94682
|
});
|
|
94286
94683
|
for (const session of summary.sessions) rememberSession(session);
|
|
94287
|
-
if (summary.upserted > 0) deps.onNewSessionsUploaded?.(now());
|
|
94288
94684
|
} catch (error63) {
|
|
94289
94685
|
const holdMs = Math.max(FAILED_PASS_RETRY_MS, retryAfterMs(error63) ?? 0);
|
|
94290
94686
|
retryNotBefore = Math.max(retryNotBefore, now() + holdMs);
|
|
94291
|
-
|
|
94687
|
+
const result = failedPassResult("new-session", startedAt, error63);
|
|
94688
|
+
if (running) failedBesidePass = result;
|
|
94689
|
+
else deps.onPassResult?.(result);
|
|
94292
94690
|
deps.log(
|
|
94293
94691
|
`new session records not uploaded (${describeError(error63)}), the next pass uploads them in ${describeDelay(holdMs)}`
|
|
94294
94692
|
);
|
|
94295
94693
|
}
|
|
94296
94694
|
for (const [transcript] of transcripts) rememberTranscript(transcript);
|
|
94297
|
-
|
|
94298
|
-
|
|
94695
|
+
newSessionRunning = false;
|
|
94696
|
+
void newSessionPass();
|
|
94299
94697
|
}
|
|
94300
|
-
function runNext(
|
|
94301
|
-
|
|
94698
|
+
function runNext() {
|
|
94699
|
+
void newSessionPass();
|
|
94302
94700
|
if (queued === null || running) return;
|
|
94303
94701
|
const next = queued === "steady" ? "net" : "change";
|
|
94304
94702
|
queued = null;
|
|
@@ -94385,6 +94783,7 @@ function createWatchLoop(deps) {
|
|
|
94385
94783
|
upserted: summary.upserted,
|
|
94386
94784
|
...summary.diagnostic && { diagnostic: summary.diagnostic }
|
|
94387
94785
|
});
|
|
94786
|
+
if (failedBesidePass !== null && now() < retryNotBefore) deps.onPassResult?.(failedBesidePass);
|
|
94388
94787
|
} catch (error63) {
|
|
94389
94788
|
consecutiveFailures += 1;
|
|
94390
94789
|
const signature = errorSignature(error63);
|
|
@@ -94400,7 +94799,7 @@ function createWatchLoop(deps) {
|
|
|
94400
94799
|
Math.min(FAILED_PASS_RETRY_MS * 2 ** (streakCount - 1), FAILED_PASS_BACKOFF_CAP_MS),
|
|
94401
94800
|
retryAfterMs(error63) ?? 0
|
|
94402
94801
|
);
|
|
94403
|
-
retryNotBefore = now() + holdMs;
|
|
94802
|
+
retryNotBefore = Math.max(retryNotBefore, now() + holdMs);
|
|
94404
94803
|
lifecycleChanged ||= consultLifecycle;
|
|
94405
94804
|
deps.onPassResult?.(failedPassResult(kind, startedAt, error63));
|
|
94406
94805
|
const failLine = `${kind} pass failed (${describeError(error63)})`;
|
|
@@ -94429,8 +94828,9 @@ function createWatchLoop(deps) {
|
|
|
94429
94828
|
}
|
|
94430
94829
|
}
|
|
94431
94830
|
running = false;
|
|
94831
|
+
failedBesidePass = null;
|
|
94432
94832
|
scheduleCompletionCheck();
|
|
94433
|
-
runNext(
|
|
94833
|
+
runNext();
|
|
94434
94834
|
}
|
|
94435
94835
|
function scheduleCompletionCheck() {
|
|
94436
94836
|
if (completionTimer) {
|
|
@@ -94517,7 +94917,7 @@ function watchEventChange(root, filename) {
|
|
|
94517
94917
|
}
|
|
94518
94918
|
function watchSessionStores(roots, onEvent, onLost) {
|
|
94519
94919
|
const watchers = roots.map((root) => {
|
|
94520
|
-
const watcher =
|
|
94920
|
+
const watcher = fsWatch3(root.dir, { recursive: root.recursive }, (_type, filename) => {
|
|
94521
94921
|
const change = watchEventChange(root, filename);
|
|
94522
94922
|
if (change !== "ignore") onEvent(change);
|
|
94523
94923
|
});
|
|
@@ -94531,10 +94931,12 @@ function watchSessionStores(roots, onEvent, onLost) {
|
|
|
94531
94931
|
function newSessionSyncOptions(shared, sinceMs, isNew) {
|
|
94532
94932
|
return {
|
|
94533
94933
|
lifecycleJournal: shared.lifecycleJournal,
|
|
94534
|
-
codexThreadLinks: shared.codexThreadLinks,
|
|
94535
|
-
codexThreadReads: shared.codexThreadReads,
|
|
94536
94934
|
log: shared.log,
|
|
94537
94935
|
enrollCommand: shared.enrollCommand,
|
|
94936
|
+
onRecordsUpserted: shared.onRecordsUpserted,
|
|
94937
|
+
recordTurns: shared.recordTurns,
|
|
94938
|
+
codexThreadLinks: shared.codexThreadLinks?.copyForSidePass(),
|
|
94939
|
+
codexThreadReads: shared.codexThreadReads?.copyForSidePass(),
|
|
94538
94940
|
explicitSince: String(STEADY_SYNC_WINDOW_DAYS),
|
|
94539
94941
|
narrowSinceMs: sinceMs,
|
|
94540
94942
|
isNewSession: isNew
|
|
@@ -94653,6 +95055,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
94653
95055
|
});
|
|
94654
95056
|
const writeStatus = (patch) => statusWriter.write(patch);
|
|
94655
95057
|
writeStatus({});
|
|
95058
|
+
const recordUpload = () => writeStatus({ lastUploadAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
94656
95059
|
const diagnostics = createDiagnosticsReporter(() => loadCredentials(config2.appEnv));
|
|
94657
95060
|
const checkIn = () => {
|
|
94658
95061
|
let current;
|
|
@@ -94734,6 +95137,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
94734
95137
|
const previewRegistrations = /* @__PURE__ */ new Map();
|
|
94735
95138
|
const codexThreadLinks = new CodexThreadLinks();
|
|
94736
95139
|
const codexThreadReads = new CodexThreadReads();
|
|
95140
|
+
const recordTurns = new RecordTurns();
|
|
94737
95141
|
const loop = createWatchLoop({
|
|
94738
95142
|
runPass: async (options) => {
|
|
94739
95143
|
let uploaded = 0;
|
|
@@ -94753,7 +95157,9 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
94753
95157
|
uploaded += 1;
|
|
94754
95158
|
if (uploaded === 1 || uploaded % 10 === 0)
|
|
94755
95159
|
log3(`Transcript progress: ${uploaded} uploaded this pass.`);
|
|
94756
|
-
}
|
|
95160
|
+
},
|
|
95161
|
+
onRecordsUpserted: recordUpload,
|
|
95162
|
+
recordTurns
|
|
94757
95163
|
};
|
|
94758
95164
|
const catchUp = createRecentCatchup(async (narrowSinceMs) => {
|
|
94759
95165
|
if (readCollectorControl(config2.appEnv, home).paused) return false;
|
|
@@ -94798,10 +95204,15 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
94798
95204
|
}
|
|
94799
95205
|
return summary;
|
|
94800
95206
|
},
|
|
94801
|
-
runNewSessionPass: ({ sinceMs, isNew }) => runSyncPass(config2, newSessionSyncOptions({
|
|
94802
|
-
|
|
94803
|
-
|
|
94804
|
-
|
|
95207
|
+
runNewSessionPass: ({ sinceMs, isNew }) => runSyncPass(config2, newSessionSyncOptions({
|
|
95208
|
+
lifecycleJournal: journal,
|
|
95209
|
+
log: log3,
|
|
95210
|
+
enrollCommand: runtime.enrollCommand,
|
|
95211
|
+
onRecordsUpserted: recordUpload,
|
|
95212
|
+
recordTurns,
|
|
95213
|
+
codexThreadLinks,
|
|
95214
|
+
codexThreadReads
|
|
95215
|
+
}, sinceMs, isNew)),
|
|
94805
95216
|
paused: () => readCollectorControl(config2.appEnv, home).paused,
|
|
94806
95217
|
onPassResult: (result) => writeStatus({
|
|
94807
95218
|
lastPass: {
|
|
@@ -94814,7 +95225,6 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
94814
95225
|
...result.diagnostic && { diagnostic: result.diagnostic }
|
|
94815
95226
|
},
|
|
94816
95227
|
...result.ok && { lastSyncAt: new Date(result.at).toISOString() },
|
|
94817
|
-
...result.ok && result.upserted > 0 && { lastUploadAt: new Date(result.at).toISOString() },
|
|
94818
95228
|
consecutiveFailures: result.ok ? 0 : statusWriter.current.consecutiveFailures + 1
|
|
94819
95229
|
}),
|
|
94820
95230
|
reportError: reportCollectorError,
|
|
@@ -94897,7 +95307,7 @@ import os20 from "node:os";
|
|
|
94897
95307
|
import path23 from "node:path";
|
|
94898
95308
|
|
|
94899
95309
|
// ../../apps/syncservice/src/codexReviewFlags.ts
|
|
94900
|
-
import { closeSync as
|
|
95310
|
+
import { closeSync as closeSync8, lstatSync as lstatSync5, openSync as openSync8, readSync as readSync6, realpathSync as realpathSync4 } from "node:fs";
|
|
94901
95311
|
import path22 from "node:path";
|
|
94902
95312
|
var pointerSchema = external_exports.object({
|
|
94903
95313
|
source: external_exports.unknown().optional(),
|
|
@@ -94935,14 +95345,14 @@ function readCodexReviewFlags(row, id, home) {
|
|
|
94935
95345
|
}
|
|
94936
95346
|
}
|
|
94937
95347
|
function readPrefix(file2) {
|
|
94938
|
-
const fd =
|
|
95348
|
+
const fd = openSync8(file2, "r");
|
|
94939
95349
|
const buffer = Buffer.alloc(MAX_PREFIX_BYTES);
|
|
94940
95350
|
let used = 0;
|
|
94941
95351
|
let first = -1;
|
|
94942
95352
|
let second = -1;
|
|
94943
95353
|
try {
|
|
94944
95354
|
while (used < buffer.length && second < 0) {
|
|
94945
|
-
const bytes =
|
|
95355
|
+
const bytes = readSync6(fd, buffer, used, Math.min(4096, buffer.length - used), null);
|
|
94946
95356
|
if (bytes === 0) break;
|
|
94947
95357
|
const end = used + bytes;
|
|
94948
95358
|
for (let i = used; i < end; i++) {
|
|
@@ -94956,7 +95366,7 @@ function readPrefix(file2) {
|
|
|
94956
95366
|
used = end;
|
|
94957
95367
|
}
|
|
94958
95368
|
} finally {
|
|
94959
|
-
|
|
95369
|
+
closeSync8(fd);
|
|
94960
95370
|
}
|
|
94961
95371
|
if (first < 0 || second < 0) return null;
|
|
94962
95372
|
try {
|
|
@@ -95231,7 +95641,7 @@ function applyLocalSessionFlags(sessions, machineId, localFlags, localKey, claud
|
|
|
95231
95641
|
};
|
|
95232
95642
|
});
|
|
95233
95643
|
}
|
|
95234
|
-
async function fetchMemberSessions(credentials, fetchImpl = fetch, options = { windowHours: RECENT_SESSION_WINDOW_MS / 36e5, limit:
|
|
95644
|
+
async function fetchMemberSessions(credentials, fetchImpl = fetch, options = { windowHours: RECENT_SESSION_WINDOW_MS / 36e5, limit: RECENT_SESSION_PAGE_MAX }) {
|
|
95235
95645
|
const { windowHours, limit } = recentSessionOptionsSchema.parse(options);
|
|
95236
95646
|
try {
|
|
95237
95647
|
const query = new URLSearchParams({ view: "recent", windowHours: String(windowHours), limit: String(limit) });
|
|
@@ -95457,7 +95867,7 @@ async function probeClaudeDesktopSessions(wanted, installed, reportFault, root =
|
|
|
95457
95867
|
|
|
95458
95868
|
// src/menuModel.ts
|
|
95459
95869
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
95460
|
-
import { mkdirSync as mkdirSync17, rmSync as rmSync10, watch as
|
|
95870
|
+
import { mkdirSync as mkdirSync17, rmSync as rmSync10, watch as fsWatch4 } from "node:fs";
|
|
95461
95871
|
import path34 from "node:path";
|
|
95462
95872
|
|
|
95463
95873
|
// src/menu.ts
|
|
@@ -95487,7 +95897,7 @@ import { accessSync, constants as constants2, readFileSync as readFileSync15 } f
|
|
|
95487
95897
|
import path28 from "node:path";
|
|
95488
95898
|
|
|
95489
95899
|
// src/version.ts
|
|
95490
|
-
var CLI_VERSION = true ? "0.4.
|
|
95900
|
+
var CLI_VERSION = true ? "0.4.22" : "0.0.0-checkout";
|
|
95491
95901
|
var CLI_RELEASE_BUILD = true ? true : false;
|
|
95492
95902
|
var CLI_PACKAGE_NAME = "@usepowerplant/cli";
|
|
95493
95903
|
|
|
@@ -96177,8 +96587,8 @@ function syncHeader(i) {
|
|
|
96177
96587
|
if (i.credentials && (i.credentials.captureMode === "scope" || i.credentials.allowedRepos !== void 0 || i.credentials.scopePaths?.length || (i.credentials.workspacePolicies?.length ?? 0) > 1 || !i.credentials.allowedOwners?.length)) {
|
|
96178
96588
|
details.push(describeStoredCaptureSummary(i.credentials));
|
|
96179
96589
|
}
|
|
96180
|
-
const
|
|
96181
|
-
if (!i.control.paused && (
|
|
96590
|
+
const uploadedAt = lastUploadTime(i);
|
|
96591
|
+
if (!i.control.paused && (uploadedAt === void 0 || i.now - uploadedAt > 36e5)) {
|
|
96182
96592
|
details.push(lastUploadLine(i));
|
|
96183
96593
|
}
|
|
96184
96594
|
return { type: "header", title, ...details.length > 0 && { subtitle: details.join(" \xB7 ") } };
|
|
@@ -96186,7 +96596,7 @@ function syncHeader(i) {
|
|
|
96186
96596
|
var AGENT_TITLE_MAX = 48;
|
|
96187
96597
|
function recentAgentItems(i) {
|
|
96188
96598
|
if (i.memberSessions === null) return null;
|
|
96189
|
-
const recent = i.memberSessions.filter((session) => i.now - Date.parse(session.lastActivityAt) < RECENT_SESSION_WINDOW_MS).filter((session) => session.archived !== true && session.subagent !== true && session.standaloneReview !== true).sort((a, b2) => Date.parse(b2.lastActivityAt) - Date.parse(a.lastActivityAt)).map((session) => agentRow(session, i));
|
|
96599
|
+
const recent = i.memberSessions.filter((session) => i.now - Date.parse(session.lastActivityAt) < RECENT_SESSION_WINDOW_MS).filter((session) => session.archived !== true && session.subagent !== true && session.standaloneReview !== true).sort((a, b2) => Date.parse(b2.lastActivityAt) - Date.parse(a.lastActivityAt)).map((session) => agentRow(session, i)).filter((row) => row.agent?.status !== "ended").sort((a, b2) => Number(b2.agent?.status === "working") - Number(a.agent?.status === "working"));
|
|
96190
96600
|
const rows = recent.length === 0 ? [{ type: "status", mark: "muted", title: i.memberSessionsIncomplete ? "No sessions found in the partial list" : "No eligible sessions in the latest results" }] : groupedAgentRows(recent.slice(0, RECENT_SESSION_VISIBLE_LIMIT));
|
|
96191
96601
|
if (i.memberSessionsIncomplete) rows.push({
|
|
96192
96602
|
type: "status",
|
|
@@ -96214,7 +96624,7 @@ function agentRow(session, i) {
|
|
|
96214
96624
|
const harness = isLegacySessionSource(session.source) ? harnessFromLegacySessionSource(session.source) : null;
|
|
96215
96625
|
const harnessName = harness?.kind === "harness" ? harness.harness : session.source;
|
|
96216
96626
|
const status = localMachine && harness?.kind === "harness" && i.sessionStatus !== void 0 ? i.sessionStatus(harness.harness, session.externalId) ?? "unknown" : void 0;
|
|
96217
|
-
const statusLabel = status ===
|
|
96627
|
+
const statusLabel = status === "waiting" ? LOCAL_SESSION_STATUS_LABELS.waiting : null;
|
|
96218
96628
|
const desktopSessionId = localMachine && session.source === "claude-code" ? i.claudeDesktopSessions?.get(session.externalId)?.sessionId : void 0;
|
|
96219
96629
|
const app = desktopSessionId !== void 0 ? "Claude desktop" : isLegacySessionSource(session.source) ? describeSessionSource(session.source) : session.source;
|
|
96220
96630
|
const links = sessionLinks(session, i.config.webUrl, {
|
|
@@ -96298,10 +96708,16 @@ function menuContentKey(payload) {
|
|
|
96298
96708
|
});
|
|
96299
96709
|
return JSON.stringify({ ...shown, desktopDiagnostic: void 0 });
|
|
96300
96710
|
}
|
|
96711
|
+
function lastUploadTime(i) {
|
|
96712
|
+
if (!("status" in i.daemon)) return void 0;
|
|
96713
|
+
const { lastSyncAt, lastUploadAt } = i.daemon.status;
|
|
96714
|
+
const times = [lastSyncAt, lastUploadAt].map((at) => Date.parse(at ?? "")).filter((at) => !Number.isNaN(at));
|
|
96715
|
+
return times.length === 0 ? void 0 : Math.max(...times);
|
|
96716
|
+
}
|
|
96301
96717
|
function lastUploadLine(i) {
|
|
96302
|
-
const
|
|
96303
|
-
if (
|
|
96304
|
-
return `Last upload ${ago(i.now -
|
|
96718
|
+
const uploadedAt = lastUploadTime(i);
|
|
96719
|
+
if (uploadedAt === void 0) return "No successful upload yet";
|
|
96720
|
+
return `Last upload ${ago(i.now - uploadedAt)}`;
|
|
96305
96721
|
}
|
|
96306
96722
|
function connectionRow(connection, envArgs, now) {
|
|
96307
96723
|
const name = CLIENT_NAMES[connection.client];
|
|
@@ -97649,14 +98065,14 @@ function createMenuModel(deps) {
|
|
|
97649
98065
|
renewDue ||= renew;
|
|
97650
98066
|
if (stopped || sources === null || awaitingRefresh || renderPending) return;
|
|
97651
98067
|
renderPending = true;
|
|
97652
|
-
const
|
|
98068
|
+
const run2 = () => {
|
|
97653
98069
|
renderPending = false;
|
|
97654
98070
|
renderTimer = null;
|
|
97655
98071
|
if (!stopped) renderNow();
|
|
97656
98072
|
};
|
|
97657
98073
|
const wait = lastContentWriteAt + MENU_WRITE_INTERVAL_MS - now();
|
|
97658
|
-
if (wait <= 0) queueMicrotask(
|
|
97659
|
-
else renderTimer = setTimeout(
|
|
98074
|
+
if (wait <= 0) queueMicrotask(run2);
|
|
98075
|
+
else renderTimer = setTimeout(run2, wait);
|
|
97660
98076
|
}
|
|
97661
98077
|
function renderNow() {
|
|
97662
98078
|
if (sources === null || awaitingRefresh) return;
|
|
@@ -97894,7 +98310,7 @@ function startMenuModel(sources) {
|
|
|
97894
98310
|
const dir = path34.dirname(menuRefreshRequestPath(appEnv, host.home));
|
|
97895
98311
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
97896
98312
|
const openFile = path34.basename(menuOpenRequestPath(appEnv, host.home));
|
|
97897
|
-
const watcher =
|
|
98313
|
+
const watcher = fsWatch4(dir, (_event, filename) => onRequest(filename === openFile ? "menu-open" : "command"));
|
|
97898
98314
|
watcher.on("error", onLost);
|
|
97899
98315
|
return () => watcher.close();
|
|
97900
98316
|
},
|
|
@@ -97906,12 +98322,12 @@ function startMenuModel(sources) {
|
|
|
97906
98322
|
// src/cli.ts
|
|
97907
98323
|
import { spawn as spawn4 } from "node:child_process";
|
|
97908
98324
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
97909
|
-
import { mkdirSync as mkdirSync20, openSync as
|
|
98325
|
+
import { mkdirSync as mkdirSync20, openSync as openSync11, realpathSync as realpathSync5 } from "node:fs";
|
|
97910
98326
|
import path37 from "node:path";
|
|
97911
98327
|
import { parseArgs } from "node:util";
|
|
97912
98328
|
|
|
97913
98329
|
// src/doctor.ts
|
|
97914
|
-
import { closeSync as
|
|
98330
|
+
import { closeSync as closeSync9, fstatSync as fstatSync4, openSync as openSync9, readSync as readSync7 } from "node:fs";
|
|
97915
98331
|
var DOCTOR_LOG_TAIL_LINES = 50;
|
|
97916
98332
|
var LOG_TAIL_READ_BYTES = 256 * 1024;
|
|
97917
98333
|
function installLine(install) {
|
|
@@ -97927,23 +98343,23 @@ function redactedLogTail(raw) {
|
|
|
97927
98343
|
function readDoctorLogTail(path38) {
|
|
97928
98344
|
let fd;
|
|
97929
98345
|
try {
|
|
97930
|
-
fd =
|
|
98346
|
+
fd = openSync9(path38, "r");
|
|
97931
98347
|
} catch (error63) {
|
|
97932
98348
|
if (error63.code === "ENOENT") return { path: path38, lines: null };
|
|
97933
98349
|
return { path: path38, lines: null, readError: error63 instanceof Error ? error63.message : String(error63) };
|
|
97934
98350
|
}
|
|
97935
98351
|
try {
|
|
97936
|
-
const size =
|
|
98352
|
+
const size = fstatSync4(fd).size;
|
|
97937
98353
|
const offset = Math.max(0, size - LOG_TAIL_READ_BYTES);
|
|
97938
98354
|
const buffer = Buffer.alloc(Math.min(size, LOG_TAIL_READ_BYTES));
|
|
97939
|
-
|
|
98355
|
+
readSync7(fd, buffer, 0, buffer.length, offset);
|
|
97940
98356
|
let text = buffer.toString("utf8");
|
|
97941
98357
|
if (offset > 0) text = text.slice(text.indexOf("\n") + 1);
|
|
97942
98358
|
return { path: path38, lines: redactedLogTail(text) };
|
|
97943
98359
|
} catch (error63) {
|
|
97944
98360
|
return { path: path38, lines: null, readError: error63 instanceof Error ? error63.message : String(error63) };
|
|
97945
98361
|
} finally {
|
|
97946
|
-
|
|
98362
|
+
closeSync9(fd);
|
|
97947
98363
|
}
|
|
97948
98364
|
}
|
|
97949
98365
|
function renderDoctorReport(i) {
|
|
@@ -97960,7 +98376,7 @@ function renderDoctorReport(i) {
|
|
|
97960
98376
|
);
|
|
97961
98377
|
const unsupported = unsupportedVersionNotice(i.cliVersion, i.oldestSupportedVersion);
|
|
97962
98378
|
if (unsupported !== null) lines.push(unsupported);
|
|
97963
|
-
lines.push(`Environment: ${i.config.appEnv} (API ${i.config.apiUrl})`);
|
|
98379
|
+
lines.push(`Environment: ${i.config.appEnv} (API ${i.credentials?.apiUrl ?? i.config.apiUrl})`);
|
|
97964
98380
|
lines.push(`Node: ${i.nodeVersion} (${i.platform})`);
|
|
97965
98381
|
lines.push(installLine(i.install));
|
|
97966
98382
|
lines.push(enrollmentLine(i));
|
|
@@ -98198,7 +98614,7 @@ function pausedSince(control, now) {
|
|
|
98198
98614
|
}
|
|
98199
98615
|
function pausedNotice(control, resumeCommand2, now) {
|
|
98200
98616
|
if (!control.paused) return null;
|
|
98201
|
-
return `! ${pausedSince(control, now)}.
|
|
98617
|
+
return `! ${pausedSince(control, now)}. To resume sync, run \`${resumeCommand2}\`.`;
|
|
98202
98618
|
}
|
|
98203
98619
|
function pausedSyncNotice(control, resumeCommand2, now, dryRun) {
|
|
98204
98620
|
if (!control.paused || dryRun) return pausedNotice(control, resumeCommand2, now);
|
|
@@ -98218,7 +98634,7 @@ async function offerResume(deps, options) {
|
|
|
98218
98634
|
);
|
|
98219
98635
|
return "resumed";
|
|
98220
98636
|
}
|
|
98221
|
-
output2.log(`
|
|
98637
|
+
output2.log(`To resume sync, run \`${deps.resumeCommand}\``);
|
|
98222
98638
|
return "still-paused";
|
|
98223
98639
|
}
|
|
98224
98640
|
async function confirmResume(deps, output2) {
|
|
@@ -98403,7 +98819,7 @@ async function runInit(deps) {
|
|
|
98403
98819
|
if (pauseOffer === "still-paused") {
|
|
98404
98820
|
command.log("! Syncing is paused");
|
|
98405
98821
|
command.log("");
|
|
98406
|
-
command.detail(`
|
|
98822
|
+
command.detail(`To resume sync, run \`${deps.pause.resumeCommand}\``);
|
|
98407
98823
|
if (connectIncomplete) command.detail(`Finish MCP setup: \`${deps.connectCommand}\``);
|
|
98408
98824
|
return "paused";
|
|
98409
98825
|
}
|
|
@@ -98558,113 +98974,187 @@ function runResumeSession(source, sessionId, deps = {}) {
|
|
|
98558
98974
|
}
|
|
98559
98975
|
|
|
98560
98976
|
// src/statusReport.ts
|
|
98561
|
-
|
|
98562
|
-
|
|
98563
|
-
|
|
98564
|
-
|
|
98565
|
-
|
|
98566
|
-
|
|
98567
|
-
|
|
98568
|
-
|
|
98569
|
-
|
|
98977
|
+
var block = (line, ...details) => ({ line, details });
|
|
98978
|
+
function run(i, args) {
|
|
98979
|
+
return `\`powerplant ${args}${i.config.appEnv === "production" ? "" : ` --env ${i.config.appEnv}`}\``;
|
|
98980
|
+
}
|
|
98981
|
+
function renderStatus(i, out) {
|
|
98982
|
+
const stopping = syncProblems(i);
|
|
98983
|
+
const sections = [
|
|
98984
|
+
...stopping.map((problem) => [problem]),
|
|
98985
|
+
machineBlock(i, stopping.length === 0),
|
|
98986
|
+
...warnings(i).map((warning2) => [warning2]),
|
|
98987
|
+
i.connections.map((connection) => mcpBlock(i, connection)),
|
|
98988
|
+
[cliBlock(i, stopping.length === 0)]
|
|
98989
|
+
];
|
|
98990
|
+
sections.filter((section) => section.length > 0).forEach((section, index) => {
|
|
98991
|
+
if (index > 0) out.log("");
|
|
98992
|
+
for (const { line, details } of section) {
|
|
98993
|
+
out.log(line);
|
|
98994
|
+
details.forEach(out.detail);
|
|
98995
|
+
}
|
|
98996
|
+
});
|
|
98570
98997
|
}
|
|
98571
|
-
function
|
|
98572
|
-
|
|
98573
|
-
|
|
98998
|
+
function daemonStatus(i) {
|
|
98999
|
+
return "status" in i.daemon ? i.daemon.status : null;
|
|
99000
|
+
}
|
|
99001
|
+
function syncProblems(i) {
|
|
98574
99002
|
if (i.credentialsError !== void 0) {
|
|
98575
|
-
|
|
98576
|
-
}
|
|
98577
|
-
|
|
98578
|
-
|
|
98579
|
-
|
|
98580
|
-
|
|
98581
|
-
|
|
99003
|
+
return [block(`\u2717 ${i.credentialsError}`, `Run ${run(i, "init")} to enroll again.`)];
|
|
99004
|
+
}
|
|
99005
|
+
if (i.credentials === null) return [block("! Not enrolled", `Run ${run(i, "init")}.`)];
|
|
99006
|
+
const problems = [];
|
|
99007
|
+
if (i.control.paused) {
|
|
99008
|
+
problems.push(block(`! ${pausedSince(i.control, i.now)}`, `To resume sync, run ${run(i, "resume")}.`));
|
|
99009
|
+
}
|
|
99010
|
+
const service = serviceProblem(i);
|
|
99011
|
+
if (service !== null) problems.push(service);
|
|
99012
|
+
const status = i.daemon.state === "running" && !i.control.paused ? i.daemon.status : null;
|
|
99013
|
+
const lastPass = status?.lastPass;
|
|
99014
|
+
if (status && lastPass && !lastPass.ok) {
|
|
99015
|
+
const failures = status.consecutiveFailures;
|
|
99016
|
+
problems.push(
|
|
99017
|
+
block(
|
|
99018
|
+
`\u2717 Last sync failed, ${lastPass.error ?? "unknown error"}`,
|
|
99019
|
+
`${failures} failure${failures === 1 ? "" : "s"} in a row. Run ${run(i, "doctor")} for diagnostics.`
|
|
99020
|
+
)
|
|
98582
99021
|
);
|
|
98583
|
-
lines.push(`${describeStoredCaptureSummary(i.credentials)}.`);
|
|
98584
|
-
for (const entry of i.protectedSessions ?? []) {
|
|
98585
|
-
const sessions = `${entry.sessionCount} recent agent session${entry.sessionCount === 1 ? "" : "s"}`;
|
|
98586
|
-
lines.push(
|
|
98587
|
-
protectedRootReview(i.credentials, entry.root) === "blocked" ? `! macOS is blocking Powerplant from reading ${entry.displayRoot} (${sessions}). Those sessions are staying local. ${MACOS_BLOCKED_FOLDER_REMEDY}` : `! Repository matching is not enabled for ${sessions} under ${entry.displayRoot}. Sessions outside folders you explicitly added are staying local, run \`powerplant init\` to review Git repository scanning.`
|
|
98588
|
-
);
|
|
98589
|
-
}
|
|
98590
99022
|
}
|
|
98591
|
-
|
|
98592
|
-
|
|
98593
|
-
|
|
99023
|
+
return problems;
|
|
99024
|
+
}
|
|
99025
|
+
function unavailableProbe(i) {
|
|
99026
|
+
return block(
|
|
99027
|
+
`! Background sync status unavailable${i.serviceError ? `, ${i.serviceError}` : ""}`,
|
|
99028
|
+
`Run ${run(i, "doctor")} for diagnostics.`
|
|
99029
|
+
);
|
|
99030
|
+
}
|
|
99031
|
+
function serviceProblem(i) {
|
|
98594
99032
|
switch (i.service) {
|
|
98595
99033
|
case "unavailable":
|
|
98596
|
-
lines.push(`Background sync: status unavailable${i.serviceError ? `, ${i.serviceError}` : ""}. Run powerplant doctor${i.config.appEnv === "production" ? "" : ` --env ${i.config.appEnv}`} for diagnostics.`);
|
|
98597
99034
|
break;
|
|
98598
99035
|
case "unsupported":
|
|
98599
|
-
|
|
98600
|
-
"Background sync
|
|
99036
|
+
return block(
|
|
99037
|
+
"! Background sync is not supported on this platform yet",
|
|
99038
|
+
`Run ${run(i, "sync")} on a schedule instead.`
|
|
98601
99039
|
);
|
|
98602
|
-
break;
|
|
98603
99040
|
case "not-installed":
|
|
98604
|
-
|
|
98605
|
-
break;
|
|
99041
|
+
return block("! Background sync is not installed", `Run ${run(i, "init")}.`);
|
|
98606
99042
|
case "not-loaded":
|
|
98607
|
-
|
|
98608
|
-
break;
|
|
99043
|
+
return block("! Background sync is installed but not loaded", `Run ${run(i, "restart")}.`);
|
|
98609
99044
|
case "loaded":
|
|
98610
|
-
lines.push(...renderDaemon(i));
|
|
98611
99045
|
break;
|
|
98612
99046
|
}
|
|
98613
|
-
|
|
98614
|
-
|
|
98615
|
-
|
|
98616
|
-
|
|
98617
|
-
|
|
98618
|
-
|
|
98619
|
-
|
|
98620
|
-
|
|
98621
|
-
|
|
98622
|
-
|
|
98623
|
-
|
|
98624
|
-
|
|
98625
|
-
|
|
98626
|
-
|
|
98627
|
-
|
|
98628
|
-
|
|
98629
|
-
|
|
99047
|
+
switch (i.daemon.state) {
|
|
99048
|
+
case "unreadable":
|
|
99049
|
+
return block(
|
|
99050
|
+
"! Background sync status file is unreadable",
|
|
99051
|
+
`A different version may have written it. Run ${run(i, "restart")}.`
|
|
99052
|
+
);
|
|
99053
|
+
case "not-running":
|
|
99054
|
+
if (i.service === "unavailable") return unavailableProbe(i);
|
|
99055
|
+
return block(
|
|
99056
|
+
"! Background sync has not reported its status",
|
|
99057
|
+
`It may still be starting. If this persists, run ${run(i, "restart")}.`,
|
|
99058
|
+
`The log is at ${serviceLogPath(i.config.appEnv)}.`
|
|
99059
|
+
);
|
|
99060
|
+
case "stalled":
|
|
99061
|
+
return block(`\u2717 Background sync stalled, no heartbeat for ${duration3(i.daemon.staleMs)}`, `Run ${run(i, "restart")}.`);
|
|
99062
|
+
case "running":
|
|
99063
|
+
return null;
|
|
98630
99064
|
}
|
|
98631
|
-
|
|
98632
|
-
|
|
98633
|
-
|
|
98634
|
-
|
|
98635
|
-
|
|
98636
|
-
|
|
98637
|
-
|
|
98638
|
-
|
|
98639
|
-
|
|
99065
|
+
}
|
|
99066
|
+
function machineBlock(i, syncing) {
|
|
99067
|
+
const credentials = i.credentials;
|
|
99068
|
+
if (credentials === null) return [];
|
|
99069
|
+
const org = credentials.orgName;
|
|
99070
|
+
const line = syncing ? `\u2713 Syncing ${credentials.machineName}${org ? ` to ${org}` : ""}` : `${credentials.machineName}${org ? ` in ${org}` : ""}`;
|
|
99071
|
+
const details = [`${describeStoredCaptureSummary(credentials)}.`];
|
|
99072
|
+
const status = daemonStatus(i);
|
|
99073
|
+
if (status !== null) {
|
|
99074
|
+
const signals = describeSyncSignals(
|
|
99075
|
+
{
|
|
99076
|
+
lastSessionActivityAt: status.lastUploadAt ?? null,
|
|
99077
|
+
lastCheckedInAt: status.lastPass?.at ?? null,
|
|
99078
|
+
syncPaused: null,
|
|
99079
|
+
lastSyncErrorAt: status.lastPass && !status.lastPass.ok ? status.lastPass.at : null
|
|
99080
|
+
},
|
|
99081
|
+
new Date(i.now),
|
|
99082
|
+
"last upload unmeasured"
|
|
98640
99083
|
);
|
|
99084
|
+
details.push(signals ?? "No sync has run since background sync started.");
|
|
98641
99085
|
}
|
|
98642
|
-
|
|
98643
|
-
|
|
98644
|
-
|
|
99086
|
+
return [block(line, ...details)];
|
|
99087
|
+
}
|
|
99088
|
+
function warnings(i) {
|
|
99089
|
+
const found = [];
|
|
99090
|
+
if (isUnsupportedVersion(i.cliVersion, i.oldestSupportedVersion)) {
|
|
99091
|
+
found.push(
|
|
99092
|
+
block(
|
|
99093
|
+
`! powerplant ${i.cliVersion} is no longer supported, the oldest supported is ${i.oldestSupportedVersion}`,
|
|
99094
|
+
`Run ${run(i, "update")} (or npm install -g @usepowerplant/cli). Unsupported versions can stop working without notice.`
|
|
99095
|
+
)
|
|
98645
99096
|
);
|
|
98646
99097
|
}
|
|
98647
|
-
const
|
|
98648
|
-
{
|
|
98649
|
-
|
|
98650
|
-
|
|
98651
|
-
|
|
98652
|
-
|
|
98653
|
-
|
|
98654
|
-
|
|
98655
|
-
|
|
98656
|
-
|
|
98657
|
-
|
|
98658
|
-
if (status.lastPass && !status.lastPass.ok) {
|
|
98659
|
-
lines.push(
|
|
98660
|
-
` \u2717 Last pass failed: ${status.lastPass.error ?? "unknown error"} (${status.consecutiveFailures} consecutive failure${status.consecutiveFailures === 1 ? "" : "s"}).`
|
|
99098
|
+
for (const entry of i.protectedSessions ?? []) {
|
|
99099
|
+
const sessions = `${entry.sessionCount} recent agent session${entry.sessionCount === 1 ? "" : "s"}`;
|
|
99100
|
+
const staying = entry.sessionCount === 1 ? "is staying local" : "are staying local";
|
|
99101
|
+
found.push(
|
|
99102
|
+
i.credentials !== null && protectedRootReview(i.credentials, entry.root) === "blocked" ? block(
|
|
99103
|
+
`! macOS is blocking Powerplant from reading ${entry.displayRoot}`,
|
|
99104
|
+
`${sessions} ${staying}. ${MACOS_BLOCKED_FOLDER_REMEDY}`
|
|
99105
|
+
) : block(
|
|
99106
|
+
`! ${sessions} under ${entry.displayRoot} ${staying}`,
|
|
99107
|
+
`Run ${run(i, "init")} to review Git repository scanning.`
|
|
99108
|
+
)
|
|
98661
99109
|
);
|
|
98662
99110
|
}
|
|
98663
|
-
|
|
99111
|
+
if (i.service === "unavailable" && i.daemon.state !== "not-running") found.push(unavailableProbe(i));
|
|
99112
|
+
if (i.mcpPreferencesError !== void 0) found.push(block("! MCP choices can't be read", i.mcpPreferencesError));
|
|
99113
|
+
for (const hook of daemonStatus(i)?.hooks ?? []) {
|
|
98664
99114
|
const silence = hookWarning(hook, i.now);
|
|
98665
|
-
if (silence)
|
|
99115
|
+
if (silence) found.push(block(`! ${silence.problem}`, silence.fix));
|
|
98666
99116
|
}
|
|
98667
|
-
return
|
|
99117
|
+
return found;
|
|
99118
|
+
}
|
|
99119
|
+
function mcpBlock(i, connection) {
|
|
99120
|
+
const name = `${AGENT_DISPLAY_NAMES[connection.client]}${connection.target ? ` (${connection.target})` : ""}`;
|
|
99121
|
+
const fix = `Run ${run(i, `connect --client ${connection.client}`)}.`;
|
|
99122
|
+
const current = connectionIsCurrent(connection, i.now);
|
|
99123
|
+
const checked = current ? "" : `, checked ${ago(i.now - Date.parse(connection.checkedAt))}`;
|
|
99124
|
+
switch (connection.state) {
|
|
99125
|
+
case "signed-in":
|
|
99126
|
+
return block(`${current ? "\u2713 " : ""}${name}: MCP connected${checked}`);
|
|
99127
|
+
case "sign-in-needed":
|
|
99128
|
+
return block(`! ${name}: MCP sign-in needed${checked}`, fix);
|
|
99129
|
+
case "different-url":
|
|
99130
|
+
return block(
|
|
99131
|
+
`! ${name}: MCP points at a different Powerplant${connection.registeredUrl ? `, ${connection.registeredUrl}` : ""}`,
|
|
99132
|
+
fix
|
|
99133
|
+
);
|
|
99134
|
+
case "not-connected":
|
|
99135
|
+
return i.mcpPreferences?.clients[connection.client]?.optedIn === true ? block(`! ${name}: MCP not connected`, fix) : block(`${name}: MCP not connected`);
|
|
99136
|
+
case "configured":
|
|
99137
|
+
return block(`${name}: MCP configured, sign-in unknown`);
|
|
99138
|
+
case "check-failed":
|
|
99139
|
+
return block(`${name}: MCP check failed${connection.detail ? `, ${connection.detail}` : ""}`);
|
|
99140
|
+
}
|
|
99141
|
+
}
|
|
99142
|
+
function cliBlock(i, syncing) {
|
|
99143
|
+
const details = [];
|
|
99144
|
+
if (i.daemon.state === "running" && i.daemon.status.version !== i.cliVersion) {
|
|
99145
|
+
details.push(
|
|
99146
|
+
`Background sync is on ${i.daemon.status.version}. It restarts onto the installed version within minutes, or now with ${run(i, "restart")}.`
|
|
99147
|
+
);
|
|
99148
|
+
}
|
|
99149
|
+
const automatic = automaticUpdatesChoice(i.control);
|
|
99150
|
+
const version2 = `powerplant ${i.cliVersion}`;
|
|
99151
|
+
if (isUpdateAvailable(i.cliVersion, i.latestVersion) && !isUnsupportedVersion(i.cliVersion, i.oldestSupportedVersion)) {
|
|
99152
|
+
return block(`${version2}, ${i.latestVersion} is available`, ...details, `Run ${run(i, "update")}.`);
|
|
99153
|
+
}
|
|
99154
|
+
if (automatic === "not-chosen" && syncing) {
|
|
99155
|
+
details.push(`Turn them on with ${run(i, "update --automatic on")}.`);
|
|
99156
|
+
}
|
|
99157
|
+
return block(`${version2}, automatic updates ${automatic === "on" ? "on" : "off"}`, ...details);
|
|
98668
99158
|
}
|
|
98669
99159
|
function statusJson(i) {
|
|
98670
99160
|
return {
|
|
@@ -98702,7 +99192,9 @@ function statusJson(i) {
|
|
|
98702
99192
|
daemon: "status" in i.daemon ? { state: i.daemon.state, ...i.daemon.status } : { state: i.daemon.state },
|
|
98703
99193
|
paused: i.control.paused,
|
|
98704
99194
|
automaticUpdates: automaticUpdatesChoice(i.control),
|
|
98705
|
-
pausedAt: i.control.pausedAt ?? null
|
|
99195
|
+
pausedAt: i.control.pausedAt ?? null,
|
|
99196
|
+
// The same saved checks the human rendering reads, each with when it ran.
|
|
99197
|
+
mcpConnections: i.connections
|
|
98706
99198
|
};
|
|
98707
99199
|
}
|
|
98708
99200
|
function supportedFlag(cliVersion2, oldestSupportedVersion) {
|
|
@@ -98864,7 +99356,7 @@ function createTerminalOutput(options) {
|
|
|
98864
99356
|
|
|
98865
99357
|
// src/credentialUpgrade.ts
|
|
98866
99358
|
import { spawn as spawn3 } from "node:child_process";
|
|
98867
|
-
import { closeSync as
|
|
99359
|
+
import { closeSync as closeSync10, mkdirSync as mkdirSync18, openSync as openSync10 } from "node:fs";
|
|
98868
99360
|
import path35 from "node:path";
|
|
98869
99361
|
async function prepareCredentialUpgrade(deps) {
|
|
98870
99362
|
if (!deps.needsMigration() || !deps.serviceExists() || deps.ready()) return "ready";
|
|
@@ -98899,7 +99391,7 @@ async function prepareCredentialUpgrade(deps) {
|
|
|
98899
99391
|
}
|
|
98900
99392
|
async function tryCredentialUpgradeLock(file2) {
|
|
98901
99393
|
mkdirSync18(path35.dirname(file2), { recursive: true, mode: 448 });
|
|
98902
|
-
|
|
99394
|
+
closeSync10(openSync10(file2, "a", 384));
|
|
98903
99395
|
const child = spawn3("/usr/bin/lockf", ["-k", "-s", "-t", "0", file2, "/bin/sh", "-c", "printf 'ready\\n'; exec /bin/cat >/dev/null"], {
|
|
98904
99396
|
detached: true,
|
|
98905
99397
|
stdio: ["pipe", "pipe", "ignore"]
|
|
@@ -99639,12 +100131,12 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
99639
100131
|
latestVersion,
|
|
99640
100132
|
oldestSupportedVersion,
|
|
99641
100133
|
protectedSessions,
|
|
99642
|
-
|
|
100134
|
+
connections: readHarnessConnections(config2.appEnv, realReadTextFile),
|
|
100135
|
+
...readMcpPreferencesForMenu(config2.appEnv),
|
|
99643
100136
|
now: Date.now()
|
|
99644
100137
|
};
|
|
99645
|
-
console.log(
|
|
99646
|
-
|
|
99647
|
-
);
|
|
100138
|
+
if (values.json) console.log(JSON.stringify(statusJson(inputs), null, 2));
|
|
100139
|
+
else renderStatus(inputs, terminal.command);
|
|
99648
100140
|
return;
|
|
99649
100141
|
}
|
|
99650
100142
|
case "doctor": {
|
|
@@ -99979,7 +100471,7 @@ function startBackgroundUpdate(config2, target) {
|
|
|
99979
100471
|
writeProgress: updateProgress.write,
|
|
99980
100472
|
spawnChild: () => {
|
|
99981
100473
|
mkdirSync20(path37.dirname(updateLogPath()), { recursive: true });
|
|
99982
|
-
const log3 =
|
|
100474
|
+
const log3 = openSync11(updateLogPath(), "a");
|
|
99983
100475
|
const child = spawn4(process.execPath, [entryPath(), "update", ...envArgsFor(config2)], {
|
|
99984
100476
|
detached: true,
|
|
99985
100477
|
stdio: ["ignore", log3, log3],
|
|
@@ -100093,4 +100585,4 @@ undici/lib/web/websocket/frame.js:
|
|
|
100093
100585
|
(*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
|
|
100094
100586
|
*/
|
|
100095
100587
|
|
|
100096
|
-
//# debugId=
|
|
100588
|
+
//# debugId=91b4b5e6-fdd5-5127-9372-913ad2bc7af5
|