@usepowerplant/cli 0.4.11 → 0.4.13
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/README.md +16 -124
- package/dist/cli.js +533 -238
- package/dist/menubar/Powerplant.app.zip +0 -0
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
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]="66f773d5-e0b2-5538-a184-3ee15c3a469a")}catch(e){}}();
|
|
2
4
|
const __cliNodeMajor = Number(process.versions.node.split('.')[0]);
|
|
3
5
|
if (__cliNodeMajor < 20) {
|
|
4
6
|
console.error(`powerplant needs Node 20 or newer — this is Node ${process.versions.node}.`);
|
|
@@ -56698,12 +56700,13 @@ function boundRedactedText(raw, maxBytes) {
|
|
|
56698
56700
|
return boundText(redactSecrets(raw), maxBytes);
|
|
56699
56701
|
}
|
|
56700
56702
|
function boundText(redacted, maxBytes) {
|
|
56701
|
-
const
|
|
56703
|
+
const text = redacted.includes("\0") ? redacted.replaceAll("\0", "\uFFFD") : redacted;
|
|
56704
|
+
const bytes = utf8Encoder.encode(text);
|
|
56702
56705
|
if (bytes.length <= maxBytes) {
|
|
56703
|
-
return { text
|
|
56706
|
+
return { text, truncated: false, originalBytes: bytes.length };
|
|
56704
56707
|
}
|
|
56705
|
-
const
|
|
56706
|
-
return { text, truncated: true, originalBytes: bytes.length };
|
|
56708
|
+
const cut = utf8Decoder.decode(bytes.subarray(0, maxBytes)).replace(/�+$/u, "");
|
|
56709
|
+
return { text: cut, truncated: true, originalBytes: bytes.length };
|
|
56707
56710
|
}
|
|
56708
56711
|
|
|
56709
56712
|
// ../core/src/codeHost.ts
|
|
@@ -56755,18 +56758,35 @@ function pullRequestRefsInText(text) {
|
|
|
56755
56758
|
}
|
|
56756
56759
|
return refs;
|
|
56757
56760
|
}
|
|
56761
|
+
var PULL_REQUEST_ALREADY_EXISTS = /a pull request for branch \S+ into branch \S+ already exists:/;
|
|
56762
|
+
function pullRequestAlreadyExistsInText(text) {
|
|
56763
|
+
return PULL_REQUEST_ALREADY_EXISTS.test(text);
|
|
56764
|
+
}
|
|
56758
56765
|
function pullRequestRefFromUrl(url2) {
|
|
56759
56766
|
return pullRequestRefsInText(url2)[0] ?? null;
|
|
56760
56767
|
}
|
|
56761
56768
|
var MAY_TOUCH_HOST = /\b(?:git|gh)\b/;
|
|
56762
56769
|
function readCodeHostCommands(command, currentBranch) {
|
|
56770
|
+
return readCommands(command, currentBranch, 0);
|
|
56771
|
+
}
|
|
56772
|
+
var SUBSTITUTION_DEPTH_MAX = 4;
|
|
56773
|
+
function readCommands(command, currentBranch, depth) {
|
|
56763
56774
|
const result = { pushes: [], pullRequestCreates: [] };
|
|
56764
56775
|
if (!MAY_TOUCH_HOST.test(command)) return result;
|
|
56765
56776
|
const chain = shellCommands(command);
|
|
56766
56777
|
let branch = currentBranch;
|
|
56767
56778
|
chain.forEach((simple, i) => {
|
|
56768
56779
|
const program = programOf(simple.words);
|
|
56769
|
-
if (program === null)
|
|
56780
|
+
if (program === null) {
|
|
56781
|
+
if (depth >= SUBSTITUTION_DEPTH_MAX) return;
|
|
56782
|
+
const alone = simple.words.length === 1 && simple.next === null;
|
|
56783
|
+
for (const substituted of simple.assignedSubstitutions) {
|
|
56784
|
+
for (const create of readCommands(substituted, branch, depth + 1).pullRequestCreates) {
|
|
56785
|
+
result.pullRequestCreates.push({ ...create, ownExitStatus: create.ownExitStatus && alone });
|
|
56786
|
+
}
|
|
56787
|
+
}
|
|
56788
|
+
return;
|
|
56789
|
+
}
|
|
56770
56790
|
if (program.name === "git") {
|
|
56771
56791
|
const git = gitSubcommand(program.args);
|
|
56772
56792
|
if (git === null) return;
|
|
@@ -56799,6 +56819,7 @@ function pushOutcomeInText(text, branch) {
|
|
|
56799
56819
|
return /Everything up-to-date/.test(text) ? true : null;
|
|
56800
56820
|
}
|
|
56801
56821
|
var ENV_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
56822
|
+
var ASSIGNMENT_NAME = /^[A-Za-z_][A-Za-z0-9_]*=$/;
|
|
56802
56823
|
function programOf(words) {
|
|
56803
56824
|
let i = 0;
|
|
56804
56825
|
while (i < words.length && (ENV_ASSIGNMENT.test(words[i]) || words[i] === "env")) i += 1;
|
|
@@ -56895,6 +56916,7 @@ function exitStatusIsOwn(chain, index) {
|
|
|
56895
56916
|
function shellCommands(text) {
|
|
56896
56917
|
const commands = [];
|
|
56897
56918
|
let words = [];
|
|
56919
|
+
let assignedSubstitutions = [];
|
|
56898
56920
|
let word = "";
|
|
56899
56921
|
let inWord = false;
|
|
56900
56922
|
let quote = null;
|
|
@@ -56906,8 +56928,9 @@ function shellCommands(text) {
|
|
|
56906
56928
|
};
|
|
56907
56929
|
const endCommand = (next) => {
|
|
56908
56930
|
endWord();
|
|
56909
|
-
if (words.length > 0) commands.push({ words: withoutRedirections(words), next });
|
|
56931
|
+
if (words.length > 0) commands.push({ words: withoutRedirections(words), assignedSubstitutions, next });
|
|
56910
56932
|
words = [];
|
|
56933
|
+
assignedSubstitutions = [];
|
|
56911
56934
|
};
|
|
56912
56935
|
for (let i = 0; i < text.length; i++) {
|
|
56913
56936
|
const ch = text[i];
|
|
@@ -56927,6 +56950,11 @@ function shellCommands(text) {
|
|
|
56927
56950
|
inWord = true;
|
|
56928
56951
|
} else if (ch === "$" && text[i + 1] === "(" || ch === "`") {
|
|
56929
56952
|
const end = substitutionEnd(text, i);
|
|
56953
|
+
const after = text[end + 1];
|
|
56954
|
+
const endsWord = after === void 0 || /[\s;&|)]/.test(after);
|
|
56955
|
+
if (ch === "$" && text[end] === ")" && ASSIGNMENT_NAME.test(word) && endsWord) {
|
|
56956
|
+
assignedSubstitutions.push(text.slice(i + 2, end));
|
|
56957
|
+
}
|
|
56930
56958
|
word += text.slice(i, end + 1);
|
|
56931
56959
|
inWord = true;
|
|
56932
56960
|
i = end;
|
|
@@ -57037,6 +57065,9 @@ var PrEvidenceCollector = class {
|
|
|
57037
57065
|
evidence = [];
|
|
57038
57066
|
seen = /* @__PURE__ */ new Set();
|
|
57039
57067
|
watched = /* @__PURE__ */ new Map();
|
|
57068
|
+
/** By process id: what a watched call left unsettled when its result said
|
|
57069
|
+
* the process still runs. */
|
|
57070
|
+
running = /* @__PURE__ */ new Map();
|
|
57040
57071
|
dropped = 0;
|
|
57041
57072
|
/** The harness recorded the pull request for this session. Repeats (a
|
|
57042
57073
|
* record per turn while a PR stays bound) keep the first time. */
|
|
@@ -57045,15 +57076,50 @@ var PrEvidenceCollector = class {
|
|
|
57045
57076
|
}
|
|
57046
57077
|
/** A shell command the session ran: watched until its result arrives when
|
|
57047
57078
|
* it pushes a branch or creates a pull request, ignored otherwise. */
|
|
57048
|
-
command(callId, command, currentBranch) {
|
|
57049
|
-
this.watch(callId, readCodeHostCommands(command, currentBranch));
|
|
57079
|
+
command(callId, command, currentBranch, startedAt = null) {
|
|
57080
|
+
this.watch(callId, readCodeHostCommands(command, currentBranch), startedAt);
|
|
57050
57081
|
}
|
|
57051
57082
|
/** A tool call that would push or create a pull request, in the code host
|
|
57052
57083
|
* adapter's terms (a harness's own pull request tool, for example). */
|
|
57053
|
-
watch(callId, commands) {
|
|
57084
|
+
watch(callId, commands, startedAt = null) {
|
|
57054
57085
|
if (commands.pushes.length === 0 && commands.pullRequestCreates.length === 0) return;
|
|
57055
|
-
this.watched
|
|
57056
|
-
|
|
57086
|
+
keepBounded(this.watched, callId, { ...commands, startedAt });
|
|
57087
|
+
}
|
|
57088
|
+
/** A call that reads more output of a running process (Codex's
|
|
57089
|
+
* write_stdin poll; Claude Code's TaskOutput, or a read of a background
|
|
57090
|
+
* task's output file): its result is read as the rest of the watched call
|
|
57091
|
+
* that started the process. */
|
|
57092
|
+
follow(callId, process2) {
|
|
57093
|
+
const unsettled = this.running.get(process2);
|
|
57094
|
+
if (unsettled === void 0) return;
|
|
57095
|
+
this.running.delete(process2);
|
|
57096
|
+
this.watch(callId, unsettled, unsettled.startedAt);
|
|
57097
|
+
}
|
|
57098
|
+
/** Whether any process is followed, so a parser reads an unwatched
|
|
57099
|
+
* call's output only while it could matter. */
|
|
57100
|
+
following() {
|
|
57101
|
+
return this.running.size > 0;
|
|
57102
|
+
}
|
|
57103
|
+
/** Another call now runs a process under this id: a later poll of the id
|
|
57104
|
+
* is no longer the rest of the watched call that left it running. */
|
|
57105
|
+
forget(process2) {
|
|
57106
|
+
this.running.delete(process2);
|
|
57107
|
+
}
|
|
57108
|
+
/** Watches several watched calls as one, in the order given: the parts of
|
|
57109
|
+
* a call whose output cannot be told apart, read once as a whole. The
|
|
57110
|
+
* parts are one call's, so they started together and the first part's
|
|
57111
|
+
* time is the whole's. */
|
|
57112
|
+
merge(callIds, into) {
|
|
57113
|
+
const parts = callIds.flatMap((callId) => this.watched.get(callId) ?? []);
|
|
57114
|
+
for (const callId of callIds) this.watched.delete(callId);
|
|
57115
|
+
this.watch(
|
|
57116
|
+
into,
|
|
57117
|
+
{
|
|
57118
|
+
pushes: parts.flatMap((part) => part.pushes),
|
|
57119
|
+
pullRequestCreates: parts.flatMap((part) => part.pullRequestCreates)
|
|
57120
|
+
},
|
|
57121
|
+
parts[0]?.startedAt ?? null
|
|
57122
|
+
);
|
|
57057
57123
|
}
|
|
57058
57124
|
watching(callId) {
|
|
57059
57125
|
return this.watched.has(callId);
|
|
@@ -57070,7 +57136,16 @@ var PrEvidenceCollector = class {
|
|
|
57070
57136
|
* result names the pull request: gh prints the created PR's URL last, so
|
|
57071
57137
|
* a call with one creation takes the last URL and a call with several
|
|
57072
57138
|
* only when the text names exactly as many; a failed call whose status
|
|
57073
|
-
* is the creation's own counts nothing
|
|
57139
|
+
* is the creation's own counts nothing, and neither does a call whose
|
|
57140
|
+
* text carries gh's refusal because the pull request exists (the URL it
|
|
57141
|
+
* prints is that pull request's, and a result read from a file states no
|
|
57142
|
+
* status). A text cut to the URL alone (`| tail -1`, a `grep` of the
|
|
57143
|
+
* output file) hides the refusal, and the URL then counts.
|
|
57144
|
+
*
|
|
57145
|
+
* When the result says one process still runs, whatever it settled
|
|
57146
|
+
* neither way waits for that process's later output (`follow`). A push
|
|
57147
|
+
* git rejected, or a command whose own status failed, is settled: a
|
|
57148
|
+
* later output never revives it.
|
|
57074
57149
|
*/
|
|
57075
57150
|
result(callId, outcome) {
|
|
57076
57151
|
const commands = this.watched.get(callId);
|
|
@@ -57079,35 +57154,45 @@ var PrEvidenceCollector = class {
|
|
|
57079
57154
|
const destinations = pushDestinationsInText(outcome.text);
|
|
57080
57155
|
const oneRemote = new Set(commands.pushes.map((push) => push.remote)).size === 1;
|
|
57081
57156
|
const shared = oneRemote && new Set(destinations).size === 1 ? destinations[0] : null;
|
|
57157
|
+
const unsettled = { pushes: [], pullRequestCreates: [], startedAt: commands.startedAt };
|
|
57082
57158
|
for (const [i, push] of commands.pushes.entries()) {
|
|
57083
57159
|
if (push.branch === null) continue;
|
|
57084
|
-
const pushed = pushOutcomeInText(outcome.text, push.branch) ?? (push.ownExitStatus
|
|
57085
|
-
if (
|
|
57160
|
+
const pushed = pushOutcomeInText(outcome.text, push.branch) ?? (push.ownExitStatus ? outcome.succeeded : null);
|
|
57161
|
+
if (pushed === null) unsettled.pushes.push(push);
|
|
57162
|
+
if (pushed !== true) continue;
|
|
57086
57163
|
const repository = destinations.length === commands.pushes.length ? destinations[i] : shared;
|
|
57087
57164
|
this.addPush({ kind: "branch-pushed", at: outcome.at, prId: null, repository, branch: push.branch, line: outcome.line });
|
|
57088
57165
|
}
|
|
57089
57166
|
const creates = commands.pullRequestCreates;
|
|
57090
|
-
if (creates.length === 0) return;
|
|
57091
57167
|
const refs = pullRequestRefsInText(outcome.text);
|
|
57092
57168
|
const paired = creates.length === 1 ? [refs.at(-1)] : refs.length === creates.length ? refs : [];
|
|
57169
|
+
const refused = pullRequestAlreadyExistsInText(outcome.text);
|
|
57093
57170
|
creates.forEach((create, i) => {
|
|
57094
57171
|
const ref = paired[i];
|
|
57095
|
-
if (
|
|
57172
|
+
if (refused || outcome.succeeded === false && create.ownExitStatus) return;
|
|
57173
|
+
if (ref === void 0) {
|
|
57174
|
+
unsettled.pullRequestCreates.push(create);
|
|
57175
|
+
return;
|
|
57176
|
+
}
|
|
57096
57177
|
this.add({
|
|
57097
57178
|
kind: "pull-request-created",
|
|
57098
57179
|
at: outcome.at,
|
|
57099
57180
|
prId: pullRequestId(ref),
|
|
57100
57181
|
repository: null,
|
|
57101
57182
|
branch: create.head,
|
|
57102
|
-
line: outcome.line
|
|
57183
|
+
line: outcome.line,
|
|
57184
|
+
commandStartedAt: commands.startedAt
|
|
57103
57185
|
});
|
|
57104
57186
|
});
|
|
57187
|
+
if (outcome.running === null || unsettled.pushes.length === 0 && unsettled.pullRequestCreates.length === 0) return;
|
|
57188
|
+
keepBounded(this.running, outcome.running, unsettled);
|
|
57105
57189
|
}
|
|
57106
57190
|
/** The evidence collected, in transcript order, with pushes past the cap
|
|
57107
|
-
* dropped oldest first. Calls still watched
|
|
57108
|
-
* never arrived. */
|
|
57191
|
+
* dropped oldest first. Calls still watched and processes still followed
|
|
57192
|
+
* are dropped: their results never arrived. */
|
|
57109
57193
|
finish() {
|
|
57110
57194
|
this.watched.clear();
|
|
57195
|
+
this.running.clear();
|
|
57111
57196
|
const pushes = this.evidence.filter((item) => item.kind === "branch-pushed");
|
|
57112
57197
|
if (pushes.length <= PUSH_EVIDENCE_MAX) return this.evidence;
|
|
57113
57198
|
const cut = new Set(pushes.slice(0, pushes.length - PUSH_EVIDENCE_MAX));
|
|
@@ -57119,10 +57204,13 @@ var PrEvidenceCollector = class {
|
|
|
57119
57204
|
droppedPushes() {
|
|
57120
57205
|
return this.dropped;
|
|
57121
57206
|
}
|
|
57122
|
-
/** A link
|
|
57123
|
-
* first.
|
|
57207
|
+
/** A link is one fact per pull request, and so is a creation per command:
|
|
57208
|
+
* repeats keep the first. Two commands that each named the pull request
|
|
57209
|
+
* are two facts (a refused retry read before the first command's own
|
|
57210
|
+
* output), because the match keeps only the one whose command can have
|
|
57211
|
+
* opened it. */
|
|
57124
57212
|
add(item) {
|
|
57125
|
-
const key = `${item.kind}|${item.prId ?? ""}|${item.branch ?? ""}`;
|
|
57213
|
+
const key = `${item.kind}|${item.prId ?? ""}|${item.branch ?? ""}|${item.commandStartedAt ?? ""}`;
|
|
57126
57214
|
if (this.seen.has(key)) return;
|
|
57127
57215
|
this.seen.add(key);
|
|
57128
57216
|
this.evidence.push(item);
|
|
@@ -57136,6 +57224,11 @@ var PrEvidenceCollector = class {
|
|
|
57136
57224
|
this.evidence.push(item);
|
|
57137
57225
|
}
|
|
57138
57226
|
};
|
|
57227
|
+
function keepBounded(map2, key, value) {
|
|
57228
|
+
map2.delete(key);
|
|
57229
|
+
map2.set(key, value);
|
|
57230
|
+
if (map2.size > WATCHED_CALLS_MAX) map2.delete(map2.keys().next().value);
|
|
57231
|
+
}
|
|
57139
57232
|
|
|
57140
57233
|
// ../core/src/digest.ts
|
|
57141
57234
|
var TOOL_CALL_INPUT_MAX_BYTES = 65536;
|
|
@@ -57155,6 +57248,7 @@ function createDigestTurnParser(options = {}) {
|
|
|
57155
57248
|
let pendingEnvelopes = [];
|
|
57156
57249
|
let currentEnvelope = null;
|
|
57157
57250
|
const evidence = new PrEvidenceCollector();
|
|
57251
|
+
const backgroundTasks = { started: /* @__PURE__ */ new Map(), reads: /* @__PURE__ */ new Map() };
|
|
57158
57252
|
let line = -1;
|
|
57159
57253
|
const landPending = (turn) => {
|
|
57160
57254
|
for (const envelope of pendingEnvelopes) {
|
|
@@ -57184,7 +57278,7 @@ function createDigestTurnParser(options = {}) {
|
|
|
57184
57278
|
if (record2.isMeta === true) return;
|
|
57185
57279
|
const at = recordTime(record2);
|
|
57186
57280
|
if (record2.type === "user") {
|
|
57187
|
-
toolResults(record2, evidence, line);
|
|
57281
|
+
toolResults(record2, evidence, backgroundTasks, line);
|
|
57188
57282
|
const text = userText(record2);
|
|
57189
57283
|
if (text) {
|
|
57190
57284
|
const origin = claudeCodeMessageOrigin(originFacts(record2), text);
|
|
@@ -57233,8 +57327,9 @@ function createDigestTurnParser(options = {}) {
|
|
|
57233
57327
|
}
|
|
57234
57328
|
pendingTools.push(call);
|
|
57235
57329
|
if (part.name === "Bash" && typeof part.id === "string" && typeof part.input?.command === "string") {
|
|
57236
|
-
evidence.command(part.id, part.input.command, recordBranch(record2));
|
|
57330
|
+
evidence.command(part.id, part.input.command, recordBranch(record2), at);
|
|
57237
57331
|
}
|
|
57332
|
+
if (typeof part.id === "string") followBackgroundTask(part.id, part.name, part.input, evidence, backgroundTasks);
|
|
57238
57333
|
}
|
|
57239
57334
|
if (part.type === "text" && typeof part.text === "string" && part.text.trim() !== "") {
|
|
57240
57335
|
const origin = claudeCodeMessageOrigin(facts, part.text);
|
|
@@ -57311,16 +57406,38 @@ function isRecord(value) {
|
|
|
57311
57406
|
function recordBranch(record2) {
|
|
57312
57407
|
return typeof record2.gitBranch === "string" && record2.gitBranch !== "" ? record2.gitBranch : null;
|
|
57313
57408
|
}
|
|
57314
|
-
function
|
|
57409
|
+
function followBackgroundTask(callId, tool, input2, evidence, tasks) {
|
|
57410
|
+
if (tasks.started.size === 0 || evidence.watching(callId)) return;
|
|
57411
|
+
const named = tool === "TaskOutput" ? input2?.task_id : tool === "Read" ? input2?.file_path : tool === "Bash" ? input2?.command : void 0;
|
|
57412
|
+
if (typeof named !== "string" || tool === "Bash" && RUNS_GH.test(named)) return;
|
|
57413
|
+
const read = new Set(
|
|
57414
|
+
[...tasks.started].filter(([task]) => tool === "TaskOutput" ? named === task : named.includes(`/${task}.output`)).map(([, followed2]) => followed2)
|
|
57415
|
+
);
|
|
57416
|
+
if (read.size !== 1) return;
|
|
57417
|
+
const [followed] = read;
|
|
57418
|
+
evidence.follow(callId, followed);
|
|
57419
|
+
if (evidence.watching(callId)) keepBounded(tasks.reads, callId, followed);
|
|
57420
|
+
}
|
|
57421
|
+
var RUNS_GH = /(?:^|[\s;&|(])gh\s/;
|
|
57422
|
+
function toolResults(record2, evidence, tasks, line) {
|
|
57315
57423
|
const content = isRecord(record2.message) ? record2.message.content : void 0;
|
|
57316
57424
|
if (!Array.isArray(content)) return;
|
|
57317
57425
|
const result = isRecord(record2.toolUseResult) ? record2.toolUseResult : {};
|
|
57426
|
+
const file2 = isRecord(result.file) ? result.file : {};
|
|
57427
|
+
const task = isRecord(result.task) ? result.task : {};
|
|
57318
57428
|
for (const block of content) {
|
|
57319
57429
|
if (!isRecord(block) || block.type !== "tool_result" || typeof block.tool_use_id !== "string") continue;
|
|
57320
57430
|
if (!evidence.watching(block.tool_use_id)) continue;
|
|
57431
|
+
const reads = tasks.reads.get(block.tool_use_id);
|
|
57432
|
+
tasks.reads.delete(block.tool_use_id);
|
|
57433
|
+
const started = typeof result.backgroundTaskId === "string" ? result.backgroundTaskId : null;
|
|
57434
|
+
if (started !== null) keepBounded(tasks.started, started, reads ?? started);
|
|
57435
|
+
const failed2 = block.is_error === true || result.interrupted === true;
|
|
57436
|
+
const taskExited = typeof task.exitCode === "number" && task.task_id === reads;
|
|
57437
|
+
const status = reads !== void 0 ? { succeeded: taskExited ? task.exitCode === 0 : null, running: taskExited ? null : reads } : { succeeded: failed2 ? false : started !== null ? null : true, running: started };
|
|
57321
57438
|
evidence.result(block.tool_use_id, {
|
|
57322
|
-
|
|
57323
|
-
text: [result.stdout, result.stderr].filter((part) => typeof part === "string").concat(contentText(block.content)).join("\n"),
|
|
57439
|
+
...status,
|
|
57440
|
+
text: [result.stdout, result.stderr, file2.content, task.output].filter((part) => typeof part === "string").concat(contentText(block.content)).join("\n"),
|
|
57324
57441
|
at: recordTime(record2),
|
|
57325
57442
|
line
|
|
57326
57443
|
});
|
|
@@ -57988,6 +58105,8 @@ function createCodexTurnParser(options = {}) {
|
|
|
57988
58105
|
let pendingTools = [];
|
|
57989
58106
|
let pendingAt = null;
|
|
57990
58107
|
const evidence = new PrEvidenceCollector();
|
|
58108
|
+
const scripts = /* @__PURE__ */ new Map();
|
|
58109
|
+
const runningScripts = /* @__PURE__ */ new Map();
|
|
57991
58110
|
let line = -1;
|
|
57992
58111
|
const envelopes = [];
|
|
57993
58112
|
let pendingEnvelopes = [];
|
|
@@ -58047,9 +58166,24 @@ function createCodexTurnParser(options = {}) {
|
|
|
58047
58166
|
const responseItem = item;
|
|
58048
58167
|
const callId = typeof responseItem.call_id === "string" ? responseItem.call_id : null;
|
|
58049
58168
|
if (callId !== null && isToolOutput(responseItem)) {
|
|
58050
|
-
|
|
58169
|
+
const script = scripts.get(callId);
|
|
58170
|
+
scripts.delete(callId);
|
|
58171
|
+
if (script !== void 0) {
|
|
58172
|
+
const [header = "", ...blocks] = outputBlocks(responseItem.output);
|
|
58173
|
+
const cell = SCRIPT_STILL_RUNNING.exec(header)?.[1];
|
|
58174
|
+
if (cell === void 0) scriptResult(evidence, script, header, blocks, at, line);
|
|
58175
|
+
else keepBounded(runningScripts, cell, script);
|
|
58176
|
+
} else if (evidence.watching(callId)) {
|
|
58051
58177
|
const text2 = contentText(responseItem.output);
|
|
58052
|
-
evidence.result(callId, { succeeded: codexExitStatus(text2), text: text2, at, line });
|
|
58178
|
+
evidence.result(callId, { succeeded: codexExitStatus(text2), text: text2, running: codexRunningProcess(text2), at, line });
|
|
58179
|
+
} else if (runningScripts.size > 0 || evidence.following()) {
|
|
58180
|
+
const [header = "", ...blocks] = outputBlocks(responseItem.output);
|
|
58181
|
+
const cell = SCRIPT_STILL_RUNNING.exec(header)?.[1];
|
|
58182
|
+
if (cell !== void 0) runningScripts.delete(cell);
|
|
58183
|
+
for (const text2 of [header, ...blocks]) {
|
|
58184
|
+
const process2 = codexRunningProcess(text2);
|
|
58185
|
+
if (process2 !== null) evidence.forget(process2);
|
|
58186
|
+
}
|
|
58053
58187
|
}
|
|
58054
58188
|
return;
|
|
58055
58189
|
}
|
|
@@ -58062,7 +58196,10 @@ function createCodexTurnParser(options = {}) {
|
|
|
58062
58196
|
}
|
|
58063
58197
|
pendingTools.push(call);
|
|
58064
58198
|
pendingAt ??= at;
|
|
58065
|
-
if (callId !== null)
|
|
58199
|
+
if (callId !== null) {
|
|
58200
|
+
const script = watchCodexCall(evidence, callId, responseItem, at, runningScripts);
|
|
58201
|
+
if (script !== null) keepBounded(scripts, callId, script);
|
|
58202
|
+
}
|
|
58066
58203
|
return;
|
|
58067
58204
|
}
|
|
58068
58205
|
if (responseItem.type !== "message") return;
|
|
@@ -58105,27 +58242,76 @@ function createCodexTurnParser(options = {}) {
|
|
|
58105
58242
|
}
|
|
58106
58243
|
};
|
|
58107
58244
|
}
|
|
58108
|
-
|
|
58245
|
+
var stepKey = (callId, step) => `${callId}#${step}`;
|
|
58246
|
+
function watchCodexCall(evidence, callId, item, at, runningScripts) {
|
|
58109
58247
|
if (item.type === "custom_tool_call" && item.name === "exec" && typeof item.input === "string") {
|
|
58110
|
-
|
|
58111
|
-
|
|
58248
|
+
const steps = execScriptSteps(item.input);
|
|
58249
|
+
const commands = [];
|
|
58250
|
+
let seen = { pushes: 0, pullRequestCreates: 0 };
|
|
58251
|
+
steps.forEach((step, i) => {
|
|
58252
|
+
if (step.polls !== null) evidence.follow(stepKey(callId, i), step.polls);
|
|
58253
|
+
if (step.command === null) return;
|
|
58254
|
+
commands.push(step.command);
|
|
58255
|
+
const read = readCodeHostCommands(commands.join("\n"), null);
|
|
58256
|
+
evidence.watch(
|
|
58257
|
+
stepKey(callId, i),
|
|
58258
|
+
{
|
|
58259
|
+
pushes: read.pushes.slice(seen.pushes),
|
|
58260
|
+
pullRequestCreates: read.pullRequestCreates.slice(seen.pullRequestCreates)
|
|
58261
|
+
},
|
|
58262
|
+
at
|
|
58263
|
+
);
|
|
58264
|
+
seen = { pushes: read.pushes.length, pullRequestCreates: read.pullRequestCreates.length };
|
|
58265
|
+
});
|
|
58266
|
+
const watched = steps.some((_, i) => evidence.watching(stepKey(callId, i)));
|
|
58267
|
+
return watched ? { callId, polls: steps.map((step) => step.polls), printsEachStep: printsEachStep(item.input, steps) } : null;
|
|
58112
58268
|
}
|
|
58113
58269
|
if (item.type === "local_shell_call") {
|
|
58114
58270
|
const command = argvCommand(asRecord2(item.action)?.command);
|
|
58115
|
-
if (command !== null) evidence.command(callId, command, null);
|
|
58116
|
-
return;
|
|
58271
|
+
if (command !== null) evidence.command(callId, command, null, at);
|
|
58272
|
+
return null;
|
|
58117
58273
|
}
|
|
58118
|
-
if (item.type !== "function_call" || typeof item.arguments !== "string") return;
|
|
58274
|
+
if (item.type !== "function_call" || typeof item.arguments !== "string") return null;
|
|
58119
58275
|
const args = safeJsonRecord(item.arguments);
|
|
58120
58276
|
if (item.name === "exec_command" && typeof args?.cmd === "string") {
|
|
58121
|
-
evidence.command(callId, args.cmd, null);
|
|
58277
|
+
evidence.command(callId, args.cmd, null, at);
|
|
58122
58278
|
} else if (item.name === "shell") {
|
|
58123
58279
|
const command = argvCommand(args?.command);
|
|
58124
|
-
if (command !== null) evidence.command(callId, command, null);
|
|
58280
|
+
if (command !== null) evidence.command(callId, command, null, at);
|
|
58281
|
+
} else if (item.name === "write_stdin" && typeof args?.session_id === "number") {
|
|
58282
|
+
evidence.follow(callId, String(args.session_id));
|
|
58283
|
+
} else if (item.name === "wait" && (typeof args?.cell_id === "string" || typeof args?.cell_id === "number")) {
|
|
58284
|
+
const script = runningScripts.get(String(args.cell_id)) ?? null;
|
|
58285
|
+
runningScripts.delete(String(args.cell_id));
|
|
58286
|
+
return script;
|
|
58125
58287
|
} else if (item.name === "_create_pull_request") {
|
|
58126
58288
|
const head = typeof args?.head === "string" ? args.head : null;
|
|
58127
|
-
evidence.watch(callId, { pushes: [], pullRequestCreates: [{ head, ownExitStatus: true }] });
|
|
58289
|
+
evidence.watch(callId, { pushes: [], pullRequestCreates: [{ head, ownExitStatus: true }] }, at);
|
|
58128
58290
|
}
|
|
58291
|
+
return null;
|
|
58292
|
+
}
|
|
58293
|
+
function scriptResult(evidence, script, header, blocks, at, line) {
|
|
58294
|
+
const paired = script.printsEachStep && blocks.length === script.polls.length;
|
|
58295
|
+
const keys = script.polls.map((_, i) => stepKey(script.callId, i));
|
|
58296
|
+
if (!paired) {
|
|
58297
|
+
evidence.merge(keys.filter((_, i) => script.polls[i] === null), script.callId);
|
|
58298
|
+
evidence.result(script.callId, { succeeded: null, text: [header, ...blocks].join("\n"), running: null, at, line });
|
|
58299
|
+
}
|
|
58300
|
+
script.polls.forEach((polls, i) => {
|
|
58301
|
+
if (!evidence.watching(keys[i])) return;
|
|
58302
|
+
const text = paired ? blocks[i] : "";
|
|
58303
|
+
const succeeded = paired ? codexExitStatus(text) : null;
|
|
58304
|
+
const running = (paired ? codexRunningProcess(text) : null) ?? (succeeded === null ? polls : null);
|
|
58305
|
+
evidence.result(keys[i], { succeeded, text, running, at, line });
|
|
58306
|
+
});
|
|
58307
|
+
}
|
|
58308
|
+
function outputBlocks(output2) {
|
|
58309
|
+
if (typeof output2 === "string") return [output2];
|
|
58310
|
+
if (!Array.isArray(output2)) return [];
|
|
58311
|
+
return output2.map((block) => {
|
|
58312
|
+
const text = asRecord2(block)?.text;
|
|
58313
|
+
return typeof text === "string" ? text : "";
|
|
58314
|
+
});
|
|
58129
58315
|
}
|
|
58130
58316
|
function argvCommand(argv) {
|
|
58131
58317
|
if (typeof argv === "string") return argv;
|
|
@@ -58134,22 +58320,56 @@ function argvCommand(argv) {
|
|
|
58134
58320
|
if (argv.length === 3 && /(?:^|\/)(?:ba|z|da|k)?sh$/.test(shell) && /^-[a-z]*c[a-z]*$/.test(flag)) return script;
|
|
58135
58321
|
return argv.map((word) => /^[A-Za-z0-9._/:=@+-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`).join(" ");
|
|
58136
58322
|
}
|
|
58137
|
-
var
|
|
58138
|
-
|
|
58139
|
-
|
|
58140
|
-
|
|
58141
|
-
|
|
58142
|
-
|
|
58143
|
-
|
|
58144
|
-
|
|
58145
|
-
|
|
58146
|
-
|
|
58323
|
+
var SCRIPT_TOOL_CALL = /tools\.(\w+)\(/g;
|
|
58324
|
+
var COMMAND_ARGUMENT = /\{\s*"?cmd"?\s*:\s*("(?:[^"\\]|\\.)*")/y;
|
|
58325
|
+
var SESSION_ARGUMENT = /\{\s*"?session_id"?\s*:\s*(\d+)/y;
|
|
58326
|
+
function execScriptSteps(script) {
|
|
58327
|
+
const steps = [];
|
|
58328
|
+
const call = new RegExp(SCRIPT_TOOL_CALL);
|
|
58329
|
+
for (let match = call.exec(script); match !== null; match = call.exec(script)) {
|
|
58330
|
+
const argument = match[1] === "exec_command" ? COMMAND_ARGUMENT : match[1] === "write_stdin" ? SESSION_ARGUMENT : null;
|
|
58331
|
+
if (argument !== null) argument.lastIndex = call.lastIndex;
|
|
58332
|
+
const value = argument?.exec(script) ?? null;
|
|
58333
|
+
if (value !== null) call.lastIndex += value[0].length;
|
|
58334
|
+
steps.push({
|
|
58335
|
+
command: value !== null && match[1] === "exec_command" ? jsonString(value[1]) : null,
|
|
58336
|
+
polls: value !== null && match[1] === "write_stdin" ? value[1] : null
|
|
58337
|
+
});
|
|
58338
|
+
}
|
|
58339
|
+
return steps;
|
|
58340
|
+
}
|
|
58341
|
+
var STRING_LITERAL = /"(?:[^"\\]|\\.)*"/g;
|
|
58342
|
+
var TEXT_CALL = /\btext\(/g;
|
|
58343
|
+
var TEXT_OF_TOOL_CALL = /\btext\(\s*await\s+tools\.\w+\(/g;
|
|
58344
|
+
var DEFERRED_CODE = /\bfunction\b|=>|\.then\(/;
|
|
58345
|
+
function printsEachStep(script, steps) {
|
|
58346
|
+
if (steps.length === 1) return true;
|
|
58347
|
+
const code = script.replace(STRING_LITERAL, '""');
|
|
58348
|
+
if (DEFERRED_CODE.test(code)) return false;
|
|
58349
|
+
const printed = [...code.matchAll(TEXT_OF_TOOL_CALL)].length;
|
|
58350
|
+
return printed === steps.length && [...code.matchAll(TEXT_CALL)].length === steps.length;
|
|
58351
|
+
}
|
|
58352
|
+
function jsonString(literal2) {
|
|
58353
|
+
try {
|
|
58354
|
+
const parsed = JSON.parse(literal2);
|
|
58355
|
+
return typeof parsed === "string" ? parsed : null;
|
|
58356
|
+
} catch {
|
|
58357
|
+
return null;
|
|
58147
58358
|
}
|
|
58148
|
-
return commands;
|
|
58149
58359
|
}
|
|
58150
58360
|
function isToolOutput(item) {
|
|
58151
58361
|
return item.type === "custom_tool_call_output" || item.type === "function_call_output" || item.type === "local_shell_call_output";
|
|
58152
58362
|
}
|
|
58363
|
+
var SCRIPT_STILL_RUNNING = /^Script running with cell ID (\d+)/;
|
|
58364
|
+
var RUNNING_CHUNK = /^\s*\{[^\n]*?"session_id"\s*:\s*(\d+)/;
|
|
58365
|
+
var RUNNING_PROCESS_LINE = /^Process running with session ID (\d+)$/m;
|
|
58366
|
+
function codexRunningProcess(output2) {
|
|
58367
|
+
const chunk = RUNNING_CHUNK.exec(output2);
|
|
58368
|
+
if (chunk !== null) return chunk[1];
|
|
58369
|
+
const outputLine = output2.search(/^Output:/m);
|
|
58370
|
+
const header = outputLine === -1 ? output2 : output2.slice(0, outputLine);
|
|
58371
|
+
return RUNNING_PROCESS_LINE.exec(header)?.[1] ?? null;
|
|
58372
|
+
}
|
|
58153
58373
|
var EXIT_STATUS = /"exit_code"\s*:\s*(\d+)|Process exited with code (\d+)/g;
|
|
58154
58374
|
function codexExitStatus(output2) {
|
|
58155
58375
|
const codes = [...output2.matchAll(EXIT_STATUS)].map((match) => Number(match[1] ?? match[2]));
|
|
@@ -85663,11 +85883,11 @@ import path12 from "node:path";
|
|
|
85663
85883
|
import { existsSync as existsSync6, lstatSync as lstatSync4 } from "node:fs";
|
|
85664
85884
|
import path11 from "node:path";
|
|
85665
85885
|
|
|
85666
|
-
// ../../apps/collector/src/
|
|
85886
|
+
// ../../apps/collector/src/codexTranscriptDiscovery.ts
|
|
85667
85887
|
import { createHash } from "node:crypto";
|
|
85668
85888
|
import { closeSync, lstatSync, openSync, readSync, readdirSync, realpathSync } from "node:fs";
|
|
85669
85889
|
import path2 from "node:path";
|
|
85670
|
-
var
|
|
85890
|
+
var transcriptDiscoveryRecordSchema = external_exports.object({
|
|
85671
85891
|
sessionId: external_exports.string().regex(/^[a-zA-Z0-9_-]{1,200}$/),
|
|
85672
85892
|
transcriptPath: external_exports.string().max(4096).nullable()
|
|
85673
85893
|
});
|
|
@@ -85680,7 +85900,7 @@ function codexTranscriptRecordPath(home, sessionId) {
|
|
|
85680
85900
|
`${createHash("sha256").update(sessionId).digest("hex")}.json`
|
|
85681
85901
|
);
|
|
85682
85902
|
}
|
|
85683
|
-
function
|
|
85903
|
+
function readCodexTranscriptDiscoveryRecords(home, roots) {
|
|
85684
85904
|
const dir = codexTranscriptRecordsDir(home);
|
|
85685
85905
|
let files;
|
|
85686
85906
|
try {
|
|
@@ -85692,9 +85912,9 @@ function readCodexTranscriptHints(home, roots) {
|
|
|
85692
85912
|
for (const file2 of files) {
|
|
85693
85913
|
if (!/^[a-f0-9]{64}\.json$/.test(file2)) continue;
|
|
85694
85914
|
try {
|
|
85695
|
-
const
|
|
85696
|
-
if (!lstatSync(
|
|
85697
|
-
const fd = openSync(
|
|
85915
|
+
const recordPath = path2.join(dir, file2);
|
|
85916
|
+
if (!lstatSync(recordPath).isFile()) continue;
|
|
85917
|
+
const fd = openSync(recordPath, "r");
|
|
85698
85918
|
let text;
|
|
85699
85919
|
try {
|
|
85700
85920
|
const buffer = Buffer.alloc(32 * 1024 + 1);
|
|
@@ -85704,10 +85924,10 @@ function readCodexTranscriptHints(home, roots) {
|
|
|
85704
85924
|
} finally {
|
|
85705
85925
|
closeSync(fd);
|
|
85706
85926
|
}
|
|
85707
|
-
const
|
|
85708
|
-
if (file2 !== `${createHash("sha256").update(
|
|
85709
|
-
if (
|
|
85710
|
-
const rolloutPath = path2.normalize(
|
|
85927
|
+
const record2 = transcriptDiscoveryRecordSchema.parse(JSON.parse(text));
|
|
85928
|
+
if (file2 !== `${createHash("sha256").update(record2.sessionId).digest("hex")}.json`) continue;
|
|
85929
|
+
if (record2.transcriptPath === null || !path2.isAbsolute(record2.transcriptPath)) continue;
|
|
85930
|
+
const rolloutPath = path2.normalize(record2.transcriptPath);
|
|
85711
85931
|
if (path2.extname(rolloutPath) !== ".jsonl") continue;
|
|
85712
85932
|
const rootIndex = roots.findIndex((root2) => {
|
|
85713
85933
|
const relative2 = path2.relative(root2, rolloutPath);
|
|
@@ -85717,7 +85937,7 @@ function readCodexTranscriptHints(home, roots) {
|
|
|
85717
85937
|
const root = roots[rootIndex];
|
|
85718
85938
|
if (realpathSync(rolloutPath) !== path2.join(realpathSync(root), path2.relative(root, rolloutPath)))
|
|
85719
85939
|
continue;
|
|
85720
|
-
result.push({ rolloutPath, sessionId:
|
|
85940
|
+
result.push({ rolloutPath, sessionId: record2.sessionId, archived: rootIndex === 1 });
|
|
85721
85941
|
} catch {
|
|
85722
85942
|
}
|
|
85723
85943
|
}
|
|
@@ -85730,7 +85950,7 @@ import { createHmac } from "node:crypto";
|
|
|
85730
85950
|
// ../../apps/collector/src/http.ts
|
|
85731
85951
|
var import_undici = __toESM(require_undici(), 1);
|
|
85732
85952
|
var CLI_VERSION_HEADER = "x-powerplant-cli-version";
|
|
85733
|
-
var cliVersion = true ? "0.4.
|
|
85953
|
+
var cliVersion = true ? "0.4.13" : "0.0.0-checkout";
|
|
85734
85954
|
function cliVersionHeaders() {
|
|
85735
85955
|
return { [CLI_VERSION_HEADER]: cliVersion, "user-agent": `powerplant-cli/${cliVersion}` };
|
|
85736
85956
|
}
|
|
@@ -86037,7 +86257,7 @@ function bindDiagnosticEnrollment(diagnostic, token) {
|
|
|
86037
86257
|
passEnrollments.set(diagnostic, token);
|
|
86038
86258
|
}
|
|
86039
86259
|
|
|
86040
|
-
// ../../apps/collector/src/
|
|
86260
|
+
// ../../apps/collector/src/codexSessions.ts
|
|
86041
86261
|
import { closeSync as closeSync3, mkdirSync as mkdirSync2, openSync as openSync3, renameSync, rmSync as rmSync2, utimesSync, writeSync } from "node:fs";
|
|
86042
86262
|
import os6 from "node:os";
|
|
86043
86263
|
import path5 from "node:path";
|
|
@@ -86477,13 +86697,17 @@ function isPathWithinScopes(resolved, scopePaths) {
|
|
|
86477
86697
|
);
|
|
86478
86698
|
}
|
|
86479
86699
|
|
|
86480
|
-
// ../../apps/collector/src/
|
|
86700
|
+
// ../../apps/collector/src/codexSessions.ts
|
|
86481
86701
|
function parseCodexRollout(text, sharedUsage) {
|
|
86482
86702
|
let meta3 = null;
|
|
86703
|
+
let initialEvent;
|
|
86704
|
+
let records = 0;
|
|
86483
86705
|
let model;
|
|
86484
86706
|
const timestamps = [];
|
|
86485
86707
|
const usage = sharedUsage ?? createCodexUsageReader();
|
|
86486
86708
|
for (const line of parseJsonl(text)) {
|
|
86709
|
+
records += 1;
|
|
86710
|
+
if (records === 2 && meta3 !== null) initialEvent = line;
|
|
86487
86711
|
if (typeof line.timestamp === "string") timestamps.push(line.timestamp);
|
|
86488
86712
|
usage.pushRecord(line);
|
|
86489
86713
|
const payload = line.payload;
|
|
@@ -86499,8 +86723,10 @@ function parseCodexRollout(text, sharedUsage) {
|
|
|
86499
86723
|
if (meta3 === null && timestamps.length === 0) return null;
|
|
86500
86724
|
const git = meta3?.git ?? null;
|
|
86501
86725
|
const sessionId = meta3?.id ?? meta3?.session_id;
|
|
86726
|
+
const facts = meta3 === null ? {} : harnessSessionFacts("codex", { ...meta3, initialEvent });
|
|
86502
86727
|
return {
|
|
86503
|
-
kind:
|
|
86728
|
+
kind: facts.subagent ? "subagent" : "session",
|
|
86729
|
+
...facts.standaloneReview && { standaloneReview: true },
|
|
86504
86730
|
...typeof sessionId === "string" && sessionId !== "" && { sessionId },
|
|
86505
86731
|
startedAt: timestamps[0],
|
|
86506
86732
|
endedAt: timestamps[timestamps.length - 1],
|
|
@@ -86536,6 +86762,7 @@ function foldRolloutPages(pages, usage) {
|
|
|
86536
86762
|
const repoFullName = first("repoFullName");
|
|
86537
86763
|
return {
|
|
86538
86764
|
kind: pages[0].kind,
|
|
86765
|
+
...pages[0].standaloneReview && { standaloneReview: true },
|
|
86539
86766
|
...sessionId !== void 0 && { sessionId },
|
|
86540
86767
|
...startedAt !== void 0 && { startedAt },
|
|
86541
86768
|
...endedAt !== void 0 && { endedAt },
|
|
@@ -86557,27 +86784,27 @@ function rolloutIdentity(rolloutPath) {
|
|
|
86557
86784
|
if (!conventional) return { threadId: name, page: false };
|
|
86558
86785
|
return { threadId: threadId2.toLowerCase(), page: pageId !== void 0 };
|
|
86559
86786
|
}
|
|
86560
|
-
function
|
|
86787
|
+
function codexMergedTranscriptsDir(home) {
|
|
86561
86788
|
return path5.join(home, ".config", "powerplant", "codex");
|
|
86562
86789
|
}
|
|
86563
|
-
function
|
|
86564
|
-
const existing = statIfExists(
|
|
86790
|
+
function mergedTranscriptIsFresh(mergedTranscriptPath, mtimeMs) {
|
|
86791
|
+
const existing = statIfExists(mergedTranscriptPath);
|
|
86565
86792
|
return existing !== null && Math.abs(existing.mtimeMs - mtimeMs) < 1;
|
|
86566
86793
|
}
|
|
86567
|
-
var
|
|
86568
|
-
constructor(
|
|
86569
|
-
this.
|
|
86570
|
-
mkdirSync2(path5.dirname(
|
|
86571
|
-
this.tmpPath = `${
|
|
86794
|
+
var MergedTranscriptWriter = class {
|
|
86795
|
+
constructor(mergedTranscriptPath) {
|
|
86796
|
+
this.mergedTranscriptPath = mergedTranscriptPath;
|
|
86797
|
+
mkdirSync2(path5.dirname(mergedTranscriptPath), { recursive: true, mode: 448 });
|
|
86798
|
+
this.tmpPath = `${mergedTranscriptPath}.${process.pid}.tmp`;
|
|
86572
86799
|
this.fd = openSync3(this.tmpPath, "w", 384);
|
|
86573
86800
|
}
|
|
86574
|
-
|
|
86801
|
+
mergedTranscriptPath;
|
|
86575
86802
|
tmpPath;
|
|
86576
86803
|
fd;
|
|
86577
86804
|
bytes = 0;
|
|
86578
|
-
append(
|
|
86805
|
+
append(pageText2) {
|
|
86579
86806
|
if (this.fd === void 0) throw new Error("merged transcript already closed");
|
|
86580
|
-
const text =
|
|
86807
|
+
const text = pageText2.endsWith("\n") ? pageText2 : `${pageText2}
|
|
86581
86808
|
`;
|
|
86582
86809
|
this.bytes += writeSync(this.fd, text);
|
|
86583
86810
|
}
|
|
@@ -86585,7 +86812,7 @@ var MergedSpoolWriter = class {
|
|
|
86585
86812
|
finish(mtimeMs) {
|
|
86586
86813
|
this.close();
|
|
86587
86814
|
utimesSync(this.tmpPath, mtimeMs / 1e3, mtimeMs / 1e3);
|
|
86588
|
-
renameSync(this.tmpPath, this.
|
|
86815
|
+
renameSync(this.tmpPath, this.mergedTranscriptPath);
|
|
86589
86816
|
return this.bytes;
|
|
86590
86817
|
}
|
|
86591
86818
|
abandon() {
|
|
@@ -86655,7 +86882,7 @@ async function collectCodexSessions(options = {}) {
|
|
|
86655
86882
|
const now = options.now ?? Date.now();
|
|
86656
86883
|
const capture = options.capture ?? captureEverythingUnresolved;
|
|
86657
86884
|
const maxBytes = options.maxTranscriptBytes ?? MAX_TRANSCRIPT_FILE_BYTES;
|
|
86658
|
-
const
|
|
86885
|
+
const mergedTranscriptsDir = options.mergedTranscriptsDir ?? codexMergedTranscriptsDir(options.homeDir ?? os6.homedir());
|
|
86659
86886
|
const items = [];
|
|
86660
86887
|
const candidates = [];
|
|
86661
86888
|
const unreadable = [];
|
|
@@ -86666,12 +86893,12 @@ async function collectCodexSessions(options = {}) {
|
|
|
86666
86893
|
let largestMergedBytes = 0;
|
|
86667
86894
|
const externalIdOf = (rolloutPath) => path5.basename(rolloutPath, ".jsonl");
|
|
86668
86895
|
const files = /* @__PURE__ */ new Map();
|
|
86669
|
-
const observe = async (paths, archived,
|
|
86896
|
+
const observe = async (paths, archived, discoverySessionId) => {
|
|
86670
86897
|
for (const rolloutPath of paths) {
|
|
86671
86898
|
const known = files.get(rolloutPath);
|
|
86672
86899
|
if (known !== void 0) {
|
|
86673
|
-
if (
|
|
86674
|
-
else known.
|
|
86900
|
+
if (discoverySessionId === void 0) delete known.discoverySessionIds;
|
|
86901
|
+
else known.discoverySessionIds?.push(discoverySessionId);
|
|
86675
86902
|
continue;
|
|
86676
86903
|
}
|
|
86677
86904
|
await yieldToEventLoop();
|
|
@@ -86684,15 +86911,15 @@ async function collectCodexSessions(options = {}) {
|
|
|
86684
86911
|
mtimeMs: stat.mtimeMs,
|
|
86685
86912
|
changedMs: Math.max(stat.mtimeMs, stat.ctimeMs),
|
|
86686
86913
|
sizeBytes: stat.size,
|
|
86687
|
-
...
|
|
86914
|
+
...discoverySessionId !== void 0 && { discoverySessionIds: [discoverySessionId] }
|
|
86688
86915
|
});
|
|
86689
86916
|
}
|
|
86690
86917
|
};
|
|
86691
86918
|
const archiveDir = codexArchivedSessionsDir(sessionsDir);
|
|
86692
|
-
const
|
|
86693
|
-
if (
|
|
86694
|
-
for (const
|
|
86695
|
-
await observe([
|
|
86919
|
+
const discoveryHome = options.homeDir ?? (options.codexDir === void 0 ? os6.homedir() : void 0);
|
|
86920
|
+
if (discoveryHome !== void 0) {
|
|
86921
|
+
for (const record2 of readCodexTranscriptDiscoveryRecords(discoveryHome, [sessionsDir, archiveDir])) {
|
|
86922
|
+
await observe([record2.rolloutPath], record2.archived, record2.sessionId);
|
|
86696
86923
|
}
|
|
86697
86924
|
}
|
|
86698
86925
|
await observe(rolloutFiles(sessionsDir), false);
|
|
@@ -86707,17 +86934,17 @@ async function collectCodexSessions(options = {}) {
|
|
|
86707
86934
|
const stored = dedupeStoreCopies(observed);
|
|
86708
86935
|
let externalId = externalIdOf((stored.find((file2) => !file2.identity.page) ?? stored[0]).rolloutPath);
|
|
86709
86936
|
try {
|
|
86710
|
-
const
|
|
86937
|
+
const mergedTranscriptPath = stored.length > 1 ? path5.join(mergedTranscriptsDir, `${threadId2}.jsonl`) : void 0;
|
|
86711
86938
|
const changedMs = Math.max(...stored.map((file2) => file2.changedMs));
|
|
86712
86939
|
if (options.sinceMs !== void 0 && changedMs < options.sinceMs) {
|
|
86713
|
-
const neverMerged =
|
|
86940
|
+
const neverMerged = mergedTranscriptPath !== void 0 && !options.locationsOnly && statIfExists(mergedTranscriptPath) === null;
|
|
86714
86941
|
if (!neverMerged) continue;
|
|
86715
86942
|
}
|
|
86716
86943
|
await yieldToEventLoop();
|
|
86717
86944
|
const named = stored.filter((file2) => {
|
|
86718
|
-
if (file2.
|
|
86945
|
+
if (file2.discoverySessionIds === void 0) return true;
|
|
86719
86946
|
const { sessionId } = rolloutLocation(file2.rolloutPath);
|
|
86720
|
-
return sessionId !== void 0 && file2.
|
|
86947
|
+
return sessionId !== void 0 && file2.discoverySessionIds.includes(sessionId);
|
|
86721
86948
|
});
|
|
86722
86949
|
if (named.length === 0) continue;
|
|
86723
86950
|
const threadFiles = named.length > 1 ? orderPages(named) : named;
|
|
@@ -86747,7 +86974,7 @@ async function collectCodexSessions(options = {}) {
|
|
|
86747
86974
|
const thread = {
|
|
86748
86975
|
externalId,
|
|
86749
86976
|
files: threadFiles,
|
|
86750
|
-
...threadFiles.length > 1 &&
|
|
86977
|
+
...threadFiles.length > 1 && mergedTranscriptPath !== void 0 && { mergedTranscriptPath },
|
|
86751
86978
|
mtimeMs,
|
|
86752
86979
|
archived: threadFiles.every((file2) => file2.archived)
|
|
86753
86980
|
};
|
|
@@ -86797,8 +87024,8 @@ async function collectCodexSessions(options = {}) {
|
|
|
86797
87024
|
const { thread, cwd, decision } = candidate;
|
|
86798
87025
|
let writer;
|
|
86799
87026
|
try {
|
|
86800
|
-
const rewrite = thread.
|
|
86801
|
-
if (thread.
|
|
87027
|
+
const rewrite = thread.mergedTranscriptPath !== void 0 && !mergedTranscriptIsFresh(thread.mergedTranscriptPath, thread.mtimeMs);
|
|
87028
|
+
if (thread.mergedTranscriptPath !== void 0 && rewrite) writer = new MergedTranscriptWriter(thread.mergedTranscriptPath);
|
|
86802
87029
|
const pages = [];
|
|
86803
87030
|
const usage = createCodexUsageReader();
|
|
86804
87031
|
let vanished = false;
|
|
@@ -86819,11 +87046,11 @@ async function collectCodexSessions(options = {}) {
|
|
|
86819
87046
|
continue;
|
|
86820
87047
|
}
|
|
86821
87048
|
const summary = foldRolloutPages(pages, usage.finish());
|
|
86822
|
-
let
|
|
86823
|
-
if (thread.
|
|
86824
|
-
const mergedBytes = writer ? writer.finish(thread.mtimeMs) : statIfExists(thread.
|
|
87049
|
+
let transcriptUploadSourcePath = thread.files[0].rolloutPath;
|
|
87050
|
+
if (thread.mergedTranscriptPath !== void 0) {
|
|
87051
|
+
const mergedBytes = writer ? writer.finish(thread.mtimeMs) : statIfExists(thread.mergedTranscriptPath)?.size ?? 0;
|
|
86825
87052
|
writer = void 0;
|
|
86826
|
-
|
|
87053
|
+
transcriptUploadSourcePath = thread.mergedTranscriptPath;
|
|
86827
87054
|
mergedThreads += 1;
|
|
86828
87055
|
largestMergedBytes = Math.max(largestMergedBytes, mergedBytes);
|
|
86829
87056
|
}
|
|
@@ -86832,13 +87059,14 @@ async function collectCodexSessions(options = {}) {
|
|
|
86832
87059
|
const title = summary.sessionId ? threadNames.get(summary.sessionId) : void 0;
|
|
86833
87060
|
items.push({
|
|
86834
87061
|
mtimeMs: thread.mtimeMs,
|
|
86835
|
-
transcriptPath,
|
|
87062
|
+
transcriptPath: transcriptUploadSourcePath,
|
|
86836
87063
|
...cwd && { cwd },
|
|
86837
87064
|
item: {
|
|
86838
87065
|
source: "codex",
|
|
86839
87066
|
externalId: thread.externalId,
|
|
86840
87067
|
status: now - thread.mtimeMs < ACTIVE_GRACE_MS ? "active" : "inactive",
|
|
86841
87068
|
archived: thread.archived,
|
|
87069
|
+
...summary.standaloneReview && { automation: true },
|
|
86842
87070
|
...summary.startedAt && { startedAt: summary.startedAt },
|
|
86843
87071
|
...summary.endedAt && { endedAt: summary.endedAt },
|
|
86844
87072
|
...summary.model && { model: summary.model },
|
|
@@ -86999,7 +87227,7 @@ function defaultCursorUserDir(home) {
|
|
|
86999
87227
|
function cursorGlobalStorageDir(home) {
|
|
87000
87228
|
return path6.join(defaultCursorUserDir(home), "globalStorage");
|
|
87001
87229
|
}
|
|
87002
|
-
function
|
|
87230
|
+
function cursorExtractedTranscriptsDir(home) {
|
|
87003
87231
|
return path6.join(home, ".config", "powerplant", "cursor");
|
|
87004
87232
|
}
|
|
87005
87233
|
var emptyResult = () => ({
|
|
@@ -87055,7 +87283,7 @@ var cachedMetaSchema = external_exports.object({
|
|
|
87055
87283
|
model: external_exports.string().optional(),
|
|
87056
87284
|
...cursorTranscriptMetaDisclosureSchema.shape
|
|
87057
87285
|
});
|
|
87058
|
-
function
|
|
87286
|
+
function extractedTranscriptFileName(composerId) {
|
|
87059
87287
|
const sanitized = composerId.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 80);
|
|
87060
87288
|
const hash2 = createHash2("sha256").update(composerId).digest("hex").slice(0, 8);
|
|
87061
87289
|
return `${sanitized}-${hash2}.jsonl`;
|
|
@@ -87118,7 +87346,7 @@ function toolFilePathOf(args) {
|
|
|
87118
87346
|
}
|
|
87119
87347
|
return void 0;
|
|
87120
87348
|
}
|
|
87121
|
-
var
|
|
87349
|
+
var EXTRACTED_TRANSCRIPT_META_RESERVE_BYTES = 64 * 1024;
|
|
87122
87350
|
var BUBBLE_FIELDS_SHARED = ["_v", "type", "bubbleId", "serverBubbleId", "text", "createdAt"];
|
|
87123
87351
|
var USER_BUBBLE_FIELDS = /* @__PURE__ */ new Set([...BUBBLE_FIELDS_SHARED, "context"]);
|
|
87124
87352
|
var ASSISTANT_BUBBLE_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -87362,7 +87590,7 @@ function extractTranscript(db, composerId, maxBytes) {
|
|
|
87362
87590
|
const spine = Array.isArray(data?.fullConversationHeadersOnly) ? data.fullConversationHeadersOnly : [];
|
|
87363
87591
|
if (spine.length === 0) return null;
|
|
87364
87592
|
const recorder = createOmissionRecorder();
|
|
87365
|
-
const budget = maxBytes -
|
|
87593
|
+
const budget = maxBytes - EXTRACTED_TRANSCRIPT_META_RESERVE_BYTES;
|
|
87366
87594
|
const serialized = [];
|
|
87367
87595
|
const modelCounts = /* @__PURE__ */ new Map();
|
|
87368
87596
|
let bytes = 0;
|
|
@@ -87443,7 +87671,7 @@ async function collectCursorSessions(options = {}) {
|
|
|
87443
87671
|
collectCursorTranscriptFiles(options, (id) => {
|
|
87444
87672
|
if (knownIds.has(id)) return true;
|
|
87445
87673
|
return db?.prepare("select composerId from composerHeaders where composerId = ?").get(id) != null;
|
|
87446
|
-
}, result, options.
|
|
87674
|
+
}, result, options.extractedTranscriptsDir ?? cursorExtractedTranscriptsDir(options.homeDir ?? os7.homedir()), extractedTranscriptFileName);
|
|
87447
87675
|
}
|
|
87448
87676
|
} finally {
|
|
87449
87677
|
try {
|
|
@@ -87457,9 +87685,9 @@ async function collectCursorSessions(options = {}) {
|
|
|
87457
87685
|
function collectFromStore(db, userDir, options, result, knownIds) {
|
|
87458
87686
|
const now = options.now ?? Date.now();
|
|
87459
87687
|
const capture = options.capture ?? captureEverythingUnresolved;
|
|
87460
|
-
const
|
|
87688
|
+
const extractedTranscriptsDir = options.extractedTranscriptsDir ?? cursorExtractedTranscriptsDir(options.homeDir ?? os7.homedir());
|
|
87461
87689
|
const maxBytes = options.maxTranscriptBytes ?? MAX_TRANSCRIPT_FILE_BYTES;
|
|
87462
|
-
let
|
|
87690
|
+
let extractedTranscriptsDirReady = false;
|
|
87463
87691
|
const columns = new Set(
|
|
87464
87692
|
db.prepare("pragma table_info(composerHeaders)").all().map((row) => isRecord2(row) ? row.name : void 0)
|
|
87465
87693
|
);
|
|
@@ -87509,15 +87737,15 @@ function collectFromStore(db, userDir, options, result, knownIds) {
|
|
|
87509
87737
|
});
|
|
87510
87738
|
continue;
|
|
87511
87739
|
}
|
|
87512
|
-
const
|
|
87513
|
-
const
|
|
87740
|
+
const transcriptUploadSourcePath = path6.join(extractedTranscriptsDir, extractedTranscriptFileName(raw.composerId));
|
|
87741
|
+
const extractedTranscriptStat = statIfExists(transcriptUploadSourcePath);
|
|
87514
87742
|
let model;
|
|
87515
|
-
const sourceUnchanged =
|
|
87516
|
-
if (sourceUnchanged &&
|
|
87743
|
+
const sourceUnchanged = extractedTranscriptStat !== null && Math.abs(extractedTranscriptStat.mtimeMs - lastUpdatedAt) < 1;
|
|
87744
|
+
if (sourceUnchanged && extractedTranscriptStat.size > maxBytes) {
|
|
87517
87745
|
result.skippedTooLarge += 1;
|
|
87518
87746
|
continue;
|
|
87519
87747
|
}
|
|
87520
|
-
const cached3 = sourceUnchanged ? readFirstRecord(
|
|
87748
|
+
const cached3 = sourceUnchanged ? readFirstRecord(transcriptUploadSourcePath, () => true) : null;
|
|
87521
87749
|
const cachedMeta = cachedMetaSchema.safeParse(cached3);
|
|
87522
87750
|
const preparationCurrent = cachedMeta.success && cachedMeta.data.composerId === raw.composerId;
|
|
87523
87751
|
let omissions;
|
|
@@ -87550,15 +87778,15 @@ function collectFromStore(db, userDir, options, result, knownIds) {
|
|
|
87550
87778
|
...counted && { omissions: transcript.omissions },
|
|
87551
87779
|
...unhandled.length > 0 && { unhandled }
|
|
87552
87780
|
};
|
|
87553
|
-
if (!
|
|
87554
|
-
mkdirSync3(
|
|
87555
|
-
chmodSync2(
|
|
87556
|
-
|
|
87781
|
+
if (!extractedTranscriptsDirReady) {
|
|
87782
|
+
mkdirSync3(extractedTranscriptsDir, { recursive: true, mode: 448 });
|
|
87783
|
+
chmodSync2(extractedTranscriptsDir, 448);
|
|
87784
|
+
extractedTranscriptsDirReady = true;
|
|
87557
87785
|
}
|
|
87558
87786
|
const body = [JSON.stringify(meta3), ...transcript.serialized, ""].join("\n");
|
|
87559
|
-
if (
|
|
87560
|
-
writeFileSync2(
|
|
87561
|
-
utimesSync2(
|
|
87787
|
+
if (extractedTranscriptStat !== null) chmodSync2(transcriptUploadSourcePath, 384);
|
|
87788
|
+
writeFileSync2(transcriptUploadSourcePath, body, { encoding: "utf8", mode: 384 });
|
|
87789
|
+
utimesSync2(transcriptUploadSourcePath, new Date(lastUpdatedAt), new Date(lastUpdatedAt));
|
|
87562
87790
|
}
|
|
87563
87791
|
if (hasCaptureGaps(omissions)) result.partiallyInterpreted += 1;
|
|
87564
87792
|
for (const observation of unhandledObservations(unhandled, raw.composerId)) {
|
|
@@ -87577,7 +87805,7 @@ function collectFromStore(db, userDir, options, result, knownIds) {
|
|
|
87577
87805
|
const startBranch = facts.branches[0];
|
|
87578
87806
|
result.sessions.push({
|
|
87579
87807
|
mtimeMs: lastUpdatedAt,
|
|
87580
|
-
transcriptPath:
|
|
87808
|
+
transcriptPath: transcriptUploadSourcePath,
|
|
87581
87809
|
...cwd && { cwd },
|
|
87582
87810
|
item: {
|
|
87583
87811
|
source: "cursor",
|
|
@@ -87711,7 +87939,7 @@ function parseCursorTranscriptFile(text) {
|
|
|
87711
87939
|
if (!lines.some((line) => CONTENT_LINE_TYPES2.has(line.type))) return null;
|
|
87712
87940
|
return { lines, omissions: recorder.omissions(), unhandled: recorder.unhandled() };
|
|
87713
87941
|
}
|
|
87714
|
-
function
|
|
87942
|
+
function extractedTranscriptBody(metaFor, lines, maxBytes) {
|
|
87715
87943
|
for (const keepPayloads of [true, false]) {
|
|
87716
87944
|
const payloadsDropped = keepPayloads ? 0 : lines.filter((line) => line.type === "unsupported" && line.payload !== void 0).length;
|
|
87717
87945
|
const records = [
|
|
@@ -87730,7 +87958,7 @@ function spoolBody(metaFor, lines, maxBytes) {
|
|
|
87730
87958
|
}
|
|
87731
87959
|
return null;
|
|
87732
87960
|
}
|
|
87733
|
-
var
|
|
87961
|
+
var extractedTranscriptMetaSchema = external_exports.object({
|
|
87734
87962
|
type: external_exports.literal("meta"),
|
|
87735
87963
|
format: external_exports.literal("cursor-local-transcript"),
|
|
87736
87964
|
version: external_exports.literal(1),
|
|
@@ -87742,7 +87970,7 @@ var spoolMetaSchema = external_exports.object({
|
|
|
87742
87970
|
model: external_exports.string().optional(),
|
|
87743
87971
|
...cursorTranscriptMetaDisclosureSchema.shape
|
|
87744
87972
|
});
|
|
87745
|
-
var
|
|
87973
|
+
var transcriptDiscoveryRecordSchema2 = external_exports.object({
|
|
87746
87974
|
sessionId: external_exports.string().regex(/^[a-zA-Z0-9_-]{1,200}$/),
|
|
87747
87975
|
transcriptPath: external_exports.string().max(4096).nullable(),
|
|
87748
87976
|
workspaceRoots: external_exports.array(external_exports.string().max(4096)).max(8),
|
|
@@ -87774,15 +88002,15 @@ function cursorTranscriptRecordPath(home, sessionId) {
|
|
|
87774
88002
|
`${createHash3("sha256").update(sessionId).digest("hex")}.json`
|
|
87775
88003
|
);
|
|
87776
88004
|
}
|
|
87777
|
-
function collectCursorTranscriptFiles(options, isDatabaseSession, result,
|
|
88005
|
+
function collectCursorTranscriptFiles(options, isDatabaseSession, result, databaseExtractedTranscriptsDir, extractedTranscriptFileName2) {
|
|
87778
88006
|
const home = options.homeDir ?? os8.homedir();
|
|
87779
|
-
const
|
|
87780
|
-
if (!existsSync3(
|
|
88007
|
+
const recordsDir = cursorTranscriptRecordsDir(home);
|
|
88008
|
+
if (!existsSync3(recordsDir)) return;
|
|
87781
88009
|
const maxBytes = options.maxTranscriptBytes ?? MAX_TRANSCRIPT_FILE_BYTES;
|
|
87782
|
-
const
|
|
88010
|
+
const nativeExtractedTranscriptsDir = path7.join(databaseExtractedTranscriptsDir, "native");
|
|
87783
88011
|
let files;
|
|
87784
88012
|
try {
|
|
87785
|
-
files = readdirSync3(
|
|
88013
|
+
files = readdirSync3(recordsDir);
|
|
87786
88014
|
} catch {
|
|
87787
88015
|
result.skippedUnreadable++;
|
|
87788
88016
|
return;
|
|
@@ -87790,15 +88018,15 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
|
|
|
87790
88018
|
for (const file2 of files) {
|
|
87791
88019
|
if (!/^[a-f0-9]{64}\.json$/.test(file2)) continue;
|
|
87792
88020
|
try {
|
|
87793
|
-
const
|
|
87794
|
-
if (!lstatSync2(
|
|
87795
|
-
const text = readBounded(
|
|
87796
|
-
const
|
|
87797
|
-
if (file2 !== `${createHash3("sha256").update(
|
|
87798
|
-
if (isDatabaseSession(
|
|
88021
|
+
const recordPath = path7.join(recordsDir, file2);
|
|
88022
|
+
if (!lstatSync2(recordPath).isFile()) continue;
|
|
88023
|
+
const text = readBounded(recordPath, 40 * 1024);
|
|
88024
|
+
const record2 = transcriptDiscoveryRecordSchema2.parse(text === null ? null : JSON.parse(text));
|
|
88025
|
+
if (file2 !== `${createHash3("sha256").update(record2.sessionId).digest("hex")}.json`) continue;
|
|
88026
|
+
if (isDatabaseSession(record2.sessionId) || existsSync3(path7.join(databaseExtractedTranscriptsDir, extractedTranscriptFileName2(record2.sessionId))))
|
|
87799
88027
|
continue;
|
|
87800
|
-
if (
|
|
87801
|
-
const cwd =
|
|
88028
|
+
if (record2.transcriptPath === null || record2.workspaceRoots.length !== 1) continue;
|
|
88029
|
+
const cwd = record2.workspaceRoots[0];
|
|
87802
88030
|
if (!path7.isAbsolute(cwd)) continue;
|
|
87803
88031
|
const decision = captureDecision(cwd, options.capture ?? captureEverythingUnresolved);
|
|
87804
88032
|
if (!decision.capture) {
|
|
@@ -87808,14 +88036,14 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
|
|
|
87808
88036
|
const projects = path7.join(home, ".cursor", "projects");
|
|
87809
88037
|
const project = cwd.replace(/[^a-zA-Z0-9]/g, "-").replace(/^-+/, "");
|
|
87810
88038
|
const base = path7.join(projects, project, "agent-transcripts");
|
|
87811
|
-
const basename2 = `${
|
|
87812
|
-
const allowed = [path7.join(base, basename2), path7.join(base,
|
|
87813
|
-
if (!allowed.includes(
|
|
88039
|
+
const basename2 = `${record2.sessionId}.jsonl`;
|
|
88040
|
+
const allowed = [path7.join(base, basename2), path7.join(base, record2.sessionId, basename2)];
|
|
88041
|
+
if (!allowed.includes(record2.transcriptPath)) {
|
|
87814
88042
|
result.skippedUnreadable++;
|
|
87815
88043
|
continue;
|
|
87816
88044
|
}
|
|
87817
|
-
const stat = lstatSync2(
|
|
87818
|
-
if (!stat.isFile() || realpathSync2(
|
|
88045
|
+
const stat = lstatSync2(record2.transcriptPath);
|
|
88046
|
+
if (!stat.isFile() || realpathSync2(record2.transcriptPath) !== path7.join(realpathSync2(projects), path7.relative(projects, record2.transcriptPath))) {
|
|
87819
88047
|
result.skippedUnreadable++;
|
|
87820
88048
|
continue;
|
|
87821
88049
|
}
|
|
@@ -87826,7 +88054,7 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
|
|
|
87826
88054
|
}
|
|
87827
88055
|
const common = {
|
|
87828
88056
|
source: "cursor",
|
|
87829
|
-
externalId:
|
|
88057
|
+
externalId: record2.sessionId,
|
|
87830
88058
|
status: (options.now ?? Date.now()) - stat.mtimeMs < ACTIVE_GRACE_MS ? "active" : "inactive",
|
|
87831
88059
|
...decision.repoFullName && { repoFullName: decision.repoFullName },
|
|
87832
88060
|
capturedVia: decision.via
|
|
@@ -87835,15 +88063,15 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
|
|
|
87835
88063
|
result.sessions.push({
|
|
87836
88064
|
cwd,
|
|
87837
88065
|
mtimeMs: stat.mtimeMs,
|
|
87838
|
-
transcriptPath:
|
|
88066
|
+
transcriptPath: record2.transcriptPath,
|
|
87839
88067
|
item: common
|
|
87840
88068
|
});
|
|
87841
88069
|
continue;
|
|
87842
88070
|
}
|
|
87843
|
-
const
|
|
87844
|
-
const
|
|
87845
|
-
const cached3 =
|
|
87846
|
-
const fresh = cached3?.success && cached3.data.composerId ===
|
|
88071
|
+
const transcriptUploadSourcePath = path7.join(nativeExtractedTranscriptsDir, extractedTranscriptFileName2(record2.sessionId));
|
|
88072
|
+
const extractedTranscriptStat = statIfExists(transcriptUploadSourcePath);
|
|
88073
|
+
const cached3 = extractedTranscriptStat !== null && extractedTranscriptStat.size <= maxBytes && Math.abs(extractedTranscriptStat.mtimeMs - stat.mtimeMs) < 1 ? extractedTranscriptMetaSchema.safeParse(readFirstRecord(transcriptUploadSourcePath, () => true)) : null;
|
|
88074
|
+
const fresh = cached3?.success && cached3.data.composerId === record2.sessionId && cached3.data.workspacePath === cwd && cached3.data.nativeSourceSize === stat.size && cached3.data.model === record2.model;
|
|
87847
88075
|
let title;
|
|
87848
88076
|
let omissions;
|
|
87849
88077
|
let unhandled = [];
|
|
@@ -87852,7 +88080,7 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
|
|
|
87852
88080
|
omissions = cached3.data.omissions;
|
|
87853
88081
|
unhandled = cached3.data.unhandled ?? [];
|
|
87854
88082
|
} else {
|
|
87855
|
-
const raw = readBounded(
|
|
88083
|
+
const raw = readBounded(record2.transcriptPath, maxBytes);
|
|
87856
88084
|
if (raw === null) {
|
|
87857
88085
|
result.skippedTooLarge++;
|
|
87858
88086
|
continue;
|
|
@@ -87873,40 +88101,40 @@ function collectCursorTranscriptFiles(options, isDatabaseSession, result, databa
|
|
|
87873
88101
|
format: "cursor-local-transcript",
|
|
87874
88102
|
version: 1,
|
|
87875
88103
|
preparationVersion: CURSOR_TRANSCRIPT_PREPARATION_VERSION,
|
|
87876
|
-
composerId:
|
|
88104
|
+
composerId: record2.sessionId,
|
|
87877
88105
|
workspacePath: cwd,
|
|
87878
88106
|
nativeSourceSize: stat.size,
|
|
87879
88107
|
...title !== void 0 && { name: title },
|
|
87880
|
-
...
|
|
88108
|
+
...record2.model && { model: record2.model },
|
|
87881
88109
|
...Object.keys(written).length > 0 && { omissions: written },
|
|
87882
88110
|
...prepared.unhandled.length > 0 && { unhandled: prepared.unhandled }
|
|
87883
88111
|
};
|
|
87884
88112
|
};
|
|
87885
|
-
const body =
|
|
88113
|
+
const body = extractedTranscriptBody(metaFor, prepared.lines, maxBytes);
|
|
87886
88114
|
if (body === null) {
|
|
87887
88115
|
result.skippedTooLarge++;
|
|
87888
88116
|
continue;
|
|
87889
88117
|
}
|
|
87890
|
-
mkdirSync4(
|
|
87891
|
-
if (
|
|
87892
|
-
writeFileSync3(
|
|
87893
|
-
utimesSync3(
|
|
88118
|
+
mkdirSync4(nativeExtractedTranscriptsDir, { recursive: true, mode: 448 });
|
|
88119
|
+
if (extractedTranscriptStat !== null) chmodSync3(transcriptUploadSourcePath, 384);
|
|
88120
|
+
writeFileSync3(transcriptUploadSourcePath, body, { mode: 384 });
|
|
88121
|
+
utimesSync3(transcriptUploadSourcePath, stat.atime, stat.mtime);
|
|
87894
88122
|
omissions = Object.keys(written).length > 0 ? written : void 0;
|
|
87895
88123
|
unhandled = prepared.unhandled;
|
|
87896
88124
|
}
|
|
87897
88125
|
if (hasCaptureGaps(omissions)) result.partiallyInterpreted++;
|
|
87898
|
-
for (const observation of unhandledObservations(unhandled,
|
|
88126
|
+
for (const observation of unhandledObservations(unhandled, record2.sessionId)) {
|
|
87899
88127
|
observeStructure(options.onStructureDiagnostic, observation);
|
|
87900
88128
|
}
|
|
87901
88129
|
result.sessions.push({
|
|
87902
88130
|
cwd,
|
|
87903
88131
|
mtimeMs: stat.mtimeMs,
|
|
87904
|
-
transcriptPath:
|
|
88132
|
+
transcriptPath: transcriptUploadSourcePath,
|
|
87905
88133
|
item: {
|
|
87906
88134
|
...common,
|
|
87907
88135
|
endedAt: stat.mtime.toISOString(),
|
|
87908
88136
|
repoDir: path7.basename(cwd),
|
|
87909
|
-
...
|
|
88137
|
+
...record2.model && { model: record2.model },
|
|
87910
88138
|
...title !== void 0 && { title }
|
|
87911
88139
|
}
|
|
87912
88140
|
});
|
|
@@ -88070,7 +88298,7 @@ function observedSessionEnd(entry, mtimeMs) {
|
|
|
88070
88298
|
return entry.at;
|
|
88071
88299
|
}
|
|
88072
88300
|
|
|
88073
|
-
// ../../apps/collector/src/
|
|
88301
|
+
// ../../apps/collector/src/harnessHooks.ts
|
|
88074
88302
|
import {
|
|
88075
88303
|
existsSync as existsSync5,
|
|
88076
88304
|
lstatSync as lstatSync3,
|
|
@@ -88086,26 +88314,39 @@ var SESSION_CHANGE_HOOK = "powerplant-session-change.mjs";
|
|
|
88086
88314
|
var CODEX_TRANSCRIPT_HOOK = "powerplant-codex-transcript.mjs";
|
|
88087
88315
|
var CURSOR_TRANSCRIPT_HOOK = "powerplant-cursor-transcript.mjs";
|
|
88088
88316
|
var SESSION_CHANGE_FILENAME = "session-change";
|
|
88317
|
+
var SUPPORTED_HOOK_HARNESSES = ["codex-local", "cursor-local"];
|
|
88089
88318
|
var jsonObject = external_exports.record(external_exports.string(), external_exports.json());
|
|
88090
|
-
function
|
|
88091
|
-
|
|
88319
|
+
function nativeHarnessName(harness) {
|
|
88320
|
+
switch (harness) {
|
|
88321
|
+
case "codex-local":
|
|
88322
|
+
return "codex";
|
|
88323
|
+
case "cursor-local":
|
|
88324
|
+
return "cursor";
|
|
88325
|
+
default:
|
|
88326
|
+
throw new Error(`unsupported hook harness: ${String(harness)}`);
|
|
88327
|
+
}
|
|
88328
|
+
}
|
|
88329
|
+
function harnessEvents(harness) {
|
|
88330
|
+
return nativeHarnessName(harness) === "cursor" ? ["sessionStart", "sessionEnd", "stop"] : ["SessionStart", "SessionEnd", "Stop"];
|
|
88092
88331
|
}
|
|
88093
|
-
function
|
|
88094
|
-
|
|
88332
|
+
function harnessHookConfigPath(harness, home) {
|
|
88333
|
+
const nativeName = nativeHarnessName(harness);
|
|
88334
|
+
return path10.join(home, `.${nativeName}`, "hooks.json");
|
|
88095
88335
|
}
|
|
88096
88336
|
var UNUSABLE_CONFIG = "hooks.json contains invalid JSON or an unsupported hook structure";
|
|
88097
88337
|
var NON_REGULAR_CONFIG = "hooks.json is not a regular file; configure the hook manually";
|
|
88098
|
-
function
|
|
88338
|
+
function harnessHookCommands(harness, text) {
|
|
88099
88339
|
try {
|
|
88340
|
+
const nativeName = nativeHarnessName(harness);
|
|
88100
88341
|
const settings = jsonObject.parse(text === null ? {} : JSON.parse(text));
|
|
88101
|
-
if (
|
|
88342
|
+
if (nativeName === "cursor" && settings.version !== void 0 && settings.version !== 1) {
|
|
88102
88343
|
return { kind: "unusable", reason: "Unsupported Cursor hooks version" };
|
|
88103
88344
|
}
|
|
88104
88345
|
const hooks = jsonObject.parse(settings.hooks === void 0 ? {} : settings.hooks);
|
|
88105
88346
|
const commands = [];
|
|
88106
|
-
for (const event of
|
|
88347
|
+
for (const event of harnessEvents(harness)) {
|
|
88107
88348
|
const entries = external_exports.array(jsonObject).parse(hooks[event] === void 0 ? [] : hooks[event]);
|
|
88108
|
-
const handlers2 =
|
|
88349
|
+
const handlers2 = nativeName === "cursor" ? entries : entries.flatMap((entry) => external_exports.array(jsonObject).parse(entry.hooks));
|
|
88109
88350
|
const ours = handlers2.filter(isOurHook);
|
|
88110
88351
|
if (ours.length === 0) return { kind: "missing" };
|
|
88111
88352
|
for (const hook of ours) {
|
|
@@ -88121,20 +88362,21 @@ function isOurHook(hook) {
|
|
|
88121
88362
|
const command = hook.command;
|
|
88122
88363
|
return typeof command === "string" && [SESSION_CHANGE_HOOK, CODEX_TRANSCRIPT_HOOK, CURSOR_TRANSCRIPT_HOOK].some((script) => command.endsWith(`/${script}'`) || command.endsWith(`/${script}"`));
|
|
88123
88364
|
}
|
|
88124
|
-
function
|
|
88365
|
+
function mergeHarnessHooks(harness, text, command) {
|
|
88125
88366
|
try {
|
|
88367
|
+
const nativeName = nativeHarnessName(harness);
|
|
88126
88368
|
const settings = jsonObject.parse(text === null ? {} : JSON.parse(text));
|
|
88127
|
-
if (
|
|
88369
|
+
if (nativeName === "cursor" && settings.version !== void 0 && settings.version !== 1) {
|
|
88128
88370
|
return { action: "skip", reason: "Unsupported Cursor hooks version" };
|
|
88129
88371
|
}
|
|
88130
88372
|
const hooks = jsonObject.parse(settings.hooks === void 0 ? {} : settings.hooks);
|
|
88131
|
-
for (const event of
|
|
88373
|
+
for (const event of harnessEvents(harness)) {
|
|
88132
88374
|
const entries = external_exports.array(jsonObject).parse(hooks[event] === void 0 ? [] : hooks[event]);
|
|
88133
|
-
const handler =
|
|
88134
|
-
const ours =
|
|
88375
|
+
const handler = nativeName === "cursor" ? { command, timeout: 2 } : { type: "command", command, timeout: 2 };
|
|
88376
|
+
const ours = nativeName === "cursor" ? handler : { hooks: [handler] };
|
|
88135
88377
|
const kept = [];
|
|
88136
88378
|
for (const entry of entries) {
|
|
88137
|
-
if (
|
|
88379
|
+
if (nativeName === "cursor") {
|
|
88138
88380
|
if (!isOurHook(entry)) kept.push(entry);
|
|
88139
88381
|
continue;
|
|
88140
88382
|
}
|
|
@@ -88145,7 +88387,7 @@ function mergeProviderHooks(provider, text, command) {
|
|
|
88145
88387
|
}
|
|
88146
88388
|
hooks[event] = [...kept, ours];
|
|
88147
88389
|
}
|
|
88148
|
-
const next = { ...settings, ...
|
|
88390
|
+
const next = { ...settings, ...nativeName === "cursor" ? { version: 1 } : {}, hooks };
|
|
88149
88391
|
if (JSON.stringify(next) === JSON.stringify(settings)) return { action: "unchanged" };
|
|
88150
88392
|
return { action: "write", text: `${JSON.stringify(next, null, 2)}
|
|
88151
88393
|
` };
|
|
@@ -88156,42 +88398,47 @@ function mergeProviderHooks(provider, text, command) {
|
|
|
88156
88398
|
function shellQuote2(value) {
|
|
88157
88399
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
88158
88400
|
}
|
|
88159
|
-
function
|
|
88160
|
-
const
|
|
88161
|
-
|
|
88162
|
-
|
|
88401
|
+
function installHarnessHook(harness, home) {
|
|
88402
|
+
const nativeName = nativeHarnessName(harness);
|
|
88403
|
+
const configDir = path10.join(home, `.${nativeName}`);
|
|
88404
|
+
if (!existsSync5(configDir)) return { provider: nativeName, settings: "absent" };
|
|
88405
|
+
const configPath = harnessHookConfigPath(harness, home);
|
|
88163
88406
|
let original = null;
|
|
88164
88407
|
let mode = 384;
|
|
88165
88408
|
try {
|
|
88166
88409
|
const stat = lstatSync3(configPath);
|
|
88167
|
-
if (!stat.isFile())
|
|
88410
|
+
if (!stat.isFile()) {
|
|
88411
|
+
return { provider: nativeName, settings: "skip", detail: NON_REGULAR_CONFIG };
|
|
88412
|
+
}
|
|
88168
88413
|
mode = stat.mode & 511;
|
|
88169
88414
|
original = readFileSync6(configPath, "utf8");
|
|
88170
88415
|
} catch (error63) {
|
|
88171
88416
|
if (!(error63 instanceof Error && "code" in error63 && error63.code === "ENOENT")) throw error63;
|
|
88172
88417
|
}
|
|
88173
88418
|
const hookDir = path10.join(home, ".config", "powerplant", "hooks");
|
|
88174
|
-
const script =
|
|
88419
|
+
const script = nativeName === "cursor" ? CURSOR_TRANSCRIPT_HOOK : CODEX_TRANSCRIPT_HOOK;
|
|
88175
88420
|
const scriptPath = path10.join(hookDir, script);
|
|
88176
|
-
const merged =
|
|
88177
|
-
|
|
88421
|
+
const merged = mergeHarnessHooks(
|
|
88422
|
+
harness,
|
|
88178
88423
|
original,
|
|
88179
88424
|
`${shellQuote2(process.execPath)} ${shellQuote2(scriptPath)}`
|
|
88180
88425
|
);
|
|
88181
|
-
if (merged.action === "skip")
|
|
88426
|
+
if (merged.action === "skip") {
|
|
88427
|
+
return { provider: nativeName, settings: "skip", detail: merged.reason };
|
|
88428
|
+
}
|
|
88182
88429
|
mkdirSync6(hookDir, { recursive: true });
|
|
88183
88430
|
writeAtomic(scriptPath, readFileSync6(hookSourcePath(script), "utf8"), 448);
|
|
88184
88431
|
if (merged.action === "write") {
|
|
88185
88432
|
const current = existsSync5(configPath) ? readFileSync6(configPath, "utf8") : null;
|
|
88186
88433
|
if (current !== original)
|
|
88187
88434
|
return {
|
|
88188
|
-
provider,
|
|
88435
|
+
provider: nativeName,
|
|
88189
88436
|
settings: "skip",
|
|
88190
88437
|
detail: "hooks.json changed during installation; restart the collector to retry"
|
|
88191
88438
|
};
|
|
88192
88439
|
writeAtomic(configPath, merged.text, mode);
|
|
88193
88440
|
}
|
|
88194
|
-
return { provider, settings: merged.action };
|
|
88441
|
+
return { provider: nativeName, settings: merged.action };
|
|
88195
88442
|
}
|
|
88196
88443
|
function writeAtomic(file2, text, mode) {
|
|
88197
88444
|
const temporary = `${file2}.${randomUUID()}.tmp`;
|
|
@@ -88202,13 +88449,13 @@ function writeAtomic(file2, text, mode) {
|
|
|
88202
88449
|
rmSync4(temporary, { force: true });
|
|
88203
88450
|
}
|
|
88204
88451
|
}
|
|
88205
|
-
function
|
|
88206
|
-
return
|
|
88452
|
+
function installHarnessHooks(home) {
|
|
88453
|
+
return SUPPORTED_HOOK_HARNESSES.map((harness) => {
|
|
88207
88454
|
try {
|
|
88208
|
-
return
|
|
88455
|
+
return installHarnessHook(harness, home);
|
|
88209
88456
|
} catch (error63) {
|
|
88210
88457
|
return {
|
|
88211
|
-
provider,
|
|
88458
|
+
provider: nativeHarnessName(harness),
|
|
88212
88459
|
settings: "skip",
|
|
88213
88460
|
detail: error63 instanceof Error ? error63.message : String(error63)
|
|
88214
88461
|
};
|
|
@@ -88220,7 +88467,7 @@ function installProviderHooks(home) {
|
|
|
88220
88467
|
var HOOK_OBSERVATION_GRACE_MS = 2 * 6e4;
|
|
88221
88468
|
var hookHealthSchema = external_exports.object({
|
|
88222
88469
|
harness: hookHarnessSchema,
|
|
88223
|
-
/** What this daemon's boot-time install did (installCollectorHooks /
|
|
88470
|
+
/** What this daemon's boot-time install did (installCollectorHooks / installHarnessHooks). */
|
|
88224
88471
|
install: hookInstallOutcomeSchema,
|
|
88225
88472
|
/** unverified: no in-scope session started since the install has been
|
|
88226
88473
|
* judged yet. firing: one carried a hook record. silent: one had none. */
|
|
@@ -88249,7 +88496,10 @@ var HARNESS_NAMES = {
|
|
|
88249
88496
|
cursor: "Cursor"
|
|
88250
88497
|
};
|
|
88251
88498
|
function configPathOf(harness, home) {
|
|
88252
|
-
return harness === "claude" ? claudeSettingsPath(home) :
|
|
88499
|
+
return harness === "claude" ? claudeSettingsPath(home) : harnessHookConfigPath(localHookHarness(harness), home);
|
|
88500
|
+
}
|
|
88501
|
+
function localHookHarness(harness) {
|
|
88502
|
+
return harness === "codex" ? "codex-local" : "cursor-local";
|
|
88253
88503
|
}
|
|
88254
88504
|
function commandPaths(command) {
|
|
88255
88505
|
const paths = [];
|
|
@@ -88284,7 +88534,7 @@ function inspectHookConfig(harness, home) {
|
|
|
88284
88534
|
detail: error63 instanceof Error ? error63.message : String(error63)
|
|
88285
88535
|
};
|
|
88286
88536
|
}
|
|
88287
|
-
const read = harness === "claude" ? collectorHookCommands(text) :
|
|
88537
|
+
const read = harness === "claude" ? collectorHookCommands(text) : harnessHookCommands(localHookHarness(harness), text);
|
|
88288
88538
|
if (read.kind === "unusable") return { kind: "config-unusable", configPath, detail: read.reason };
|
|
88289
88539
|
if (read.kind === "missing") return { kind: "entries-missing", configPath };
|
|
88290
88540
|
for (const command of read.commands) {
|
|
@@ -89186,7 +89436,7 @@ async function uploadPreviewRegistration(apiUrl, machineToken, registration) {
|
|
|
89186
89436
|
function encodeRawTranscript(text) {
|
|
89187
89437
|
return gzipSync(redactJsonl(text));
|
|
89188
89438
|
}
|
|
89189
|
-
async function uploadRawSessions(apiUrl, machineToken,
|
|
89439
|
+
async function uploadRawSessions(apiUrl, machineToken, transcriptUploadSources, readTranscript = (p) => readFileSync9(p, "utf8"), shipped, progress) {
|
|
89190
89440
|
const summary = {
|
|
89191
89441
|
uploaded: 0,
|
|
89192
89442
|
skippedTooLarge: 0,
|
|
@@ -89197,18 +89447,19 @@ async function uploadRawSessions(apiUrl, machineToken, collected, readTranscript
|
|
|
89197
89447
|
};
|
|
89198
89448
|
const initiallyShipped = new Map(shipped);
|
|
89199
89449
|
let rateLimited;
|
|
89200
|
-
for (const session of
|
|
89450
|
+
for (const session of transcriptUploadSources) {
|
|
89201
89451
|
summary.uploaded += await progress?.beforeUpload?.() ?? 0;
|
|
89202
|
-
const
|
|
89203
|
-
|
|
89452
|
+
const transcriptUploadSourcePath = session.transcriptPath;
|
|
89453
|
+
const acknowledged = shipped?.get(transcriptUploadSourcePath);
|
|
89454
|
+
if (acknowledged === session.mtimeMs || acknowledged !== void 0 && acknowledged !== initiallyShipped.get(transcriptUploadSourcePath)) {
|
|
89204
89455
|
summary.skippedUnchanged += 1;
|
|
89205
89456
|
continue;
|
|
89206
89457
|
}
|
|
89207
89458
|
try {
|
|
89208
|
-
const body = encodeRawTranscript(readTranscript(
|
|
89459
|
+
const body = encodeRawTranscript(readTranscript(transcriptUploadSourcePath));
|
|
89209
89460
|
if (body.byteLength > MAX_RAW_UPLOAD_BYTES) {
|
|
89210
89461
|
summary.skippedTooLarge += 1;
|
|
89211
|
-
shipped?.set(
|
|
89462
|
+
shipped?.set(transcriptUploadSourcePath, session.mtimeMs);
|
|
89212
89463
|
continue;
|
|
89213
89464
|
}
|
|
89214
89465
|
const query = `source=${session.item.source}&externalId=${encodeURIComponent(session.item.externalId)}`;
|
|
@@ -89241,7 +89492,7 @@ async function uploadRawSessions(apiUrl, machineToken, collected, readTranscript
|
|
|
89241
89492
|
}
|
|
89242
89493
|
summary.uploaded += 1;
|
|
89243
89494
|
progress?.onUploaded?.();
|
|
89244
|
-
shipped?.set(
|
|
89495
|
+
shipped?.set(transcriptUploadSourcePath, session.mtimeMs);
|
|
89245
89496
|
} catch (error63) {
|
|
89246
89497
|
if (error63 instanceof RateLimitedError) rateLimited ??= error63;
|
|
89247
89498
|
summary.failed.push(
|
|
@@ -91112,7 +91363,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
91112
91363
|
);
|
|
91113
91364
|
reportCollectorError(error63, "watch-hook-install");
|
|
91114
91365
|
}
|
|
91115
|
-
for (const hook of
|
|
91366
|
+
for (const hook of installHarnessHooks(home)) {
|
|
91116
91367
|
hookInstalls[hook.provider] = hook.settings;
|
|
91117
91368
|
if (hook.settings === "absent") continue;
|
|
91118
91369
|
if (hook.settings === "skip") {
|
|
@@ -91861,7 +92112,7 @@ function belowVersionFloor(client, versionText) {
|
|
|
91861
92112
|
}
|
|
91862
92113
|
|
|
91863
92114
|
// src/connect.ts
|
|
91864
|
-
var
|
|
92115
|
+
var mcpServerNameFor = (appEnv) => appEnv === "production" ? "powerplant" : `powerplant-${appEnv}`;
|
|
91865
92116
|
var AGENT_DISPLAY_NAMES = {
|
|
91866
92117
|
claude: "Claude Code",
|
|
91867
92118
|
codex: "Codex",
|
|
@@ -92298,7 +92549,7 @@ function realCheckboxPrompt(question, choices, seams = {}) {
|
|
|
92298
92549
|
function claudeAddArgs(deps) {
|
|
92299
92550
|
const official = deps.officialClients?.["claude-code"];
|
|
92300
92551
|
const credentialArgs = official ? ["--client-id", official.clientId, "--callback-port", String(official.callbackPort)] : [];
|
|
92301
|
-
return ["mcp", "add", "--transport", "http", "--scope", "user", ...credentialArgs,
|
|
92552
|
+
return ["mcp", "add", "--transport", "http", "--scope", "user", ...credentialArgs, deps.serverName, deps.mcpUrl];
|
|
92302
92553
|
}
|
|
92303
92554
|
function parseClaudeProbe(result) {
|
|
92304
92555
|
const output2 = result.stdout + result.stderr;
|
|
@@ -92319,7 +92570,7 @@ function claudeEnv(client) {
|
|
|
92319
92570
|
function connectClaude(client, name, deps) {
|
|
92320
92571
|
const { bin } = client;
|
|
92321
92572
|
const env = claudeEnv(client);
|
|
92322
|
-
const probe = parseClaudeProbe(deps.run(bin, ["mcp", "get",
|
|
92573
|
+
const probe = parseClaudeProbe(deps.run(bin, ["mcp", "get", deps.serverName], env));
|
|
92323
92574
|
if (probe.broken) {
|
|
92324
92575
|
return failed(`probing for the Powerplant MCP failed, ${probe.detail}`);
|
|
92325
92576
|
}
|
|
@@ -92327,7 +92578,7 @@ function connectClaude(client, name, deps) {
|
|
|
92327
92578
|
if (missing || registeredUrl !== void 0 && registeredUrl !== deps.mcpUrl) {
|
|
92328
92579
|
if (!missing) {
|
|
92329
92580
|
deps.log(`${name}: registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
|
|
92330
|
-
deps.run(bin, ["mcp", "remove", "--scope", "user",
|
|
92581
|
+
deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
|
|
92331
92582
|
}
|
|
92332
92583
|
const add = deps.run(bin, claudeAddArgs(deps), env);
|
|
92333
92584
|
if (add.status !== 0) {
|
|
@@ -92339,7 +92590,7 @@ function connectClaude(client, name, deps) {
|
|
|
92339
92590
|
return { state: "connected", unchanged: true };
|
|
92340
92591
|
} else if (deps.officialClients?.["claude-code"]) {
|
|
92341
92592
|
deps.log(`${name}: re-registering with the pre-registered client before sign-in.`);
|
|
92342
|
-
deps.run(bin, ["mcp", "remove", "--scope", "user",
|
|
92593
|
+
deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
|
|
92343
92594
|
const add = deps.run(bin, claudeAddArgs(deps), env);
|
|
92344
92595
|
if (add.status !== 0) {
|
|
92345
92596
|
return failed(`registering the Powerplant MCP failed, ${describeFailure(add)}`);
|
|
@@ -92347,7 +92598,7 @@ function connectClaude(client, name, deps) {
|
|
|
92347
92598
|
} else {
|
|
92348
92599
|
deps.log(`${name}: Powerplant MCP already registered.`);
|
|
92349
92600
|
}
|
|
92350
|
-
return login(bin, name, ["mcp", "login",
|
|
92601
|
+
return login(bin, name, ["mcp", "login", deps.serverName], deps, env);
|
|
92351
92602
|
}
|
|
92352
92603
|
function codexOauthHeaderPattern(serverName) {
|
|
92353
92604
|
return new RegExp(
|
|
@@ -92514,7 +92765,7 @@ function parseCodexServers(stdout) {
|
|
|
92514
92765
|
}
|
|
92515
92766
|
}
|
|
92516
92767
|
var CODEX_AUTHENTICATED_STATUSES = /* @__PURE__ */ new Set(["o_auth", "bearer_token"]);
|
|
92517
|
-
function parseCodexProbe(result) {
|
|
92768
|
+
function parseCodexProbe(result, serverName) {
|
|
92518
92769
|
if (result.status !== 0) {
|
|
92519
92770
|
return {
|
|
92520
92771
|
broken: true,
|
|
@@ -92532,7 +92783,7 @@ function parseCodexProbe(result) {
|
|
|
92532
92783
|
authenticated: false
|
|
92533
92784
|
};
|
|
92534
92785
|
}
|
|
92535
|
-
const existing = servers.find((server) => server.name ===
|
|
92786
|
+
const existing = servers.find((server) => server.name === serverName);
|
|
92536
92787
|
if (!existing) return { broken: false, missing: true, authenticated: false };
|
|
92537
92788
|
return {
|
|
92538
92789
|
broken: false,
|
|
@@ -92544,7 +92795,7 @@ function parseCodexProbe(result) {
|
|
|
92544
92795
|
function codexAddArgs(deps, options) {
|
|
92545
92796
|
const official = deps.officialClients?.codex;
|
|
92546
92797
|
const credentialArgs = options.withOfficialClientId && official ? ["--oauth-client-id", official.clientId] : [];
|
|
92547
|
-
return ["mcp", "add",
|
|
92798
|
+
return ["mcp", "add", deps.serverName, ...credentialArgs, "--url", deps.mcpUrl];
|
|
92548
92799
|
}
|
|
92549
92800
|
function codexAddLogsIn(bin, deps) {
|
|
92550
92801
|
const help = deps.run(bin, ["mcp", "add", "--help"]);
|
|
@@ -92559,9 +92810,9 @@ function codexServerEntryPattern(serverName) {
|
|
|
92559
92810
|
function healOrphanCodexOauthTable(name, deps) {
|
|
92560
92811
|
const existing = deps.readTextFile(deps.codexConfigPath);
|
|
92561
92812
|
if (existing === null) return;
|
|
92562
|
-
if (!codexOauthHeaderPattern(
|
|
92563
|
-
if (codexServerEntryPattern(
|
|
92564
|
-
const { content, changed } = unpatchCodexConfigToml(existing,
|
|
92813
|
+
if (!codexOauthHeaderPattern(deps.serverName).test(existing)) return;
|
|
92814
|
+
if (codexServerEntryPattern(deps.serverName).test(existing)) return;
|
|
92815
|
+
const { content, changed } = unpatchCodexConfigToml(existing, deps.serverName);
|
|
92565
92816
|
if (!changed) return;
|
|
92566
92817
|
deps.writeTextFile(deps.codexConfigPath, content);
|
|
92567
92818
|
deps.log(
|
|
@@ -92570,7 +92821,7 @@ function healOrphanCodexOauthTable(name, deps) {
|
|
|
92570
92821
|
}
|
|
92571
92822
|
function connectCodex(bin, name, deps) {
|
|
92572
92823
|
healOrphanCodexOauthTable(name, deps);
|
|
92573
|
-
const probe = parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"]));
|
|
92824
|
+
const probe = parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"]), deps.serverName);
|
|
92574
92825
|
if (probe.broken) {
|
|
92575
92826
|
return failed(probe.detail ?? "probing for the Powerplant MCP failed");
|
|
92576
92827
|
}
|
|
@@ -92597,7 +92848,7 @@ function connectCodex(bin, name, deps) {
|
|
|
92597
92848
|
}
|
|
92598
92849
|
ensureCodexOfficialClient(name, deps);
|
|
92599
92850
|
if (alreadyConnected) return { state: "connected", unchanged: true };
|
|
92600
|
-
return login(bin, name, ["mcp", "login",
|
|
92851
|
+
return login(bin, name, ["mcp", "login", deps.serverName], deps);
|
|
92601
92852
|
}
|
|
92602
92853
|
function applyCodexConfigPatch(name, deps, patch, successLine) {
|
|
92603
92854
|
if (patch.conflict !== void 0) {
|
|
@@ -92629,7 +92880,7 @@ function ensureCodexOfficialClient(name, deps) {
|
|
|
92629
92880
|
deps,
|
|
92630
92881
|
patchCodexConfigToml(
|
|
92631
92882
|
deps.readTextFile(deps.codexConfigPath),
|
|
92632
|
-
|
|
92883
|
+
deps.serverName,
|
|
92633
92884
|
official.clientId,
|
|
92634
92885
|
official.callbackPort
|
|
92635
92886
|
),
|
|
@@ -92640,7 +92891,7 @@ function connectCursor(mcpJsonPath, name, deps) {
|
|
|
92640
92891
|
const official = deps.officialClients?.cursor;
|
|
92641
92892
|
const patch = patchCursorMcpJson(
|
|
92642
92893
|
deps.readTextFile(mcpJsonPath),
|
|
92643
|
-
|
|
92894
|
+
deps.serverName,
|
|
92644
92895
|
deps.mcpUrl,
|
|
92645
92896
|
official?.clientId ?? null
|
|
92646
92897
|
);
|
|
@@ -92651,12 +92902,12 @@ function connectCursor(mcpJsonPath, name, deps) {
|
|
|
92651
92902
|
}
|
|
92652
92903
|
if (patch.changed) deps.writeTextFile(mcpJsonPath, patch.content);
|
|
92653
92904
|
const configured = patch.changed ? "configured" : "already configured";
|
|
92654
|
-
if (deps.openUrl(cursorInstallDeeplink(
|
|
92905
|
+
if (deps.openUrl(cursorInstallDeeplink(deps.serverName, patch.entry))) {
|
|
92655
92906
|
deps.log(`\u2192 ${name} ${configured}, approve inside Cursor when it asks.`);
|
|
92656
92907
|
return { state: "configured", unchanged: !patch.changed };
|
|
92657
92908
|
}
|
|
92658
92909
|
deps.log(
|
|
92659
|
-
`\u2192 ${name} ${configured}, could not open Cursor; in Cursor's MCP settings, enable the
|
|
92910
|
+
`\u2192 ${name} ${configured}, could not open Cursor; in Cursor's MCP settings, enable the ${deps.serverName} server and sign in.`
|
|
92660
92911
|
);
|
|
92661
92912
|
return { state: "pending", unchanged: false };
|
|
92662
92913
|
}
|
|
@@ -92717,7 +92968,7 @@ function disconnectClaude(client, deps) {
|
|
|
92717
92968
|
const { bin } = client;
|
|
92718
92969
|
const name = describeClaudeTarget(client);
|
|
92719
92970
|
const env = claudeEnv(client);
|
|
92720
|
-
const get = deps.run(bin, ["mcp", "get",
|
|
92971
|
+
const get = deps.run(bin, ["mcp", "get", deps.serverName], env);
|
|
92721
92972
|
const output2 = get.stdout + get.stderr;
|
|
92722
92973
|
if (/No MCP server named/i.test(output2)) {
|
|
92723
92974
|
deps.log(`${name}: not connected.`);
|
|
@@ -92727,7 +92978,7 @@ function disconnectClaude(client, deps) {
|
|
|
92727
92978
|
deps.log(`\u2717 ${name}: probing for the Powerplant MCP failed, ${describeFailure(get)}`);
|
|
92728
92979
|
return "failed";
|
|
92729
92980
|
}
|
|
92730
|
-
const remove = deps.run(bin, ["mcp", "remove", "--scope", "user",
|
|
92981
|
+
const remove = deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
|
|
92731
92982
|
if (remove.status !== 0) {
|
|
92732
92983
|
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed, ${describeFailure(remove)}`);
|
|
92733
92984
|
return "failed";
|
|
@@ -92747,15 +92998,15 @@ function disconnectCodex(bin, deps) {
|
|
|
92747
92998
|
deps.log(`\u2717 ${name}: could not read its MCP server list, is this codex version very old?`);
|
|
92748
92999
|
return "failed";
|
|
92749
93000
|
}
|
|
92750
|
-
const registered = servers.some((server) => server.name ===
|
|
92751
|
-
const patch = unpatchCodexConfigToml(deps.readTextFile(deps.codexConfigPath),
|
|
93001
|
+
const registered = servers.some((server) => server.name === deps.serverName);
|
|
93002
|
+
const patch = unpatchCodexConfigToml(deps.readTextFile(deps.codexConfigPath), deps.serverName);
|
|
92752
93003
|
if (patch.changed) deps.writeTextFile(deps.codexConfigPath, patch.content);
|
|
92753
93004
|
if (!registered) {
|
|
92754
93005
|
deps.log(`${name}: not connected.`);
|
|
92755
93006
|
return "notConnected";
|
|
92756
93007
|
}
|
|
92757
|
-
deps.run(bin, ["mcp", "logout",
|
|
92758
|
-
const remove = deps.run(bin, ["mcp", "remove",
|
|
93008
|
+
deps.run(bin, ["mcp", "logout", deps.serverName]);
|
|
93009
|
+
const remove = deps.run(bin, ["mcp", "remove", deps.serverName]);
|
|
92759
93010
|
if (remove.status !== 0) {
|
|
92760
93011
|
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed, ${describeFailure(remove)}`);
|
|
92761
93012
|
return "failed";
|
|
@@ -92765,9 +93016,9 @@ function disconnectCodex(bin, deps) {
|
|
|
92765
93016
|
}
|
|
92766
93017
|
function disconnectCursor(mcpJsonPath, deps) {
|
|
92767
93018
|
const name = `Cursor (${mcpJsonPath.replace(os20.homedir(), "~")})`;
|
|
92768
|
-
const patch = unpatchCursorMcpJson(deps.readTextFile(mcpJsonPath),
|
|
93019
|
+
const patch = unpatchCursorMcpJson(deps.readTextFile(mcpJsonPath), deps.serverName);
|
|
92769
93020
|
if (patch.error !== void 0) {
|
|
92770
|
-
deps.log(`\u2717 ${name}: mcp.json is ${patch.error}, fix it by hand, then re-run
|
|
93021
|
+
deps.log(`\u2717 ${name}: mcp.json is ${patch.error}, fix it by hand, then re-run ${deps.disconnectCommand}.`);
|
|
92771
93022
|
return "failed";
|
|
92772
93023
|
}
|
|
92773
93024
|
if (!patch.changed) {
|
|
@@ -92781,15 +93032,15 @@ function disconnectCursor(mcpJsonPath, deps) {
|
|
|
92781
93032
|
function anyClientStillConnected(clients, deps) {
|
|
92782
93033
|
return clients.some((client) => {
|
|
92783
93034
|
if (client.client === "claude") {
|
|
92784
|
-
const get = deps.run(client.bin, ["mcp", "get",
|
|
93035
|
+
const get = deps.run(client.bin, ["mcp", "get", deps.serverName], claudeEnv(client));
|
|
92785
93036
|
return get.status === 0 && !/No MCP server named/i.test(get.stdout + get.stderr);
|
|
92786
93037
|
}
|
|
92787
93038
|
if (client.client === "codex") {
|
|
92788
93039
|
const list = deps.run(client.bin, ["mcp", "list", "--json"]);
|
|
92789
93040
|
if (list.status !== 0) return false;
|
|
92790
|
-
return parseCodexServers(list.stdout)?.some((server) => server.name ===
|
|
93041
|
+
return parseCodexServers(list.stdout)?.some((server) => server.name === deps.serverName) ?? false;
|
|
92791
93042
|
}
|
|
92792
|
-
const patch = unpatchCursorMcpJson(deps.readTextFile(client.bin),
|
|
93043
|
+
const patch = unpatchCursorMcpJson(deps.readTextFile(client.bin), deps.serverName);
|
|
92793
93044
|
return patch.error === void 0 && patch.changed;
|
|
92794
93045
|
});
|
|
92795
93046
|
}
|
|
@@ -92974,10 +93225,10 @@ function probeClient(client, deps) {
|
|
|
92974
93225
|
return report(
|
|
92975
93226
|
kind,
|
|
92976
93227
|
kind === "claude" ? parseClaudeProbe(
|
|
92977
|
-
deps.run(bin, ["mcp", "get",
|
|
93228
|
+
deps.run(bin, ["mcp", "get", deps.serverName], {
|
|
92978
93229
|
CLAUDE_CONFIG_DIR: client.configDir
|
|
92979
93230
|
})
|
|
92980
|
-
) : parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"])),
|
|
93231
|
+
) : parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"]), deps.serverName),
|
|
92981
93232
|
deps.mcpUrl
|
|
92982
93233
|
);
|
|
92983
93234
|
}
|
|
@@ -93000,7 +93251,7 @@ function probeCursor(mcpJsonPath, deps) {
|
|
|
93000
93251
|
detail: error63 instanceof Error ? error63.message : String(error63)
|
|
93001
93252
|
};
|
|
93002
93253
|
}
|
|
93003
|
-
const registration = readCursorRegistration(raw,
|
|
93254
|
+
const registration = readCursorRegistration(raw, deps.serverName);
|
|
93004
93255
|
if (registration.error !== void 0) {
|
|
93005
93256
|
return { client: "cursor", state: "check-failed", detail: `mcp.json is ${registration.error}` };
|
|
93006
93257
|
}
|
|
@@ -93158,7 +93409,7 @@ import { accessSync, constants as constants2, readFileSync as readFileSync12 } f
|
|
|
93158
93409
|
import path25 from "node:path";
|
|
93159
93410
|
|
|
93160
93411
|
// src/version.ts
|
|
93161
|
-
var CLI_VERSION = true ? "0.4.
|
|
93412
|
+
var CLI_VERSION = true ? "0.4.13" : "0.0.0-checkout";
|
|
93162
93413
|
var CLI_RELEASE_BUILD = true ? true : false;
|
|
93163
93414
|
var CLI_PACKAGE_NAME = "@usepowerplant/cli";
|
|
93164
93415
|
|
|
@@ -93278,7 +93529,13 @@ function realInspectEnvironment() {
|
|
|
93278
93529
|
|
|
93279
93530
|
// src/update.ts
|
|
93280
93531
|
var updateProgressSchema = external_exports.object({
|
|
93281
|
-
|
|
93532
|
+
/** "up-to-date": the last run installed nothing, because this build is
|
|
93533
|
+
* already at or past the release. That record is kept only so the menu
|
|
93534
|
+
* bar app that started the run can stop showing "Updating CLI…"
|
|
93535
|
+
* (menu.ts cliUpToDateAt); to every other reader it is no update at all.
|
|
93536
|
+
* A CLI from before this state rejects the record, which it reads as no
|
|
93537
|
+
* record. */
|
|
93538
|
+
state: external_exports.enum(["installing", "failed", "up-to-date"]),
|
|
93282
93539
|
/** The release aimed at; null when the registry couldn't be asked (its latest). */
|
|
93283
93540
|
target: external_exports.string().nullable(),
|
|
93284
93541
|
startedAt: external_exports.string(),
|
|
@@ -93318,7 +93575,7 @@ function readUpdateProgress(readTextFile, file2 = updateProgressPath()) {
|
|
|
93318
93575
|
}
|
|
93319
93576
|
}
|
|
93320
93577
|
function updateProgressView(progress, cliVersion2, now) {
|
|
93321
|
-
if (progress === null) return { kind: "none" };
|
|
93578
|
+
if (progress === null || progress.state === "up-to-date") return { kind: "none" };
|
|
93322
93579
|
const reached = progress.target === null ? null : compareReleaseVersions(cliVersion2, progress.target);
|
|
93323
93580
|
if (reached === 0 || reached === 1) return { kind: "none" };
|
|
93324
93581
|
if (progress.state === "failed") {
|
|
@@ -93351,13 +93608,29 @@ async function runUpdate(deps) {
|
|
|
93351
93608
|
const reserved = running?.state === "installing" ? running.target : null;
|
|
93352
93609
|
const attempts = (release2) => running?.target === release2 && running.attempts !== void 0 ? { attempts: running.attempts } : {};
|
|
93353
93610
|
deps.writeProgress({ state: "installing", target: reserved, startedAt, pid: deps.pid, ...attempts(reserved) });
|
|
93354
|
-
const
|
|
93611
|
+
const resolved = await deps.resolveTarget();
|
|
93612
|
+
if (resolved !== null) deps.recordAvailableVersion(resolved);
|
|
93613
|
+
const target = resolved ?? reserved;
|
|
93355
93614
|
if (target === null && deps.targetRequired) {
|
|
93356
93615
|
deps.clearProgress();
|
|
93357
93616
|
throw new ExpectedCliError(
|
|
93358
93617
|
"No release is promoted for production right now (or the API couldn't be reached), so there is nothing to update to. Production machines only install the promoted release."
|
|
93359
93618
|
);
|
|
93360
93619
|
}
|
|
93620
|
+
const reached = target === null ? null : compareReleaseVersions(deps.cliVersion, target);
|
|
93621
|
+
if (reached === 0 || reached === 1) {
|
|
93622
|
+
deps.writeProgress({
|
|
93623
|
+
state: "up-to-date",
|
|
93624
|
+
target,
|
|
93625
|
+
startedAt,
|
|
93626
|
+
pid: deps.pid,
|
|
93627
|
+
finishedAt: new Date(deps.now()).toISOString()
|
|
93628
|
+
});
|
|
93629
|
+
deps.log(
|
|
93630
|
+
reached === 0 ? `Already up to date (v${deps.cliVersion}).` : `Already on v${deps.cliVersion}, newer than the available release (v${target}). Nothing was installed.`
|
|
93631
|
+
);
|
|
93632
|
+
return;
|
|
93633
|
+
}
|
|
93361
93634
|
deps.writeProgress({ state: "installing", target, startedAt, pid: deps.pid, ...attempts(target) });
|
|
93362
93635
|
const { bin, args } = updateCommand(manager, target, inspection.prefix, deps.channel);
|
|
93363
93636
|
deps.log(`Updating ${CLI_PACKAGE_NAME}${target === null ? "" : ` to ${target}`} via ${manager}\u2026`);
|
|
@@ -94202,6 +94475,7 @@ function renderMenu(i) {
|
|
|
94202
94475
|
logPath: updateLogPath()
|
|
94203
94476
|
}
|
|
94204
94477
|
},
|
|
94478
|
+
...i.update.progress?.state === "up-to-date" && { cliUpToDateAt: i.update.progress.finishedAt },
|
|
94205
94479
|
...i.desktopDiagnostic && { desktopDiagnostic: i.desktopDiagnostic },
|
|
94206
94480
|
appEnv: i.config.appEnv,
|
|
94207
94481
|
cliVersion: i.cliVersion,
|
|
@@ -94505,14 +94779,17 @@ async function cachedLatestVersion(options) {
|
|
|
94505
94779
|
}
|
|
94506
94780
|
}
|
|
94507
94781
|
const version2 = await options.fetchLatest();
|
|
94782
|
+
writeVersionCache({ ...options, version: version2 });
|
|
94783
|
+
return version2;
|
|
94784
|
+
}
|
|
94785
|
+
function writeVersionCache(options) {
|
|
94508
94786
|
try {
|
|
94509
94787
|
options.writeTextFile(
|
|
94510
94788
|
options.cacheFile,
|
|
94511
|
-
JSON.stringify({ checkedAt: new Date(options.now).toISOString(), version:
|
|
94789
|
+
JSON.stringify({ checkedAt: new Date(options.now).toISOString(), version: options.version })
|
|
94512
94790
|
);
|
|
94513
94791
|
} catch {
|
|
94514
94792
|
}
|
|
94515
|
-
return version2;
|
|
94516
94793
|
}
|
|
94517
94794
|
|
|
94518
94795
|
// src/liveTerminalSessions.ts
|
|
@@ -95569,6 +95846,7 @@ ${USAGE}`);
|
|
|
95569
95846
|
log: log3
|
|
95570
95847
|
});
|
|
95571
95848
|
const connectCommand = withEnv("powerplant connect");
|
|
95849
|
+
const disconnectCommand = withEnv("powerplant disconnect");
|
|
95572
95850
|
const clientFilter = parseClientFilter(values.client);
|
|
95573
95851
|
const pickerOn = pickerAllowed({
|
|
95574
95852
|
yes: values.yes,
|
|
@@ -95618,6 +95896,7 @@ ${USAGE}`);
|
|
|
95618
95896
|
}
|
|
95619
95897
|
const outcome = runConnect(clients, {
|
|
95620
95898
|
mcpUrl: `${config2.apiUrl}/mcp`,
|
|
95899
|
+
serverName: mcpServerNameFor(config2.appEnv),
|
|
95621
95900
|
connectCommand,
|
|
95622
95901
|
officialClients: await fetchOfficialClients(config2.apiUrl, log3),
|
|
95623
95902
|
log: log3,
|
|
@@ -95705,6 +95984,8 @@ ${USAGE}`);
|
|
|
95705
95984
|
}
|
|
95706
95985
|
const outcome = runDisconnect(clients, {
|
|
95707
95986
|
log: console.log,
|
|
95987
|
+
serverName: mcpServerNameFor(config2.appEnv),
|
|
95988
|
+
disconnectCommand,
|
|
95708
95989
|
run: realRun,
|
|
95709
95990
|
readTextFile: realReadTextFileStrict,
|
|
95710
95991
|
writeTextFile: realWriteTextFile,
|
|
@@ -95837,6 +96118,7 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
95837
96118
|
oldestSupportedVersion,
|
|
95838
96119
|
connections: probeConnections(clients, {
|
|
95839
96120
|
mcpUrl: `${config2.apiUrl}/mcp`,
|
|
96121
|
+
serverName: mcpServerNameFor(config2.appEnv),
|
|
95840
96122
|
run: runWithPath(probePath, budget),
|
|
95841
96123
|
readTextFile: realReadTextFileStrict,
|
|
95842
96124
|
grantedClientIds
|
|
@@ -95886,7 +96168,14 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
95886
96168
|
}
|
|
95887
96169
|
await runUpdate({
|
|
95888
96170
|
inspection,
|
|
96171
|
+
cliVersion: CLI_VERSION,
|
|
95889
96172
|
resolveTarget: () => fetchAvailableVersion(config2, loadCredentialsSafely(config2).credentials),
|
|
96173
|
+
recordAvailableVersion: (version2) => writeVersionCache({
|
|
96174
|
+
now: Date.now(),
|
|
96175
|
+
cacheFile: versionCachePath(void 0, releaseSource(config2.appEnv)),
|
|
96176
|
+
writeTextFile: realWriteTextFile,
|
|
96177
|
+
version: version2
|
|
96178
|
+
}),
|
|
95890
96179
|
channel: releaseSource(config2.appEnv) === "npm" ? "next" : "latest",
|
|
95891
96180
|
targetRequired: releaseSource(config2.appEnv) === "promoted",
|
|
95892
96181
|
claimsReservation: process.env[UPDATE_CHILD_ENV] === "1",
|
|
@@ -95984,9 +96273,13 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
95984
96273
|
"Credentials kept, `powerplant init` re-installs without re-enrolling. (--forget deletes them.)"
|
|
95985
96274
|
);
|
|
95986
96275
|
}
|
|
95987
|
-
if (anyClientStillConnected(detectClients(), {
|
|
96276
|
+
if (anyClientStillConnected(detectClients(), {
|
|
96277
|
+
run: realRun,
|
|
96278
|
+
readTextFile: realReadTextFile,
|
|
96279
|
+
serverName: mcpServerNameFor(config2.appEnv)
|
|
96280
|
+
})) {
|
|
95988
96281
|
console.log(
|
|
95989
|
-
|
|
96282
|
+
`Your coding agents are still connected to the Powerplant MCP server, remove those connections with: ${disconnectCommand}`
|
|
95990
96283
|
);
|
|
95991
96284
|
}
|
|
95992
96285
|
return;
|
|
@@ -96168,3 +96461,5 @@ undici/lib/web/fetch/body.js:
|
|
|
96168
96461
|
undici/lib/web/websocket/frame.js:
|
|
96169
96462
|
(*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
|
|
96170
96463
|
*/
|
|
96464
|
+
|
|
96465
|
+
//# debugId=66f773d5-e0b2-5538-a184-3ee15c3a469a
|