@usepowerplant/cli 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +961 -882
- package/package.json +1 -1
- package/dist/hooks/powerplant-inbox.mjs +0 -147
package/dist/cli.js
CHANGED
|
@@ -6877,19 +6877,19 @@ var require_module_details_from_path = __commonJS({
|
|
|
6877
6877
|
basedir += segments[i] + sep2;
|
|
6878
6878
|
}
|
|
6879
6879
|
}
|
|
6880
|
-
var
|
|
6880
|
+
var path18 = "";
|
|
6881
6881
|
var lastSegmentIndex = segments.length - 1;
|
|
6882
6882
|
for (var i2 = index + offset; i2 <= lastSegmentIndex; i2++) {
|
|
6883
6883
|
if (i2 === lastSegmentIndex) {
|
|
6884
|
-
|
|
6884
|
+
path18 += segments[i2];
|
|
6885
6885
|
} else {
|
|
6886
|
-
|
|
6886
|
+
path18 += segments[i2] + sep2;
|
|
6887
6887
|
}
|
|
6888
6888
|
}
|
|
6889
6889
|
return {
|
|
6890
6890
|
name,
|
|
6891
6891
|
basedir,
|
|
6892
|
-
path:
|
|
6892
|
+
path: path18
|
|
6893
6893
|
};
|
|
6894
6894
|
};
|
|
6895
6895
|
}
|
|
@@ -6899,7 +6899,7 @@ var require_module_details_from_path = __commonJS({
|
|
|
6899
6899
|
var require_require_in_the_middle = __commonJS({
|
|
6900
6900
|
"../../node_modules/.pnpm/require-in-the-middle@8.0.1/node_modules/require-in-the-middle/index.js"(exports, module2) {
|
|
6901
6901
|
"use strict";
|
|
6902
|
-
var
|
|
6902
|
+
var path18 = __require("path");
|
|
6903
6903
|
var Module = __require("module");
|
|
6904
6904
|
var debug2 = require_src3()("require-in-the-middle");
|
|
6905
6905
|
var moduleDetailsFromPath = require_module_details_from_path();
|
|
@@ -7044,7 +7044,7 @@ var require_require_in_the_middle = __commonJS({
|
|
|
7044
7044
|
}
|
|
7045
7045
|
moduleName = filename;
|
|
7046
7046
|
} else if (hasWhitelist === true && modules.includes(filename)) {
|
|
7047
|
-
const parsedPath =
|
|
7047
|
+
const parsedPath = path18.parse(filename);
|
|
7048
7048
|
moduleName = parsedPath.name;
|
|
7049
7049
|
basedir = parsedPath.dir;
|
|
7050
7050
|
} else {
|
|
@@ -7082,7 +7082,7 @@ var require_require_in_the_middle = __commonJS({
|
|
|
7082
7082
|
}
|
|
7083
7083
|
if (res !== filename) {
|
|
7084
7084
|
if (internals === true) {
|
|
7085
|
-
moduleName = moduleName +
|
|
7085
|
+
moduleName = moduleName + path18.sep + path18.relative(basedir, filename);
|
|
7086
7086
|
debug2("preparing to process require of internal file: %s", moduleName);
|
|
7087
7087
|
} else {
|
|
7088
7088
|
debug2("ignoring require of non-main module file: %s", res);
|
|
@@ -7118,8 +7118,8 @@ var require_require_in_the_middle = __commonJS({
|
|
|
7118
7118
|
}
|
|
7119
7119
|
};
|
|
7120
7120
|
function resolveModuleName(stat) {
|
|
7121
|
-
const normalizedPath =
|
|
7122
|
-
return
|
|
7121
|
+
const normalizedPath = path18.sep !== "/" ? stat.path.split(path18.sep).join("/") : stat.path;
|
|
7122
|
+
return path18.posix.join(stat.name, normalizedPath).replace(normalize3, "");
|
|
7123
7123
|
}
|
|
7124
7124
|
}
|
|
7125
7125
|
});
|
|
@@ -7204,7 +7204,7 @@ var require_RequireInTheMiddleSingleton = __commonJS({
|
|
|
7204
7204
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7205
7205
|
exports.RequireInTheMiddleSingleton = void 0;
|
|
7206
7206
|
var require_in_the_middle_1 = require_require_in_the_middle();
|
|
7207
|
-
var
|
|
7207
|
+
var path18 = __require("path");
|
|
7208
7208
|
var ModuleNameTrie_1 = require_ModuleNameTrie();
|
|
7209
7209
|
var isMocha = [
|
|
7210
7210
|
"afterEach",
|
|
@@ -7268,7 +7268,7 @@ var require_RequireInTheMiddleSingleton = __commonJS({
|
|
|
7268
7268
|
};
|
|
7269
7269
|
exports.RequireInTheMiddleSingleton = RequireInTheMiddleSingleton;
|
|
7270
7270
|
function normalizePathSeparators(moduleNameOrPath) {
|
|
7271
|
-
return
|
|
7271
|
+
return path18.sep !== ModuleNameTrie_1.ModuleNameSeparator ? moduleNameOrPath.split(path18.sep).join(ModuleNameTrie_1.ModuleNameSeparator) : moduleNameOrPath;
|
|
7272
7272
|
}
|
|
7273
7273
|
}
|
|
7274
7274
|
});
|
|
@@ -7434,7 +7434,7 @@ var require_register = __commonJS({
|
|
|
7434
7434
|
// ../../node_modules/.pnpm/import-in-the-middle@3.3.3/node_modules/import-in-the-middle/index.js
|
|
7435
7435
|
var require_import_in_the_middle = __commonJS({
|
|
7436
7436
|
"../../node_modules/.pnpm/import-in-the-middle@3.3.3/node_modules/import-in-the-middle/index.js"(exports, module2) {
|
|
7437
|
-
var
|
|
7437
|
+
var path18 = __require("path");
|
|
7438
7438
|
var moduleDetailsFromPath = require_module_details_from_path();
|
|
7439
7439
|
var { fileURLToPath: fileURLToPath3 } = __require("url");
|
|
7440
7440
|
var { MessageChannel } = __require("worker_threads");
|
|
@@ -7553,7 +7553,7 @@ var require_import_in_the_middle = __commonJS({
|
|
|
7553
7553
|
} else if (baseDir.endsWith(specifiers.get(loadUrl)) || isTurbopackSpecifier(specifiers.get(loadUrl), baseDir)) {
|
|
7554
7554
|
callHookFn(hookFn, namespace, name, baseDir);
|
|
7555
7555
|
} else if (internals) {
|
|
7556
|
-
const internalPath = name +
|
|
7556
|
+
const internalPath = name + path18.sep + path18.relative(baseDir, filePath);
|
|
7557
7557
|
callHookFn(hookFn, namespace, internalPath, baseDir);
|
|
7558
7558
|
}
|
|
7559
7559
|
} else if (matchArg === specifier) {
|
|
@@ -7628,7 +7628,7 @@ var require_instrumentation2 = __commonJS({
|
|
|
7628
7628
|
"use strict";
|
|
7629
7629
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7630
7630
|
exports.InstrumentationBase = void 0;
|
|
7631
|
-
var
|
|
7631
|
+
var path18 = __require("path");
|
|
7632
7632
|
var util_1 = __require("util");
|
|
7633
7633
|
var semver_1 = require_semver();
|
|
7634
7634
|
var shimmer_1 = require_shimmer();
|
|
@@ -7729,7 +7729,7 @@ var require_instrumentation2 = __commonJS({
|
|
|
7729
7729
|
}
|
|
7730
7730
|
_extractPackageVersion(baseDir) {
|
|
7731
7731
|
try {
|
|
7732
|
-
const json2 = (0, fs_1.readFileSync)(
|
|
7732
|
+
const json2 = (0, fs_1.readFileSync)(path18.join(baseDir, "package.json"), {
|
|
7733
7733
|
encoding: "utf8"
|
|
7734
7734
|
});
|
|
7735
7735
|
const version2 = JSON.parse(json2).version;
|
|
@@ -7771,7 +7771,7 @@ var require_instrumentation2 = __commonJS({
|
|
|
7771
7771
|
return exports2;
|
|
7772
7772
|
}
|
|
7773
7773
|
const files = module3.files ?? [];
|
|
7774
|
-
const normalizedName =
|
|
7774
|
+
const normalizedName = path18.normalize(name);
|
|
7775
7775
|
const supportedFileInstrumentations = files.filter((f) => f.name === normalizedName && isSupported(f.supportedVersions, version2, module3.includePrerelease));
|
|
7776
7776
|
return supportedFileInstrumentations.reduce((patchedExports, file2) => {
|
|
7777
7777
|
file2.moduleExports = patchedExports;
|
|
@@ -7817,8 +7817,8 @@ var require_instrumentation2 = __commonJS({
|
|
|
7817
7817
|
this._warnOnPreloadedModules();
|
|
7818
7818
|
for (const module3 of this._modules) {
|
|
7819
7819
|
const hookFn = (exports2, name, baseDir) => {
|
|
7820
|
-
if (!baseDir &&
|
|
7821
|
-
const parsedPath =
|
|
7820
|
+
if (!baseDir && path18.isAbsolute(name)) {
|
|
7821
|
+
const parsedPath = path18.parse(name);
|
|
7822
7822
|
name = parsedPath.name;
|
|
7823
7823
|
baseDir = parsedPath.dir;
|
|
7824
7824
|
}
|
|
@@ -7827,7 +7827,7 @@ var require_instrumentation2 = __commonJS({
|
|
|
7827
7827
|
const onRequire = (exports2, name, baseDir) => {
|
|
7828
7828
|
return this._onRequire(module3, exports2, name, baseDir);
|
|
7829
7829
|
};
|
|
7830
|
-
const hook =
|
|
7830
|
+
const hook = path18.isAbsolute(module3.name) ? new require_in_the_middle_1.Hook([module3.name], { internals: true }, onRequire) : this._requireInTheMiddleSingleton.register(module3.name, onRequire);
|
|
7831
7831
|
this._hooks.push(hook);
|
|
7832
7832
|
const esmHook = new import_in_the_middle_1.Hook([module3.name], { internals: true }, hookFn);
|
|
7833
7833
|
this._hooks.push(esmHook);
|
|
@@ -8435,9 +8435,9 @@ var require_getMachineId_linux = __commonJS({
|
|
|
8435
8435
|
var api_1 = (init_esm(), __toCommonJS(esm_exports));
|
|
8436
8436
|
async function getMachineId() {
|
|
8437
8437
|
const paths = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
|
|
8438
|
-
for (const
|
|
8438
|
+
for (const path18 of paths) {
|
|
8439
8439
|
try {
|
|
8440
|
-
const result = await fs_1.promises.readFile(
|
|
8440
|
+
const result = await fs_1.promises.readFile(path18, { encoding: "utf8" });
|
|
8441
8441
|
return result.trim();
|
|
8442
8442
|
} catch (e) {
|
|
8443
8443
|
api_1.diag.debug(`error reading machine id: ${e}`);
|
|
@@ -11792,14 +11792,14 @@ var require_util = __commonJS({
|
|
|
11792
11792
|
}
|
|
11793
11793
|
const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
|
|
11794
11794
|
let origin = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
|
|
11795
|
-
let
|
|
11795
|
+
let path18 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
|
|
11796
11796
|
if (origin[origin.length - 1] === "/") {
|
|
11797
11797
|
origin = origin.slice(0, origin.length - 1);
|
|
11798
11798
|
}
|
|
11799
|
-
if (
|
|
11800
|
-
|
|
11799
|
+
if (path18 && path18[0] !== "/") {
|
|
11800
|
+
path18 = `/${path18}`;
|
|
11801
11801
|
}
|
|
11802
|
-
return new URL(`${origin}${
|
|
11802
|
+
return new URL(`${origin}${path18}`);
|
|
11803
11803
|
}
|
|
11804
11804
|
if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
|
|
11805
11805
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -12620,9 +12620,9 @@ var require_diagnostics = __commonJS({
|
|
|
12620
12620
|
"undici:client:sendHeaders",
|
|
12621
12621
|
(evt) => {
|
|
12622
12622
|
const {
|
|
12623
|
-
request: { method, path:
|
|
12623
|
+
request: { method, path: path18, origin }
|
|
12624
12624
|
} = evt;
|
|
12625
|
-
debugLog3("sending request to %s %s%s", method, origin,
|
|
12625
|
+
debugLog3("sending request to %s %s%s", method, origin, path18);
|
|
12626
12626
|
}
|
|
12627
12627
|
);
|
|
12628
12628
|
}
|
|
@@ -12640,14 +12640,14 @@ var require_diagnostics = __commonJS({
|
|
|
12640
12640
|
"undici:request:headers",
|
|
12641
12641
|
(evt) => {
|
|
12642
12642
|
const {
|
|
12643
|
-
request: { method, path:
|
|
12643
|
+
request: { method, path: path18, origin },
|
|
12644
12644
|
response: { statusCode }
|
|
12645
12645
|
} = evt;
|
|
12646
12646
|
debugLog3(
|
|
12647
12647
|
"received response to %s %s%s - HTTP %d",
|
|
12648
12648
|
method,
|
|
12649
12649
|
origin,
|
|
12650
|
-
|
|
12650
|
+
path18,
|
|
12651
12651
|
statusCode
|
|
12652
12652
|
);
|
|
12653
12653
|
}
|
|
@@ -12656,23 +12656,23 @@ var require_diagnostics = __commonJS({
|
|
|
12656
12656
|
"undici:request:trailers",
|
|
12657
12657
|
(evt) => {
|
|
12658
12658
|
const {
|
|
12659
|
-
request: { method, path:
|
|
12659
|
+
request: { method, path: path18, origin }
|
|
12660
12660
|
} = evt;
|
|
12661
|
-
debugLog3("trailers received from %s %s%s", method, origin,
|
|
12661
|
+
debugLog3("trailers received from %s %s%s", method, origin, path18);
|
|
12662
12662
|
}
|
|
12663
12663
|
);
|
|
12664
12664
|
diagnosticsChannel9.subscribe(
|
|
12665
12665
|
"undici:request:error",
|
|
12666
12666
|
(evt) => {
|
|
12667
12667
|
const {
|
|
12668
|
-
request: { method, path:
|
|
12668
|
+
request: { method, path: path18, origin },
|
|
12669
12669
|
error: error52
|
|
12670
12670
|
} = evt;
|
|
12671
12671
|
debugLog3(
|
|
12672
12672
|
"request to %s %s%s errored - %s",
|
|
12673
12673
|
method,
|
|
12674
12674
|
origin,
|
|
12675
|
-
|
|
12675
|
+
path18,
|
|
12676
12676
|
error52.message
|
|
12677
12677
|
);
|
|
12678
12678
|
}
|
|
@@ -12787,7 +12787,7 @@ var require_request = __commonJS({
|
|
|
12787
12787
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
12788
12788
|
var Request2 = class {
|
|
12789
12789
|
constructor(origin, {
|
|
12790
|
-
path:
|
|
12790
|
+
path: path18,
|
|
12791
12791
|
method,
|
|
12792
12792
|
body,
|
|
12793
12793
|
headers,
|
|
@@ -12804,11 +12804,11 @@ var require_request = __commonJS({
|
|
|
12804
12804
|
maxRedirections,
|
|
12805
12805
|
typeOfService
|
|
12806
12806
|
}, handler) {
|
|
12807
|
-
if (typeof
|
|
12807
|
+
if (typeof path18 !== "string") {
|
|
12808
12808
|
throw new InvalidArgumentError("path must be a string");
|
|
12809
|
-
} else if (
|
|
12809
|
+
} else if (path18[0] !== "/" && !(path18.startsWith("http://") || path18.startsWith("https://")) && method !== "CONNECT") {
|
|
12810
12810
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
12811
|
-
} else if (invalidPathRegex.test(
|
|
12811
|
+
} else if (invalidPathRegex.test(path18)) {
|
|
12812
12812
|
throw new InvalidArgumentError("invalid request path");
|
|
12813
12813
|
}
|
|
12814
12814
|
if (typeof method !== "string") {
|
|
@@ -12883,7 +12883,7 @@ var require_request = __commonJS({
|
|
|
12883
12883
|
this.completed = false;
|
|
12884
12884
|
this.aborted = false;
|
|
12885
12885
|
this.upgrade = upgrade || null;
|
|
12886
|
-
this.path = query ? serializePathWithQuery(
|
|
12886
|
+
this.path = query ? serializePathWithQuery(path18, query) : path18;
|
|
12887
12887
|
this.origin = origin;
|
|
12888
12888
|
this.protocol = getProtocolFromUrlString(origin);
|
|
12889
12889
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -18066,7 +18066,7 @@ var require_client_h1 = __commonJS({
|
|
|
18066
18066
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
18067
18067
|
}
|
|
18068
18068
|
function writeH1(client, request2) {
|
|
18069
|
-
const { method, path:
|
|
18069
|
+
const { method, path: path18, host, upgrade, blocking, reset } = request2;
|
|
18070
18070
|
let { body, headers, contentLength } = request2;
|
|
18071
18071
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
18072
18072
|
if (util2.isFormDataLike(body)) {
|
|
@@ -18144,7 +18144,7 @@ var require_client_h1 = __commonJS({
|
|
|
18144
18144
|
if (socket.setTypeOfService) {
|
|
18145
18145
|
socket.setTypeOfService(request2.typeOfService);
|
|
18146
18146
|
}
|
|
18147
|
-
let header = `${method} ${
|
|
18147
|
+
let header = `${method} ${path18} HTTP/1.1\r
|
|
18148
18148
|
`;
|
|
18149
18149
|
if (typeof host === "string") {
|
|
18150
18150
|
header += `host: ${host}\r
|
|
@@ -18797,7 +18797,7 @@ var require_client_h2 = __commonJS({
|
|
|
18797
18797
|
function writeH2(client, request2) {
|
|
18798
18798
|
const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
18799
18799
|
const session = client[kHTTP2Session];
|
|
18800
|
-
const { method, path:
|
|
18800
|
+
const { method, path: path18, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
18801
18801
|
let { body } = request2;
|
|
18802
18802
|
if (upgrade != null && upgrade !== "websocket") {
|
|
18803
18803
|
util2.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -18865,7 +18865,7 @@ var require_client_h2 = __commonJS({
|
|
|
18865
18865
|
}
|
|
18866
18866
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
18867
18867
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
18868
|
-
headers[HTTP2_HEADER_PATH] =
|
|
18868
|
+
headers[HTTP2_HEADER_PATH] = path18;
|
|
18869
18869
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
18870
18870
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
18871
18871
|
} else {
|
|
@@ -18906,7 +18906,7 @@ var require_client_h2 = __commonJS({
|
|
|
18906
18906
|
stream.setTimeout(requestTimeout);
|
|
18907
18907
|
return true;
|
|
18908
18908
|
}
|
|
18909
|
-
headers[HTTP2_HEADER_PATH] =
|
|
18909
|
+
headers[HTTP2_HEADER_PATH] = path18;
|
|
18910
18910
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
18911
18911
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
18912
18912
|
if (body && typeof body.read === "function") {
|
|
@@ -21249,10 +21249,10 @@ var require_proxy_agent = __commonJS({
|
|
|
21249
21249
|
};
|
|
21250
21250
|
const {
|
|
21251
21251
|
origin,
|
|
21252
|
-
path:
|
|
21252
|
+
path: path18 = "/",
|
|
21253
21253
|
headers = {}
|
|
21254
21254
|
} = opts;
|
|
21255
|
-
opts.path = origin +
|
|
21255
|
+
opts.path = origin + path18;
|
|
21256
21256
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
21257
21257
|
const { host } = new URL(origin);
|
|
21258
21258
|
headers.host = host;
|
|
@@ -23335,20 +23335,20 @@ var require_mock_utils = __commonJS({
|
|
|
23335
23335
|
}
|
|
23336
23336
|
return normalizedQp;
|
|
23337
23337
|
}
|
|
23338
|
-
function safeUrl(
|
|
23339
|
-
if (typeof
|
|
23340
|
-
return
|
|
23338
|
+
function safeUrl(path18) {
|
|
23339
|
+
if (typeof path18 !== "string") {
|
|
23340
|
+
return path18;
|
|
23341
23341
|
}
|
|
23342
|
-
const pathSegments =
|
|
23342
|
+
const pathSegments = path18.split("?", 3);
|
|
23343
23343
|
if (pathSegments.length !== 2) {
|
|
23344
|
-
return
|
|
23344
|
+
return path18;
|
|
23345
23345
|
}
|
|
23346
23346
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
23347
23347
|
qp.sort();
|
|
23348
23348
|
return [...pathSegments, qp.toString()].join("?");
|
|
23349
23349
|
}
|
|
23350
|
-
function matchKey(mockDispatch2, { path:
|
|
23351
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
23350
|
+
function matchKey(mockDispatch2, { path: path18, method, body, headers }) {
|
|
23351
|
+
const pathMatch = matchValue(mockDispatch2.path, path18);
|
|
23352
23352
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
23353
23353
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
23354
23354
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -23373,8 +23373,8 @@ var require_mock_utils = __commonJS({
|
|
|
23373
23373
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
23374
23374
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
23375
23375
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
23376
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
23377
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
23376
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path18, ignoreTrailingSlash }) => {
|
|
23377
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path18)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path18), resolvedPath);
|
|
23378
23378
|
});
|
|
23379
23379
|
if (matchedMockDispatches.length === 0) {
|
|
23380
23380
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -23413,19 +23413,19 @@ var require_mock_utils = __commonJS({
|
|
|
23413
23413
|
mockDispatches.splice(index, 1);
|
|
23414
23414
|
}
|
|
23415
23415
|
}
|
|
23416
|
-
function removeTrailingSlash(
|
|
23417
|
-
while (
|
|
23418
|
-
|
|
23416
|
+
function removeTrailingSlash(path18) {
|
|
23417
|
+
while (path18.endsWith("/")) {
|
|
23418
|
+
path18 = path18.slice(0, -1);
|
|
23419
23419
|
}
|
|
23420
|
-
if (
|
|
23421
|
-
|
|
23420
|
+
if (path18.length === 0) {
|
|
23421
|
+
path18 = "/";
|
|
23422
23422
|
}
|
|
23423
|
-
return
|
|
23423
|
+
return path18;
|
|
23424
23424
|
}
|
|
23425
23425
|
function buildKey(opts) {
|
|
23426
|
-
const { path:
|
|
23426
|
+
const { path: path18, method, body, headers, query } = opts;
|
|
23427
23427
|
return {
|
|
23428
|
-
path:
|
|
23428
|
+
path: path18,
|
|
23429
23429
|
method,
|
|
23430
23430
|
body,
|
|
23431
23431
|
headers,
|
|
@@ -24115,10 +24115,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
24115
24115
|
}
|
|
24116
24116
|
format(pendingInterceptors) {
|
|
24117
24117
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
24118
|
-
({ method, path:
|
|
24118
|
+
({ method, path: path18, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
24119
24119
|
Method: method,
|
|
24120
24120
|
Origin: origin,
|
|
24121
|
-
Path:
|
|
24121
|
+
Path: path18,
|
|
24122
24122
|
"Status code": statusCode,
|
|
24123
24123
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
24124
24124
|
Invocations: timesInvoked,
|
|
@@ -24200,9 +24200,9 @@ var require_mock_agent = __commonJS({
|
|
|
24200
24200
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
24201
24201
|
const dispatchOpts = { ...opts };
|
|
24202
24202
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
24203
|
-
const [
|
|
24203
|
+
const [path18, searchParams] = dispatchOpts.path.split("?");
|
|
24204
24204
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
24205
|
-
dispatchOpts.path = `${
|
|
24205
|
+
dispatchOpts.path = `${path18}?${normalizedSearchParams}`;
|
|
24206
24206
|
}
|
|
24207
24207
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
24208
24208
|
}
|
|
@@ -24603,12 +24603,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
24603
24603
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
24604
24604
|
*/
|
|
24605
24605
|
async loadSnapshots(filePath) {
|
|
24606
|
-
const
|
|
24607
|
-
if (!
|
|
24606
|
+
const path18 = filePath || this.#snapshotPath;
|
|
24607
|
+
if (!path18) {
|
|
24608
24608
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
24609
24609
|
}
|
|
24610
24610
|
try {
|
|
24611
|
-
const data = await readFile2(resolve2(
|
|
24611
|
+
const data = await readFile2(resolve2(path18), "utf8");
|
|
24612
24612
|
const parsed = JSON.parse(data);
|
|
24613
24613
|
if (Array.isArray(parsed)) {
|
|
24614
24614
|
this.#snapshots.clear();
|
|
@@ -24622,7 +24622,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
24622
24622
|
if (error52.code === "ENOENT") {
|
|
24623
24623
|
this.#snapshots.clear();
|
|
24624
24624
|
} else {
|
|
24625
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
24625
|
+
throw new UndiciError(`Failed to load snapshots from ${path18}`, { cause: error52 });
|
|
24626
24626
|
}
|
|
24627
24627
|
}
|
|
24628
24628
|
}
|
|
@@ -24633,11 +24633,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
24633
24633
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
24634
24634
|
*/
|
|
24635
24635
|
async saveSnapshots(filePath) {
|
|
24636
|
-
const
|
|
24637
|
-
if (!
|
|
24636
|
+
const path18 = filePath || this.#snapshotPath;
|
|
24637
|
+
if (!path18) {
|
|
24638
24638
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
24639
24639
|
}
|
|
24640
|
-
const resolvedPath = resolve2(
|
|
24640
|
+
const resolvedPath = resolve2(path18);
|
|
24641
24641
|
await mkdir(dirname2(resolvedPath), { recursive: true });
|
|
24642
24642
|
const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
|
|
24643
24643
|
hash: hash2,
|
|
@@ -25269,15 +25269,15 @@ var require_redirect_handler = __commonJS({
|
|
|
25269
25269
|
return;
|
|
25270
25270
|
}
|
|
25271
25271
|
const { origin, pathname, search } = util2.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
25272
|
-
const
|
|
25273
|
-
const redirectUrlString = `${origin}${
|
|
25272
|
+
const path18 = search ? `${pathname}${search}` : pathname;
|
|
25273
|
+
const redirectUrlString = `${origin}${path18}`;
|
|
25274
25274
|
for (const historyUrl of this.history) {
|
|
25275
25275
|
if (historyUrl.toString() === redirectUrlString) {
|
|
25276
25276
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
25277
25277
|
}
|
|
25278
25278
|
}
|
|
25279
25279
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
25280
|
-
this.opts.path =
|
|
25280
|
+
this.opts.path = path18;
|
|
25281
25281
|
this.opts.origin = origin;
|
|
25282
25282
|
this.opts.query = null;
|
|
25283
25283
|
}
|
|
@@ -27046,10 +27046,10 @@ var require_cache_handler = __commonJS({
|
|
|
27046
27046
|
}
|
|
27047
27047
|
return locationUrl.pathname + locationUrl.search;
|
|
27048
27048
|
}
|
|
27049
|
-
function deleteCachedUri(store, cacheKey,
|
|
27049
|
+
function deleteCachedUri(store, cacheKey, path18) {
|
|
27050
27050
|
deleteCachedValue(store, {
|
|
27051
27051
|
...cacheKey,
|
|
27052
|
-
path:
|
|
27052
|
+
path: path18
|
|
27053
27053
|
});
|
|
27054
27054
|
for (let i = 0; i < util2.safeHTTPMethods.length; i++) {
|
|
27055
27055
|
const method = util2.safeHTTPMethods[i];
|
|
@@ -27057,7 +27057,7 @@ var require_cache_handler = __commonJS({
|
|
|
27057
27057
|
deleteCachedValue(store, {
|
|
27058
27058
|
...cacheKey,
|
|
27059
27059
|
method,
|
|
27060
|
-
path:
|
|
27060
|
+
path: path18
|
|
27061
27061
|
});
|
|
27062
27062
|
}
|
|
27063
27063
|
}
|
|
@@ -27068,9 +27068,9 @@ var require_cache_handler = __commonJS({
|
|
|
27068
27068
|
}
|
|
27069
27069
|
const values = Array.isArray(headerValue) ? headerValue : [headerValue];
|
|
27070
27070
|
for (let i = 0; i < values.length; i++) {
|
|
27071
|
-
const
|
|
27072
|
-
if (
|
|
27073
|
-
deleteCachedUri(store, cacheKey,
|
|
27071
|
+
const path18 = getSameOriginPath(cacheKey, values[i]);
|
|
27072
|
+
if (path18 !== void 0) {
|
|
27073
|
+
deleteCachedUri(store, cacheKey, path18);
|
|
27074
27074
|
}
|
|
27075
27075
|
}
|
|
27076
27076
|
}
|
|
@@ -31948,11 +31948,11 @@ var require_fetch = __commonJS({
|
|
|
31948
31948
|
function dispatch({ body }) {
|
|
31949
31949
|
const url2 = requestCurrentURL(request2);
|
|
31950
31950
|
const agent = fetchParams.controller.dispatcher;
|
|
31951
|
-
const
|
|
31951
|
+
const path18 = url2.pathname + url2.search;
|
|
31952
31952
|
const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
|
|
31953
31953
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
31954
31954
|
{
|
|
31955
|
-
path: hasTrailingQuestionMark ? `${
|
|
31955
|
+
path: hasTrailingQuestionMark ? `${path18}?` : path18,
|
|
31956
31956
|
origin: url2.origin,
|
|
31957
31957
|
method: request2.method,
|
|
31958
31958
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -32899,9 +32899,9 @@ var require_util4 = __commonJS({
|
|
|
32899
32899
|
}
|
|
32900
32900
|
}
|
|
32901
32901
|
}
|
|
32902
|
-
function validateCookiePath(
|
|
32903
|
-
for (let i = 0; i <
|
|
32904
|
-
const code =
|
|
32902
|
+
function validateCookiePath(path18) {
|
|
32903
|
+
for (let i = 0; i < path18.length; ++i) {
|
|
32904
|
+
const code = path18.charCodeAt(i);
|
|
32905
32905
|
if (code < 32 || // exclude CTLs (0-31)
|
|
32906
32906
|
code > 126 || // exclude DEL and non-ascii
|
|
32907
32907
|
code === 59) {
|
|
@@ -36138,11 +36138,11 @@ var require_undici = __commonJS({
|
|
|
36138
36138
|
if (typeof opts.path !== "string") {
|
|
36139
36139
|
throw new InvalidArgumentError("invalid opts.path");
|
|
36140
36140
|
}
|
|
36141
|
-
let
|
|
36141
|
+
let path18 = opts.path;
|
|
36142
36142
|
if (!opts.path.startsWith("/")) {
|
|
36143
|
-
|
|
36143
|
+
path18 = `/${path18}`;
|
|
36144
36144
|
}
|
|
36145
|
-
url2 = new URL(util2.parseOrigin(url2).origin +
|
|
36145
|
+
url2 = new URL(util2.parseOrigin(url2).origin + path18);
|
|
36146
36146
|
} else {
|
|
36147
36147
|
if (!opts) {
|
|
36148
36148
|
opts = typeof url2 === "object" ? url2 : {};
|
|
@@ -36253,7 +36253,7 @@ ${captureLines}` : capture.stack;
|
|
|
36253
36253
|
|
|
36254
36254
|
// src/cli.ts
|
|
36255
36255
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
36256
|
-
import { existsSync as
|
|
36256
|
+
import { existsSync as existsSync6, realpathSync as realpathSync2 } from "node:fs";
|
|
36257
36257
|
import { parseArgs } from "node:util";
|
|
36258
36258
|
|
|
36259
36259
|
// ../../apps/collector/src/credentials.ts
|
|
@@ -37028,10 +37028,10 @@ function mergeDefs(...defs) {
|
|
|
37028
37028
|
function cloneDef(schema) {
|
|
37029
37029
|
return mergeDefs(schema._zod.def);
|
|
37030
37030
|
}
|
|
37031
|
-
function getElementAtPath(obj,
|
|
37032
|
-
if (!
|
|
37031
|
+
function getElementAtPath(obj, path18) {
|
|
37032
|
+
if (!path18)
|
|
37033
37033
|
return obj;
|
|
37034
|
-
return
|
|
37034
|
+
return path18.reduce((acc, key) => acc?.[key], obj);
|
|
37035
37035
|
}
|
|
37036
37036
|
function promiseAllObject(promisesObj) {
|
|
37037
37037
|
const keys = Object.keys(promisesObj);
|
|
@@ -37440,11 +37440,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
37440
37440
|
}
|
|
37441
37441
|
return false;
|
|
37442
37442
|
}
|
|
37443
|
-
function prefixIssues(
|
|
37443
|
+
function prefixIssues(path18, issues) {
|
|
37444
37444
|
return issues.map((iss) => {
|
|
37445
37445
|
var _a4;
|
|
37446
37446
|
(_a4 = iss).path ?? (_a4.path = []);
|
|
37447
|
-
iss.path.unshift(
|
|
37447
|
+
iss.path.unshift(path18);
|
|
37448
37448
|
return iss;
|
|
37449
37449
|
});
|
|
37450
37450
|
}
|
|
@@ -37591,16 +37591,16 @@ function flattenError(error52, mapper = (issue2) => issue2.message) {
|
|
|
37591
37591
|
}
|
|
37592
37592
|
function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
37593
37593
|
const fieldErrors = { _errors: [] };
|
|
37594
|
-
const processError = (error53,
|
|
37594
|
+
const processError = (error53, path18 = []) => {
|
|
37595
37595
|
for (const issue2 of error53.issues) {
|
|
37596
37596
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
37597
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
37597
|
+
issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
|
|
37598
37598
|
} else if (issue2.code === "invalid_key") {
|
|
37599
|
-
processError({ issues: issue2.issues }, [...
|
|
37599
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
37600
37600
|
} else if (issue2.code === "invalid_element") {
|
|
37601
|
-
processError({ issues: issue2.issues }, [...
|
|
37601
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
37602
37602
|
} else {
|
|
37603
|
-
const fullpath = [...
|
|
37603
|
+
const fullpath = [...path18, ...issue2.path];
|
|
37604
37604
|
if (fullpath.length === 0) {
|
|
37605
37605
|
fieldErrors._errors.push(mapper(issue2));
|
|
37606
37606
|
} else {
|
|
@@ -37627,17 +37627,17 @@ function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
|
37627
37627
|
}
|
|
37628
37628
|
function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
37629
37629
|
const result = { errors: [] };
|
|
37630
|
-
const processError = (error53,
|
|
37630
|
+
const processError = (error53, path18 = []) => {
|
|
37631
37631
|
var _a4, _b;
|
|
37632
37632
|
for (const issue2 of error53.issues) {
|
|
37633
37633
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
37634
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
37634
|
+
issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
|
|
37635
37635
|
} else if (issue2.code === "invalid_key") {
|
|
37636
|
-
processError({ issues: issue2.issues }, [...
|
|
37636
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
37637
37637
|
} else if (issue2.code === "invalid_element") {
|
|
37638
|
-
processError({ issues: issue2.issues }, [...
|
|
37638
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
37639
37639
|
} else {
|
|
37640
|
-
const fullpath = [...
|
|
37640
|
+
const fullpath = [...path18, ...issue2.path];
|
|
37641
37641
|
if (fullpath.length === 0) {
|
|
37642
37642
|
result.errors.push(mapper(issue2));
|
|
37643
37643
|
continue;
|
|
@@ -37669,8 +37669,8 @@ function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
|
37669
37669
|
}
|
|
37670
37670
|
function toDotPath(_path) {
|
|
37671
37671
|
const segs = [];
|
|
37672
|
-
const
|
|
37673
|
-
for (const seg of
|
|
37672
|
+
const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
37673
|
+
for (const seg of path18) {
|
|
37674
37674
|
if (typeof seg === "number")
|
|
37675
37675
|
segs.push(`[${seg}]`);
|
|
37676
37676
|
else if (typeof seg === "symbol")
|
|
@@ -50362,13 +50362,13 @@ function resolveRef(ref, ctx) {
|
|
|
50362
50362
|
if (!ref.startsWith("#")) {
|
|
50363
50363
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
50364
50364
|
}
|
|
50365
|
-
const
|
|
50366
|
-
if (
|
|
50365
|
+
const path18 = ref.slice(1).split("/").filter(Boolean);
|
|
50366
|
+
if (path18.length === 0) {
|
|
50367
50367
|
return ctx.rootSchema;
|
|
50368
50368
|
}
|
|
50369
50369
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
50370
|
-
if (
|
|
50371
|
-
const key =
|
|
50370
|
+
if (path18[0] === defsKey) {
|
|
50371
|
+
const key = path18[1];
|
|
50372
50372
|
if (!key || !ctx.defs[key]) {
|
|
50373
50373
|
throw new Error(`Reference not found: ${ref}`);
|
|
50374
50374
|
}
|
|
@@ -50833,6 +50833,17 @@ function capturedSessionEvents(turns, anchor) {
|
|
|
50833
50833
|
return events;
|
|
50834
50834
|
}
|
|
50835
50835
|
|
|
50836
|
+
// ../core/src/workspaceClaims.ts
|
|
50837
|
+
function workspaceClaimsRepo(repoFullName, policy) {
|
|
50838
|
+
const repo = repoFullName.toLowerCase();
|
|
50839
|
+
if (policy.repos !== null) return policy.repos.includes(repo);
|
|
50840
|
+
const owner = repo.split("/")[0] ?? "";
|
|
50841
|
+
return policy.owners.length > 0 && policy.owners.includes(owner);
|
|
50842
|
+
}
|
|
50843
|
+
function workspaceClaimsAnyRepo(policy) {
|
|
50844
|
+
return policy.repos !== null ? policy.repos.length > 0 : policy.owners.length > 0;
|
|
50845
|
+
}
|
|
50846
|
+
|
|
50836
50847
|
// ../core/src/transcriptImages.ts
|
|
50837
50848
|
var IMAGE_DATA_URI_RE = /^data:(image\/[\w.+-]+);base64,([A-Za-z0-9+/=_-]*)$/;
|
|
50838
50849
|
function isImageDataUri(value) {
|
|
@@ -51398,8 +51409,8 @@ function primaryArg(args) {
|
|
|
51398
51409
|
function readFilePath(name, primary) {
|
|
51399
51410
|
if (!primary || !READ_TOOLS.has(name)) return null;
|
|
51400
51411
|
if (ARTIFACT_PATH_RE.test(primary)) return null;
|
|
51401
|
-
const
|
|
51402
|
-
return
|
|
51412
|
+
const path18 = primary.startsWith("/workspace/") ? primary.slice("/workspace/".length) : primary;
|
|
51413
|
+
return path18.length > 0 ? path18 : null;
|
|
51403
51414
|
}
|
|
51404
51415
|
function asRecord3(value) {
|
|
51405
51416
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -51693,6 +51704,8 @@ var SESSION_SOURCES = [
|
|
|
51693
51704
|
"cursor-cloud",
|
|
51694
51705
|
"github-pr"
|
|
51695
51706
|
];
|
|
51707
|
+
var SESSION_SPEED_MODES = ["standard", "fast"];
|
|
51708
|
+
var SESSION_SPEED_OBSERVATIONS = [...SESSION_SPEED_MODES, "unknown"];
|
|
51696
51709
|
function isSessionSource(source) {
|
|
51697
51710
|
return typeof source === "string" && SESSION_SOURCES.includes(source);
|
|
51698
51711
|
}
|
|
@@ -51906,8 +51919,8 @@ function getFunctionName(fn) {
|
|
|
51906
51919
|
return defaultFunctionName;
|
|
51907
51920
|
}
|
|
51908
51921
|
}
|
|
51909
|
-
function normalizeStackTracePath(
|
|
51910
|
-
let filename =
|
|
51922
|
+
function normalizeStackTracePath(path18) {
|
|
51923
|
+
let filename = path18?.startsWith("file://") ? path18.slice(7) : path18;
|
|
51911
51924
|
if (filename?.match(/\/[A-Z]:/)) {
|
|
51912
51925
|
filename = filename.slice(1);
|
|
51913
51926
|
}
|
|
@@ -53717,8 +53730,8 @@ function isValidProtocol(protocol) {
|
|
|
53717
53730
|
return protocol === "http" || protocol === "https";
|
|
53718
53731
|
}
|
|
53719
53732
|
function dsnToString(dsn, withPassword = false) {
|
|
53720
|
-
const { host, path:
|
|
53721
|
-
return `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ""}@${host}${port ? `:${port}` : ""}/${
|
|
53733
|
+
const { host, path: path18, pass, port, projectId, protocol, publicKey } = dsn;
|
|
53734
|
+
return `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ""}@${host}${port ? `:${port}` : ""}/${path18 ? `${path18}/` : path18}${projectId}`;
|
|
53722
53735
|
}
|
|
53723
53736
|
function dsnFromString(str) {
|
|
53724
53737
|
const match = DSN_REGEX.exec(str);
|
|
@@ -53729,11 +53742,11 @@ function dsnFromString(str) {
|
|
|
53729
53742
|
return void 0;
|
|
53730
53743
|
}
|
|
53731
53744
|
const [protocol, publicKey, pass = "", host = "", port = "", lastPath = ""] = match.slice(1);
|
|
53732
|
-
let
|
|
53745
|
+
let path18 = "";
|
|
53733
53746
|
let projectId = lastPath;
|
|
53734
53747
|
const split = projectId.split("/");
|
|
53735
53748
|
if (split.length > 1) {
|
|
53736
|
-
|
|
53749
|
+
path18 = split.slice(0, -1).join("/");
|
|
53737
53750
|
projectId = split.pop();
|
|
53738
53751
|
}
|
|
53739
53752
|
if (projectId) {
|
|
@@ -53742,7 +53755,7 @@ function dsnFromString(str) {
|
|
|
53742
53755
|
projectId = projectMatch[0];
|
|
53743
53756
|
}
|
|
53744
53757
|
}
|
|
53745
|
-
return dsnFromComponents({ host, pass, path:
|
|
53758
|
+
return dsnFromComponents({ host, pass, path: path18, projectId, port, protocol, publicKey });
|
|
53746
53759
|
}
|
|
53747
53760
|
function dsnFromComponents(components) {
|
|
53748
53761
|
return {
|
|
@@ -58276,9 +58289,9 @@ function stripUrlQueryAndFragment(urlPath) {
|
|
|
58276
58289
|
return urlPath.split(/[?#]/, 1)[0];
|
|
58277
58290
|
}
|
|
58278
58291
|
function getSanitizedUrlString(url2) {
|
|
58279
|
-
const { protocol, host, path:
|
|
58292
|
+
const { protocol, host, path: path18 } = url2;
|
|
58280
58293
|
const filteredHost = host?.replace(/^.*@/, "[filtered]:[filtered]@").replace(/(:80)$/, "").replace(/(:443)$/, "") || "";
|
|
58281
|
-
return `${protocol ? `${protocol}://` : ""}${filteredHost}${
|
|
58294
|
+
return `${protocol ? `${protocol}://` : ""}${filteredHost}${path18}`;
|
|
58282
58295
|
}
|
|
58283
58296
|
function stripDataUrlContent(url2, includeDataPrefix = true) {
|
|
58284
58297
|
if (url2.startsWith("data:")) {
|
|
@@ -59221,8 +59234,8 @@ function splitPath(filename) {
|
|
|
59221
59234
|
const parts = splitPathRe.exec(truncated);
|
|
59222
59235
|
return parts ? parts.slice(1) : [];
|
|
59223
59236
|
}
|
|
59224
|
-
function dirname(
|
|
59225
|
-
const result = splitPath(
|
|
59237
|
+
function dirname(path18) {
|
|
59238
|
+
const result = splitPath(path18);
|
|
59226
59239
|
const root = result[0] || "";
|
|
59227
59240
|
let dir = result[1];
|
|
59228
59241
|
if (!root && !dir) {
|
|
@@ -63148,15 +63161,15 @@ var getLayerMetadata = (route, layer, layerPath) => {
|
|
|
63148
63161
|
};
|
|
63149
63162
|
}
|
|
63150
63163
|
};
|
|
63151
|
-
var getRouterPath = (
|
|
63164
|
+
var getRouterPath = (path18, layer) => {
|
|
63152
63165
|
const stackLayer = Array.isArray(layer.handle?.stack) ? layer.handle?.stack?.[0] : void 0;
|
|
63153
63166
|
if (stackLayer?.route?.path) {
|
|
63154
|
-
return `${
|
|
63167
|
+
return `${path18}${stackLayer.route.path}`;
|
|
63155
63168
|
}
|
|
63156
63169
|
if (stackLayer && Array.isArray(stackLayer?.handle?.stack)) {
|
|
63157
|
-
return getRouterPath(
|
|
63170
|
+
return getRouterPath(path18, stackLayer);
|
|
63158
63171
|
}
|
|
63159
|
-
return
|
|
63172
|
+
return path18;
|
|
63160
63173
|
};
|
|
63161
63174
|
var isLayerIgnored = (name, type, config2) => {
|
|
63162
63175
|
if (Array.isArray(config2?.ignoreLayersType) && config2?.ignoreLayersType?.includes(type)) {
|
|
@@ -63176,7 +63189,7 @@ function getActualMatchedRoute(req, constructedRoute) {
|
|
|
63176
63189
|
if (layersStore.length === 0) {
|
|
63177
63190
|
return void 0;
|
|
63178
63191
|
}
|
|
63179
|
-
if (layersStore.every((
|
|
63192
|
+
if (layersStore.every((path18) => path18 === "/")) {
|
|
63180
63193
|
return req.originalUrl === "/" ? "/" : void 0;
|
|
63181
63194
|
}
|
|
63182
63195
|
if (constructedRoute === "*") {
|
|
@@ -63192,11 +63205,11 @@ function getActualMatchedRoute(req, constructedRoute) {
|
|
|
63192
63205
|
function getConstructedRoute(req) {
|
|
63193
63206
|
const layersStore = getStoredLayers(req);
|
|
63194
63207
|
let constructedRoute = "";
|
|
63195
|
-
for (const
|
|
63196
|
-
if (
|
|
63208
|
+
for (const path18 of layersStore) {
|
|
63209
|
+
if (path18 === "/" || path18 === "/*") {
|
|
63197
63210
|
continue;
|
|
63198
63211
|
}
|
|
63199
|
-
constructedRoute += !constructedRoute || constructedRoute.endsWith("/") ?
|
|
63212
|
+
constructedRoute += !constructedRoute || constructedRoute.endsWith("/") ? path18 : `/${path18}`;
|
|
63200
63213
|
}
|
|
63201
63214
|
return constructedRoute.replace(/\/{2,}/g, "/");
|
|
63202
63215
|
}
|
|
@@ -63701,9 +63714,9 @@ function getRequestUrlObject(requestOptions) {
|
|
|
63701
63714
|
const hostHeader = requestOptions.headers?.host && String(requestOptions.headers?.host);
|
|
63702
63715
|
const hostname4 = hostHeader || requestOptions.hostname || requestOptions.host || "";
|
|
63703
63716
|
const port = !requestOptions.port || requestOptions.port === 80 || requestOptions.port === 443 || /^(.*):(\d+)$/.test(hostname4) ? "" : `:${requestOptions.port}`;
|
|
63704
|
-
const
|
|
63717
|
+
const path18 = requestOptions.path ? requestOptions.path : "/";
|
|
63705
63718
|
const base = `${protocol}//${hostname4}${port}`;
|
|
63706
|
-
return new URL(
|
|
63719
|
+
return new URL(path18.startsWith("//") ? `${base}${path18}` : path18, base);
|
|
63707
63720
|
}
|
|
63708
63721
|
function getRequestUrlFromClientRequest(request2) {
|
|
63709
63722
|
return String(getRequestUrl(getRequestOptions(request2)));
|
|
@@ -64376,11 +64389,11 @@ function shouldIgnoreSpansForIncomingRequest(request2, {
|
|
|
64376
64389
|
return false;
|
|
64377
64390
|
}
|
|
64378
64391
|
function isStaticAssetRequest(urlPath) {
|
|
64379
|
-
const
|
|
64380
|
-
if (
|
|
64392
|
+
const path18 = stripUrlQueryAndFragment(urlPath);
|
|
64393
|
+
if (path18.match(/\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {
|
|
64381
64394
|
return true;
|
|
64382
64395
|
}
|
|
64383
|
-
if (
|
|
64396
|
+
if (path18.match(/^\/(robots\.txt|sitemap\.xml|manifest\.json|browserconfig\.xml)$/)) {
|
|
64384
64397
|
return true;
|
|
64385
64398
|
}
|
|
64386
64399
|
return false;
|
|
@@ -64621,11 +64634,11 @@ function isKnownPrefetchRequest2(req) {
|
|
|
64621
64634
|
return req.headers["next-router-prefetch"] === "1";
|
|
64622
64635
|
}
|
|
64623
64636
|
function isStaticAssetRequest2(urlPath) {
|
|
64624
|
-
const
|
|
64625
|
-
if (
|
|
64637
|
+
const path18 = stripUrlQueryAndFragment(urlPath);
|
|
64638
|
+
if (path18.match(/\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {
|
|
64626
64639
|
return true;
|
|
64627
64640
|
}
|
|
64628
|
-
if (
|
|
64641
|
+
if (path18.match(/^\/(robots\.txt|sitemap\.xml|manifest\.json|browserconfig\.xml)$/)) {
|
|
64629
64642
|
return true;
|
|
64630
64643
|
}
|
|
64631
64644
|
return false;
|
|
@@ -64985,19 +64998,19 @@ function getBreadcrumbData(request2) {
|
|
|
64985
64998
|
return {};
|
|
64986
64999
|
}
|
|
64987
65000
|
}
|
|
64988
|
-
function getAbsoluteUrl2(origin,
|
|
65001
|
+
function getAbsoluteUrl2(origin, path18 = "/") {
|
|
64989
65002
|
try {
|
|
64990
|
-
const url2 = new URL(
|
|
65003
|
+
const url2 = new URL(path18, origin);
|
|
64991
65004
|
return url2.toString();
|
|
64992
65005
|
} catch {
|
|
64993
65006
|
const url2 = `${origin}`;
|
|
64994
|
-
if (url2.endsWith("/") &&
|
|
64995
|
-
return `${url2}${
|
|
65007
|
+
if (url2.endsWith("/") && path18.startsWith("/")) {
|
|
65008
|
+
return `${url2}${path18.slice(1)}`;
|
|
64996
65009
|
}
|
|
64997
|
-
if (!url2.endsWith("/") && !
|
|
64998
|
-
return `${url2}/${
|
|
65010
|
+
if (!url2.endsWith("/") && !path18.startsWith("/")) {
|
|
65011
|
+
return `${url2}/${path18}`;
|
|
64999
65012
|
}
|
|
65000
|
-
return `${url2}${
|
|
65013
|
+
return `${url2}${path18}`;
|
|
65001
65014
|
}
|
|
65002
65015
|
}
|
|
65003
65016
|
|
|
@@ -65242,15 +65255,15 @@ function getRequestMethod(original) {
|
|
|
65242
65255
|
}
|
|
65243
65256
|
return "_OTHER";
|
|
65244
65257
|
}
|
|
65245
|
-
function getAbsoluteUrl3(origin,
|
|
65258
|
+
function getAbsoluteUrl3(origin, path18 = "/") {
|
|
65246
65259
|
const url2 = `${origin}`;
|
|
65247
|
-
if (url2.endsWith("/") &&
|
|
65248
|
-
return `${url2}${
|
|
65260
|
+
if (url2.endsWith("/") && path18.startsWith("/")) {
|
|
65261
|
+
return `${url2}${path18.slice(1)}`;
|
|
65249
65262
|
}
|
|
65250
|
-
if (!url2.endsWith("/") && !
|
|
65251
|
-
return `${url2}/${
|
|
65263
|
+
if (!url2.endsWith("/") && !path18.startsWith("/")) {
|
|
65264
|
+
return `${url2}/${path18}`;
|
|
65252
65265
|
}
|
|
65253
|
-
return `${url2}${
|
|
65266
|
+
return `${url2}${path18}`;
|
|
65254
65267
|
}
|
|
65255
65268
|
|
|
65256
65269
|
// ../../node_modules/.pnpm/@sentry+node-core@10.71.0_@opentelemetry+api@1.9.1_@opentelemetry+core@2.10.0_@opentele_e57ddc8c682f93a270df4265a143e64e/node_modules/@sentry/node-core/build/esm/integrations/node-fetch/index.js
|
|
@@ -67736,12 +67749,12 @@ function emplace(map2, key, contents) {
|
|
|
67736
67749
|
}
|
|
67737
67750
|
return value;
|
|
67738
67751
|
}
|
|
67739
|
-
function shouldSkipContextLinesForFile(
|
|
67740
|
-
if (
|
|
67741
|
-
if (
|
|
67742
|
-
if (
|
|
67743
|
-
if (
|
|
67744
|
-
if (
|
|
67752
|
+
function shouldSkipContextLinesForFile(path18) {
|
|
67753
|
+
if (path18.startsWith("node:")) return true;
|
|
67754
|
+
if (path18.endsWith(".min.js")) return true;
|
|
67755
|
+
if (path18.endsWith(".min.cjs")) return true;
|
|
67756
|
+
if (path18.endsWith(".min.mjs")) return true;
|
|
67757
|
+
if (path18.startsWith("data:")) return true;
|
|
67745
67758
|
return false;
|
|
67746
67759
|
}
|
|
67747
67760
|
function shouldSkipContextLinesForFrame(frame) {
|
|
@@ -67789,9 +67802,9 @@ function makeLineReaderRanges(lines, linecontext) {
|
|
|
67789
67802
|
}
|
|
67790
67803
|
return out;
|
|
67791
67804
|
}
|
|
67792
|
-
function getContextLinesFromFile(
|
|
67805
|
+
function getContextLinesFromFile(path18, ranges, output) {
|
|
67793
67806
|
return new Promise((resolve2, _reject) => {
|
|
67794
|
-
const stream = createReadStream(
|
|
67807
|
+
const stream = createReadStream(path18);
|
|
67795
67808
|
const lineReaded = createInterface({
|
|
67796
67809
|
input: stream
|
|
67797
67810
|
});
|
|
@@ -67809,8 +67822,8 @@ function getContextLinesFromFile(path19, ranges, output) {
|
|
|
67809
67822
|
let rangeStart = range[0];
|
|
67810
67823
|
let rangeEnd = range[1];
|
|
67811
67824
|
function onStreamError(e) {
|
|
67812
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
67813
|
-
DEBUG_BUILD2 && debug.error(`Failed to read file: ${
|
|
67825
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path18, 1);
|
|
67826
|
+
DEBUG_BUILD2 && debug.error(`Failed to read file: ${path18}. Error: ${e}`);
|
|
67814
67827
|
lineReaded.close();
|
|
67815
67828
|
lineReaded.removeAllListeners();
|
|
67816
67829
|
destroyStreamAndResolve();
|
|
@@ -69249,8 +69262,8 @@ function getSpotlightConfig(optionsSpotlight) {
|
|
|
69249
69262
|
|
|
69250
69263
|
// ../../node_modules/.pnpm/@sentry+node-core@10.71.0_@opentelemetry+api@1.9.1_@opentelemetry+core@2.10.0_@opentele_e57ddc8c682f93a270df4265a143e64e/node_modules/@sentry/node-core/build/esm/utils/module.js
|
|
69251
69264
|
import { posix, sep } from "node:path";
|
|
69252
|
-
function normalizeWindowsPath(
|
|
69253
|
-
return
|
|
69265
|
+
function normalizeWindowsPath(path18) {
|
|
69266
|
+
return path18.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
69254
69267
|
}
|
|
69255
69268
|
function createGetModuleFromFilename(basePath = process.argv[1] ? dirname(process.argv[1]) : process.cwd(), isWindows = sep === "\\") {
|
|
69256
69269
|
const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
|
|
@@ -72122,22 +72135,22 @@ function addSpanSource(span, loc, start, end) {
|
|
|
72122
72135
|
span.setAttribute(AttributeNames2.SOURCE, source);
|
|
72123
72136
|
}
|
|
72124
72137
|
}
|
|
72125
|
-
function createFieldIfNotExists(contextValue, info,
|
|
72126
|
-
let field = getField(contextValue,
|
|
72138
|
+
function createFieldIfNotExists(contextValue, info, path18) {
|
|
72139
|
+
let field = getField(contextValue, path18);
|
|
72127
72140
|
if (field) {
|
|
72128
72141
|
return { field, spanAdded: false };
|
|
72129
72142
|
}
|
|
72130
|
-
const parentSpan = getParentFieldSpan(contextValue,
|
|
72143
|
+
const parentSpan = getParentFieldSpan(contextValue, path18);
|
|
72131
72144
|
field = {
|
|
72132
|
-
span: createResolverSpan(contextValue, info,
|
|
72145
|
+
span: createResolverSpan(contextValue, info, path18, parentSpan)
|
|
72133
72146
|
};
|
|
72134
|
-
addField(contextValue,
|
|
72147
|
+
addField(contextValue, path18, field);
|
|
72135
72148
|
return { field, spanAdded: true };
|
|
72136
72149
|
}
|
|
72137
|
-
function createResolverSpan(contextValue, info,
|
|
72150
|
+
function createResolverSpan(contextValue, info, path18, parentSpan) {
|
|
72138
72151
|
const attributes = {
|
|
72139
72152
|
[AttributeNames2.FIELD_NAME]: info.fieldName,
|
|
72140
|
-
[AttributeNames2.FIELD_PATH]:
|
|
72153
|
+
[AttributeNames2.FIELD_PATH]: path18.join("."),
|
|
72141
72154
|
[AttributeNames2.FIELD_TYPE]: info.returnType.toString(),
|
|
72142
72155
|
[AttributeNames2.PARENT_NAME]: info.parentType.name
|
|
72143
72156
|
};
|
|
@@ -72169,15 +72182,15 @@ function getOperation(document2, operationName) {
|
|
|
72169
72182
|
return document2.definitions.find((definition) => OPERATION_VALUES.indexOf(definition?.operation) !== -1);
|
|
72170
72183
|
}
|
|
72171
72184
|
}
|
|
72172
|
-
function addField(contextValue,
|
|
72173
|
-
return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[
|
|
72185
|
+
function addField(contextValue, path18, field) {
|
|
72186
|
+
return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[path18.join(".")] = field;
|
|
72174
72187
|
}
|
|
72175
|
-
function getField(contextValue,
|
|
72176
|
-
return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[
|
|
72188
|
+
function getField(contextValue, path18) {
|
|
72189
|
+
return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].fields[path18.join(".")];
|
|
72177
72190
|
}
|
|
72178
|
-
function getParentFieldSpan(contextValue,
|
|
72179
|
-
for (let i =
|
|
72180
|
-
const field = getField(contextValue,
|
|
72191
|
+
function getParentFieldSpan(contextValue, path18) {
|
|
72192
|
+
for (let i = path18.length - 1; i > 0; i--) {
|
|
72193
|
+
const field = getField(contextValue, path18.slice(0, i));
|
|
72181
72194
|
if (field) {
|
|
72182
72195
|
return field.span;
|
|
72183
72196
|
}
|
|
@@ -72187,9 +72200,9 @@ function getParentFieldSpan(contextValue, path19) {
|
|
|
72187
72200
|
function getRootSpan2(contextValue) {
|
|
72188
72201
|
return contextValue[OTEL_GRAPHQL_DATA_SYMBOL].span;
|
|
72189
72202
|
}
|
|
72190
|
-
function pathToArray(
|
|
72203
|
+
function pathToArray(path18) {
|
|
72191
72204
|
const flattened = [];
|
|
72192
|
-
let curr =
|
|
72205
|
+
let curr = path18;
|
|
72193
72206
|
while (curr) {
|
|
72194
72207
|
flattened.push(String(curr.key));
|
|
72195
72208
|
curr = curr.prev;
|
|
@@ -72330,8 +72343,8 @@ function wrapFieldResolver(getConfig3, fieldResolver, isDefaultResolver = false)
|
|
|
72330
72343
|
if (!contextValue[OTEL_GRAPHQL_DATA_SYMBOL]) {
|
|
72331
72344
|
return fieldResolver.call(this, source, args, contextValue, info);
|
|
72332
72345
|
}
|
|
72333
|
-
const
|
|
72334
|
-
const { field, spanAdded } = createFieldIfNotExists(contextValue, info,
|
|
72346
|
+
const path18 = pathToArray(info?.path);
|
|
72347
|
+
const { field, spanAdded } = createFieldIfNotExists(contextValue, info, path18);
|
|
72335
72348
|
const span = field.span;
|
|
72336
72349
|
const shouldEndSpan = spanAdded;
|
|
72337
72350
|
return withActiveSpan(span, () => {
|
|
@@ -75314,10 +75327,10 @@ var PostgresJsInstrumentation = class extends import_instrumentation24.Instrumen
|
|
|
75314
75327
|
},
|
|
75315
75328
|
(exports) => exports
|
|
75316
75329
|
);
|
|
75317
|
-
["src", "cf/src", "cjs/src"].forEach((
|
|
75330
|
+
["src", "cf/src", "cjs/src"].forEach((path18) => {
|
|
75318
75331
|
module2.files.push(
|
|
75319
75332
|
new InstrumentationNodeModuleFile(
|
|
75320
|
-
`postgres/${
|
|
75333
|
+
`postgres/${path18}/query.js`,
|
|
75321
75334
|
SUPPORTED_VERSIONS4,
|
|
75322
75335
|
this._patchQueryPrototype.bind(this),
|
|
75323
75336
|
this._unpatchQueryPrototype.bind(this)
|
|
@@ -75948,13 +75961,13 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
|
|
|
75948
75961
|
return function(original) {
|
|
75949
75962
|
return function wrappedHandler(...args) {
|
|
75950
75963
|
if (typeof args[0] === "string") {
|
|
75951
|
-
const
|
|
75964
|
+
const path18 = args[0];
|
|
75952
75965
|
if (args.length === 1) {
|
|
75953
|
-
return original.apply(this, [
|
|
75966
|
+
return original.apply(this, [path18]);
|
|
75954
75967
|
}
|
|
75955
75968
|
const handlers2 = args.slice(1);
|
|
75956
75969
|
return original.apply(this, [
|
|
75957
|
-
|
|
75970
|
+
path18,
|
|
75958
75971
|
...handlers2.map((handler) => instrumentation._wrapHandler(handler))
|
|
75959
75972
|
]);
|
|
75960
75973
|
}
|
|
@@ -75988,13 +76001,13 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
|
|
|
75988
76001
|
return function(original) {
|
|
75989
76002
|
return function wrappedHandler(...args) {
|
|
75990
76003
|
if (typeof args[0] === "string") {
|
|
75991
|
-
const
|
|
76004
|
+
const path18 = args[0];
|
|
75992
76005
|
if (args.length === 1) {
|
|
75993
|
-
return original.apply(this, [
|
|
76006
|
+
return original.apply(this, [path18]);
|
|
75994
76007
|
}
|
|
75995
76008
|
const handlers2 = args.slice(1);
|
|
75996
76009
|
return original.apply(this, [
|
|
75997
|
-
|
|
76010
|
+
path18,
|
|
75998
76011
|
...handlers2.map((handler) => instrumentation._wrapHandler(handler))
|
|
75999
76012
|
]);
|
|
76000
76013
|
}
|
|
@@ -76014,8 +76027,8 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
|
|
|
76014
76027
|
if (!instrumentation.isEnabled()) {
|
|
76015
76028
|
return handler.apply(this, [c, next]);
|
|
76016
76029
|
}
|
|
76017
|
-
const
|
|
76018
|
-
const span = instrumentation.tracer.startSpan(
|
|
76030
|
+
const path18 = c.req.path;
|
|
76031
|
+
const span = instrumentation.tracer.startSpan(path18);
|
|
76019
76032
|
return context.with(trace.setSpan(context.active(), span), () => {
|
|
76020
76033
|
return instrumentation._safeExecute(
|
|
76021
76034
|
() => {
|
|
@@ -76025,7 +76038,7 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
|
|
|
76025
76038
|
const type = instrumentation._determineHandlerType(result2);
|
|
76026
76039
|
span.setAttributes({
|
|
76027
76040
|
[AttributeNames5.HONO_TYPE]: type,
|
|
76028
|
-
[AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ?
|
|
76041
|
+
[AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ? path18 : handler.name || "anonymous"
|
|
76029
76042
|
});
|
|
76030
76043
|
instrumentation.getConfig().responseHook?.(span);
|
|
76031
76044
|
return result2;
|
|
@@ -76034,7 +76047,7 @@ var HonoInstrumentation = class extends import_instrumentation27.Instrumentation
|
|
|
76034
76047
|
const type = instrumentation._determineHandlerType(result);
|
|
76035
76048
|
span.setAttributes({
|
|
76036
76049
|
[AttributeNames5.HONO_TYPE]: type,
|
|
76037
|
-
[AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ?
|
|
76050
|
+
[AttributeNames5.HONO_NAME]: type === HonoTypes.REQUEST_HANDLER ? path18 : handler.name || "anonymous"
|
|
76038
76051
|
});
|
|
76039
76052
|
instrumentation.getConfig().responseHook?.(span);
|
|
76040
76053
|
return result;
|
|
@@ -76238,11 +76251,11 @@ var KoaInstrumentation = class extends import_instrumentation29.InstrumentationB
|
|
|
76238
76251
|
const router = dispatchLayer.router;
|
|
76239
76252
|
const routesStack = router?.stack ?? [];
|
|
76240
76253
|
for (const pathLayer of routesStack) {
|
|
76241
|
-
const
|
|
76254
|
+
const path18 = pathLayer.path;
|
|
76242
76255
|
const pathStack = pathLayer.stack;
|
|
76243
76256
|
for (let j = 0; j < pathStack.length; j++) {
|
|
76244
76257
|
const routedMiddleware = pathStack[j];
|
|
76245
|
-
pathStack[j] = this._patchLayer(routedMiddleware, true,
|
|
76258
|
+
pathStack[j] = this._patchLayer(routedMiddleware, true, path18);
|
|
76246
76259
|
}
|
|
76247
76260
|
}
|
|
76248
76261
|
return dispatchLayer;
|
|
@@ -78558,6 +78571,23 @@ var storedCredentialsSchema = external_exports.object({
|
|
|
78558
78571
|
* alongside the owners. Absent = the org has no list — the owner check
|
|
78559
78572
|
* decides (and pre-list enrollments read the same way). */
|
|
78560
78573
|
allowedRepos: external_exports.array(external_exports.string()).optional(),
|
|
78574
|
+
/** org-repos mode: per-workspace claim policies across every workspace
|
|
78575
|
+
* the member belongs to (home first), refreshed every sync — the union
|
|
78576
|
+
* an offline pass still filters with. Absent = cached before routing;
|
|
78577
|
+
* the flat fields above are the whole boundary. */
|
|
78578
|
+
workspacePolicies: external_exports.array(
|
|
78579
|
+
external_exports.object({
|
|
78580
|
+
orgId: external_exports.string().min(1),
|
|
78581
|
+
name: external_exports.string(),
|
|
78582
|
+
owners: external_exports.array(external_exports.string()),
|
|
78583
|
+
repos: external_exports.array(external_exports.string()).nullable(),
|
|
78584
|
+
/** This entry's claims were UNRESOLVED when cached (a linked
|
|
78585
|
+
* installation whose account failed to resolve, nothing usable to
|
|
78586
|
+
* stand in) — unknown, never "claims nothing". A pass reading only
|
|
78587
|
+
* the cache must not stamp a deep sweep done over it. */
|
|
78588
|
+
unresolved: external_exports.literal(true).optional()
|
|
78589
|
+
})
|
|
78590
|
+
).optional(),
|
|
78561
78591
|
/** Folders this member explicitly chose. Under scope mode they are the
|
|
78562
78592
|
* whole boundary (never empty — enrollment requires at least one); under
|
|
78563
78593
|
* org-repos they are additions on top of the org policy
|
|
@@ -78583,7 +78613,7 @@ function parseStoredCredentials(raw, appEnv) {
|
|
|
78583
78613
|
const parsed = storedCredentialsSchema.safeParse(json2);
|
|
78584
78614
|
if (!parsed.success) {
|
|
78585
78615
|
throw new InvalidStoredCredentialsError(
|
|
78586
|
-
`Stored sync service credentials for ${appEnv} are invalid (corrupted or from an incompatible version)
|
|
78616
|
+
`Stored sync service credentials for ${appEnv} are invalid (corrupted or from an incompatible version), re-enroll this machine (powerplant enroll, or pnpm collector enroll from the checkout)`
|
|
78587
78617
|
);
|
|
78588
78618
|
}
|
|
78589
78619
|
return parsed.data;
|
|
@@ -78645,14 +78675,14 @@ function fallbackFile(appEnv) {
|
|
|
78645
78675
|
|
|
78646
78676
|
// ../../apps/collector/src/enroll.ts
|
|
78647
78677
|
import { spawn } from "node:child_process";
|
|
78648
|
-
import { randomBytes } from "node:crypto";
|
|
78678
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
78649
78679
|
import http5 from "node:http";
|
|
78650
78680
|
import os6 from "node:os";
|
|
78651
78681
|
|
|
78652
78682
|
// ../../apps/collector/src/http.ts
|
|
78653
78683
|
var import_undici = __toESM(require_undici(), 1);
|
|
78654
78684
|
var CLI_VERSION_HEADER = "x-powerplant-cli-version";
|
|
78655
|
-
var cliVersion = true ? "0.
|
|
78685
|
+
var cliVersion = true ? "0.4.1" : "0.0.0-checkout";
|
|
78656
78686
|
function cliVersionHeaders() {
|
|
78657
78687
|
return { [CLI_VERSION_HEADER]: cliVersion, "user-agent": `powerplant-cli/${cliVersion}` };
|
|
78658
78688
|
}
|
|
@@ -78668,11 +78698,11 @@ function installHttp1Transport() {
|
|
|
78668
78698
|
}
|
|
78669
78699
|
async function fetchWithRetry(operation, url2, init3, options = {}) {
|
|
78670
78700
|
const settled = (status) => status < 500 || status === 503 && options.treat503AsFinal === true;
|
|
78671
|
-
const wrapped = (cause) => new Error(`${operation}: couldn't reach ${new URL(url2).host}
|
|
78701
|
+
const wrapped = (cause) => new Error(`${operation}: couldn't reach ${new URL(url2).host}, ${describeFetchFailure(cause)}`, {
|
|
78672
78702
|
cause
|
|
78673
78703
|
});
|
|
78674
78704
|
const request2 = withVersionHeader(init3);
|
|
78675
|
-
const delaysMs = [250, 1e3];
|
|
78705
|
+
const delaysMs = options.retry === false ? [] : [250, 1e3];
|
|
78676
78706
|
for (const delayMs of delaysMs) {
|
|
78677
78707
|
try {
|
|
78678
78708
|
const response = await fetch(url2, request2);
|
|
@@ -78917,9 +78947,10 @@ function captureDecision(cwd, policy) {
|
|
|
78917
78947
|
}
|
|
78918
78948
|
const repoFullName = policy.repoOf(cwd);
|
|
78919
78949
|
if (repoFullName === null) return { capture: false, reason: "no-github-repo" };
|
|
78920
|
-
const
|
|
78921
|
-
|
|
78922
|
-
|
|
78950
|
+
const claims = policy.workspaceClaims ?? [
|
|
78951
|
+
{ owners: policy.allowedOwners, repos: policy.allowedRepos }
|
|
78952
|
+
];
|
|
78953
|
+
return claims.some((workspace) => workspaceClaimsRepo(repoFullName, workspace)) ? { capture: true, via: "org-policy", repoFullName } : { capture: false, reason: "outside-policy" };
|
|
78923
78954
|
}
|
|
78924
78955
|
}
|
|
78925
78956
|
}
|
|
@@ -78931,9 +78962,6 @@ function memberChoice(cwd, policy) {
|
|
|
78931
78962
|
...repoFullName !== null && { repoFullName }
|
|
78932
78963
|
};
|
|
78933
78964
|
}
|
|
78934
|
-
function ownerOfRepo(repoFullName) {
|
|
78935
|
-
return repoFullName.split("/")[0] ?? "";
|
|
78936
|
-
}
|
|
78937
78965
|
function listSome(values, max = 6) {
|
|
78938
78966
|
return values.length <= max ? values.join(", ") : `${values.slice(0, max).join(", ")} and ${values.length - max} more`;
|
|
78939
78967
|
}
|
|
@@ -78942,8 +78970,11 @@ function describeCapturePolicy(policy) {
|
|
|
78942
78970
|
case "scope":
|
|
78943
78971
|
return `sessions under ${policy.scopePaths.join(", ")}`;
|
|
78944
78972
|
case "org-repos": {
|
|
78945
|
-
const repoPart = policy.allowedRepos !== null ? policy.allowedRepos.length > 0 ? `sessions in the org's allowlisted repos: ${listSome(policy.allowedRepos)}` : "the org's repo allowlist is empty
|
|
78946
|
-
|
|
78973
|
+
const repoPart = policy.allowedRepos !== null ? policy.allowedRepos.length > 0 ? `sessions in the org's allowlisted repos: ${listSome(policy.allowedRepos)}` : "the org's repo allowlist is empty, no repo-based uploads" : policy.allowedOwners.length > 0 ? `sessions in GitHub repos owned by ${policy.allowedOwners.join(", ")}` : "org-owned GitHub repos, but the org has no GitHub integration, so nothing uploads";
|
|
78974
|
+
const claiming = (policy.workspaceClaims ?? []).filter(workspaceClaimsAnyRepo);
|
|
78975
|
+
const severalWorkspaces = (policy.workspaceClaims?.length ?? 0) > 1;
|
|
78976
|
+
const withOthers = severalWorkspaces && claiming.length > 0 ? `${repoPart}, routing each repo to the workspace that syncs it (${listSome(claiming.map((workspace) => workspace.name))})` : repoPart;
|
|
78977
|
+
return policy.memberFolders.length > 0 ? `${withOthers}, plus folders you added: ${policy.memberFolders.join(", ")}` : withOthers;
|
|
78947
78978
|
}
|
|
78948
78979
|
}
|
|
78949
78980
|
}
|
|
@@ -78959,6 +78990,9 @@ function describeStoredCapture(credentials) {
|
|
|
78959
78990
|
mode: "org-repos",
|
|
78960
78991
|
allowedOwners: credentials.allowedOwners ?? [],
|
|
78961
78992
|
allowedRepos: credentials.allowedRepos ?? null,
|
|
78993
|
+
...credentials.workspacePolicies !== void 0 && {
|
|
78994
|
+
workspaceClaims: credentials.workspacePolicies
|
|
78995
|
+
},
|
|
78962
78996
|
memberFolders: credentials.scopePaths ?? [],
|
|
78963
78997
|
repoOf: () => null
|
|
78964
78998
|
});
|
|
@@ -79083,7 +79117,16 @@ async function fetchCapturePolicy(apiUrl, machineToken) {
|
|
|
79083
79117
|
data: external_exports.object({
|
|
79084
79118
|
owners: external_exports.array(external_exports.string()),
|
|
79085
79119
|
repos: external_exports.array(external_exports.string()).nullable(),
|
|
79086
|
-
integration: external_exports.enum(["none", "linked"])
|
|
79120
|
+
integration: external_exports.enum(["none", "linked"]),
|
|
79121
|
+
workspaces: external_exports.array(
|
|
79122
|
+
external_exports.object({
|
|
79123
|
+
orgId: external_exports.string().min(1),
|
|
79124
|
+
name: external_exports.string(),
|
|
79125
|
+
owners: external_exports.array(external_exports.string()),
|
|
79126
|
+
repos: external_exports.array(external_exports.string()).nullable(),
|
|
79127
|
+
integration: external_exports.enum(["none", "linked"])
|
|
79128
|
+
})
|
|
79129
|
+
).optional()
|
|
79087
79130
|
})
|
|
79088
79131
|
}),
|
|
79089
79132
|
await response.json().catch(() => null),
|
|
@@ -79095,6 +79138,7 @@ async function uploadSessions(apiUrl, machineToken, items) {
|
|
|
79095
79138
|
let upserted = 0;
|
|
79096
79139
|
let unchanged = 0;
|
|
79097
79140
|
let outOfPolicy = 0;
|
|
79141
|
+
let deferred = 0;
|
|
79098
79142
|
for (let offset = 0; offset < items.length; offset += MAX_INGEST_BATCH) {
|
|
79099
79143
|
const batch = items.slice(offset, offset + MAX_INGEST_BATCH);
|
|
79100
79144
|
const response = await fetchWithRetry("uploading session metadata", `${apiUrl}/api/ingest/sessions`, {
|
|
@@ -79113,7 +79157,8 @@ async function uploadSessions(apiUrl, machineToken, items) {
|
|
|
79113
79157
|
data: external_exports.object({
|
|
79114
79158
|
upserted: external_exports.number(),
|
|
79115
79159
|
unchanged: external_exports.number(),
|
|
79116
|
-
outOfPolicy: external_exports.number()
|
|
79160
|
+
outOfPolicy: external_exports.number(),
|
|
79161
|
+
deferred: external_exports.number().optional()
|
|
79117
79162
|
})
|
|
79118
79163
|
}),
|
|
79119
79164
|
await response.json().catch(() => null),
|
|
@@ -79122,8 +79167,9 @@ async function uploadSessions(apiUrl, machineToken, items) {
|
|
|
79122
79167
|
upserted += result.data.upserted;
|
|
79123
79168
|
unchanged += result.data.unchanged;
|
|
79124
79169
|
outOfPolicy += result.data.outOfPolicy;
|
|
79170
|
+
deferred += result.data.deferred ?? 0;
|
|
79125
79171
|
}
|
|
79126
|
-
return { upserted, unchanged, outOfPolicy };
|
|
79172
|
+
return { upserted, unchanged, outOfPolicy, deferred };
|
|
79127
79173
|
}
|
|
79128
79174
|
async function uploadBranchFacts(apiUrl, machineToken, facts) {
|
|
79129
79175
|
let recorded = 0;
|
|
@@ -79173,6 +79219,7 @@ async function uploadRawSessions(apiUrl, machineToken, collected, readTranscript
|
|
|
79173
79219
|
uploaded: 0,
|
|
79174
79220
|
skippedTooLarge: 0,
|
|
79175
79221
|
skippedUnchanged: 0,
|
|
79222
|
+
missingMetadata: 0,
|
|
79176
79223
|
failed: [],
|
|
79177
79224
|
unconfigured: false
|
|
79178
79225
|
};
|
|
@@ -79205,6 +79252,10 @@ async function uploadRawSessions(apiUrl, machineToken, collected, readTranscript
|
|
|
79205
79252
|
summary.unconfigured = true;
|
|
79206
79253
|
return summary;
|
|
79207
79254
|
}
|
|
79255
|
+
if (response.status === 404) {
|
|
79256
|
+
summary.missingMetadata += 1;
|
|
79257
|
+
continue;
|
|
79258
|
+
}
|
|
79208
79259
|
if (!response.ok) {
|
|
79209
79260
|
throw new Error(`${response.status}: ${await errorDetail(response)}`);
|
|
79210
79261
|
}
|
|
@@ -79221,7 +79272,6 @@ async function uploadRawSessions(apiUrl, machineToken, collected, readTranscript
|
|
|
79221
79272
|
|
|
79222
79273
|
// ../../apps/collector/src/enroll.ts
|
|
79223
79274
|
var APPROVAL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
79224
|
-
var MAX_DELIVERY_BYTES = 64 * 1024;
|
|
79225
79275
|
var gotrueTokenSchema = external_exports.object({ access_token: external_exports.string().min(1) });
|
|
79226
79276
|
var gotrueErrorSchema = external_exports.object({
|
|
79227
79277
|
error_description: external_exports.string().optional(),
|
|
@@ -79288,11 +79338,12 @@ async function runEnrollment(config2, options) {
|
|
|
79288
79338
|
log: log3
|
|
79289
79339
|
});
|
|
79290
79340
|
let orgPolicy = captureMode === "org-repos" ? await fetchCapturePolicy(config2.apiUrl, result.token) : void 0;
|
|
79291
|
-
|
|
79341
|
+
const anyWorkspaceClaims = (orgPolicy?.workspaces ?? []).some(workspaceClaimsAnyRepo);
|
|
79342
|
+
if (orgPolicy !== void 0 && orgPolicy.owners.length === 0 && orgPolicy.repos === null && !anyWorkspaceClaims) {
|
|
79292
79343
|
if (config2.appEnv === "development") {
|
|
79293
79344
|
const home = normalizeScopePath(os6.homedir());
|
|
79294
79345
|
log3(
|
|
79295
|
-
`No GitHub integration on org "${result.org.name}"
|
|
79346
|
+
`No GitHub integration on org "${result.org.name}", syncing sessions under ${home} (your home folder, local DB only). Re-enroll with --scope <path> to narrow.`
|
|
79296
79347
|
);
|
|
79297
79348
|
captureMode = "scope";
|
|
79298
79349
|
scopePaths = [home];
|
|
@@ -79311,7 +79362,7 @@ async function runEnrollment(config2, options) {
|
|
|
79311
79362
|
throw new ExpectedCliError(
|
|
79312
79363
|
[
|
|
79313
79364
|
`Your org "${result.org.name}" has no GitHub integration yet, so "work = org-owned repos" can't be resolved.`,
|
|
79314
|
-
"If that isn't the org you expected, sign in with your work email
|
|
79365
|
+
"If that isn't the org you expected, sign in with your work email, org membership follows the email's domain.",
|
|
79315
79366
|
"Either:",
|
|
79316
79367
|
` \xB7 connect GitHub in Settings, then re-run: ${options.enrollCommand}`,
|
|
79317
79368
|
" \xB7 or choose the upload boundary by hand:",
|
|
@@ -79320,10 +79371,20 @@ async function runEnrollment(config2, options) {
|
|
|
79320
79371
|
);
|
|
79321
79372
|
}
|
|
79322
79373
|
}
|
|
79374
|
+
const workspacePolicies = orgPolicy?.workspaces?.map((workspace) => ({
|
|
79375
|
+
orgId: workspace.orgId,
|
|
79376
|
+
name: workspace.name,
|
|
79377
|
+
owners: workspace.owners,
|
|
79378
|
+
repos: workspace.repos,
|
|
79379
|
+
// Cached unknownness survives enrollment: an unresolved workspace's
|
|
79380
|
+
// claims are unknown, and the first sweep must not stamp over them.
|
|
79381
|
+
...workspace.integration === "linked" && workspace.owners.length === 0 && workspace.repos === null && { unresolved: true }
|
|
79382
|
+
}));
|
|
79323
79383
|
const policy = captureMode === "org-repos" ? {
|
|
79324
79384
|
mode: "org-repos",
|
|
79325
79385
|
allowedOwners: orgPolicy?.owners ?? [],
|
|
79326
79386
|
allowedRepos: orgPolicy?.repos ?? null,
|
|
79387
|
+
...workspacePolicies !== void 0 && { workspaceClaims: workspacePolicies },
|
|
79327
79388
|
memberFolders: [],
|
|
79328
79389
|
repoOf: () => null
|
|
79329
79390
|
} : { mode: "scope", scopePaths, repoOf: () => null };
|
|
@@ -79338,6 +79399,7 @@ async function runEnrollment(config2, options) {
|
|
|
79338
79399
|
captureMode,
|
|
79339
79400
|
...orgPolicy && { allowedOwners: orgPolicy.owners },
|
|
79340
79401
|
...orgPolicy?.repos != null && { allowedRepos: orgPolicy.repos },
|
|
79402
|
+
...captureMode === "org-repos" && workspacePolicies !== void 0 && { workspacePolicies },
|
|
79341
79403
|
scopePaths
|
|
79342
79404
|
};
|
|
79343
79405
|
const location = saveCredentials(config2.appEnv, credentials);
|
|
@@ -79349,24 +79411,73 @@ async function runEnrollment(config2, options) {
|
|
|
79349
79411
|
);
|
|
79350
79412
|
return credentials;
|
|
79351
79413
|
}
|
|
79352
|
-
async function enroll(config2, options, createAuthClient = gotrueAuthClient) {
|
|
79414
|
+
async function enroll(config2, options, createAuthClient = gotrueAuthClient, listener = {}) {
|
|
79353
79415
|
if (options.email && options.password) {
|
|
79354
79416
|
return enrollWithPassword(config2, options.name, options.email, options.password, createAuthClient);
|
|
79355
79417
|
}
|
|
79356
79418
|
const state = randomBytes(16).toString("base64url");
|
|
79419
|
+
const verifier = randomBytes(32).toString("base64url");
|
|
79357
79420
|
return waitForApproval(
|
|
79358
|
-
enrollApprovalUrl(config2.webUrl,
|
|
79421
|
+
enrollApprovalUrl(config2.webUrl, {
|
|
79422
|
+
name: options.name,
|
|
79423
|
+
state,
|
|
79424
|
+
challenge: challengeFor(verifier),
|
|
79425
|
+
capture: options.capture
|
|
79426
|
+
}),
|
|
79359
79427
|
state,
|
|
79360
|
-
{ log: options.log }
|
|
79428
|
+
{ ...listener, log: options.log, redeem: (code) => redeemApproval(config2.apiUrl, code, verifier) }
|
|
79361
79429
|
);
|
|
79362
79430
|
}
|
|
79363
|
-
|
|
79431
|
+
var challengeFor = (verifier) => createHash("sha256").update(verifier).digest("hex");
|
|
79432
|
+
function enrollApprovalUrl(webUrl, {
|
|
79433
|
+
name,
|
|
79434
|
+
state,
|
|
79435
|
+
challenge,
|
|
79436
|
+
capture
|
|
79437
|
+
}) {
|
|
79364
79438
|
return `${webUrl}/enroll-machine?${new URLSearchParams({
|
|
79365
79439
|
name,
|
|
79366
79440
|
state,
|
|
79441
|
+
challenge,
|
|
79367
79442
|
...capture && { capture: capture.mode, folders: String(capture.folderCount) }
|
|
79368
79443
|
}).toString()}`;
|
|
79369
79444
|
}
|
|
79445
|
+
async function redeemApproval(apiUrl, code, verifier) {
|
|
79446
|
+
const response = await fetchWithRetry(
|
|
79447
|
+
"redeeming the enrollment approval",
|
|
79448
|
+
`${apiUrl}/api/machines/redeem`,
|
|
79449
|
+
{
|
|
79450
|
+
method: "POST",
|
|
79451
|
+
headers: { "content-type": "application/json" },
|
|
79452
|
+
body: JSON.stringify({ code, verifier })
|
|
79453
|
+
},
|
|
79454
|
+
{ retry: false }
|
|
79455
|
+
);
|
|
79456
|
+
if (response.status === 404) {
|
|
79457
|
+
throw new ExpectedCliError(
|
|
79458
|
+
"the API doesn't know how to redeem an enrollment approval yet. It is likely older than this CLI (deploy in progress?). Try again in a minute."
|
|
79459
|
+
);
|
|
79460
|
+
}
|
|
79461
|
+
if (response.status >= 400 && response.status < 500) {
|
|
79462
|
+
const body = await response.json().catch(() => null);
|
|
79463
|
+
throw new ExpectedCliError(`enrollment failed: ${body?.error ?? `the API answered ${response.status}`}`);
|
|
79464
|
+
}
|
|
79465
|
+
return readEnrollmentResponse(response);
|
|
79466
|
+
}
|
|
79467
|
+
async function readEnrollmentResponse(response) {
|
|
79468
|
+
if (response.status !== 201) {
|
|
79469
|
+
const body2 = await response.json().catch(() => null);
|
|
79470
|
+
throw new Error(`enrollment failed (${response.status}): ${body2?.error ?? "no detail"}`);
|
|
79471
|
+
}
|
|
79472
|
+
const body = await response.json().catch(() => null);
|
|
79473
|
+
const enrollment = body?.data;
|
|
79474
|
+
if (!isEnrollResult(enrollment)) {
|
|
79475
|
+
throw new ExpectedCliError(
|
|
79476
|
+
"enrollment answered 201 without the expected machine/org/token. The API is likely older than this CLI (deploy in progress?). Try again in a minute."
|
|
79477
|
+
);
|
|
79478
|
+
}
|
|
79479
|
+
return enrollment;
|
|
79480
|
+
}
|
|
79370
79481
|
async function enrollWithPassword(config2, name, email3, password, createAuthClient) {
|
|
79371
79482
|
const client = createAuthClient(config2.supabaseUrl, config2.supabasePublishableKey);
|
|
79372
79483
|
const { data, error: error52 } = await client.auth.signInWithPassword({ email: email3, password });
|
|
@@ -79378,18 +79489,7 @@ async function enrollWithPassword(config2, name, email3, password, createAuthCli
|
|
|
79378
79489
|
headers: { authorization: `Bearer ${data.session.access_token}`, "content-type": "application/json" },
|
|
79379
79490
|
body: JSON.stringify({ name })
|
|
79380
79491
|
});
|
|
79381
|
-
|
|
79382
|
-
const body2 = await response.json().catch(() => null);
|
|
79383
|
-
throw new Error(`enrollment failed (${response.status}): ${body2?.error ?? "no detail"}`);
|
|
79384
|
-
}
|
|
79385
|
-
const body = await response.json().catch(() => null);
|
|
79386
|
-
const enrollment = body?.data;
|
|
79387
|
-
if (!isEnrollResult(enrollment)) {
|
|
79388
|
-
throw new ExpectedCliError(
|
|
79389
|
-
"enrollment answered 201 without the expected machine/org/token \u2014 the API is likely older than this CLI (deploy in progress?). Try again in a minute."
|
|
79390
|
-
);
|
|
79391
|
-
}
|
|
79392
|
-
return enrollment;
|
|
79492
|
+
return await readEnrollmentResponse(response);
|
|
79393
79493
|
} finally {
|
|
79394
79494
|
await client.auth.signOut({ scope: "local" });
|
|
79395
79495
|
}
|
|
@@ -79398,61 +79498,84 @@ function isEnrollResult(value) {
|
|
|
79398
79498
|
const candidate = value;
|
|
79399
79499
|
return typeof candidate?.machine?.id === "string" && typeof candidate.machine.name === "string" && typeof candidate.org?.id === "string" && typeof candidate.org.name === "string" && typeof candidate.token === "string";
|
|
79400
79500
|
}
|
|
79401
|
-
function waitForApproval(approvalUrl, state, options
|
|
79501
|
+
function waitForApproval(approvalUrl, state, options) {
|
|
79402
79502
|
const {
|
|
79503
|
+
redeem,
|
|
79403
79504
|
port = MACHINE_ENROLL_CALLBACK_PORT,
|
|
79404
79505
|
open = openBrowser,
|
|
79506
|
+
onListening,
|
|
79405
79507
|
timeoutMs = APPROVAL_TIMEOUT_MS,
|
|
79406
79508
|
log: log3 = console.log
|
|
79407
79509
|
} = options;
|
|
79408
79510
|
return new Promise((resolve2, reject) => {
|
|
79409
79511
|
const baseHeaders = { connection: "close" };
|
|
79512
|
+
let redeeming = false;
|
|
79410
79513
|
const server = http5.createServer((request2, response) => {
|
|
79411
|
-
|
|
79514
|
+
const url2 = new URL(request2.url ?? "/", "http://127.0.0.1");
|
|
79515
|
+
if (request2.method !== "GET" || url2.pathname !== MACHINE_ENROLL_CALLBACK_PATH) {
|
|
79412
79516
|
response.writeHead(404, baseHeaders).end();
|
|
79413
79517
|
return;
|
|
79414
79518
|
}
|
|
79415
79519
|
const answer = (status, html, onFlushed) => {
|
|
79416
79520
|
response.writeHead(status, { ...baseHeaders, "content-type": "text/html; charset=utf-8" }).end(html, onFlushed);
|
|
79417
79521
|
};
|
|
79418
|
-
|
|
79419
|
-
|
|
79420
|
-
|
|
79421
|
-
|
|
79422
|
-
|
|
79423
|
-
|
|
79424
|
-
|
|
79425
|
-
|
|
79426
|
-
|
|
79427
|
-
|
|
79428
|
-
|
|
79429
|
-
|
|
79430
|
-
|
|
79431
|
-
|
|
79432
|
-
|
|
79433
|
-
|
|
79434
|
-
|
|
79435
|
-
|
|
79436
|
-
|
|
79437
|
-
|
|
79438
|
-
|
|
79439
|
-
|
|
79440
|
-
const data = delivery.data;
|
|
79522
|
+
if (url2.searchParams.get("state") !== state) {
|
|
79523
|
+
answer(
|
|
79524
|
+
403,
|
|
79525
|
+
approvalAnswerPage(
|
|
79526
|
+
"This isn't the enrollment the terminal is waiting for",
|
|
79527
|
+
"Go back to the terminal that's waiting, open the link it printed, and approve from there."
|
|
79528
|
+
)
|
|
79529
|
+
);
|
|
79530
|
+
return;
|
|
79531
|
+
}
|
|
79532
|
+
const code = url2.searchParams.get("code");
|
|
79533
|
+
if (code === null || code === "") {
|
|
79534
|
+
answer(
|
|
79535
|
+
400,
|
|
79536
|
+
approvalAnswerPage(
|
|
79537
|
+
"The approval couldn't be read",
|
|
79538
|
+
"Close this tab and start over from the terminal."
|
|
79539
|
+
)
|
|
79540
|
+
);
|
|
79541
|
+
return;
|
|
79542
|
+
}
|
|
79543
|
+
if (redeeming) {
|
|
79441
79544
|
answer(
|
|
79545
|
+
409,
|
|
79546
|
+
approvalAnswerPage(
|
|
79547
|
+
"This approval is already being handled",
|
|
79548
|
+
"The terminal is finishing this enrollment. You can close this tab."
|
|
79549
|
+
)
|
|
79550
|
+
);
|
|
79551
|
+
return;
|
|
79552
|
+
}
|
|
79553
|
+
redeeming = true;
|
|
79554
|
+
clearTimeout(timeout);
|
|
79555
|
+
void redeem(code).then(
|
|
79556
|
+
(data) => answer(
|
|
79442
79557
|
200,
|
|
79443
79558
|
approvalAnswerPage(
|
|
79444
79559
|
`${data.machine.name} is enrolled in ${data.org.name}`,
|
|
79445
79560
|
"You can close this tab and return to the terminal."
|
|
79446
79561
|
),
|
|
79447
79562
|
() => finish(() => resolve2(data))
|
|
79448
|
-
)
|
|
79449
|
-
|
|
79563
|
+
),
|
|
79564
|
+
(cause) => answer(
|
|
79565
|
+
500,
|
|
79566
|
+
approvalAnswerPage(
|
|
79567
|
+
"The approval couldn't be completed",
|
|
79568
|
+
"Return to the terminal. It says what went wrong and how to retry."
|
|
79569
|
+
),
|
|
79570
|
+
() => finish(() => reject(cause instanceof Error ? cause : new Error(String(cause))))
|
|
79571
|
+
)
|
|
79572
|
+
);
|
|
79450
79573
|
});
|
|
79451
79574
|
const timeout = setTimeout(
|
|
79452
79575
|
() => finish(
|
|
79453
79576
|
() => reject(
|
|
79454
79577
|
new ExpectedCliError(
|
|
79455
|
-
"enrollment approval timed out after 5 minutes
|
|
79578
|
+
"enrollment approval timed out after 5 minutes, run the same command again to retry"
|
|
79456
79579
|
)
|
|
79457
79580
|
)
|
|
79458
79581
|
),
|
|
@@ -79466,41 +79589,16 @@ function waitForApproval(approvalUrl, state, options = {}) {
|
|
|
79466
79589
|
};
|
|
79467
79590
|
server.once("error", (cause) => finish(() => reject(cause)));
|
|
79468
79591
|
server.listen(port, "127.0.0.1", () => {
|
|
79592
|
+
const address = server.address();
|
|
79593
|
+
if (onListening && address !== null && typeof address === "object") onListening(address.port);
|
|
79469
79594
|
log3(`Open approval page: ${approvalUrl}`);
|
|
79470
79595
|
open(approvalUrl);
|
|
79471
79596
|
});
|
|
79472
79597
|
});
|
|
79473
79598
|
}
|
|
79474
|
-
|
|
79475
|
-
return new Promise((resolve2) => {
|
|
79476
|
-
const chunks = [];
|
|
79477
|
-
let size = 0;
|
|
79478
|
-
request2.on("data", (chunk) => {
|
|
79479
|
-
size += chunk.length;
|
|
79480
|
-
if (size > MAX_DELIVERY_BYTES) {
|
|
79481
|
-
request2.destroy();
|
|
79482
|
-
resolve2(null);
|
|
79483
|
-
return;
|
|
79484
|
-
}
|
|
79485
|
-
chunks.push(chunk);
|
|
79486
|
-
});
|
|
79487
|
-
request2.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
|
|
79488
|
-
request2.on("error", () => resolve2(null));
|
|
79489
|
-
});
|
|
79490
|
-
}
|
|
79491
|
-
function parseDelivery(raw) {
|
|
79492
|
-
if (raw === null) return null;
|
|
79493
|
-
const fields = new URLSearchParams(raw);
|
|
79494
|
-
let data;
|
|
79495
|
-
try {
|
|
79496
|
-
data = JSON.parse(fields.get("data") ?? "");
|
|
79497
|
-
} catch {
|
|
79498
|
-
data = void 0;
|
|
79499
|
-
}
|
|
79500
|
-
return { state: fields.get("state") ?? void 0, data };
|
|
79501
|
-
}
|
|
79599
|
+
var PPLOGO_SVG = '<svg width="20" height="20" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M35.4167 7.5H17.5L3.75 30L17.5 52.5L30 30H17.0833L35.4167 7.5Z" fill="#FFD17A"/><path d="M24.5833 52.5H42.5L56.25 30L42.5 7.5L30 30H42.9167L24.5833 52.5Z" fill="#FFA600"/></svg>';
|
|
79502
79600
|
function approvalAnswerPage(heading, detail) {
|
|
79503
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Powerplant</title
|
|
79601
|
+
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Powerplant</title><style>body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:oklch(98.7% 0.004 250);color:#232422;font-family:"Figtree",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased}main{display:flex;flex-direction:column;align-items:center;gap:0.75rem;max-width:24rem;padding:1.5rem;text-align:center}.mark{display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:1px solid oklch(92.5% 0.006 250);border-radius:0.375rem;background:#ffffff}h1{margin:0;font-size:1.25rem;line-height:1.75rem;font-weight:700}p{margin:0;font-size:0.875rem;line-height:1.5;color:#6a6d69}</style></head><body><main><span class="mark">${PPLOGO_SVG}</span><h1>${escapeHtml(heading)}</h1><p>${escapeHtml(detail)}</p></main></body></html>`;
|
|
79504
79602
|
}
|
|
79505
79603
|
var escapeHtml = (text) => text.replace(/[&<>"']/g, (character) => `&#${character.charCodeAt(0)};`);
|
|
79506
79604
|
function openBrowser(url2) {
|
|
@@ -79514,7 +79612,7 @@ function requireEnrolled(config2, enrollCommand, deps) {
|
|
|
79514
79612
|
const credentials = deps.load(config2.appEnv);
|
|
79515
79613
|
if (!credentials) {
|
|
79516
79614
|
throw new ExpectedCliError(
|
|
79517
|
-
`This machine isn't enrolled for ${config2.appEnv}
|
|
79615
|
+
`This machine isn't enrolled for ${config2.appEnv}, run: ${enrollCommand}`
|
|
79518
79616
|
);
|
|
79519
79617
|
}
|
|
79520
79618
|
return credentials;
|
|
@@ -79543,7 +79641,7 @@ function addFolder(config2, rawPath, enrollCommand, log3, deps = defaultDeps) {
|
|
|
79543
79641
|
});
|
|
79544
79642
|
const org = credentials.orgName ?? "your org";
|
|
79545
79643
|
log3(
|
|
79546
|
-
credentials.captureMode === "org-repos" ? `Sessions under ${folder} will now upload to ${org}
|
|
79644
|
+
credentials.captureMode === "org-repos" ? `Sessions under ${folder} will now upload to ${org}, even outside the org's allowlisted repos.` : `Added ${folder} to this machine's sync boundary.`
|
|
79547
79645
|
);
|
|
79548
79646
|
log3("Takes effect on the next sync pass; run the sync command to apply now.");
|
|
79549
79647
|
}
|
|
@@ -79559,14 +79657,14 @@ function removeFolder(config2, rawPath, enrollCommand, log3, deps = defaultDeps)
|
|
|
79559
79657
|
const remaining = folders.filter((existing) => existing !== folder);
|
|
79560
79658
|
if (credentials.captureMode === "scope" && remaining.length === 0) {
|
|
79561
79659
|
throw new ExpectedCliError(
|
|
79562
|
-
"A --scope enrollment needs at least one folder
|
|
79660
|
+
"A --scope enrollment needs at least one folder, re-enroll to change the sync boundary instead."
|
|
79563
79661
|
);
|
|
79564
79662
|
}
|
|
79565
79663
|
deps.persist(config2.appEnv, {
|
|
79566
79664
|
...credentials,
|
|
79567
79665
|
scopePaths: remaining
|
|
79568
79666
|
});
|
|
79569
|
-
log3(`Removed ${folder}
|
|
79667
|
+
log3(`Removed ${folder}, sessions there stay local from the next sync pass.`);
|
|
79570
79668
|
}
|
|
79571
79669
|
|
|
79572
79670
|
// ../../apps/collector/src/protectedRepoDiscovery.ts
|
|
@@ -79705,6 +79803,7 @@ function parseClaudeCodeTranscript(text) {
|
|
|
79705
79803
|
let cwd;
|
|
79706
79804
|
let gitBranch;
|
|
79707
79805
|
let anonCounter = 0;
|
|
79806
|
+
let speedMode;
|
|
79708
79807
|
for (const record2 of parseJsonl(text)) {
|
|
79709
79808
|
if (record2.type === "custom-title" && typeof record2.customTitle === "string") {
|
|
79710
79809
|
title = record2.customTitle;
|
|
@@ -79723,25 +79822,42 @@ function parseClaudeCodeTranscript(text) {
|
|
|
79723
79822
|
const message = record2.message;
|
|
79724
79823
|
if (!message || message.model === "<synthetic>") continue;
|
|
79725
79824
|
const id = message.id ?? (typeof record2.requestId === "string" ? record2.requestId : void 0) ?? (typeof record2.uuid === "string" ? record2.uuid : void 0) ?? `anon-${anonCounter++}`;
|
|
79726
|
-
const
|
|
79727
|
-
|
|
79728
|
-
|
|
79825
|
+
const previousMessage = usageByMessage.get(id);
|
|
79826
|
+
const isNewMessage = previousMessage === void 0;
|
|
79827
|
+
const speedValue = message.usage?.speed;
|
|
79828
|
+
const observedSpeed = speedModeOf(speedValue);
|
|
79829
|
+
const messageSpeed = observedSpeed ?? previousMessage?.speedMode;
|
|
79830
|
+
if (speedValue !== void 0) speedMode = observedSpeed ?? "unknown";
|
|
79831
|
+
if (message.usage) {
|
|
79832
|
+
usageByMessage.set(id, {
|
|
79833
|
+
usage: toUsage(message.usage),
|
|
79834
|
+
...messageSpeed && { speedMode: messageSpeed }
|
|
79835
|
+
});
|
|
79836
|
+
} else if (isNewMessage) {
|
|
79837
|
+
usageByMessage.set(id, {
|
|
79838
|
+
usage: { input: 0, cacheRead: 0, cacheCreation: 0, output: 0 }
|
|
79839
|
+
});
|
|
79840
|
+
}
|
|
79729
79841
|
if (isNewMessage && typeof message.model === "string") {
|
|
79730
79842
|
modelCounts.set(message.model, (modelCounts.get(message.model) ?? 0) + 1);
|
|
79731
79843
|
}
|
|
79732
79844
|
}
|
|
79733
79845
|
if (usageByMessage.size === 0 && timestamps.length === 0) return null;
|
|
79734
|
-
const summed = [...usageByMessage.values()].reduce(addUsage, {
|
|
79846
|
+
const summed = [...usageByMessage.values()].map((entry) => entry.usage).reduce(addUsage, {
|
|
79735
79847
|
input: 0,
|
|
79736
79848
|
cacheRead: 0,
|
|
79737
79849
|
cacheCreation: 0,
|
|
79738
79850
|
output: 0
|
|
79739
79851
|
});
|
|
79852
|
+
const speedFullyMeasured = usageByMessage.size > 0 && [...usageByMessage.values()].every((entry) => entry.speedMode !== void 0);
|
|
79853
|
+
const fastUsage = speedFullyMeasured ? [...usageByMessage.values()].filter((entry) => entry.speedMode === "fast").map((entry) => entry.usage).reduce(addUsage, { input: 0, cacheRead: 0, cacheCreation: 0, output: 0 }) : null;
|
|
79740
79854
|
return {
|
|
79741
79855
|
startedAt: timestamps[0],
|
|
79742
79856
|
endedAt: timestamps[timestamps.length - 1],
|
|
79743
79857
|
model: dominantModel(modelCounts),
|
|
79744
79858
|
usage: usageByMessage.size > 0 ? summed : null,
|
|
79859
|
+
fastUsage,
|
|
79860
|
+
...speedMode && { speedMode },
|
|
79745
79861
|
title,
|
|
79746
79862
|
turnCount: usageByMessage.size,
|
|
79747
79863
|
cwd,
|
|
@@ -79752,9 +79868,13 @@ async function collectClaudeCodeSessions(options = {}) {
|
|
|
79752
79868
|
const claudeDir = options.claudeDir ?? path5.join(os7.homedir(), ".claude");
|
|
79753
79869
|
const now = options.now ?? Date.now();
|
|
79754
79870
|
const capture = options.capture ?? captureEverythingUnresolved;
|
|
79871
|
+
const maxBytes = options.maxTranscriptBytes ?? MAX_TRANSCRIPT_FILE_BYTES;
|
|
79755
79872
|
const projectsDir = path5.join(claudeDir, "projects");
|
|
79756
79873
|
const items = [];
|
|
79757
79874
|
const skips = { skippedOutOfScope: 0, skippedNoRepo: 0 };
|
|
79875
|
+
const candidates = [];
|
|
79876
|
+
const unreadable = [];
|
|
79877
|
+
let skippedTooLarge = 0;
|
|
79758
79878
|
const home = path5.dirname(claudeDir);
|
|
79759
79879
|
const lifecycle = options.lifecycle ?? readLifecycleJournal(home);
|
|
79760
79880
|
for (const projectDir of listDirs(projectsDir)) {
|
|
@@ -79764,39 +79884,76 @@ async function collectClaudeCodeSessions(options = {}) {
|
|
|
79764
79884
|
const stat = statIfExists(transcriptPath);
|
|
79765
79885
|
if (!stat) continue;
|
|
79766
79886
|
if (options.sinceMs !== void 0 && stat.mtimeMs < options.sinceMs) continue;
|
|
79887
|
+
if (stat.size > maxBytes) {
|
|
79888
|
+
skippedTooLarge += 1;
|
|
79889
|
+
continue;
|
|
79890
|
+
}
|
|
79767
79891
|
const sessionId = path5.basename(entry, ".jsonl");
|
|
79768
79892
|
const endObservedAt = observedSessionEnd(lifecycle.get(sessionId), stat.mtimeMs);
|
|
79769
79893
|
const status = endObservedAt === null && now - stat.mtimeMs < ACTIVE_GRACE_MS ? "active" : "inactive";
|
|
79770
|
-
|
|
79894
|
+
try {
|
|
79771
79895
|
const cwd = transcriptCwd(transcriptPath);
|
|
79772
|
-
const
|
|
79773
|
-
if (!
|
|
79774
|
-
countCaptureSkip(skips,
|
|
79896
|
+
const decision = captureDecision(cwd, capture);
|
|
79897
|
+
if (!decision.capture) {
|
|
79898
|
+
countCaptureSkip(skips, decision.reason);
|
|
79775
79899
|
continue;
|
|
79776
79900
|
}
|
|
79777
|
-
|
|
79778
|
-
|
|
79901
|
+
if (options.locationsOnly) {
|
|
79902
|
+
items.push({
|
|
79903
|
+
mtimeMs: stat.mtimeMs,
|
|
79904
|
+
transcriptPath,
|
|
79905
|
+
...cwd && { cwd },
|
|
79906
|
+
item: { source: "claude-code", externalId: sessionId, status, capturedVia: decision.via }
|
|
79907
|
+
});
|
|
79908
|
+
continue;
|
|
79909
|
+
}
|
|
79910
|
+
candidates.push({
|
|
79779
79911
|
transcriptPath,
|
|
79912
|
+
projectDir,
|
|
79913
|
+
sessionId,
|
|
79914
|
+
mtimeMs: stat.mtimeMs,
|
|
79915
|
+
status,
|
|
79916
|
+
endObservedAt,
|
|
79780
79917
|
...cwd && { cwd },
|
|
79781
|
-
|
|
79918
|
+
decision
|
|
79782
79919
|
});
|
|
79783
|
-
|
|
79920
|
+
} catch (error52) {
|
|
79921
|
+
unreadable.push(`${sessionId}: ${describeReadError(error52)}`);
|
|
79784
79922
|
}
|
|
79923
|
+
}
|
|
79924
|
+
}
|
|
79925
|
+
if (options.locationsOnly) {
|
|
79926
|
+
return {
|
|
79927
|
+
sessions: items.sort((a, b2) => b2.mtimeMs - a.mtimeMs),
|
|
79928
|
+
...skips,
|
|
79929
|
+
skippedTooLarge,
|
|
79930
|
+
unreadable,
|
|
79931
|
+
heldBack: 0
|
|
79932
|
+
};
|
|
79933
|
+
}
|
|
79934
|
+
candidates.sort((a, b2) => b2.mtimeMs - a.mtimeMs);
|
|
79935
|
+
const chosen = options.maxSessions === void 0 ? candidates : candidates.slice(0, options.maxSessions);
|
|
79936
|
+
for (const candidate of chosen) {
|
|
79937
|
+
await yieldToEventLoop();
|
|
79938
|
+
const { transcriptPath, projectDir, sessionId, mtimeMs, status, endObservedAt, cwd, decision } = candidate;
|
|
79939
|
+
try {
|
|
79785
79940
|
const text = readIfExists2(transcriptPath);
|
|
79786
79941
|
if (text === null) continue;
|
|
79787
79942
|
const summary = parseClaudeCodeTranscript(text);
|
|
79788
79943
|
if (!summary) continue;
|
|
79789
|
-
const
|
|
79790
|
-
|
|
79791
|
-
|
|
79792
|
-
|
|
79793
|
-
|
|
79794
|
-
|
|
79944
|
+
const usage = addSubagentUsage(
|
|
79945
|
+
summary.usage,
|
|
79946
|
+
summary.fastUsage,
|
|
79947
|
+
path5.join(projectDir, sessionId, "subagents"),
|
|
79948
|
+
{ maxBytes, sessionId }
|
|
79949
|
+
);
|
|
79950
|
+
skippedTooLarge += usage.skippedTooLarge;
|
|
79951
|
+
unreadable.push(...usage.unreadable);
|
|
79795
79952
|
const endedAt = endObservedAt ?? summary.endedAt;
|
|
79796
79953
|
items.push({
|
|
79797
|
-
mtimeMs
|
|
79954
|
+
mtimeMs,
|
|
79798
79955
|
transcriptPath,
|
|
79799
|
-
...
|
|
79956
|
+
...cwd && { cwd },
|
|
79800
79957
|
item: {
|
|
79801
79958
|
source: "claude-code",
|
|
79802
79959
|
externalId: sessionId,
|
|
@@ -79804,28 +79961,42 @@ async function collectClaudeCodeSessions(options = {}) {
|
|
|
79804
79961
|
...summary.startedAt && { startedAt: summary.startedAt },
|
|
79805
79962
|
...endedAt && { endedAt },
|
|
79806
79963
|
...summary.model && { model: summary.model },
|
|
79964
|
+
...summary.speedMode && { speedMode: summary.speedMode },
|
|
79807
79965
|
// Total input-class tokens the source reported (uncached + cache
|
|
79808
79966
|
// reads + cache writes) — a real reported total, not an estimate.
|
|
79809
79967
|
// The cache breakdown rides along: pricing bills reads at 0.1×
|
|
79810
79968
|
// and writes at 1.25×, so collapsing it would inflate estimates.
|
|
79811
|
-
...usage && {
|
|
79812
|
-
|
|
79813
|
-
|
|
79814
|
-
...usage && {
|
|
79969
|
+
...usage.total && {
|
|
79970
|
+
inputTokens: usage.total.input + usage.total.cacheRead + usage.total.cacheCreation
|
|
79971
|
+
},
|
|
79972
|
+
...usage.total && { outputTokens: usage.total.output },
|
|
79973
|
+
...usage.total && { cacheReadTokens: usage.total.cacheRead },
|
|
79974
|
+
...usage.total && { cacheWriteTokens: usage.total.cacheCreation },
|
|
79975
|
+
...usage.fast && {
|
|
79976
|
+
fastInputTokens: usage.fast.input + usage.fast.cacheRead + usage.fast.cacheCreation,
|
|
79977
|
+
fastOutputTokens: usage.fast.output,
|
|
79978
|
+
fastCacheReadTokens: usage.fast.cacheRead,
|
|
79979
|
+
fastCacheWriteTokens: usage.fast.cacheCreation
|
|
79980
|
+
},
|
|
79815
79981
|
...summary.title && { title: redactText(summary.title).slice(0, 500) },
|
|
79816
79982
|
// The PR-join coordinates: the checkout's directory name (bare
|
|
79817
79983
|
// repo, not the local path) and the branch the work started on.
|
|
79818
|
-
...
|
|
79984
|
+
...cwd && { repoDir: path5.basename(cwd) },
|
|
79819
79985
|
...summary.gitBranch && { gitBranch: summary.gitBranch },
|
|
79820
79986
|
...decision.repoFullName && { repoFullName: decision.repoFullName },
|
|
79821
79987
|
capturedVia: decision.via
|
|
79822
79988
|
}
|
|
79823
79989
|
});
|
|
79990
|
+
} catch (error52) {
|
|
79991
|
+
unreadable.push(`${sessionId}: ${describeReadError(error52)}`);
|
|
79824
79992
|
}
|
|
79825
79993
|
}
|
|
79826
79994
|
return {
|
|
79827
79995
|
sessions: items.sort((a, b2) => b2.mtimeMs - a.mtimeMs),
|
|
79828
|
-
...skips
|
|
79996
|
+
...skips,
|
|
79997
|
+
skippedTooLarge,
|
|
79998
|
+
unreadable,
|
|
79999
|
+
heldBack: candidates.length - chosen.length
|
|
79829
80000
|
};
|
|
79830
80001
|
}
|
|
79831
80002
|
function transcriptCwd(transcriptPath) {
|
|
@@ -79844,6 +80015,9 @@ function toUsage(u) {
|
|
|
79844
80015
|
output: n(u.output_tokens)
|
|
79845
80016
|
};
|
|
79846
80017
|
}
|
|
80018
|
+
function speedModeOf(value) {
|
|
80019
|
+
return value === "fast" || value === "standard" ? value : void 0;
|
|
80020
|
+
}
|
|
79847
80021
|
function addUsage(a, b2) {
|
|
79848
80022
|
return {
|
|
79849
80023
|
input: a.input + b2.input,
|
|
@@ -79852,15 +80026,36 @@ function addUsage(a, b2) {
|
|
|
79852
80026
|
output: a.output + b2.output
|
|
79853
80027
|
};
|
|
79854
80028
|
}
|
|
79855
|
-
function addSubagentUsage(main2, subagentsDir) {
|
|
79856
|
-
let
|
|
80029
|
+
function addSubagentUsage(main2, mainFast, subagentsDir, bounds) {
|
|
80030
|
+
let total = main2;
|
|
80031
|
+
let fast = mainFast;
|
|
80032
|
+
let fastCoverageComplete = main2 === null || mainFast !== null;
|
|
80033
|
+
let skippedTooLarge = 0;
|
|
80034
|
+
const unreadable = [];
|
|
79857
80035
|
for (const entry of listFiles(subagentsDir, ".jsonl")) {
|
|
79858
|
-
const
|
|
79859
|
-
|
|
79860
|
-
|
|
79861
|
-
|
|
80036
|
+
const sidecarPath = path5.join(subagentsDir, entry);
|
|
80037
|
+
try {
|
|
80038
|
+
const stat = statIfExists(sidecarPath);
|
|
80039
|
+
if (stat === null) continue;
|
|
80040
|
+
if (stat.size > bounds.maxBytes) {
|
|
80041
|
+
skippedTooLarge += 1;
|
|
80042
|
+
continue;
|
|
80043
|
+
}
|
|
80044
|
+
const text = readIfExists2(sidecarPath);
|
|
80045
|
+
if (text === null) continue;
|
|
80046
|
+
const summary = parseClaudeCodeTranscript(text);
|
|
80047
|
+
if (summary?.usage) {
|
|
80048
|
+
total = addUsage(total ?? { input: 0, cacheRead: 0, cacheCreation: 0, output: 0 }, summary.usage);
|
|
80049
|
+
if (summary.fastUsage === null) fastCoverageComplete = false;
|
|
80050
|
+
}
|
|
80051
|
+
if (summary?.fastUsage) {
|
|
80052
|
+
fast = addUsage(fast ?? { input: 0, cacheRead: 0, cacheCreation: 0, output: 0 }, summary.fastUsage);
|
|
80053
|
+
}
|
|
80054
|
+
} catch (error52) {
|
|
80055
|
+
unreadable.push(`${bounds.sessionId} (subagent ${entry}): ${describeReadError(error52)}`);
|
|
80056
|
+
}
|
|
79862
80057
|
}
|
|
79863
|
-
return
|
|
80058
|
+
return { total, fast: fastCoverageComplete ? fast : null, skippedTooLarge, unreadable };
|
|
79864
80059
|
}
|
|
79865
80060
|
function dominantModel(counts) {
|
|
79866
80061
|
let best;
|
|
@@ -79879,6 +80074,10 @@ function parseCodexRollout(text) {
|
|
|
79879
80074
|
let meta3 = null;
|
|
79880
80075
|
let model;
|
|
79881
80076
|
let totals = null;
|
|
80077
|
+
let fastTotals = { input: 0, cached: 0, output: 0 };
|
|
80078
|
+
let speedMode;
|
|
80079
|
+
let fastCoverageComplete = true;
|
|
80080
|
+
let classifiedUsage = false;
|
|
79882
80081
|
const timestamps = [];
|
|
79883
80082
|
for (const line of parseJsonl(text)) {
|
|
79884
80083
|
if (typeof line.timestamp === "string") timestamps.push(line.timestamp);
|
|
@@ -79889,15 +80088,38 @@ function parseCodexRollout(text) {
|
|
|
79889
80088
|
meta3 ??= record2;
|
|
79890
80089
|
} else if (line.type === "turn_context" && typeof record2.model === "string") {
|
|
79891
80090
|
model = record2.model;
|
|
80091
|
+
} else if (line.type === "event_msg" && record2.type === "thread_settings_applied") {
|
|
80092
|
+
const settings = record2.thread_settings;
|
|
80093
|
+
if (settings && typeof settings === "object" && !Array.isArray(settings)) {
|
|
80094
|
+
const tier = settings.service_tier;
|
|
80095
|
+
if (tier !== void 0) speedMode = codexSpeedMode(tier) ?? "unknown";
|
|
80096
|
+
}
|
|
79892
80097
|
} else if (line.type === "event_msg" && record2.type === "token_count") {
|
|
79893
80098
|
const info = record2.info;
|
|
79894
80099
|
const usage = info?.total_token_usage;
|
|
79895
80100
|
if (usage) {
|
|
79896
80101
|
const n = (value) => typeof value === "number" ? value : 0;
|
|
79897
|
-
|
|
79898
|
-
|
|
79899
|
-
|
|
79900
|
-
|
|
80102
|
+
const next = {
|
|
80103
|
+
input: n(usage.input_tokens),
|
|
80104
|
+
cached: n(usage.cached_input_tokens),
|
|
80105
|
+
output: n(usage.output_tokens)
|
|
80106
|
+
};
|
|
80107
|
+
const previous = totals ?? { input: 0, cached: 0, output: 0 };
|
|
80108
|
+
const delta = {
|
|
80109
|
+
input: Math.max(0, next.input - previous.input),
|
|
80110
|
+
cached: Math.max(0, next.cached - previous.cached),
|
|
80111
|
+
output: Math.max(0, next.output - previous.output)
|
|
80112
|
+
};
|
|
80113
|
+
if (delta.input > 0 || delta.cached > 0 || delta.output > 0) {
|
|
80114
|
+
if (speedMode === "fast" || speedMode === "standard") classifiedUsage = true;
|
|
80115
|
+
else fastCoverageComplete = false;
|
|
80116
|
+
if (speedMode === "fast") fastTotals = addCodexTotals(fastTotals, delta);
|
|
80117
|
+
}
|
|
80118
|
+
totals = {
|
|
80119
|
+
input: Math.max(previous.input, next.input),
|
|
80120
|
+
cached: Math.max(previous.cached, next.cached),
|
|
80121
|
+
output: Math.max(previous.output, next.output)
|
|
80122
|
+
};
|
|
79901
80123
|
}
|
|
79902
80124
|
}
|
|
79903
80125
|
}
|
|
@@ -79911,6 +80133,8 @@ function parseCodexRollout(text) {
|
|
|
79911
80133
|
endedAt: timestamps[timestamps.length - 1],
|
|
79912
80134
|
...model && { model },
|
|
79913
80135
|
totals,
|
|
80136
|
+
fastTotals: fastCoverageComplete && classifiedUsage ? fastTotals : null,
|
|
80137
|
+
...speedMode && { speedMode },
|
|
79914
80138
|
...typeof meta3?.cwd === "string" && meta3.cwd !== "" && { cwd: meta3.cwd },
|
|
79915
80139
|
...typeof git?.branch === "string" && git.branch !== "" && { gitBranch: git.branch },
|
|
79916
80140
|
...repoNameFromUrl(git?.repository_url) ?? {},
|
|
@@ -79924,14 +80148,23 @@ function parseRolloutFile(rolloutPath) {
|
|
|
79924
80148
|
function rolloutLocation(rolloutPath) {
|
|
79925
80149
|
const record2 = readFirstRecord(rolloutPath, (candidate) => candidate.type === "session_meta");
|
|
79926
80150
|
const meta3 = record2?.payload;
|
|
79927
|
-
if (!meta3 || typeof meta3 !== "object" || Array.isArray(meta3)) return { kind: "session", totals: null };
|
|
80151
|
+
if (!meta3 || typeof meta3 !== "object" || Array.isArray(meta3)) return { kind: "session", totals: null, fastTotals: null };
|
|
79928
80152
|
const { thread_source: threadSource, cwd } = meta3;
|
|
79929
80153
|
return {
|
|
79930
80154
|
kind: threadSource === "subagent" ? "subagent" : "session",
|
|
79931
80155
|
totals: null,
|
|
80156
|
+
fastTotals: null,
|
|
79932
80157
|
...typeof cwd === "string" && cwd !== "" && { cwd }
|
|
79933
80158
|
};
|
|
79934
80159
|
}
|
|
80160
|
+
function codexSpeedMode(value) {
|
|
80161
|
+
if (value === "priority" || value === "fast") return "fast";
|
|
80162
|
+
if (value === "default") return "standard";
|
|
80163
|
+
return void 0;
|
|
80164
|
+
}
|
|
80165
|
+
function addCodexTotals(a, b2) {
|
|
80166
|
+
return { input: a.input + b2.input, cached: a.cached + b2.cached, output: a.output + b2.output };
|
|
80167
|
+
}
|
|
79935
80168
|
function repoFullNameFrom(url2) {
|
|
79936
80169
|
const fullName = parseGithubRepo(url2);
|
|
79937
80170
|
return fullName ? { repoFullName: fullName } : {};
|
|
@@ -80062,6 +80295,7 @@ async function collectCodexSessions(options = {}) {
|
|
|
80062
80295
|
...summary.startedAt && { startedAt: summary.startedAt },
|
|
80063
80296
|
...summary.endedAt && { endedAt: summary.endedAt },
|
|
80064
80297
|
...summary.model && { model: summary.model },
|
|
80298
|
+
...summary.speedMode && { speedMode: summary.speedMode },
|
|
80065
80299
|
...title && { title: redactText(title).slice(0, 500) },
|
|
80066
80300
|
// input_tokens already includes the cached subset — it IS the
|
|
80067
80301
|
// all-in input-class total. No cache-write figure exists, so
|
|
@@ -80069,6 +80303,12 @@ async function collectCodexSessions(options = {}) {
|
|
|
80069
80303
|
...summary.totals && { inputTokens: summary.totals.input },
|
|
80070
80304
|
...summary.totals && { outputTokens: summary.totals.output },
|
|
80071
80305
|
...summary.totals && { cacheReadTokens: summary.totals.cached },
|
|
80306
|
+
...summary.fastTotals && { fastInputTokens: summary.fastTotals.input },
|
|
80307
|
+
...summary.fastTotals && { fastOutputTokens: summary.fastTotals.output },
|
|
80308
|
+
...summary.fastTotals && { fastCacheReadTokens: summary.fastTotals.cached },
|
|
80309
|
+
// OpenAI prompt-cache writes have no separate price in the current
|
|
80310
|
+
// session cost model; zero is measured here, not an invented count.
|
|
80311
|
+
...summary.fastTotals && { fastCacheWriteTokens: 0 },
|
|
80072
80312
|
...repoDir && { repoDir },
|
|
80073
80313
|
...summary.gitBranch && { gitBranch: summary.gitBranch },
|
|
80074
80314
|
...repoFullName && { repoFullName },
|
|
@@ -80090,7 +80330,7 @@ async function collectCodexSessions(options = {}) {
|
|
|
80090
80330
|
}
|
|
80091
80331
|
|
|
80092
80332
|
// ../../apps/collector/src/cursorLocal.ts
|
|
80093
|
-
import { createHash } from "node:crypto";
|
|
80333
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
80094
80334
|
import { mkdirSync as mkdirSync2, utimesSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
80095
80335
|
import os9 from "node:os";
|
|
80096
80336
|
import path7 from "node:path";
|
|
@@ -80117,6 +80357,8 @@ var emptyResult = () => ({
|
|
|
80117
80357
|
skippedSubagentComposers: 0,
|
|
80118
80358
|
skippedNonLocalComposers: 0,
|
|
80119
80359
|
skippedUnreadable: 0,
|
|
80360
|
+
skippedTooLarge: 0,
|
|
80361
|
+
truncatedTranscripts: 0,
|
|
80120
80362
|
unavailable: null
|
|
80121
80363
|
});
|
|
80122
80364
|
var SQLITE_EXPERIMENTAL_WARNING = "SQLite is an experimental feature and might change at any time";
|
|
@@ -80144,9 +80386,6 @@ async function openCursorDatabase(dbPath) {
|
|
|
80144
80386
|
const sqlite = await loadSqlite();
|
|
80145
80387
|
return new sqlite.DatabaseSync(dbPath, { readOnly: true });
|
|
80146
80388
|
}
|
|
80147
|
-
function describeError(error52) {
|
|
80148
|
-
return error52 instanceof Error ? error52.message : String(error52);
|
|
80149
|
-
}
|
|
80150
80389
|
function isRecord3(value) {
|
|
80151
80390
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
80152
80391
|
}
|
|
@@ -80160,7 +80399,7 @@ function safeJsonRecord2(text) {
|
|
|
80160
80399
|
}
|
|
80161
80400
|
function spoolFileName(composerId) {
|
|
80162
80401
|
const sanitized = composerId.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 80);
|
|
80163
|
-
const hash2 =
|
|
80402
|
+
const hash2 = createHash2("sha256").update(composerId).digest("hex").slice(0, 8);
|
|
80164
80403
|
return `${sanitized}-${hash2}.jsonl`;
|
|
80165
80404
|
}
|
|
80166
80405
|
function workspaceFolderOf(cursorUserDir, workspaceId) {
|
|
@@ -80221,6 +80460,8 @@ function toolFilePathOf(args) {
|
|
|
80221
80460
|
}
|
|
80222
80461
|
return void 0;
|
|
80223
80462
|
}
|
|
80463
|
+
var SPOOL_META_RESERVE_BYTES = 64 * 1024;
|
|
80464
|
+
var lineBytes = (line) => Buffer.byteLength(JSON.stringify(line)) + 1;
|
|
80224
80465
|
function bubbleLines(bubble) {
|
|
80225
80466
|
const lines = [];
|
|
80226
80467
|
const createdAt = typeof bubble.createdAt === "string" ? { createdAt: bubble.createdAt } : {};
|
|
@@ -80260,43 +80501,50 @@ function bubbleLines(bubble) {
|
|
|
80260
80501
|
}
|
|
80261
80502
|
return lines;
|
|
80262
80503
|
}
|
|
80263
|
-
function extractTranscript(db, composerId) {
|
|
80504
|
+
function extractTranscript(db, composerId, maxBytes) {
|
|
80264
80505
|
const valueByKey = db.prepare("select value from cursorDiskKV where key = ?");
|
|
80265
80506
|
const dataRow = valueByKey.get(`composerData:${composerId}`);
|
|
80266
80507
|
const dataText = isRecord3(dataRow) && typeof dataRow.value === "string" ? dataRow.value : null;
|
|
80267
80508
|
const data = dataText === null ? null : safeJsonRecord2(dataText);
|
|
80268
80509
|
const spine = Array.isArray(data?.fullConversationHeadersOnly) ? data.fullConversationHeadersOnly : [];
|
|
80269
80510
|
if (spine.length === 0) return null;
|
|
80511
|
+
const budget = maxBytes - SPOOL_META_RESERVE_BYTES;
|
|
80270
80512
|
const lines = [];
|
|
80271
80513
|
const modelCounts = /* @__PURE__ */ new Map();
|
|
80514
|
+
let bytes = 0;
|
|
80272
80515
|
let bubbleCount = 0;
|
|
80273
|
-
|
|
80516
|
+
let bubblesOmitted = 0;
|
|
80517
|
+
for (const [index, entry] of spine.entries()) {
|
|
80274
80518
|
if (!isRecord3(entry) || typeof entry.bubbleId !== "string") continue;
|
|
80275
80519
|
const row = valueByKey.get(`bubbleId:${composerId}:${entry.bubbleId}`);
|
|
80276
80520
|
const text = isRecord3(row) && typeof row.value === "string" ? row.value : null;
|
|
80277
80521
|
const bubble = text === null ? null : safeJsonRecord2(text);
|
|
80278
80522
|
if (bubble === null) continue;
|
|
80523
|
+
const bubbleLinesOut = bubbleLines(bubble);
|
|
80524
|
+
const bubbleBytes = bubbleLinesOut.reduce((sum2, line) => sum2 + lineBytes(line), 0);
|
|
80525
|
+
if (bytes + bubbleBytes > budget) {
|
|
80526
|
+
bubblesOmitted = spine.length - index;
|
|
80527
|
+
break;
|
|
80528
|
+
}
|
|
80529
|
+
bytes += bubbleBytes;
|
|
80279
80530
|
bubbleCount += 1;
|
|
80280
|
-
for (const line of
|
|
80531
|
+
for (const line of bubbleLinesOut) {
|
|
80281
80532
|
lines.push(line);
|
|
80282
80533
|
if (line.type === "agent" && line.model !== void 0) {
|
|
80283
80534
|
modelCounts.set(line.model, (modelCounts.get(line.model) ?? 0) + 1);
|
|
80284
80535
|
}
|
|
80285
80536
|
}
|
|
80286
80537
|
}
|
|
80287
|
-
if (bubbleCount === 0) return null;
|
|
80538
|
+
if (bubbleCount === 0 && bubblesOmitted === 0) return null;
|
|
80288
80539
|
let model;
|
|
80289
80540
|
let best = 0;
|
|
80290
80541
|
for (const [name, count] of modelCounts) {
|
|
80291
80542
|
if (count > best) [model, best] = [name, count];
|
|
80292
80543
|
}
|
|
80293
|
-
return { lines, ...model && { model }, bubbleCount };
|
|
80544
|
+
return { lines, ...model && { model }, bubbleCount, bubblesOmitted };
|
|
80294
80545
|
}
|
|
80295
80546
|
function readSpoolModel(spoolPath) {
|
|
80296
|
-
const
|
|
80297
|
-
if (text === null) return void 0;
|
|
80298
|
-
const newline = text.indexOf("\n");
|
|
80299
|
-
const record2 = safeJsonRecord2(newline === -1 ? text : text.slice(0, newline));
|
|
80547
|
+
const record2 = readFirstRecord(spoolPath, () => true);
|
|
80300
80548
|
if (record2 === null || record2.type !== "meta" || record2.format !== "cursor-local-transcript") {
|
|
80301
80549
|
return void 0;
|
|
80302
80550
|
}
|
|
@@ -80309,20 +80557,20 @@ async function collectCursorSessions(options = {}) {
|
|
|
80309
80557
|
try {
|
|
80310
80558
|
if (statIfExists(dbPath) === null) return result;
|
|
80311
80559
|
} catch (error52) {
|
|
80312
|
-
result.unavailable = `Cursor's session store isn't readable (${
|
|
80560
|
+
result.unavailable = `Cursor's session store isn't readable (${describeReadError(error52)})`;
|
|
80313
80561
|
return result;
|
|
80314
80562
|
}
|
|
80315
80563
|
let db;
|
|
80316
80564
|
try {
|
|
80317
80565
|
db = await openCursorDatabase(dbPath);
|
|
80318
80566
|
} catch (error52) {
|
|
80319
|
-
result.unavailable = `Cursor's session store couldn't be opened (${
|
|
80567
|
+
result.unavailable = `Cursor's session store couldn't be opened (${describeReadError(error52)})`;
|
|
80320
80568
|
return result;
|
|
80321
80569
|
}
|
|
80322
80570
|
try {
|
|
80323
80571
|
collectFromStore(db, userDir, options, result);
|
|
80324
80572
|
} catch (error52) {
|
|
80325
|
-
result.unavailable = `reading Cursor's session store failed (${
|
|
80573
|
+
result.unavailable = `reading Cursor's session store failed (${describeReadError(error52)})`;
|
|
80326
80574
|
} finally {
|
|
80327
80575
|
try {
|
|
80328
80576
|
db.close();
|
|
@@ -80336,6 +80584,7 @@ function collectFromStore(db, userDir, options, result) {
|
|
|
80336
80584
|
const now = options.now ?? Date.now();
|
|
80337
80585
|
const capture = options.capture ?? captureEverythingUnresolved;
|
|
80338
80586
|
const spoolDir = options.spoolDir ?? cursorSpoolDir(os9.homedir());
|
|
80587
|
+
const maxBytes = options.maxTranscriptBytes ?? MAX_TRANSCRIPT_FILE_BYTES;
|
|
80339
80588
|
let spoolDirReady = false;
|
|
80340
80589
|
const headerRows = db.prepare(
|
|
80341
80590
|
"select composerId, workspaceId, createdAt, lastUpdatedAt, isArchived, isSubagent, value from composerHeaders where lastUpdatedAt >= ? order by lastUpdatedAt desc"
|
|
@@ -80385,10 +80634,15 @@ function collectFromStore(db, userDir, options, result) {
|
|
|
80385
80634
|
const spoolStat = statIfExists(spoolPath);
|
|
80386
80635
|
let model;
|
|
80387
80636
|
if (spoolStat !== null && Math.abs(spoolStat.mtimeMs - lastUpdatedAt) < 1) {
|
|
80637
|
+
if (spoolStat.size > maxBytes) {
|
|
80638
|
+
result.skippedTooLarge += 1;
|
|
80639
|
+
continue;
|
|
80640
|
+
}
|
|
80388
80641
|
model = readSpoolModel(spoolPath);
|
|
80389
80642
|
} else {
|
|
80390
|
-
const transcript = extractTranscript(db, raw.composerId);
|
|
80643
|
+
const transcript = extractTranscript(db, raw.composerId, maxBytes);
|
|
80391
80644
|
if (transcript === null) continue;
|
|
80645
|
+
if (transcript.bubblesOmitted > 0) result.truncatedTranscripts += 1;
|
|
80392
80646
|
model = transcript.model;
|
|
80393
80647
|
const meta3 = {
|
|
80394
80648
|
type: "meta",
|
|
@@ -80400,7 +80654,8 @@ function collectFromStore(db, userDir, options, result) {
|
|
|
80400
80654
|
...model && { model },
|
|
80401
80655
|
...typeof raw.createdAt === "number" && { createdAt: raw.createdAt },
|
|
80402
80656
|
lastUpdatedAt,
|
|
80403
|
-
...cwd && { workspacePath: cwd }
|
|
80657
|
+
...cwd && { workspacePath: cwd },
|
|
80658
|
+
...transcript.bubblesOmitted > 0 && { bubblesOmitted: transcript.bubblesOmitted }
|
|
80404
80659
|
};
|
|
80405
80660
|
if (!spoolDirReady) {
|
|
80406
80661
|
mkdirSync2(spoolDir, { recursive: true });
|
|
@@ -80518,7 +80773,7 @@ function allowProtectedRepoDiscovery(config2, found, environment = {}, deps = de
|
|
|
80518
80773
|
const credentials = deps.load(config2.appEnv);
|
|
80519
80774
|
if (credentials === null || credentials.token !== enrollment.token || credentials.enrolledAt !== enrollment.enrolledAt) {
|
|
80520
80775
|
throw new ExpectedCliError(
|
|
80521
|
-
"This machine's enrollment changed while the folders were being reviewed, so the approval was not saved
|
|
80776
|
+
"This machine's enrollment changed while the folders were being reviewed, so the approval was not saved, run `powerplant init` again to review them."
|
|
80522
80777
|
);
|
|
80523
80778
|
}
|
|
80524
80779
|
const allowedProtectedRoots = [
|
|
@@ -80534,17 +80789,16 @@ function allowProtectedRepoDiscovery(config2, found, environment = {}, deps = de
|
|
|
80534
80789
|
}
|
|
80535
80790
|
|
|
80536
80791
|
// ../../apps/collector/src/hookInstall.ts
|
|
80537
|
-
import { existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
|
|
80792
|
+
import { existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync6, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
80538
80793
|
import os11 from "node:os";
|
|
80539
80794
|
import path9 from "node:path";
|
|
80540
80795
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
80541
|
-
var INBOX_HOOK_FILENAME = "powerplant-inbox.mjs";
|
|
80542
80796
|
var LIFECYCLE_HOOK_FILENAME = "powerplant-session-lifecycle.mjs";
|
|
80543
80797
|
var HOOK_WIRINGS = [
|
|
80544
|
-
{ event: "UserPromptSubmit", script: INBOX_HOOK_FILENAME },
|
|
80545
80798
|
{ event: "SessionStart", script: LIFECYCLE_HOOK_FILENAME },
|
|
80546
80799
|
{ event: "SessionEnd", script: LIFECYCLE_HOOK_FILENAME }
|
|
80547
80800
|
];
|
|
80801
|
+
var RETIRED_HOOK_WIRINGS = [{ event: "UserPromptSubmit", script: "powerplant-inbox.mjs" }];
|
|
80548
80802
|
var HOOK_SCRIPTS = [...new Set(HOOK_WIRINGS.map((wiring) => wiring.script))];
|
|
80549
80803
|
function isOurGroup(group, script) {
|
|
80550
80804
|
return Array.isArray(group.hooks) && group.hooks.some((hook) => typeof hook.command === "string" && hook.command.includes(script));
|
|
@@ -80565,9 +80819,10 @@ function mergeCollectorHooks(settingsText, commandFor) {
|
|
|
80565
80819
|
}
|
|
80566
80820
|
}
|
|
80567
80821
|
const hooks = settings.hooks !== null && typeof settings.hooks === "object" && !Array.isArray(settings.hooks) ? { ...settings.hooks } : {};
|
|
80822
|
+
const groupsOf = (event) => Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
80568
80823
|
let changed = false;
|
|
80569
80824
|
for (const wiring of HOOK_WIRINGS) {
|
|
80570
|
-
const groups =
|
|
80825
|
+
const groups = groupsOf(wiring.event);
|
|
80571
80826
|
const ourGroup = {
|
|
80572
80827
|
hooks: [{ type: "command", command: commandFor(wiring.script), timeout: 5 }]
|
|
80573
80828
|
};
|
|
@@ -80576,6 +80831,14 @@ function mergeCollectorHooks(settingsText, commandFor) {
|
|
|
80576
80831
|
hooks[wiring.event] = [...groups.filter((group) => !isOurGroup(group, wiring.script)), ourGroup];
|
|
80577
80832
|
changed = true;
|
|
80578
80833
|
}
|
|
80834
|
+
for (const retired of RETIRED_HOOK_WIRINGS) {
|
|
80835
|
+
const groups = groupsOf(retired.event);
|
|
80836
|
+
const kept = groups.filter((group) => !isOurGroup(group, retired.script));
|
|
80837
|
+
if (kept.length === groups.length) continue;
|
|
80838
|
+
if (kept.length === 0) delete hooks[retired.event];
|
|
80839
|
+
else hooks[retired.event] = kept;
|
|
80840
|
+
changed = true;
|
|
80841
|
+
}
|
|
80579
80842
|
if (!changed) return { action: "unchanged" };
|
|
80580
80843
|
const next = { ...settings, hooks };
|
|
80581
80844
|
return { action: "write", text: `${JSON.stringify(next, null, 2)}
|
|
@@ -80613,6 +80876,11 @@ function installCollectorHooks(homeDir = os11.homedir()) {
|
|
|
80613
80876
|
mkdirSync3(settingsDir, { recursive: true });
|
|
80614
80877
|
writeFileSync3(settingsPath, merged.text);
|
|
80615
80878
|
}
|
|
80879
|
+
if (merged.action !== "skip") {
|
|
80880
|
+
for (const retired of RETIRED_HOOK_WIRINGS) {
|
|
80881
|
+
rmSync(path9.join(hookDir, retired.script), { force: true });
|
|
80882
|
+
}
|
|
80883
|
+
}
|
|
80616
80884
|
return {
|
|
80617
80885
|
hookDir,
|
|
80618
80886
|
settings: merged.action,
|
|
@@ -80622,7 +80890,7 @@ function installCollectorHooks(homeDir = os11.homedir()) {
|
|
|
80622
80890
|
|
|
80623
80891
|
// ../../apps/collector/src/service.ts
|
|
80624
80892
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
80625
|
-
import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync7, rmSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
80893
|
+
import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync7, rmSync as rmSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
80626
80894
|
import os12 from "node:os";
|
|
80627
80895
|
import path10 from "node:path";
|
|
80628
80896
|
var RESTART_THROTTLE_SECONDS = 60;
|
|
@@ -80653,7 +80921,7 @@ function refuseStaleAppEnvLauncher(env, readLauncher = readLauncherIfExists) {
|
|
|
80653
80921
|
const script = readLauncher(launcherPath(appEnv));
|
|
80654
80922
|
if (script === null || !script.includes("APP_ENV=") || script.includes("POWERPLANT_ENV=")) return;
|
|
80655
80923
|
throw new ExpectedCliError(
|
|
80656
|
-
`This background service was installed before the POWERPLANT_ENV rename and is no longer supported. Remove it with: powerplant uninstall --env ${appEnv}` + (appEnv === "production" ? "
|
|
80924
|
+
`This background service was installed before the POWERPLANT_ENV rename and is no longer supported. Remove it with: powerplant uninstall --env ${appEnv}` + (appEnv === "production" ? ", then powerplant init reinstalls it." : `, then powerplant init --env ${appEnv} reinstalls it if you still need it.`)
|
|
80657
80925
|
);
|
|
80658
80926
|
}
|
|
80659
80927
|
function readLauncherIfExists(launcherFile) {
|
|
@@ -80698,7 +80966,7 @@ function installService(config2, command) {
|
|
|
80698
80966
|
if (!waitForUnload(() => isLoaded(config2.appEnv))) {
|
|
80699
80967
|
const service = `gui/${uid()}/${label(config2.appEnv)}`;
|
|
80700
80968
|
throw new Error(
|
|
80701
|
-
`launchd is still unloading ${label(config2.appEnv)} after ${UNLOAD_WAIT_MS / 1e3}s
|
|
80969
|
+
`launchd is still unloading ${label(config2.appEnv)} after ${UNLOAD_WAIT_MS / 1e3}s, re-run powerplant init, or unload it by hand first: launchctl bootout ${service}`
|
|
80702
80970
|
);
|
|
80703
80971
|
}
|
|
80704
80972
|
const launcher = launcherPath(config2.appEnv);
|
|
@@ -80744,7 +81012,7 @@ function serviceUpToDate(config2, command) {
|
|
|
80744
81012
|
function uninstallService(config2) {
|
|
80745
81013
|
requireMacos();
|
|
80746
81014
|
const existed = bootout(config2.appEnv);
|
|
80747
|
-
|
|
81015
|
+
rmSync2(launcherPath(config2.appEnv), { force: true });
|
|
80748
81016
|
if (existsSync2(plistPath(config2.appEnv))) {
|
|
80749
81017
|
unlinkSync2(plistPath(config2.appEnv));
|
|
80750
81018
|
return true;
|
|
@@ -80814,7 +81082,7 @@ function xmlEscape(value) {
|
|
|
80814
81082
|
}
|
|
80815
81083
|
|
|
80816
81084
|
// ../../apps/collector/src/status.ts
|
|
80817
|
-
import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, renameSync, rmSync as
|
|
81085
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, renameSync, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
80818
81086
|
import os13 from "node:os";
|
|
80819
81087
|
import path11 from "node:path";
|
|
80820
81088
|
var HEARTBEAT_INTERVAL_MS = 6e4;
|
|
@@ -80917,10 +81185,10 @@ function writeCollectorControl(appEnv, control, homeDir) {
|
|
|
80917
81185
|
writeAtomically(controlFilePath(appEnv, homeDir), JSON.stringify(control, null, 2));
|
|
80918
81186
|
}
|
|
80919
81187
|
function clearCollectorControl(appEnv, homeDir) {
|
|
80920
|
-
|
|
81188
|
+
rmSync3(controlFilePath(appEnv, homeDir), { force: true });
|
|
80921
81189
|
}
|
|
80922
81190
|
function clearCollectorStatus(appEnv, homeDir) {
|
|
80923
|
-
|
|
81191
|
+
rmSync3(statusFilePath(appEnv, homeDir), { force: true });
|
|
80924
81192
|
}
|
|
80925
81193
|
function describeDaemonState(read, probes = {}) {
|
|
80926
81194
|
if (read.file === "invalid") return { state: "unreadable" };
|
|
@@ -81093,12 +81361,33 @@ async function resolveCapturePolicy(config2, credentials, log3, deps = defaultPo
|
|
|
81093
81361
|
}
|
|
81094
81362
|
let owners = credentials.allowedOwners ?? [];
|
|
81095
81363
|
let repos = credentials.allowedRepos ?? null;
|
|
81364
|
+
let workspacePolicies = credentials.workspacePolicies;
|
|
81096
81365
|
let ownersUnresolved = false;
|
|
81366
|
+
let claimsUnresolved = false;
|
|
81097
81367
|
try {
|
|
81098
81368
|
const fresh = await deps.fetchPolicy(credentials.apiUrl, credentials.token);
|
|
81099
81369
|
ownersUnresolved = fresh.integration === "linked" && fresh.owners.length === 0;
|
|
81100
81370
|
const nextOwners = ownersUnresolved ? owners : fresh.owners;
|
|
81101
|
-
const
|
|
81371
|
+
const nextWorkspaces = fresh.workspaces?.map((workspace) => {
|
|
81372
|
+
const unresolved = workspace.integration === "linked" && workspace.owners.length === 0 && workspace.repos === null;
|
|
81373
|
+
const cached3 = workspacePolicies?.find((entry) => entry.orgId === workspace.orgId) ?? (credentials.orgId !== void 0 && workspace.orgId === credentials.orgId ? { orgId: workspace.orgId, name: workspace.name, owners, repos } : void 0);
|
|
81374
|
+
const usableCache = cached3 !== void 0 && workspaceClaimsAnyRepo(cached3);
|
|
81375
|
+
const effective = unresolved && usableCache ? cached3 : unresolved ? {
|
|
81376
|
+
orgId: workspace.orgId,
|
|
81377
|
+
name: workspace.name,
|
|
81378
|
+
owners: workspace.owners,
|
|
81379
|
+
repos: workspace.repos,
|
|
81380
|
+
unresolved: true
|
|
81381
|
+
} : {
|
|
81382
|
+
orgId: workspace.orgId,
|
|
81383
|
+
name: workspace.name,
|
|
81384
|
+
owners: workspace.owners,
|
|
81385
|
+
repos: workspace.repos
|
|
81386
|
+
};
|
|
81387
|
+
if (effective.unresolved) claimsUnresolved = true;
|
|
81388
|
+
return effective;
|
|
81389
|
+
});
|
|
81390
|
+
const changed = nextOwners.join(",") !== owners.join(",") || (fresh.repos?.join(",") ?? null) !== (repos?.join(",") ?? null) || JSON.stringify(nextWorkspaces ?? null) !== JSON.stringify(workspacePolicies ?? null);
|
|
81102
81391
|
if (changed) {
|
|
81103
81392
|
const next = {
|
|
81104
81393
|
...credentials,
|
|
@@ -81106,34 +81395,48 @@ async function resolveCapturePolicy(config2, credentials, log3, deps = defaultPo
|
|
|
81106
81395
|
};
|
|
81107
81396
|
if (fresh.repos !== null) next.allowedRepos = fresh.repos;
|
|
81108
81397
|
else delete next.allowedRepos;
|
|
81398
|
+
if (nextWorkspaces !== void 0) next.workspacePolicies = nextWorkspaces;
|
|
81399
|
+
else delete next.workspacePolicies;
|
|
81109
81400
|
deps.persist(config2.appEnv, next);
|
|
81110
81401
|
}
|
|
81111
81402
|
owners = nextOwners;
|
|
81112
81403
|
repos = fresh.repos;
|
|
81404
|
+
workspacePolicies = nextWorkspaces;
|
|
81113
81405
|
} catch (cause) {
|
|
81406
|
+
const cachedCoversSomething = owners.length > 0 || repos !== null || (workspacePolicies ?? []).some((entry) => workspaceClaimsAnyRepo(entry));
|
|
81407
|
+
if (!cachedCoversSomething || (workspacePolicies ?? []).some((entry) => entry.unresolved === true)) {
|
|
81408
|
+
claimsUnresolved = true;
|
|
81409
|
+
}
|
|
81114
81410
|
log3(
|
|
81115
|
-
`\u26A0 Couldn't refresh the org's repo sync policy (${describeSyncError(cause)})
|
|
81411
|
+
`\u26A0 Couldn't refresh the org's repo sync policy (${describeSyncError(cause)}), ` + (cachedCoversSomething ? "using the cached policy." : "nothing will upload this pass.")
|
|
81116
81412
|
);
|
|
81117
81413
|
}
|
|
81118
81414
|
const memberFolders = credentials.scopePaths ?? [];
|
|
81415
|
+
if (ownersUnresolved && owners.length === 0 && repos === null) claimsUnresolved = true;
|
|
81119
81416
|
if (ownersUnresolved) {
|
|
81120
81417
|
log3(
|
|
81121
|
-
"\u26A0 The org's GitHub is connected, but its account couldn't be resolved just now
|
|
81418
|
+
"\u26A0 The org's GitHub is connected, but its account couldn't be resolved just now, " + (owners.length > 0 ? `using the cached owner list: ${owners.join(", ")}.` : "no owner-based uploads this pass. This is usually temporary; syncing resumes when it resolves.")
|
|
81122
81419
|
);
|
|
81123
81420
|
}
|
|
81421
|
+
const homeOrgId = credentials.orgId ?? workspacePolicies?.[0]?.orgId;
|
|
81422
|
+
const foreignClaims = (workspacePolicies ?? []).filter(
|
|
81423
|
+
(entry) => entry.orgId !== homeOrgId && workspaceClaimsAnyRepo(entry)
|
|
81424
|
+
);
|
|
81124
81425
|
if (repos !== null && repos.length === 0) {
|
|
81125
81426
|
log3(
|
|
81126
|
-
"\u26A0 The org's repo allowlist is empty
|
|
81427
|
+
"\u26A0 The org's repo allowlist is empty, no repo-based uploads for it" + (foreignClaims.length > 0 ? `; repos synced by ${foreignClaims.map((entry) => entry.name).join(", ")} still upload.` : memberFolders.length > 0 ? "; only folders you added upload." : ".")
|
|
81127
81428
|
);
|
|
81128
81429
|
} else if (repos === null && owners.length === 0 && !ownersUnresolved) {
|
|
81129
81430
|
log3(
|
|
81130
|
-
"\u26A0 Syncing is gated on org-owned GitHub repos, but the org has no GitHub integration
|
|
81431
|
+
foreignClaims.length > 0 ? `Your home workspace has no GitHub integration, syncing repos for ${foreignClaims.map((entry) => entry.name).join(", ")}.` : "\u26A0 Syncing is gated on org-owned GitHub repos, but the org has no GitHub integration, nothing uploads. Connect GitHub in Settings, or add folders with `powerplant folders add`."
|
|
81131
81432
|
);
|
|
81132
81433
|
}
|
|
81133
81434
|
return {
|
|
81134
81435
|
mode: "org-repos",
|
|
81135
81436
|
allowedOwners: owners,
|
|
81136
81437
|
allowedRepos: repos,
|
|
81438
|
+
...workspacePolicies !== void 0 && { workspaceClaims: workspacePolicies },
|
|
81439
|
+
...claimsUnresolved && { claimsUnresolved },
|
|
81137
81440
|
memberFolders,
|
|
81138
81441
|
repoOf,
|
|
81139
81442
|
environment
|
|
@@ -81144,66 +81447,75 @@ async function runSyncPass(config2, options = {}) {
|
|
|
81144
81447
|
const credentials = loadCredentials(config2.appEnv);
|
|
81145
81448
|
if (!credentials) {
|
|
81146
81449
|
throw new ExpectedCliError(
|
|
81147
|
-
`This machine isn't enrolled for ${config2.appEnv}
|
|
81450
|
+
`This machine isn't enrolled for ${config2.appEnv}, run: ${options.enrollCommand ?? "pnpm collector enroll"}`
|
|
81148
81451
|
);
|
|
81149
81452
|
}
|
|
81150
81453
|
const window2 = resolveSyncWindow(options.explicitSince, credentials.deepSyncedAt);
|
|
81151
81454
|
if (window2.deepSweep) {
|
|
81152
81455
|
log3(
|
|
81153
|
-
`First sync for this enrollment
|
|
81456
|
+
`First sync for this enrollment, sweeping the last ${window2.days} days and backfilling up to the ${DEEP_FIRST_SYNC_MAX_SESSIONS} most recently active sessions already on this machine (later syncs cover ${STEADY_SYNC_WINDOW_DAYS} days).`
|
|
81154
81457
|
);
|
|
81155
81458
|
}
|
|
81156
81459
|
const capture = await resolveCapturePolicy(config2, credentials, log3);
|
|
81157
81460
|
const sinceMs = resolveScanFloor(window2, Date.now(), options.narrowSinceMs);
|
|
81158
81461
|
const maxSessions = window2.deepSweep ? DEEP_FIRST_SYNC_MAX_SESSIONS : void 0;
|
|
81159
|
-
const claude = await collectClaudeCodeSessions({ sinceMs, capture });
|
|
81462
|
+
const claude = await collectClaudeCodeSessions({ sinceMs, capture, maxSessions });
|
|
81160
81463
|
const codex = await collectCodexSessions({ sinceMs, capture, maxSessions });
|
|
81161
81464
|
const cursor = await collectCursorSessions({ sinceMs, capture });
|
|
81162
81465
|
if (cursor.unavailable !== null) {
|
|
81163
|
-
log3(`\u26A0 Cursor sessions skipped this pass
|
|
81466
|
+
log3(`\u26A0 Cursor sessions skipped this pass, ${cursor.unavailable}. Other syncing is unaffected.`);
|
|
81164
81467
|
}
|
|
81165
81468
|
const inWindow = [...claude.sessions, ...codex.sessions, ...cursor.sessions].sort(
|
|
81166
81469
|
(a, b2) => b2.mtimeMs - a.mtimeMs
|
|
81167
81470
|
);
|
|
81168
81471
|
const collected = maxSessions === void 0 ? inWindow : inWindow.slice(0, maxSessions);
|
|
81169
|
-
const heldBack = inWindow.length - collected.length + codex.heldBack;
|
|
81472
|
+
const heldBack = inWindow.length - collected.length + claude.heldBack + codex.heldBack;
|
|
81170
81473
|
const skippedOutOfScope = claude.skippedOutOfScope + codex.skippedOutOfScope + cursor.skippedOutOfScope;
|
|
81171
81474
|
const skippedNoRepo = claude.skippedNoRepo + codex.skippedNoRepo + cursor.skippedNoRepo;
|
|
81172
81475
|
const items = collected.map((c) => c.item);
|
|
81173
81476
|
const active = items.filter((s) => s.status === "active").length;
|
|
81477
|
+
const tooLarge = (count, what) => count > 0 ? ` \xB7 ${count} ${what} skipped (over ${MAX_TRANSCRIPT_FILE_BYTES / (1024 * 1024)}MB, too large to read)` : "";
|
|
81174
81478
|
log3(
|
|
81175
|
-
`Found ${inWindow.length} local session(s) (${claude.sessions.length} claude, ${codex.sessions.length} codex, ${cursor.sessions.length} cursor) ` + describeScanReach(window2, options.narrowSinceMs) + (active > 0 ? ` (${active} still active)` : "") + (skippedOutOfScope > 0 ? ` \xB7 ${skippedOutOfScope} ${describeSkipReason(capture)}` : "") + (skippedNoRepo > 0 ? ` \xB7 ${skippedNoRepo} ${describeNoRepoSkipReason(capture)}` : "") + (codex.skippedSubagentThreads > 0 ? ` \xB7 ${codex.skippedSubagentThreads} codex subagent thread(s) skipped (spend unmeasured)` : "") + (cursor.skippedSubagentComposers > 0 ? ` \xB7 ${cursor.skippedSubagentComposers} cursor subagent thread(s) skipped` : "") + (cursor.skippedNonLocalComposers > 0 ? ` \xB7 ${cursor.skippedNonLocalComposers} cursor session(s) skipped (not local to this machine)` : "") + (cursor.skippedUnreadable > 0 ? ` \xB7 ${cursor.skippedUnreadable} cursor session(s) unreadable, skipped` : "") + (
|
|
81479
|
+
`Found ${inWindow.length} local session(s) (${claude.sessions.length} claude, ${codex.sessions.length} codex, ${cursor.sessions.length} cursor) ` + describeScanReach(window2, options.narrowSinceMs) + (active > 0 ? ` (${active} still active)` : "") + (skippedOutOfScope > 0 ? ` \xB7 ${skippedOutOfScope} ${describeSkipReason(capture)}` : "") + (skippedNoRepo > 0 ? ` \xB7 ${skippedNoRepo} ${describeNoRepoSkipReason(capture)}` : "") + (codex.skippedSubagentThreads > 0 ? ` \xB7 ${codex.skippedSubagentThreads} codex subagent thread(s) skipped (spend unmeasured)` : "") + (cursor.skippedSubagentComposers > 0 ? ` \xB7 ${cursor.skippedSubagentComposers} cursor subagent thread(s) skipped` : "") + (cursor.skippedNonLocalComposers > 0 ? ` \xB7 ${cursor.skippedNonLocalComposers} cursor session(s) skipped (not local to this machine)` : "") + (cursor.skippedUnreadable > 0 ? ` \xB7 ${cursor.skippedUnreadable} cursor session(s) unreadable, skipped` : "") + tooLarge(claude.skippedTooLarge, "claude transcript(s)") + (claude.unreadable.length > 0 ? ` \xB7 ${claude.unreadable.length} claude transcript(s) unreadable, skipped` : "") + tooLarge(codex.skippedTooLarge, "codex rollout(s)") + (codex.unreadable.length > 0 ? ` \xB7 ${codex.unreadable.length} codex rollout(s) unreadable, skipped` : "") + tooLarge(cursor.skippedTooLarge, "cursor transcript(s)") + (cursor.truncatedTranscripts > 0 ? ` \xB7 ${cursor.truncatedTranscripts} cursor transcript(s) cut at ${MAX_TRANSCRIPT_FILE_BYTES / (1024 * 1024)}MB (the rest of the conversation stays local)` : "") + (heldBack > 0 ? ` \xB7 ${heldBack} older session(s) held back, the first sync backfills the ${DEEP_FIRST_SYNC_MAX_SESSIONS} most recently active` : "") + "."
|
|
81176
81480
|
);
|
|
81177
|
-
for (const failure of
|
|
81481
|
+
for (const failure of claude.unreadable) log3(` claude transcript skipped, ${failure}`);
|
|
81482
|
+
for (const failure of codex.unreadable) log3(` codex rollout skipped, ${failure}`);
|
|
81178
81483
|
if (options.dryRun) {
|
|
81179
81484
|
for (const s of items.slice(0, 10)) {
|
|
81180
81485
|
log3(` ${s.externalId} ${s.model ?? "model unmeasured"} ${s.title ?? "(untitled)"}`);
|
|
81181
81486
|
}
|
|
81182
81487
|
if (items.length > 10) log3(` ... and ${items.length - 10} more`);
|
|
81183
|
-
log3("Dry run
|
|
81488
|
+
log3("Dry run, nothing uploaded.");
|
|
81184
81489
|
return { sessions: collected, upserted: 0 };
|
|
81185
81490
|
}
|
|
81186
81491
|
const markDeepSynced = () => {
|
|
81187
81492
|
if (!window2.deepSweep) return;
|
|
81188
81493
|
const current = loadCredentials(config2.appEnv);
|
|
81189
81494
|
if (current === null) {
|
|
81190
|
-
log3("Deep sync finished, but this machine's credentials are gone
|
|
81495
|
+
log3("Deep sync finished, but this machine's credentials are gone, nothing to stamp.");
|
|
81191
81496
|
return;
|
|
81192
81497
|
}
|
|
81193
81498
|
if (current.token !== credentials.token || current.enrolledAt !== credentials.enrolledAt) {
|
|
81194
81499
|
log3(
|
|
81195
|
-
"Deep sync finished for a superseded enrollment
|
|
81500
|
+
"Deep sync finished for a superseded enrollment, the current enrollment still owes its own deep sweep."
|
|
81196
81501
|
);
|
|
81197
81502
|
return;
|
|
81198
81503
|
}
|
|
81199
81504
|
saveCredentials(config2.appEnv, { ...current, deepSyncedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
81200
|
-
log3(`Deep sync complete
|
|
81505
|
+
log3(`Deep sync complete, future syncs cover the last ${STEADY_SYNC_WINDOW_DAYS} days.`);
|
|
81201
81506
|
};
|
|
81507
|
+
const claimsUnresolved = capture.mode === "org-repos" && capture.claimsUnresolved === true;
|
|
81202
81508
|
if (items.length === 0) {
|
|
81203
|
-
|
|
81509
|
+
if (claimsUnresolved) {
|
|
81510
|
+
if (window2.deepSweep) {
|
|
81511
|
+
log3("Deep sync not stamped, a workspace's claims are unresolved; the sweep re-runs next pass.");
|
|
81512
|
+
}
|
|
81513
|
+
} else {
|
|
81514
|
+
markDeepSynced();
|
|
81515
|
+
}
|
|
81204
81516
|
return { sessions: collected, upserted: 0 };
|
|
81205
81517
|
}
|
|
81206
|
-
const { upserted, unchanged, outOfPolicy } = await uploadSessions(
|
|
81518
|
+
const { upserted, unchanged, outOfPolicy, deferred } = await uploadSessions(
|
|
81207
81519
|
credentials.apiUrl,
|
|
81208
81520
|
credentials.token,
|
|
81209
81521
|
items
|
|
@@ -81211,9 +81523,14 @@ async function runSyncPass(config2, options = {}) {
|
|
|
81211
81523
|
log3(
|
|
81212
81524
|
`Uploaded: ${upserted} session(s) upserted` + (unchanged > 0 ? `, ${unchanged} unchanged (no writes issued)` : "") + "."
|
|
81213
81525
|
);
|
|
81526
|
+
if (deferred > 0) {
|
|
81527
|
+
log3(
|
|
81528
|
+
`\u26A0 ${deferred} session(s) deferred, a workspace's GitHub owners couldn't be resolved just now, so routing waited rather than guessing a workspace. They upload on a later pass.`
|
|
81529
|
+
);
|
|
81530
|
+
}
|
|
81214
81531
|
if (outOfPolicy > 0) {
|
|
81215
81532
|
log3(
|
|
81216
|
-
`\u26A0 ${outOfPolicy} session(s) refused by the org's repo sync policy
|
|
81533
|
+
`\u26A0 ${outOfPolicy} session(s) refused by the org's repo sync policy, they stayed out of Powerplant. The next pass refreshes the policy and stops offering them.`
|
|
81217
81534
|
);
|
|
81218
81535
|
}
|
|
81219
81536
|
const registerPreviews = options.registerPreviews ?? registerAnnouncedPreviews;
|
|
@@ -81228,13 +81545,13 @@ async function runSyncPass(config2, options = {}) {
|
|
|
81228
81545
|
}
|
|
81229
81546
|
for (const externalId of previewSummary.foreignOwned) {
|
|
81230
81547
|
log3(
|
|
81231
|
-
`Previews for ${externalId} are registered by another machine
|
|
81548
|
+
`Previews for ${externalId} are registered by another machine, leaving its list in place.`
|
|
81232
81549
|
);
|
|
81233
81550
|
}
|
|
81234
81551
|
for (const externalId of previewSummary.previewsOff) {
|
|
81235
|
-
log3(`Previews for ${externalId} refused
|
|
81552
|
+
log3(`Previews for ${externalId} refused, this organization has previews switched off.`);
|
|
81236
81553
|
}
|
|
81237
|
-
for (const failure of previewSummary.failed) log3(` preview registration failed
|
|
81554
|
+
for (const failure of previewSummary.failed) log3(` preview registration failed, ${failure}`);
|
|
81238
81555
|
try {
|
|
81239
81556
|
const observe = options.observeBranch ? options.observeBranch() : branchObserver({ allowedProtectedRoots: credentials.repoDiscoveryRoots ?? [] });
|
|
81240
81557
|
const facts = branchFactsOf(collected, observe);
|
|
@@ -81244,7 +81561,7 @@ async function runSyncPass(config2, options = {}) {
|
|
|
81244
81561
|
log3(`Branch facts: ${recorded} branch state(s) recorded.`);
|
|
81245
81562
|
}
|
|
81246
81563
|
} catch (cause) {
|
|
81247
|
-
log3(`\u26A0 Branch facts skipped this pass
|
|
81564
|
+
log3(`\u26A0 Branch facts skipped this pass, ${describeSyncError(cause)}`);
|
|
81248
81565
|
}
|
|
81249
81566
|
const rawFloor = rawShipFloorMs(config2.appEnv, Date.now(), options.explicitSince);
|
|
81250
81567
|
const rawEligible = rawFloor === null ? collected : collected.filter((c) => c.mtimeMs >= rawFloor);
|
|
@@ -81257,7 +81574,7 @@ async function runSyncPass(config2, options = {}) {
|
|
|
81257
81574
|
options.rawShipped
|
|
81258
81575
|
);
|
|
81259
81576
|
if (raw.unconfigured) {
|
|
81260
|
-
log3("Raw content: this environment has no raw storage yet
|
|
81577
|
+
log3("Raw content: this environment has no raw storage yet, skipped.");
|
|
81261
81578
|
} else {
|
|
81262
81579
|
const parts = [`${raw.uploaded} uploaded`];
|
|
81263
81580
|
if (raw.skippedUnchanged > 0) parts.push(`${raw.skippedUnchanged} unchanged`);
|
|
@@ -81265,12 +81582,25 @@ async function runSyncPass(config2, options = {}) {
|
|
|
81265
81582
|
if (raw.skippedTooLarge > 0) parts.push(`${raw.skippedTooLarge} skipped (too large)`);
|
|
81266
81583
|
if (raw.failed.length > 0) parts.push(`${raw.failed.length} failed`);
|
|
81267
81584
|
log3(`Raw content: ${parts.join(", ")}.`);
|
|
81268
|
-
for (const failure of raw.failed) log3(` raw upload failed
|
|
81269
|
-
|
|
81585
|
+
for (const failure of raw.failed) log3(` raw upload failed, ${failure}`);
|
|
81586
|
+
if (raw.missingMetadata > 0) {
|
|
81587
|
+
log3(
|
|
81588
|
+
`${raw.missingMetadata} raw transcript(s) waiting on their session metadata, they re-send once it lands.`
|
|
81589
|
+
);
|
|
81590
|
+
}
|
|
81591
|
+
const nothingElseAccountedFor = raw.skippedUnchanged === 0 && raw.skippedTooLarge === 0 && rawWindowSkipped === 0 && raw.missingMetadata === 0;
|
|
81270
81592
|
if (raw.uploaded === 0 && (raw.failed.length > 1 || raw.failed.length === 1 && nothingElseAccountedFor)) {
|
|
81271
|
-
throw new Error(`all ${raw.failed.length} raw upload(s) failed this pass
|
|
81593
|
+
throw new Error(`all ${raw.failed.length} raw upload(s) failed this pass, ${raw.failed[0]}`);
|
|
81594
|
+
}
|
|
81595
|
+
if (deferred > 0 || claimsUnresolved) {
|
|
81596
|
+
if (window2.deepSweep) {
|
|
81597
|
+
log3(
|
|
81598
|
+
deferred > 0 ? "Deep sync not stamped, deferred sessions still owe their upload; the sweep re-runs next pass." : "Deep sync not stamped, a workspace's claims are unresolved; the sweep re-runs next pass."
|
|
81599
|
+
);
|
|
81600
|
+
}
|
|
81601
|
+
} else {
|
|
81602
|
+
markDeepSynced();
|
|
81272
81603
|
}
|
|
81273
|
-
markDeepSynced();
|
|
81274
81604
|
}
|
|
81275
81605
|
return { sessions: collected, upserted };
|
|
81276
81606
|
}
|
|
@@ -81307,293 +81637,9 @@ function unsupportedVersionNotice(cliVersion2, oldestSupportedVersion) {
|
|
|
81307
81637
|
}
|
|
81308
81638
|
|
|
81309
81639
|
// ../../apps/collector/src/watch.ts
|
|
81310
|
-
import { existsSync as
|
|
81640
|
+
import { existsSync as existsSync3, watch as fsWatch } from "node:fs";
|
|
81311
81641
|
import os14 from "node:os";
|
|
81312
|
-
import path14 from "node:path";
|
|
81313
|
-
|
|
81314
|
-
// ../../apps/collector/src/wake.ts
|
|
81315
|
-
import { execFile as execFile2, execFileSync as execFileSync4 } from "node:child_process";
|
|
81316
|
-
import { existsSync as existsSync3 } from "node:fs";
|
|
81317
81642
|
import path13 from "node:path";
|
|
81318
|
-
var WAKE_POLL_MS = 5e3;
|
|
81319
|
-
var WAKE_QUIET_MS = 2 * 6e4;
|
|
81320
|
-
var WAKE_TURN_TIMEOUT_MS = 10 * 6e4;
|
|
81321
|
-
var FETCH_TIMEOUT_MS2 = 5e3;
|
|
81322
|
-
function findClaudeTranscript(homeDir, externalId) {
|
|
81323
|
-
for (const projectDir of listDirs(path13.join(homeDir, ".claude", "projects"))) {
|
|
81324
|
-
const transcript = path13.join(projectDir, `${externalId}.jsonl`);
|
|
81325
|
-
const stat = statIfExists(transcript);
|
|
81326
|
-
if (stat === null) continue;
|
|
81327
|
-
const text = readIfExists2(transcript);
|
|
81328
|
-
if (text === null) continue;
|
|
81329
|
-
for (const record2 of parseJsonl(text)) {
|
|
81330
|
-
if (typeof record2.cwd === "string" && record2.cwd !== "") {
|
|
81331
|
-
return { cwd: record2.cwd, mtimeMs: stat.mtimeMs };
|
|
81332
|
-
}
|
|
81333
|
-
}
|
|
81334
|
-
return null;
|
|
81335
|
-
}
|
|
81336
|
-
return null;
|
|
81337
|
-
}
|
|
81338
|
-
function formatWakePrompt(messages) {
|
|
81339
|
-
const lines = messages.map(
|
|
81340
|
-
(message) => `- From ${message.authorEmail ?? "a teammate"} (sent ${message.createdAt}): ${message.body}`
|
|
81341
|
-
);
|
|
81342
|
-
return [
|
|
81343
|
-
`While this session was idle, ${messages.length === 1 ? "a teammate sent a message" : `teammates sent ${messages.length} messages`} to it via Powerplant:`,
|
|
81344
|
-
...lines,
|
|
81345
|
-
"This prompt was submitted automatically by Powerplant's message delivery \u2014 no one is at the keyboard. Acknowledge the message and act on it as an instruction from that teammate."
|
|
81346
|
-
].join("\n");
|
|
81347
|
-
}
|
|
81348
|
-
function createWakePoller(deps) {
|
|
81349
|
-
const inFlight = /* @__PURE__ */ new Set();
|
|
81350
|
-
let polling = false;
|
|
81351
|
-
let consecutivePollFailures = 0;
|
|
81352
|
-
return {
|
|
81353
|
-
async poll() {
|
|
81354
|
-
if (polling) return;
|
|
81355
|
-
polling = true;
|
|
81356
|
-
try {
|
|
81357
|
-
for (const target of await deps.listPending()) {
|
|
81358
|
-
if (inFlight.has(target.externalId)) continue;
|
|
81359
|
-
const home = deps.inspect(target);
|
|
81360
|
-
if (home === null) continue;
|
|
81361
|
-
if (deps.now() - home.mtimeMs < WAKE_QUIET_MS) continue;
|
|
81362
|
-
const messages = await deps.claim(target);
|
|
81363
|
-
if (messages.length === 0) continue;
|
|
81364
|
-
inFlight.add(target.externalId);
|
|
81365
|
-
deps.log(
|
|
81366
|
-
`waking session ${target.externalId} with ${messages.length} message(s) in ${home.cwd}`
|
|
81367
|
-
);
|
|
81368
|
-
void deps.runClaude(target, formatWakePrompt(messages), home.cwd).then(() => deps.log(`wake finished for session ${target.externalId}`)).catch(
|
|
81369
|
-
(error52) => reportFailedWake(deps, target, messages, describeError2(error52))
|
|
81370
|
-
).finally(() => inFlight.delete(target.externalId));
|
|
81371
|
-
}
|
|
81372
|
-
consecutivePollFailures = 0;
|
|
81373
|
-
} catch (error52) {
|
|
81374
|
-
consecutivePollFailures += 1;
|
|
81375
|
-
deps.log(`\u26A0 wake poll failed (${describeError2(error52)}) \u2014 next poll retries`);
|
|
81376
|
-
if (consecutivePollFailures === REPORT_AFTER_CONSECUTIVE_FAILURES) {
|
|
81377
|
-
deps.reportError?.(error52, "wake-poll", { consecutivePollFailures });
|
|
81378
|
-
}
|
|
81379
|
-
} finally {
|
|
81380
|
-
polling = false;
|
|
81381
|
-
}
|
|
81382
|
-
}
|
|
81383
|
-
};
|
|
81384
|
-
}
|
|
81385
|
-
async function reportFailedWake(deps, target, messages, reason) {
|
|
81386
|
-
deps.log(
|
|
81387
|
-
`\u26A0 wake failed for session ${target.externalId} AFTER its messages were claimed (${reason})`
|
|
81388
|
-
);
|
|
81389
|
-
const messageIds = messages.flatMap((message) => message.id === null ? [] : [message.id]);
|
|
81390
|
-
try {
|
|
81391
|
-
await deps.reportWakeFailure(target, messageIds, reason);
|
|
81392
|
-
deps.log(
|
|
81393
|
-
`wake failure reported for session ${target.externalId} \u2014 its ${messageIds.length} message(s) now read "Not delivered"`
|
|
81394
|
-
);
|
|
81395
|
-
} catch (reportError) {
|
|
81396
|
-
deps.log(
|
|
81397
|
-
`\u26A0 wake failure report for session ${target.externalId} ALSO failed \u2014 its messages read Delivered but no agent ran (${describeError2(reportError)})`
|
|
81398
|
-
);
|
|
81399
|
-
deps.reportError?.(reportError, "wake-failure-report", {
|
|
81400
|
-
externalId: target.externalId,
|
|
81401
|
-
messageCount: messageIds.length
|
|
81402
|
-
});
|
|
81403
|
-
}
|
|
81404
|
-
}
|
|
81405
|
-
function resolveClaudeBin(homeDir, env = process.env) {
|
|
81406
|
-
if (env.POWERPLANT_CLAUDE_BIN) {
|
|
81407
|
-
return existsSync3(env.POWERPLANT_CLAUDE_BIN) ? env.POWERPLANT_CLAUDE_BIN : null;
|
|
81408
|
-
}
|
|
81409
|
-
const candidates = [
|
|
81410
|
-
path13.join(homeDir, ".local", "bin", "claude"),
|
|
81411
|
-
"/opt/homebrew/bin/claude",
|
|
81412
|
-
"/usr/local/bin/claude"
|
|
81413
|
-
];
|
|
81414
|
-
const found = candidates.find((candidate) => existsSync3(candidate));
|
|
81415
|
-
if (found) return found;
|
|
81416
|
-
try {
|
|
81417
|
-
const fromPath = execFileSync4("which", ["claude"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
81418
|
-
return fromPath === "" ? null : fromPath;
|
|
81419
|
-
} catch {
|
|
81420
|
-
return null;
|
|
81421
|
-
}
|
|
81422
|
-
}
|
|
81423
|
-
var WAKE_MIN_CLAUDE_VERSION = "2.1.0";
|
|
81424
|
-
var VERSION_TIMEOUT_MS = 15e3;
|
|
81425
|
-
function versionParts(version2) {
|
|
81426
|
-
return version2.split(".").map(Number);
|
|
81427
|
-
}
|
|
81428
|
-
function versionAtLeast(version2, floor) {
|
|
81429
|
-
const have = versionParts(version2);
|
|
81430
|
-
const need = versionParts(floor);
|
|
81431
|
-
for (let i = 0; i < need.length; i += 1) {
|
|
81432
|
-
const a = have[i] ?? 0;
|
|
81433
|
-
const b2 = need[i] ?? 0;
|
|
81434
|
-
if (a !== b2) return a > b2;
|
|
81435
|
-
}
|
|
81436
|
-
return true;
|
|
81437
|
-
}
|
|
81438
|
-
function execClaudeVersion(claudeBin) {
|
|
81439
|
-
return execFileSync4(claudeBin, ["--version"], {
|
|
81440
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
81441
|
-
timeout: VERSION_TIMEOUT_MS
|
|
81442
|
-
}).toString();
|
|
81443
|
-
}
|
|
81444
|
-
function preflightClaudeVersion(claudeBin, readVersionOutput = execClaudeVersion) {
|
|
81445
|
-
let output;
|
|
81446
|
-
try {
|
|
81447
|
-
output = readVersionOutput(claudeBin);
|
|
81448
|
-
} catch (error52) {
|
|
81449
|
-
return { ok: false, problem: `\`${claudeBin} --version\` failed (${describeError2(error52)})` };
|
|
81450
|
-
}
|
|
81451
|
-
const version2 = /\d+\.\d+\.\d+/.exec(output)?.[0] ?? null;
|
|
81452
|
-
if (version2 === null) {
|
|
81453
|
-
return {
|
|
81454
|
-
ok: false,
|
|
81455
|
-
problem: `\`${claudeBin} --version\` answered "${output.trim()}" \u2014 no version in that`
|
|
81456
|
-
};
|
|
81457
|
-
}
|
|
81458
|
-
if (!versionAtLeast(version2, WAKE_MIN_CLAUDE_VERSION)) {
|
|
81459
|
-
return {
|
|
81460
|
-
ok: false,
|
|
81461
|
-
problem: `claude ${version2} is older than ${WAKE_MIN_CLAUDE_VERSION} \u2014 too old to headlessly resume current transcripts (it hangs until the wake timeout)`
|
|
81462
|
-
};
|
|
81463
|
-
}
|
|
81464
|
-
return { ok: true, version: version2 };
|
|
81465
|
-
}
|
|
81466
|
-
async function collectorApiList(credentials, pathAndQuery, key) {
|
|
81467
|
-
const response = await fetch(`${credentials.apiUrl}${pathAndQuery}`, {
|
|
81468
|
-
headers: { authorization: `Bearer ${credentials.token}`, ...cliVersionHeaders() },
|
|
81469
|
-
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
81470
|
-
});
|
|
81471
|
-
const route = pathAndQuery.split("?")[0];
|
|
81472
|
-
if (!response.ok) throw new Error(`${route} answered ${response.status}`);
|
|
81473
|
-
const envelope = external_exports.object({ data: external_exports.record(external_exports.string(), external_exports.unknown()) }).safeParse(await response.json().catch(() => null));
|
|
81474
|
-
if (!envelope.success) {
|
|
81475
|
-
throw new Error(`${route} answered an unexpected shape: ${zodIssueSummary(envelope.error)}`, {
|
|
81476
|
-
cause: envelope.error
|
|
81477
|
-
});
|
|
81478
|
-
}
|
|
81479
|
-
const list = envelope.data.data[key];
|
|
81480
|
-
if (!Array.isArray(list)) {
|
|
81481
|
-
throw new Error(`${route} answered an unexpected shape: data.${key} is not a list`);
|
|
81482
|
-
}
|
|
81483
|
-
const values = list;
|
|
81484
|
-
return values;
|
|
81485
|
-
}
|
|
81486
|
-
var wakeTargetSchema = external_exports.object({ source: external_exports.string().min(1), externalId: external_exports.string().min(1) });
|
|
81487
|
-
async function fetchWakePending(credentials) {
|
|
81488
|
-
const sessions = await collectorApiList(credentials, "/api/collector/wake-pending", "sessions");
|
|
81489
|
-
return sessions.flatMap((entry) => {
|
|
81490
|
-
const parsed = wakeTargetSchema.safeParse(entry);
|
|
81491
|
-
return parsed.success ? [{ source: parsed.data.source, externalId: parsed.data.externalId }] : [];
|
|
81492
|
-
});
|
|
81493
|
-
}
|
|
81494
|
-
var wakeMessageSchema = external_exports.object({
|
|
81495
|
-
id: external_exports.string().nullable().catch(null),
|
|
81496
|
-
authorEmail: external_exports.string().nullable().catch(null),
|
|
81497
|
-
body: external_exports.string(),
|
|
81498
|
-
createdAt: external_exports.string().catch("")
|
|
81499
|
-
});
|
|
81500
|
-
async function claimInbox(credentials, target) {
|
|
81501
|
-
const messages = await collectorApiList(
|
|
81502
|
-
credentials,
|
|
81503
|
-
`/api/collector/inbox?source=${encodeURIComponent(target.source)}&externalId=${encodeURIComponent(target.externalId)}`,
|
|
81504
|
-
"messages"
|
|
81505
|
-
);
|
|
81506
|
-
return messages.flatMap((entry) => {
|
|
81507
|
-
const parsed = wakeMessageSchema.safeParse(entry);
|
|
81508
|
-
return parsed.success ? [parsed.data] : [];
|
|
81509
|
-
});
|
|
81510
|
-
}
|
|
81511
|
-
async function postWakeFailure(credentials, target, messageIds, reason) {
|
|
81512
|
-
const response = await fetchWithRetry(
|
|
81513
|
-
"reporting a failed wake",
|
|
81514
|
-
`${credentials.apiUrl}/api/collector/wake-failed`,
|
|
81515
|
-
{
|
|
81516
|
-
method: "POST",
|
|
81517
|
-
headers: {
|
|
81518
|
-
authorization: `Bearer ${credentials.token}`,
|
|
81519
|
-
"content-type": "application/json"
|
|
81520
|
-
},
|
|
81521
|
-
body: JSON.stringify({
|
|
81522
|
-
source: target.source,
|
|
81523
|
-
externalId: target.externalId,
|
|
81524
|
-
messageIds,
|
|
81525
|
-
reason
|
|
81526
|
-
})
|
|
81527
|
-
}
|
|
81528
|
-
);
|
|
81529
|
-
if (!response.ok) throw new Error(`/api/collector/wake-failed answered ${response.status}`);
|
|
81530
|
-
}
|
|
81531
|
-
function runClaudeResume(claudeBin, externalId, prompt, cwd) {
|
|
81532
|
-
return new Promise((resolve2, reject) => {
|
|
81533
|
-
const child = execFile2(
|
|
81534
|
-
claudeBin,
|
|
81535
|
-
["-p", "--resume", externalId, prompt],
|
|
81536
|
-
{ cwd, timeout: WAKE_TURN_TIMEOUT_MS, maxBuffer: 16 * 1024 * 1024 },
|
|
81537
|
-
(error52, _stdout, stderr) => error52 ? reject(new Error(describeWakeTurnFailure(error52, stderr))) : resolve2()
|
|
81538
|
-
);
|
|
81539
|
-
child.stdin?.end();
|
|
81540
|
-
});
|
|
81541
|
-
}
|
|
81542
|
-
var STDERR_TAIL_CHARS = 300;
|
|
81543
|
-
function describeWakeTurnFailure(error52, stderr) {
|
|
81544
|
-
const tail = redactText(stderr.trim()).slice(-STDERR_TAIL_CHARS);
|
|
81545
|
-
const base = baseWakeTurnReason(error52);
|
|
81546
|
-
return tail === "" ? base : `${base} \u2014 stderr: ${tail}`;
|
|
81547
|
-
}
|
|
81548
|
-
function baseWakeTurnReason(error52) {
|
|
81549
|
-
if (error52.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER") return error52.message;
|
|
81550
|
-
if (error52.killed) {
|
|
81551
|
-
return `wake turn killed after ${WAKE_TURN_TIMEOUT_MS / 6e4} minutes \u2014 the resumed claude turn never finished`;
|
|
81552
|
-
}
|
|
81553
|
-
if (typeof error52.code === "number") return `claude exited with code ${error52.code}`;
|
|
81554
|
-
if (error52.signal) return `claude died on signal ${error52.signal}`;
|
|
81555
|
-
return error52.message;
|
|
81556
|
-
}
|
|
81557
|
-
function startWakeService(config2, homeDir, log3) {
|
|
81558
|
-
if (process.env.POWERPLANT_WAKE_ON_MESSAGE === "0") {
|
|
81559
|
-
log3("wake-on-message disabled (POWERPLANT_WAKE_ON_MESSAGE=0)");
|
|
81560
|
-
return null;
|
|
81561
|
-
}
|
|
81562
|
-
const credentials = loadCredentials(config2.appEnv);
|
|
81563
|
-
if (credentials === null) {
|
|
81564
|
-
log3("wake-on-message off: machine not enrolled");
|
|
81565
|
-
return null;
|
|
81566
|
-
}
|
|
81567
|
-
const claudeBin = resolveClaudeBin(homeDir);
|
|
81568
|
-
if (claudeBin === null) {
|
|
81569
|
-
log3("wake-on-message off: claude CLI not found (set POWERPLANT_CLAUDE_BIN)");
|
|
81570
|
-
return null;
|
|
81571
|
-
}
|
|
81572
|
-
const preflight = preflightClaudeVersion(claudeBin);
|
|
81573
|
-
if (!preflight.ok) {
|
|
81574
|
-
log3(
|
|
81575
|
-
`wake-on-message off: ${preflight.problem} \u2014 update Claude Code (npm install -g @anthropic-ai/claude-code) or point POWERPLANT_CLAUDE_BIN at a ${WAKE_MIN_CLAUDE_VERSION}+ CLI, then restart the sync service to re-arm wake`
|
|
81576
|
-
);
|
|
81577
|
-
return null;
|
|
81578
|
-
}
|
|
81579
|
-
log3(`wake-on-message claude binary: ${claudeBin} (version ${preflight.version})`);
|
|
81580
|
-
const poller = createWakePoller({
|
|
81581
|
-
listPending: () => fetchWakePending(credentials),
|
|
81582
|
-
claim: (target) => claimInbox(credentials, target),
|
|
81583
|
-
inspect: (target) => findClaudeTranscript(homeDir, target.externalId),
|
|
81584
|
-
runClaude: (target, prompt, cwd) => runClaudeResume(claudeBin, target.externalId, prompt, cwd),
|
|
81585
|
-
reportWakeFailure: (target, messageIds, reason) => postWakeFailure(credentials, target, messageIds, reason),
|
|
81586
|
-
now: Date.now,
|
|
81587
|
-
log: log3,
|
|
81588
|
-
reportError: reportCollectorError
|
|
81589
|
-
});
|
|
81590
|
-
const timer = setInterval(() => void poller.poll(), WAKE_POLL_MS);
|
|
81591
|
-
log3(`wake-on-message armed: polling every ${WAKE_POLL_MS / 1e3}s (${config2.appEnv})`);
|
|
81592
|
-
return () => clearInterval(timer);
|
|
81593
|
-
}
|
|
81594
|
-
function describeError2(error52) {
|
|
81595
|
-
return error52 instanceof Error ? error52.message : String(error52);
|
|
81596
|
-
}
|
|
81597
81643
|
|
|
81598
81644
|
// ../../apps/collector/src/selfRestart.ts
|
|
81599
81645
|
import { statSync as statSync3 } from "node:fs";
|
|
@@ -81631,6 +81677,8 @@ var SAFETY_NET_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
81631
81677
|
var NARROW_OVERLAP_MS = 6e4;
|
|
81632
81678
|
var WATCHER_RETRY_MS = 6e4;
|
|
81633
81679
|
var FAILED_PASS_RETRY_MS = 6e4;
|
|
81680
|
+
var FAILED_PASS_BACKOFF_CAP_MS = 15 * 6e4;
|
|
81681
|
+
var STREAK_REREPORT_INTERVAL_MS = 60 * 6e4;
|
|
81634
81682
|
var VERSION_NOTICE_INTERVAL_MS = 60 * 6e4;
|
|
81635
81683
|
var COMPLETION_SLACK_MS = 3e4;
|
|
81636
81684
|
function createWatchLoop(deps) {
|
|
@@ -81643,6 +81691,10 @@ function createWatchLoop(deps) {
|
|
|
81643
81691
|
let completionTimer = null;
|
|
81644
81692
|
let running = false;
|
|
81645
81693
|
let consecutiveFailures = 0;
|
|
81694
|
+
let streakSignature = null;
|
|
81695
|
+
let streakCount = 0;
|
|
81696
|
+
let streakStartedAt = 0;
|
|
81697
|
+
let streakReportedAt = 0;
|
|
81646
81698
|
let pausedLogged = false;
|
|
81647
81699
|
let queued = null;
|
|
81648
81700
|
let retryNotBefore = 0;
|
|
@@ -81669,7 +81721,7 @@ function createWatchLoop(deps) {
|
|
|
81669
81721
|
if (stopped) return;
|
|
81670
81722
|
try {
|
|
81671
81723
|
closeWatcher = deps.watch(onEvent, (error52) => {
|
|
81672
|
-
deps.log(`watcher lost (${
|
|
81724
|
+
deps.log(`watcher lost (${describeError(error52)}), re-arming and re-scanning`);
|
|
81673
81725
|
closeWatcher?.();
|
|
81674
81726
|
closeWatcher = null;
|
|
81675
81727
|
arm();
|
|
@@ -81677,7 +81729,7 @@ function createWatchLoop(deps) {
|
|
|
81677
81729
|
});
|
|
81678
81730
|
} catch (error52) {
|
|
81679
81731
|
deps.log(
|
|
81680
|
-
`cannot watch yet (${
|
|
81732
|
+
`cannot watch yet (${describeError(error52)}), retrying in ${WATCHER_RETRY_MS / 1e3}s`
|
|
81681
81733
|
);
|
|
81682
81734
|
watcherRetry = setTimeout(arm, WATCHER_RETRY_MS);
|
|
81683
81735
|
}
|
|
@@ -81686,7 +81738,7 @@ function createWatchLoop(deps) {
|
|
|
81686
81738
|
if (stopped) return;
|
|
81687
81739
|
if (deps.paused?.()) {
|
|
81688
81740
|
if (!pausedLogged) {
|
|
81689
|
-
deps.log("syncing paused
|
|
81741
|
+
deps.log("syncing paused, skipping sync passes until resumed");
|
|
81690
81742
|
pausedLogged = true;
|
|
81691
81743
|
}
|
|
81692
81744
|
return;
|
|
@@ -81734,6 +81786,8 @@ function createWatchLoop(deps) {
|
|
|
81734
81786
|
}
|
|
81735
81787
|
}
|
|
81736
81788
|
consecutiveFailures = 0;
|
|
81789
|
+
streakSignature = null;
|
|
81790
|
+
streakCount = 0;
|
|
81737
81791
|
deps.onPassResult?.({
|
|
81738
81792
|
kind,
|
|
81739
81793
|
at: startedAt,
|
|
@@ -81743,31 +81797,50 @@ function createWatchLoop(deps) {
|
|
|
81743
81797
|
});
|
|
81744
81798
|
} catch (error52) {
|
|
81745
81799
|
consecutiveFailures += 1;
|
|
81746
|
-
|
|
81800
|
+
const signature = errorSignature(error52);
|
|
81801
|
+
if (signature === streakSignature) {
|
|
81802
|
+
streakCount += 1;
|
|
81803
|
+
} else {
|
|
81804
|
+
streakSignature = signature;
|
|
81805
|
+
streakCount = 1;
|
|
81806
|
+
streakStartedAt = startedAt;
|
|
81807
|
+
streakReportedAt = 0;
|
|
81808
|
+
}
|
|
81809
|
+
const holdMs = Math.max(
|
|
81810
|
+
Math.min(FAILED_PASS_RETRY_MS * 2 ** (streakCount - 1), FAILED_PASS_BACKOFF_CAP_MS),
|
|
81811
|
+
retryAfterMs(error52) ?? 0
|
|
81812
|
+
);
|
|
81813
|
+
retryNotBefore = now() + holdMs;
|
|
81747
81814
|
lifecycleChanged ||= consultLifecycle;
|
|
81748
81815
|
deps.onPassResult?.({
|
|
81749
81816
|
kind,
|
|
81750
81817
|
at: startedAt,
|
|
81751
81818
|
ok: false,
|
|
81752
|
-
error:
|
|
81819
|
+
error: describeError(error52),
|
|
81753
81820
|
sessions: 0,
|
|
81754
81821
|
upserted: 0
|
|
81755
81822
|
});
|
|
81756
|
-
|
|
81823
|
+
const failLine = `${kind} pass failed (${describeError(error52)})`;
|
|
81824
|
+
deps.log(
|
|
81825
|
+
streakCount > 1 ? `${failLine}: same failure ${streakCount} times in a row, next attempt in ${describeDelay(holdMs)}` : `${failLine}, next attempt in ${describeDelay(holdMs)} re-covers this window`
|
|
81826
|
+
);
|
|
81757
81827
|
if (error52 instanceof Error && !(error52 instanceof ExpectedCliError) && error52.stack) {
|
|
81758
81828
|
deps.log(error52.stack);
|
|
81759
81829
|
}
|
|
81760
81830
|
if (isPoisonedHttp2Session(error52)) {
|
|
81761
81831
|
deps.reportError?.(error52, `watch-pass-${kind}-poisoned-pool`);
|
|
81762
81832
|
deps.fatal?.(
|
|
81763
|
-
"connection pool poisoned by a destroyed HTTP/2 session
|
|
81833
|
+
"connection pool poisoned by a destroyed HTTP/2 session, exiting so the service restarts clean"
|
|
81764
81834
|
);
|
|
81765
81835
|
return;
|
|
81766
81836
|
}
|
|
81767
|
-
if (consecutiveFailures >= REPORT_AFTER_CONSECUTIVE_FAILURES) {
|
|
81837
|
+
if (consecutiveFailures >= REPORT_AFTER_CONSECUTIVE_FAILURES && (streakReportedAt === 0 || now() - streakReportedAt >= STREAK_REREPORT_INTERVAL_MS)) {
|
|
81838
|
+
streakReportedAt = now();
|
|
81768
81839
|
const report2 = error52 instanceof ExpectedCliError ? new Error(`${consecutiveFailures} consecutive failed passes: ${error52.message}`) : error52;
|
|
81769
81840
|
deps.reportError?.(report2, `watch-pass-${kind}`, {
|
|
81770
81841
|
consecutiveFailures,
|
|
81842
|
+
sameFailureCount: streakCount,
|
|
81843
|
+
streakMinutes: Math.round((now() - streakStartedAt) / 6e4),
|
|
81771
81844
|
pendingCompletions: pendingCompletions.size
|
|
81772
81845
|
});
|
|
81773
81846
|
}
|
|
@@ -81821,7 +81894,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81821
81894
|
const home = homeDir ?? os14.homedir();
|
|
81822
81895
|
process.on("uncaughtException", (error52) => {
|
|
81823
81896
|
console.error(
|
|
81824
|
-
`${(/* @__PURE__ */ new Date()).toISOString()} \u26A0 uncaught exception
|
|
81897
|
+
`${(/* @__PURE__ */ new Date()).toISOString()} \u26A0 uncaught exception, exiting for a clean restart`,
|
|
81825
81898
|
error52
|
|
81826
81899
|
);
|
|
81827
81900
|
reportCollectorError(error52, "watch-uncaught-exception");
|
|
@@ -81829,16 +81902,16 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81829
81902
|
});
|
|
81830
81903
|
process.on("unhandledRejection", (reason) => {
|
|
81831
81904
|
console.error(
|
|
81832
|
-
`${(/* @__PURE__ */ new Date()).toISOString()} \u26A0 unhandled rejection
|
|
81905
|
+
`${(/* @__PURE__ */ new Date()).toISOString()} \u26A0 unhandled rejection, exiting for a clean restart`,
|
|
81833
81906
|
reason
|
|
81834
81907
|
);
|
|
81835
81908
|
reportCollectorError(reason, "watch-unhandled-rejection");
|
|
81836
81909
|
void flushReporting().then(() => process.exit(1));
|
|
81837
81910
|
});
|
|
81838
81911
|
const storeRoots = [
|
|
81839
|
-
{ dir:
|
|
81840
|
-
{ dir:
|
|
81841
|
-
{ dir:
|
|
81912
|
+
{ dir: path13.join(home, ".claude", "projects"), recursive: true },
|
|
81913
|
+
{ dir: path13.join(home, ".codex", "sessions"), recursive: true },
|
|
81914
|
+
{ dir: path13.join(home, ".codex", "archived_sessions"), recursive: true },
|
|
81842
81915
|
// Cursor keeps every local session in one SQLite store here; its WAL
|
|
81843
81916
|
// file changes on session writes, so a non-recursive watch on the
|
|
81844
81917
|
// directory is the freshness signal. Cursor's own unrelated writes to
|
|
@@ -81846,7 +81919,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81846
81919
|
{ dir: cursorGlobalStorageDir(home), recursive: false }
|
|
81847
81920
|
];
|
|
81848
81921
|
const lifecycleRoot = {
|
|
81849
|
-
dir:
|
|
81922
|
+
dir: path13.join(home, ".config", "powerplant"),
|
|
81850
81923
|
recursive: false,
|
|
81851
81924
|
lifecycle: true
|
|
81852
81925
|
};
|
|
@@ -81855,7 +81928,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81855
81928
|
try {
|
|
81856
81929
|
return loadCredentials(config2.appEnv);
|
|
81857
81930
|
} catch (error52) {
|
|
81858
|
-
log3(`\u26A0 credential store unreadable (${
|
|
81931
|
+
log3(`\u26A0 credential store unreadable (${describeError(error52)}), identity omitted from status`);
|
|
81859
81932
|
return null;
|
|
81860
81933
|
}
|
|
81861
81934
|
})();
|
|
@@ -81865,21 +81938,15 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81865
81938
|
try {
|
|
81866
81939
|
const hook = installCollectorHooks(home);
|
|
81867
81940
|
log3(
|
|
81868
|
-
hook.settings === "skip" ? `\u26A0 Claude Code hooks not wired: ${hook.detail ?? "settings.json unusable"}
|
|
81941
|
+
hook.settings === "skip" ? `\u26A0 Claude Code hooks not wired: ${hook.detail ?? "settings.json unusable"}, fix ~/.claude/settings.json and restart` : `Claude Code hooks ${hook.settings === "write" ? "installed" : "current"} at ${hook.hookDir} (new Claude sessions pick them up)`
|
|
81869
81942
|
);
|
|
81870
81943
|
} catch (error52) {
|
|
81871
81944
|
log3(
|
|
81872
|
-
`\u26A0 Claude Code hook install failed (${
|
|
81945
|
+
`\u26A0 Claude Code hook install failed (${describeError(error52)}), syncing continues without them`
|
|
81873
81946
|
);
|
|
81874
81947
|
reportCollectorError(error52, "watch-hook-install");
|
|
81875
81948
|
}
|
|
81876
|
-
|
|
81877
|
-
startWakeService(config2, home, log3);
|
|
81878
|
-
} catch (error52) {
|
|
81879
|
-
log3(`\u26A0 wake-on-message failed to start (${describeError3(error52)}) \u2014 syncing continues`);
|
|
81880
|
-
reportCollectorError(error52, "watch-wake-start");
|
|
81881
|
-
}
|
|
81882
|
-
const presentRoots = storeRoots.filter(({ dir }) => existsSync4(dir)).map(({ dir }) => dir);
|
|
81949
|
+
const presentRoots = storeRoots.filter(({ dir }) => existsSync3(dir)).map(({ dir }) => dir);
|
|
81883
81950
|
const initialControl = readCollectorControl(config2.appEnv, home);
|
|
81884
81951
|
const pausedAtMs = initialControl.paused ? Date.parse(initialControl.pausedAt ?? "") : Number.NaN;
|
|
81885
81952
|
let status = {
|
|
@@ -81907,7 +81974,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81907
81974
|
statusWriteFailed = false;
|
|
81908
81975
|
} catch (error52) {
|
|
81909
81976
|
if (!statusWriteFailed) {
|
|
81910
|
-
log3(`\u26A0 status file write failed (${
|
|
81977
|
+
log3(`\u26A0 status file write failed (${describeError(error52)}), syncing continues`);
|
|
81911
81978
|
reportCollectorError(error52, "watch-status-write");
|
|
81912
81979
|
}
|
|
81913
81980
|
statusWriteFailed = true;
|
|
@@ -81961,7 +82028,7 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81961
82028
|
},
|
|
81962
82029
|
...Number.isFinite(pausedAtMs) && { initialCoveredSinceMs: pausedAtMs },
|
|
81963
82030
|
watch: (onEvent, onLost) => {
|
|
81964
|
-
const present = armableWatchRoots(storeRoots, lifecycleRoot,
|
|
82031
|
+
const present = armableWatchRoots(storeRoots, lifecycleRoot, existsSync3);
|
|
81965
82032
|
if (present === null) throw new Error(`no session stores found under ${home}`);
|
|
81966
82033
|
log3(
|
|
81967
82034
|
`watching ${present.map(({ dir }) => dir).join(" + ")} for session changes (${config2.appEnv})`
|
|
@@ -81998,21 +82065,33 @@ function startWatch(config2, homeDir, runtime = { version: "checkout" }) {
|
|
|
81998
82065
|
controlPoll.unref?.();
|
|
81999
82066
|
if (runtime.entryPath) {
|
|
82000
82067
|
watchEntryForUpdate(runtime.entryPath, (detail) => {
|
|
82001
|
-
log3(`${detail}
|
|
82068
|
+
log3(`${detail}, exiting so the service restarts on the new version`);
|
|
82002
82069
|
void flushReporting().then(() => process.exit(1));
|
|
82003
82070
|
});
|
|
82004
82071
|
}
|
|
82005
82072
|
return new Promise(() => {
|
|
82006
82073
|
});
|
|
82007
82074
|
}
|
|
82008
|
-
function
|
|
82075
|
+
function describeError(error52) {
|
|
82009
82076
|
return error52 instanceof Error ? error52.message : String(error52);
|
|
82010
82077
|
}
|
|
82078
|
+
function errorSignature(error52) {
|
|
82079
|
+
const parts = [];
|
|
82080
|
+
for (let cause = error52; cause instanceof Error; cause = cause.cause) {
|
|
82081
|
+
parts.push(`${cause.name}: ${cause.message}`);
|
|
82082
|
+
}
|
|
82083
|
+
if (parts.length === 0) parts.push(String(error52));
|
|
82084
|
+
return parts.join(" | ").replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "#").replace(/[0-9a-f]{8,}/gi, "#").replace(/\d+/g, "#");
|
|
82085
|
+
}
|
|
82086
|
+
function describeDelay(ms) {
|
|
82087
|
+
const seconds = Math.round(ms / 1e3);
|
|
82088
|
+
return seconds < 120 ? `${seconds}s` : `${Math.round(seconds / 60)} minutes`;
|
|
82089
|
+
}
|
|
82011
82090
|
|
|
82012
82091
|
// src/connect.ts
|
|
82013
|
-
import { execFileSync as
|
|
82092
|
+
import { execFileSync as execFileSync4, spawnSync } from "node:child_process";
|
|
82014
82093
|
import {
|
|
82015
|
-
existsSync as
|
|
82094
|
+
existsSync as existsSync4,
|
|
82016
82095
|
mkdirSync as mkdirSync6,
|
|
82017
82096
|
mkdtempSync,
|
|
82018
82097
|
readdirSync as readdirSync2,
|
|
@@ -82022,7 +82101,7 @@ import {
|
|
|
82022
82101
|
writeFileSync as writeFileSync6
|
|
82023
82102
|
} from "node:fs";
|
|
82024
82103
|
import os15 from "node:os";
|
|
82025
|
-
import
|
|
82104
|
+
import path14 from "node:path";
|
|
82026
82105
|
import { emitKeypressEvents } from "node:readline";
|
|
82027
82106
|
var MCP_SERVER_NAME = "powerplant";
|
|
82028
82107
|
var AGENT_DISPLAY_NAMES = {
|
|
@@ -82036,7 +82115,7 @@ function parseClientFilter(values) {
|
|
|
82036
82115
|
for (const value of values) {
|
|
82037
82116
|
if (value === "claude" || value === "claude-code") filter.add("claude");
|
|
82038
82117
|
else if (value === "codex" || value === "cursor") filter.add(value);
|
|
82039
|
-
else throw new ExpectedCliError(`Unknown --client "${value}"
|
|
82118
|
+
else throw new ExpectedCliError(`Unknown --client "${value}", one of: claude, codex, cursor`);
|
|
82040
82119
|
}
|
|
82041
82120
|
return filter;
|
|
82042
82121
|
}
|
|
@@ -82060,7 +82139,7 @@ function detectClients(options = {}) {
|
|
|
82060
82139
|
const homeDir = options.homeDir ?? os15.homedir();
|
|
82061
82140
|
const whichAll = options.whichAll ?? defaultWhichAll;
|
|
82062
82141
|
const env = options.env ?? process.env;
|
|
82063
|
-
const applicationsDirs = options.applicationsDirs ?? (process.platform === "darwin" ? ["/Applications",
|
|
82142
|
+
const applicationsDirs = options.applicationsDirs ?? (process.platform === "darwin" ? ["/Applications", path14.join(homeDir, "Applications")] : []);
|
|
82064
82143
|
const bundleSeams = {
|
|
82065
82144
|
readBundleInfo: options.readBundleInfo ?? realReadBundleInfo,
|
|
82066
82145
|
verifySignature: options.verifySignature ?? realVerifySignature,
|
|
@@ -82082,20 +82161,20 @@ function detectClients(options = {}) {
|
|
|
82082
82161
|
clients.push({ client, bin, ...configDir !== void 0 && { configDir } });
|
|
82083
82162
|
};
|
|
82084
82163
|
for (const bin of whichAll("claude")) add("claude", bin);
|
|
82085
|
-
const localClaude =
|
|
82086
|
-
if (
|
|
82164
|
+
const localClaude = path14.join(homeDir, ".local", "bin", "claude");
|
|
82165
|
+
if (existsSync4(localClaude)) add("claude", localClaude);
|
|
82087
82166
|
for (const bin of desktopClaudeBinaries(homeDir)) add("claude", bin);
|
|
82088
82167
|
const claudeBins = clients.filter((client) => client.client === "claude" && client.configDir === void 0).map((client) => client.bin);
|
|
82089
82168
|
for (const configDir of claudeConfigHomes(homeDir, env)) {
|
|
82090
82169
|
for (const bin of claudeBins) add("claude", bin, configDir);
|
|
82091
82170
|
}
|
|
82092
82171
|
for (const bin of whichAll("codex")) add("codex", bin);
|
|
82093
|
-
const localCodex =
|
|
82094
|
-
if (
|
|
82172
|
+
const localCodex = path14.join(homeDir, ".local", "bin", "codex");
|
|
82173
|
+
if (existsSync4(localCodex)) add("codex", localCodex);
|
|
82095
82174
|
for (const bin of codexBundleBinaries(applicationsDirs, bundleSeams)) add("codex", bin);
|
|
82096
|
-
const cursorDir =
|
|
82097
|
-
if (
|
|
82098
|
-
clients.push({ client: "cursor", bin:
|
|
82175
|
+
const cursorDir = path14.join(homeDir, ".cursor");
|
|
82176
|
+
if (existsSync4(cursorDir) || cursorAppInstalled(applicationsDirs, bundleSeams)) {
|
|
82177
|
+
clients.push({ client: "cursor", bin: path14.join(cursorDir, "mcp.json") });
|
|
82099
82178
|
}
|
|
82100
82179
|
return clients;
|
|
82101
82180
|
}
|
|
@@ -82103,7 +82182,7 @@ function claudeConfigHomes(homeDir, env) {
|
|
|
82103
82182
|
const homes = [];
|
|
82104
82183
|
const seen = /* @__PURE__ */ new Set();
|
|
82105
82184
|
try {
|
|
82106
|
-
seen.add(realpathSync(
|
|
82185
|
+
seen.add(realpathSync(path14.join(homeDir, ".claude")));
|
|
82107
82186
|
} catch {
|
|
82108
82187
|
}
|
|
82109
82188
|
const add = (configDir) => {
|
|
@@ -82115,7 +82194,7 @@ function claudeConfigHomes(homeDir, env) {
|
|
|
82115
82194
|
}
|
|
82116
82195
|
if (seen.has(real)) return;
|
|
82117
82196
|
seen.add(real);
|
|
82118
|
-
homes.push(
|
|
82197
|
+
homes.push(path14.resolve(configDir));
|
|
82119
82198
|
};
|
|
82120
82199
|
let entries = [];
|
|
82121
82200
|
try {
|
|
@@ -82123,8 +82202,8 @@ function claudeConfigHomes(homeDir, env) {
|
|
|
82123
82202
|
} catch {
|
|
82124
82203
|
}
|
|
82125
82204
|
for (const entry of entries.sort()) {
|
|
82126
|
-
if (entry.startsWith(".claude-") &&
|
|
82127
|
-
add(
|
|
82205
|
+
if (entry.startsWith(".claude-") && existsSync4(path14.join(homeDir, entry, ".claude.json"))) {
|
|
82206
|
+
add(path14.join(homeDir, entry));
|
|
82128
82207
|
}
|
|
82129
82208
|
}
|
|
82130
82209
|
if (env.CLAUDE_CONFIG_DIR) add(env.CLAUDE_CONFIG_DIR);
|
|
@@ -82135,7 +82214,7 @@ var CODESIGN_TIMEOUT_MS = 1e4;
|
|
|
82135
82214
|
function budgetedTimeout(capMs, appDir, seams) {
|
|
82136
82215
|
const remaining = seams.budget.remainingMs();
|
|
82137
82216
|
if (remaining <= 0) {
|
|
82138
|
-
seams.warn(`Skipping ${appDir}
|
|
82217
|
+
seams.warn(`Skipping ${appDir}, out of time to verify app bundles this run.`);
|
|
82139
82218
|
return null;
|
|
82140
82219
|
}
|
|
82141
82220
|
return Math.min(capMs, remaining);
|
|
@@ -82152,7 +82231,7 @@ function appBundles(applicationsDirs, namePrefixes) {
|
|
|
82152
82231
|
for (const entry of entries) {
|
|
82153
82232
|
if (!entry.endsWith(".app")) continue;
|
|
82154
82233
|
if (!namePrefixes.some((prefix) => entry.startsWith(prefix))) continue;
|
|
82155
|
-
bundles.push(
|
|
82234
|
+
bundles.push(path14.join(dir, entry));
|
|
82156
82235
|
}
|
|
82157
82236
|
}
|
|
82158
82237
|
return bundles;
|
|
@@ -82162,7 +82241,7 @@ function signedByTeam(binPath, teamId, vendor, appDir, seams) {
|
|
|
82162
82241
|
if (timeoutMs === null) return false;
|
|
82163
82242
|
if (seams.verifySignature(binPath, teamId, timeoutMs)) return true;
|
|
82164
82243
|
seams.warn(
|
|
82165
|
-
`Skipping ${appDir}
|
|
82244
|
+
`Skipping ${appDir}, its bundled binary is not verifiably signed by ${vendor} (the Apple-anchored signature check failed).`
|
|
82166
82245
|
);
|
|
82167
82246
|
return false;
|
|
82168
82247
|
}
|
|
@@ -82172,7 +82251,7 @@ function codexBundleBinaries(applicationsDirs, seams) {
|
|
|
82172
82251
|
const infoTimeoutMs = budgetedTimeout(BUNDLE_INFO_TIMEOUT_MS, appDir, seams);
|
|
82173
82252
|
if (infoTimeoutMs === null) continue;
|
|
82174
82253
|
if (seams.readBundleInfo(appDir, infoTimeoutMs)?.bundleId !== CODEX_BUNDLE_ID) continue;
|
|
82175
|
-
const bin =
|
|
82254
|
+
const bin = path14.join(appDir, "Contents", "Resources", "codex");
|
|
82176
82255
|
if (!isExecutableFile(bin)) continue;
|
|
82177
82256
|
if (!signedByTeam(bin, OPENAI_TEAM_ID, "OpenAI", appDir, seams)) continue;
|
|
82178
82257
|
found.push(bin);
|
|
@@ -82185,7 +82264,7 @@ function cursorAppInstalled(applicationsDirs, seams) {
|
|
|
82185
82264
|
if (infoTimeoutMs === null) continue;
|
|
82186
82265
|
const executable = seams.readBundleInfo(appDir, infoTimeoutMs)?.executable;
|
|
82187
82266
|
if (executable === void 0) continue;
|
|
82188
|
-
const bin =
|
|
82267
|
+
const bin = path14.join(appDir, "Contents", "MacOS", executable);
|
|
82189
82268
|
if (!isExecutableFile(bin)) continue;
|
|
82190
82269
|
if (!signedByTeam(bin, CURSOR_TEAM_ID, "Cursor", appDir, seams)) continue;
|
|
82191
82270
|
return true;
|
|
@@ -82207,7 +82286,7 @@ var bundleInfoSchema = external_exports.object({
|
|
|
82207
82286
|
function realReadBundleInfo(appDir, timeoutMs) {
|
|
82208
82287
|
const result = spawnSync(
|
|
82209
82288
|
"plutil",
|
|
82210
|
-
["-convert", "json", "-o", "-",
|
|
82289
|
+
["-convert", "json", "-o", "-", path14.join(appDir, "Contents", "Info.plist")],
|
|
82211
82290
|
{ encoding: "utf8", timeout: timeoutMs }
|
|
82212
82291
|
);
|
|
82213
82292
|
if (result.status !== 0) return null;
|
|
@@ -82225,18 +82304,18 @@ function realVerifySignature(binPath, teamId, timeoutMs) {
|
|
|
82225
82304
|
}).status === 0;
|
|
82226
82305
|
}
|
|
82227
82306
|
function desktopClaudeBinaries(homeDir) {
|
|
82228
|
-
const root =
|
|
82307
|
+
const root = path14.join(homeDir, "Library", "Application Support", "Claude", "claude-code");
|
|
82229
82308
|
let versions;
|
|
82230
82309
|
try {
|
|
82231
82310
|
versions = readdirSync2(root);
|
|
82232
82311
|
} catch {
|
|
82233
82312
|
return [];
|
|
82234
82313
|
}
|
|
82235
|
-
return versions.map((version2) =>
|
|
82314
|
+
return versions.map((version2) => path14.join(root, version2, "claude.app", "Contents", "MacOS", "claude")).filter((bin) => existsSync4(bin));
|
|
82236
82315
|
}
|
|
82237
82316
|
function defaultWhichAll(name) {
|
|
82238
82317
|
try {
|
|
82239
|
-
return
|
|
82318
|
+
return execFileSync4("which", ["-a", name], { encoding: "utf8" }).split("\n").map((line) => line.trim()).filter(Boolean);
|
|
82240
82319
|
} catch {
|
|
82241
82320
|
return [];
|
|
82242
82321
|
}
|
|
@@ -82253,7 +82332,7 @@ function runConnect(clients, deps) {
|
|
|
82253
82332
|
failed: 0
|
|
82254
82333
|
};
|
|
82255
82334
|
if (clients.length === 0) {
|
|
82256
|
-
deps.log("No coding agents found (looked for `claude`, `codex`, and Cursor)
|
|
82335
|
+
deps.log("No coding agents found (looked for `claude`, `codex`, and Cursor), nothing to connect.");
|
|
82257
82336
|
return outcome;
|
|
82258
82337
|
}
|
|
82259
82338
|
for (const [agent, candidates] of agents) {
|
|
@@ -82439,30 +82518,30 @@ function connectClaude(client, name, deps) {
|
|
|
82439
82518
|
const env = claudeEnv(client);
|
|
82440
82519
|
const probe = parseClaudeProbe(deps.run(bin, ["mcp", "get", MCP_SERVER_NAME], env));
|
|
82441
82520
|
if (probe.broken) {
|
|
82442
|
-
deps.log(`\u2717 ${name}: probing for the Powerplant MCP failed
|
|
82521
|
+
deps.log(`\u2717 ${name}: probing for the Powerplant MCP failed, ${probe.detail}`);
|
|
82443
82522
|
return { state: "failed", unchanged: false };
|
|
82444
82523
|
}
|
|
82445
82524
|
const { missing, registeredUrl } = probe;
|
|
82446
82525
|
if (missing || registeredUrl !== void 0 && registeredUrl !== deps.mcpUrl) {
|
|
82447
82526
|
if (!missing) {
|
|
82448
|
-
deps.log(`${name}: registered against ${registeredUrl}
|
|
82527
|
+
deps.log(`${name}: registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
|
|
82449
82528
|
deps.run(bin, ["mcp", "remove", "--scope", "user", MCP_SERVER_NAME], env);
|
|
82450
82529
|
}
|
|
82451
82530
|
const add = deps.run(bin, claudeAddArgs(deps), env);
|
|
82452
82531
|
if (add.status !== 0) {
|
|
82453
|
-
deps.log(`\u2717 ${name}: registering the Powerplant MCP failed
|
|
82532
|
+
deps.log(`\u2717 ${name}: registering the Powerplant MCP failed, ${describeFailure(add)}`);
|
|
82454
82533
|
return { state: "failed", unchanged: false };
|
|
82455
82534
|
}
|
|
82456
82535
|
deps.log(`${name}: Powerplant MCP registered (user scope).`);
|
|
82457
82536
|
} else if (probe.authenticated) {
|
|
82458
|
-
deps.log(`\u2713 ${name} already connected`);
|
|
82537
|
+
deps.log(`\u2713 ${name} MCP already connected`);
|
|
82459
82538
|
return { state: "connected", unchanged: true };
|
|
82460
82539
|
} else if (deps.officialClients?.["claude-code"]) {
|
|
82461
82540
|
deps.log(`${name}: re-registering with the pre-registered client before sign-in.`);
|
|
82462
82541
|
deps.run(bin, ["mcp", "remove", "--scope", "user", MCP_SERVER_NAME], env);
|
|
82463
82542
|
const add = deps.run(bin, claudeAddArgs(deps), env);
|
|
82464
82543
|
if (add.status !== 0) {
|
|
82465
|
-
deps.log(`\u2717 ${name}: registering the Powerplant MCP failed
|
|
82544
|
+
deps.log(`\u2717 ${name}: registering the Powerplant MCP failed, ${describeFailure(add)}`);
|
|
82466
82545
|
return { state: "failed", unchanged: false };
|
|
82467
82546
|
}
|
|
82468
82547
|
} else {
|
|
@@ -82639,7 +82718,7 @@ function parseCodexProbe(result) {
|
|
|
82639
82718
|
if (result.status !== 0) {
|
|
82640
82719
|
return {
|
|
82641
82720
|
broken: true,
|
|
82642
|
-
detail: `listing MCP servers failed
|
|
82721
|
+
detail: `listing MCP servers failed, ${describeFailure(result)}`,
|
|
82643
82722
|
missing: false,
|
|
82644
82723
|
authenticated: false
|
|
82645
82724
|
};
|
|
@@ -82648,7 +82727,7 @@ function parseCodexProbe(result) {
|
|
|
82648
82727
|
if (servers === null) {
|
|
82649
82728
|
return {
|
|
82650
82729
|
broken: true,
|
|
82651
|
-
detail: "could not read its MCP server list
|
|
82730
|
+
detail: "could not read its MCP server list, is this codex version very old?",
|
|
82652
82731
|
missing: false,
|
|
82653
82732
|
authenticated: false
|
|
82654
82733
|
};
|
|
@@ -82686,7 +82765,7 @@ function healOrphanCodexOauthTable(name, deps) {
|
|
|
82686
82765
|
if (!changed) return;
|
|
82687
82766
|
deps.writeTextFile(deps.codexConfigPath, content);
|
|
82688
82767
|
deps.log(
|
|
82689
|
-
`${name}: removed leftover sign-in settings from an interrupted setup
|
|
82768
|
+
`${name}: removed leftover sign-in settings from an interrupted setup, codex can read its configuration again.`
|
|
82690
82769
|
);
|
|
82691
82770
|
}
|
|
82692
82771
|
function connectCodex(bin, name, deps) {
|
|
@@ -82700,7 +82779,7 @@ function connectCodex(bin, name, deps) {
|
|
|
82700
82779
|
const wrongUrl = registeredUrl !== void 0 && registeredUrl !== deps.mcpUrl;
|
|
82701
82780
|
const alreadyConnected = !missing && !wrongUrl && probe.authenticated;
|
|
82702
82781
|
if (missing || wrongUrl) {
|
|
82703
|
-
if (wrongUrl) deps.log(`${name}: registered against ${registeredUrl}
|
|
82782
|
+
if (wrongUrl) deps.log(`${name}: registered against ${registeredUrl}, re-registering for ${deps.mcpUrl}.`);
|
|
82704
82783
|
if (codexAddLogsIn(bin, deps)) {
|
|
82705
82784
|
ensureCodexCallbackPort(name, deps);
|
|
82706
82785
|
const outcome = login(bin, name, codexAddArgs(deps, { withOfficialClientId: true }), deps);
|
|
@@ -82709,12 +82788,12 @@ function connectCodex(bin, name, deps) {
|
|
|
82709
82788
|
}
|
|
82710
82789
|
const add = deps.run(bin, codexAddArgs(deps, { withOfficialClientId: false }));
|
|
82711
82790
|
if (add.status !== 0) {
|
|
82712
|
-
deps.log(`\u2717 ${name}: registering the Powerplant MCP failed
|
|
82791
|
+
deps.log(`\u2717 ${name}: registering the Powerplant MCP failed, ${describeFailure(add)}`);
|
|
82713
82792
|
return { state: "failed", unchanged: false };
|
|
82714
82793
|
}
|
|
82715
82794
|
deps.log(`${name}: Powerplant MCP registered.`);
|
|
82716
82795
|
} else if (alreadyConnected) {
|
|
82717
|
-
deps.log(`\u2713 ${name} already connected`);
|
|
82796
|
+
deps.log(`\u2713 ${name} MCP already connected`);
|
|
82718
82797
|
} else {
|
|
82719
82798
|
deps.log(`${name}: Powerplant MCP already registered.`);
|
|
82720
82799
|
}
|
|
@@ -82725,7 +82804,7 @@ function connectCodex(bin, name, deps) {
|
|
|
82725
82804
|
function applyCodexConfigPatch(name, deps, patch, successLine) {
|
|
82726
82805
|
if (patch.conflict !== void 0) {
|
|
82727
82806
|
deps.log(
|
|
82728
|
-
`${name}: ${patch.conflict}
|
|
82807
|
+
`${name}: ${patch.conflict}, sign-in may fail until the port conflict is resolved; then re-run ${deps.connectCommand}.`
|
|
82729
82808
|
);
|
|
82730
82809
|
return;
|
|
82731
82810
|
}
|
|
@@ -82769,18 +82848,18 @@ function connectCursor(mcpJsonPath, name, deps) {
|
|
|
82769
82848
|
);
|
|
82770
82849
|
if (patch.error !== void 0 || patch.entry === void 0) {
|
|
82771
82850
|
deps.log(
|
|
82772
|
-
`\u2717 ${name}: ${mcpJsonPath.replace(os15.homedir(), "~")} is ${patch.error}
|
|
82851
|
+
`\u2717 ${name}: ${mcpJsonPath.replace(os15.homedir(), "~")} is ${patch.error}, fix it by hand, then re-run ${deps.connectCommand}.`
|
|
82773
82852
|
);
|
|
82774
82853
|
return { state: "failed", unchanged: false };
|
|
82775
82854
|
}
|
|
82776
82855
|
if (patch.changed) deps.writeTextFile(mcpJsonPath, patch.content);
|
|
82777
82856
|
const configured = patch.changed ? "configured" : "already configured";
|
|
82778
82857
|
if (deps.openUrl(cursorInstallDeeplink(MCP_SERVER_NAME, patch.entry))) {
|
|
82779
|
-
deps.log(`\u2192 ${name} ${configured}
|
|
82858
|
+
deps.log(`\u2192 ${name} ${configured}, approve inside Cursor when it asks.`);
|
|
82780
82859
|
return { state: "configured", unchanged: !patch.changed };
|
|
82781
82860
|
}
|
|
82782
82861
|
deps.log(
|
|
82783
|
-
`\u2192 ${name} ${configured}
|
|
82862
|
+
`\u2192 ${name} ${configured}, could not open Cursor; in Cursor's MCP settings, enable the powerplant server and sign in.`
|
|
82784
82863
|
);
|
|
82785
82864
|
return { state: "pending", unchanged: false };
|
|
82786
82865
|
}
|
|
@@ -82788,10 +82867,10 @@ function login(bin, name, args, deps, env) {
|
|
|
82788
82867
|
deps.log(`\u2192 ${name} approve in your browser\u2026`);
|
|
82789
82868
|
const status = deps.runInteractive(bin, args, env);
|
|
82790
82869
|
if (status === 0) {
|
|
82791
|
-
deps.log(`\u2713 ${name} connected`);
|
|
82870
|
+
deps.log(`\u2713 ${name} MCP connected`);
|
|
82792
82871
|
return { state: "connected", unchanged: false };
|
|
82793
82872
|
}
|
|
82794
|
-
deps.log(`\u2192 ${name}
|
|
82873
|
+
deps.log(`\u2192 ${name} MCP sign-in not completed, finish later with: ${deps.connectCommand}`);
|
|
82795
82874
|
return { state: "pending", unchanged: false };
|
|
82796
82875
|
}
|
|
82797
82876
|
function runDisconnect(clients, deps) {
|
|
@@ -82804,7 +82883,7 @@ function runDisconnect(clients, deps) {
|
|
|
82804
82883
|
};
|
|
82805
82884
|
if (clients.length === 0) {
|
|
82806
82885
|
deps.log(
|
|
82807
|
-
"No coding agents found (looked for `claude`, `codex`, and Cursor)
|
|
82886
|
+
"No coding agents found (looked for `claude`, `codex`, and Cursor), nothing to disconnect."
|
|
82808
82887
|
);
|
|
82809
82888
|
return outcome;
|
|
82810
82889
|
}
|
|
@@ -82848,12 +82927,12 @@ function disconnectClaude(client, deps) {
|
|
|
82848
82927
|
return "notConnected";
|
|
82849
82928
|
}
|
|
82850
82929
|
if (get.status !== 0) {
|
|
82851
|
-
deps.log(`\u2717 ${name}: probing for the Powerplant MCP failed
|
|
82930
|
+
deps.log(`\u2717 ${name}: probing for the Powerplant MCP failed, ${describeFailure(get)}`);
|
|
82852
82931
|
return "failed";
|
|
82853
82932
|
}
|
|
82854
82933
|
const remove = deps.run(bin, ["mcp", "remove", "--scope", "user", MCP_SERVER_NAME], env);
|
|
82855
82934
|
if (remove.status !== 0) {
|
|
82856
|
-
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed
|
|
82935
|
+
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed, ${describeFailure(remove)}`);
|
|
82857
82936
|
return "failed";
|
|
82858
82937
|
}
|
|
82859
82938
|
deps.log(`${name}: Powerplant MCP removed, sign-in included.`);
|
|
@@ -82863,12 +82942,12 @@ function disconnectCodex(bin, deps) {
|
|
|
82863
82942
|
const name = describeBinary(bin);
|
|
82864
82943
|
const list = deps.run(bin, ["mcp", "list", "--json"]);
|
|
82865
82944
|
if (list.status !== 0) {
|
|
82866
|
-
deps.log(`\u2717 ${name}: listing MCP servers failed
|
|
82945
|
+
deps.log(`\u2717 ${name}: listing MCP servers failed, ${describeFailure(list)}`);
|
|
82867
82946
|
return "failed";
|
|
82868
82947
|
}
|
|
82869
82948
|
const servers = parseCodexServers(list.stdout);
|
|
82870
82949
|
if (servers === null) {
|
|
82871
|
-
deps.log(`\u2717 ${name}: could not read its MCP server list
|
|
82950
|
+
deps.log(`\u2717 ${name}: could not read its MCP server list, is this codex version very old?`);
|
|
82872
82951
|
return "failed";
|
|
82873
82952
|
}
|
|
82874
82953
|
const registered = servers.some((server) => server.name === MCP_SERVER_NAME);
|
|
@@ -82881,7 +82960,7 @@ function disconnectCodex(bin, deps) {
|
|
|
82881
82960
|
deps.run(bin, ["mcp", "logout", MCP_SERVER_NAME]);
|
|
82882
82961
|
const remove = deps.run(bin, ["mcp", "remove", MCP_SERVER_NAME]);
|
|
82883
82962
|
if (remove.status !== 0) {
|
|
82884
|
-
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed
|
|
82963
|
+
deps.log(`\u2717 ${name}: removing the Powerplant MCP failed, ${describeFailure(remove)}`);
|
|
82885
82964
|
return "failed";
|
|
82886
82965
|
}
|
|
82887
82966
|
deps.log(`${name}: Powerplant MCP removed, sign-in included.`);
|
|
@@ -82891,7 +82970,7 @@ function disconnectCursor(mcpJsonPath, deps) {
|
|
|
82891
82970
|
const name = `Cursor (${mcpJsonPath.replace(os15.homedir(), "~")})`;
|
|
82892
82971
|
const patch = unpatchCursorMcpJson(deps.readTextFile(mcpJsonPath), MCP_SERVER_NAME);
|
|
82893
82972
|
if (patch.error !== void 0) {
|
|
82894
|
-
deps.log(`\u2717 ${name}: mcp.json is ${patch.error}
|
|
82973
|
+
deps.log(`\u2717 ${name}: mcp.json is ${patch.error}, fix it by hand, then re-run powerplant disconnect.`);
|
|
82895
82974
|
return "failed";
|
|
82896
82975
|
}
|
|
82897
82976
|
if (!patch.changed) {
|
|
@@ -82918,11 +82997,11 @@ function anyClientStillConnected(clients, deps) {
|
|
|
82918
82997
|
});
|
|
82919
82998
|
}
|
|
82920
82999
|
function describeBinary(bin) {
|
|
82921
|
-
return `${
|
|
83000
|
+
return `${path14.basename(bin)} (${bin.replace(os15.homedir(), "~")})`;
|
|
82922
83001
|
}
|
|
82923
83002
|
function describeClaudeTarget(client) {
|
|
82924
83003
|
if (client.configDir === void 0) return describeBinary(client.bin);
|
|
82925
|
-
return `${
|
|
83004
|
+
return `${path14.basename(client.bin)} (${client.configDir.replace(os15.homedir(), "~")})`;
|
|
82926
83005
|
}
|
|
82927
83006
|
function describeFailure(result) {
|
|
82928
83007
|
return result.error ?? lastLine(result.stdout + result.stderr);
|
|
@@ -82933,7 +83012,7 @@ function lastLine(output) {
|
|
|
82933
83012
|
}
|
|
82934
83013
|
var neutralDirMemo;
|
|
82935
83014
|
function neutralWorkdir() {
|
|
82936
|
-
neutralDirMemo ??= mkdtempSync(
|
|
83015
|
+
neutralDirMemo ??= mkdtempSync(path14.join(os15.tmpdir(), "powerplant-connect-"));
|
|
82937
83016
|
return neutralDirMemo;
|
|
82938
83017
|
}
|
|
82939
83018
|
async function fetchOfficialClients(apiUrl, log3) {
|
|
@@ -82956,7 +83035,7 @@ async function fetchOfficialClients(apiUrl, log3) {
|
|
|
82956
83035
|
return officialClientsDocumentSchema.parse(await response.json()).clients;
|
|
82957
83036
|
} catch (error52) {
|
|
82958
83037
|
log3(
|
|
82959
|
-
`Official client ids unavailable (${error52 instanceof Error ? error52.message : String(error52)})
|
|
83038
|
+
`Official client ids unavailable (${error52 instanceof Error ? error52.message : String(error52)}), agents will use dynamic registration where the environment allows it.`
|
|
82960
83039
|
);
|
|
82961
83040
|
return null;
|
|
82962
83041
|
}
|
|
@@ -82977,11 +83056,11 @@ function realReadTextFileStrict(filePath) {
|
|
|
82977
83056
|
}
|
|
82978
83057
|
}
|
|
82979
83058
|
function realWriteTextFile(filePath, content) {
|
|
82980
|
-
mkdirSync6(
|
|
83059
|
+
mkdirSync6(path14.dirname(filePath), { recursive: true });
|
|
82981
83060
|
writeFileSync6(filePath, content);
|
|
82982
83061
|
}
|
|
82983
83062
|
function codexConfigPath(homeDir = os15.homedir()) {
|
|
82984
|
-
return
|
|
83063
|
+
return path14.join(process.env.CODEX_HOME ?? path14.join(homeDir, ".codex"), "config.toml");
|
|
82985
83064
|
}
|
|
82986
83065
|
function realOpenUrl(url2) {
|
|
82987
83066
|
const bin = process.platform === "darwin" ? "open" : process.platform === "linux" ? "xdg-open" : null;
|
|
@@ -83029,9 +83108,9 @@ function realRunInteractive(bin, args, env) {
|
|
|
83029
83108
|
}
|
|
83030
83109
|
|
|
83031
83110
|
// src/connections.ts
|
|
83032
|
-
import { execFileSync as
|
|
83111
|
+
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
83033
83112
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
83034
|
-
import
|
|
83113
|
+
import path15 from "node:path";
|
|
83035
83114
|
function probeConnections(clients, deps) {
|
|
83036
83115
|
const reports = [];
|
|
83037
83116
|
for (const kind of ["claude", "codex", "cursor"]) {
|
|
@@ -83075,7 +83154,7 @@ function aggregateClaudeTargets(targets) {
|
|
|
83075
83154
|
if (targets.length === 1 || worst.report.state === "signed-in") return worst.report;
|
|
83076
83155
|
return {
|
|
83077
83156
|
...worst.report,
|
|
83078
|
-
target: worst.configDir === void 0 ? "default profile" :
|
|
83157
|
+
target: worst.configDir === void 0 ? "default profile" : path15.basename(worst.configDir)
|
|
83079
83158
|
};
|
|
83080
83159
|
}
|
|
83081
83160
|
function probeClient(client, deps) {
|
|
@@ -83154,12 +83233,12 @@ var detectedClientsSchema = external_exports.object({
|
|
|
83154
83233
|
)
|
|
83155
83234
|
});
|
|
83156
83235
|
function detectedClientsPath(homeDir) {
|
|
83157
|
-
return
|
|
83236
|
+
return path15.join(collectorStateDir(homeDir), "detected-clients.json");
|
|
83158
83237
|
}
|
|
83159
83238
|
function saveDetectedClients(clients, pathValue, homeDir) {
|
|
83160
83239
|
try {
|
|
83161
83240
|
const file2 = detectedClientsPath(homeDir);
|
|
83162
|
-
mkdirSync7(
|
|
83241
|
+
mkdirSync7(path15.dirname(file2), { recursive: true });
|
|
83163
83242
|
const record2 = {
|
|
83164
83243
|
detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83165
83244
|
path: pathValue,
|
|
@@ -83232,7 +83311,7 @@ function runWithPath(pathValue, budget = UNLIMITED_TIME_BUDGET) {
|
|
|
83232
83311
|
function whichAllWith(pathValue) {
|
|
83233
83312
|
return (name) => {
|
|
83234
83313
|
try {
|
|
83235
|
-
return
|
|
83314
|
+
return execFileSync5("which", ["-a", name], {
|
|
83236
83315
|
encoding: "utf8",
|
|
83237
83316
|
env: { ...process.env, PATH: pathValue }
|
|
83238
83317
|
}).split("\n").map((line) => line.trim()).filter(Boolean);
|
|
@@ -83250,72 +83329,72 @@ function renderStatus(i) {
|
|
|
83250
83329
|
const lines = [];
|
|
83251
83330
|
lines.push(`Environment: ${i.config.appEnv} (API ${i.config.apiUrl})`);
|
|
83252
83331
|
lines.push(
|
|
83253
|
-
`CLI: powerplant ${i.cliVersion}` + (i.latestVersion !== null && i.latestVersion !== i.cliVersion ?
|
|
83332
|
+
`CLI: powerplant ${i.cliVersion}` + (i.latestVersion !== null && i.latestVersion !== i.cliVersion ? `, ${i.latestVersion} is available: powerplant update` : "")
|
|
83254
83333
|
);
|
|
83255
83334
|
const unsupported = unsupportedVersionNotice(i.cliVersion, i.oldestSupportedVersion);
|
|
83256
83335
|
if (unsupported !== null) lines.push(unsupported);
|
|
83257
83336
|
if (i.credentialsError !== void 0) {
|
|
83258
83337
|
lines.push(`\u26A0 ${i.credentialsError}`);
|
|
83259
83338
|
} else if (!i.credentials) {
|
|
83260
|
-
lines.push("Not enrolled
|
|
83339
|
+
lines.push("Not enrolled, run: powerplant init");
|
|
83261
83340
|
} else {
|
|
83262
|
-
const orgLine = i.credentials.orgName ? ` into org "${i.credentials.orgName}"` : " (org not recorded
|
|
83341
|
+
const orgLine = i.credentials.orgName ? ` into org "${i.credentials.orgName}"` : " (org not recorded, re-enroll to see it)";
|
|
83263
83342
|
lines.push(
|
|
83264
83343
|
`Enrolled as "${i.credentials.machineName}" (${i.credentials.machineId})${orgLine} on ${i.credentials.enrolledAt}.`
|
|
83265
83344
|
);
|
|
83266
83345
|
lines.push(`Syncing: ${describeStoredCapture(i.credentials)}.`);
|
|
83267
83346
|
for (const entry of i.protectedSessions ?? []) {
|
|
83268
83347
|
lines.push(
|
|
83269
|
-
`\u26A0 Repository matching is not enabled for ${entry.sessionCount} recent agent session${entry.sessionCount === 1 ? "" : "s"} under ${entry.displayRoot}. Sessions outside folders you explicitly added are staying local
|
|
83348
|
+
`\u26A0 Repository matching is not enabled for ${entry.sessionCount} recent agent session${entry.sessionCount === 1 ? "" : "s"} under ${entry.displayRoot}. Sessions outside folders you explicitly added are staying local, run \`powerplant init\` to review Git repository scanning.`
|
|
83270
83349
|
);
|
|
83271
83350
|
}
|
|
83272
83351
|
}
|
|
83273
83352
|
switch (i.service) {
|
|
83274
83353
|
case "unsupported":
|
|
83275
83354
|
lines.push(
|
|
83276
|
-
"Background
|
|
83355
|
+
"Background sync: unsupported on this platform (macOS-only for now), run `powerplant sync` on a schedule instead."
|
|
83277
83356
|
);
|
|
83278
83357
|
break;
|
|
83279
83358
|
case "not-installed":
|
|
83280
|
-
lines.push("Background
|
|
83359
|
+
lines.push("Background sync: not installed, run: powerplant init");
|
|
83281
83360
|
break;
|
|
83282
83361
|
case "not-loaded":
|
|
83283
|
-
lines.push("Background
|
|
83362
|
+
lines.push("Background sync: installed but not loaded, run: powerplant restart");
|
|
83284
83363
|
break;
|
|
83285
83364
|
case "loaded":
|
|
83286
83365
|
lines.push(...renderDaemon(i));
|
|
83287
83366
|
break;
|
|
83288
83367
|
}
|
|
83289
83368
|
if (i.control.paused) {
|
|
83290
|
-
lines.push("\u23F8 Syncing is paused
|
|
83369
|
+
lines.push("\u23F8 Syncing is paused, resume with: powerplant resume");
|
|
83291
83370
|
}
|
|
83292
83371
|
return lines;
|
|
83293
83372
|
}
|
|
83294
83373
|
function renderDaemon(i) {
|
|
83295
83374
|
if (i.daemon.state === "unreadable") {
|
|
83296
83375
|
return [
|
|
83297
|
-
"Background
|
|
83376
|
+
"Background sync: loaded, but its status file is unreadable (written by a different version?), run: powerplant restart"
|
|
83298
83377
|
];
|
|
83299
83378
|
}
|
|
83300
83379
|
if (i.daemon.state === "not-running") {
|
|
83301
83380
|
return [
|
|
83302
|
-
`Background
|
|
83381
|
+
`Background sync: loaded, but no background sync status is available, starting up, or running a version from before status reporting. If this persists: powerplant restart. Log: ${serviceLogPath(i.config.appEnv)}`
|
|
83303
83382
|
];
|
|
83304
83383
|
}
|
|
83305
83384
|
const status = i.daemon.status;
|
|
83306
83385
|
const lines = [];
|
|
83307
83386
|
if (i.daemon.state === "stalled") {
|
|
83308
83387
|
lines.push(
|
|
83309
|
-
`\u26A0
|
|
83388
|
+
`\u26A0 Background sync stalled, no heartbeat for ${duration3(i.daemon.staleMs)} (pid ${status.pid}). Run: powerplant restart`
|
|
83310
83389
|
);
|
|
83311
83390
|
} else {
|
|
83312
83391
|
lines.push(
|
|
83313
|
-
`
|
|
83392
|
+
`Background sync: running (version ${status.version}, pid ${status.pid}, started ${status.startedAt}).`
|
|
83314
83393
|
);
|
|
83315
83394
|
}
|
|
83316
83395
|
if (status.version !== i.cliVersion) {
|
|
83317
83396
|
lines.push(
|
|
83318
|
-
` The daemon is on ${status.version}, this CLI is ${i.cliVersion}
|
|
83397
|
+
` The daemon is on ${status.version}, this CLI is ${i.cliVersion}, it restarts onto the installed version within minutes, or now via: powerplant restart`
|
|
83319
83398
|
);
|
|
83320
83399
|
}
|
|
83321
83400
|
lines.push(
|
|
@@ -83399,13 +83478,13 @@ function redactedLogTail(raw) {
|
|
|
83399
83478
|
while (lines.length > 0 && lines[lines.length - 1]?.trim() === "") lines.pop();
|
|
83400
83479
|
return lines.slice(-DOCTOR_LOG_TAIL_LINES);
|
|
83401
83480
|
}
|
|
83402
|
-
function readDoctorLogTail(
|
|
83481
|
+
function readDoctorLogTail(path18) {
|
|
83403
83482
|
let fd;
|
|
83404
83483
|
try {
|
|
83405
|
-
fd = openSync2(
|
|
83484
|
+
fd = openSync2(path18, "r");
|
|
83406
83485
|
} catch (error52) {
|
|
83407
|
-
if (error52.code === "ENOENT") return { path:
|
|
83408
|
-
return { path:
|
|
83486
|
+
if (error52.code === "ENOENT") return { path: path18, lines: null };
|
|
83487
|
+
return { path: path18, lines: null, readError: error52 instanceof Error ? error52.message : String(error52) };
|
|
83409
83488
|
}
|
|
83410
83489
|
try {
|
|
83411
83490
|
const size = fstatSync(fd).size;
|
|
@@ -83414,9 +83493,9 @@ function readDoctorLogTail(path19) {
|
|
|
83414
83493
|
readSync2(fd, buffer, 0, buffer.length, offset);
|
|
83415
83494
|
let text = buffer.toString("utf8");
|
|
83416
83495
|
if (offset > 0) text = text.slice(text.indexOf("\n") + 1);
|
|
83417
|
-
return { path:
|
|
83496
|
+
return { path: path18, lines: redactedLogTail(text) };
|
|
83418
83497
|
} catch (error52) {
|
|
83419
|
-
return { path:
|
|
83498
|
+
return { path: path18, lines: null, readError: error52 instanceof Error ? error52.message : String(error52) };
|
|
83420
83499
|
} finally {
|
|
83421
83500
|
closeSync2(fd);
|
|
83422
83501
|
}
|
|
@@ -83424,7 +83503,7 @@ function readDoctorLogTail(path19) {
|
|
|
83424
83503
|
function renderDoctorReport(i) {
|
|
83425
83504
|
const lines = [];
|
|
83426
83505
|
lines.push(
|
|
83427
|
-
"Powerplant diagnostics
|
|
83506
|
+
"Powerplant diagnostics, paste everything below into your email to support@forestwalk.ai."
|
|
83428
83507
|
);
|
|
83429
83508
|
lines.push(
|
|
83430
83509
|
`Collected ${new Date(i.now).toISOString()}. This command only prints; nothing was uploaded.`
|
|
@@ -83446,7 +83525,7 @@ function renderDoctorReport(i) {
|
|
|
83446
83525
|
}
|
|
83447
83526
|
function enrollmentLine(i) {
|
|
83448
83527
|
if (i.credentialsError !== void 0) {
|
|
83449
|
-
return `Enrollment: credential store unreadable
|
|
83528
|
+
return `Enrollment: credential store unreadable, ${i.credentialsError}`;
|
|
83450
83529
|
}
|
|
83451
83530
|
if (!i.credentials) return "Enrollment: not enrolled";
|
|
83452
83531
|
return `Enrollment: machine ${i.credentials.machineId}, org ${i.credentials.orgId ?? "not recorded"}, since ${i.credentials.enrolledAt}`;
|
|
@@ -83471,28 +83550,28 @@ function serviceLines(i) {
|
|
|
83471
83550
|
const status = i.daemon.status;
|
|
83472
83551
|
const out = [];
|
|
83473
83552
|
out.push(
|
|
83474
|
-
i.daemon.state === "stalled" ? `Sync service: stalled
|
|
83553
|
+
i.daemon.state === "stalled" ? `Sync service: stalled, no heartbeat for ${duration3(i.daemon.staleMs)} (version ${status.version}, pid ${status.pid})` : `Sync service: running (version ${status.version}, pid ${status.pid}, started ${status.startedAt})`
|
|
83475
83554
|
);
|
|
83476
83555
|
out.push(
|
|
83477
83556
|
status.lastSyncAt !== void 0 ? `Last successful sync: ${ago(i.now - Date.parse(status.lastSyncAt))} (${status.lastSyncAt})` : "No successful sync yet in this daemon run."
|
|
83478
83557
|
);
|
|
83479
83558
|
if (status.lastPass) {
|
|
83480
83559
|
out.push(
|
|
83481
|
-
status.lastPass.ok ? `Last pass: ok (${status.lastPass.kind}, ${status.lastPass.sessions} sessions, ${status.lastPass.upserted} uploaded, at ${status.lastPass.at})` : `Last pass: failed at ${status.lastPass.at}
|
|
83560
|
+
status.lastPass.ok ? `Last pass: ok (${status.lastPass.kind}, ${status.lastPass.sessions} sessions, ${status.lastPass.upserted} uploaded, at ${status.lastPass.at})` : `Last pass: failed at ${status.lastPass.at}, ${redactText(status.lastPass.error ?? "unknown error")} (${status.consecutiveFailures} consecutive failure${status.consecutiveFailures === 1 ? "" : "s"})`
|
|
83482
83561
|
);
|
|
83483
83562
|
}
|
|
83484
83563
|
return out;
|
|
83485
83564
|
}
|
|
83486
83565
|
function logLines(tail) {
|
|
83487
83566
|
if (tail.readError !== void 0) {
|
|
83488
|
-
return [`Sync service log: could not read ${tail.path}
|
|
83567
|
+
return [`Sync service log: could not read ${tail.path}, ${tail.readError}`];
|
|
83489
83568
|
}
|
|
83490
83569
|
if (tail.lines === null) {
|
|
83491
83570
|
return [`Sync service log: no file at ${tail.path} (the background service may never have run).`];
|
|
83492
83571
|
}
|
|
83493
83572
|
if (tail.lines.length === 0) return [`Sync service log: ${tail.path} is empty.`];
|
|
83494
83573
|
return [
|
|
83495
|
-
`Sync service log
|
|
83574
|
+
`Sync service log, last ${tail.lines.length} line${tail.lines.length === 1 ? "" : "s"} of ${tail.path}, credentials redacted:`,
|
|
83496
83575
|
...tail.lines
|
|
83497
83576
|
];
|
|
83498
83577
|
}
|
|
@@ -83536,13 +83615,13 @@ function isCliEnv(value) {
|
|
|
83536
83615
|
}
|
|
83537
83616
|
function describeEnvironment(config2, env, explicitEnv) {
|
|
83538
83617
|
const steeredByEnvVar = explicitEnv === void 0 && env.POWERPLANT_ENV !== void 0;
|
|
83539
|
-
return `Environment: ${config2.appEnv} (API ${config2.apiUrl})${steeredByEnvVar ? "
|
|
83618
|
+
return `Environment: ${config2.appEnv} (API ${config2.apiUrl})${steeredByEnvVar ? ", set by POWERPLANT_ENV" : ""}`;
|
|
83540
83619
|
}
|
|
83541
83620
|
function resolveCliConfig(env, explicitEnv) {
|
|
83542
83621
|
const name = explicitEnv ?? env.POWERPLANT_ENV ?? "production";
|
|
83543
83622
|
if (!isCliEnv(name)) {
|
|
83544
83623
|
throw new ExpectedCliError(
|
|
83545
|
-
explicitEnv === void 0 ? `Unknown environment "${name}" (from POWERPLANT_ENV in your shell)
|
|
83624
|
+
explicitEnv === void 0 ? `Unknown environment "${name}" (from POWERPLANT_ENV in your shell), unset POWERPLANT_ENV to use production.` : `Unknown environment "${name}", drop --env to use production.`
|
|
83546
83625
|
);
|
|
83547
83626
|
}
|
|
83548
83627
|
const base = CLI_ENVIRONMENTS[name];
|
|
@@ -83584,7 +83663,7 @@ async function runInit(deps) {
|
|
|
83584
83663
|
let repoDiscoveryEnabled = false;
|
|
83585
83664
|
let protectedFoldersNeedAttention = false;
|
|
83586
83665
|
let installed = false;
|
|
83587
|
-
log3("2/3 Start background
|
|
83666
|
+
log3("2/3 Start background sync");
|
|
83588
83667
|
if (deps.platform === "darwin") {
|
|
83589
83668
|
const protectedSessions = await deps.activity(
|
|
83590
83669
|
"Checking recent session locations\u2026",
|
|
@@ -83639,29 +83718,29 @@ async function runInit(deps) {
|
|
|
83639
83718
|
}
|
|
83640
83719
|
if (deps.platform !== "darwin") {
|
|
83641
83720
|
log3(
|
|
83642
|
-
"
|
|
83721
|
+
" Background sync is macOS-only for now. Run `powerplant sync` on a schedule of your choosing instead."
|
|
83643
83722
|
);
|
|
83644
83723
|
} else if (deps.serviceUpToDate()) {
|
|
83645
|
-
log3("\u2713 Background
|
|
83724
|
+
log3("\u2713 Background sync is running");
|
|
83646
83725
|
} else {
|
|
83647
|
-
await deps.activity("Installing
|
|
83648
|
-
log3(" \u2713
|
|
83726
|
+
await deps.activity("Installing background sync\u2026", deps.installService);
|
|
83727
|
+
log3(" \u2713 Background sync is running");
|
|
83649
83728
|
log3(
|
|
83650
83729
|
` Runs quietly and only uploads sessions inside ${orgName ? `${orgName}\u2019s` : "your organization\u2019s"} boundary.`
|
|
83651
83730
|
);
|
|
83652
83731
|
installed = true;
|
|
83653
83732
|
}
|
|
83654
83733
|
log3("");
|
|
83655
|
-
log3("3/3
|
|
83734
|
+
log3("3/3 Give your agents Powerplant MCP access");
|
|
83656
83735
|
let outcome = null;
|
|
83657
83736
|
try {
|
|
83658
83737
|
outcome = await deps.connect();
|
|
83659
83738
|
} catch (error52) {
|
|
83660
|
-
log3(` \u2717
|
|
83739
|
+
log3(` \u2717 Could not give your agents Powerplant MCP access, ${error52 instanceof Error ? error52.message : String(error52)}`);
|
|
83661
83740
|
}
|
|
83662
83741
|
if (outcome?.found === 0) {
|
|
83663
83742
|
log3(
|
|
83664
|
-
deps.platform === "darwin" ? ` This machine still syncs once one is installed
|
|
83743
|
+
deps.platform === "darwin" ? ` This machine still syncs once one is installed, then run: ${deps.connectCommand}` : ` Once one is installed, run: ${deps.connectCommand}`
|
|
83665
83744
|
);
|
|
83666
83745
|
}
|
|
83667
83746
|
log3("");
|
|
@@ -83689,7 +83768,7 @@ async function runInit(deps) {
|
|
|
83689
83768
|
log3(` Open Powerplant: ${deps.webUrl}`);
|
|
83690
83769
|
log3("");
|
|
83691
83770
|
log3(
|
|
83692
|
-
deps.platform === "darwin" ? ` Start a coding session in ${repository}
|
|
83771
|
+
deps.platform === "darwin" ? ` Start a coding session in ${repository}, watch it appear in Powerplant.` : ` Start a coding session in ${repository}, then run \`powerplant sync\` to see it in Powerplant.`
|
|
83693
83772
|
);
|
|
83694
83773
|
}
|
|
83695
83774
|
async function confirmProtectedRepoDiscovery(deps) {
|
|
@@ -83721,10 +83800,10 @@ async function realPromptLine(question) {
|
|
|
83721
83800
|
}
|
|
83722
83801
|
|
|
83723
83802
|
// src/memberSessions.ts
|
|
83724
|
-
import { execFileSync as
|
|
83725
|
-
import { existsSync as
|
|
83803
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
83804
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
83726
83805
|
import os16 from "node:os";
|
|
83727
|
-
import
|
|
83806
|
+
import path16 from "node:path";
|
|
83728
83807
|
var memberSessionSchema = external_exports.object({
|
|
83729
83808
|
id: external_exports.string().min(1),
|
|
83730
83809
|
source: external_exports.string().min(1),
|
|
@@ -83735,12 +83814,12 @@ var memberSessionSchema = external_exports.object({
|
|
|
83735
83814
|
lastActivityAt: external_exports.string().min(1),
|
|
83736
83815
|
providerUrl: external_exports.string().nullable()
|
|
83737
83816
|
});
|
|
83738
|
-
var
|
|
83817
|
+
var FETCH_TIMEOUT_MS2 = 3e3;
|
|
83739
83818
|
async function fetchMemberSessions(credentials, fetchImpl = fetch) {
|
|
83740
83819
|
try {
|
|
83741
83820
|
const response = await fetchImpl(`${credentials.apiUrl}/api/collector/member-sessions`, {
|
|
83742
83821
|
headers: { authorization: `Bearer ${credentials.token}`, ...cliVersionHeaders() },
|
|
83743
|
-
signal: AbortSignal.timeout(
|
|
83822
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
83744
83823
|
});
|
|
83745
83824
|
if (!response.ok) return null;
|
|
83746
83825
|
const envelope = external_exports.object({ data: external_exports.object({ sessions: external_exports.array(memberSessionSchema) }) }).safeParse(await response.json());
|
|
@@ -83784,11 +83863,11 @@ function codexThreadId(externalId) {
|
|
|
83784
83863
|
}
|
|
83785
83864
|
var CODEX_APP_BUNDLES = ["ChatGPT.app", "Codex.app"];
|
|
83786
83865
|
var urlSchemesSchema = external_exports.array(external_exports.object({ CFBundleURLSchemes: external_exports.array(external_exports.string()).optional() }));
|
|
83787
|
-
function detectCodexDesktop(probe = { exists:
|
|
83788
|
-
const roots = ["/Applications",
|
|
83866
|
+
function detectCodexDesktop(probe = { exists: existsSync5, readUrlSchemes: realReadUrlSchemes }) {
|
|
83867
|
+
const roots = ["/Applications", path16.join(os16.homedir(), "Applications")];
|
|
83789
83868
|
return roots.some(
|
|
83790
83869
|
(root) => CODEX_APP_BUNDLES.some((bundle) => {
|
|
83791
|
-
const bundlePath =
|
|
83870
|
+
const bundlePath = path16.join(root, bundle);
|
|
83792
83871
|
return probe.exists(bundlePath) && probe.readUrlSchemes(bundlePath).includes("codex");
|
|
83793
83872
|
})
|
|
83794
83873
|
);
|
|
@@ -83796,9 +83875,9 @@ function detectCodexDesktop(probe = { exists: existsSync6, readUrlSchemes: realR
|
|
|
83796
83875
|
function realReadUrlSchemes(bundlePath) {
|
|
83797
83876
|
if (process.platform !== "darwin") return [];
|
|
83798
83877
|
try {
|
|
83799
|
-
const json2 =
|
|
83878
|
+
const json2 = execFileSync6(
|
|
83800
83879
|
"plutil",
|
|
83801
|
-
["-extract", "CFBundleURLTypes", "json", "-o", "-",
|
|
83880
|
+
["-extract", "CFBundleURLTypes", "json", "-o", "-", path16.join(bundlePath, "Contents", "Info.plist")],
|
|
83802
83881
|
{ stdio: ["ignore", "pipe", "ignore"] }
|
|
83803
83882
|
).toString();
|
|
83804
83883
|
const parsed = urlSchemesSchema.safeParse(JSON.parse(json2));
|
|
@@ -83810,7 +83889,7 @@ function realReadUrlSchemes(bundlePath) {
|
|
|
83810
83889
|
}
|
|
83811
83890
|
|
|
83812
83891
|
// src/menu.ts
|
|
83813
|
-
import
|
|
83892
|
+
import path17 from "node:path";
|
|
83814
83893
|
var MENU_CONTRACT = 1;
|
|
83815
83894
|
var CLIENT_NAMES = { claude: "Claude Code", codex: "Codex", cursor: "Cursor" };
|
|
83816
83895
|
function renderMenu(i) {
|
|
@@ -83856,7 +83935,7 @@ function renderMenu(i) {
|
|
|
83856
83935
|
}
|
|
83857
83936
|
if (i.connections.length > 0) {
|
|
83858
83937
|
items.push({ type: "separator" });
|
|
83859
|
-
items.push({ type: "section", title: "
|
|
83938
|
+
items.push({ type: "section", title: "Agents authorized for MCP" });
|
|
83860
83939
|
for (const connection of i.connections) {
|
|
83861
83940
|
const { row, action, warns } = connectionRow(connection, envArgs);
|
|
83862
83941
|
if (warns) attention = true;
|
|
@@ -83877,7 +83956,7 @@ function renderMenu(i) {
|
|
|
83877
83956
|
items.push({ type: "separator" });
|
|
83878
83957
|
items.push({ type: "action", title: "Open Powerplant", url: i.config.webUrl });
|
|
83879
83958
|
if (i.credentials !== null && i.service === "loaded" && !i.control.paused) {
|
|
83880
|
-
items.push({ type: "action", title: "Pause
|
|
83959
|
+
items.push({ type: "action", title: "Pause syncing", run: ["pause", ...envArgs] });
|
|
83881
83960
|
}
|
|
83882
83961
|
const icon = attention ? "attention" : i.control.paused ? "paused" : "running";
|
|
83883
83962
|
return {
|
|
@@ -83898,12 +83977,12 @@ function updateAction(i) {
|
|
|
83898
83977
|
function collectorBlock(i, envArgs, problem) {
|
|
83899
83978
|
const restart = {
|
|
83900
83979
|
type: "action",
|
|
83901
|
-
title: "Restart
|
|
83980
|
+
title: "Restart background sync",
|
|
83902
83981
|
run: ["restart", ...envArgs]
|
|
83903
83982
|
};
|
|
83904
83983
|
const viewLog = {
|
|
83905
83984
|
type: "action",
|
|
83906
|
-
title: "View
|
|
83985
|
+
title: "View background sync log",
|
|
83907
83986
|
file: serviceLogPath(i.config.appEnv)
|
|
83908
83987
|
};
|
|
83909
83988
|
switch (i.service) {
|
|
@@ -83912,19 +83991,19 @@ function collectorBlock(i, envArgs, problem) {
|
|
|
83912
83991
|
{
|
|
83913
83992
|
type: "status",
|
|
83914
83993
|
mark: "muted",
|
|
83915
|
-
title: "Background
|
|
83994
|
+
title: "Background sync isn't supported on this platform",
|
|
83916
83995
|
subtitle: "Sessions upload when you run: powerplant sync"
|
|
83917
83996
|
}
|
|
83918
83997
|
];
|
|
83919
83998
|
case "not-installed":
|
|
83920
83999
|
return [
|
|
83921
|
-
problem("Not uploading
|
|
83922
|
-
{ type: "action", title: "Set
|
|
84000
|
+
problem("Not uploading, the background sync isn't set up"),
|
|
84001
|
+
{ type: "action", title: "Set up background sync\u2026", terminal: ["init", ...envArgs] }
|
|
83923
84002
|
];
|
|
83924
84003
|
case "not-loaded":
|
|
83925
84004
|
return [
|
|
83926
|
-
problem("Not uploading
|
|
83927
|
-
{ type: "action", title: "Start
|
|
84005
|
+
problem("Not uploading, the background sync is stopped"),
|
|
84006
|
+
{ type: "action", title: "Start background sync", run: ["restart", ...envArgs] }
|
|
83928
84007
|
];
|
|
83929
84008
|
case "loaded":
|
|
83930
84009
|
break;
|
|
@@ -83933,15 +84012,15 @@ function collectorBlock(i, envArgs, problem) {
|
|
|
83933
84012
|
case "unreadable":
|
|
83934
84013
|
return [
|
|
83935
84014
|
problem(
|
|
83936
|
-
"
|
|
83937
|
-
"Its report was written by a different version
|
|
84015
|
+
"Background sync status can't be read",
|
|
84016
|
+
"Its report was written by a different version, restarting usually clears this."
|
|
83938
84017
|
),
|
|
83939
84018
|
restart
|
|
83940
84019
|
];
|
|
83941
84020
|
case "not-running":
|
|
83942
84021
|
return [
|
|
83943
84022
|
problem(
|
|
83944
|
-
"Not uploading
|
|
84023
|
+
"Not uploading, the background sync isn't running",
|
|
83945
84024
|
"It may be starting up. If this lasts, restart it."
|
|
83946
84025
|
),
|
|
83947
84026
|
restart
|
|
@@ -83949,7 +84028,7 @@ function collectorBlock(i, envArgs, problem) {
|
|
|
83949
84028
|
case "stalled":
|
|
83950
84029
|
return [
|
|
83951
84030
|
problem(
|
|
83952
|
-
`
|
|
84031
|
+
`Background sync quiet for ${duration3(i.daemon.staleMs)}, it may be stuck`,
|
|
83953
84032
|
lastUploadLine(i)
|
|
83954
84033
|
),
|
|
83955
84034
|
restart
|
|
@@ -83963,9 +84042,9 @@ function collectorBlock(i, envArgs, problem) {
|
|
|
83963
84042
|
type: "status",
|
|
83964
84043
|
mark: "paused",
|
|
83965
84044
|
title: "Syncing paused",
|
|
83966
|
-
subtitle: "The sync
|
|
84045
|
+
subtitle: "The background sync is running but uploads nothing."
|
|
83967
84046
|
},
|
|
83968
|
-
{ type: "action", title: "Resume
|
|
84047
|
+
{ type: "action", title: "Resume syncing", run: ["resume", ...envArgs] }
|
|
83969
84048
|
];
|
|
83970
84049
|
}
|
|
83971
84050
|
const status = i.daemon.status;
|
|
@@ -83979,7 +84058,7 @@ function collectorBlock(i, envArgs, problem) {
|
|
|
83979
84058
|
];
|
|
83980
84059
|
}
|
|
83981
84060
|
return [
|
|
83982
|
-
{ type: "status", mark: "ok", title: "
|
|
84061
|
+
{ type: "status", mark: "ok", title: "Background sync running", subtitle: lastUploadLine(i) }
|
|
83983
84062
|
];
|
|
83984
84063
|
}
|
|
83985
84064
|
var MAX_ACTIVE_AGENTS = 8;
|
|
@@ -84030,15 +84109,15 @@ function connectionRow(connection, envArgs) {
|
|
|
84030
84109
|
type: "connection",
|
|
84031
84110
|
mark,
|
|
84032
84111
|
name,
|
|
84033
|
-
state: connection.target === void 0 ? state : `${state}
|
|
84112
|
+
state: connection.target === void 0 ? state : `${state}, ${connection.target}`
|
|
84034
84113
|
});
|
|
84035
84114
|
switch (connection.state) {
|
|
84036
84115
|
case "signed-in":
|
|
84037
|
-
return { row: row("ok", "
|
|
84116
|
+
return { row: row("ok", "MCP access granted"), warns: false };
|
|
84038
84117
|
case "sign-in-needed":
|
|
84039
84118
|
return {
|
|
84040
|
-
row: row("warn", "
|
|
84041
|
-
action: fix(`
|
|
84119
|
+
row: row("warn", "MCP sign-in needed"),
|
|
84120
|
+
action: fix(`Give ${name} MCP access\u2026`),
|
|
84042
84121
|
warns: true
|
|
84043
84122
|
};
|
|
84044
84123
|
case "different-url":
|
|
@@ -84049,12 +84128,12 @@ function connectionRow(connection, envArgs) {
|
|
|
84049
84128
|
};
|
|
84050
84129
|
case "not-connected":
|
|
84051
84130
|
return {
|
|
84052
|
-
row: row("warn", connection.client === "cursor" ? "
|
|
84053
|
-
action: fix(connection.client === "cursor" ? "
|
|
84131
|
+
row: row("warn", connection.client === "cursor" ? "MCP not configured" : "Not connected"),
|
|
84132
|
+
action: fix(connection.client === "cursor" ? "Add Powerplant MCP to Cursor\u2026" : `Give ${name} MCP access\u2026`),
|
|
84054
84133
|
warns: true
|
|
84055
84134
|
};
|
|
84056
84135
|
case "configured":
|
|
84057
|
-
return { row: row("muted", "
|
|
84136
|
+
return { row: row("muted", "MCP configured in Cursor"), warns: false };
|
|
84058
84137
|
case "check-failed":
|
|
84059
84138
|
return { row: row("muted", "Can't check right now"), warns: false };
|
|
84060
84139
|
}
|
|
@@ -84074,13 +84153,13 @@ function moreItems(i) {
|
|
|
84074
84153
|
muted(`Enrolled ${i.credentials.enrolledAt.slice(0, 10)}`),
|
|
84075
84154
|
muted(`CLI ${i.cliVersion}`, daemonVersionNote(i))
|
|
84076
84155
|
];
|
|
84077
|
-
more.push({ type: "submenu", title: "
|
|
84156
|
+
more.push({ type: "submenu", title: "Background sync details", items: details });
|
|
84078
84157
|
}
|
|
84079
84158
|
more.push({ type: "action", title: "Copy Diagnostics", diagnostics: true });
|
|
84080
84159
|
if (i.config.appEnv !== "production") {
|
|
84081
84160
|
more.push({
|
|
84082
84161
|
type: "action",
|
|
84083
|
-
title: "View
|
|
84162
|
+
title: "View background sync log",
|
|
84084
84163
|
file: serviceLogPath(i.config.appEnv)
|
|
84085
84164
|
});
|
|
84086
84165
|
}
|
|
@@ -84092,18 +84171,18 @@ function captureLine(credentials) {
|
|
|
84092
84171
|
return `Syncs sessions under ${(credentials.scopePaths ?? []).join(", ")}`;
|
|
84093
84172
|
case "org-repos": {
|
|
84094
84173
|
const owners = credentials.allowedOwners ?? [];
|
|
84095
|
-
return owners.length > 0 ? `Syncs sessions in ${owners.join(", ")} repositories` : "Set to sync your organization's repositories, but none are linked yet
|
|
84174
|
+
return owners.length > 0 ? `Syncs sessions in ${owners.join(", ")} repositories` : "Set to sync your organization's repositories, but none are linked yet, nothing uploads";
|
|
84096
84175
|
}
|
|
84097
84176
|
}
|
|
84098
84177
|
}
|
|
84099
84178
|
function daemonVersionNote(i) {
|
|
84100
84179
|
if (!("status" in i.daemon)) return void 0;
|
|
84101
84180
|
const version2 = i.daemon.status.version;
|
|
84102
|
-
return version2 === i.cliVersion ? void 0 : `
|
|
84181
|
+
return version2 === i.cliVersion ? void 0 : `Background sync ${version2}`;
|
|
84103
84182
|
}
|
|
84104
84183
|
var VERSION_CACHE_TTL_MS = 60 * 6e4;
|
|
84105
84184
|
function versionCachePath(homeDir) {
|
|
84106
|
-
return
|
|
84185
|
+
return path17.join(collectorStateDir(homeDir), "version-check.json");
|
|
84107
84186
|
}
|
|
84108
84187
|
async function cachedLatestVersion(options) {
|
|
84109
84188
|
const raw = options.readTextFile(options.cacheFile);
|
|
@@ -84138,7 +84217,7 @@ function resumeSessionArgv(source, sessionId) {
|
|
|
84138
84217
|
const command = RESUME_COMMANDS[source];
|
|
84139
84218
|
if (command === void 0) {
|
|
84140
84219
|
throw new ExpectedCliError(
|
|
84141
|
-
`Sessions from "${source}" have no terminal to resume in
|
|
84220
|
+
`Sessions from "${source}" have no terminal to resume in, open them in Powerplant instead.`
|
|
84142
84221
|
);
|
|
84143
84222
|
}
|
|
84144
84223
|
return command(sessionId);
|
|
@@ -84151,7 +84230,7 @@ function runResumeSession(source, sessionId, spawn2 = spawnSync3) {
|
|
|
84151
84230
|
const result = spawn2(binary, args, { stdio: "inherit" });
|
|
84152
84231
|
if (result.error !== void 0) {
|
|
84153
84232
|
throw new ExpectedCliError(
|
|
84154
|
-
`Could not run ${binary} (${result.error.message})
|
|
84233
|
+
`Could not run ${binary} (${result.error.message}), is the ${binary} CLI installed on this machine?`
|
|
84155
84234
|
);
|
|
84156
84235
|
}
|
|
84157
84236
|
if (result.status !== null && result.status !== 0) {
|
|
@@ -84284,7 +84363,7 @@ ${RESTART_NOTE}`;
|
|
|
84284
84363
|
}
|
|
84285
84364
|
|
|
84286
84365
|
// src/version.ts
|
|
84287
|
-
var CLI_VERSION = true ? "0.
|
|
84366
|
+
var CLI_VERSION = true ? "0.4.1" : "0.0.0-checkout";
|
|
84288
84367
|
var CLI_PACKAGE_NAME = "@usepowerplant/cli";
|
|
84289
84368
|
|
|
84290
84369
|
// src/workspace.ts
|
|
@@ -84294,18 +84373,18 @@ var workspaceSchema = external_exports.object({
|
|
|
84294
84373
|
role: external_exports.string().min(1),
|
|
84295
84374
|
active: external_exports.boolean()
|
|
84296
84375
|
});
|
|
84297
|
-
var
|
|
84298
|
-
async function callApi(credentials,
|
|
84376
|
+
var FETCH_TIMEOUT_MS3 = 1e4;
|
|
84377
|
+
async function callApi(credentials, path18, init3, fetchImpl) {
|
|
84299
84378
|
let response;
|
|
84300
84379
|
try {
|
|
84301
|
-
response = await fetchImpl(`${credentials.apiUrl}${
|
|
84380
|
+
response = await fetchImpl(`${credentials.apiUrl}${path18}`, {
|
|
84302
84381
|
...init3,
|
|
84303
84382
|
headers: {
|
|
84304
84383
|
authorization: `Bearer ${credentials.token}`,
|
|
84305
84384
|
"content-type": "application/json",
|
|
84306
84385
|
...cliVersionHeaders()
|
|
84307
84386
|
},
|
|
84308
|
-
signal: AbortSignal.timeout(
|
|
84387
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS3)
|
|
84309
84388
|
});
|
|
84310
84389
|
} catch (error52) {
|
|
84311
84390
|
const detail = error52 instanceof Error ? error52.message : String(error52);
|
|
@@ -84313,11 +84392,11 @@ async function callApi(credentials, path19, init3, fetchImpl) {
|
|
|
84313
84392
|
}
|
|
84314
84393
|
if (response.status === 401) {
|
|
84315
84394
|
throw new ExpectedCliError(
|
|
84316
|
-
"Powerplant refused this machine's credentials
|
|
84395
|
+
"Powerplant refused this machine's credentials, run `powerplant enroll` to re-enroll it."
|
|
84317
84396
|
);
|
|
84318
84397
|
}
|
|
84319
84398
|
if (!response.ok) {
|
|
84320
|
-
throw new ExpectedCliError(`Powerplant answered ${response.status} for ${
|
|
84399
|
+
throw new ExpectedCliError(`Powerplant answered ${response.status} for ${path18}.`);
|
|
84321
84400
|
}
|
|
84322
84401
|
return response.json();
|
|
84323
84402
|
}
|
|
@@ -84325,7 +84404,7 @@ async function fetchWorkspaces(credentials, fetchImpl = fetch) {
|
|
|
84325
84404
|
const envelope = external_exports.object({ data: external_exports.object({ workspaces: external_exports.array(workspaceSchema) }) }).safeParse(await callApi(credentials, "/api/collector/workspaces", {}, fetchImpl));
|
|
84326
84405
|
if (!envelope.success) {
|
|
84327
84406
|
throw new ExpectedCliError(
|
|
84328
|
-
"Powerplant answered in a shape this CLI can't read
|
|
84407
|
+
"Powerplant answered in a shape this CLI can't read, run `powerplant update`."
|
|
84329
84408
|
);
|
|
84330
84409
|
}
|
|
84331
84410
|
return envelope.data.data.workspaces;
|
|
@@ -84340,7 +84419,7 @@ async function selectWorkspace(credentials, orgId, fetchImpl = fetch) {
|
|
|
84340
84419
|
}
|
|
84341
84420
|
function renderWorkspaces(workspaces) {
|
|
84342
84421
|
const lines = workspaces.map(
|
|
84343
|
-
(workspace) => `${workspace.active ? "*" : " "} ${workspace.name} (${workspace.role})${workspace.active ? "
|
|
84422
|
+
(workspace) => `${workspace.active ? "*" : " "} ${workspace.name} (${workspace.role})${workspace.active ? ", active" : ""}`
|
|
84344
84423
|
);
|
|
84345
84424
|
if (workspaces.length > 1) {
|
|
84346
84425
|
lines.push("", "Switch with: powerplant workspace <name>");
|
|
@@ -84359,7 +84438,7 @@ function matchWorkspace(workspaces, target) {
|
|
|
84359
84438
|
}
|
|
84360
84439
|
const ids = matches.map((workspace) => `${workspace.name} = ${workspace.id}`).join(", ");
|
|
84361
84440
|
throw new ExpectedCliError(
|
|
84362
|
-
`"${target}" names ${matches.length} of your workspaces
|
|
84441
|
+
`"${target}" names ${matches.length} of your workspaces, switch by id instead: ${ids}.`
|
|
84363
84442
|
);
|
|
84364
84443
|
}
|
|
84365
84444
|
async function runWorkspaceCommand(targetWords, credentials, print, fetchImpl = fetch) {
|
|
@@ -84380,39 +84459,39 @@ async function runWorkspaceCommand(targetWords, credentials, print, fetchImpl =
|
|
|
84380
84459
|
}
|
|
84381
84460
|
|
|
84382
84461
|
// src/cli.ts
|
|
84383
|
-
var USAGE = `powerplant
|
|
84462
|
+
var USAGE = `powerplant, the Powerplant background sync for this machine
|
|
84384
84463
|
|
|
84385
84464
|
Usage: powerplant <command> [options]
|
|
84386
84465
|
|
|
84387
84466
|
Commands:
|
|
84388
|
-
init
|
|
84389
|
-
|
|
84390
|
-
Safe to re-run
|
|
84391
|
-
connect
|
|
84392
|
-
Cursor)
|
|
84467
|
+
init Enroll this machine, start background sync, and give your
|
|
84468
|
+
coding agents Powerplant MCP access.
|
|
84469
|
+
Safe to re-run, finished steps are skipped.
|
|
84470
|
+
connect Give installed coding agents Powerplant MCP access (Claude Code,
|
|
84471
|
+
Codex, Cursor), also for later installs and re-authentication.
|
|
84393
84472
|
--client claude|codex|cursor adds just those (repeatable).
|
|
84394
84473
|
disconnect The inverse of connect: remove the Powerplant MCP entry (and
|
|
84395
84474
|
its sign-in) from every installed coding agent.
|
|
84396
84475
|
enroll (Re-)enroll this machine into your org (browser approval).
|
|
84397
|
-
status What the sync
|
|
84476
|
+
status What the background sync is doing on this machine (--json for tools).
|
|
84398
84477
|
doctor A diagnostics summary for support: status plus the redacted
|
|
84399
|
-
tail of the sync
|
|
84478
|
+
tail of the background sync log. Prints only, nothing is uploaded.
|
|
84400
84479
|
Paste the output into your email to support@forestwalk.ai.
|
|
84401
84480
|
update Update this CLI to the latest published version (via npm).
|
|
84402
|
-
restart Restart the background
|
|
84403
|
-
pause Pause syncing
|
|
84481
|
+
restart Restart the background sync.
|
|
84482
|
+
pause Pause syncing, the service keeps running, nothing uploads.
|
|
84404
84483
|
resume Resume syncing (runs a catch-up pass over the pause).
|
|
84405
84484
|
sync Run one sync pass in the foreground [--since <days>] [--dry-run].
|
|
84406
84485
|
folders The folders you explicitly sync on this machine:
|
|
84407
84486
|
powerplant folders [add <path> | remove <path>]. Additions on
|
|
84408
|
-
top of your org's allowlisted repos
|
|
84487
|
+
top of your org's allowlisted repos, no re-enroll needed.
|
|
84409
84488
|
workspace Your workspaces, and which one Powerplant and your connected
|
|
84410
84489
|
agents use: powerplant workspace [<name>] switches to <name>.
|
|
84411
84490
|
resume-session Reopen a synced session in its own CLI, right here in
|
|
84412
84491
|
this terminal: powerplant resume-session <claude-code|codex>
|
|
84413
84492
|
<session-id>.
|
|
84414
|
-
watch Run the sync
|
|
84415
|
-
uninstall Remove the background
|
|
84493
|
+
watch Run the background sync in the foreground.
|
|
84494
|
+
uninstall Remove the background sync [--forget also deletes this
|
|
84416
84495
|
machine's stored credentials].
|
|
84417
84496
|
|
|
84418
84497
|
Options:
|
|
@@ -84500,7 +84579,7 @@ ${USAGE}`);
|
|
|
84500
84579
|
let clients = clientFilter === void 0 ? detected : detected.filter((client) => clientFilter.has(client.client));
|
|
84501
84580
|
if (clientFilter !== void 0 && clients.length === 0) {
|
|
84502
84581
|
log3(
|
|
84503
|
-
`No ${[...clientFilter].join(" or ")} installation found on this machine
|
|
84582
|
+
`No ${[...clientFilter].join(" or ")} installation found on this machine, nothing to connect.`
|
|
84504
84583
|
);
|
|
84505
84584
|
return {
|
|
84506
84585
|
found: 0,
|
|
@@ -84517,7 +84596,7 @@ ${USAGE}`);
|
|
|
84517
84596
|
clients = await pickAgents(clients, { log: log3, promptCheckboxes: realCheckboxPrompt });
|
|
84518
84597
|
skipped = agentCount(detected) - agentCount(clients);
|
|
84519
84598
|
if (clients.length === 0) {
|
|
84520
|
-
log3(`MCP wasn't added
|
|
84599
|
+
log3(`Powerplant MCP wasn't added to any agents. Run any time: ${connectCommand}`);
|
|
84521
84600
|
return {
|
|
84522
84601
|
found: agentCount(detected),
|
|
84523
84602
|
connected: 0,
|
|
@@ -84575,7 +84654,7 @@ ${USAGE}`);
|
|
|
84575
84654
|
case "connect": {
|
|
84576
84655
|
const outcome = await connect3(console.log);
|
|
84577
84656
|
if (outcome.pending > 0) {
|
|
84578
|
-
console.log(`Some logins are unfinished
|
|
84657
|
+
console.log(`Some logins are unfinished, re-run \`${connectCommand}\` any time.`);
|
|
84579
84658
|
}
|
|
84580
84659
|
if (outcome.failed > 0) process.exitCode = 1;
|
|
84581
84660
|
return;
|
|
@@ -84662,7 +84741,7 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
84662
84741
|
const clients = mergeDetectedClients(
|
|
84663
84742
|
detectClients({ whichAll: whichAllWith(probePath), budget }),
|
|
84664
84743
|
saved,
|
|
84665
|
-
|
|
84744
|
+
existsSync6
|
|
84666
84745
|
);
|
|
84667
84746
|
const [latestVersion, oldestSupportedVersion, memberSessions, grantedClientIds] = await Promise.all([
|
|
84668
84747
|
cachedLatestVersion({
|
|
@@ -84705,7 +84784,7 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
84705
84784
|
const stored = loadCredentialsSafely(config2);
|
|
84706
84785
|
if (stored.credentials === null) {
|
|
84707
84786
|
throw new ExpectedCliError(
|
|
84708
|
-
`This machine isn't enrolled yet
|
|
84787
|
+
`This machine isn't enrolled yet, run \`powerplant init\` first.${stored.credentialsError ? ` (${stored.credentialsError})` : ""}`
|
|
84709
84788
|
);
|
|
84710
84789
|
}
|
|
84711
84790
|
await runWorkspaceCommand(positionals.slice(1), stored.credentials, console.log);
|
|
@@ -84720,31 +84799,31 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
84720
84799
|
const npm = spawnSync5("npm", ["install", "-g", CLI_PACKAGE_NAME], { stdio: "inherit" });
|
|
84721
84800
|
if (npm.error) {
|
|
84722
84801
|
throw new ExpectedCliError(
|
|
84723
|
-
`Could not run npm (${npm.error.message})
|
|
84802
|
+
`Could not run npm (${npm.error.message}), update by hand: npm install -g ${CLI_PACKAGE_NAME}`
|
|
84724
84803
|
);
|
|
84725
84804
|
}
|
|
84726
84805
|
if (npm.status !== 0) {
|
|
84727
|
-
throw new ExpectedCliError("npm install failed
|
|
84806
|
+
throw new ExpectedCliError("npm install failed, see the output above.");
|
|
84728
84807
|
}
|
|
84729
84808
|
console.log(updatedMessage(installedGlobalVersion(CLI_PACKAGE_NAME)));
|
|
84730
84809
|
return;
|
|
84731
84810
|
}
|
|
84732
84811
|
case "restart": {
|
|
84733
84812
|
if (restartService(config2) === "not-installed") {
|
|
84734
|
-
throw new ExpectedCliError("No background
|
|
84813
|
+
throw new ExpectedCliError("No background sync installed, run: powerplant init");
|
|
84735
84814
|
}
|
|
84736
|
-
console.log("Background
|
|
84815
|
+
console.log("Background sync restarted.");
|
|
84737
84816
|
return;
|
|
84738
84817
|
}
|
|
84739
84818
|
case "pause": {
|
|
84740
84819
|
writeCollectorControl(config2.appEnv, { paused: true, pausedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
84741
|
-
console.log("Syncing paused
|
|
84820
|
+
console.log("Syncing paused, the background sync keeps running but uploads nothing.");
|
|
84742
84821
|
console.log("Resume with: powerplant resume");
|
|
84743
84822
|
return;
|
|
84744
84823
|
}
|
|
84745
84824
|
case "resume": {
|
|
84746
84825
|
writeCollectorControl(config2.appEnv, { paused: false, resumedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
84747
|
-
console.log("Syncing resumed
|
|
84826
|
+
console.log("Syncing resumed, the background sync runs a catch-up pass covering the pause.");
|
|
84748
84827
|
return;
|
|
84749
84828
|
}
|
|
84750
84829
|
case "sync": {
|
|
@@ -84783,18 +84862,18 @@ The access you granted these agents stays on your Powerplant account until you r
|
|
|
84783
84862
|
const removed = uninstallService(config2);
|
|
84784
84863
|
clearCollectorStatus(config2.appEnv);
|
|
84785
84864
|
clearCollectorControl(config2.appEnv);
|
|
84786
|
-
console.log(removed ? "Background
|
|
84865
|
+
console.log(removed ? "Background sync removed." : "No background sync was installed.");
|
|
84787
84866
|
if (values.forget) {
|
|
84788
84867
|
deleteCredentials(config2.appEnv);
|
|
84789
|
-
console.log("Stored credentials deleted
|
|
84868
|
+
console.log("Stored credentials deleted, this machine is no longer enrolled.");
|
|
84790
84869
|
} else {
|
|
84791
84870
|
console.log(
|
|
84792
|
-
"Credentials kept
|
|
84871
|
+
"Credentials kept, `powerplant init` re-installs without re-enrolling. (--forget deletes them.)"
|
|
84793
84872
|
);
|
|
84794
84873
|
}
|
|
84795
84874
|
if (anyClientStillConnected(detectClients(), { run: realRun, readTextFile: realReadTextFile })) {
|
|
84796
84875
|
console.log(
|
|
84797
|
-
"Your coding agents are still connected to the Powerplant MCP server
|
|
84876
|
+
"Your coding agents are still connected to the Powerplant MCP server, remove those connections with: powerplant disconnect"
|
|
84798
84877
|
);
|
|
84799
84878
|
}
|
|
84800
84879
|
return;
|