@usepowerplant/cli 0.4.11 → 0.4.12
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 +6 -5
- package/dist/cli.js +319 -88
- package/dist/menubar/Powerplant.app.zip +0 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -226,11 +226,12 @@ npm install -g --prefix ~/.powerplant-staging @usepowerplant/cli@next
|
|
|
226
226
|
~/.powerplant-staging/bin/powerplant init --env staging
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
-
`init --env staging`
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
`init --env staging` registers its own MCP entry, `powerplant-staging`, in each
|
|
230
|
+
selected agent, beside the production `powerplant` entry. Agents see its tools
|
|
231
|
+
as `mcp__powerplant-staging__*`. A CLI older than this change registered
|
|
232
|
+
staging as `powerplant`: if that entry still points at staging, run a bare
|
|
233
|
+
`powerplant connect` from your production install once to restore it. Include
|
|
234
|
+
`--env staging` on every staging command.
|
|
234
235
|
|
|
235
236
|
The `@next` pin matters: a bare install resolves `latest`, the production
|
|
236
237
|
channel, so the new staging copy would start on the promoted release and
|
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]="7d73a97a-938c-5f0f-8b6b-c4076b82abad")}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]));
|
|
@@ -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.12" : "0.0.0-checkout";
|
|
85734
85954
|
function cliVersionHeaders() {
|
|
85735
85955
|
return { [CLI_VERSION_HEADER]: cliVersion, "user-agent": `powerplant-cli/${cliVersion}` };
|
|
85736
85956
|
}
|
|
@@ -86575,9 +86795,9 @@ var MergedSpoolWriter = class {
|
|
|
86575
86795
|
tmpPath;
|
|
86576
86796
|
fd;
|
|
86577
86797
|
bytes = 0;
|
|
86578
|
-
append(
|
|
86798
|
+
append(pageText2) {
|
|
86579
86799
|
if (this.fd === void 0) throw new Error("merged transcript already closed");
|
|
86580
|
-
const text =
|
|
86800
|
+
const text = pageText2.endsWith("\n") ? pageText2 : `${pageText2}
|
|
86581
86801
|
`;
|
|
86582
86802
|
this.bytes += writeSync(this.fd, text);
|
|
86583
86803
|
}
|
|
@@ -91861,7 +92081,7 @@ function belowVersionFloor(client, versionText) {
|
|
|
91861
92081
|
}
|
|
91862
92082
|
|
|
91863
92083
|
// src/connect.ts
|
|
91864
|
-
var
|
|
92084
|
+
var mcpServerNameFor = (appEnv) => appEnv === "production" ? "powerplant" : `powerplant-${appEnv}`;
|
|
91865
92085
|
var AGENT_DISPLAY_NAMES = {
|
|
91866
92086
|
claude: "Claude Code",
|
|
91867
92087
|
codex: "Codex",
|
|
@@ -92298,7 +92518,7 @@ function realCheckboxPrompt(question, choices, seams = {}) {
|
|
|
92298
92518
|
function claudeAddArgs(deps) {
|
|
92299
92519
|
const official = deps.officialClients?.["claude-code"];
|
|
92300
92520
|
const credentialArgs = official ? ["--client-id", official.clientId, "--callback-port", String(official.callbackPort)] : [];
|
|
92301
|
-
return ["mcp", "add", "--transport", "http", "--scope", "user", ...credentialArgs,
|
|
92521
|
+
return ["mcp", "add", "--transport", "http", "--scope", "user", ...credentialArgs, deps.serverName, deps.mcpUrl];
|
|
92302
92522
|
}
|
|
92303
92523
|
function parseClaudeProbe(result) {
|
|
92304
92524
|
const output2 = result.stdout + result.stderr;
|
|
@@ -92319,7 +92539,7 @@ function claudeEnv(client) {
|
|
|
92319
92539
|
function connectClaude(client, name, deps) {
|
|
92320
92540
|
const { bin } = client;
|
|
92321
92541
|
const env = claudeEnv(client);
|
|
92322
|
-
const probe = parseClaudeProbe(deps.run(bin, ["mcp", "get",
|
|
92542
|
+
const probe = parseClaudeProbe(deps.run(bin, ["mcp", "get", deps.serverName], env));
|
|
92323
92543
|
if (probe.broken) {
|
|
92324
92544
|
return failed(`probing for the Powerplant MCP failed, ${probe.detail}`);
|
|
92325
92545
|
}
|
|
@@ -92327,7 +92547,7 @@ function connectClaude(client, name, deps) {
|
|
|
92327
92547
|
if (missing || registeredUrl !== void 0 && registeredUrl !== deps.mcpUrl) {
|
|
92328
92548
|
if (!missing) {
|
|
92329
92549
|
deps.log(`${name}: registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
|
|
92330
|
-
deps.run(bin, ["mcp", "remove", "--scope", "user",
|
|
92550
|
+
deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
|
|
92331
92551
|
}
|
|
92332
92552
|
const add = deps.run(bin, claudeAddArgs(deps), env);
|
|
92333
92553
|
if (add.status !== 0) {
|
|
@@ -92339,7 +92559,7 @@ function connectClaude(client, name, deps) {
|
|
|
92339
92559
|
return { state: "connected", unchanged: true };
|
|
92340
92560
|
} else if (deps.officialClients?.["claude-code"]) {
|
|
92341
92561
|
deps.log(`${name}: re-registering with the pre-registered client before sign-in.`);
|
|
92342
|
-
deps.run(bin, ["mcp", "remove", "--scope", "user",
|
|
92562
|
+
deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
|
|
92343
92563
|
const add = deps.run(bin, claudeAddArgs(deps), env);
|
|
92344
92564
|
if (add.status !== 0) {
|
|
92345
92565
|
return failed(`registering the Powerplant MCP failed, ${describeFailure(add)}`);
|
|
@@ -92347,7 +92567,7 @@ function connectClaude(client, name, deps) {
|
|
|
92347
92567
|
} else {
|
|
92348
92568
|
deps.log(`${name}: Powerplant MCP already registered.`);
|
|
92349
92569
|
}
|
|
92350
|
-
return login(bin, name, ["mcp", "login",
|
|
92570
|
+
return login(bin, name, ["mcp", "login", deps.serverName], deps, env);
|
|
92351
92571
|
}
|
|
92352
92572
|
function codexOauthHeaderPattern(serverName) {
|
|
92353
92573
|
return new RegExp(
|
|
@@ -92514,7 +92734,7 @@ function parseCodexServers(stdout) {
|
|
|
92514
92734
|
}
|
|
92515
92735
|
}
|
|
92516
92736
|
var CODEX_AUTHENTICATED_STATUSES = /* @__PURE__ */ new Set(["o_auth", "bearer_token"]);
|
|
92517
|
-
function parseCodexProbe(result) {
|
|
92737
|
+
function parseCodexProbe(result, serverName) {
|
|
92518
92738
|
if (result.status !== 0) {
|
|
92519
92739
|
return {
|
|
92520
92740
|
broken: true,
|
|
@@ -92532,7 +92752,7 @@ function parseCodexProbe(result) {
|
|
|
92532
92752
|
authenticated: false
|
|
92533
92753
|
};
|
|
92534
92754
|
}
|
|
92535
|
-
const existing = servers.find((server) => server.name ===
|
|
92755
|
+
const existing = servers.find((server) => server.name === serverName);
|
|
92536
92756
|
if (!existing) return { broken: false, missing: true, authenticated: false };
|
|
92537
92757
|
return {
|
|
92538
92758
|
broken: false,
|
|
@@ -92544,7 +92764,7 @@ function parseCodexProbe(result) {
|
|
|
92544
92764
|
function codexAddArgs(deps, options) {
|
|
92545
92765
|
const official = deps.officialClients?.codex;
|
|
92546
92766
|
const credentialArgs = options.withOfficialClientId && official ? ["--oauth-client-id", official.clientId] : [];
|
|
92547
|
-
return ["mcp", "add",
|
|
92767
|
+
return ["mcp", "add", deps.serverName, ...credentialArgs, "--url", deps.mcpUrl];
|
|
92548
92768
|
}
|
|
92549
92769
|
function codexAddLogsIn(bin, deps) {
|
|
92550
92770
|
const help = deps.run(bin, ["mcp", "add", "--help"]);
|
|
@@ -92559,9 +92779,9 @@ function codexServerEntryPattern(serverName) {
|
|
|
92559
92779
|
function healOrphanCodexOauthTable(name, deps) {
|
|
92560
92780
|
const existing = deps.readTextFile(deps.codexConfigPath);
|
|
92561
92781
|
if (existing === null) return;
|
|
92562
|
-
if (!codexOauthHeaderPattern(
|
|
92563
|
-
if (codexServerEntryPattern(
|
|
92564
|
-
const { content, changed } = unpatchCodexConfigToml(existing,
|
|
92782
|
+
if (!codexOauthHeaderPattern(deps.serverName).test(existing)) return;
|
|
92783
|
+
if (codexServerEntryPattern(deps.serverName).test(existing)) return;
|
|
92784
|
+
const { content, changed } = unpatchCodexConfigToml(existing, deps.serverName);
|
|
92565
92785
|
if (!changed) return;
|
|
92566
92786
|
deps.writeTextFile(deps.codexConfigPath, content);
|
|
92567
92787
|
deps.log(
|
|
@@ -92570,7 +92790,7 @@ function healOrphanCodexOauthTable(name, deps) {
|
|
|
92570
92790
|
}
|
|
92571
92791
|
function connectCodex(bin, name, deps) {
|
|
92572
92792
|
healOrphanCodexOauthTable(name, deps);
|
|
92573
|
-
const probe = parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"]));
|
|
92793
|
+
const probe = parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"]), deps.serverName);
|
|
92574
92794
|
if (probe.broken) {
|
|
92575
92795
|
return failed(probe.detail ?? "probing for the Powerplant MCP failed");
|
|
92576
92796
|
}
|
|
@@ -92597,7 +92817,7 @@ function connectCodex(bin, name, deps) {
|
|
|
92597
92817
|
}
|
|
92598
92818
|
ensureCodexOfficialClient(name, deps);
|
|
92599
92819
|
if (alreadyConnected) return { state: "connected", unchanged: true };
|
|
92600
|
-
return login(bin, name, ["mcp", "login",
|
|
92820
|
+
return login(bin, name, ["mcp", "login", deps.serverName], deps);
|
|
92601
92821
|
}
|
|
92602
92822
|
function applyCodexConfigPatch(name, deps, patch, successLine) {
|
|
92603
92823
|
if (patch.conflict !== void 0) {
|
|
@@ -92629,7 +92849,7 @@ function ensureCodexOfficialClient(name, deps) {
|
|
|
92629
92849
|
deps,
|
|
92630
92850
|
patchCodexConfigToml(
|
|
92631
92851
|
deps.readTextFile(deps.codexConfigPath),
|
|
92632
|
-
|
|
92852
|
+
deps.serverName,
|
|
92633
92853
|
official.clientId,
|
|
92634
92854
|
official.callbackPort
|
|
92635
92855
|
),
|
|
@@ -92640,7 +92860,7 @@ function connectCursor(mcpJsonPath, name, deps) {
|
|
|
92640
92860
|
const official = deps.officialClients?.cursor;
|
|
92641
92861
|
const patch = patchCursorMcpJson(
|
|
92642
92862
|
deps.readTextFile(mcpJsonPath),
|
|
92643
|
-
|
|
92863
|
+
deps.serverName,
|
|
92644
92864
|
deps.mcpUrl,
|
|
92645
92865
|
official?.clientId ?? null
|
|
92646
92866
|
);
|
|
@@ -92651,12 +92871,12 @@ function connectCursor(mcpJsonPath, name, deps) {
|
|
|
92651
92871
|
}
|
|
92652
92872
|
if (patch.changed) deps.writeTextFile(mcpJsonPath, patch.content);
|
|
92653
92873
|
const configured = patch.changed ? "configured" : "already configured";
|
|
92654
|
-
if (deps.openUrl(cursorInstallDeeplink(
|
|
92874
|
+
if (deps.openUrl(cursorInstallDeeplink(deps.serverName, patch.entry))) {
|
|
92655
92875
|
deps.log(`\u2192 ${name} ${configured}, approve inside Cursor when it asks.`);
|
|
92656
92876
|
return { state: "configured", unchanged: !patch.changed };
|
|
92657
92877
|
}
|
|
92658
92878
|
deps.log(
|
|
92659
|
-
`\u2192 ${name} ${configured}, could not open Cursor; in Cursor's MCP settings, enable the
|
|
92879
|
+
`\u2192 ${name} ${configured}, could not open Cursor; in Cursor's MCP settings, enable the ${deps.serverName} server and sign in.`
|
|
92660
92880
|
);
|
|
92661
92881
|
return { state: "pending", unchanged: false };
|
|
92662
92882
|
}
|
|
@@ -92717,7 +92937,7 @@ function disconnectClaude(client, deps) {
|
|
|
92717
92937
|
const { bin } = client;
|
|
92718
92938
|
const name = describeClaudeTarget(client);
|
|
92719
92939
|
const env = claudeEnv(client);
|
|
92720
|
-
const get = deps.run(bin, ["mcp", "get",
|
|
92940
|
+
const get = deps.run(bin, ["mcp", "get", deps.serverName], env);
|
|
92721
92941
|
const output2 = get.stdout + get.stderr;
|
|
92722
92942
|
if (/No MCP server named/i.test(output2)) {
|
|
92723
92943
|
deps.log(`${name}: not connected.`);
|
|
@@ -92727,7 +92947,7 @@ function disconnectClaude(client, deps) {
|
|
|
92727
92947
|
deps.log(`\u2717 ${name}: probing for the Powerplant MCP failed, ${describeFailure(get)}`);
|
|
92728
92948
|
return "failed";
|
|
92729
92949
|
}
|
|
92730
|
-
const remove = deps.run(bin, ["mcp", "remove", "--scope", "user",
|
|
92950
|
+
const remove = deps.run(bin, ["mcp", "remove", "--scope", "user", deps.serverName], env);
|
|
92731
92951
|
if (remove.status !== 0) {
|
|
92732
92952
|
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed, ${describeFailure(remove)}`);
|
|
92733
92953
|
return "failed";
|
|
@@ -92747,15 +92967,15 @@ function disconnectCodex(bin, deps) {
|
|
|
92747
92967
|
deps.log(`\u2717 ${name}: could not read its MCP server list, is this codex version very old?`);
|
|
92748
92968
|
return "failed";
|
|
92749
92969
|
}
|
|
92750
|
-
const registered = servers.some((server) => server.name ===
|
|
92751
|
-
const patch = unpatchCodexConfigToml(deps.readTextFile(deps.codexConfigPath),
|
|
92970
|
+
const registered = servers.some((server) => server.name === deps.serverName);
|
|
92971
|
+
const patch = unpatchCodexConfigToml(deps.readTextFile(deps.codexConfigPath), deps.serverName);
|
|
92752
92972
|
if (patch.changed) deps.writeTextFile(deps.codexConfigPath, patch.content);
|
|
92753
92973
|
if (!registered) {
|
|
92754
92974
|
deps.log(`${name}: not connected.`);
|
|
92755
92975
|
return "notConnected";
|
|
92756
92976
|
}
|
|
92757
|
-
deps.run(bin, ["mcp", "logout",
|
|
92758
|
-
const remove = deps.run(bin, ["mcp", "remove",
|
|
92977
|
+
deps.run(bin, ["mcp", "logout", deps.serverName]);
|
|
92978
|
+
const remove = deps.run(bin, ["mcp", "remove", deps.serverName]);
|
|
92759
92979
|
if (remove.status !== 0) {
|
|
92760
92980
|
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed, ${describeFailure(remove)}`);
|
|
92761
92981
|
return "failed";
|
|
@@ -92765,9 +92985,9 @@ function disconnectCodex(bin, deps) {
|
|
|
92765
92985
|
}
|
|
92766
92986
|
function disconnectCursor(mcpJsonPath, deps) {
|
|
92767
92987
|
const name = `Cursor (${mcpJsonPath.replace(os20.homedir(), "~")})`;
|
|
92768
|
-
const patch = unpatchCursorMcpJson(deps.readTextFile(mcpJsonPath),
|
|
92988
|
+
const patch = unpatchCursorMcpJson(deps.readTextFile(mcpJsonPath), deps.serverName);
|
|
92769
92989
|
if (patch.error !== void 0) {
|
|
92770
|
-
deps.log(`\u2717 ${name}: mcp.json is ${patch.error}, fix it by hand, then re-run
|
|
92990
|
+
deps.log(`\u2717 ${name}: mcp.json is ${patch.error}, fix it by hand, then re-run ${deps.disconnectCommand}.`);
|
|
92771
92991
|
return "failed";
|
|
92772
92992
|
}
|
|
92773
92993
|
if (!patch.changed) {
|
|
@@ -92781,15 +93001,15 @@ function disconnectCursor(mcpJsonPath, deps) {
|
|
|
92781
93001
|
function anyClientStillConnected(clients, deps) {
|
|
92782
93002
|
return clients.some((client) => {
|
|
92783
93003
|
if (client.client === "claude") {
|
|
92784
|
-
const get = deps.run(client.bin, ["mcp", "get",
|
|
93004
|
+
const get = deps.run(client.bin, ["mcp", "get", deps.serverName], claudeEnv(client));
|
|
92785
93005
|
return get.status === 0 && !/No MCP server named/i.test(get.stdout + get.stderr);
|
|
92786
93006
|
}
|
|
92787
93007
|
if (client.client === "codex") {
|
|
92788
93008
|
const list = deps.run(client.bin, ["mcp", "list", "--json"]);
|
|
92789
93009
|
if (list.status !== 0) return false;
|
|
92790
|
-
return parseCodexServers(list.stdout)?.some((server) => server.name ===
|
|
93010
|
+
return parseCodexServers(list.stdout)?.some((server) => server.name === deps.serverName) ?? false;
|
|
92791
93011
|
}
|
|
92792
|
-
const patch = unpatchCursorMcpJson(deps.readTextFile(client.bin),
|
|
93012
|
+
const patch = unpatchCursorMcpJson(deps.readTextFile(client.bin), deps.serverName);
|
|
92793
93013
|
return patch.error === void 0 && patch.changed;
|
|
92794
93014
|
});
|
|
92795
93015
|
}
|
|
@@ -92974,10 +93194,10 @@ function probeClient(client, deps) {
|
|
|
92974
93194
|
return report(
|
|
92975
93195
|
kind,
|
|
92976
93196
|
kind === "claude" ? parseClaudeProbe(
|
|
92977
|
-
deps.run(bin, ["mcp", "get",
|
|
93197
|
+
deps.run(bin, ["mcp", "get", deps.serverName], {
|
|
92978
93198
|
CLAUDE_CONFIG_DIR: client.configDir
|
|
92979
93199
|
})
|
|
92980
|
-
) : parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"])),
|
|
93200
|
+
) : parseCodexProbe(deps.run(bin, ["mcp", "list", "--json"]), deps.serverName),
|
|
92981
93201
|
deps.mcpUrl
|
|
92982
93202
|
);
|
|
92983
93203
|
}
|
|
@@ -93000,7 +93220,7 @@ function probeCursor(mcpJsonPath, deps) {
|
|
|
93000
93220
|
detail: error63 instanceof Error ? error63.message : String(error63)
|
|
93001
93221
|
};
|
|
93002
93222
|
}
|
|
93003
|
-
const registration = readCursorRegistration(raw,
|
|
93223
|
+
const registration = readCursorRegistration(raw, deps.serverName);
|
|
93004
93224
|
if (registration.error !== void 0) {
|
|
93005
93225
|
return { client: "cursor", state: "check-failed", detail: `mcp.json is ${registration.error}` };
|
|
93006
93226
|
}
|
|
@@ -93158,7 +93378,7 @@ import { accessSync, constants as constants2, readFileSync as readFileSync12 } f
|
|
|
93158
93378
|
import path25 from "node:path";
|
|
93159
93379
|
|
|
93160
93380
|
// src/version.ts
|
|
93161
|
-
var CLI_VERSION = true ? "0.4.
|
|
93381
|
+
var CLI_VERSION = true ? "0.4.12" : "0.0.0-checkout";
|
|
93162
93382
|
var CLI_RELEASE_BUILD = true ? true : false;
|
|
93163
93383
|
var CLI_PACKAGE_NAME = "@usepowerplant/cli";
|
|
93164
93384
|
|
|
@@ -95569,6 +95789,7 @@ ${USAGE}`);
|
|
|
95569
95789
|
log: log3
|
|
95570
95790
|
});
|
|
95571
95791
|
const connectCommand = withEnv("powerplant connect");
|
|
95792
|
+
const disconnectCommand = withEnv("powerplant disconnect");
|
|
95572
95793
|
const clientFilter = parseClientFilter(values.client);
|
|
95573
95794
|
const pickerOn = pickerAllowed({
|
|
95574
95795
|
yes: values.yes,
|
|
@@ -95618,6 +95839,7 @@ ${USAGE}`);
|
|
|
95618
95839
|
}
|
|
95619
95840
|
const outcome = runConnect(clients, {
|
|
95620
95841
|
mcpUrl: `${config2.apiUrl}/mcp`,
|
|
95842
|
+
serverName: mcpServerNameFor(config2.appEnv),
|
|
95621
95843
|
connectCommand,
|
|
95622
95844
|
officialClients: await fetchOfficialClients(config2.apiUrl, log3),
|
|
95623
95845
|
log: log3,
|
|
@@ -95705,6 +95927,8 @@ ${USAGE}`);
|
|
|
95705
95927
|
}
|
|
95706
95928
|
const outcome = runDisconnect(clients, {
|
|
95707
95929
|
log: console.log,
|
|
95930
|
+
serverName: mcpServerNameFor(config2.appEnv),
|
|
95931
|
+
disconnectCommand,
|
|
95708
95932
|
run: realRun,
|
|
95709
95933
|
readTextFile: realReadTextFileStrict,
|
|
95710
95934
|
writeTextFile: realWriteTextFile,
|
|
@@ -95837,6 +96061,7 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
95837
96061
|
oldestSupportedVersion,
|
|
95838
96062
|
connections: probeConnections(clients, {
|
|
95839
96063
|
mcpUrl: `${config2.apiUrl}/mcp`,
|
|
96064
|
+
serverName: mcpServerNameFor(config2.appEnv),
|
|
95840
96065
|
run: runWithPath(probePath, budget),
|
|
95841
96066
|
readTextFile: realReadTextFileStrict,
|
|
95842
96067
|
grantedClientIds
|
|
@@ -95984,9 +96209,13 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
95984
96209
|
"Credentials kept, `powerplant init` re-installs without re-enrolling. (--forget deletes them.)"
|
|
95985
96210
|
);
|
|
95986
96211
|
}
|
|
95987
|
-
if (anyClientStillConnected(detectClients(), {
|
|
96212
|
+
if (anyClientStillConnected(detectClients(), {
|
|
96213
|
+
run: realRun,
|
|
96214
|
+
readTextFile: realReadTextFile,
|
|
96215
|
+
serverName: mcpServerNameFor(config2.appEnv)
|
|
96216
|
+
})) {
|
|
95988
96217
|
console.log(
|
|
95989
|
-
|
|
96218
|
+
`Your coding agents are still connected to the Powerplant MCP server, remove those connections with: ${disconnectCommand}`
|
|
95990
96219
|
);
|
|
95991
96220
|
}
|
|
95992
96221
|
return;
|
|
@@ -96168,3 +96397,5 @@ undici/lib/web/fetch/body.js:
|
|
|
96168
96397
|
undici/lib/web/websocket/frame.js:
|
|
96169
96398
|
(*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
|
|
96170
96399
|
*/
|
|
96400
|
+
|
|
96401
|
+
//# debugId=7d73a97a-938c-5f0f-8b6b-c4076b82abad
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usepowerplant/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"powerplant": "dist/cli.js"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"!dist/**/*.map"
|
|
19
20
|
],
|
|
20
21
|
"engines": {
|
|
21
22
|
"node": ">=20"
|