@primitive.ai/prim 0.1.0-alpha.91 → 0.1.0-alpha.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -2
- package/dist/{chunk-67VNLLBN.js → chunk-2GP5UFV7.js} +1 -0
- package/dist/{chunk-VW3FDYRT.js → chunk-36TWVNBE.js} +6 -6
- package/dist/{chunk-HU4PW6I6.js → chunk-C3VAA5CG.js} +1 -1
- package/dist/{chunk-FOLKHXLJ.js → chunk-DCJN6LZH.js} +37 -5
- package/dist/{chunk-M6RIJVRE.js → chunk-DSWT6BCC.js} +78 -4
- package/dist/{chunk-FBAYCS3X.js → chunk-DXJQR4QI.js} +150 -38
- package/dist/{chunk-PCVGBE5B.js → chunk-G2VMA2QO.js} +2 -1
- package/dist/{chunk-NAHHFSLH.js → chunk-ICM2XCXS.js} +2 -2
- package/dist/{chunk-OAAP2MY6.js → chunk-K7D2EYBS.js} +2 -2
- package/dist/{chunk-5AFRMOPX.js → chunk-OH3EZXYX.js} +1 -1
- package/dist/{chunk-KFXF2V5G.js → chunk-OTHKG76J.js} +1 -1
- package/dist/chunk-OYHYCK4K.js +13 -0
- package/dist/{chunk-FKXFUUWJ.js → chunk-TYAHC25F.js} +1 -1
- package/dist/{chunk-5GYQ4J3D.js → chunk-UKUAAAXE.js} +2 -2
- package/dist/{chunk-EWZMDD44.js → chunk-X64HTHUF.js} +22 -3
- package/dist/{chunk-WX52U7Z2.js → chunk-ZU563PQI.js} +58 -2
- package/dist/daemon/server.js +382 -124
- package/dist/hook-runtime/daemon/server.js +382 -124
- package/dist/hook-runtime/hooks/post-commit.js +57 -39
- package/dist/hook-runtime/hooks/post-rewrite.js +58 -40
- package/dist/hook-runtime/hooks/post-tool-use.js +111 -78
- package/dist/hook-runtime/hooks/pre-tool-use.js +48 -26
- package/dist/hook-runtime/hooks/prim-hook.js +157 -117
- package/dist/hook-runtime/hooks/session-end.js +1 -1
- package/dist/hook-runtime/hooks/session-start.js +38 -4
- package/dist/hook-runtime/index.js +1293 -526
- package/dist/hook-runtime/statusline-main.js +23 -1
- package/dist/hooks/post-commit.js +11 -8
- package/dist/hooks/post-rewrite.js +11 -8
- package/dist/hooks/post-tool-use.js +13 -15
- package/dist/hooks/pre-commit.js +4 -4
- package/dist/hooks/pre-tool-use.js +10 -12
- package/dist/hooks/prim-hook.js +17 -14
- package/dist/hooks/session-end.js +4 -4
- package/dist/hooks/session-start.js +12 -36
- package/dist/index.js +867 -291
- package/dist/statusline-main.js +23 -1
- package/package.json +1 -1
- package/dist/chunk-BTNNEH2W.js +0 -79
|
@@ -3035,7 +3035,7 @@ var require_commander = __commonJS({
|
|
|
3035
3035
|
var require_polyfills = __commonJS({
|
|
3036
3036
|
"node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js"(exports, module) {
|
|
3037
3037
|
"use strict";
|
|
3038
|
-
var
|
|
3038
|
+
var constants9 = __require("constants");
|
|
3039
3039
|
var origCwd = process.cwd;
|
|
3040
3040
|
var cwd = null;
|
|
3041
3041
|
var platform2 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
@@ -3059,7 +3059,7 @@ var require_polyfills = __commonJS({
|
|
|
3059
3059
|
var chdir;
|
|
3060
3060
|
module.exports = patch;
|
|
3061
3061
|
function patch(fs5) {
|
|
3062
|
-
if (
|
|
3062
|
+
if (constants9.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
3063
3063
|
patchLchmod(fs5);
|
|
3064
3064
|
}
|
|
3065
3065
|
if (!fs5.lutimes) {
|
|
@@ -3161,7 +3161,7 @@ var require_polyfills = __commonJS({
|
|
|
3161
3161
|
fs6.lchmod = function(path9, mode, callback) {
|
|
3162
3162
|
fs6.open(
|
|
3163
3163
|
path9,
|
|
3164
|
-
|
|
3164
|
+
constants9.O_WRONLY | constants9.O_SYMLINK,
|
|
3165
3165
|
mode,
|
|
3166
3166
|
function(err, fd) {
|
|
3167
3167
|
if (err) {
|
|
@@ -3177,7 +3177,7 @@ var require_polyfills = __commonJS({
|
|
|
3177
3177
|
);
|
|
3178
3178
|
};
|
|
3179
3179
|
fs6.lchmodSync = function(path9, mode) {
|
|
3180
|
-
var fd = fs6.openSync(path9,
|
|
3180
|
+
var fd = fs6.openSync(path9, constants9.O_WRONLY | constants9.O_SYMLINK, mode);
|
|
3181
3181
|
var threw = true;
|
|
3182
3182
|
var ret;
|
|
3183
3183
|
try {
|
|
@@ -3197,9 +3197,9 @@ var require_polyfills = __commonJS({
|
|
|
3197
3197
|
};
|
|
3198
3198
|
}
|
|
3199
3199
|
function patchLutimes(fs6) {
|
|
3200
|
-
if (
|
|
3200
|
+
if (constants9.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
|
|
3201
3201
|
fs6.lutimes = function(path9, at, mt, cb) {
|
|
3202
|
-
fs6.open(path9,
|
|
3202
|
+
fs6.open(path9, constants9.O_SYMLINK, function(er, fd) {
|
|
3203
3203
|
if (er) {
|
|
3204
3204
|
if (cb) cb(er);
|
|
3205
3205
|
return;
|
|
@@ -3212,7 +3212,7 @@ var require_polyfills = __commonJS({
|
|
|
3212
3212
|
});
|
|
3213
3213
|
};
|
|
3214
3214
|
fs6.lutimesSync = function(path9, at, mt) {
|
|
3215
|
-
var fd = fs6.openSync(path9,
|
|
3215
|
+
var fd = fs6.openSync(path9, constants9.O_SYMLINK);
|
|
3216
3216
|
var ret;
|
|
3217
3217
|
var threw = true;
|
|
3218
3218
|
try {
|
|
@@ -3495,14 +3495,14 @@ var require_graceful_fs = __commonJS({
|
|
|
3495
3495
|
return close;
|
|
3496
3496
|
})(fs5.close);
|
|
3497
3497
|
fs5.closeSync = (function(fs$closeSync) {
|
|
3498
|
-
function
|
|
3498
|
+
function closeSync9(fd) {
|
|
3499
3499
|
fs$closeSync.apply(fs5, arguments);
|
|
3500
3500
|
resetQueue();
|
|
3501
3501
|
}
|
|
3502
|
-
Object.defineProperty(
|
|
3502
|
+
Object.defineProperty(closeSync9, previousSymbol, {
|
|
3503
3503
|
value: fs$closeSync
|
|
3504
3504
|
});
|
|
3505
|
-
return
|
|
3505
|
+
return closeSync9;
|
|
3506
3506
|
})(fs5.closeSync);
|
|
3507
3507
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
3508
3508
|
process.on("exit", function() {
|
|
@@ -4963,7 +4963,7 @@ var require_rc = __commonJS({
|
|
|
4963
4963
|
"node_modules/.pnpm/rc@1.2.8/node_modules/rc/index.js"(exports, module) {
|
|
4964
4964
|
"use strict";
|
|
4965
4965
|
var cc = require_utils();
|
|
4966
|
-
var
|
|
4966
|
+
var join30 = __require("path").join;
|
|
4967
4967
|
var deepExtend = require_deep_extend();
|
|
4968
4968
|
var etc = "/etc";
|
|
4969
4969
|
var win = process.platform === "win32";
|
|
@@ -4988,15 +4988,15 @@ var require_rc = __commonJS({
|
|
|
4988
4988
|
}
|
|
4989
4989
|
if (!win)
|
|
4990
4990
|
[
|
|
4991
|
-
|
|
4992
|
-
|
|
4991
|
+
join30(etc, name, "config"),
|
|
4992
|
+
join30(etc, name + "rc")
|
|
4993
4993
|
].forEach(addConfigFile);
|
|
4994
4994
|
if (home)
|
|
4995
4995
|
[
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
4996
|
+
join30(home, ".config", name, "config"),
|
|
4997
|
+
join30(home, ".config", name),
|
|
4998
|
+
join30(home, "." + name, "config"),
|
|
4999
|
+
join30(home, "." + name + "rc")
|
|
5000
5000
|
].forEach(addConfigFile);
|
|
5001
5001
|
addConfigFile(cc.find("." + name + "rc"));
|
|
5002
5002
|
if (env4.config) addConfigFile(env4.config);
|
|
@@ -5014,7 +5014,7 @@ var require_rc = __commonJS({
|
|
|
5014
5014
|
var require_polyfills2 = __commonJS({
|
|
5015
5015
|
"node_modules/.pnpm/graceful-fs@4.2.10/node_modules/graceful-fs/polyfills.js"(exports, module) {
|
|
5016
5016
|
"use strict";
|
|
5017
|
-
var
|
|
5017
|
+
var constants9 = __require("constants");
|
|
5018
5018
|
var origCwd = process.cwd;
|
|
5019
5019
|
var cwd = null;
|
|
5020
5020
|
var platform2 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
@@ -5038,7 +5038,7 @@ var require_polyfills2 = __commonJS({
|
|
|
5038
5038
|
var chdir;
|
|
5039
5039
|
module.exports = patch;
|
|
5040
5040
|
function patch(fs5) {
|
|
5041
|
-
if (
|
|
5041
|
+
if (constants9.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
5042
5042
|
patchLchmod(fs5);
|
|
5043
5043
|
}
|
|
5044
5044
|
if (!fs5.lutimes) {
|
|
@@ -5140,7 +5140,7 @@ var require_polyfills2 = __commonJS({
|
|
|
5140
5140
|
fs6.lchmod = function(path9, mode, callback) {
|
|
5141
5141
|
fs6.open(
|
|
5142
5142
|
path9,
|
|
5143
|
-
|
|
5143
|
+
constants9.O_WRONLY | constants9.O_SYMLINK,
|
|
5144
5144
|
mode,
|
|
5145
5145
|
function(err, fd) {
|
|
5146
5146
|
if (err) {
|
|
@@ -5156,7 +5156,7 @@ var require_polyfills2 = __commonJS({
|
|
|
5156
5156
|
);
|
|
5157
5157
|
};
|
|
5158
5158
|
fs6.lchmodSync = function(path9, mode) {
|
|
5159
|
-
var fd = fs6.openSync(path9,
|
|
5159
|
+
var fd = fs6.openSync(path9, constants9.O_WRONLY | constants9.O_SYMLINK, mode);
|
|
5160
5160
|
var threw = true;
|
|
5161
5161
|
var ret;
|
|
5162
5162
|
try {
|
|
@@ -5176,9 +5176,9 @@ var require_polyfills2 = __commonJS({
|
|
|
5176
5176
|
};
|
|
5177
5177
|
}
|
|
5178
5178
|
function patchLutimes(fs6) {
|
|
5179
|
-
if (
|
|
5179
|
+
if (constants9.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
|
|
5180
5180
|
fs6.lutimes = function(path9, at, mt, cb) {
|
|
5181
|
-
fs6.open(path9,
|
|
5181
|
+
fs6.open(path9, constants9.O_SYMLINK, function(er, fd) {
|
|
5182
5182
|
if (er) {
|
|
5183
5183
|
if (cb) cb(er);
|
|
5184
5184
|
return;
|
|
@@ -5191,7 +5191,7 @@ var require_polyfills2 = __commonJS({
|
|
|
5191
5191
|
});
|
|
5192
5192
|
};
|
|
5193
5193
|
fs6.lutimesSync = function(path9, at, mt) {
|
|
5194
|
-
var fd = fs6.openSync(path9,
|
|
5194
|
+
var fd = fs6.openSync(path9, constants9.O_SYMLINK);
|
|
5195
5195
|
var ret;
|
|
5196
5196
|
var threw = true;
|
|
5197
5197
|
try {
|
|
@@ -5474,14 +5474,14 @@ var require_graceful_fs2 = __commonJS({
|
|
|
5474
5474
|
return close;
|
|
5475
5475
|
})(fs5.close);
|
|
5476
5476
|
fs5.closeSync = (function(fs$closeSync) {
|
|
5477
|
-
function
|
|
5477
|
+
function closeSync9(fd) {
|
|
5478
5478
|
fs$closeSync.apply(fs5, arguments);
|
|
5479
5479
|
resetQueue();
|
|
5480
5480
|
}
|
|
5481
|
-
Object.defineProperty(
|
|
5481
|
+
Object.defineProperty(closeSync9, previousSymbol, {
|
|
5482
5482
|
value: fs$closeSync
|
|
5483
5483
|
});
|
|
5484
|
-
return
|
|
5484
|
+
return closeSync9;
|
|
5485
5485
|
})(fs5.closeSync);
|
|
5486
5486
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
5487
5487
|
process.on("exit", function() {
|
|
@@ -6340,11 +6340,11 @@ var require_util = __commonJS({
|
|
|
6340
6340
|
if (files.includes("node_modules") || files.includes("package.json") || files.includes("package.json5") || files.includes("package.yaml") || files.includes("pnpm-workspace.yaml")) {
|
|
6341
6341
|
return name2;
|
|
6342
6342
|
}
|
|
6343
|
-
const
|
|
6344
|
-
if (
|
|
6343
|
+
const dirname21 = path9.dirname(name2);
|
|
6344
|
+
if (dirname21 === name2) {
|
|
6345
6345
|
return original;
|
|
6346
6346
|
}
|
|
6347
|
-
return find(
|
|
6347
|
+
return find(dirname21, original);
|
|
6348
6348
|
} catch (error) {
|
|
6349
6349
|
if (name2 === original) {
|
|
6350
6350
|
if (error.code === "ENOENT") {
|
|
@@ -8313,7 +8313,7 @@ var require_semver2 = __commonJS({
|
|
|
8313
8313
|
"node_modules/.pnpm/semver@7.7.4/node_modules/semver/index.js"(exports, module) {
|
|
8314
8314
|
"use strict";
|
|
8315
8315
|
var internalRe = require_re();
|
|
8316
|
-
var
|
|
8316
|
+
var constants9 = require_constants();
|
|
8317
8317
|
var SemVer = require_semver();
|
|
8318
8318
|
var identifiers = require_identifiers();
|
|
8319
8319
|
var parse2 = require_parse();
|
|
@@ -8395,8 +8395,8 @@ var require_semver2 = __commonJS({
|
|
|
8395
8395
|
re: internalRe.re,
|
|
8396
8396
|
src: internalRe.src,
|
|
8397
8397
|
tokens: internalRe.t,
|
|
8398
|
-
SEMVER_SPEC_VERSION:
|
|
8399
|
-
RELEASE_TYPES:
|
|
8398
|
+
SEMVER_SPEC_VERSION: constants9.SEMVER_SPEC_VERSION,
|
|
8399
|
+
RELEASE_TYPES: constants9.RELEASE_TYPES,
|
|
8400
8400
|
compareIdentifiers: identifiers.compareIdentifiers,
|
|
8401
8401
|
rcompareIdentifiers: identifiers.rcompareIdentifiers
|
|
8402
8402
|
};
|
|
@@ -8896,8 +8896,8 @@ var require_ucs2length = __commonJS({
|
|
|
8896
8896
|
});
|
|
8897
8897
|
|
|
8898
8898
|
// src/index.ts
|
|
8899
|
-
import { readFileSync as
|
|
8900
|
-
import { dirname as
|
|
8899
|
+
import { readFileSync as readFileSync24 } from "fs";
|
|
8900
|
+
import { dirname as dirname20, resolve as resolve10 } from "path";
|
|
8901
8901
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
8902
8902
|
|
|
8903
8903
|
// node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
|
|
@@ -9257,14 +9257,14 @@ var Temp = {
|
|
|
9257
9257
|
}
|
|
9258
9258
|
},
|
|
9259
9259
|
truncate: (filePath) => {
|
|
9260
|
-
const
|
|
9261
|
-
if (
|
|
9260
|
+
const basename5 = path2.basename(filePath);
|
|
9261
|
+
if (basename5.length <= LIMIT_BASENAME_LENGTH)
|
|
9262
9262
|
return filePath;
|
|
9263
|
-
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(
|
|
9263
|
+
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename5);
|
|
9264
9264
|
if (!truncable)
|
|
9265
9265
|
return filePath;
|
|
9266
|
-
const truncationLength =
|
|
9267
|
-
return `${filePath.slice(0, -
|
|
9266
|
+
const truncationLength = basename5.length - LIMIT_BASENAME_LENGTH;
|
|
9267
|
+
return `${filePath.slice(0, -basename5.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
|
|
9268
9268
|
}
|
|
9269
9269
|
};
|
|
9270
9270
|
node_default(Temp.purgeSyncAll);
|
|
@@ -12398,13 +12398,13 @@ function sameIssuerUrl(value, field, issuer) {
|
|
|
12398
12398
|
return parsed.toString();
|
|
12399
12399
|
}
|
|
12400
12400
|
function parseWorkosConnectConfiguration(value) {
|
|
12401
|
-
const
|
|
12401
|
+
const record3 = recordFrom(value, "Connect discovery");
|
|
12402
12402
|
const expectedKeys = ["protocol_version", "issuer", "client_id", "default_scopes"];
|
|
12403
|
-
if (
|
|
12403
|
+
if (record3.protocol_version !== 1 || Object.keys(record3).length !== expectedKeys.length || expectedKeys.some((key) => !Object.hasOwn(record3, key)) || !Array.isArray(record3.default_scopes) || record3.default_scopes.length !== WORKOS_CONNECT_DEFAULT_SCOPES.length || record3.default_scopes.some((scope, index) => scope !== WORKOS_CONNECT_DEFAULT_SCOPES[index])) {
|
|
12404
12404
|
throw new WorkosConnectProtocolError("invalid_response", "Connect discovery is invalid");
|
|
12405
12405
|
}
|
|
12406
|
-
const issuer = canonicalIssuer(
|
|
12407
|
-
const clientId = exactString(
|
|
12406
|
+
const issuer = canonicalIssuer(record3.issuer);
|
|
12407
|
+
const clientId = exactString(record3.client_id, "client_id", MAX_CLIENT_ID_LENGTH);
|
|
12408
12408
|
if (!CONNECT_CLIENT_ID_PATTERN.test(clientId)) {
|
|
12409
12409
|
throw new WorkosConnectProtocolError("invalid_response", "Connect discovery is invalid");
|
|
12410
12410
|
}
|
|
@@ -12415,14 +12415,14 @@ function parseWorkosConnectConfiguration(value) {
|
|
|
12415
12415
|
};
|
|
12416
12416
|
}
|
|
12417
12417
|
function parseWorkosConnectCredentialMetadata(value) {
|
|
12418
|
-
const
|
|
12419
|
-
if (
|
|
12418
|
+
const record3 = recordFrom(value, "credential metadata");
|
|
12419
|
+
if (record3.version !== 1 || record3.family !== "workos_connect") {
|
|
12420
12420
|
throw new WorkosConnectProtocolError("invalid_metadata", "credential metadata is invalid");
|
|
12421
12421
|
}
|
|
12422
|
-
const issuer = canonicalIssuer(
|
|
12423
|
-
const clientId = exactString(
|
|
12424
|
-
const accessTokenHash = exactString(
|
|
12425
|
-
const refreshTokenHash = exactString(
|
|
12422
|
+
const issuer = canonicalIssuer(record3.issuer);
|
|
12423
|
+
const clientId = exactString(record3.clientId, "clientId", MAX_CLIENT_ID_LENGTH);
|
|
12424
|
+
const accessTokenHash = exactString(record3.accessTokenHash, "accessTokenHash", 64);
|
|
12425
|
+
const refreshTokenHash = exactString(record3.refreshTokenHash, "refreshTokenHash", 64);
|
|
12426
12426
|
if (!CONNECT_CLIENT_ID_PATTERN.test(clientId)) {
|
|
12427
12427
|
throw new WorkosConnectProtocolError("invalid_metadata", "credential clientId is invalid");
|
|
12428
12428
|
}
|
|
@@ -12526,37 +12526,37 @@ async function requestWorkosDeviceAuthorization(configuration, fetchImpl = fetch
|
|
|
12526
12526
|
`Device authorization returned HTTP ${response.status}`
|
|
12527
12527
|
);
|
|
12528
12528
|
}
|
|
12529
|
-
const
|
|
12529
|
+
const record3 = recordFrom(value, "device authorization");
|
|
12530
12530
|
const verificationUri = sameIssuerUrl(
|
|
12531
|
-
|
|
12531
|
+
record3.verification_uri,
|
|
12532
12532
|
"verification_uri",
|
|
12533
12533
|
configuration.issuer
|
|
12534
12534
|
);
|
|
12535
12535
|
return {
|
|
12536
|
-
deviceCode: exactString(
|
|
12537
|
-
userCode: exactString(
|
|
12536
|
+
deviceCode: exactString(record3.device_code, "device_code", MAX_DEVICE_CODE_LENGTH),
|
|
12537
|
+
userCode: exactString(record3.user_code, "user_code", MAX_USER_CODE_LENGTH),
|
|
12538
12538
|
verificationUri,
|
|
12539
|
-
verificationUriComplete:
|
|
12540
|
-
|
|
12539
|
+
verificationUriComplete: record3.verification_uri_complete === void 0 ? void 0 : sameIssuerUrl(
|
|
12540
|
+
record3.verification_uri_complete,
|
|
12541
12541
|
"verification_uri_complete",
|
|
12542
12542
|
configuration.issuer
|
|
12543
12543
|
),
|
|
12544
|
-
expiresIn: safeInteger(
|
|
12545
|
-
interval: safeInteger(
|
|
12544
|
+
expiresIn: safeInteger(record3.expires_in, "expires_in", 1, MAX_DEVICE_LIFETIME_SECONDS),
|
|
12545
|
+
interval: safeInteger(record3.interval ?? 5, "interval", 1, MAX_INTERVAL_SECONDS)
|
|
12546
12546
|
};
|
|
12547
12547
|
}
|
|
12548
12548
|
function parseWorkosConnectTokens(value, options = {}) {
|
|
12549
|
-
const
|
|
12549
|
+
const record3 = recordFrom(value, "token response");
|
|
12550
12550
|
const accessToken = exactString(
|
|
12551
|
-
|
|
12551
|
+
record3.access_token,
|
|
12552
12552
|
"access_token",
|
|
12553
12553
|
WORKOS_CONNECT_RESPONSE_MAX_BYTES
|
|
12554
12554
|
);
|
|
12555
|
-
const refreshToken2 =
|
|
12555
|
+
const refreshToken2 = record3.refresh_token === void 0 && options.fallbackRefreshToken !== void 0 ? options.fallbackRefreshToken : exactString(record3.refresh_token, "refresh_token", WORKOS_CONNECT_RESPONSE_MAX_BYTES);
|
|
12556
12556
|
return {
|
|
12557
12557
|
accessToken,
|
|
12558
12558
|
refreshToken: refreshToken2,
|
|
12559
|
-
expiresIn:
|
|
12559
|
+
expiresIn: record3.expires_in === void 0 ? void 0 : safeInteger(record3.expires_in, "expires_in", 1, MAX_TOKEN_LIFETIME_SECONDS)
|
|
12560
12560
|
};
|
|
12561
12561
|
}
|
|
12562
12562
|
function providerError(value) {
|
|
@@ -12678,15 +12678,15 @@ function parseLegacyBrokerCredentialMetadata(value) {
|
|
|
12678
12678
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
12679
12679
|
throw new Error("credential family is invalid");
|
|
12680
12680
|
}
|
|
12681
|
-
const
|
|
12682
|
-
if (
|
|
12681
|
+
const record3 = value;
|
|
12682
|
+
if (record3.version !== 1 || record3.family !== "legacy_broker" || typeof record3.accessTokenHash !== "string" || typeof record3.refreshTokenHash !== "string" || !/^[a-f0-9]{64}$/u.test(record3.accessTokenHash) || !/^[a-f0-9]{64}$/u.test(record3.refreshTokenHash)) {
|
|
12683
12683
|
throw new Error("credential family is invalid");
|
|
12684
12684
|
}
|
|
12685
12685
|
return {
|
|
12686
12686
|
version: 1,
|
|
12687
12687
|
family: "legacy_broker",
|
|
12688
|
-
accessTokenHash:
|
|
12689
|
-
refreshTokenHash:
|
|
12688
|
+
accessTokenHash: record3.accessTokenHash,
|
|
12689
|
+
refreshTokenHash: record3.refreshTokenHash
|
|
12690
12690
|
};
|
|
12691
12691
|
}
|
|
12692
12692
|
function readBoundedCredentialJson(path9) {
|
|
@@ -12721,9 +12721,9 @@ function readCredentialFamily(path9) {
|
|
|
12721
12721
|
}
|
|
12722
12722
|
function isCredentialMigrationSentinel(value) {
|
|
12723
12723
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
12724
|
-
const
|
|
12725
|
-
const keys = Object.keys(
|
|
12726
|
-
return keys.length === 2 && keys[0] === "state" && keys[1] === "version" &&
|
|
12724
|
+
const record3 = value;
|
|
12725
|
+
const keys = Object.keys(record3).sort();
|
|
12726
|
+
return keys.length === 2 && keys[0] === "state" && keys[1] === "version" && record3.version === CREDENTIAL_MIGRATION_VERSION && record3.state === CREDENTIAL_MIGRATION_STATE;
|
|
12727
12727
|
}
|
|
12728
12728
|
function readCredentialMigrationState(path9 = CREDENTIAL_MIGRATION_PATH) {
|
|
12729
12729
|
const parsed = readBoundedCredentialJson(path9);
|
|
@@ -13837,10 +13837,10 @@ async function performTokenRefresh(options = {}) {
|
|
|
13837
13837
|
}
|
|
13838
13838
|
return void 0;
|
|
13839
13839
|
}
|
|
13840
|
-
const
|
|
13841
|
-
accessToken = typeof
|
|
13842
|
-
replacementRefreshToken = typeof
|
|
13843
|
-
expiresIn = typeof
|
|
13840
|
+
const record3 = typeof data === "object" && data !== null && !Array.isArray(data) ? data : void 0;
|
|
13841
|
+
accessToken = typeof record3?.access_token === "string" ? record3.access_token.trim() : "";
|
|
13842
|
+
replacementRefreshToken = typeof record3?.refresh_token === "string" ? record3.refresh_token.trim() : "";
|
|
13843
|
+
expiresIn = typeof record3?.expires_in === "number" && Number.isFinite(record3.expires_in) ? record3.expires_in : void 0;
|
|
13844
13844
|
if (!(accessToken && replacementRefreshToken)) {
|
|
13845
13845
|
if (readTrimmed2(REFRESH_TOKEN_PATH) === currentGeneration) {
|
|
13846
13846
|
writeTerminalFingerprint(currentGeneration);
|
|
@@ -31856,19 +31856,19 @@ var defaultDependencies = {
|
|
|
31856
31856
|
function isSafeVersion(value) {
|
|
31857
31857
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
31858
31858
|
}
|
|
31859
|
-
function optionalStringArray(
|
|
31860
|
-
const value =
|
|
31859
|
+
function optionalStringArray(record3, key) {
|
|
31860
|
+
const value = record3[key];
|
|
31861
31861
|
if (value === void 0) return void 0;
|
|
31862
31862
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) return void 0;
|
|
31863
31863
|
return [...value];
|
|
31864
31864
|
}
|
|
31865
|
-
function optionalSafeInteger(
|
|
31866
|
-
const value =
|
|
31865
|
+
function optionalSafeInteger(record3, key) {
|
|
31866
|
+
const value = record3[key];
|
|
31867
31867
|
if (value === void 0) return void 0;
|
|
31868
31868
|
return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
|
|
31869
31869
|
}
|
|
31870
|
-
function optionalUserScopeMembers(
|
|
31871
|
-
const value =
|
|
31870
|
+
function optionalUserScopeMembers(record3) {
|
|
31871
|
+
const value = record3.users;
|
|
31872
31872
|
if (value === void 0) return void 0;
|
|
31873
31873
|
if (!Array.isArray(value)) return void 0;
|
|
31874
31874
|
const members = [];
|
|
@@ -31897,27 +31897,27 @@ function optionalUserScopeMembers(record2) {
|
|
|
31897
31897
|
}
|
|
31898
31898
|
function policyFromUnknown(value) {
|
|
31899
31899
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
31900
|
-
const
|
|
31901
|
-
if (!isSafeVersion(
|
|
31900
|
+
const record3 = value;
|
|
31901
|
+
if (!isSafeVersion(record3.updatedAt)) return void 0;
|
|
31902
31902
|
const fields = {
|
|
31903
|
-
repositories: optionalStringArray(
|
|
31904
|
-
directories: optionalStringArray(
|
|
31905
|
-
globs: optionalStringArray(
|
|
31906
|
-
branches: optionalStringArray(
|
|
31907
|
-
effectiveFrom: optionalSafeInteger(
|
|
31908
|
-
effectiveUntil: optionalSafeInteger(
|
|
31909
|
-
users: optionalUserScopeMembers(
|
|
31903
|
+
repositories: optionalStringArray(record3, "repositories"),
|
|
31904
|
+
directories: optionalStringArray(record3, "directories"),
|
|
31905
|
+
globs: optionalStringArray(record3, "globs"),
|
|
31906
|
+
branches: optionalStringArray(record3, "branches"),
|
|
31907
|
+
effectiveFrom: optionalSafeInteger(record3, "effectiveFrom"),
|
|
31908
|
+
effectiveUntil: optionalSafeInteger(record3, "effectiveUntil"),
|
|
31909
|
+
users: optionalUserScopeMembers(record3)
|
|
31910
31910
|
};
|
|
31911
31911
|
if (Object.entries(fields).some(
|
|
31912
|
-
([key, parsed]) =>
|
|
31912
|
+
([key, parsed]) => record3[key] !== void 0 && parsed === void 0
|
|
31913
31913
|
)) {
|
|
31914
31914
|
return void 0;
|
|
31915
31915
|
}
|
|
31916
|
-
if (
|
|
31916
|
+
if (record3.effectiveFrom !== void 0 && fields.effectiveFrom === void 0 || record3.effectiveUntil !== void 0 && fields.effectiveUntil === void 0 || fields.effectiveFrom !== void 0 && fields.effectiveUntil !== void 0 && fields.effectiveFrom >= fields.effectiveUntil) {
|
|
31917
31917
|
return void 0;
|
|
31918
31918
|
}
|
|
31919
31919
|
return {
|
|
31920
|
-
updatedAt:
|
|
31920
|
+
updatedAt: record3.updatedAt,
|
|
31921
31921
|
...fields.repositories === void 0 ? {} : { repositories: fields.repositories },
|
|
31922
31922
|
...fields.directories === void 0 ? {} : { directories: fields.directories },
|
|
31923
31923
|
...fields.globs === void 0 ? {} : { globs: fields.globs },
|
|
@@ -33697,18 +33697,18 @@ function parseAuthBrokerConfig(value) {
|
|
|
33697
33697
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
33698
33698
|
throw new Error("broker config must be an object");
|
|
33699
33699
|
}
|
|
33700
|
-
const
|
|
33701
|
-
if (typeof
|
|
33700
|
+
const record3 = value;
|
|
33701
|
+
if (typeof record3.authorization_server !== "string" || !record3.authorization_server.trim()) {
|
|
33702
33702
|
throw new Error("authorization_server is required");
|
|
33703
33703
|
}
|
|
33704
|
-
if (typeof
|
|
33704
|
+
if (typeof record3.client_id !== "string" || !record3.client_id.trim()) {
|
|
33705
33705
|
throw new Error("client_id is required");
|
|
33706
33706
|
}
|
|
33707
|
-
if (!Array.isArray(
|
|
33707
|
+
if (!Array.isArray(record3.default_scopes) || !record3.default_scopes.every((scope) => typeof scope === "string" && scope.length > 0)) {
|
|
33708
33708
|
throw new Error("default_scopes must be a string array");
|
|
33709
33709
|
}
|
|
33710
|
-
const authorizationServer = parseHttpUrl(
|
|
33711
|
-
const rawEndpoint =
|
|
33710
|
+
const authorizationServer = parseHttpUrl(record3.authorization_server, "authorization_server");
|
|
33711
|
+
const rawEndpoint = record3.authorization_endpoint === void 0 ? DEFAULT_WORKOS_AUTHORIZE_URL : record3.authorization_endpoint;
|
|
33712
33712
|
if (typeof rawEndpoint !== "string" || !rawEndpoint.trim()) {
|
|
33713
33713
|
throw new Error("authorization_endpoint must be a URL");
|
|
33714
33714
|
}
|
|
@@ -33719,8 +33719,8 @@ function parseAuthBrokerConfig(value) {
|
|
|
33719
33719
|
return {
|
|
33720
33720
|
authorization_server: authorizationServer.toString(),
|
|
33721
33721
|
authorization_endpoint: authorizationEndpoint.toString(),
|
|
33722
|
-
client_id:
|
|
33723
|
-
default_scopes: [...
|
|
33722
|
+
client_id: record3.client_id.trim(),
|
|
33723
|
+
default_scopes: [...record3.default_scopes]
|
|
33724
33724
|
};
|
|
33725
33725
|
}
|
|
33726
33726
|
async function fetchAuthBrokerConfig(siteUrl, fetchImpl = fetch) {
|
|
@@ -34963,7 +34963,7 @@ import {
|
|
|
34963
34963
|
utimesSync,
|
|
34964
34964
|
writeFileSync as writeFileSync6
|
|
34965
34965
|
} from "fs";
|
|
34966
|
-
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join10, resolve as resolve5 } from "path";
|
|
34966
|
+
import { delimiter, dirname as dirname8, isAbsolute as isAbsolute5, join as join10, resolve as resolve5 } from "path";
|
|
34967
34967
|
var HOOK_RUNTIME_SCHEMA_VERSION = 1;
|
|
34968
34968
|
var DIRECTORY_MODE2 = 448;
|
|
34969
34969
|
var DATA_FILE_MODE = 384;
|
|
@@ -35313,11 +35313,28 @@ function writeRelease(sourceDir, releaseDir, manifest, releasesDir) {
|
|
|
35313
35313
|
rmSync4(stagingDir, { recursive: true, force: true });
|
|
35314
35314
|
}
|
|
35315
35315
|
}
|
|
35316
|
+
function stableNodePath(execPath = process.execPath, searchPath = process.env.PATH ?? "") {
|
|
35317
|
+
let target;
|
|
35318
|
+
try {
|
|
35319
|
+
target = realpathSync2(execPath);
|
|
35320
|
+
} catch {
|
|
35321
|
+
return execPath;
|
|
35322
|
+
}
|
|
35323
|
+
for (const directory of searchPath.split(delimiter)) {
|
|
35324
|
+
if (!isAbsolute5(directory)) continue;
|
|
35325
|
+
const candidate = join10(directory, "node");
|
|
35326
|
+
try {
|
|
35327
|
+
if (realpathSync2(candidate) === target) return candidate;
|
|
35328
|
+
} catch {
|
|
35329
|
+
}
|
|
35330
|
+
}
|
|
35331
|
+
return execPath;
|
|
35332
|
+
}
|
|
35316
35333
|
function stageHookRuntime(options = {}) {
|
|
35317
35334
|
const root = packageRoot();
|
|
35318
35335
|
const sourceDir = options.sourceDir ?? (root ? join10(root, "dist", "hook-runtime") : null);
|
|
35319
35336
|
const version = options.version ?? packageVersion();
|
|
35320
|
-
const nodePath = resolve5(options.nodePath ??
|
|
35337
|
+
const nodePath = resolve5(options.nodePath ?? stableNodePath());
|
|
35321
35338
|
if (!sourceDir || !version || compareSemver(version, version) !== 0 || !isAbsolute5(nodePath) || /[\r\n]/u.test(nodePath)) {
|
|
35322
35339
|
throw new Error("cannot stage hook runtime: package identity is unavailable");
|
|
35323
35340
|
}
|
|
@@ -36369,7 +36386,7 @@ function registerCursorCommands(program3) {
|
|
|
36369
36386
|
|
|
36370
36387
|
// src/commands/daemon.ts
|
|
36371
36388
|
import { spawn as spawn3 } from "child_process";
|
|
36372
|
-
import { closeSync as
|
|
36389
|
+
import { closeSync as closeSync4, existsSync as existsSync12, mkdirSync as mkdirSync9, openSync as openSync4, readFileSync as readFileSync13, unlinkSync as unlinkSync3 } from "fs";
|
|
36373
36390
|
import { join as join16 } from "path";
|
|
36374
36391
|
|
|
36375
36392
|
// src/daemon/latest-bootstrap.ts
|
|
@@ -36441,12 +36458,12 @@ async function runLatestDaemonBootstrap(ensureCurrent, options = {}) {
|
|
|
36441
36458
|
import { spawnSync } from "child_process";
|
|
36442
36459
|
import { createHash as createHash8, randomBytes as randomBytes5 } from "crypto";
|
|
36443
36460
|
import {
|
|
36444
|
-
constants as
|
|
36461
|
+
constants as constants5,
|
|
36445
36462
|
accessSync as accessSync2,
|
|
36446
36463
|
chmodSync as chmodSync4,
|
|
36447
36464
|
copyFileSync as copyFileSync2,
|
|
36448
36465
|
existsSync as existsSync11,
|
|
36449
|
-
lstatSync as
|
|
36466
|
+
lstatSync as lstatSync6,
|
|
36450
36467
|
mkdirSync as mkdirSync8,
|
|
36451
36468
|
mkdtempSync as mkdtempSync2,
|
|
36452
36469
|
readFileSync as readFileSync12,
|
|
@@ -36455,16 +36472,53 @@ import {
|
|
|
36455
36472
|
realpathSync as realpathSync3,
|
|
36456
36473
|
renameSync as renameSync4,
|
|
36457
36474
|
rmSync as rmSync5,
|
|
36475
|
+
statSync as statSync3,
|
|
36458
36476
|
symlinkSync,
|
|
36459
36477
|
writeFileSync as writeFileSync7
|
|
36460
36478
|
} from "fs";
|
|
36461
36479
|
import { homedir as homedir8 } from "os";
|
|
36462
36480
|
import { basename as basename3, dirname as dirname10, isAbsolute as isAbsolute7, join as join15, resolve as resolve6 } from "path";
|
|
36463
36481
|
|
|
36482
|
+
// src/lib/bounded-file.ts
|
|
36483
|
+
import { constants as constants4, closeSync as closeSync3, fstatSync, lstatSync as lstatSync5, openSync as openSync3, readSync } from "fs";
|
|
36484
|
+
function readBoundedRegularFile(path9, maxBytes) {
|
|
36485
|
+
let fd;
|
|
36486
|
+
try {
|
|
36487
|
+
const linked = lstatSync5(path9);
|
|
36488
|
+
if (!linked.isFile() || linked.size > maxBytes) return void 0;
|
|
36489
|
+
fd = openSync3(path9, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
36490
|
+
const opened = fstatSync(fd);
|
|
36491
|
+
if (!opened.isFile() || opened.dev !== linked.dev || opened.ino !== linked.ino || opened.size > maxBytes) {
|
|
36492
|
+
return void 0;
|
|
36493
|
+
}
|
|
36494
|
+
const buffer = Buffer.allocUnsafe(opened.size + 1);
|
|
36495
|
+
let length = 0;
|
|
36496
|
+
while (length < buffer.length) {
|
|
36497
|
+
const count = readSync(fd, buffer, length, buffer.length - length, length);
|
|
36498
|
+
if (count === 0) break;
|
|
36499
|
+
length += count;
|
|
36500
|
+
}
|
|
36501
|
+
if (length > opened.size) return void 0;
|
|
36502
|
+
return { text: buffer.subarray(0, length).toString("utf8"), ownerUid: opened.uid };
|
|
36503
|
+
} catch {
|
|
36504
|
+
return void 0;
|
|
36505
|
+
} finally {
|
|
36506
|
+
if (fd !== void 0) {
|
|
36507
|
+
try {
|
|
36508
|
+
closeSync3(fd);
|
|
36509
|
+
} catch {
|
|
36510
|
+
}
|
|
36511
|
+
}
|
|
36512
|
+
}
|
|
36513
|
+
}
|
|
36514
|
+
|
|
36464
36515
|
// src/daemon/env-binding.ts
|
|
36465
36516
|
function normalizeApiUrl(url) {
|
|
36466
36517
|
return url.trim().replace(/\/+$/, "");
|
|
36467
36518
|
}
|
|
36519
|
+
function apiUrlsMatch(a, b) {
|
|
36520
|
+
return normalizeApiUrl(a) === normalizeApiUrl(b);
|
|
36521
|
+
}
|
|
36468
36522
|
|
|
36469
36523
|
// src/daemon/launchd.ts
|
|
36470
36524
|
var LAUNCHD_LABEL = "ai.getprimitive.prim-daemon";
|
|
@@ -36483,6 +36537,11 @@ var SERVICE_NOT_FOUND = 113;
|
|
|
36483
36537
|
var TRANSITION_IN_PROGRESS = 5;
|
|
36484
36538
|
var OUTPUT_LIMIT = 4096;
|
|
36485
36539
|
var DAEMON_DISABLED_CONTENT = "disabled by `prim daemon stop`\n";
|
|
36540
|
+
var LAUNCHER_MAX_BYTES = 64 * 1024;
|
|
36541
|
+
var PLIST_MAX_BYTES = 64 * 1024;
|
|
36542
|
+
var DRIFT_HEAL_MARKER = "daemon-drift-heal.json";
|
|
36543
|
+
var DRIFT_HEAL_MARKER_TEMPORARY_RE = /^daemon-drift-heal\.json\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.tmp$/u;
|
|
36544
|
+
var DRIFT_HEAL_CLAIM_OWNER = "owner.json";
|
|
36486
36545
|
var LaunchctlError = class extends Error {
|
|
36487
36546
|
status;
|
|
36488
36547
|
timedOut;
|
|
@@ -36522,6 +36581,8 @@ function daemonControlPaths(options = {}) {
|
|
|
36522
36581
|
return {
|
|
36523
36582
|
launcher: join15(configDir, `prim-daemon-launcher-v${LAUNCHER_SCHEMA_VERSION}`),
|
|
36524
36583
|
disabledMarker: join15(configDir, "daemon.disabled"),
|
|
36584
|
+
driftHealMarker: join15(configDir, DRIFT_HEAL_MARKER),
|
|
36585
|
+
driftHealClaim: join15(configDir, "daemon-drift-heal.lock"),
|
|
36525
36586
|
lifecycleLockDir: join15(configDir, "daemon.lifecycle.lock"),
|
|
36526
36587
|
legacyDisabledMarker: legacy.disabledMarker,
|
|
36527
36588
|
legacyLifecycleLockDir: legacy.lifecycleLockDir
|
|
@@ -36582,7 +36643,7 @@ function readOwnedRuntimeManifest(releaseDir) {
|
|
|
36582
36643
|
}
|
|
36583
36644
|
const manifest = parsed;
|
|
36584
36645
|
if (manifest.schemaVersion !== RUNTIME_SCHEMA_VERSION || compareSemver(manifest.version, manifest.version) !== 0 || !isAbsolute7(manifest.nodePath) || /[\r\n]/u.test(manifest.nodePath) || manifest.daemonFile !== "prim-daemon-server" || !/^[0-9a-f]{64}$/u.test(manifest.daemonSha256) || new Date(manifest.stagedAt).toISOString() !== manifest.stagedAt || raw !== `${JSON.stringify(manifest, null, 2)}
|
|
36585
|
-
` || !
|
|
36646
|
+
` || !lstatSync6(daemonPath).isFile() || sha256File(daemonPath) !== manifest.daemonSha256) {
|
|
36586
36647
|
return null;
|
|
36587
36648
|
}
|
|
36588
36649
|
const entries = readdirSync3(releaseDir).sort();
|
|
@@ -36591,8 +36652,17 @@ function readOwnedRuntimeManifest(releaseDir) {
|
|
|
36591
36652
|
return null;
|
|
36592
36653
|
}
|
|
36593
36654
|
}
|
|
36655
|
+
function sameNode(recorded, desired) {
|
|
36656
|
+
if (recorded === desired) return true;
|
|
36657
|
+
try {
|
|
36658
|
+
const target = realpathSync3(desired);
|
|
36659
|
+
return recorded !== target && realpathSync3(recorded) === target;
|
|
36660
|
+
} catch {
|
|
36661
|
+
return false;
|
|
36662
|
+
}
|
|
36663
|
+
}
|
|
36594
36664
|
function sameRuntime(current, desired, daemonPath) {
|
|
36595
|
-
if (!current || current.version !== desired.version || current.nodePath
|
|
36665
|
+
if (!current || current.version !== desired.version || !sameNode(current.nodePath, desired.nodePath) || current.daemonSha256 !== desired.daemonSha256) {
|
|
36596
36666
|
return false;
|
|
36597
36667
|
}
|
|
36598
36668
|
try {
|
|
@@ -36620,7 +36690,7 @@ function stageRuntime(options = {}) {
|
|
|
36620
36690
|
if (!daemonSource || !existsSync11(daemonSource)) {
|
|
36621
36691
|
throw new Error("cannot stage runtime: prim-daemon-server bundle is unavailable");
|
|
36622
36692
|
}
|
|
36623
|
-
const nodePath = resolve6(options.nodePath ??
|
|
36693
|
+
const nodePath = resolve6(options.nodePath ?? stableNodePath());
|
|
36624
36694
|
const version = options.version ?? findPackageVersion(daemonSource);
|
|
36625
36695
|
const desired = {
|
|
36626
36696
|
schemaVersion: RUNTIME_SCHEMA_VERSION,
|
|
@@ -36719,13 +36789,30 @@ function assertRegularFile(path9, label) {
|
|
|
36719
36789
|
}
|
|
36720
36790
|
function lstatIfPresent3(path9) {
|
|
36721
36791
|
try {
|
|
36722
|
-
return
|
|
36792
|
+
return lstatSync6(path9);
|
|
36723
36793
|
} catch (error) {
|
|
36724
36794
|
const code = error.code;
|
|
36725
36795
|
if (code === "ENOENT" || code === "ENOTDIR") return void 0;
|
|
36726
36796
|
throw error;
|
|
36727
36797
|
}
|
|
36728
36798
|
}
|
|
36799
|
+
function driftHealMarkerTemporaries(configDir) {
|
|
36800
|
+
try {
|
|
36801
|
+
return readdirSync3(configDir).filter((entry) => DRIFT_HEAL_MARKER_TEMPORARY_RE.test(entry)).map((entry) => join15(configDir, entry));
|
|
36802
|
+
} catch (error) {
|
|
36803
|
+
const code = error.code;
|
|
36804
|
+
if (code === "ENOENT" || code === "ENOTDIR") return [];
|
|
36805
|
+
throw error;
|
|
36806
|
+
}
|
|
36807
|
+
}
|
|
36808
|
+
function assertDriftHealClaim(path9) {
|
|
36809
|
+
const claim = lstatIfPresent3(path9);
|
|
36810
|
+
if (!claim) return;
|
|
36811
|
+
if (!claim.isDirectory() || readdirSync3(path9).some((entry) => entry !== DRIFT_HEAL_CLAIM_OWNER)) {
|
|
36812
|
+
throw new Error(`refusing to remove unrecognized daemon drift-heal claim at ${path9}`);
|
|
36813
|
+
}
|
|
36814
|
+
assertRegularFile(join15(path9, DRIFT_HEAL_CLAIM_OWNER), "daemon drift-heal claim owner");
|
|
36815
|
+
}
|
|
36729
36816
|
function assertExactFile(path9, expected, label) {
|
|
36730
36817
|
if (!lstatIfPresent3(path9)) return;
|
|
36731
36818
|
assertRegularFile(path9, label);
|
|
@@ -36764,17 +36851,16 @@ function assertOwnedDaemonRuntime(options) {
|
|
|
36764
36851
|
);
|
|
36765
36852
|
}
|
|
36766
36853
|
assertRegularFile(logPath, "daemon log");
|
|
36854
|
+
assertRegularFile(control.driftHealMarker, "daemon drift-heal marker");
|
|
36855
|
+
for (const temporary of driftHealMarkerTemporaries(configDir)) {
|
|
36856
|
+
assertRegularFile(temporary, "daemon drift-heal marker temporary");
|
|
36857
|
+
}
|
|
36858
|
+
assertDriftHealClaim(control.driftHealClaim);
|
|
36767
36859
|
assertRegularFile(join15(configDir, "daemon-health.json"), "daemon health snapshot");
|
|
36768
36860
|
assertRegularFile(join15(configDir, "client_instance_id"), "daemon client instance id");
|
|
36769
36861
|
if (service && lstatIfPresent3(service.plistPath)) {
|
|
36770
36862
|
assertRegularFile(service.plistPath, "launchd property list");
|
|
36771
|
-
|
|
36772
|
-
launcherPath: control.launcher,
|
|
36773
|
-
logPath,
|
|
36774
|
-
workingDirectory: options.homeDir ?? homedir8(),
|
|
36775
|
-
label: options.label
|
|
36776
|
-
});
|
|
36777
|
-
if (readFileSync12(service.plistPath, "utf8") !== expected) {
|
|
36863
|
+
if (readFileSync12(service.plistPath, "utf8") !== ownedLaunchAgentPlist(options, logPath)) {
|
|
36778
36864
|
throw new Error(
|
|
36779
36865
|
`refusing to remove unrecognized launchd property list at ${service.plistPath}`
|
|
36780
36866
|
);
|
|
@@ -36851,6 +36937,9 @@ async function removeDaemonRuntime(options = {}) {
|
|
|
36851
36937
|
control.launcher,
|
|
36852
36938
|
control.disabledMarker,
|
|
36853
36939
|
control.legacyDisabledMarker,
|
|
36940
|
+
control.driftHealMarker,
|
|
36941
|
+
...driftHealMarkerTemporaries(configDir),
|
|
36942
|
+
control.driftHealClaim,
|
|
36854
36943
|
...service ? [service.plistPath] : [],
|
|
36855
36944
|
logPath,
|
|
36856
36945
|
join15(configDir, "daemon-health.json"),
|
|
@@ -36862,7 +36951,7 @@ async function removeDaemonRuntime(options = {}) {
|
|
|
36862
36951
|
return withDaemonLifecycleLock(async () => {
|
|
36863
36952
|
assertOwnedDaemonRuntime(options);
|
|
36864
36953
|
for (const path9 of ownedArtifacts.filter((candidate) => candidate !== runtime.runtimeDir)) {
|
|
36865
|
-
rmSync5(path9, { force: true });
|
|
36954
|
+
rmSync5(path9, { force: true, recursive: path9 === control.driftHealClaim });
|
|
36866
36955
|
}
|
|
36867
36956
|
if (lstatIfPresent3(runtime.runtimeDir)) {
|
|
36868
36957
|
const quarantined = `${runtime.runtimeDir}.uninstall-${String(process.pid)}-${randomBytes5(8).toString("hex")}`;
|
|
@@ -36896,9 +36985,22 @@ ${config.configDir ? `export PRIM_CONFIG_DIR=${shellQuote2(config.configDir)}
|
|
|
36896
36985
|
`
|
|
36897
36986
|
};
|
|
36898
36987
|
}
|
|
36988
|
+
function ownedLaunchAgentPlist(options, logPath) {
|
|
36989
|
+
return generateLaunchAgentPlist({
|
|
36990
|
+
launcherPath: daemonControlPaths(options).launcher,
|
|
36991
|
+
logPath,
|
|
36992
|
+
workingDirectory: options.homeDir ?? homedir8(),
|
|
36993
|
+
label: options.label
|
|
36994
|
+
});
|
|
36995
|
+
}
|
|
36899
36996
|
function readDaemonLauncher(path9) {
|
|
36997
|
+
return readDaemonLauncherFile(path9)?.config ?? null;
|
|
36998
|
+
}
|
|
36999
|
+
function readDaemonLauncherFile(path9) {
|
|
36900
37000
|
try {
|
|
36901
|
-
const
|
|
37001
|
+
const file = readBoundedRegularFile(path9, LAUNCHER_MAX_BYTES);
|
|
37002
|
+
if (!file) return null;
|
|
37003
|
+
const content = file.text;
|
|
36902
37004
|
const encoded = /^# prim-daemon-launcher: ([A-Za-z0-9_-]+)$/mu.exec(content)?.[1];
|
|
36903
37005
|
if (!encoded) return null;
|
|
36904
37006
|
const value = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
@@ -36913,7 +37015,7 @@ function readDaemonLauncher(path9) {
|
|
|
36913
37015
|
...typeof value.configDir === "string" ? { configDir: value.configDir } : {}
|
|
36914
37016
|
};
|
|
36915
37017
|
const expected = generateDaemonLauncher(config);
|
|
36916
|
-
return expected.revision === value.revision && expected.content === content ? config : null;
|
|
37018
|
+
return expected.revision === value.revision && expected.content === content ? { config, ownerUid: file.ownerUid } : null;
|
|
36917
37019
|
} catch {
|
|
36918
37020
|
return null;
|
|
36919
37021
|
}
|
|
@@ -36923,7 +37025,7 @@ function readUsableDaemonConfig(path9) {
|
|
|
36923
37025
|
if (!config) return null;
|
|
36924
37026
|
const manifest = readRuntimeManifest(join15(dirname10(config.daemonPath), "manifest.json"));
|
|
36925
37027
|
try {
|
|
36926
|
-
accessSync2(config.nodePath,
|
|
37028
|
+
accessSync2(config.nodePath, constants5.X_OK);
|
|
36927
37029
|
return manifest?.version === config.runtimeVersion && manifest.nodePath === config.nodePath && manifest.daemonSha256 === sha256File(config.daemonPath) ? config : null;
|
|
36928
37030
|
} catch {
|
|
36929
37031
|
return null;
|
|
@@ -37267,6 +37369,68 @@ function setDaemonExplicitlyDisabled(disabled, options = {}) {
|
|
|
37267
37369
|
}
|
|
37268
37370
|
atomicWrite3(paths.disabledMarker, content, RUNTIME_FILE_MODE);
|
|
37269
37371
|
}
|
|
37372
|
+
function launcherRunnable(config) {
|
|
37373
|
+
try {
|
|
37374
|
+
accessSync2(config.nodePath, constants5.X_OK);
|
|
37375
|
+
return statSync3(config.daemonPath).isFile();
|
|
37376
|
+
} catch {
|
|
37377
|
+
return false;
|
|
37378
|
+
}
|
|
37379
|
+
}
|
|
37380
|
+
function selectedDaemonLauncher(options = {}) {
|
|
37381
|
+
const file = readDaemonLauncherFile(daemonControlPaths(options).launcher);
|
|
37382
|
+
if (!file) return null;
|
|
37383
|
+
const { config, ownerUid } = file;
|
|
37384
|
+
return {
|
|
37385
|
+
runtimeVersion: config.runtimeVersion,
|
|
37386
|
+
...config.apiUrl ? { apiUrl: config.apiUrl } : {},
|
|
37387
|
+
ownerUid,
|
|
37388
|
+
runnable: launcherRunnable(config)
|
|
37389
|
+
};
|
|
37390
|
+
}
|
|
37391
|
+
var XML_ENTITIES = {
|
|
37392
|
+
"&": "&",
|
|
37393
|
+
"<": "<",
|
|
37394
|
+
">": ">",
|
|
37395
|
+
""": '"',
|
|
37396
|
+
"'": "'"
|
|
37397
|
+
};
|
|
37398
|
+
var XML_ENTITY_RE = /&(?:amp|lt|gt|quot|apos);/gu;
|
|
37399
|
+
var PLIST_LABEL_KEY = "<key>Label</key>";
|
|
37400
|
+
var PLIST_PROGRAM_KEY = "<key>ProgramArguments</key>";
|
|
37401
|
+
var PLIST_LABEL_RE = /<key>Label<\/key>\s*<string>([^<]*)<\/string>/u;
|
|
37402
|
+
var PLIST_PROGRAM_RE = /<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]*)<\/string>/u;
|
|
37403
|
+
function xmlUnescape(value) {
|
|
37404
|
+
if (value.replace(XML_ENTITY_RE, "").includes("&")) return void 0;
|
|
37405
|
+
return value.replace(XML_ENTITY_RE, (entity) => XML_ENTITIES[entity] ?? entity);
|
|
37406
|
+
}
|
|
37407
|
+
function launchAgentProgram(plist) {
|
|
37408
|
+
if (plist.split(PLIST_LABEL_KEY).length !== 2 || plist.split(PLIST_PROGRAM_KEY).length !== 2) {
|
|
37409
|
+
return void 0;
|
|
37410
|
+
}
|
|
37411
|
+
const label = PLIST_LABEL_RE.exec(plist)?.[1];
|
|
37412
|
+
const program3 = PLIST_PROGRAM_RE.exec(plist)?.[1];
|
|
37413
|
+
if (label === void 0 || program3 === void 0) return void 0;
|
|
37414
|
+
const decodedLabel = xmlUnescape(label);
|
|
37415
|
+
const decodedProgram = xmlUnescape(program3);
|
|
37416
|
+
return decodedLabel === void 0 || decodedProgram === void 0 ? void 0 : { label: decodedLabel, program: decodedProgram };
|
|
37417
|
+
}
|
|
37418
|
+
function launchAgentRunsConfigRoot(options = {}) {
|
|
37419
|
+
try {
|
|
37420
|
+
const service = launchdPaths(options);
|
|
37421
|
+
const plist = readBoundedRegularFile(service.plistPath, PLIST_MAX_BYTES);
|
|
37422
|
+
const agent = plist ? launchAgentProgram(plist.text) : void 0;
|
|
37423
|
+
return agent?.label === (options.label ?? LAUNCHD_LABEL) && agent.program === daemonControlPaths(options).launcher;
|
|
37424
|
+
} catch {
|
|
37425
|
+
return false;
|
|
37426
|
+
}
|
|
37427
|
+
}
|
|
37428
|
+
function daemonDriftHealMarkerPath(options = {}) {
|
|
37429
|
+
return daemonControlPaths(options).driftHealMarker;
|
|
37430
|
+
}
|
|
37431
|
+
function daemonDriftHealClaimPath(options = {}) {
|
|
37432
|
+
return daemonControlPaths(options).driftHealClaim;
|
|
37433
|
+
}
|
|
37270
37434
|
async function ensureMacDaemon(options = {}) {
|
|
37271
37435
|
return withDaemonLifecycleLock(() => ensureMacDaemonLocked(options), options);
|
|
37272
37436
|
}
|
|
@@ -37454,6 +37618,54 @@ async function bootoutMacDaemonLocked(options) {
|
|
|
37454
37618
|
return { wasLoaded, legacyStopped, service };
|
|
37455
37619
|
}
|
|
37456
37620
|
|
|
37621
|
+
// src/lib/delivery-backlog.ts
|
|
37622
|
+
var MS_PER_SECOND = 1e3;
|
|
37623
|
+
var MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
|
37624
|
+
var MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
|
37625
|
+
var MS_PER_DAY = 24 * MS_PER_HOUR;
|
|
37626
|
+
function isNonNegativeInteger(value) {
|
|
37627
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
37628
|
+
}
|
|
37629
|
+
function isPositiveInteger(value) {
|
|
37630
|
+
return isNonNegativeInteger(value) && value > 0;
|
|
37631
|
+
}
|
|
37632
|
+
function deliveryBacklogState(ingestion) {
|
|
37633
|
+
if (ingestion?.healthy !== false) return void 0;
|
|
37634
|
+
const failures = ingestion.consecutiveFailures;
|
|
37635
|
+
const failedWithoutProgress = failures !== 0 && !(isPositiveInteger(failures) && isPositiveInteger(ingestion.lastFailedDrainAcknowledgedCount));
|
|
37636
|
+
if (failedWithoutProgress) return "failing";
|
|
37637
|
+
const retained = ingestion.lastRetainedBucketCount;
|
|
37638
|
+
if (!isNonNegativeInteger(retained)) return "failing";
|
|
37639
|
+
return retained > 0 ? "retained" : "draining";
|
|
37640
|
+
}
|
|
37641
|
+
function formatBacklogAge(ageMs) {
|
|
37642
|
+
if (ageMs >= MS_PER_DAY) return `${String(Math.floor(ageMs / MS_PER_DAY))}d`;
|
|
37643
|
+
if (ageMs >= MS_PER_HOUR) return `${String(Math.floor(ageMs / MS_PER_HOUR))}h`;
|
|
37644
|
+
if (ageMs >= MS_PER_MINUTE) return `${String(Math.floor(ageMs / MS_PER_MINUTE))}m`;
|
|
37645
|
+
return `${String(Math.max(0, Math.floor(ageMs / MS_PER_SECOND)))}s`;
|
|
37646
|
+
}
|
|
37647
|
+
function formatPendingBacklog(backlog, now = Date.now()) {
|
|
37648
|
+
const count = backlog.pendingCount;
|
|
37649
|
+
const moves = typeof count === "number" && count > 0 ? `${backlog.pendingSampled ? "at least " : ""}${String(count)} pending move${count === 1 ? "" : "s"}` : "an unknown number of pending moves";
|
|
37650
|
+
const age = backlog.oldestPendingAt === void 0 ? "" : ` (oldest ${backlog.pendingSampled ? "\u2265 " : ""}${formatBacklogAge(now - backlog.oldestPendingAt)})`;
|
|
37651
|
+
return `${moves}${age}`;
|
|
37652
|
+
}
|
|
37653
|
+
function deliveryBacklogSummary(ingestion, now = Date.now(), backlog = ingestion) {
|
|
37654
|
+
const state = deliveryBacklogState(ingestion);
|
|
37655
|
+
if (!(state && ingestion && backlog)) return void 0;
|
|
37656
|
+
const pending = formatPendingBacklog(backlog, now);
|
|
37657
|
+
if (state === "draining") return `draining ${pending} in the background`;
|
|
37658
|
+
if (state === "retained") {
|
|
37659
|
+
const buckets = ingestion.lastRetainedBucketCount ?? 0;
|
|
37660
|
+
const reasons = boundedHealthError(ingestion.lastRetainedReasons);
|
|
37661
|
+
return `delivery held back: ${String(buckets)} journal bucket${buckets === 1 ? "" : "s"} retained${reasons ? ` (${reasons})` : ""} \xB7 holding ${pending} \u2014 run \`prim doctor\``;
|
|
37662
|
+
}
|
|
37663
|
+
const failures = ingestion.consecutiveFailures;
|
|
37664
|
+
const count = isPositiveInteger(failures) ? ` (${String(failures)} consecutive failure${failures === 1 ? "" : "s"})` : "";
|
|
37665
|
+
const error = boundedHealthError(ingestion.lastError);
|
|
37666
|
+
return `delivery failing${count}${error ? `: ${error}` : ""} \xB7 retrying ${pending} in the background`;
|
|
37667
|
+
}
|
|
37668
|
+
|
|
37457
37669
|
// src/lib/presence.ts
|
|
37458
37670
|
var DECISION_ORIGIN = "https://app.getprimitive.ai";
|
|
37459
37671
|
function validDecisionUrl(value) {
|
|
@@ -37528,7 +37740,8 @@ function formatStatusline(version, snapshot, resolveIngestionStatus, options = {
|
|
|
37528
37740
|
if (snapshot.ingestion?.healthy === false) {
|
|
37529
37741
|
const pending = snapshot.ingestion.pendingCount;
|
|
37530
37742
|
const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
|
|
37531
|
-
|
|
37743
|
+
const delivery = deliveryBacklogState(snapshot.ingestion) === "draining" && snapshot.heartbeat?.healthy === true ? "draining" : "stalled";
|
|
37744
|
+
return `primitive ${version} (daemon: degraded \xB7 delivery: ${delivery}${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
|
|
37532
37745
|
}
|
|
37533
37746
|
if (snapshot.heartbeat?.healthy === false) {
|
|
37534
37747
|
return `primitive ${version} (daemon: degraded \xB7 presence: unavailable${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
|
|
@@ -37571,16 +37784,20 @@ var STATUS_PROBE_TIMEOUT_MS = 500;
|
|
|
37571
37784
|
var READY_TIMEOUT_MS = 5e3;
|
|
37572
37785
|
var READY_POLL_MS2 = 100;
|
|
37573
37786
|
var READY_PROBE_TIMEOUT_MS2 = 250;
|
|
37574
|
-
var
|
|
37575
|
-
var
|
|
37787
|
+
var READY_SNAPSHOT_TIMEOUT_MS = 3e4;
|
|
37788
|
+
var READY_SNAPSHOT_POLL_MS = 250;
|
|
37576
37789
|
var EXIT_OK3 = 0;
|
|
37577
37790
|
var EXIT_NOT_RUNNING = 2;
|
|
37578
37791
|
var EXIT_BOOTING = 3;
|
|
37579
|
-
|
|
37580
|
-
|
|
37792
|
+
var VERIFIED_PREFIX = "[prim] \u2713 ";
|
|
37793
|
+
function formatDaemonLifecycleMessage(message, decisionIngestion, snapshot, now = Date.now()) {
|
|
37794
|
+
const backlog = deliveryBacklogSummary(snapshot?.ingestion, now);
|
|
37795
|
+
const state = deliveryBacklogState(snapshot?.ingestion);
|
|
37796
|
+
const verdict = (state === "failing" || state === "retained") && message.startsWith(VERIFIED_PREFIX) ? `[prim] \u26A0 ${message.slice(VERIFIED_PREFIX.length)}` : message;
|
|
37797
|
+
return `${verdict} \xB7 Decision ingestion ${decisionIngestion}${backlog ? ` \xB7 ${backlog}` : ""}`;
|
|
37581
37798
|
}
|
|
37582
|
-
function formatCurrentDaemonLifecycleMessage(message) {
|
|
37583
|
-
return formatDaemonLifecycleMessage(message, decisionIngestionStatus(process.cwd()));
|
|
37799
|
+
function formatCurrentDaemonLifecycleMessage(message, snapshot) {
|
|
37800
|
+
return formatDaemonLifecycleMessage(message, decisionIngestionStatus(process.cwd()), snapshot);
|
|
37584
37801
|
}
|
|
37585
37802
|
function daemonDegradedReason(snapshot) {
|
|
37586
37803
|
if (!snapshot || snapshot.healthy !== false) return void 0;
|
|
@@ -37631,7 +37848,7 @@ function openDaemonLog(configDir = CONFIG_DIR) {
|
|
|
37631
37848
|
if (!existsSync12(configDir)) {
|
|
37632
37849
|
mkdirSync9(configDir, { recursive: true, mode: CONFIG_DIR_MODE2 });
|
|
37633
37850
|
}
|
|
37634
|
-
return
|
|
37851
|
+
return openSync4(join16(configDir, "daemon.log"), "a", LOG_FILE_MODE);
|
|
37635
37852
|
}
|
|
37636
37853
|
async function waitForReady() {
|
|
37637
37854
|
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
@@ -37643,17 +37860,23 @@ async function waitForReady() {
|
|
|
37643
37860
|
}
|
|
37644
37861
|
return daemonIsLive(READY_PROBE_TIMEOUT_MS2);
|
|
37645
37862
|
}
|
|
37646
|
-
|
|
37647
|
-
|
|
37863
|
+
function requestStatusSnapshot() {
|
|
37864
|
+
return daemonRequest(
|
|
37865
|
+
"status_snapshot",
|
|
37866
|
+
{},
|
|
37867
|
+
{ timeoutMs: STATUS_PROBE_TIMEOUT_MS }
|
|
37868
|
+
);
|
|
37869
|
+
}
|
|
37870
|
+
async function waitForReadySnapshot(expectedVersion, options = {}) {
|
|
37871
|
+
const request2 = options.requestSnapshot ?? requestStatusSnapshot;
|
|
37872
|
+
const wait = options.sleep ?? sleep;
|
|
37873
|
+
const nowMs = options.nowMs ?? Date.now;
|
|
37874
|
+
const deadline = nowMs() + READY_SNAPSHOT_TIMEOUT_MS;
|
|
37648
37875
|
let snapshot = null;
|
|
37649
|
-
while (
|
|
37650
|
-
snapshot = await
|
|
37651
|
-
|
|
37652
|
-
|
|
37653
|
-
{ timeoutMs: STATUS_PROBE_TIMEOUT_MS }
|
|
37654
|
-
);
|
|
37655
|
-
if (snapshot?.healthy === true && snapshot.version === expectedVersion) return snapshot;
|
|
37656
|
-
await sleep(HEALTHY_POLL_MS);
|
|
37876
|
+
while (nowMs() < deadline) {
|
|
37877
|
+
snapshot = await request2();
|
|
37878
|
+
if (daemonStartIsReady(true, snapshot, expectedVersion)) return snapshot;
|
|
37879
|
+
await wait(READY_SNAPSHOT_POLL_MS);
|
|
37657
37880
|
}
|
|
37658
37881
|
return snapshot;
|
|
37659
37882
|
}
|
|
@@ -37666,11 +37889,20 @@ async function verifiedPid(existing) {
|
|
|
37666
37889
|
);
|
|
37667
37890
|
return snapshot?.pid === existing.pid ? snapshot : null;
|
|
37668
37891
|
}
|
|
37669
|
-
function
|
|
37670
|
-
|
|
37892
|
+
function daemonStartIsReady(serviceReady, snapshot, expectedVersion) {
|
|
37893
|
+
if (!serviceReady || !snapshot || expectedVersion === void 0) return false;
|
|
37894
|
+
if (snapshot.version !== expectedVersion || snapshot.needsReauth === true) return false;
|
|
37895
|
+
if (snapshot.healthy === true) return true;
|
|
37896
|
+
return snapshot.heartbeat?.healthy === true && snapshot.ingestion?.healthy === false;
|
|
37671
37897
|
}
|
|
37672
|
-
function
|
|
37673
|
-
|
|
37898
|
+
function daemonBacklogFields(snapshot) {
|
|
37899
|
+
const state = deliveryBacklogState(snapshot?.ingestion);
|
|
37900
|
+
if (!state) return {};
|
|
37901
|
+
if (state === "draining") return { draining: true, ingestion: snapshot?.ingestion };
|
|
37902
|
+
return state === "retained" ? { draining: false, deliveryRetained: true, ingestion: snapshot?.ingestion } : { draining: false, deliveryFailing: true, ingestion: snapshot?.ingestion };
|
|
37903
|
+
}
|
|
37904
|
+
function daemonStartHealthFields(ready, snapshot) {
|
|
37905
|
+
if (ready) return daemonBacklogFields(snapshot);
|
|
37674
37906
|
return {
|
|
37675
37907
|
state: "degraded",
|
|
37676
37908
|
needsReauth: snapshot?.needsReauth === true,
|
|
@@ -37678,16 +37910,28 @@ function daemonStartHealthFields(healthy, snapshot) {
|
|
|
37678
37910
|
ingestion: snapshot?.ingestion ?? null
|
|
37679
37911
|
};
|
|
37680
37912
|
}
|
|
37913
|
+
function daemonStartFailureReason(snapshot, expectedVersion) {
|
|
37914
|
+
if (snapshot && !snapshot.needsReauth && expectedVersion !== void 0 && snapshot.version !== expectedVersion) {
|
|
37915
|
+
return `daemon reports ${snapshot.version ? `v${snapshot.version}` : "no version"}, expected v${expectedVersion}`;
|
|
37916
|
+
}
|
|
37917
|
+
return daemonDegradedReason(snapshot);
|
|
37918
|
+
}
|
|
37681
37919
|
async function detachedDaemonStart(opts) {
|
|
37682
37920
|
const existing = readPidfile();
|
|
37683
37921
|
if (existing?.alive) {
|
|
37684
37922
|
const snapshot = await verifiedPid(existing);
|
|
37685
37923
|
if (snapshot) {
|
|
37686
37924
|
process.stderr.write(
|
|
37687
|
-
`${formatCurrentDaemonLifecycleMessage(`[prim] daemon already running (pid=${existing.pid})
|
|
37925
|
+
`${formatCurrentDaemonLifecycleMessage(`[prim] daemon already running (pid=${existing.pid})`, snapshot)}
|
|
37688
37926
|
`
|
|
37689
37927
|
);
|
|
37690
|
-
console.log(
|
|
37928
|
+
console.log(
|
|
37929
|
+
JSON.stringify(
|
|
37930
|
+
{ started: false, pid: existing.pid, ...daemonBacklogFields(snapshot) },
|
|
37931
|
+
null,
|
|
37932
|
+
2
|
|
37933
|
+
)
|
|
37934
|
+
);
|
|
37691
37935
|
return;
|
|
37692
37936
|
}
|
|
37693
37937
|
process.stderr.write(
|
|
@@ -37736,16 +37980,19 @@ async function detachedDaemonStart(opts) {
|
|
|
37736
37980
|
});
|
|
37737
37981
|
child.unref();
|
|
37738
37982
|
if (logFd !== void 0) {
|
|
37739
|
-
|
|
37983
|
+
closeSync4(logFd);
|
|
37740
37984
|
}
|
|
37741
37985
|
const live = await waitForReady();
|
|
37742
37986
|
if (live) {
|
|
37743
37987
|
const after = readPidfile();
|
|
37988
|
+
const snapshot = await requestStatusSnapshot();
|
|
37744
37989
|
process.stderr.write(
|
|
37745
|
-
`${formatCurrentDaemonLifecycleMessage(`[prim] \u2713 daemon started (pid=${after?.pid ?? "?"}, socket=${SOCK_PATH2})
|
|
37990
|
+
`${formatCurrentDaemonLifecycleMessage(`[prim] \u2713 daemon started (pid=${after?.pid ?? "?"}, socket=${SOCK_PATH2})`, snapshot)}
|
|
37746
37991
|
`
|
|
37747
37992
|
);
|
|
37748
|
-
console.log(
|
|
37993
|
+
console.log(
|
|
37994
|
+
JSON.stringify({ started: true, pid: after?.pid, ...daemonBacklogFields(snapshot) }, null, 2)
|
|
37995
|
+
);
|
|
37749
37996
|
return;
|
|
37750
37997
|
}
|
|
37751
37998
|
process.stderr.write(
|
|
@@ -37868,19 +38115,25 @@ async function macDaemonStart(forceRestart = false) {
|
|
|
37868
38115
|
const result = await ensureMacDaemon({ explicitlyStarted: true, forceRestart });
|
|
37869
38116
|
const serviceReady = result.state === "running";
|
|
37870
38117
|
const expectedVersion = result.runtime?.manifest.version;
|
|
37871
|
-
const snapshot = serviceReady && expectedVersion ? await
|
|
37872
|
-
const
|
|
37873
|
-
if (
|
|
38118
|
+
const snapshot = serviceReady && expectedVersion ? await waitForReadySnapshot(expectedVersion) : null;
|
|
38119
|
+
const ready = daemonStartIsReady(serviceReady, snapshot, expectedVersion);
|
|
38120
|
+
if (ready) {
|
|
37874
38121
|
const verb = result.action === "none" ? "already running" : "started";
|
|
37875
38122
|
const servicePid = result.service.loaded ? result.service.pid : void 0;
|
|
37876
38123
|
process.stderr.write(
|
|
37877
|
-
`${formatCurrentDaemonLifecycleMessage(`[prim] \u2713 daemon ${verb} under launchd (pid=${snapshot?.pid ?? servicePid ?? "?"})
|
|
38124
|
+
`${formatCurrentDaemonLifecycleMessage(`[prim] \u2713 daemon ${verb} under launchd (pid=${snapshot?.pid ?? servicePid ?? "?"})`, snapshot)}
|
|
37878
38125
|
`
|
|
37879
38126
|
);
|
|
38127
|
+
} else if (!(serviceReady && expectedVersion)) {
|
|
38128
|
+
process.stderr.write(
|
|
38129
|
+
`[prim] \u2717 launchd did not converge on the desired daemon (${result.action}) (see ${LOG_PATH})
|
|
38130
|
+
`
|
|
38131
|
+
);
|
|
38132
|
+
if (!process.exitCode) process.exitCode = EXIT_NOT_RUNNING;
|
|
37880
38133
|
} else {
|
|
37881
|
-
const reason =
|
|
38134
|
+
const reason = daemonStartFailureReason(snapshot, expectedVersion);
|
|
37882
38135
|
process.stderr.write(
|
|
37883
|
-
`[prim] \u2717 launchd daemon did not reach healthy heartbeat
|
|
38136
|
+
`[prim] \u2717 launchd daemon did not reach a healthy heartbeat on the expected version${reason ? ` \xB7 ${reason}` : ""} (see ${LOG_PATH})
|
|
37884
38137
|
`
|
|
37885
38138
|
);
|
|
37886
38139
|
if (!process.exitCode) process.exitCode = EXIT_NOT_RUNNING;
|
|
@@ -37888,14 +38141,20 @@ async function macDaemonStart(forceRestart = false) {
|
|
|
37888
38141
|
console.log(
|
|
37889
38142
|
JSON.stringify(
|
|
37890
38143
|
{
|
|
37891
|
-
started:
|
|
38144
|
+
started: ready,
|
|
37892
38145
|
supervised: true,
|
|
37893
38146
|
action: result.action,
|
|
37894
38147
|
pid: snapshot?.pid ?? (result.service.loaded ? result.service.pid : void 0),
|
|
37895
38148
|
loaded: result.service.loaded,
|
|
37896
38149
|
responding: result.responding,
|
|
37897
|
-
healthy
|
|
37898
|
-
|
|
38150
|
+
// `healthy` keeps meaning "start succeeded" (always equal to `started`
|
|
38151
|
+
// and the exit code) so existing consumers stay correct. It is not the
|
|
38152
|
+
// daemon's own health: `daemon status --json` stays degraded while a
|
|
38153
|
+
// backlog drains, is held back, or fails to deliver, which start
|
|
38154
|
+
// reports additively via `draining`, `deliveryRetained`,
|
|
38155
|
+
// `deliveryFailing`, and `ingestion`.
|
|
38156
|
+
healthy: ready,
|
|
38157
|
+
...daemonStartHealthFields(ready, snapshot),
|
|
37899
38158
|
version: snapshot?.version,
|
|
37900
38159
|
expectedVersion
|
|
37901
38160
|
},
|
|
@@ -38199,11 +38458,12 @@ async function daemonEnsure() {
|
|
|
38199
38458
|
return { disabled };
|
|
38200
38459
|
}
|
|
38201
38460
|
const result = await ensureMacDaemon();
|
|
38461
|
+
const snapshot = result.state === "running" ? await requestStatusSnapshot() : null;
|
|
38202
38462
|
if (result.state === "disabled") {
|
|
38203
38463
|
process.stderr.write("[prim] daemon remains explicitly disabled\n");
|
|
38204
38464
|
} else if (result.state === "running") {
|
|
38205
38465
|
process.stderr.write(
|
|
38206
|
-
`${formatCurrentDaemonLifecycleMessage(`[prim] \u2713 daemon ensured under launchd (${result.action})
|
|
38466
|
+
`${formatCurrentDaemonLifecycleMessage(`[prim] \u2713 daemon ensured under launchd (${result.action})`, snapshot)}
|
|
38207
38467
|
`
|
|
38208
38468
|
);
|
|
38209
38469
|
} else {
|
|
@@ -38217,7 +38477,8 @@ async function daemonEnsure() {
|
|
|
38217
38477
|
ensured: result.state === "running",
|
|
38218
38478
|
disabled: result.state === "disabled",
|
|
38219
38479
|
supervised: true,
|
|
38220
|
-
action: result.action
|
|
38480
|
+
action: result.action,
|
|
38481
|
+
...daemonBacklogFields(snapshot)
|
|
38221
38482
|
},
|
|
38222
38483
|
null,
|
|
38223
38484
|
2
|
|
@@ -39273,11 +39534,11 @@ function asRecord(value, path9) {
|
|
|
39273
39534
|
}
|
|
39274
39535
|
return value;
|
|
39275
39536
|
}
|
|
39276
|
-
function assertKeys(
|
|
39537
|
+
function assertKeys(record3, path9, required, optional = []) {
|
|
39277
39538
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
39278
|
-
const missing = required.find((key) => !Object.hasOwn(
|
|
39539
|
+
const missing = required.find((key) => !Object.hasOwn(record3, key));
|
|
39279
39540
|
if (missing !== void 0) contractError(path9, `is missing ${missing}`);
|
|
39280
|
-
const extra = Object.keys(
|
|
39541
|
+
const extra = Object.keys(record3).find((key) => !allowed.has(key));
|
|
39281
39542
|
if (extra !== void 0) contractError(path9, `contains unexpected field ${extra}`);
|
|
39282
39543
|
}
|
|
39283
39544
|
function asString(value, path9, options) {
|
|
@@ -39307,97 +39568,97 @@ function asSha(value, path9) {
|
|
|
39307
39568
|
if (!SHA_RE.test(sha)) contractError(path9, "must be a canonical lowercase Git commit SHA");
|
|
39308
39569
|
return sha;
|
|
39309
39570
|
}
|
|
39310
|
-
function optionalString(
|
|
39311
|
-
if (!Object.hasOwn(
|
|
39312
|
-
return asString(
|
|
39571
|
+
function optionalString(record3, key, path9, max) {
|
|
39572
|
+
if (!Object.hasOwn(record3, key)) return void 0;
|
|
39573
|
+
return asString(record3[key], `${path9}.${key}`, { max, nonempty: true });
|
|
39313
39574
|
}
|
|
39314
39575
|
function parseProposal(value, path9) {
|
|
39315
|
-
const
|
|
39576
|
+
const record3 = asRecord(value, path9);
|
|
39316
39577
|
assertKeys(
|
|
39317
|
-
|
|
39578
|
+
record3,
|
|
39318
39579
|
path9,
|
|
39319
39580
|
["_id", "repoFullName", "deadCommitSha", "status", "signals", "lastEvaluatedAt"],
|
|
39320
39581
|
["proposedSha", "proposedTier", "nextEvaluateAt"]
|
|
39321
39582
|
);
|
|
39322
|
-
const repoFullName = asString(
|
|
39583
|
+
const repoFullName = asString(record3.repoFullName, `${path9}.repoFullName`, {
|
|
39323
39584
|
max: 200,
|
|
39324
39585
|
nonempty: true
|
|
39325
39586
|
});
|
|
39326
39587
|
if (!REPO_FULL_NAME_RE.test(repoFullName)) {
|
|
39327
39588
|
contractError(`${path9}.repoFullName`, "must be canonical owner/repository syntax");
|
|
39328
39589
|
}
|
|
39329
|
-
const status =
|
|
39590
|
+
const status = record3.status;
|
|
39330
39591
|
if (status !== "proposed" && status !== "confirmed" && status !== "verification_failed") {
|
|
39331
39592
|
contractError(`${path9}.status`, "is not a review-visible proposal status");
|
|
39332
39593
|
}
|
|
39333
|
-
if (!Array.isArray(
|
|
39594
|
+
if (!Array.isArray(record3.signals) || record3.signals.length > MAX_SIGNALS) {
|
|
39334
39595
|
contractError(`${path9}.signals`, "must be a bounded array");
|
|
39335
39596
|
}
|
|
39336
|
-
const signals =
|
|
39597
|
+
const signals = record3.signals.map(
|
|
39337
39598
|
(signal, index) => asString(signal, `${path9}.signals[${String(index)}]`, {
|
|
39338
39599
|
max: MAX_SIGNAL_LENGTH,
|
|
39339
39600
|
nonempty: true
|
|
39340
39601
|
})
|
|
39341
39602
|
);
|
|
39342
|
-
const proposedSha = Object.hasOwn(
|
|
39603
|
+
const proposedSha = Object.hasOwn(record3, "proposedSha") ? asSha(record3.proposedSha, `${path9}.proposedSha`) : void 0;
|
|
39343
39604
|
let proposedTier;
|
|
39344
|
-
if (Object.hasOwn(
|
|
39345
|
-
if (
|
|
39605
|
+
if (Object.hasOwn(record3, "proposedTier")) {
|
|
39606
|
+
if (record3.proposedTier !== "exact_patch_body" && record3.proposedTier !== "exact_file_set") {
|
|
39346
39607
|
contractError(`${path9}.proposedTier`, "is not a supported match tier");
|
|
39347
39608
|
}
|
|
39348
|
-
proposedTier =
|
|
39609
|
+
proposedTier = record3.proposedTier;
|
|
39349
39610
|
}
|
|
39350
|
-
const nextEvaluateAt = Object.hasOwn(
|
|
39611
|
+
const nextEvaluateAt = Object.hasOwn(record3, "nextEvaluateAt") ? asTimestamp(record3.nextEvaluateAt, `${path9}.nextEvaluateAt`) : void 0;
|
|
39351
39612
|
return {
|
|
39352
|
-
_id: asString(
|
|
39613
|
+
_id: asString(record3._id, `${path9}._id`, { max: 256, nonempty: true }),
|
|
39353
39614
|
repoFullName,
|
|
39354
|
-
deadCommitSha: asSha(
|
|
39615
|
+
deadCommitSha: asSha(record3.deadCommitSha, `${path9}.deadCommitSha`),
|
|
39355
39616
|
status,
|
|
39356
39617
|
proposedSha,
|
|
39357
39618
|
proposedTier,
|
|
39358
39619
|
signals,
|
|
39359
|
-
lastEvaluatedAt: asTimestamp(
|
|
39620
|
+
lastEvaluatedAt: asTimestamp(record3.lastEvaluatedAt, `${path9}.lastEvaluatedAt`),
|
|
39360
39621
|
nextEvaluateAt
|
|
39361
39622
|
};
|
|
39362
39623
|
}
|
|
39363
39624
|
function parseDecision(value, path9) {
|
|
39364
|
-
const
|
|
39365
|
-
assertKeys(
|
|
39366
|
-
const status =
|
|
39625
|
+
const record3 = asRecord(value, path9);
|
|
39626
|
+
assertKeys(record3, path9, ["_id", "intent", "status", "intentTruncated"], ["shortId"]);
|
|
39627
|
+
const status = record3.status;
|
|
39367
39628
|
if (status !== "provisional" && status !== "abandoned") {
|
|
39368
39629
|
contractError(`${path9}.status`, "is not a repairable decision status");
|
|
39369
39630
|
}
|
|
39370
39631
|
return {
|
|
39371
|
-
_id: asString(
|
|
39372
|
-
shortId: optionalString(
|
|
39373
|
-
intent: asString(
|
|
39632
|
+
_id: asString(record3._id, `${path9}._id`, { max: 256, nonempty: true }),
|
|
39633
|
+
shortId: optionalString(record3, "shortId", path9, 128),
|
|
39634
|
+
intent: asString(record3.intent, `${path9}.intent`, { max: MAX_INTENT_LENGTH }),
|
|
39374
39635
|
status,
|
|
39375
|
-
intentTruncated: asBoolean(
|
|
39636
|
+
intentTruncated: asBoolean(record3.intentTruncated, `${path9}.intentTruncated`)
|
|
39376
39637
|
};
|
|
39377
39638
|
}
|
|
39378
39639
|
function parseListItem(value, path9) {
|
|
39379
|
-
const
|
|
39380
|
-
assertKeys(
|
|
39640
|
+
const record3 = asRecord(value, path9);
|
|
39641
|
+
assertKeys(record3, path9, [
|
|
39381
39642
|
"proposal",
|
|
39382
39643
|
"decisions",
|
|
39383
39644
|
"affectedDecisionCount",
|
|
39384
39645
|
"decisionsTruncated",
|
|
39385
39646
|
"reviewToken"
|
|
39386
39647
|
]);
|
|
39387
|
-
if (!Array.isArray(
|
|
39648
|
+
if (!Array.isArray(record3.decisions) || record3.decisions.length > MAX_REPAIR_DECISIONS_FOR_CONFIRM) {
|
|
39388
39649
|
contractError(`${path9}.decisions`, "must be a bounded array");
|
|
39389
39650
|
}
|
|
39390
|
-
const decisions =
|
|
39651
|
+
const decisions = record3.decisions.map(
|
|
39391
39652
|
(decision, index) => parseDecision(decision, `${path9}.decisions[${String(index)}]`)
|
|
39392
39653
|
);
|
|
39393
|
-
const proposal = parseProposal(
|
|
39394
|
-
const decisionsTruncated = asBoolean(
|
|
39395
|
-
const affectedDecisionCount =
|
|
39654
|
+
const proposal = parseProposal(record3.proposal, `${path9}.proposal`);
|
|
39655
|
+
const decisionsTruncated = asBoolean(record3.decisionsTruncated, `${path9}.decisionsTruncated`);
|
|
39656
|
+
const affectedDecisionCount = record3.affectedDecisionCount === null ? null : asCount(record3.affectedDecisionCount, `${path9}.affectedDecisionCount`);
|
|
39396
39657
|
let reviewToken;
|
|
39397
|
-
if (
|
|
39658
|
+
if (record3.reviewToken === null) {
|
|
39398
39659
|
reviewToken = null;
|
|
39399
39660
|
} else {
|
|
39400
|
-
reviewToken = asString(
|
|
39661
|
+
reviewToken = asString(record3.reviewToken, `${path9}.reviewToken`, {
|
|
39401
39662
|
max: 64,
|
|
39402
39663
|
nonempty: true
|
|
39403
39664
|
});
|
|
@@ -39430,19 +39691,19 @@ function parseListItem(value, path9) {
|
|
|
39430
39691
|
}
|
|
39431
39692
|
function parseListPage(value, pageNumber) {
|
|
39432
39693
|
const path9 = `page ${String(pageNumber)}`;
|
|
39433
|
-
const
|
|
39434
|
-
assertKeys(
|
|
39435
|
-
if (!Array.isArray(
|
|
39694
|
+
const record3 = asRecord(value, path9);
|
|
39695
|
+
assertKeys(record3, path9, ["repairs", "isDone", "nextCursor", "truncated"]);
|
|
39696
|
+
if (!Array.isArray(record3.repairs) || record3.repairs.length > MAX_REPAIRS_PER_PAGE) {
|
|
39436
39697
|
contractError(`${path9}.repairs`, "must be a bounded array");
|
|
39437
39698
|
}
|
|
39438
|
-
const isDone = asBoolean(
|
|
39439
|
-
const truncated = asBoolean(
|
|
39699
|
+
const isDone = asBoolean(record3.isDone, `${path9}.isDone`);
|
|
39700
|
+
const truncated = asBoolean(record3.truncated, `${path9}.truncated`);
|
|
39440
39701
|
if (truncated === isDone) contractError(path9, "has inconsistent isDone/truncated flags");
|
|
39441
39702
|
let nextCursor;
|
|
39442
|
-
if (
|
|
39703
|
+
if (record3.nextCursor === null) {
|
|
39443
39704
|
nextCursor = null;
|
|
39444
39705
|
} else {
|
|
39445
|
-
nextCursor = asString(
|
|
39706
|
+
nextCursor = asString(record3.nextCursor, `${path9}.nextCursor`, {
|
|
39446
39707
|
max: MAX_CURSOR_LENGTH,
|
|
39447
39708
|
nonempty: true
|
|
39448
39709
|
});
|
|
@@ -39450,7 +39711,7 @@ function parseListPage(value, pageNumber) {
|
|
|
39450
39711
|
if (isDone && nextCursor !== null) contractError(path9, "is done but includes a next cursor");
|
|
39451
39712
|
if (!isDone && nextCursor === null) contractError(path9, "is incomplete without a next cursor");
|
|
39452
39713
|
return {
|
|
39453
|
-
repairs:
|
|
39714
|
+
repairs: record3.repairs.map(
|
|
39454
39715
|
(item, index) => parseListItem(item, `${path9}.repairs[${String(index)}]`)
|
|
39455
39716
|
),
|
|
39456
39717
|
isDone,
|
|
@@ -39528,23 +39789,23 @@ function normalizedResolutionInput(proposalId, expectedProposedSha) {
|
|
|
39528
39789
|
return { proposalId, expectedProposedSha: expectedProposedSha.toLowerCase() };
|
|
39529
39790
|
}
|
|
39530
39791
|
function parseResolutionOutcome(value, action) {
|
|
39531
|
-
const
|
|
39792
|
+
const record3 = asRecord(value, "resolution response");
|
|
39532
39793
|
const allowed = action === "confirm" ? ["confirmed", "already_applied", "disabled", "no_op", "stale"] : ["rejected", "already_applied", "no_op", "stale"];
|
|
39533
|
-
if (
|
|
39534
|
-
assertKeys(
|
|
39794
|
+
if (record3.status === "backoff") {
|
|
39795
|
+
assertKeys(record3, "resolution response", ["status", "retryAt"]);
|
|
39535
39796
|
if (action !== "confirm") {
|
|
39536
39797
|
contractError("resolution response.status", "backoff is impossible for reject");
|
|
39537
39798
|
}
|
|
39538
39799
|
return {
|
|
39539
39800
|
status: "backoff",
|
|
39540
|
-
retryAt: asTimestamp(
|
|
39801
|
+
retryAt: asTimestamp(record3.retryAt, "resolution response.retryAt")
|
|
39541
39802
|
};
|
|
39542
39803
|
}
|
|
39543
|
-
assertKeys(
|
|
39544
|
-
if (typeof
|
|
39804
|
+
assertKeys(record3, "resolution response", ["status"]);
|
|
39805
|
+
if (typeof record3.status !== "string" || !allowed.includes(record3.status)) {
|
|
39545
39806
|
contractError("resolution response.status", "is not a supported outcome");
|
|
39546
39807
|
}
|
|
39547
|
-
return { status:
|
|
39808
|
+
return { status: record3.status };
|
|
39548
39809
|
}
|
|
39549
39810
|
function normalizedReviewToken(value) {
|
|
39550
39811
|
if (value === void 0 || !REVIEW_TOKEN_INPUT_RE.test(value)) {
|
|
@@ -39555,18 +39816,18 @@ function normalizedReviewToken(value) {
|
|
|
39555
39816
|
return value.toLowerCase();
|
|
39556
39817
|
}
|
|
39557
39818
|
function parseConflictOutcome(value, action) {
|
|
39558
|
-
const
|
|
39559
|
-
assertKeys(
|
|
39819
|
+
const record3 = asRecord(value, "resolution conflict response");
|
|
39820
|
+
assertKeys(record3, "resolution conflict response", ["status"]);
|
|
39560
39821
|
if (action !== "confirm") {
|
|
39561
39822
|
contractError(
|
|
39562
39823
|
"resolution conflict response.status",
|
|
39563
39824
|
"a review conflict is impossible for reject"
|
|
39564
39825
|
);
|
|
39565
39826
|
}
|
|
39566
|
-
if (
|
|
39827
|
+
if (record3.status !== "review_too_large" && record3.status !== "stale_review") {
|
|
39567
39828
|
contractError("resolution conflict response.status", "is not a supported 409 outcome");
|
|
39568
39829
|
}
|
|
39569
|
-
return { status:
|
|
39830
|
+
return { status: record3.status };
|
|
39570
39831
|
}
|
|
39571
39832
|
async function resolveRepair(proposalId, expectedProposedSha, action, expectedReviewToken, deps = defaultDeps6) {
|
|
39572
39833
|
const normalized = normalizedResolutionInput(proposalId, expectedProposedSha);
|
|
@@ -40708,7 +40969,7 @@ function registerDecisionsCommands(program3) {
|
|
|
40708
40969
|
}
|
|
40709
40970
|
|
|
40710
40971
|
// src/commands/doctor.ts
|
|
40711
|
-
import { existsSync as
|
|
40972
|
+
import { existsSync as existsSync16 } from "fs";
|
|
40712
40973
|
|
|
40713
40974
|
// src/decisions/feedback.ts
|
|
40714
40975
|
var FEEDBACK_PROTOCOL_VERSION = 2;
|
|
@@ -40757,28 +41018,35 @@ function parseOrganizationBinding(value) {
|
|
|
40757
41018
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
40758
41019
|
return { state: "server_contract_unavailable" };
|
|
40759
41020
|
}
|
|
40760
|
-
const
|
|
40761
|
-
if (
|
|
41021
|
+
const record3 = value;
|
|
41022
|
+
if (record3.authenticated !== true || record3.organizationBindingVersion !== ORGANIZATION_BINDING_VERSION || !isCaptureAuthorityKind(record3.captureAuthorityKind)) {
|
|
40762
41023
|
return { state: "server_contract_unavailable" };
|
|
40763
41024
|
}
|
|
40764
|
-
if (
|
|
41025
|
+
if (record3.organizationId === null && record3.workosOrganizationId === null) {
|
|
40765
41026
|
return { state: "no_current_organization" };
|
|
40766
41027
|
}
|
|
40767
|
-
if (safeOrganizationId(
|
|
41028
|
+
if (safeOrganizationId(record3.organizationId) && record3.workosOrganizationId === null) {
|
|
40768
41029
|
return { state: "organization_identity_unreconciled" };
|
|
40769
41030
|
}
|
|
40770
|
-
if (!safeOrganizationId(
|
|
41031
|
+
if (!safeOrganizationId(record3.organizationId) || !safeOrganizationId(record3.workosOrganizationId)) {
|
|
40771
41032
|
return { state: "server_contract_unavailable" };
|
|
40772
41033
|
}
|
|
40773
41034
|
return {
|
|
40774
41035
|
state: "current",
|
|
40775
41036
|
binding: {
|
|
40776
|
-
captureAuthorityKind:
|
|
40777
|
-
organizationId:
|
|
40778
|
-
workosOrganizationId:
|
|
41037
|
+
captureAuthorityKind: record3.captureAuthorityKind,
|
|
41038
|
+
organizationId: record3.organizationId,
|
|
41039
|
+
workosOrganizationId: record3.workosOrganizationId
|
|
40779
41040
|
}
|
|
40780
41041
|
};
|
|
40781
41042
|
}
|
|
41043
|
+
function summarizeRetainedBuckets(retained) {
|
|
41044
|
+
const counts = /* @__PURE__ */ new Map();
|
|
41045
|
+
for (const item of retained) {
|
|
41046
|
+
counts.set(item.reason, (counts.get(item.reason) ?? 0) + 1);
|
|
41047
|
+
}
|
|
41048
|
+
return [...counts].sort(([left], [right]) => left.localeCompare(right)).map(([reason, count]) => `${reason}:${String(count)}`).join(", ");
|
|
41049
|
+
}
|
|
40782
41050
|
function classifyJournalBuckets(buckets, binding) {
|
|
40783
41051
|
const deliverableBuckets = /* @__PURE__ */ new Set();
|
|
40784
41052
|
const retainedBuckets = [];
|
|
@@ -40852,18 +41120,109 @@ async function inspectJournalDelivery(buckets, options = {}) {
|
|
|
40852
41120
|
// src/journal.ts
|
|
40853
41121
|
import {
|
|
40854
41122
|
appendFileSync,
|
|
40855
|
-
closeSync as
|
|
40856
|
-
existsSync as
|
|
40857
|
-
fstatSync,
|
|
41123
|
+
closeSync as closeSync5,
|
|
41124
|
+
existsSync as existsSync14,
|
|
41125
|
+
fstatSync as fstatSync2,
|
|
40858
41126
|
mkdirSync as mkdirSync10,
|
|
40859
|
-
openSync as
|
|
41127
|
+
openSync as openSync5,
|
|
40860
41128
|
opendirSync,
|
|
41129
|
+
readFileSync as readFileSync15,
|
|
41130
|
+
readSync as readSync2,
|
|
41131
|
+
readdirSync as readdirSync5
|
|
41132
|
+
} from "fs";
|
|
41133
|
+
import { dirname as dirname12, join as join18 } from "path";
|
|
41134
|
+
|
|
41135
|
+
// src/drain-progress.ts
|
|
41136
|
+
import {
|
|
41137
|
+
chmodSync as chmodSync5,
|
|
41138
|
+
existsSync as existsSync13,
|
|
40861
41139
|
readFileSync as readFileSync14,
|
|
40862
|
-
|
|
40863
|
-
|
|
41140
|
+
readdirSync as readdirSync4,
|
|
41141
|
+
rmSync as rmSync6,
|
|
41142
|
+
rmdirSync
|
|
40864
41143
|
} from "fs";
|
|
40865
|
-
import { dirname as dirname11, join as join17 } from "path";
|
|
40866
|
-
var
|
|
41144
|
+
import { basename as basename4, dirname as dirname11, join as join17 } from "path";
|
|
41145
|
+
var DIRECTORY_MODE3 = 448;
|
|
41146
|
+
var FILE_MODE2 = 384;
|
|
41147
|
+
var DRAIN_PROGRESS_DIRNAME = "drain-progress";
|
|
41148
|
+
var CHECKPOINT_NAME = /^(.+)\.json(?:\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.tmp)?$/;
|
|
41149
|
+
function rotationIdentity(stat) {
|
|
41150
|
+
return { size: stat.size, ino: stat.ino, dev: stat.dev };
|
|
41151
|
+
}
|
|
41152
|
+
function drainProgressDirectory(flushingPath) {
|
|
41153
|
+
return join17(dirname11(flushingPath), DRAIN_PROGRESS_DIRNAME);
|
|
41154
|
+
}
|
|
41155
|
+
function drainProgressPath(flushingPath) {
|
|
41156
|
+
return join17(drainProgressDirectory(flushingPath), `${basename4(flushingPath)}.json`);
|
|
41157
|
+
}
|
|
41158
|
+
function isByteCount(value) {
|
|
41159
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
41160
|
+
}
|
|
41161
|
+
function drainResumeOffset(flushingPath, rotation) {
|
|
41162
|
+
let parsed;
|
|
41163
|
+
try {
|
|
41164
|
+
parsed = JSON.parse(readFileSync14(drainProgressPath(flushingPath), "utf8"));
|
|
41165
|
+
} catch {
|
|
41166
|
+
return 0;
|
|
41167
|
+
}
|
|
41168
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
41169
|
+
return 0;
|
|
41170
|
+
}
|
|
41171
|
+
const { v, offset, size, ino, dev } = parsed;
|
|
41172
|
+
if (v !== 2 || ino !== rotation.ino || dev !== rotation.dev || size !== rotation.size || !isByteCount(offset) || offset > rotation.size) {
|
|
41173
|
+
return 0;
|
|
41174
|
+
}
|
|
41175
|
+
return offset;
|
|
41176
|
+
}
|
|
41177
|
+
function writeDrainCheckpoint(flushingPath, checkpoint) {
|
|
41178
|
+
const directory = drainProgressDirectory(flushingPath);
|
|
41179
|
+
ensureDurableDirectory(directory, DIRECTORY_MODE3);
|
|
41180
|
+
chmodSync5(directory, DIRECTORY_MODE3);
|
|
41181
|
+
atomicWriteFile(drainProgressPath(flushingPath), `${JSON.stringify(checkpoint)}
|
|
41182
|
+
`, {
|
|
41183
|
+
mode: FILE_MODE2
|
|
41184
|
+
});
|
|
41185
|
+
}
|
|
41186
|
+
function removeEmptyDirectory(directory) {
|
|
41187
|
+
try {
|
|
41188
|
+
rmdirSync(directory);
|
|
41189
|
+
} catch (error) {
|
|
41190
|
+
const code = error.code;
|
|
41191
|
+
if (code !== "ENOENT" && code !== "ENOTEMPTY" && code !== "EEXIST") {
|
|
41192
|
+
throw error;
|
|
41193
|
+
}
|
|
41194
|
+
}
|
|
41195
|
+
}
|
|
41196
|
+
function removeDrainCheckpoint(flushingPath) {
|
|
41197
|
+
rmSync6(drainProgressPath(flushingPath), { force: true });
|
|
41198
|
+
removeEmptyDirectory(drainProgressDirectory(flushingPath));
|
|
41199
|
+
}
|
|
41200
|
+
function sweepOrphanedDrainCheckpoints(bucketDirectory) {
|
|
41201
|
+
const directory = join17(bucketDirectory, DRAIN_PROGRESS_DIRNAME);
|
|
41202
|
+
let names;
|
|
41203
|
+
try {
|
|
41204
|
+
names = readdirSync4(directory);
|
|
41205
|
+
} catch {
|
|
41206
|
+
return;
|
|
41207
|
+
}
|
|
41208
|
+
for (const name of names) {
|
|
41209
|
+
const rotation = CHECKPOINT_NAME.exec(name)?.[1];
|
|
41210
|
+
if (rotation === void 0 || existsSync13(join17(bucketDirectory, rotation))) {
|
|
41211
|
+
continue;
|
|
41212
|
+
}
|
|
41213
|
+
try {
|
|
41214
|
+
rmSync6(join17(directory, name), { force: true });
|
|
41215
|
+
} catch {
|
|
41216
|
+
}
|
|
41217
|
+
}
|
|
41218
|
+
try {
|
|
41219
|
+
removeEmptyDirectory(directory);
|
|
41220
|
+
} catch {
|
|
41221
|
+
}
|
|
41222
|
+
}
|
|
41223
|
+
|
|
41224
|
+
// src/journal.ts
|
|
41225
|
+
var JOURNAL_DIR = join18(primConfigDirectory(), "moves");
|
|
40867
41226
|
var JOURNAL_BASENAME = "journal.ndjson";
|
|
40868
41227
|
var JOURNAL_STATS_SAMPLE_BYTES = 64 * 1024;
|
|
40869
41228
|
var PENDING_STATS_MAX_FILES = 128;
|
|
@@ -40875,7 +41234,7 @@ function envSlug(apiUrl) {
|
|
|
40875
41234
|
return slug;
|
|
40876
41235
|
}
|
|
40877
41236
|
function currentEnvDir() {
|
|
40878
|
-
return
|
|
41237
|
+
return join18(JOURNAL_DIR, envSlug(getSiteUrl()));
|
|
40879
41238
|
}
|
|
40880
41239
|
function parseMoves(content) {
|
|
40881
41240
|
const moves = [];
|
|
@@ -40891,23 +41250,23 @@ function parseMoves(content) {
|
|
|
40891
41250
|
return moves;
|
|
40892
41251
|
}
|
|
40893
41252
|
function readMovesFromPath(path9) {
|
|
40894
|
-
if (!
|
|
41253
|
+
if (!existsSync14(path9)) {
|
|
40895
41254
|
return [];
|
|
40896
41255
|
}
|
|
40897
|
-
return parseMoves(
|
|
41256
|
+
return parseMoves(readFileSync15(path9, "utf-8"));
|
|
40898
41257
|
}
|
|
40899
41258
|
function listBuckets() {
|
|
40900
41259
|
const out = [];
|
|
40901
41260
|
const envDir = currentEnvDir();
|
|
40902
|
-
if (!
|
|
41261
|
+
if (!existsSync14(envDir)) {
|
|
40903
41262
|
return out;
|
|
40904
41263
|
}
|
|
40905
|
-
for (const entry of
|
|
41264
|
+
for (const entry of readdirSync5(envDir, { withFileTypes: true })) {
|
|
40906
41265
|
if (!entry.isDirectory()) {
|
|
40907
41266
|
continue;
|
|
40908
41267
|
}
|
|
40909
|
-
const path9 =
|
|
40910
|
-
if (
|
|
41268
|
+
const path9 = join18(envDir, entry.name, JOURNAL_BASENAME);
|
|
41269
|
+
if (existsSync14(path9)) {
|
|
40911
41270
|
out.push({ bucket: entry.name, path: path9 });
|
|
40912
41271
|
}
|
|
40913
41272
|
}
|
|
@@ -40924,22 +41283,23 @@ function oldestCapturedAt(moves) {
|
|
|
40924
41283
|
}
|
|
40925
41284
|
return oldest;
|
|
40926
41285
|
}
|
|
40927
|
-
function sampleJournalFile(path9, maxBytes = JOURNAL_STATS_SAMPLE_BYTES) {
|
|
40928
|
-
const fd =
|
|
41286
|
+
function sampleJournalFile(path9, maxBytes = JOURNAL_STATS_SAMPLE_BYTES, options = {}) {
|
|
41287
|
+
const fd = openSync5(path9, "r");
|
|
40929
41288
|
try {
|
|
40930
|
-
const initial =
|
|
40931
|
-
const
|
|
41289
|
+
const initial = fstatSync2(fd);
|
|
41290
|
+
const start = options.fromDrainCheckpoint ? drainResumeOffset(path9, rotationIdentity(initial)) : 0;
|
|
41291
|
+
const target = Math.min(initial.size - start, Math.max(0, maxBytes));
|
|
40932
41292
|
const buffer = Buffer.allocUnsafe(target);
|
|
40933
41293
|
let sampledBytes = 0;
|
|
40934
41294
|
while (sampledBytes < target) {
|
|
40935
|
-
const count =
|
|
41295
|
+
const count = readSync2(fd, buffer, sampledBytes, target - sampledBytes, start + sampledBytes);
|
|
40936
41296
|
if (count === 0) {
|
|
40937
41297
|
break;
|
|
40938
41298
|
}
|
|
40939
41299
|
sampledBytes += count;
|
|
40940
41300
|
}
|
|
40941
|
-
const stat =
|
|
40942
|
-
const sampled = stat.size > sampledBytes;
|
|
41301
|
+
const stat = fstatSync2(fd);
|
|
41302
|
+
const sampled = stat.size - start > sampledBytes;
|
|
40943
41303
|
let content = buffer.subarray(0, sampledBytes).toString("utf-8");
|
|
40944
41304
|
if (sampled) {
|
|
40945
41305
|
const lastNewline = content.lastIndexOf("\n");
|
|
@@ -40949,6 +41309,7 @@ function sampleJournalFile(path9, maxBytes = JOURNAL_STATS_SAMPLE_BYTES) {
|
|
|
40949
41309
|
const moves = parseMoves(content);
|
|
40950
41310
|
return {
|
|
40951
41311
|
sizeBytes: stat.size,
|
|
41312
|
+
pendingBytes: Math.max(0, stat.size - start),
|
|
40952
41313
|
mtimeMs: stat.mtimeMs,
|
|
40953
41314
|
lineCount: sampled && stat.size > 0 ? Math.max(1, lines.length) : lines.length,
|
|
40954
41315
|
oldestCapturedAt: oldestCapturedAt(moves),
|
|
@@ -40956,7 +41317,7 @@ function sampleJournalFile(path9, maxBytes = JOURNAL_STATS_SAMPLE_BYTES) {
|
|
|
40956
41317
|
sampledBytes
|
|
40957
41318
|
};
|
|
40958
41319
|
} finally {
|
|
40959
|
-
|
|
41320
|
+
closeSync5(fd);
|
|
40960
41321
|
}
|
|
40961
41322
|
}
|
|
40962
41323
|
function parseFlushingPid(name) {
|
|
@@ -40967,7 +41328,7 @@ function parseFlushingPid(name) {
|
|
|
40967
41328
|
return Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
|
|
40968
41329
|
}
|
|
40969
41330
|
function listFlushingInDir(dir, bucket, options = {}) {
|
|
40970
|
-
if (!
|
|
41331
|
+
if (!existsSync14(dir)) {
|
|
40971
41332
|
return [];
|
|
40972
41333
|
}
|
|
40973
41334
|
const out = [];
|
|
@@ -40981,10 +41342,10 @@ function listFlushingInDir(dir, bucket, options = {}) {
|
|
|
40981
41342
|
entry = entries.readSync();
|
|
40982
41343
|
continue;
|
|
40983
41344
|
}
|
|
40984
|
-
const path9 =
|
|
41345
|
+
const path9 = join18(dir, entry.name);
|
|
40985
41346
|
let sample;
|
|
40986
41347
|
try {
|
|
40987
|
-
sample = sampleJournalFile(path9, remainingBytes);
|
|
41348
|
+
sample = sampleJournalFile(path9, remainingBytes, { fromDrainCheckpoint: true });
|
|
40988
41349
|
} catch (err) {
|
|
40989
41350
|
if (err.code === "ENOENT") {
|
|
40990
41351
|
entry = entries.readSync();
|
|
@@ -41008,18 +41369,18 @@ function listFlushingInDir(dir, bucket, options = {}) {
|
|
|
41008
41369
|
}
|
|
41009
41370
|
function listFlushing(options = {}) {
|
|
41010
41371
|
const envDir = currentEnvDir();
|
|
41011
|
-
if (!
|
|
41372
|
+
if (!existsSync14(envDir)) {
|
|
41012
41373
|
return [];
|
|
41013
41374
|
}
|
|
41014
41375
|
const out = [];
|
|
41015
41376
|
let remainingBytes = options.sampleBytes ?? JOURNAL_STATS_SAMPLE_BYTES;
|
|
41016
41377
|
const maxFiles = options.maxFiles ?? Number.POSITIVE_INFINITY;
|
|
41017
|
-
for (const entry of
|
|
41378
|
+
for (const entry of readdirSync5(envDir, { withFileTypes: true })) {
|
|
41018
41379
|
if (out.length >= maxFiles) {
|
|
41019
41380
|
break;
|
|
41020
41381
|
}
|
|
41021
41382
|
if (entry.isDirectory()) {
|
|
41022
|
-
const found = listFlushingInDir(
|
|
41383
|
+
const found = listFlushingInDir(join18(envDir, entry.name), entry.name, {
|
|
41023
41384
|
sampleBytes: remainingBytes,
|
|
41024
41385
|
maxFiles: maxFiles - out.length
|
|
41025
41386
|
});
|
|
@@ -41032,6 +41393,17 @@ function listFlushing(options = {}) {
|
|
|
41032
41393
|
}
|
|
41033
41394
|
return out;
|
|
41034
41395
|
}
|
|
41396
|
+
function sweepOrphanedDrainProgress() {
|
|
41397
|
+
const envDir = currentEnvDir();
|
|
41398
|
+
if (!existsSync14(envDir)) {
|
|
41399
|
+
return;
|
|
41400
|
+
}
|
|
41401
|
+
for (const entry of readdirSync5(envDir, { withFileTypes: true })) {
|
|
41402
|
+
if (entry.isDirectory()) {
|
|
41403
|
+
sweepOrphanedDrainCheckpoints(join18(envDir, entry.name));
|
|
41404
|
+
}
|
|
41405
|
+
}
|
|
41406
|
+
}
|
|
41035
41407
|
function bucketStats(options = {}) {
|
|
41036
41408
|
const out = [];
|
|
41037
41409
|
let remainingBytes = options.sampleBytes ?? JOURNAL_STATS_SAMPLE_BYTES;
|
|
@@ -41077,9 +41449,9 @@ function pendingJournalStats() {
|
|
|
41077
41449
|
}
|
|
41078
41450
|
|
|
41079
41451
|
// src/commands/hermes-install.ts
|
|
41080
|
-
import { existsSync as
|
|
41452
|
+
import { existsSync as existsSync15, readFileSync as readFileSync16, rmSync as rmSync7, statSync as statSync4 } from "fs";
|
|
41081
41453
|
import { homedir as homedir9 } from "os";
|
|
41082
|
-
import { join as
|
|
41454
|
+
import { join as join19 } from "path";
|
|
41083
41455
|
|
|
41084
41456
|
// node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/nodes/identity.js
|
|
41085
41457
|
var ALIAS = /* @__PURE__ */ Symbol.for("yaml.alias");
|
|
@@ -47358,13 +47730,13 @@ var JSON_INDENT3 = 2;
|
|
|
47358
47730
|
var CONFIG_MODE = 384;
|
|
47359
47731
|
var PRIM_BINS4 = [CAPTURE_BIN4, GATE_BIN4, POST_TOOL_USE_BIN3, SESSION_START_BIN4, SESSION_END_BIN3];
|
|
47360
47732
|
function hermesHome() {
|
|
47361
|
-
return process.env.HERMES_HOME ??
|
|
47733
|
+
return process.env.HERMES_HOME ?? join19(homedir9(), ".hermes");
|
|
47362
47734
|
}
|
|
47363
47735
|
function configPath() {
|
|
47364
|
-
return
|
|
47736
|
+
return join19(hermesHome(), "config.yaml");
|
|
47365
47737
|
}
|
|
47366
47738
|
function legacyShimPath() {
|
|
47367
|
-
return
|
|
47739
|
+
return join19(hermesHome(), "agent-hooks", "prim-shim.sh");
|
|
47368
47740
|
}
|
|
47369
47741
|
function commandFor2(bin) {
|
|
47370
47742
|
return stableHookCommand(bin, HERMES_ARGS);
|
|
@@ -47478,8 +47850,8 @@ function hookRuntimeResolutions3(hooks) {
|
|
|
47478
47850
|
}
|
|
47479
47851
|
function inspectHookRuntimeResolutions4() {
|
|
47480
47852
|
const path9 = configPath();
|
|
47481
|
-
if (!
|
|
47482
|
-
return hookRuntimeResolutions3(readHooks(parseHermesDocument(
|
|
47853
|
+
if (!existsSync15(path9)) return [];
|
|
47854
|
+
return hookRuntimeResolutions3(readHooks(parseHermesDocument(readFileSync16(path9, "utf8"))));
|
|
47483
47855
|
}
|
|
47484
47856
|
function entryMatchesRegistration3(owned, registration) {
|
|
47485
47857
|
const expected = entryFor(registration);
|
|
@@ -47748,11 +48120,11 @@ function assertMergeValid(before, after, expectedHooks) {
|
|
|
47748
48120
|
}
|
|
47749
48121
|
}
|
|
47750
48122
|
function readConfigSnapshot(path9) {
|
|
47751
|
-
if (!
|
|
48123
|
+
if (!existsSync15(path9)) return { exists: false, mode: CONFIG_MODE, raw: "" };
|
|
47752
48124
|
return {
|
|
47753
48125
|
exists: true,
|
|
47754
|
-
mode:
|
|
47755
|
-
raw:
|
|
48126
|
+
mode: statSync4(path9).mode & 511,
|
|
48127
|
+
raw: readFileSync16(path9, "utf8")
|
|
47756
48128
|
};
|
|
47757
48129
|
}
|
|
47758
48130
|
var CONCURRENT_CONFIG_MESSAGE = "Hermes config changed during update; concurrent changes were preserved, retry the command";
|
|
@@ -47761,7 +48133,7 @@ function writeHermesConfigSnapshot(path9, before, after, expectedHooks) {
|
|
|
47761
48133
|
ensureParent: true,
|
|
47762
48134
|
mode: before.mode,
|
|
47763
48135
|
validate(temporaryPath) {
|
|
47764
|
-
const flushed =
|
|
48136
|
+
const flushed = readFileSync16(temporaryPath, "utf8");
|
|
47765
48137
|
if (!mergePreservesHermesSemantics(before.raw, flushed, expectedHooks)) {
|
|
47766
48138
|
throw new Error(INVALID_MERGE_MESSAGE);
|
|
47767
48139
|
}
|
|
@@ -47773,7 +48145,7 @@ function writeHermesConfigSnapshot(path9, before, after, expectedHooks) {
|
|
|
47773
48145
|
});
|
|
47774
48146
|
}
|
|
47775
48147
|
function removeLegacyShim() {
|
|
47776
|
-
|
|
48148
|
+
rmSync7(legacyShimPath(), { force: true });
|
|
47777
48149
|
}
|
|
47778
48150
|
function autoAcceptOf(raw) {
|
|
47779
48151
|
if (raw.trim().length === 0) {
|
|
@@ -47814,7 +48186,7 @@ function performInstall4(opts) {
|
|
|
47814
48186
|
}
|
|
47815
48187
|
function performUninstall4() {
|
|
47816
48188
|
const path9 = configPath();
|
|
47817
|
-
if (!
|
|
48189
|
+
if (!existsSync15(path9)) {
|
|
47818
48190
|
removeLegacyShim();
|
|
47819
48191
|
return { path: path9, gate: false, capture: false, autoAccept: false, changed: false };
|
|
47820
48192
|
}
|
|
@@ -47839,7 +48211,7 @@ function performUninstall4() {
|
|
|
47839
48211
|
}
|
|
47840
48212
|
function performStatus4() {
|
|
47841
48213
|
const path9 = configPath();
|
|
47842
|
-
const raw =
|
|
48214
|
+
const raw = existsSync15(path9) ? readFileSync16(path9, "utf8") : "";
|
|
47843
48215
|
const hooks = raw ? readHooks(parseHermesDocument(raw)) : {};
|
|
47844
48216
|
return {
|
|
47845
48217
|
path: path9,
|
|
@@ -47893,7 +48265,6 @@ function registerHermesCommands(program3) {
|
|
|
47893
48265
|
// src/commands/doctor.ts
|
|
47894
48266
|
var DAEMON_PROBE_TIMEOUT_MS2 = 500;
|
|
47895
48267
|
var CONNECTIVITY_TIMEOUT_MS = 3e3;
|
|
47896
|
-
var MS_PER_SECOND = 1e3;
|
|
47897
48268
|
var STALE_PENDING_MS = 3e4;
|
|
47898
48269
|
var EXIT_UNHEALTHY = 1;
|
|
47899
48270
|
function classifyDoctor(checks) {
|
|
@@ -47929,7 +48300,7 @@ function checkAuth() {
|
|
|
47929
48300
|
return classifyAuthCredential(
|
|
47930
48301
|
credential,
|
|
47931
48302
|
storedCredential ? getTokenExpiresAt() : void 0,
|
|
47932
|
-
storedCredential &&
|
|
48303
|
+
storedCredential && existsSync16(REFRESH_TOKEN_PATH)
|
|
47933
48304
|
);
|
|
47934
48305
|
}
|
|
47935
48306
|
function classifyDaemonHealth(snapshot, options = {}) {
|
|
@@ -48015,8 +48386,19 @@ function classifyDaemonHealth(snapshot, options = {}) {
|
|
|
48015
48386
|
};
|
|
48016
48387
|
}
|
|
48017
48388
|
if (!snapshot.ingestion?.healthy) {
|
|
48018
|
-
|
|
48019
|
-
|
|
48389
|
+
if (options.backlogExpected && deliveryBacklogState(snapshot.ingestion) === "draining") {
|
|
48390
|
+
const ingestionStatus2 = options.ingestionStatus ?? decisionIngestionStatus(process.cwd());
|
|
48391
|
+
const live = options.backlog;
|
|
48392
|
+
const progress = live && live.pendingCount === 0 && live.pendingSampled !== true ? "backlog drained; daemon health refreshes on its next sweep" : deliveryBacklogSummary(snapshot.ingestion, options.now, live);
|
|
48393
|
+
return {
|
|
48394
|
+
name: "daemon",
|
|
48395
|
+
status: "warn",
|
|
48396
|
+
detail: `supervised and live${snapshot.version ? ` \xB7 v${snapshot.version}` : ""} \xB7 Decision ingestion ${ingestionStatus2} \xB7 ${progress}`
|
|
48397
|
+
};
|
|
48398
|
+
}
|
|
48399
|
+
const counts = options.backlog ?? snapshot.ingestion;
|
|
48400
|
+
const pending = counts?.pendingCount ?? 0;
|
|
48401
|
+
const pendingLabel = counts?.pendingSampled ? `at least ${String(pending)}` : String(pending);
|
|
48020
48402
|
return {
|
|
48021
48403
|
name: "daemon",
|
|
48022
48404
|
status: "fail",
|
|
@@ -48033,17 +48415,23 @@ function classifyDaemonHealth(snapshot, options = {}) {
|
|
|
48033
48415
|
detail: `supervised and healthy${snapshot.version ? ` \xB7 v${snapshot.version}` : ""} \xB7 Decision ingestion ${ingestionStatus}`
|
|
48034
48416
|
};
|
|
48035
48417
|
}
|
|
48036
|
-
async function
|
|
48418
|
+
async function probeDelivery() {
|
|
48419
|
+
const stats = pendingJournalStats();
|
|
48420
|
+
const now = Date.now();
|
|
48421
|
+
const disabled = daemonExplicitlyDisabled();
|
|
48422
|
+
const expectedVersion = packageVersion();
|
|
48037
48423
|
let service;
|
|
48038
48424
|
if (process.platform === "darwin") {
|
|
48039
48425
|
try {
|
|
48040
48426
|
service = getLaunchdService();
|
|
48041
48427
|
} catch (error) {
|
|
48042
|
-
const detail = boundedHealthError(error instanceof Error ? error.message : String(error));
|
|
48043
48428
|
return {
|
|
48044
|
-
|
|
48045
|
-
|
|
48046
|
-
|
|
48429
|
+
snapshot: null,
|
|
48430
|
+
launchdError: error instanceof Error ? error.message : String(error),
|
|
48431
|
+
disabled,
|
|
48432
|
+
expectedVersion,
|
|
48433
|
+
stats,
|
|
48434
|
+
now
|
|
48047
48435
|
};
|
|
48048
48436
|
}
|
|
48049
48437
|
}
|
|
@@ -48052,53 +48440,74 @@ async function checkDaemon() {
|
|
|
48052
48440
|
{ callerEnv: getSiteUrl() },
|
|
48053
48441
|
{ timeoutMs: DAEMON_PROBE_TIMEOUT_MS2 }
|
|
48054
48442
|
);
|
|
48055
|
-
return
|
|
48056
|
-
|
|
48057
|
-
|
|
48058
|
-
|
|
48443
|
+
return { snapshot, service, disabled, expectedVersion, stats, now };
|
|
48444
|
+
}
|
|
48445
|
+
function daemonCheckVouchesForDrain(check) {
|
|
48446
|
+
return check.name === "daemon" && check.status !== "fail";
|
|
48447
|
+
}
|
|
48448
|
+
function classifyDelivery(probe, options = {}) {
|
|
48449
|
+
const { stats, now } = probe;
|
|
48450
|
+
const launchdDetail = probe.launchdError === void 0 ? void 0 : boundedHealthError(probe.launchdError);
|
|
48451
|
+
const daemon = probe.launchdError === void 0 ? classifyDaemonHealth(probe.snapshot, {
|
|
48452
|
+
disabled: probe.disabled,
|
|
48453
|
+
service: probe.service,
|
|
48454
|
+
ingestionStatus: probe.ingestionStatus,
|
|
48455
|
+
expectedVersion: probe.expectedVersion,
|
|
48456
|
+
backlogExpected: options.backlogExpected,
|
|
48457
|
+
backlog: {
|
|
48458
|
+
pendingCount: stats.pendingCount,
|
|
48459
|
+
pendingSampled: stats.sampled,
|
|
48460
|
+
oldestPendingAt: stats.oldestPendingAt
|
|
48461
|
+
},
|
|
48462
|
+
now
|
|
48463
|
+
}) : {
|
|
48464
|
+
name: "daemon",
|
|
48465
|
+
status: "fail",
|
|
48466
|
+
detail: `launchd status unavailable${launchdDetail ? `: ${launchdDetail}` : ""}`
|
|
48467
|
+
};
|
|
48468
|
+
const journal = classifyJournal(stats, now, {
|
|
48469
|
+
backlogExpected: options.backlogExpected === true && daemonCheckVouchesForDrain(daemon)
|
|
48059
48470
|
});
|
|
48471
|
+
return [daemon, journal, classifyStranded(stats)];
|
|
48060
48472
|
}
|
|
48061
|
-
function
|
|
48062
|
-
const stats = pendingJournalStats();
|
|
48473
|
+
function classifyJournal(stats, now, options = {}) {
|
|
48063
48474
|
const pending = stats.pendingCount;
|
|
48064
48475
|
const pendingLabel = stats.sampled ? `at least ${String(pending)}` : String(pending);
|
|
48476
|
+
const backlog = (detail) => options.backlogExpected ? {
|
|
48477
|
+
name: "journal",
|
|
48478
|
+
status: "warn",
|
|
48479
|
+
detail: `${formatPendingBacklog(
|
|
48480
|
+
{
|
|
48481
|
+
pendingCount: pending,
|
|
48482
|
+
pendingSampled: stats.sampled,
|
|
48483
|
+
oldestPendingAt: stats.oldestPendingAt
|
|
48484
|
+
},
|
|
48485
|
+
now
|
|
48486
|
+
)} \u2014 draining in the background`
|
|
48487
|
+
} : { name: "journal", status: "fail", detail };
|
|
48065
48488
|
if (pending === 0) {
|
|
48066
48489
|
if (stats.sampled) {
|
|
48067
|
-
return
|
|
48068
|
-
name: "journal",
|
|
48069
|
-
status: "fail",
|
|
48070
|
-
detail: "bounded journal sample could not prove the queue is empty"
|
|
48071
|
-
};
|
|
48490
|
+
return backlog("bounded journal sample could not prove the queue is empty");
|
|
48072
48491
|
}
|
|
48073
48492
|
return { name: "journal", status: "ok", detail: "no pending moves" };
|
|
48074
48493
|
}
|
|
48075
48494
|
if (stats.oldestPendingAt === void 0) {
|
|
48076
|
-
|
|
48077
|
-
|
|
48078
|
-
status: "fail",
|
|
48079
|
-
detail: `${pendingLabel} pending with no readable capture timestamp`
|
|
48080
|
-
};
|
|
48495
|
+
const detail = `${pendingLabel} pending with no readable capture timestamp`;
|
|
48496
|
+
return stats.sampled ? backlog(detail) : { name: "journal", status: "fail", detail };
|
|
48081
48497
|
}
|
|
48082
|
-
const oldestMs =
|
|
48498
|
+
const oldestMs = now - stats.oldestPendingAt;
|
|
48083
48499
|
const oldestS = Math.round(oldestMs / MS_PER_SECOND);
|
|
48084
48500
|
if (oldestMs > STALE_PENDING_MS) {
|
|
48085
|
-
return
|
|
48086
|
-
|
|
48087
|
-
|
|
48088
|
-
detail: `${pendingLabel} pending, oldest observed ${String(oldestS)}s \u2014 30s delivery SLA missed`
|
|
48089
|
-
};
|
|
48501
|
+
return backlog(
|
|
48502
|
+
`${pendingLabel} pending, oldest observed ${String(oldestS)}s \u2014 30s delivery SLA missed`
|
|
48503
|
+
);
|
|
48090
48504
|
}
|
|
48091
48505
|
if (stats.sampled) {
|
|
48092
|
-
return {
|
|
48093
|
-
name: "journal",
|
|
48094
|
-
status: "fail",
|
|
48095
|
-
detail: `${pendingLabel} pending in bounded sample; 30s delivery SLA cannot be proven`
|
|
48096
|
-
};
|
|
48506
|
+
return backlog(`${pendingLabel} pending in bounded sample; 30s delivery SLA cannot be proven`);
|
|
48097
48507
|
}
|
|
48098
48508
|
return { name: "journal", status: "ok", detail: `${String(pending)} pending, draining` };
|
|
48099
48509
|
}
|
|
48100
|
-
function
|
|
48101
|
-
const stats = pendingJournalStats();
|
|
48510
|
+
function classifyStranded(stats) {
|
|
48102
48511
|
if (stats.strandedFileCount === 0 && !stats.strandedSampled) {
|
|
48103
48512
|
return { name: "stranded", status: "ok", detail: "none" };
|
|
48104
48513
|
}
|
|
@@ -48124,15 +48533,10 @@ function classifyJournalOrganization(bucketCount, retainedBuckets) {
|
|
|
48124
48533
|
detail: "all pending buckets match the active credential"
|
|
48125
48534
|
};
|
|
48126
48535
|
}
|
|
48127
|
-
const reasonCounts = /* @__PURE__ */ new Map();
|
|
48128
|
-
for (const item of retainedBuckets) {
|
|
48129
|
-
reasonCounts.set(item.reason, (reasonCounts.get(item.reason) ?? 0) + 1);
|
|
48130
|
-
}
|
|
48131
|
-
const reasons = [...reasonCounts].sort(([left], [right]) => left.localeCompare(right)).map(([reason, count]) => `${reason}:${String(count)}`).join(", ");
|
|
48132
48536
|
return {
|
|
48133
48537
|
name: "journal-org",
|
|
48134
48538
|
status: "fail",
|
|
48135
|
-
detail: `${String(retainedBuckets.length)} bucket(s) retained (${
|
|
48539
|
+
detail: `${String(retainedBuckets.length)} bucket(s) retained (${summarizeRetainedBuckets(retainedBuckets)})`
|
|
48136
48540
|
};
|
|
48137
48541
|
}
|
|
48138
48542
|
async function checkJournalOrganization() {
|
|
@@ -48543,30 +48947,37 @@ function refreshOwnedGlobalHooksForHealth() {
|
|
|
48543
48947
|
} catch {
|
|
48544
48948
|
}
|
|
48545
48949
|
}
|
|
48546
|
-
async function
|
|
48950
|
+
async function independentChecks() {
|
|
48547
48951
|
refreshOwnedGlobalHooksForHealth();
|
|
48548
48952
|
const backend = await checkBackend();
|
|
48549
|
-
return
|
|
48550
|
-
checkAuth(),
|
|
48551
|
-
|
|
48552
|
-
|
|
48553
|
-
|
|
48554
|
-
|
|
48555
|
-
|
|
48556
|
-
|
|
48557
|
-
|
|
48558
|
-
|
|
48559
|
-
|
|
48560
|
-
|
|
48561
|
-
|
|
48562
|
-
|
|
48563
|
-
|
|
48953
|
+
return {
|
|
48954
|
+
before: [checkAuth()],
|
|
48955
|
+
after: [
|
|
48956
|
+
await checkJournalOrganization(),
|
|
48957
|
+
checkFeedbackHooks(),
|
|
48958
|
+
...checkAgentHooks(),
|
|
48959
|
+
checkHookRuntime(),
|
|
48960
|
+
await checkRepositoryBinding(),
|
|
48961
|
+
checkManagedHook("post-commit", inspectEffectivePostCommitHook),
|
|
48962
|
+
checkManagedHook("post-rewrite", inspectEffectivePostRewriteHook),
|
|
48963
|
+
...backend,
|
|
48964
|
+
await checkFeedbackCapability()
|
|
48965
|
+
]
|
|
48966
|
+
};
|
|
48967
|
+
}
|
|
48968
|
+
var DEFAULT_DOCTOR_PROBES = {
|
|
48969
|
+
delivery: probeDelivery,
|
|
48970
|
+
independent: independentChecks
|
|
48971
|
+
};
|
|
48972
|
+
async function collectChecks(options, probes) {
|
|
48973
|
+
const { before, after } = await probes.independent();
|
|
48974
|
+
return [...before, ...classifyDelivery(await probes.delivery(), options), ...after];
|
|
48564
48975
|
}
|
|
48565
48976
|
function icon(status) {
|
|
48566
48977
|
return status === "ok" ? "\u2713" : status === "warn" ? "\u26A0" : "\u2717";
|
|
48567
48978
|
}
|
|
48568
|
-
async function runDoctor() {
|
|
48569
|
-
const checks = await collectChecks();
|
|
48979
|
+
async function runDoctor(options, probes) {
|
|
48980
|
+
const checks = await collectChecks(options, probes);
|
|
48570
48981
|
const { json, exitCode } = classifyDoctor(checks);
|
|
48571
48982
|
const headline = json.status === "ok" ? "\u2713 healthy" : json.status === "warn" ? "\u26A0 degraded" : "\u2717 unhealthy";
|
|
48572
48983
|
process.stderr.write(`[prim] doctor: ${headline}
|
|
@@ -48580,101 +48991,104 @@ async function runDoctor() {
|
|
|
48580
48991
|
process.exitCode = exitCode;
|
|
48581
48992
|
}
|
|
48582
48993
|
}
|
|
48583
|
-
function registerDoctorCommands(program3) {
|
|
48994
|
+
function registerDoctorCommands(program3, dependencies = {}) {
|
|
48584
48995
|
program3.command("doctor").description(
|
|
48585
48996
|
"Check capture and feedback health end to end (auth, supervisor, delivery, server)"
|
|
48586
|
-
).action(async () => {
|
|
48587
|
-
await runDoctor(
|
|
48997
|
+
).addOption(new Option("--expect-backlog").hideHelp()).action(async (opts) => {
|
|
48998
|
+
await runDoctor(
|
|
48999
|
+
{ backlogExpected: opts.expectBacklog === true },
|
|
49000
|
+
dependencies.probes ?? DEFAULT_DOCTOR_PROBES
|
|
49001
|
+
);
|
|
48588
49002
|
});
|
|
48589
49003
|
}
|
|
48590
49004
|
|
|
48591
49005
|
// src/commands/moves.ts
|
|
48592
|
-
import { existsSync as
|
|
48593
|
-
import { join as
|
|
49006
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync12, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
49007
|
+
import { join as join22 } from "path";
|
|
48594
49008
|
|
|
48595
49009
|
// src/flusher.ts
|
|
48596
|
-
import { createReadStream, renameSync as renameSync6, unlinkSync as unlinkSync4 } from "fs";
|
|
48597
|
-
import { dirname as
|
|
49010
|
+
import { createReadStream, renameSync as renameSync6, statSync as statSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
49011
|
+
import { dirname as dirname14, join as join21 } from "path";
|
|
48598
49012
|
|
|
48599
49013
|
// src/dead-letter.ts
|
|
48600
49014
|
import { createHash as createHash9, randomBytes as randomBytes6 } from "crypto";
|
|
48601
49015
|
import {
|
|
48602
|
-
constants as
|
|
48603
|
-
chmodSync as
|
|
48604
|
-
closeSync as
|
|
48605
|
-
existsSync as
|
|
49016
|
+
constants as constants6,
|
|
49017
|
+
chmodSync as chmodSync6,
|
|
49018
|
+
closeSync as closeSync6,
|
|
49019
|
+
existsSync as existsSync17,
|
|
48606
49020
|
fchmodSync as fchmodSync3,
|
|
48607
49021
|
fsyncSync as fsyncSync3,
|
|
48608
49022
|
mkdirSync as mkdirSync11,
|
|
48609
|
-
openSync as
|
|
49023
|
+
openSync as openSync6,
|
|
48610
49024
|
renameSync as renameSync5,
|
|
48611
|
-
rmSync as
|
|
49025
|
+
rmSync as rmSync8,
|
|
48612
49026
|
writeFileSync as writeFileSync8
|
|
48613
49027
|
} from "fs";
|
|
48614
|
-
import { dirname as
|
|
48615
|
-
var
|
|
48616
|
-
var
|
|
49028
|
+
import { dirname as dirname13, join as join20 } from "path";
|
|
49029
|
+
var DIRECTORY_MODE4 = 448;
|
|
49030
|
+
var FILE_MODE3 = 384;
|
|
48617
49031
|
var DEAD_LETTER_DIRNAME = "dead-letter";
|
|
48618
49032
|
function deadLetterDirectoryForRotation(flushingPath) {
|
|
48619
|
-
return
|
|
49033
|
+
return join20(dirname13(flushingPath), DEAD_LETTER_DIRNAME);
|
|
48620
49034
|
}
|
|
48621
49035
|
function deadLetterPathForRawLine(flushingPath, rawLine) {
|
|
48622
49036
|
const quarantineId = createHash9("sha256").update(rawLine).digest("hex");
|
|
48623
|
-
return
|
|
49037
|
+
return join20(deadLetterDirectoryForRotation(flushingPath), `raw-${quarantineId}.json`);
|
|
48624
49038
|
}
|
|
48625
49039
|
function ensureDeadLetterDirectory(flushingPath, persistDirectory) {
|
|
48626
49040
|
const directory = deadLetterDirectoryForRotation(flushingPath);
|
|
48627
|
-
mkdirSync11(directory, { recursive: true, mode:
|
|
48628
|
-
|
|
48629
|
-
persistDirectory(
|
|
49041
|
+
mkdirSync11(directory, { recursive: true, mode: DIRECTORY_MODE4 });
|
|
49042
|
+
chmodSync6(directory, DIRECTORY_MODE4);
|
|
49043
|
+
persistDirectory(dirname13(directory));
|
|
48630
49044
|
return directory;
|
|
48631
49045
|
}
|
|
48632
|
-
function persistDeadLetter(directory, path9, quarantineId,
|
|
48633
|
-
if (
|
|
49046
|
+
function persistDeadLetter(directory, path9, quarantineId, record3, persistDirectory) {
|
|
49047
|
+
if (existsSync17(path9)) {
|
|
48634
49048
|
persistDirectory(directory);
|
|
48635
49049
|
return;
|
|
48636
49050
|
}
|
|
48637
|
-
const temporaryPath =
|
|
49051
|
+
const temporaryPath = join20(
|
|
48638
49052
|
directory,
|
|
48639
49053
|
`.${quarantineId}.${String(process.pid)}.${randomBytes6(8).toString("hex")}.tmp`
|
|
48640
49054
|
);
|
|
48641
|
-
const flags =
|
|
49055
|
+
const flags = constants6.O_CREAT | constants6.O_EXCL | constants6.O_WRONLY | constants6.O_NOFOLLOW;
|
|
48642
49056
|
try {
|
|
48643
|
-
const fd =
|
|
49057
|
+
const fd = openSync6(temporaryPath, flags, FILE_MODE3);
|
|
48644
49058
|
try {
|
|
48645
|
-
fchmodSync3(fd,
|
|
48646
|
-
writeFileSync8(fd, `${JSON.stringify(
|
|
49059
|
+
fchmodSync3(fd, FILE_MODE3);
|
|
49060
|
+
writeFileSync8(fd, `${JSON.stringify(record3)}
|
|
48647
49061
|
`, "utf8");
|
|
48648
49062
|
fsyncSync3(fd);
|
|
48649
49063
|
} finally {
|
|
48650
|
-
|
|
49064
|
+
closeSync6(fd);
|
|
48651
49065
|
}
|
|
48652
49066
|
renameSync5(temporaryPath, path9);
|
|
48653
49067
|
persistDirectory(directory);
|
|
48654
49068
|
} finally {
|
|
48655
|
-
|
|
49069
|
+
rmSync8(temporaryPath, { force: true });
|
|
48656
49070
|
}
|
|
48657
49071
|
}
|
|
48658
49072
|
function quarantineMove(flushingPath, move, reason, now = Date.now, options = {}) {
|
|
48659
49073
|
const persistDirectory = options.syncDirectory ?? syncDirectory;
|
|
48660
49074
|
const directory = ensureDeadLetterDirectory(flushingPath, persistDirectory);
|
|
48661
49075
|
const serializedMove = JSON.stringify(move);
|
|
48662
|
-
const
|
|
49076
|
+
const record3 = {
|
|
48663
49077
|
version: 1,
|
|
48664
49078
|
quarantineId: createHash9("sha256").update(serializedMove).digest("hex"),
|
|
48665
49079
|
quarantinedAt: now(),
|
|
48666
49080
|
reason,
|
|
48667
49081
|
move
|
|
48668
49082
|
};
|
|
48669
|
-
const path9 =
|
|
48670
|
-
persistDeadLetter(directory, path9,
|
|
48671
|
-
return
|
|
49083
|
+
const path9 = join20(directory, `${record3.quarantineId}.json`);
|
|
49084
|
+
persistDeadLetter(directory, path9, record3.quarantineId, record3, persistDirectory);
|
|
49085
|
+
return record3;
|
|
48672
49086
|
}
|
|
48673
49087
|
function quarantineRawLine(flushingPath, rawLine, now = Date.now, options = {}) {
|
|
48674
49088
|
const persistDirectory = options.syncDirectory ?? syncDirectory;
|
|
48675
49089
|
const directory = ensureDeadLetterDirectory(flushingPath, persistDirectory);
|
|
48676
49090
|
const bytes = Buffer.from(rawLine);
|
|
48677
|
-
const
|
|
49091
|
+
const record3 = {
|
|
48678
49092
|
version: 1,
|
|
48679
49093
|
recordKind: "raw_line_v1",
|
|
48680
49094
|
quarantineId: createHash9("sha256").update(bytes).digest("hex"),
|
|
@@ -48687,11 +49101,11 @@ function quarantineRawLine(flushingPath, rawLine, now = Date.now, options = {})
|
|
|
48687
49101
|
persistDeadLetter(
|
|
48688
49102
|
directory,
|
|
48689
49103
|
deadLetterPathForRawLine(flushingPath, bytes),
|
|
48690
|
-
|
|
48691
|
-
|
|
49104
|
+
record3.quarantineId,
|
|
49105
|
+
record3,
|
|
48692
49106
|
persistDirectory
|
|
48693
49107
|
);
|
|
48694
|
-
return
|
|
49108
|
+
return record3;
|
|
48695
49109
|
}
|
|
48696
49110
|
|
|
48697
49111
|
// src/ingest-response.ts
|
|
@@ -48725,9 +49139,13 @@ function requireDurableIngestAcknowledgement(value, expected, cwd = process.cwd(
|
|
|
48725
49139
|
|
|
48726
49140
|
// src/flusher.ts
|
|
48727
49141
|
var BATCH_SIZE = 500;
|
|
49142
|
+
var BATCH_MAX_BYTES = 1048576;
|
|
48728
49143
|
var HTTP_TIMEOUT_MS = 1e4;
|
|
48729
49144
|
var OPPORTUNISTIC_FLUSH_AFTER_MS = 6e4;
|
|
48730
49145
|
var ORPHAN_QUARANTINE_MS = 6e4;
|
|
49146
|
+
function exceedsBatchBytes(count, bytes, nextBytes, maxBytes) {
|
|
49147
|
+
return count > 0 && bytes + nextBytes > maxBytes;
|
|
49148
|
+
}
|
|
48731
49149
|
function addDrainCounts(left, right) {
|
|
48732
49150
|
return {
|
|
48733
49151
|
flushed: left.flushed + right.flushed,
|
|
@@ -48738,8 +49156,8 @@ function collectionScopeRoots(batch) {
|
|
|
48738
49156
|
return batch.flatMap((move) => {
|
|
48739
49157
|
const env4 = move.env;
|
|
48740
49158
|
if (typeof env4 !== "object" || env4 === null || Array.isArray(env4)) return [];
|
|
48741
|
-
const
|
|
48742
|
-
const root = typeof
|
|
49159
|
+
const record3 = env4;
|
|
49160
|
+
const root = typeof record3.gitRoot === "string" ? record3.gitRoot : record3.cwd;
|
|
48743
49161
|
return typeof root === "string" && root.length > 0 ? [root] : [];
|
|
48744
49162
|
});
|
|
48745
49163
|
}
|
|
@@ -48747,8 +49165,8 @@ function isVersionedInvalidMoveDisposition(body) {
|
|
|
48747
49165
|
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
48748
49166
|
return false;
|
|
48749
49167
|
}
|
|
48750
|
-
const
|
|
48751
|
-
return Object.keys(
|
|
49168
|
+
const record3 = body;
|
|
49169
|
+
return Object.keys(record3).length === 2 && record3.error === "invalid_move" && record3.errorVersion === 1;
|
|
48752
49170
|
}
|
|
48753
49171
|
function deadLetterReason(error) {
|
|
48754
49172
|
if (error instanceof InvalidJournalEnvelopeError) {
|
|
@@ -48771,23 +49189,31 @@ function deadLetterReason(error) {
|
|
|
48771
49189
|
}
|
|
48772
49190
|
return void 0;
|
|
48773
49191
|
}
|
|
48774
|
-
|
|
49192
|
+
function mayBeBatchSizeFailure(error) {
|
|
49193
|
+
if (error instanceof HttpError) {
|
|
49194
|
+
return error.status >= 500 && error.status !== 503;
|
|
49195
|
+
}
|
|
49196
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
49197
|
+
}
|
|
49198
|
+
async function* rawJournalLines(input, offset) {
|
|
48775
49199
|
let pending = [];
|
|
48776
49200
|
let pendingBytes = 0;
|
|
49201
|
+
let end = offset;
|
|
48777
49202
|
for await (const value of input) {
|
|
48778
49203
|
const chunk2 = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
48779
49204
|
let start = 0;
|
|
48780
49205
|
let newline = chunk2.indexOf(10, start);
|
|
48781
49206
|
while (newline !== -1) {
|
|
48782
49207
|
const tail = chunk2.subarray(start, newline + 1);
|
|
48783
|
-
|
|
48784
|
-
|
|
48785
|
-
} else {
|
|
49208
|
+
let line = tail;
|
|
49209
|
+
if (pending.length > 0) {
|
|
48786
49210
|
pending.push(tail);
|
|
48787
|
-
|
|
49211
|
+
line = Buffer.concat(pending, pendingBytes + tail.length);
|
|
48788
49212
|
pending = [];
|
|
48789
49213
|
pendingBytes = 0;
|
|
48790
49214
|
}
|
|
49215
|
+
end += line.length;
|
|
49216
|
+
yield { bytes: line, end };
|
|
48791
49217
|
start = newline + 1;
|
|
48792
49218
|
newline = chunk2.indexOf(10, start);
|
|
48793
49219
|
}
|
|
@@ -48798,21 +49224,46 @@ async function* rawJournalLines(input) {
|
|
|
48798
49224
|
}
|
|
48799
49225
|
}
|
|
48800
49226
|
if (pendingBytes > 0) {
|
|
48801
|
-
|
|
49227
|
+
const bytes = pending.length === 1 ? pending[0] : Buffer.concat(pending, pendingBytes);
|
|
49228
|
+
yield { bytes, end: end + pendingBytes };
|
|
48802
49229
|
}
|
|
48803
49230
|
}
|
|
49231
|
+
var drainProgressWarned = false;
|
|
48804
49232
|
async function drainFlushingPath(flushingPath, client, binding, options = {}) {
|
|
49233
|
+
const rotation = rotationIdentity(statSync5(flushingPath));
|
|
49234
|
+
const resumeAt = drainResumeOffset(flushingPath, rotation);
|
|
49235
|
+
const recordProgress = (end) => {
|
|
49236
|
+
if (end === void 0 || end >= rotation.size) {
|
|
49237
|
+
return;
|
|
49238
|
+
}
|
|
49239
|
+
try {
|
|
49240
|
+
writeDrainCheckpoint(flushingPath, { v: 2, offset: end, ...rotation });
|
|
49241
|
+
drainProgressWarned = false;
|
|
49242
|
+
} catch (error) {
|
|
49243
|
+
if (!drainProgressWarned) {
|
|
49244
|
+
drainProgressWarned = true;
|
|
49245
|
+
process.stderr.write(
|
|
49246
|
+
`[prim] could not record drain progress: ${error instanceof Error ? error.message : String(error)}
|
|
49247
|
+
`
|
|
49248
|
+
);
|
|
49249
|
+
}
|
|
49250
|
+
}
|
|
49251
|
+
};
|
|
49252
|
+
const reportProgress = (delta) => {
|
|
49253
|
+
options.onProgress?.(delta);
|
|
49254
|
+
return delta;
|
|
49255
|
+
};
|
|
48805
49256
|
const postBatch = async (batch2) => {
|
|
49257
|
+
const moves = batch2.map((entry) => entry.move);
|
|
48806
49258
|
try {
|
|
48807
|
-
const request2 = buildOrganizationBoundMoveRequest(
|
|
49259
|
+
const request2 = buildOrganizationBoundMoveRequest(moves, binding);
|
|
48808
49260
|
const response = await client.post("/api/cli/moves/ingest", request2, {
|
|
48809
49261
|
signal: AbortSignal.timeout(HTTP_TIMEOUT_MS)
|
|
48810
49262
|
});
|
|
48811
|
-
requireDurableIngestAcknowledgement(response,
|
|
48812
|
-
return { flushed: batch2.length, quarantined: 0 };
|
|
49263
|
+
requireDurableIngestAcknowledgement(response, moves.length, collectionScopeRoots(moves));
|
|
48813
49264
|
} catch (error) {
|
|
48814
49265
|
const reason = deadLetterReason(error);
|
|
48815
|
-
if (!reason) {
|
|
49266
|
+
if (!(reason || mayBeBatchSizeFailure(error))) {
|
|
48816
49267
|
throw error;
|
|
48817
49268
|
}
|
|
48818
49269
|
if (batch2.length > 1) {
|
|
@@ -48821,33 +49272,46 @@ async function drainFlushingPath(flushingPath, client, binding, options = {}) {
|
|
|
48821
49272
|
const right = await postBatch(batch2.slice(midpoint));
|
|
48822
49273
|
return addDrainCounts(left, right);
|
|
48823
49274
|
}
|
|
48824
|
-
|
|
49275
|
+
if (!reason) {
|
|
49276
|
+
throw error;
|
|
49277
|
+
}
|
|
49278
|
+
const [entry] = batch2;
|
|
48825
49279
|
const quarantined = quarantineMove(
|
|
48826
49280
|
flushingPath,
|
|
48827
|
-
move,
|
|
49281
|
+
entry.move,
|
|
48828
49282
|
reason,
|
|
48829
49283
|
Date.now,
|
|
48830
49284
|
options.deadLetterPersistence
|
|
48831
49285
|
);
|
|
49286
|
+
recordProgress(entry.end);
|
|
48832
49287
|
process.stderr.write(
|
|
48833
49288
|
`[prim] quarantined rejected move ${quarantined.quarantineId.slice(0, 12)} (${reason})
|
|
48834
49289
|
`
|
|
48835
49290
|
);
|
|
48836
|
-
return { flushed: 0, quarantined: 1 };
|
|
49291
|
+
return reportProgress({ flushed: 0, quarantined: 1 });
|
|
48837
49292
|
}
|
|
49293
|
+
recordProgress(batch2.at(-1)?.end);
|
|
49294
|
+
return reportProgress({ flushed: batch2.length, quarantined: 0 });
|
|
48838
49295
|
};
|
|
48839
|
-
const input = createReadStream(flushingPath);
|
|
49296
|
+
const input = createReadStream(flushingPath, { start: resumeAt });
|
|
48840
49297
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
48841
49298
|
let batch = [];
|
|
49299
|
+
let batchBytes = 0;
|
|
48842
49300
|
let counts = { flushed: 0, quarantined: 0 };
|
|
49301
|
+
const postPending = async () => {
|
|
49302
|
+
counts = addDrainCounts(counts, await postBatch(batch));
|
|
49303
|
+
batch = [];
|
|
49304
|
+
batchBytes = 0;
|
|
49305
|
+
};
|
|
48843
49306
|
try {
|
|
48844
|
-
for await (const rawLine of rawJournalLines(input)) {
|
|
49307
|
+
for await (const { bytes: rawLine, end } of rawJournalLines(input, resumeAt)) {
|
|
48845
49308
|
if (rawLine.length === 1 && rawLine[0] === 10 || rawLine.length === 2 && rawLine[0] === 13 && rawLine[1] === 10) {
|
|
48846
49309
|
continue;
|
|
48847
49310
|
}
|
|
49311
|
+
let move;
|
|
48848
49312
|
try {
|
|
48849
49313
|
const line = decoder.decode(rawLine);
|
|
48850
|
-
|
|
49314
|
+
move = JSON.parse(line);
|
|
48851
49315
|
} catch {
|
|
48852
49316
|
const quarantined = quarantineRawLine(
|
|
48853
49317
|
flushingPath,
|
|
@@ -48859,24 +49323,35 @@ async function drainFlushingPath(flushingPath, client, binding, options = {}) {
|
|
|
48859
49323
|
`[prim] quarantined invalid journal line ${quarantined.quarantineId.slice(0, 12)} (invalid_move)
|
|
48860
49324
|
`
|
|
48861
49325
|
);
|
|
48862
|
-
counts
|
|
49326
|
+
counts = addDrainCounts(counts, reportProgress({ flushed: 0, quarantined: 1 }));
|
|
49327
|
+
if (batch.length === 0) {
|
|
49328
|
+
recordProgress(end);
|
|
49329
|
+
}
|
|
48863
49330
|
continue;
|
|
48864
49331
|
}
|
|
48865
|
-
if (batch.length
|
|
48866
|
-
|
|
48867
|
-
|
|
49332
|
+
if (exceedsBatchBytes(batch.length, batchBytes, rawLine.length, BATCH_MAX_BYTES)) {
|
|
49333
|
+
await postPending();
|
|
49334
|
+
}
|
|
49335
|
+
batch.push({ move, end });
|
|
49336
|
+
batchBytes += rawLine.length;
|
|
49337
|
+
if (batch.length >= BATCH_SIZE) {
|
|
49338
|
+
await postPending();
|
|
48868
49339
|
}
|
|
48869
49340
|
}
|
|
48870
49341
|
if (batch.length > 0) {
|
|
48871
|
-
|
|
49342
|
+
await postPending();
|
|
48872
49343
|
}
|
|
48873
49344
|
} finally {
|
|
48874
49345
|
input.destroy();
|
|
48875
49346
|
}
|
|
48876
49347
|
unlinkSync4(flushingPath);
|
|
49348
|
+
try {
|
|
49349
|
+
removeDrainCheckpoint(flushingPath);
|
|
49350
|
+
} catch {
|
|
49351
|
+
}
|
|
48877
49352
|
return counts;
|
|
48878
49353
|
}
|
|
48879
|
-
async function drainPath(path9, client, binding) {
|
|
49354
|
+
async function drainPath(path9, client, binding, onProgress) {
|
|
48880
49355
|
const tmpPath = `${path9}.flushing.${String(Date.now())}.${String(process.pid)}`;
|
|
48881
49356
|
try {
|
|
48882
49357
|
renameSync6(path9, tmpPath);
|
|
@@ -48886,7 +49361,19 @@ async function drainPath(path9, client, binding) {
|
|
|
48886
49361
|
}
|
|
48887
49362
|
throw err;
|
|
48888
49363
|
}
|
|
48889
|
-
return drainFlushingPath(tmpPath, client, binding);
|
|
49364
|
+
return drainFlushingPath(tmpPath, client, binding, { onProgress });
|
|
49365
|
+
}
|
|
49366
|
+
async function settleDrain(drain) {
|
|
49367
|
+
let progress = { flushed: 0, quarantined: 0 };
|
|
49368
|
+
try {
|
|
49369
|
+
return {
|
|
49370
|
+
counts: await drain((delta) => {
|
|
49371
|
+
progress = addDrainCounts(progress, delta);
|
|
49372
|
+
})
|
|
49373
|
+
};
|
|
49374
|
+
} catch (error) {
|
|
49375
|
+
return { counts: progress, failure: { error } };
|
|
49376
|
+
}
|
|
48890
49377
|
}
|
|
48891
49378
|
function selectRecoverable(files, now, opts = {}) {
|
|
48892
49379
|
const quarantineMs = opts.quarantineMs ?? ORPHAN_QUARANTINE_MS;
|
|
@@ -48903,7 +49390,8 @@ async function recoverOrphans(candidates, options) {
|
|
|
48903
49390
|
flushed: 0,
|
|
48904
49391
|
quarantined: 0,
|
|
48905
49392
|
errors: [],
|
|
48906
|
-
failedBuckets: /* @__PURE__ */ new Set()
|
|
49393
|
+
failedBuckets: /* @__PURE__ */ new Set(),
|
|
49394
|
+
failedDrainFlushed: 0
|
|
48907
49395
|
};
|
|
48908
49396
|
const recoverable = selectRecoverable(candidates, options.now ?? Date.now(), {
|
|
48909
49397
|
ownerPid: options.ownerPid ?? process.pid,
|
|
@@ -48914,28 +49402,41 @@ async function recoverOrphans(candidates, options) {
|
|
|
48914
49402
|
if (summary.failedBuckets.has(file.bucket)) {
|
|
48915
49403
|
continue;
|
|
48916
49404
|
}
|
|
48917
|
-
|
|
48918
|
-
|
|
48919
|
-
|
|
48920
|
-
|
|
48921
|
-
|
|
48922
|
-
summary.errors.push(
|
|
49405
|
+
const { counts, failure: failure4 } = await settleDrain((onProgress) => drain(file.path, onProgress));
|
|
49406
|
+
summary.flushed += counts.flushed;
|
|
49407
|
+
summary.quarantined += counts.quarantined;
|
|
49408
|
+
if (failure4) {
|
|
49409
|
+
summary.failedDrainFlushed += counts.flushed;
|
|
49410
|
+
summary.errors.push(failure4.error);
|
|
48923
49411
|
summary.failedBuckets.add(file.bucket);
|
|
48924
49412
|
}
|
|
48925
49413
|
}
|
|
48926
49414
|
return summary;
|
|
48927
49415
|
}
|
|
48928
49416
|
var FlushError = class extends Error {
|
|
49417
|
+
/** Moves the whole sweep acknowledged, across every drain it ran. */
|
|
48929
49418
|
flushed;
|
|
48930
49419
|
quarantined;
|
|
48931
|
-
|
|
49420
|
+
/** Buckets the failed sweep held back without sending, as on success. */
|
|
49421
|
+
retained;
|
|
49422
|
+
/**
|
|
49423
|
+
* Of `flushed`, the Moves acknowledged by the drains that failed, before
|
|
49424
|
+
* they failed. Only this shows the failure itself is advancing: `flushed`
|
|
49425
|
+
* also counts other buckets' drains, so a bucket whose drain fails every
|
|
49426
|
+
* time would read as progress while a sibling bucket kept delivering.
|
|
49427
|
+
*/
|
|
49428
|
+
failedDrainFlushed;
|
|
49429
|
+
constructor(cause, flushed, quarantined, retained = [], failedDrainFlushed = 0) {
|
|
48932
49430
|
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
48933
49431
|
this.name = "FlushError";
|
|
48934
49432
|
this.flushed = flushed;
|
|
48935
49433
|
this.quarantined = quarantined;
|
|
49434
|
+
this.retained = retained;
|
|
49435
|
+
this.failedDrainFlushed = failedDrainFlushed;
|
|
48936
49436
|
}
|
|
48937
49437
|
};
|
|
48938
49438
|
async function flushOnce() {
|
|
49439
|
+
sweepOrphanedDrainProgress();
|
|
48939
49440
|
const orphanCandidates = listFlushing({ sampleBytes: 0 });
|
|
48940
49441
|
const liveBuckets = listBuckets();
|
|
48941
49442
|
if (orphanCandidates.length === 0 && liveBuckets.length === 0) {
|
|
@@ -48952,10 +49453,11 @@ async function flushOnce() {
|
|
|
48952
49453
|
const binding = inspection.binding;
|
|
48953
49454
|
const recovered = await recoverOrphans(
|
|
48954
49455
|
orphanCandidates.filter((file) => inspection.deliverableBuckets.has(file.bucket)),
|
|
48955
|
-
{ drain: (path9) => drainFlushingPath(path9, client, binding) }
|
|
49456
|
+
{ drain: (path9, onProgress) => drainFlushingPath(path9, client, binding, { onProgress }) }
|
|
48956
49457
|
);
|
|
48957
49458
|
let total = recovered.flushed;
|
|
48958
49459
|
let quarantined = recovered.quarantined;
|
|
49460
|
+
let failedDrainFlushed = recovered.failedDrainFlushed;
|
|
48959
49461
|
const errors = recovered.errors;
|
|
48960
49462
|
for (const { bucket, path: path9 } of liveBuckets) {
|
|
48961
49463
|
if (!inspection.deliverableBuckets.has(bucket)) {
|
|
@@ -48964,21 +49466,29 @@ async function flushOnce() {
|
|
|
48964
49466
|
if (recovered.failedBuckets.has(bucket)) {
|
|
48965
49467
|
continue;
|
|
48966
49468
|
}
|
|
48967
|
-
|
|
48968
|
-
|
|
48969
|
-
|
|
48970
|
-
|
|
48971
|
-
|
|
48972
|
-
|
|
49469
|
+
const { counts, failure: failure4 } = await settleDrain(
|
|
49470
|
+
(onProgress) => drainPath(path9, client, binding, onProgress)
|
|
49471
|
+
);
|
|
49472
|
+
total += counts.flushed;
|
|
49473
|
+
quarantined += counts.quarantined;
|
|
49474
|
+
if (failure4) {
|
|
49475
|
+
failedDrainFlushed += counts.flushed;
|
|
49476
|
+
errors.push(failure4.error);
|
|
48973
49477
|
}
|
|
48974
49478
|
}
|
|
48975
49479
|
if (errors.length > 0) {
|
|
48976
|
-
throw new FlushError(
|
|
49480
|
+
throw new FlushError(
|
|
49481
|
+
errors[0],
|
|
49482
|
+
total,
|
|
49483
|
+
quarantined,
|
|
49484
|
+
inspection.retainedBuckets,
|
|
49485
|
+
failedDrainFlushed
|
|
49486
|
+
);
|
|
48977
49487
|
}
|
|
48978
49488
|
return inspection.retainedBuckets.length > 0 ? { flushed: total, quarantined, retained: inspection.retainedBuckets } : { flushed: total, quarantined };
|
|
48979
49489
|
}
|
|
48980
49490
|
var flushInFlight;
|
|
48981
|
-
var FLUSH_LOCK_PATH =
|
|
49491
|
+
var FLUSH_LOCK_PATH = join21(dirname14(JOURNAL_DIR), ".flush.lock");
|
|
48982
49492
|
var FLUSH_LOCK_TIMEOUT_MS = 250;
|
|
48983
49493
|
function isFlushLockContended(error) {
|
|
48984
49494
|
return error instanceof Error && error.message.startsWith("timed out waiting for file lock");
|
|
@@ -49003,18 +49513,16 @@ function flush() {
|
|
|
49003
49513
|
return attempt;
|
|
49004
49514
|
}
|
|
49005
49515
|
function shouldFlushPending(stats, now, thresholdMs = OPPORTUNISTIC_FLUSH_AFTER_MS) {
|
|
49006
|
-
if (stats.sampled) {
|
|
49516
|
+
if (stats.sampled || stats.strandedFileCount > 0 && stats.strandedCount === 0) {
|
|
49007
49517
|
return true;
|
|
49008
49518
|
}
|
|
49009
49519
|
return stats.pendingCount > 0 && (stats.oldestPendingAt === void 0 || now - stats.oldestPendingAt > thresholdMs);
|
|
49010
49520
|
}
|
|
49011
|
-
|
|
49521
|
+
function journalNeedsFlush(now = Date.now()) {
|
|
49012
49522
|
try {
|
|
49013
|
-
|
|
49014
|
-
if (shouldFlushPending(stats, Date.now())) {
|
|
49015
|
-
await flush();
|
|
49016
|
-
}
|
|
49523
|
+
return shouldFlushPending(pendingJournalStats(), now);
|
|
49017
49524
|
} catch {
|
|
49525
|
+
return false;
|
|
49018
49526
|
}
|
|
49019
49527
|
}
|
|
49020
49528
|
|
|
@@ -49027,7 +49535,7 @@ var EVENT_COL_WIDTH = 20;
|
|
|
49027
49535
|
var BUCKET_COL_WIDTH = 20;
|
|
49028
49536
|
var TAIL_BUCKET_COL_WIDTH = 12;
|
|
49029
49537
|
var DIR_MODE = 448;
|
|
49030
|
-
var
|
|
49538
|
+
var FILE_MODE4 = 384;
|
|
49031
49539
|
var WORKSPACE_FILE = ".prim/workspace.json";
|
|
49032
49540
|
function registerMovesCommands(program3) {
|
|
49033
49541
|
const moves = program3.command("moves").description("Decision Event Pipeline \u2014 local journal");
|
|
@@ -49073,7 +49581,7 @@ function registerMovesCommands(program3) {
|
|
|
49073
49581
|
}
|
|
49074
49582
|
if (stranded.length > 0) {
|
|
49075
49583
|
const moveCount = stranded.reduce((n, f) => n + f.lineCount, 0);
|
|
49076
|
-
const byteCount = stranded.reduce((n, f) => n + f.
|
|
49584
|
+
const byteCount = stranded.reduce((n, f) => n + f.pendingBytes, 0);
|
|
49077
49585
|
const sampled = stranded.some((file) => file.sampled);
|
|
49078
49586
|
const qualifier = sampled ? "at least " : "";
|
|
49079
49587
|
console.log(
|
|
@@ -49084,7 +49592,7 @@ function registerMovesCommands(program3) {
|
|
|
49084
49592
|
const owner = f.pid === void 0 ? "no pid" : `pid ${String(f.pid)}`;
|
|
49085
49593
|
const count = `${String(f.lineCount)}${f.sampled ? "+" : ""}`;
|
|
49086
49594
|
console.log(
|
|
49087
|
-
` ${f.bucket.padEnd(BUCKET_COL_WIDTH)} ${count.padStart(5)} stranded, ${String(f.
|
|
49595
|
+
` ${f.bucket.padEnd(BUCKET_COL_WIDTH)} ${count.padStart(5)} stranded, ${String(f.pendingBytes).padStart(8)} bytes, ${String(ageS)}s ago (${owner})`
|
|
49088
49596
|
);
|
|
49089
49597
|
}
|
|
49090
49598
|
}
|
|
@@ -49112,19 +49620,19 @@ function registerMovesCommands(program3) {
|
|
|
49112
49620
|
}
|
|
49113
49621
|
});
|
|
49114
49622
|
moves.command("bind").description("Pin the current directory to an org via .prim/workspace.json").requiredOption("--orgId <orgId>", "Convex organization id").action((opts) => {
|
|
49115
|
-
const dir =
|
|
49116
|
-
if (!
|
|
49623
|
+
const dir = join22(process.cwd(), ".prim");
|
|
49624
|
+
if (!existsSync18(dir)) {
|
|
49117
49625
|
mkdirSync12(dir, { recursive: true, mode: DIR_MODE });
|
|
49118
49626
|
}
|
|
49119
|
-
const file =
|
|
49627
|
+
const file = join22(process.cwd(), WORKSPACE_FILE);
|
|
49120
49628
|
writeFileSync9(file, JSON.stringify({ orgId: opts.orgId, boundAt: Date.now() }, null, 2), {
|
|
49121
|
-
mode:
|
|
49629
|
+
mode: FILE_MODE4
|
|
49122
49630
|
});
|
|
49123
49631
|
console.log(`[prim] bound ${process.cwd()} to org ${opts.orgId}`);
|
|
49124
49632
|
});
|
|
49125
49633
|
moves.command("drop").description("Remove the .prim/workspace.json binding from the cwd").action(() => {
|
|
49126
|
-
const file =
|
|
49127
|
-
if (!
|
|
49634
|
+
const file = join22(process.cwd(), WORKSPACE_FILE);
|
|
49635
|
+
if (!existsSync18(file)) {
|
|
49128
49636
|
console.log("[prim] no workspace binding in cwd");
|
|
49129
49637
|
return;
|
|
49130
49638
|
}
|
|
@@ -49215,31 +49723,31 @@ function registerReconcileCommands(program3) {
|
|
|
49215
49723
|
|
|
49216
49724
|
// src/commands/session.ts
|
|
49217
49725
|
import {
|
|
49218
|
-
existsSync as
|
|
49726
|
+
existsSync as existsSync20,
|
|
49219
49727
|
mkdirSync as mkdirSync13,
|
|
49220
|
-
readFileSync as
|
|
49221
|
-
readdirSync as
|
|
49728
|
+
readFileSync as readFileSync18,
|
|
49729
|
+
readdirSync as readdirSync6,
|
|
49222
49730
|
unlinkSync as unlinkSync6,
|
|
49223
49731
|
writeFileSync as writeFileSync10
|
|
49224
49732
|
} from "fs";
|
|
49225
|
-
import { join as
|
|
49733
|
+
import { join as join24 } from "path";
|
|
49226
49734
|
|
|
49227
49735
|
// src/binding.ts
|
|
49228
|
-
import { existsSync as
|
|
49229
|
-
import { dirname as
|
|
49736
|
+
import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
|
|
49737
|
+
import { dirname as dirname15, join as join23 } from "path";
|
|
49230
49738
|
var PRIM_CONFIG_DIR = primConfigDirectory();
|
|
49231
|
-
var SESSIONS_DIR =
|
|
49739
|
+
var SESSIONS_DIR = join23(PRIM_CONFIG_DIR, "sessions");
|
|
49232
49740
|
|
|
49233
49741
|
// src/commands/session.ts
|
|
49234
49742
|
var DIR_MODE2 = 448;
|
|
49235
|
-
var
|
|
49743
|
+
var FILE_MODE5 = 384;
|
|
49236
49744
|
function ensureDir() {
|
|
49237
|
-
if (!
|
|
49745
|
+
if (!existsSync20(SESSIONS_DIR)) {
|
|
49238
49746
|
mkdirSync13(SESSIONS_DIR, { recursive: true, mode: DIR_MODE2 });
|
|
49239
49747
|
}
|
|
49240
49748
|
}
|
|
49241
49749
|
function markerPath(sessionId) {
|
|
49242
|
-
return
|
|
49750
|
+
return join24(SESSIONS_DIR, `${sessionId}.json`);
|
|
49243
49751
|
}
|
|
49244
49752
|
function registerSessionCommands(program3) {
|
|
49245
49753
|
const session = program3.command("session").description("Decision Event Pipeline \u2014 session binding markers");
|
|
@@ -49250,16 +49758,16 @@ function registerSessionCommands(program3) {
|
|
|
49250
49758
|
startedAt: Date.now()
|
|
49251
49759
|
};
|
|
49252
49760
|
writeFileSync10(markerPath(sessionId), JSON.stringify(marker, null, 2), {
|
|
49253
|
-
mode:
|
|
49761
|
+
mode: FILE_MODE5
|
|
49254
49762
|
});
|
|
49255
49763
|
console.log(`[prim] session ${sessionId} bound to org ${opts.orgId}`);
|
|
49256
49764
|
});
|
|
49257
49765
|
session.command("list").description("List active session markers").action(() => {
|
|
49258
|
-
if (!
|
|
49766
|
+
if (!existsSync20(SESSIONS_DIR)) {
|
|
49259
49767
|
console.log("[prim] no session markers");
|
|
49260
49768
|
return;
|
|
49261
49769
|
}
|
|
49262
|
-
const files =
|
|
49770
|
+
const files = readdirSync6(SESSIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
49263
49771
|
if (files.length === 0) {
|
|
49264
49772
|
console.log("[prim] no session markers");
|
|
49265
49773
|
return;
|
|
@@ -49267,7 +49775,7 @@ function registerSessionCommands(program3) {
|
|
|
49267
49775
|
for (const f of files) {
|
|
49268
49776
|
const sessionId = f.replace(/\.json$/, "");
|
|
49269
49777
|
try {
|
|
49270
|
-
const m = JSON.parse(
|
|
49778
|
+
const m = JSON.parse(readFileSync18(join24(SESSIONS_DIR, f), "utf-8"));
|
|
49271
49779
|
console.log(`${sessionId} org=${m.orgId}`);
|
|
49272
49780
|
} catch {
|
|
49273
49781
|
}
|
|
@@ -49275,7 +49783,7 @@ function registerSessionCommands(program3) {
|
|
|
49275
49783
|
});
|
|
49276
49784
|
session.command("drop <sessionId>").description("Remove a session marker").action((sessionId) => {
|
|
49277
49785
|
const p = markerPath(sessionId);
|
|
49278
|
-
if (!
|
|
49786
|
+
if (!existsSync20(p)) {
|
|
49279
49787
|
console.log(`[prim] no marker for session ${sessionId}`);
|
|
49280
49788
|
return;
|
|
49281
49789
|
}
|
|
@@ -49286,10 +49794,24 @@ function registerSessionCommands(program3) {
|
|
|
49286
49794
|
|
|
49287
49795
|
// src/commands/setup.ts
|
|
49288
49796
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
49289
|
-
import { existsSync as
|
|
49290
|
-
import { join as
|
|
49797
|
+
import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
|
|
49798
|
+
import { join as join25 } from "path";
|
|
49291
49799
|
var EXIT_INCOMPLETE = 1;
|
|
49292
49800
|
var EXIT_USAGE3 = 2;
|
|
49801
|
+
var SETUP_ORCHESTRATOR_ENV = "PRIM_SETUP_ORCHESTRATOR";
|
|
49802
|
+
var SETUP_DAEMON_DRAINS_ENV = "PRIM_SETUP_DAEMON_DRAINS";
|
|
49803
|
+
function setupStepSpawnOptions(capture, env4 = process.env, options = {}) {
|
|
49804
|
+
return {
|
|
49805
|
+
env: {
|
|
49806
|
+
...env4,
|
|
49807
|
+
[SETUP_ORCHESTRATOR_ENV]: "1",
|
|
49808
|
+
// Unset rather than inherited when this setup starts no daemon.
|
|
49809
|
+
[SETUP_DAEMON_DRAINS_ENV]: options.startsDaemon === true ? "1" : void 0
|
|
49810
|
+
},
|
|
49811
|
+
stdio: capture ? ["inherit", "pipe", "ignore"] : "inherit",
|
|
49812
|
+
encoding: "utf-8"
|
|
49813
|
+
};
|
|
49814
|
+
}
|
|
49293
49815
|
var SESSION_LABELS = {
|
|
49294
49816
|
claude: "Claude Code integration",
|
|
49295
49817
|
codex: "Codex integration",
|
|
@@ -49340,7 +49862,7 @@ function planSetupSteps(opts) {
|
|
|
49340
49862
|
steps.push({
|
|
49341
49863
|
key: "health",
|
|
49342
49864
|
label: "Capture health",
|
|
49343
|
-
args: ["doctor"],
|
|
49865
|
+
args: ["doctor", "--expect-backlog"],
|
|
49344
49866
|
required: true
|
|
49345
49867
|
});
|
|
49346
49868
|
}
|
|
@@ -49369,8 +49891,8 @@ function detectProjectConflicts(agent, run) {
|
|
|
49369
49891
|
}
|
|
49370
49892
|
try {
|
|
49371
49893
|
const root = gitToplevel();
|
|
49372
|
-
const preCommit = root &&
|
|
49373
|
-
if (preCommit &&
|
|
49894
|
+
const preCommit = root && join25(root, ".git", "hooks", "pre-commit");
|
|
49895
|
+
if (preCommit && existsSync21(preCommit) && readFileSync19(preCommit, "utf-8").includes("prim-pre-commit")) {
|
|
49374
49896
|
conflicts.push(CONFLICT_HOOKS);
|
|
49375
49897
|
}
|
|
49376
49898
|
} catch {
|
|
@@ -49440,10 +49962,11 @@ function registerSetupCommand(program3, dependencies = {}) {
|
|
|
49440
49962
|
const self = process.argv[1];
|
|
49441
49963
|
const globals = program3.optsWithGlobals();
|
|
49442
49964
|
const run = dependencies.run ?? ((args, capture = false) => {
|
|
49443
|
-
const r = spawnSync2(
|
|
49444
|
-
|
|
49445
|
-
|
|
49446
|
-
|
|
49965
|
+
const r = spawnSync2(
|
|
49966
|
+
process.execPath,
|
|
49967
|
+
[self, ...args],
|
|
49968
|
+
setupStepSpawnOptions(capture, process.env, { startsDaemon: opts.daemon })
|
|
49969
|
+
);
|
|
49447
49970
|
return { code: r.status ?? 1, stdout: capture ? r.stdout ?? "" : "" };
|
|
49448
49971
|
});
|
|
49449
49972
|
const results = {};
|
|
@@ -49536,20 +50059,20 @@ function registerSetupCommand(program3, dependencies = {}) {
|
|
|
49536
50059
|
// src/commands/skill.ts
|
|
49537
50060
|
import { createHash as createHash11 } from "crypto";
|
|
49538
50061
|
import {
|
|
49539
|
-
constants as
|
|
49540
|
-
closeSync as
|
|
49541
|
-
existsSync as
|
|
49542
|
-
fstatSync as
|
|
49543
|
-
lstatSync as
|
|
49544
|
-
openSync as
|
|
49545
|
-
readFileSync as
|
|
49546
|
-
readSync as
|
|
49547
|
-
readdirSync as
|
|
49548
|
-
rmdirSync as
|
|
50062
|
+
constants as constants8,
|
|
50063
|
+
closeSync as closeSync8,
|
|
50064
|
+
existsSync as existsSync23,
|
|
50065
|
+
fstatSync as fstatSync4,
|
|
50066
|
+
lstatSync as lstatSync8,
|
|
50067
|
+
openSync as openSync8,
|
|
50068
|
+
readFileSync as readFileSync21,
|
|
50069
|
+
readSync as readSync4,
|
|
50070
|
+
readdirSync as readdirSync8,
|
|
50071
|
+
rmdirSync as rmdirSync3,
|
|
49549
50072
|
unlinkSync as unlinkSync7
|
|
49550
50073
|
} from "fs";
|
|
49551
50074
|
import { homedir as homedir11 } from "os";
|
|
49552
|
-
import { dirname as
|
|
50075
|
+
import { dirname as dirname17, join as join28, resolve as resolve8 } from "path";
|
|
49553
50076
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
49554
50077
|
|
|
49555
50078
|
// node_modules/.pnpm/diff@5.2.2/node_modules/diff/lib/index.mjs
|
|
@@ -49719,7 +50242,7 @@ Diff.prototype = {
|
|
|
49719
50242
|
tokenize: function tokenize(value) {
|
|
49720
50243
|
return value.split("");
|
|
49721
50244
|
},
|
|
49722
|
-
join: function
|
|
50245
|
+
join: function join26(chars) {
|
|
49723
50246
|
return chars.join("");
|
|
49724
50247
|
}
|
|
49725
50248
|
};
|
|
@@ -50057,30 +50580,30 @@ function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) {
|
|
|
50057
50580
|
// src/commands/claude-plugin.ts
|
|
50058
50581
|
import { createHash as createHash10 } from "crypto";
|
|
50059
50582
|
import {
|
|
50060
|
-
constants as
|
|
50061
|
-
closeSync as
|
|
50062
|
-
existsSync as
|
|
50063
|
-
fstatSync as
|
|
50064
|
-
lstatSync as
|
|
50583
|
+
constants as constants7,
|
|
50584
|
+
closeSync as closeSync7,
|
|
50585
|
+
existsSync as existsSync22,
|
|
50586
|
+
fstatSync as fstatSync3,
|
|
50587
|
+
lstatSync as lstatSync7,
|
|
50065
50588
|
mkdirSync as mkdirSync14,
|
|
50066
|
-
openSync as
|
|
50067
|
-
readFileSync as
|
|
50068
|
-
readSync as
|
|
50069
|
-
readdirSync as
|
|
50589
|
+
openSync as openSync7,
|
|
50590
|
+
readFileSync as readFileSync20,
|
|
50591
|
+
readSync as readSync3,
|
|
50592
|
+
readdirSync as readdirSync7,
|
|
50070
50593
|
realpathSync as realpathSync4,
|
|
50071
|
-
rmSync as
|
|
50072
|
-
rmdirSync
|
|
50594
|
+
rmSync as rmSync9,
|
|
50595
|
+
rmdirSync as rmdirSync2
|
|
50073
50596
|
} from "fs";
|
|
50074
50597
|
import { homedir as homedir10 } from "os";
|
|
50075
|
-
import { dirname as
|
|
50598
|
+
import { dirname as dirname16, isAbsolute as isAbsolute8, join as join27, relative as relative2, resolve as resolve7, sep as sep2 } from "path";
|
|
50076
50599
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
50077
|
-
var __dirname4 =
|
|
50600
|
+
var __dirname4 = dirname16(fileURLToPath4(import.meta.url));
|
|
50078
50601
|
var PLUGIN_DESCRIPTION = "Primitive decision-graph guidance for the prim CLI \u2014 a model-invoked skill installed by prim skill install.";
|
|
50079
50602
|
var MAX_MANIFEST_BYTES2 = 64 * 1024;
|
|
50080
50603
|
var MAX_SKILL_BYTES = 1024 * 1024;
|
|
50081
50604
|
function pluginDirFor(cwd, scope) {
|
|
50082
|
-
const base = scope === "user" ?
|
|
50083
|
-
return
|
|
50605
|
+
const base = scope === "user" ? join27(homedir10(), ".claude") : join27(gitToplevel(cwd) ?? cwd, ".claude");
|
|
50606
|
+
return join27(base, "skills", "prim");
|
|
50084
50607
|
}
|
|
50085
50608
|
function resolvePluginDir(cwd, scope) {
|
|
50086
50609
|
if (scope && scope !== "user" && scope !== "project") {
|
|
@@ -50091,10 +50614,10 @@ function resolvePluginDir(cwd, scope) {
|
|
|
50091
50614
|
}
|
|
50092
50615
|
function packageVersion2() {
|
|
50093
50616
|
let dir = __dirname4;
|
|
50094
|
-
while (dir !==
|
|
50617
|
+
while (dir !== dirname16(dir)) {
|
|
50095
50618
|
const p = resolve7(dir, "package.json");
|
|
50096
|
-
if (
|
|
50097
|
-
dir =
|
|
50619
|
+
if (existsSync22(p)) return JSON.parse(readFileSync20(p, "utf-8")).version;
|
|
50620
|
+
dir = dirname16(dir);
|
|
50098
50621
|
}
|
|
50099
50622
|
return "0.0.0";
|
|
50100
50623
|
}
|
|
@@ -50108,12 +50631,12 @@ function renderClaudePlugin() {
|
|
|
50108
50631
|
return { manifest: pluginManifest(version), skill: loadSkill(), version };
|
|
50109
50632
|
}
|
|
50110
50633
|
function removeDirIfEmpty(dir) {
|
|
50111
|
-
if (
|
|
50634
|
+
if (existsSync22(dir) && readdirSync7(dir).length === 0) rmdirSync2(dir);
|
|
50112
50635
|
}
|
|
50113
50636
|
function pluginPaths(dir) {
|
|
50114
50637
|
return {
|
|
50115
|
-
manifestPath:
|
|
50116
|
-
skillPath:
|
|
50638
|
+
manifestPath: join27(dir, ".claude-plugin", "plugin.json"),
|
|
50639
|
+
skillPath: join27(dir, "SKILL.md")
|
|
50117
50640
|
};
|
|
50118
50641
|
}
|
|
50119
50642
|
function installClaudePlugin(cwd, opts) {
|
|
@@ -50121,8 +50644,8 @@ function installClaudePlugin(cwd, opts) {
|
|
|
50121
50644
|
if (dir === null) return 1;
|
|
50122
50645
|
const { manifestPath, skillPath } = pluginPaths(dir);
|
|
50123
50646
|
const { manifest, skill } = renderClaudePlugin();
|
|
50124
|
-
const manifestCurrent =
|
|
50125
|
-
const skillCurrent =
|
|
50647
|
+
const manifestCurrent = existsSync22(manifestPath) ? readFileSync20(manifestPath, "utf-8") : null;
|
|
50648
|
+
const skillCurrent = existsSync22(skillPath) ? readFileSync20(skillPath, "utf-8") : null;
|
|
50126
50649
|
if (manifestCurrent === manifest && skillCurrent === skill) {
|
|
50127
50650
|
console.log("No changes \u2014 prim skill plugin already up to date.");
|
|
50128
50651
|
return 0;
|
|
@@ -50131,7 +50654,7 @@ function installClaudePlugin(cwd, opts) {
|
|
|
50131
50654
|
console.log(`Would write plugin to ${dir} (.claude-plugin/plugin.json + SKILL.md)`);
|
|
50132
50655
|
return 0;
|
|
50133
50656
|
}
|
|
50134
|
-
mkdirSync14(
|
|
50657
|
+
mkdirSync14(join27(dir, ".claude-plugin"), { recursive: true });
|
|
50135
50658
|
atomicWrite4(manifestPath, manifest);
|
|
50136
50659
|
atomicWrite4(skillPath, skill);
|
|
50137
50660
|
console.log(`Installed prim skill plugin at ${dir}`);
|
|
@@ -50145,13 +50668,13 @@ function uninstallClaudePlugin(cwd, opts) {
|
|
|
50145
50668
|
const dir = resolvePluginDir(cwd, opts.scope);
|
|
50146
50669
|
if (dir === null) return 1;
|
|
50147
50670
|
const { manifestPath, skillPath } = pluginPaths(dir);
|
|
50148
|
-
if (!
|
|
50671
|
+
if (!existsSync22(manifestPath) && !existsSync22(skillPath)) {
|
|
50149
50672
|
console.log(`prim skill plugin not present at ${dir}`);
|
|
50150
50673
|
return 0;
|
|
50151
50674
|
}
|
|
50152
|
-
|
|
50153
|
-
|
|
50154
|
-
removeDirIfEmpty(
|
|
50675
|
+
rmSync9(manifestPath, { force: true });
|
|
50676
|
+
rmSync9(skillPath, { force: true });
|
|
50677
|
+
removeDirIfEmpty(join27(dir, ".claude-plugin"));
|
|
50155
50678
|
removeDirIfEmpty(dir);
|
|
50156
50679
|
console.log(`Removed prim skill plugin from ${dir}`);
|
|
50157
50680
|
return 0;
|
|
@@ -50160,7 +50683,7 @@ function statusClaudePlugin(cwd, opts) {
|
|
|
50160
50683
|
const dir = resolvePluginDir(cwd, opts.scope);
|
|
50161
50684
|
if (dir === null) return 1;
|
|
50162
50685
|
const { skillPath } = pluginPaths(dir);
|
|
50163
|
-
const installed =
|
|
50686
|
+
const installed = existsSync22(skillPath);
|
|
50164
50687
|
if (opts.json) {
|
|
50165
50688
|
printJson({ installed, target: dir });
|
|
50166
50689
|
return installed ? 0 : 1;
|
|
@@ -50174,7 +50697,7 @@ function statusClaudePlugin(cwd, opts) {
|
|
|
50174
50697
|
}
|
|
50175
50698
|
|
|
50176
50699
|
// src/commands/skill.ts
|
|
50177
|
-
var __dirname5 =
|
|
50700
|
+
var __dirname5 = dirname17(fileURLToPath5(import.meta.url));
|
|
50178
50701
|
var SKILL_BEGIN = "<!-- BEGIN PRIM SKILL v1 -->";
|
|
50179
50702
|
var SKILL_END = "<!-- END PRIM SKILL v1 -->";
|
|
50180
50703
|
var CODEX_GUIDANCE_LIMIT_BYTES = 1024 * 1024;
|
|
@@ -50202,25 +50725,25 @@ function sha2563(content) {
|
|
|
50202
50725
|
}
|
|
50203
50726
|
function cursorSkillDirectory(cwd, scope) {
|
|
50204
50727
|
const base = scope === "user" ? cursorConfigDirectory() : gitToplevel(cwd) ?? cwd;
|
|
50205
|
-
return
|
|
50728
|
+
return join28(base, scope === "user" ? "skills" : ".cursor/skills", "prim");
|
|
50206
50729
|
}
|
|
50207
50730
|
function cursorSkillPaths(cwd, scope) {
|
|
50208
50731
|
const directory = cursorSkillDirectory(cwd, scope);
|
|
50209
50732
|
return {
|
|
50210
50733
|
directory,
|
|
50211
|
-
skill:
|
|
50212
|
-
manifest:
|
|
50734
|
+
skill: join28(directory, "SKILL.md"),
|
|
50735
|
+
manifest: join28(directory, CURSOR_SKILL_MANIFEST)
|
|
50213
50736
|
};
|
|
50214
50737
|
}
|
|
50215
50738
|
function readCursorSkillManifest(path9) {
|
|
50216
50739
|
try {
|
|
50217
|
-
const value = JSON.parse(
|
|
50740
|
+
const value = JSON.parse(readFileSync21(path9, "utf8"));
|
|
50218
50741
|
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
50219
|
-
const
|
|
50220
|
-
if (
|
|
50742
|
+
const record3 = value;
|
|
50743
|
+
if (record3.version !== 1 || record3.owner !== CURSOR_SKILL_OWNER || typeof record3.contentSha256 !== "string" || !/^[0-9a-f]{64}$/u.test(record3.contentSha256)) {
|
|
50221
50744
|
return;
|
|
50222
50745
|
}
|
|
50223
|
-
return
|
|
50746
|
+
return record3;
|
|
50224
50747
|
} catch {
|
|
50225
50748
|
return;
|
|
50226
50749
|
}
|
|
@@ -50228,7 +50751,7 @@ function readCursorSkillManifest(path9) {
|
|
|
50228
50751
|
function cursorSkillStatus(cwd, scope) {
|
|
50229
50752
|
const paths = cursorSkillPaths(cwd, scope);
|
|
50230
50753
|
const manifest = readCursorSkillManifest(paths.manifest);
|
|
50231
|
-
const content =
|
|
50754
|
+
const content = existsSync23(paths.skill) ? readFileSync21(paths.skill, "utf8") : void 0;
|
|
50232
50755
|
const owned = manifest !== void 0;
|
|
50233
50756
|
const installed = owned && content !== void 0 && sha2563(content) === manifest.contentSha256;
|
|
50234
50757
|
return {
|
|
@@ -50246,8 +50769,8 @@ function validCursorSkillScope(scope) {
|
|
|
50246
50769
|
function installCursorSkill(cwd, opts) {
|
|
50247
50770
|
const paths = cursorSkillPaths(cwd, opts.scope);
|
|
50248
50771
|
const status = cursorSkillStatus(cwd, opts.scope);
|
|
50249
|
-
const manifestExists =
|
|
50250
|
-
const skillExists =
|
|
50772
|
+
const manifestExists = existsSync23(paths.manifest);
|
|
50773
|
+
const skillExists = existsSync23(paths.skill);
|
|
50251
50774
|
if (manifestExists && !status.owned || !manifestExists && skillExists || status.edited) {
|
|
50252
50775
|
console.error(`Refusing to overwrite a foreign or edited Cursor skill at ${paths.skill}`);
|
|
50253
50776
|
return 1;
|
|
@@ -50258,12 +50781,12 @@ function installCursorSkill(cwd, opts) {
|
|
|
50258
50781
|
owner: CURSOR_SKILL_OWNER,
|
|
50259
50782
|
contentSha256: sha2563(content)
|
|
50260
50783
|
};
|
|
50261
|
-
if (status.installed &&
|
|
50784
|
+
if (status.installed && readFileSync21(paths.skill, "utf8") === content) {
|
|
50262
50785
|
console.log(`No changes \u2014 Cursor skill already up to date at ${paths.skill}`);
|
|
50263
50786
|
return 0;
|
|
50264
50787
|
}
|
|
50265
50788
|
if (opts.dryRun) {
|
|
50266
|
-
const existing = skillExists ?
|
|
50789
|
+
const existing = skillExists ? readFileSync21(paths.skill, "utf8") : "";
|
|
50267
50790
|
process.stdout.write(createPatch(paths.skill, existing, content, "current", "proposed"));
|
|
50268
50791
|
return 0;
|
|
50269
50792
|
}
|
|
@@ -50284,34 +50807,34 @@ function uninstallCursorSkill(cwd, scope) {
|
|
|
50284
50807
|
console.error(`Refusing to remove an edited Cursor skill at ${paths.skill}`);
|
|
50285
50808
|
return 1;
|
|
50286
50809
|
}
|
|
50287
|
-
if (
|
|
50288
|
-
if (
|
|
50810
|
+
if (existsSync23(paths.skill)) unlinkSync7(paths.skill);
|
|
50811
|
+
if (existsSync23(paths.manifest)) unlinkSync7(paths.manifest);
|
|
50289
50812
|
try {
|
|
50290
|
-
if (
|
|
50813
|
+
if (readdirSync8(paths.directory).length === 0) rmdirSync3(paths.directory);
|
|
50291
50814
|
} catch {
|
|
50292
50815
|
}
|
|
50293
50816
|
console.log(`Removed Primitive-owned Cursor skill from ${paths.skill}`);
|
|
50294
50817
|
return 0;
|
|
50295
50818
|
}
|
|
50296
50819
|
function userTargetFor(agent) {
|
|
50297
|
-
if (agent === "claude") return
|
|
50298
|
-
if (agent === "codex") return
|
|
50820
|
+
if (agent === "claude") return join28(homedir11(), ".claude", "CLAUDE.md");
|
|
50821
|
+
if (agent === "codex") return join28(homedir11(), ".codex", "AGENTS.md");
|
|
50299
50822
|
if (agent === "hermes") {
|
|
50300
|
-
return
|
|
50823
|
+
return join28(process.env.HERMES_HOME ?? join28(homedir11(), ".hermes"), ".hermes.md");
|
|
50301
50824
|
}
|
|
50302
50825
|
return null;
|
|
50303
50826
|
}
|
|
50304
50827
|
function loadSkill() {
|
|
50305
50828
|
let dir = __dirname5;
|
|
50306
|
-
while (dir !==
|
|
50829
|
+
while (dir !== dirname17(dir)) {
|
|
50307
50830
|
const p = resolve8(dir, "SKILL.md");
|
|
50308
|
-
if (
|
|
50309
|
-
dir =
|
|
50831
|
+
if (existsSync23(p)) return readFileSync21(p, "utf-8");
|
|
50832
|
+
dir = dirname17(dir);
|
|
50310
50833
|
}
|
|
50311
50834
|
throw new Error("SKILL.md not found in package");
|
|
50312
50835
|
}
|
|
50313
50836
|
function detectTargets(cwd) {
|
|
50314
|
-
return TARGET_CANDIDATES.filter((p) =>
|
|
50837
|
+
return TARGET_CANDIDATES.filter((p) => existsSync23(resolve8(cwd, p)));
|
|
50315
50838
|
}
|
|
50316
50839
|
function detectNewline(content) {
|
|
50317
50840
|
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
@@ -50377,7 +50900,7 @@ function runInstall(cwd, opts) {
|
|
|
50377
50900
|
}
|
|
50378
50901
|
const target = resolveTarget(cwd, opts);
|
|
50379
50902
|
if (target === null) return 1;
|
|
50380
|
-
const existing =
|
|
50903
|
+
const existing = existsSync23(target) ? readFileSync21(target, "utf-8") : "";
|
|
50381
50904
|
const eol = existing ? detectNewline(existing) : "\n";
|
|
50382
50905
|
const block = composeBlock(loadSkill(), eol);
|
|
50383
50906
|
const next = applyBlock(existing, block, eol);
|
|
@@ -50401,11 +50924,11 @@ function runUninstall(cwd, opts) {
|
|
|
50401
50924
|
}
|
|
50402
50925
|
const target = resolveTarget(cwd, opts);
|
|
50403
50926
|
if (target === null) return 1;
|
|
50404
|
-
if (!
|
|
50927
|
+
if (!existsSync23(target)) {
|
|
50405
50928
|
console.log(`Skill block not present at ${target}`);
|
|
50406
50929
|
return 0;
|
|
50407
50930
|
}
|
|
50408
|
-
const existing =
|
|
50931
|
+
const existing = readFileSync21(target, "utf-8");
|
|
50409
50932
|
const next = removeBlock(existing);
|
|
50410
50933
|
if (next === null) {
|
|
50411
50934
|
console.log(`Skill block not present at ${target}`);
|
|
@@ -50429,10 +50952,10 @@ function runStatus(cwd, opts) {
|
|
|
50429
50952
|
}
|
|
50430
50953
|
const target = resolveTarget(cwd, opts);
|
|
50431
50954
|
if (target === null) return 1;
|
|
50432
|
-
const fileExists =
|
|
50955
|
+
const fileExists = existsSync23(target);
|
|
50433
50956
|
let installed = false;
|
|
50434
50957
|
if (fileExists) {
|
|
50435
|
-
const content =
|
|
50958
|
+
const content = readFileSync21(target, "utf-8");
|
|
50436
50959
|
installed = content.includes(SKILL_BEGIN) && content.includes(SKILL_END);
|
|
50437
50960
|
}
|
|
50438
50961
|
if (opts.json) {
|
|
@@ -50469,13 +50992,13 @@ function registerSkillCommands(program3) {
|
|
|
50469
50992
|
}
|
|
50470
50993
|
|
|
50471
50994
|
// src/commands/statusline.ts
|
|
50472
|
-
import { readFileSync as
|
|
50473
|
-
import { dirname as
|
|
50995
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
50996
|
+
import { dirname as dirname18, resolve as resolve9 } from "path";
|
|
50474
50997
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
50475
50998
|
var STATUSLINE_TIMEOUT_MS = 200;
|
|
50476
50999
|
function readPackageVersion() {
|
|
50477
51000
|
try {
|
|
50478
|
-
const here =
|
|
51001
|
+
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
50479
51002
|
const candidates = [
|
|
50480
51003
|
// Schema-v2 runtimes staged a manifest beside this standalone bundle.
|
|
50481
51004
|
// Keep resolving it while those legacy launchers transition to schema v3.
|
|
@@ -50485,7 +51008,7 @@ function readPackageVersion() {
|
|
|
50485
51008
|
];
|
|
50486
51009
|
for (const path9 of candidates) {
|
|
50487
51010
|
try {
|
|
50488
|
-
const pkg2 = JSON.parse(
|
|
51011
|
+
const pkg2 = JSON.parse(readFileSync22(path9, "utf-8"));
|
|
50489
51012
|
if (pkg2.version) {
|
|
50490
51013
|
return pkg2.version;
|
|
50491
51014
|
}
|
|
@@ -50899,28 +51422,272 @@ function registerWelcomeCommand(program3, deps = { getClient }) {
|
|
|
50899
51422
|
});
|
|
50900
51423
|
}
|
|
50901
51424
|
|
|
51425
|
+
// src/daemon/self-heal.ts
|
|
51426
|
+
import { spawn as spawn4 } from "child_process";
|
|
51427
|
+
|
|
51428
|
+
// src/lib/unattended.ts
|
|
51429
|
+
var UNATTENDED_ENV = "PRIM_UNATTENDED";
|
|
51430
|
+
function unattendedEnv(env4 = process.env) {
|
|
51431
|
+
return { ...env4, [UNATTENDED_ENV]: "1" };
|
|
51432
|
+
}
|
|
51433
|
+
function isUnattended(env4 = process.env) {
|
|
51434
|
+
return env4[UNATTENDED_ENV] === "1";
|
|
51435
|
+
}
|
|
51436
|
+
|
|
51437
|
+
// src/daemon/self-heal.ts
|
|
51438
|
+
function kickDaemonEnsure(options = {}) {
|
|
51439
|
+
const primEntry = options.primEntry === void 0 ? binFile("prim") : options.primEntry;
|
|
51440
|
+
if (!primEntry) {
|
|
51441
|
+
return false;
|
|
51442
|
+
}
|
|
51443
|
+
try {
|
|
51444
|
+
const args = [primEntry, "daemon", "ensure"];
|
|
51445
|
+
if (options.latestBootstrap ?? (options.platform ?? process.platform) === "darwin") {
|
|
51446
|
+
args.push("--latest-bootstrap");
|
|
51447
|
+
}
|
|
51448
|
+
const child = (options.spawnProcess ?? spawn4)(
|
|
51449
|
+
options.nodeEntry ?? process.execPath,
|
|
51450
|
+
args,
|
|
51451
|
+
// Unattended: neither SessionStart's repair nor a drift heal is a person
|
|
51452
|
+
// running prim, so the child (and its descendants) never heal in turn.
|
|
51453
|
+
{ detached: true, stdio: "ignore", env: unattendedEnv() }
|
|
51454
|
+
);
|
|
51455
|
+
child.once("error", () => {
|
|
51456
|
+
});
|
|
51457
|
+
child.unref();
|
|
51458
|
+
return true;
|
|
51459
|
+
} catch {
|
|
51460
|
+
return false;
|
|
51461
|
+
}
|
|
51462
|
+
}
|
|
51463
|
+
|
|
51464
|
+
// src/daemon/drift-heal.ts
|
|
51465
|
+
var ATTEMPT_MARKER_MODE = 384;
|
|
51466
|
+
var ATTEMPT_MARKER_MAX_BYTES = 1024;
|
|
51467
|
+
var PATH_SEPARATORS = /[\\/]/u;
|
|
51468
|
+
var DAEMON_DRIFT_HEAL_ENV = "PRIM_DAEMON_DRIFT_HEAL";
|
|
51469
|
+
var DAEMON_DRIFT_HEAL_RETRY_MS = 60 * 60 * 1e3;
|
|
51470
|
+
function readAttempt(path9) {
|
|
51471
|
+
const file = readBoundedRegularFile(path9, ATTEMPT_MARKER_MAX_BYTES);
|
|
51472
|
+
if (!file) return null;
|
|
51473
|
+
try {
|
|
51474
|
+
const value = JSON.parse(file.text);
|
|
51475
|
+
if (typeof value !== "object" || value === null) return null;
|
|
51476
|
+
const attempt = value;
|
|
51477
|
+
return typeof attempt.attemptedAt === "number" && Number.isFinite(attempt.attemptedAt) && typeof attempt.fromVersion === "string" && typeof attempt.toVersion === "string" ? attempt : null;
|
|
51478
|
+
} catch {
|
|
51479
|
+
return null;
|
|
51480
|
+
}
|
|
51481
|
+
}
|
|
51482
|
+
function claimHeld() {
|
|
51483
|
+
throw new Error("another command holds the daemon drift-heal claim");
|
|
51484
|
+
}
|
|
51485
|
+
function claimAttempt(markerPath2, attempt) {
|
|
51486
|
+
const previous = readAttempt(markerPath2);
|
|
51487
|
+
const elapsed = previous ? attempt.attemptedAt - previous.attemptedAt : Number.POSITIVE_INFINITY;
|
|
51488
|
+
if (elapsed >= 0 && elapsed < DAEMON_DRIFT_HEAL_RETRY_MS) return false;
|
|
51489
|
+
atomicWriteFile(markerPath2, `${JSON.stringify(attempt)}
|
|
51490
|
+
`, { mode: ATTEMPT_MARKER_MODE });
|
|
51491
|
+
return true;
|
|
51492
|
+
}
|
|
51493
|
+
function isInstalledPackage(root) {
|
|
51494
|
+
return root?.split(PATH_SEPARATORS).includes("node_modules") === true;
|
|
51495
|
+
}
|
|
51496
|
+
function needsHeal(launcher, toVersion) {
|
|
51497
|
+
const order = compareSemver(launcher.runtimeVersion, toVersion);
|
|
51498
|
+
return order === -1 || order === 0 && !launcher.runnable;
|
|
51499
|
+
}
|
|
51500
|
+
function startDriftHeal(options) {
|
|
51501
|
+
if ((options.platform ?? process.platform) !== "darwin") return false;
|
|
51502
|
+
const env4 = options.env ?? process.env;
|
|
51503
|
+
if (env4[DAEMON_DRIFT_HEAL_ENV] === "0") return false;
|
|
51504
|
+
const root = options.packageRoot === void 0 ? packageRoot() : options.packageRoot;
|
|
51505
|
+
if (!isInstalledPackage(root)) return false;
|
|
51506
|
+
const euid = options.euid ?? process.geteuid?.();
|
|
51507
|
+
if (euid === void 0 || euid === 0) return false;
|
|
51508
|
+
const paths = { env: env4, homeDir: options.homeDir };
|
|
51509
|
+
if (daemonExplicitlyDisabled(paths)) return false;
|
|
51510
|
+
const launcher = (options.selectedLauncher ?? (() => selectedDaemonLauncher(paths)))();
|
|
51511
|
+
if (!launcher || launcher.ownerUid !== euid) return false;
|
|
51512
|
+
const toVersion = options.cliVersion === void 0 ? packageVersion() : options.cliVersion;
|
|
51513
|
+
if (!(toVersion && needsHeal(launcher, toVersion))) return false;
|
|
51514
|
+
if (!apiUrlsMatch(
|
|
51515
|
+
getSiteUrlForEnvironment(launcher.apiUrl),
|
|
51516
|
+
getSiteUrlForEnvironment(env4.PRIM_API_URL)
|
|
51517
|
+
)) {
|
|
51518
|
+
return false;
|
|
51519
|
+
}
|
|
51520
|
+
const runsConfigRoot = options.launchAgentRunsConfigRoot ?? (() => launchAgentRunsConfigRoot(paths));
|
|
51521
|
+
if (!runsConfigRoot()) return false;
|
|
51522
|
+
const primEntry = options.primEntry === void 0 ? binFile("prim") : options.primEntry;
|
|
51523
|
+
if (!primEntry) return false;
|
|
51524
|
+
const attempt = {
|
|
51525
|
+
attemptedAt: (options.nowMs ?? Date.now)(),
|
|
51526
|
+
fromVersion: launcher.runtimeVersion,
|
|
51527
|
+
toVersion
|
|
51528
|
+
};
|
|
51529
|
+
const claimed = withFileLockSync(
|
|
51530
|
+
daemonDriftHealClaimPath(paths),
|
|
51531
|
+
() => claimAttempt(daemonDriftHealMarkerPath(paths), attempt),
|
|
51532
|
+
{ timeoutMs: 0, sleep: claimHeld }
|
|
51533
|
+
);
|
|
51534
|
+
if (!claimed) return false;
|
|
51535
|
+
return kickDaemonEnsure({
|
|
51536
|
+
primEntry,
|
|
51537
|
+
nodeEntry: options.nodeEntry,
|
|
51538
|
+
spawnProcess: options.spawnProcess,
|
|
51539
|
+
latestBootstrap: false
|
|
51540
|
+
});
|
|
51541
|
+
}
|
|
51542
|
+
function healDaemonDrift(options = {}) {
|
|
51543
|
+
try {
|
|
51544
|
+
return startDriftHeal(options);
|
|
51545
|
+
} catch {
|
|
51546
|
+
return false;
|
|
51547
|
+
}
|
|
51548
|
+
}
|
|
51549
|
+
|
|
51550
|
+
// src/lib/background-flush.ts
|
|
51551
|
+
import { spawn as spawn5 } from "child_process";
|
|
51552
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
51553
|
+
|
|
51554
|
+
// src/daemon/health.ts
|
|
51555
|
+
import { chmodSync as chmodSync7, existsSync as existsSync24, mkdirSync as mkdirSync15, renameSync as renameSync7, writeFileSync as writeFileSync11 } from "fs";
|
|
51556
|
+
import { dirname as dirname19, join as join29 } from "path";
|
|
51557
|
+
var HEARTBEAT_FRESH_MS = 9e4;
|
|
51558
|
+
var DAEMON_HEALTH_PATH = join29(primConfigDirectory(), "daemon-health.json");
|
|
51559
|
+
|
|
51560
|
+
// src/lib/background-flush.ts
|
|
51561
|
+
function record2(value) {
|
|
51562
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
51563
|
+
}
|
|
51564
|
+
function daemonOwnsDrain(options = {}) {
|
|
51565
|
+
try {
|
|
51566
|
+
const expectedVersion = options.expectedVersion === void 0 ? packageVersion() : options.expectedVersion;
|
|
51567
|
+
if (!expectedVersion) return false;
|
|
51568
|
+
const health = record2(
|
|
51569
|
+
JSON.parse(readFileSync23(options.healthPath ?? DAEMON_HEALTH_PATH, "utf8"))
|
|
51570
|
+
);
|
|
51571
|
+
const heartbeat = record2(health?.heartbeat);
|
|
51572
|
+
const ingestion = record2(health?.ingestion);
|
|
51573
|
+
if (!(health && heartbeat && ingestion)) return false;
|
|
51574
|
+
if (health.schemaVersion !== 1 || health.version !== expectedVersion) return false;
|
|
51575
|
+
const daemonSiteUrl = health.siteUrl;
|
|
51576
|
+
if (typeof daemonSiteUrl !== "string" || envSlug(daemonSiteUrl) !== envSlug(options.siteUrl ?? getSiteUrl())) {
|
|
51577
|
+
return false;
|
|
51578
|
+
}
|
|
51579
|
+
if (health.needsReauth === true) return false;
|
|
51580
|
+
const pid = health.pid;
|
|
51581
|
+
if (typeof pid !== "number" || !(options.isAlive ?? processIsAlive)(pid)) return false;
|
|
51582
|
+
const lastSuccessAt = heartbeat.lastSuccessAt;
|
|
51583
|
+
const now = options.now ?? Date.now();
|
|
51584
|
+
return heartbeat.consecutiveFailures === 0 && typeof lastSuccessAt === "number" && lastSuccessAt <= now && now - lastSuccessAt < HEARTBEAT_FRESH_MS && ingestion.consecutiveFailures === 0;
|
|
51585
|
+
} catch {
|
|
51586
|
+
return false;
|
|
51587
|
+
}
|
|
51588
|
+
}
|
|
51589
|
+
function startBackgroundFlush(options = {}) {
|
|
51590
|
+
try {
|
|
51591
|
+
if ((options.daemonOwnsDrain ?? daemonOwnsDrain)()) return false;
|
|
51592
|
+
if (!(options.needsFlush ?? journalNeedsFlush)()) return false;
|
|
51593
|
+
const primEntry = options.primEntry === void 0 ? binFile("prim") : options.primEntry;
|
|
51594
|
+
if (!primEntry) return false;
|
|
51595
|
+
const child = (options.spawnProcess ?? spawn5)(
|
|
51596
|
+
options.nodeEntry ?? process.execPath,
|
|
51597
|
+
[primEntry, "moves", "flush"],
|
|
51598
|
+
// Ignored stdio matters as much as detaching: a child holding inherited
|
|
51599
|
+
// pipes would keep a caller that captures them (spawnSync) waiting.
|
|
51600
|
+
// windowsHide keeps the detached child from opening a console window.
|
|
51601
|
+
// The child is unattended even when its parent is not: `doctor` or
|
|
51602
|
+
// `statusline` must not reach the daemon drift heal through its drain.
|
|
51603
|
+
{ detached: true, stdio: "ignore", windowsHide: true, env: unattendedEnv() }
|
|
51604
|
+
);
|
|
51605
|
+
child.once("error", () => {
|
|
51606
|
+
});
|
|
51607
|
+
child.unref();
|
|
51608
|
+
return true;
|
|
51609
|
+
} catch {
|
|
51610
|
+
return false;
|
|
51611
|
+
}
|
|
51612
|
+
}
|
|
51613
|
+
|
|
50902
51614
|
// src/lib/startup-background.ts
|
|
50903
51615
|
var ROOT_OPTIONS = /* @__PURE__ */ new Set(["-y", "--yes", "--non-interactive"]);
|
|
51616
|
+
var HELP_OPTIONS = /* @__PURE__ */ new Set(["-h", "--help"]);
|
|
51617
|
+
var DAEMON_HEAL_COMMANDS = /* @__PURE__ */ new Map([
|
|
51618
|
+
// Credentials; `auth login` is how a person returns to a daemon held for re-auth.
|
|
51619
|
+
["auth", /* @__PURE__ */ new Set(["api-keys", "login", "set-token", "status"])],
|
|
51620
|
+
// Reading and curating the decision graph: the everyday attended surface.
|
|
51621
|
+
[
|
|
51622
|
+
"decisions",
|
|
51623
|
+
/* @__PURE__ */ new Set([
|
|
51624
|
+
"cascade",
|
|
51625
|
+
"check",
|
|
51626
|
+
"confirm",
|
|
51627
|
+
"create",
|
|
51628
|
+
"demote",
|
|
51629
|
+
"link",
|
|
51630
|
+
"promote",
|
|
51631
|
+
"publish",
|
|
51632
|
+
"ratify",
|
|
51633
|
+
"recent",
|
|
51634
|
+
"repairs",
|
|
51635
|
+
"rescope",
|
|
51636
|
+
"restore",
|
|
51637
|
+
"show",
|
|
51638
|
+
"supersede",
|
|
51639
|
+
"unlink",
|
|
51640
|
+
"withdraw"
|
|
51641
|
+
])
|
|
51642
|
+
],
|
|
51643
|
+
["reconcile", "any"],
|
|
51644
|
+
// Repository connection, activation, and journal plumbing a person steers.
|
|
51645
|
+
// Hook-side `moves flush` drains are unattended and never reach this table.
|
|
51646
|
+
["github", /* @__PURE__ */ new Set(["connect"])],
|
|
51647
|
+
["enable", "any"],
|
|
51648
|
+
["moves", /* @__PURE__ */ new Set(["bind", "drop", "flush", "status", "tail"])],
|
|
51649
|
+
["session", /* @__PURE__ */ new Set(["drop", "list", "start"])],
|
|
51650
|
+
// Installing or inspecting an integration, never removing one.
|
|
51651
|
+
["claude", /* @__PURE__ */ new Set(["install", "preauth", "status"])],
|
|
51652
|
+
["codex", /* @__PURE__ */ new Set(["install", "status"])],
|
|
51653
|
+
["cursor", /* @__PURE__ */ new Set(["install", "status"])],
|
|
51654
|
+
["hermes", /* @__PURE__ */ new Set(["install", "status"])],
|
|
51655
|
+
["hooks", /* @__PURE__ */ new Set(["install"])],
|
|
51656
|
+
["skill", /* @__PURE__ */ new Set(["install", "status"])],
|
|
51657
|
+
["welcome", "any"]
|
|
51658
|
+
]);
|
|
50904
51659
|
function commandArguments(argv) {
|
|
50905
51660
|
let index = 0;
|
|
50906
51661
|
while (ROOT_OPTIONS.has(argv[index] ?? "")) index += 1;
|
|
50907
51662
|
return argv.slice(index);
|
|
50908
51663
|
}
|
|
51664
|
+
function mayHealDaemon(argv, env4) {
|
|
51665
|
+
if (isUnattended(env4) || env4[SETUP_ORCHESTRATOR_ENV] === "1") return false;
|
|
51666
|
+
const args = commandArguments(argv);
|
|
51667
|
+
if (args.some((arg) => HELP_OPTIONS.has(arg))) return false;
|
|
51668
|
+
const [command, subcommand] = args;
|
|
51669
|
+
const allowed = command === void 0 ? void 0 : DAEMON_HEAL_COMMANDS.get(command);
|
|
51670
|
+
if (allowed === void 0) return false;
|
|
51671
|
+
return allowed === "any" || subcommand !== void 0 && allowed.has(subcommand);
|
|
51672
|
+
}
|
|
50909
51673
|
function runStartupBackgroundWork(argv, env4, work) {
|
|
50910
|
-
const
|
|
51674
|
+
const args = commandArguments(argv);
|
|
51675
|
+
const [command, subcommand] = args;
|
|
50911
51676
|
const uninstall = command === "uninstall" || env4[UNINSTALL_ORCHESTRATOR_ENV] === "1";
|
|
50912
51677
|
if (uninstall) return;
|
|
50913
51678
|
work.notify();
|
|
50914
|
-
|
|
50915
|
-
|
|
51679
|
+
const setupDaemonDrains = command === "setup" && !args.includes("--no-daemon") || env4[SETUP_DAEMON_DRAINS_ENV] === "1";
|
|
51680
|
+
if (!setupDaemonDrains && (command !== "moves" || subcommand !== "flush")) work.flush();
|
|
51681
|
+
if (mayHealDaemon(argv, env4)) work.healDaemon();
|
|
50916
51682
|
}
|
|
50917
51683
|
|
|
50918
51684
|
// src/index.ts
|
|
50919
|
-
var __dirname6 =
|
|
50920
|
-
var pkg = JSON.parse(
|
|
51685
|
+
var __dirname6 = dirname20(fileURLToPath7(import.meta.url));
|
|
51686
|
+
var pkg = JSON.parse(readFileSync24(resolve10(__dirname6, "../package.json"), "utf-8"));
|
|
50921
51687
|
runStartupBackgroundWork(process.argv.slice(2), process.env, {
|
|
50922
51688
|
notify: () => updateNotifier({ pkg }).notify(),
|
|
50923
|
-
flush: () =>
|
|
51689
|
+
flush: () => startBackgroundFlush(),
|
|
51690
|
+
healDaemon: () => healDaemonDrift()
|
|
50924
51691
|
});
|
|
50925
51692
|
var program2 = new Command();
|
|
50926
51693
|
program2.name("prim").description("CLI for Primitive's decision graph").version(pkg.version).option("-y, --yes", "auto-confirm prompts").option(
|