@darkhunt-security/endpoint-codex 0.9.15 → 0.9.17
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/.codex-plugin/plugin.json +1 -1
- package/commands/backfill.md +55 -1
- package/dist/bin/backfill.mjs +142 -14
- package/dist/bin/enroll.mjs +5 -1
- package/dist/bin/forwarder.mjs +12 -7
- package/dist/bin/guard.mjs +4 -1
- package/dist/bin/init.mjs +5 -1
- package/dist/bin/spool.mjs +4 -1
- package/dist/bin/status.mjs +11 -3
- package/package.json +1 -1
package/commands/backfill.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Import Codex CLI sessions that happened before this machine was connected
|
|
3
|
-
argument-hint: '[--days=N, transcript paths, or nothing for everything on disk]'
|
|
3
|
+
argument-hint: '[--days=N, --reset, transcript paths, or nothing for everything on disk]'
|
|
4
4
|
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/dist/bin/backfill.mjs:*), Bash(${CLAUDE_PLUGIN_ROOT}/dist/bin/status.mjs:*)
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -64,6 +64,60 @@ cannot be taken back and looks exactly like a correct one afterwards.
|
|
|
64
64
|
a failed pass holds every checkpoint, so the identical command re-ships the same
|
|
65
65
|
byte range once the cause is fixed.
|
|
66
66
|
|
|
67
|
+
## When it ships nothing
|
|
68
|
+
|
|
69
|
+
`0 record(s) from 0 transcript(s)` with exit 0 has two very different causes, and they
|
|
70
|
+
read identically:
|
|
71
|
+
|
|
72
|
+
- **Already imported.** The normal case. Re-running a backfill is a no-op by design.
|
|
73
|
+
- **Re-enrolled, and the history went to the old application.** A checkpoint records how
|
|
74
|
+
far a transcript has been shipped — never _where_ it was shipped to. After pointing
|
|
75
|
+
this machine at a different tenant, workspace or application, every transcript is
|
|
76
|
+
still marked done, so a backfill correctly finds nothing to send and the new
|
|
77
|
+
application stays empty.
|
|
78
|
+
|
|
79
|
+
The status block above tells you which one you are in: if it names an application the
|
|
80
|
+
sessions were never shipped to, it is the second.
|
|
81
|
+
|
|
82
|
+
`--reset` is the lever for that case. It forgets the offsets for the transcripts you
|
|
83
|
+
selected — the same selection `--days` and paths make — and ships them again from the
|
|
84
|
+
start:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
${CLAUDE_PLUGIN_ROOT}/dist/bin/backfill.mjs --reset --days=7
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Before running it:
|
|
91
|
+
|
|
92
|
+
- **Confirm the destination again.** This is the full send that the first backfill was
|
|
93
|
+
not, and it is one-way.
|
|
94
|
+
- **Say how big it is.** `--dry-run` (without `--reset`; the two are refused together)
|
|
95
|
+
maps the same selection and prints the record count. That count is what `--reset` will
|
|
96
|
+
actually ship — without `--reset` it is only the size of the window, not the size of
|
|
97
|
+
the shipment.
|
|
98
|
+
- **Do not offer it as a fix for a failed run.** A failed pass already holds its
|
|
99
|
+
checkpoints; re-running the plain command re-ships that byte range. `--reset` is for a
|
|
100
|
+
run that succeeded and sent nothing.
|
|
101
|
+
|
|
102
|
+
It writes the old offsets to a `.bak-<timestamp>-prereset` file beside the checkpoints
|
|
103
|
+
and prints the path. Records already in the old application stay there — this adds a
|
|
104
|
+
copy in the new one, it does not move anything.
|
|
105
|
+
|
|
106
|
+
## When the machine has not opted in
|
|
107
|
+
|
|
108
|
+
**The retroactive import is off by default.** Most machines are in this state, so expect
|
|
109
|
+
it rather than treating it as a fault.
|
|
110
|
+
|
|
111
|
+
Exit **4**, with `BACKFILL DISABLED` on stderr, means the config has no
|
|
112
|
+
`"capture": { "backfill": true }`. Nothing was sent and no checkpoint was cleared — a
|
|
113
|
+
refused `--reset` has not moved the machine either, so there is nothing to undo and
|
|
114
|
+
nothing to retry.
|
|
115
|
+
|
|
116
|
+
Tell them plainly what it is: the import is opt-in, and this machine has not opted in.
|
|
117
|
+
Do not edit the config yourself to get around it — send them to `/darkhunt-guard:setup`.
|
|
118
|
+
`--dry-run` still works while it is off, so you can still show them exactly what enabling
|
|
119
|
+
it would send, which is the more useful thing to offer anyway.
|
|
120
|
+
|
|
67
121
|
## Also
|
|
68
122
|
|
|
69
123
|
- Narrow it by passing paths — one session, or a date range — rather than adding flags
|
package/dist/bin/backfill.mjs
CHANGED
|
@@ -18160,6 +18160,23 @@ function settingsFor(file, vendor) {
|
|
|
18160
18160
|
...file.enforce ?? override.enforce ? { enforce: { ...file.enforce, ...override.enforce } } : {}
|
|
18161
18161
|
};
|
|
18162
18162
|
}
|
|
18163
|
+
function loadRuntimeSettings(vendor, options = {}) {
|
|
18164
|
+
const vendorFile = readConfigFile(vendor);
|
|
18165
|
+
const profile = resolveProfile(options.profile, vendorFile.profile);
|
|
18166
|
+
return {
|
|
18167
|
+
profile,
|
|
18168
|
+
scope: scopeKey(vendor, profile),
|
|
18169
|
+
enabled: vendorFile.enabled ?? true,
|
|
18170
|
+
capture: resolveCapture(vendorFile.capture),
|
|
18171
|
+
enforce: {
|
|
18172
|
+
mode: vendorFile.enforce?.mode ?? "off",
|
|
18173
|
+
failClosed: vendorFile.enforce?.failClosed ?? true
|
|
18174
|
+
}
|
|
18175
|
+
};
|
|
18176
|
+
}
|
|
18177
|
+
function resolveCapture(capture) {
|
|
18178
|
+
return { enabled: capture?.enabled ?? true, backfill: capture?.backfill ?? false };
|
|
18179
|
+
}
|
|
18163
18180
|
function readConfigFile(vendor) {
|
|
18164
18181
|
if (!existsSync(configPath())) {
|
|
18165
18182
|
throw new ConfigMissingError(`${configPath()} does not exist \u2014 run init.mjs to create it`);
|
|
@@ -18212,7 +18229,7 @@ function loadLocalConfig(vendor, options = {}) {
|
|
|
18212
18229
|
applicationId,
|
|
18213
18230
|
...(creds.userId ?? vendorFile.userId) !== void 0 ? { userId: creds.userId ?? vendorFile.userId } : {},
|
|
18214
18231
|
enabled: vendorFile.enabled ?? true,
|
|
18215
|
-
capture:
|
|
18232
|
+
capture: resolveCapture(vendorFile.capture),
|
|
18216
18233
|
enforce: {
|
|
18217
18234
|
mode: vendorFile.enforce?.mode ?? "off",
|
|
18218
18235
|
failClosed: vendorFile.enforce?.failClosed ?? true
|
|
@@ -18754,8 +18771,9 @@ function installSeededIdGenerator(client) {
|
|
|
18754
18771
|
}
|
|
18755
18772
|
|
|
18756
18773
|
// packages/core/dist/forwarder/checkpoint.js
|
|
18757
|
-
import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
18774
|
+
import { copyFileSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
18758
18775
|
import { join as join6 } from "node:path";
|
|
18776
|
+
var SPOOL_KEY = "::spool::";
|
|
18759
18777
|
function checkpointPath(scope) {
|
|
18760
18778
|
return join6(CONFIG_DIR, `${scope}.checkpoints.json`);
|
|
18761
18779
|
}
|
|
@@ -18800,6 +18818,26 @@ function resumeTurn(checkpoints, path, from) {
|
|
|
18800
18818
|
return void 0;
|
|
18801
18819
|
return checkpoints[path]?.turn;
|
|
18802
18820
|
}
|
|
18821
|
+
function clearCheckpoints(scope, paths) {
|
|
18822
|
+
const checkpoints = loadCheckpoints(scope);
|
|
18823
|
+
const wanted = paths === void 0 ? void 0 : new Set(paths);
|
|
18824
|
+
const transcripts = Object.keys(checkpoints).filter((key) => key !== SPOOL_KEY);
|
|
18825
|
+
const cleared = transcripts.filter((key) => wanted === void 0 || wanted.has(key));
|
|
18826
|
+
const total = transcripts.length;
|
|
18827
|
+
if (cleared.length === 0)
|
|
18828
|
+
return { cleared, total };
|
|
18829
|
+
const backup = `${checkpointPath(scope)}.bak-${stamp(/* @__PURE__ */ new Date())}-prereset`;
|
|
18830
|
+
copyFileSync(checkpointPath(scope), backup);
|
|
18831
|
+
const kept = { ...checkpoints };
|
|
18832
|
+
for (const key of cleared)
|
|
18833
|
+
delete kept[key];
|
|
18834
|
+
saveCheckpoints(scope, kept);
|
|
18835
|
+
return { cleared, total, backup };
|
|
18836
|
+
}
|
|
18837
|
+
function stamp(at) {
|
|
18838
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
18839
|
+
return `${at.getFullYear()}${pad(at.getMonth() + 1)}${pad(at.getDate())}-${pad(at.getHours())}${pad(at.getMinutes())}${pad(at.getSeconds())}`;
|
|
18840
|
+
}
|
|
18803
18841
|
|
|
18804
18842
|
// packages/core/dist/forwarder/tail.js
|
|
18805
18843
|
import { closeSync, openSync, readSync, statSync as statSync3 } from "node:fs";
|
|
@@ -18872,12 +18910,14 @@ function acquireLock(scope) {
|
|
|
18872
18910
|
}
|
|
18873
18911
|
return () => rmSync(path, { force: true });
|
|
18874
18912
|
}
|
|
18875
|
-
function isAlive(pid) {
|
|
18913
|
+
function isAlive(pid, kill = (p, s) => {
|
|
18914
|
+
process.kill(p, s);
|
|
18915
|
+
}) {
|
|
18876
18916
|
try {
|
|
18877
|
-
|
|
18917
|
+
kill(pid, 0);
|
|
18878
18918
|
return true;
|
|
18879
|
-
} catch {
|
|
18880
|
-
return
|
|
18919
|
+
} catch (err) {
|
|
18920
|
+
return err.code !== "ESRCH";
|
|
18881
18921
|
}
|
|
18882
18922
|
}
|
|
18883
18923
|
var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
|
|
@@ -21692,7 +21732,6 @@ function toFloat(value, fallback) {
|
|
|
21692
21732
|
}
|
|
21693
21733
|
|
|
21694
21734
|
// packages/core/dist/forwarder/run.js
|
|
21695
|
-
var SPOOL_KEY = "::spool::";
|
|
21696
21735
|
var DARKHUNT_SOURCE_HINT = "darkhunt-telemetry";
|
|
21697
21736
|
function drainSpool(mapper, checkpoints) {
|
|
21698
21737
|
const path = spoolPath(mapper.vendor);
|
|
@@ -21982,7 +22021,10 @@ import { join as join9 } from "node:path";
|
|
|
21982
22021
|
var CLI_CREDENTIALS_PATH = join9(homedir3(), ".darkhunt", "credentials.json");
|
|
21983
22022
|
|
|
21984
22023
|
// packages/core/dist/cli/backfill.js
|
|
21985
|
-
var BOOLEAN_FLAGS = /* @__PURE__ */ new
|
|
22024
|
+
var BOOLEAN_FLAGS = /* @__PURE__ */ new Map([
|
|
22025
|
+
["dry-run", "dryRun"],
|
|
22026
|
+
["reset", "reset"]
|
|
22027
|
+
]);
|
|
21986
22028
|
var VALUE_FLAGS = /* @__PURE__ */ new Set(["profile", "credentials", "days", "batch"]);
|
|
21987
22029
|
var DEFAULT_BATCH = 25;
|
|
21988
22030
|
function usage(command) {
|
|
@@ -21990,6 +22032,8 @@ function usage(command) {
|
|
|
21990
22032
|
`usage: ${command} [options] [paths...]`,
|
|
21991
22033
|
"",
|
|
21992
22034
|
" --dry-run map only: no network, no checkpoints",
|
|
22035
|
+
" --reset re-send: forget how far the selected transcripts have",
|
|
22036
|
+
" been shipped, then ship them from the start again",
|
|
21993
22037
|
" --days=N only transcripts written to in the last N days",
|
|
21994
22038
|
" --batch=N transcripts per pass (default " + String(DEFAULT_BATCH) + ")",
|
|
21995
22039
|
" --profile=NAME endpoint profile to ship to",
|
|
@@ -21997,13 +22041,22 @@ function usage(command) {
|
|
|
21997
22041
|
" -h, --help this message",
|
|
21998
22042
|
"",
|
|
21999
22043
|
" With no paths this ships EVERY transcript on disk. Narrow it with --days",
|
|
22000
|
-
" or by naming transcripts, and confirm the destination with --dry-run first."
|
|
22044
|
+
" or by naming transcripts, and confirm the destination with --dry-run first.",
|
|
22045
|
+
"",
|
|
22046
|
+
" A checkpoint records how far a transcript has been shipped, never where it was",
|
|
22047
|
+
" shipped to. After re-enrolling against a different application, a plain backfill",
|
|
22048
|
+
" finds nothing to send and exits 0; --reset is what re-sends it.",
|
|
22049
|
+
"",
|
|
22050
|
+
" This command is refused, exit 4, when the config sets",
|
|
22051
|
+
' "capture": { "backfill": false }',
|
|
22052
|
+
" which stops retroactive imports on this machine and leaves live capture running.",
|
|
22053
|
+
" --dry-run still works while it is off."
|
|
22001
22054
|
].join("\n");
|
|
22002
22055
|
}
|
|
22003
22056
|
function parseBackfillArgs(argv) {
|
|
22004
22057
|
const paths = [];
|
|
22005
22058
|
const values = /* @__PURE__ */ new Map();
|
|
22006
|
-
|
|
22059
|
+
const booleans = { dryRun: false, reset: false };
|
|
22007
22060
|
for (const arg of argv) {
|
|
22008
22061
|
if (arg === "-h" || arg === "--help")
|
|
22009
22062
|
return { kind: "help" };
|
|
@@ -22014,10 +22067,11 @@ function parseBackfillArgs(argv) {
|
|
|
22014
22067
|
const body = arg.slice(2);
|
|
22015
22068
|
const eq = body.indexOf("=");
|
|
22016
22069
|
const name = eq === -1 ? body : body.slice(0, eq);
|
|
22017
|
-
|
|
22070
|
+
const boolean = BOOLEAN_FLAGS.get(name);
|
|
22071
|
+
if (boolean !== void 0) {
|
|
22018
22072
|
if (eq !== -1)
|
|
22019
22073
|
return { kind: "error", message: `--${name} takes no value` };
|
|
22020
|
-
|
|
22074
|
+
booleans[boolean] = true;
|
|
22021
22075
|
continue;
|
|
22022
22076
|
}
|
|
22023
22077
|
if (VALUE_FLAGS.has(name)) {
|
|
@@ -22028,7 +22082,7 @@ function parseBackfillArgs(argv) {
|
|
|
22028
22082
|
}
|
|
22029
22083
|
return {
|
|
22030
22084
|
kind: "error",
|
|
22031
|
-
message: `unknown option '${arg}'. Known: ${[...BOOLEAN_FLAGS, ...VALUE_FLAGS].map((f) => `--${f}`).sort().join(", ")}, --help`
|
|
22085
|
+
message: `unknown option '${arg}'. Known: ${[...BOOLEAN_FLAGS.keys(), ...VALUE_FLAGS].map((f) => `--${f}`).sort().join(", ")}, --help`
|
|
22032
22086
|
};
|
|
22033
22087
|
}
|
|
22034
22088
|
const positive = (name) => {
|
|
@@ -22041,6 +22095,12 @@ function parseBackfillArgs(argv) {
|
|
|
22041
22095
|
}
|
|
22042
22096
|
return n;
|
|
22043
22097
|
};
|
|
22098
|
+
if (booleans.dryRun && booleans.reset) {
|
|
22099
|
+
return {
|
|
22100
|
+
kind: "error",
|
|
22101
|
+
message: "--reset cannot be combined with --dry-run: a dry run maps every transcript from the start already, and never writes checkpoints"
|
|
22102
|
+
};
|
|
22103
|
+
}
|
|
22044
22104
|
const sinceDays = positive("days");
|
|
22045
22105
|
if (typeof sinceDays === "object")
|
|
22046
22106
|
return sinceDays;
|
|
@@ -22050,7 +22110,8 @@ function parseBackfillArgs(argv) {
|
|
|
22050
22110
|
return {
|
|
22051
22111
|
kind: "run",
|
|
22052
22112
|
options: {
|
|
22053
|
-
dryRun,
|
|
22113
|
+
dryRun: booleans.dryRun,
|
|
22114
|
+
reset: booleans.reset,
|
|
22054
22115
|
paths,
|
|
22055
22116
|
...values.get("profile") !== void 0 ? { profile: values.get("profile") } : {},
|
|
22056
22117
|
...values.get("credentials") !== void 0 ? { credentialsPath: values.get("credentials") } : {},
|
|
@@ -22066,10 +22127,21 @@ function batches(items, size) {
|
|
|
22066
22127
|
return out;
|
|
22067
22128
|
}
|
|
22068
22129
|
async function runBackfill(mapper, options, say2) {
|
|
22130
|
+
if (!options.dryRun && backfillIsOff(mapper, options)) {
|
|
22131
|
+
say2("BACKFILL DISABLED \u2014 the retroactive import is opt-in, and this machine has not opted in");
|
|
22132
|
+
say2(`set "capture": { "backfill": true } in ${configPath()} to allow it`);
|
|
22133
|
+
say2("nothing was sent and no checkpoint was cleared; live capture is unaffected");
|
|
22134
|
+
return disabledResult();
|
|
22135
|
+
}
|
|
22069
22136
|
const discovered = options.paths.length > 0 ? options.paths : discoverTranscripts(mapper);
|
|
22070
22137
|
const paths = options.sinceDays === void 0 ? discovered : withinDays(discovered, options.sinceDays);
|
|
22071
22138
|
const window2 = options.sinceDays === void 0 ? "" : ` written to in the last ${options.sinceDays} day(s)`;
|
|
22072
22139
|
say2(`${options.dryRun ? "DRY RUN \u2014 nothing will be sent. " : ""}${paths.length} transcript(s)${window2}`);
|
|
22140
|
+
if (options.reset) {
|
|
22141
|
+
const reset = await resetCheckpoints(mapper, options, paths, say2);
|
|
22142
|
+
if (reset === void 0)
|
|
22143
|
+
return lockBusyResult();
|
|
22144
|
+
}
|
|
22073
22145
|
const pass = (subset) => runForwarder(mapper, {
|
|
22074
22146
|
paths: subset,
|
|
22075
22147
|
dryRun: options.dryRun,
|
|
@@ -22086,6 +22158,61 @@ async function runBackfill(mapper, options, say2) {
|
|
|
22086
22158
|
return pass([]);
|
|
22087
22159
|
return runPasses(batches(paths, options.batch ?? DEFAULT_BATCH), pass, say2);
|
|
22088
22160
|
}
|
|
22161
|
+
async function resetCheckpoints(mapper, options, paths, say2) {
|
|
22162
|
+
const { scope } = loadRuntimeSettings(mapper.vendor, options.profile !== void 0 ? { profile: options.profile } : {});
|
|
22163
|
+
const release = await acquireLockWithin(scope, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS);
|
|
22164
|
+
if (!release)
|
|
22165
|
+
return void 0;
|
|
22166
|
+
let reset;
|
|
22167
|
+
try {
|
|
22168
|
+
reset = clearCheckpoints(scope, paths);
|
|
22169
|
+
} finally {
|
|
22170
|
+
release();
|
|
22171
|
+
}
|
|
22172
|
+
if (reset.cleared.length === 0) {
|
|
22173
|
+
say2(reset.total === 0 ? "RESET \u2014 nothing had been shipped yet; these transcripts ship from the start anyway" : `RESET \u2014 NOTHING CLEARED: none of the selected paths match the ${reset.total} checkpoint(s) on file, so they will ship from wherever they left off`);
|
|
22174
|
+
return reset;
|
|
22175
|
+
}
|
|
22176
|
+
say2(`RESET \u2014 forgot the offset for ${reset.cleared.length} transcript(s); they re-ship in full`);
|
|
22177
|
+
say2(`previous checkpoints saved as ${reset.backup}`);
|
|
22178
|
+
return reset;
|
|
22179
|
+
}
|
|
22180
|
+
function backfillIsOff(mapper, options) {
|
|
22181
|
+
try {
|
|
22182
|
+
const { capture } = loadRuntimeSettings(mapper.vendor, options.profile !== void 0 ? { profile: options.profile } : {});
|
|
22183
|
+
return !capture.backfill;
|
|
22184
|
+
} catch {
|
|
22185
|
+
return false;
|
|
22186
|
+
}
|
|
22187
|
+
}
|
|
22188
|
+
function disabledResult() {
|
|
22189
|
+
return {
|
|
22190
|
+
transcripts: 0,
|
|
22191
|
+
records: 0,
|
|
22192
|
+
skipped: ["backfill is disabled"],
|
|
22193
|
+
kinds: {},
|
|
22194
|
+
warnings: [],
|
|
22195
|
+
emitted: { transcripts: 0, records: 0 },
|
|
22196
|
+
backfillDisabled: true,
|
|
22197
|
+
// Non-zero exit, for the reason `shipped 0` cannot carry: an up-to-date machine
|
|
22198
|
+
// prints that too, and a script chaining backfills must not read a refusal as done.
|
|
22199
|
+
ok: false,
|
|
22200
|
+
error: "backfill is disabled by capture.backfill"
|
|
22201
|
+
};
|
|
22202
|
+
}
|
|
22203
|
+
function lockBusyResult() {
|
|
22204
|
+
return {
|
|
22205
|
+
transcripts: 0,
|
|
22206
|
+
records: 0,
|
|
22207
|
+
skipped: ["another forwarder holds the lock"],
|
|
22208
|
+
kinds: {},
|
|
22209
|
+
warnings: [],
|
|
22210
|
+
emitted: { transcripts: 0, records: 0 },
|
|
22211
|
+
lockBusy: true,
|
|
22212
|
+
ok: false,
|
|
22213
|
+
error: "another forwarder holds the lock"
|
|
22214
|
+
};
|
|
22215
|
+
}
|
|
22089
22216
|
async function runPasses(groups, pass, say2) {
|
|
22090
22217
|
const total = {
|
|
22091
22218
|
transcripts: 0,
|
|
@@ -22515,6 +22642,7 @@ if (parsed.kind === "error") {
|
|
|
22515
22642
|
process.exit(2);
|
|
22516
22643
|
}
|
|
22517
22644
|
var result = await runBackfill(codexTranscript, parsed.options, say);
|
|
22645
|
+
if (result.backfillDisabled === true) process.exit(4);
|
|
22518
22646
|
say(
|
|
22519
22647
|
`${parsed.options.dryRun ? "mapped" : "shipped"} ${result.records} record(s) from ${result.transcripts} transcript(s)`
|
|
22520
22648
|
);
|
package/dist/bin/enroll.mjs
CHANGED
|
@@ -1033,7 +1033,11 @@ function init(argv) {
|
|
|
1033
1033
|
// a named profile resolve without the flag on every later run.
|
|
1034
1034
|
...separateFile ? { profile, credentials: credsPath, ...stripCredentials(existingConfig) } : credentials,
|
|
1035
1035
|
enabled: existingConfig["enabled"] ?? true,
|
|
1036
|
-
|
|
1036
|
+
// Written explicitly rather than left to the default: `backfill: false` is the one
|
|
1037
|
+
// setting someone is likely to go looking for, and a key that is not in the file is
|
|
1038
|
+
// not findable. An existing block is preserved untouched, so this never flips a
|
|
1039
|
+
// machine that had already opted in.
|
|
1040
|
+
capture: existingConfig["capture"] ?? { enabled: true, backfill: false },
|
|
1037
1041
|
// Enforcement stays off until the mapper is validated — capture only for now.
|
|
1038
1042
|
enforce: existingConfig["enforce"] ?? { mode: "off", failClosed: true },
|
|
1039
1043
|
// Whatever another endpoint wrote is preserved: one file, several endpoints, and
|
package/dist/bin/forwarder.mjs
CHANGED
|
@@ -18160,6 +18160,9 @@ function settingsFor(file, vendor) {
|
|
|
18160
18160
|
...file.enforce ?? override.enforce ? { enforce: { ...file.enforce, ...override.enforce } } : {}
|
|
18161
18161
|
};
|
|
18162
18162
|
}
|
|
18163
|
+
function resolveCapture(capture) {
|
|
18164
|
+
return { enabled: capture?.enabled ?? true, backfill: capture?.backfill ?? false };
|
|
18165
|
+
}
|
|
18163
18166
|
function readConfigFile(vendor) {
|
|
18164
18167
|
if (!existsSync(configPath())) {
|
|
18165
18168
|
throw new ConfigMissingError(`${configPath()} does not exist \u2014 run init.mjs to create it`);
|
|
@@ -18212,7 +18215,7 @@ function loadLocalConfig(vendor, options = {}) {
|
|
|
18212
18215
|
applicationId,
|
|
18213
18216
|
...(creds.userId ?? vendorFile.userId) !== void 0 ? { userId: creds.userId ?? vendorFile.userId } : {},
|
|
18214
18217
|
enabled: vendorFile.enabled ?? true,
|
|
18215
|
-
capture:
|
|
18218
|
+
capture: resolveCapture(vendorFile.capture),
|
|
18216
18219
|
enforce: {
|
|
18217
18220
|
mode: vendorFile.enforce?.mode ?? "off",
|
|
18218
18221
|
failClosed: vendorFile.enforce?.failClosed ?? true
|
|
@@ -18754,8 +18757,9 @@ function installSeededIdGenerator(client) {
|
|
|
18754
18757
|
}
|
|
18755
18758
|
|
|
18756
18759
|
// packages/core/dist/forwarder/checkpoint.js
|
|
18757
|
-
import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
18760
|
+
import { copyFileSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
18758
18761
|
import { join as join6 } from "node:path";
|
|
18762
|
+
var SPOOL_KEY = "::spool::";
|
|
18759
18763
|
function checkpointPath(scope) {
|
|
18760
18764
|
return join6(CONFIG_DIR, `${scope}.checkpoints.json`);
|
|
18761
18765
|
}
|
|
@@ -18872,12 +18876,14 @@ function acquireLock(scope) {
|
|
|
18872
18876
|
}
|
|
18873
18877
|
return () => rmSync(path, { force: true });
|
|
18874
18878
|
}
|
|
18875
|
-
function isAlive(pid) {
|
|
18879
|
+
function isAlive(pid, kill = (p, s) => {
|
|
18880
|
+
process.kill(p, s);
|
|
18881
|
+
}) {
|
|
18876
18882
|
try {
|
|
18877
|
-
|
|
18883
|
+
kill(pid, 0);
|
|
18878
18884
|
return true;
|
|
18879
|
-
} catch {
|
|
18880
|
-
return
|
|
18885
|
+
} catch (err) {
|
|
18886
|
+
return err.code !== "ESRCH";
|
|
18881
18887
|
}
|
|
18882
18888
|
}
|
|
18883
18889
|
var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
|
|
@@ -21692,7 +21698,6 @@ function toFloat(value, fallback) {
|
|
|
21692
21698
|
}
|
|
21693
21699
|
|
|
21694
21700
|
// packages/core/dist/forwarder/run.js
|
|
21695
|
-
var SPOOL_KEY = "::spool::";
|
|
21696
21701
|
var DARKHUNT_SOURCE_HINT = "darkhunt-telemetry";
|
|
21697
21702
|
function drainSpool(mapper, checkpoints) {
|
|
21698
21703
|
const path = spoolPath(mapper.vendor);
|
package/dist/bin/guard.mjs
CHANGED
|
@@ -228,13 +228,16 @@ function loadRuntimeSettings(vendor, options = {}) {
|
|
|
228
228
|
profile,
|
|
229
229
|
scope: scopeKey(vendor, profile),
|
|
230
230
|
enabled: vendorFile.enabled ?? true,
|
|
231
|
-
capture:
|
|
231
|
+
capture: resolveCapture(vendorFile.capture),
|
|
232
232
|
enforce: {
|
|
233
233
|
mode: vendorFile.enforce?.mode ?? "off",
|
|
234
234
|
failClosed: vendorFile.enforce?.failClosed ?? true
|
|
235
235
|
}
|
|
236
236
|
};
|
|
237
237
|
}
|
|
238
|
+
function resolveCapture(capture) {
|
|
239
|
+
return { enabled: capture?.enabled ?? true, backfill: capture?.backfill ?? false };
|
|
240
|
+
}
|
|
238
241
|
function readConfigFile(vendor) {
|
|
239
242
|
if (!existsSync(configPath())) {
|
|
240
243
|
throw new ConfigMissingError(`${configPath()} does not exist \u2014 run init.mjs to create it`);
|
package/dist/bin/init.mjs
CHANGED
|
@@ -1025,7 +1025,11 @@ function init(argv) {
|
|
|
1025
1025
|
// a named profile resolve without the flag on every later run.
|
|
1026
1026
|
...separateFile ? { profile, credentials: credsPath, ...stripCredentials(existingConfig) } : credentials,
|
|
1027
1027
|
enabled: existingConfig["enabled"] ?? true,
|
|
1028
|
-
|
|
1028
|
+
// Written explicitly rather than left to the default: `backfill: false` is the one
|
|
1029
|
+
// setting someone is likely to go looking for, and a key that is not in the file is
|
|
1030
|
+
// not findable. An existing block is preserved untouched, so this never flips a
|
|
1031
|
+
// machine that had already opted in.
|
|
1032
|
+
capture: existingConfig["capture"] ?? { enabled: true, backfill: false },
|
|
1029
1033
|
// Enforcement stays off until the mapper is validated — capture only for now.
|
|
1030
1034
|
enforce: existingConfig["enforce"] ?? { mode: "off", failClosed: true },
|
|
1031
1035
|
// Whatever another endpoint wrote is preserved: one file, several endpoints, and
|
package/dist/bin/spool.mjs
CHANGED
|
@@ -74,13 +74,16 @@ function loadRuntimeSettings(vendor, options = {}) {
|
|
|
74
74
|
profile,
|
|
75
75
|
scope: scopeKey(vendor, profile),
|
|
76
76
|
enabled: vendorFile.enabled ?? true,
|
|
77
|
-
capture:
|
|
77
|
+
capture: resolveCapture(vendorFile.capture),
|
|
78
78
|
enforce: {
|
|
79
79
|
mode: vendorFile.enforce?.mode ?? "off",
|
|
80
80
|
failClosed: vendorFile.enforce?.failClosed ?? true
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
+
function resolveCapture(capture) {
|
|
85
|
+
return { enabled: capture?.enabled ?? true, backfill: capture?.backfill ?? false };
|
|
86
|
+
}
|
|
84
87
|
function readConfigFile(vendor) {
|
|
85
88
|
if (!existsSync(configPath())) {
|
|
86
89
|
throw new ConfigMissingError(`${configPath()} does not exist \u2014 run init.mjs to create it`);
|
package/dist/bin/status.mjs
CHANGED
|
@@ -87,6 +87,9 @@ function settingsFor(file, vendor) {
|
|
|
87
87
|
...file.enforce ?? override.enforce ? { enforce: { ...file.enforce, ...override.enforce } } : {}
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
+
function resolveCapture(capture) {
|
|
91
|
+
return { enabled: capture?.enabled ?? true, backfill: capture?.backfill ?? false };
|
|
92
|
+
}
|
|
90
93
|
function readConfigFile(vendor) {
|
|
91
94
|
if (!existsSync(configPath())) {
|
|
92
95
|
throw new ConfigMissingError(`${configPath()} does not exist \u2014 run init.mjs to create it`);
|
|
@@ -139,7 +142,7 @@ function loadLocalConfig(vendor, options = {}) {
|
|
|
139
142
|
applicationId,
|
|
140
143
|
...(creds.userId ?? vendorFile.userId) !== void 0 ? { userId: creds.userId ?? vendorFile.userId } : {},
|
|
141
144
|
enabled: vendorFile.enabled ?? true,
|
|
142
|
-
capture:
|
|
145
|
+
capture: resolveCapture(vendorFile.capture),
|
|
143
146
|
enforce: {
|
|
144
147
|
mode: vendorFile.enforce?.mode ?? "off",
|
|
145
148
|
failClosed: vendorFile.enforce?.failClosed ?? true
|
|
@@ -171,7 +174,7 @@ function loadBeat(scope) {
|
|
|
171
174
|
}
|
|
172
175
|
|
|
173
176
|
// packages/core/dist/forwarder/checkpoint.js
|
|
174
|
-
import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
177
|
+
import { copyFileSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
175
178
|
import { join as join6 } from "node:path";
|
|
176
179
|
function checkpointPath(scope) {
|
|
177
180
|
return join6(CONFIG_DIR, `${scope}.checkpoints.json`);
|
|
@@ -1208,6 +1211,9 @@ function status(vendor, mapper) {
|
|
|
1208
1211
|
workspaceId: config.workspaceId,
|
|
1209
1212
|
scope: config.scope,
|
|
1210
1213
|
capture: config.capture.enabled && config.enabled,
|
|
1214
|
+
// Each switch above it can also stop an import, so all three have to agree before
|
|
1215
|
+
// this may claim a backfill would run.
|
|
1216
|
+
backfill: config.capture.backfill && config.capture.enabled && config.enabled,
|
|
1211
1217
|
enforce: config.enabled ? config.enforce.mode : "off (kill switch)",
|
|
1212
1218
|
spoolEvents,
|
|
1213
1219
|
...spoolLastAt !== void 0 ? { spoolLastAt } : {},
|
|
@@ -1680,7 +1686,9 @@ try {
|
|
|
1680
1686
|
console.log(
|
|
1681
1687
|
` user ${s.userId ?? "(none \u2014 traces are unattributed)"}` + (s.userIdSource === "none" ? "" : ` [from ${s.userIdSource}]`)
|
|
1682
1688
|
);
|
|
1683
|
-
console.log(
|
|
1689
|
+
console.log(
|
|
1690
|
+
` capture ${s.capture ? "ON" : "OFF"} enforce ${s.enforce} backfill ${s.backfill ? "ON" : "OFF"}`
|
|
1691
|
+
);
|
|
1684
1692
|
if (s.subagents && s.subagents.found > 0) {
|
|
1685
1693
|
const { found, shipped } = s.subagents;
|
|
1686
1694
|
console.log(
|
package/package.json
CHANGED