codiedev 0.10.0-beta.1 → 0.10.0-beta.11
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 +11 -5
- package/assets/opencode-plugin.mjs +6 -0
- package/assets/session-key.mjs +48 -0
- package/assets/tui-brand-plugin.tsx +73 -0
- package/dist/backup/cache.js +1 -5
- package/dist/backup/match.js +0 -6
- package/dist/backup/run.js +3 -35
- package/dist/captureExclusions.js +0 -12
- package/dist/captureLog.js +0 -28
- package/dist/captureReadiness.js +0 -58
- package/dist/captureSignals.js +184 -0
- package/dist/cli.js +135 -72
- package/dist/cliSession.js +456 -0
- package/dist/codexHookTrust.js +125 -6
- package/dist/codexLimitScan.js +359 -0
- package/dist/codie.js +77 -130
- package/dist/codieBrandInstall.js +80 -0
- package/dist/codieLauncher.js +76 -79
- package/dist/codieRuntime.js +19 -23
- package/dist/codieRuntimeInstall.js +108 -23
- package/dist/codieUsage.js +181 -0
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1101 -0
- package/dist/commands/agentsSdk.generated.js +7 -0
- package/dist/commands/ask.js +0 -3
- package/dist/commands/capture.js +0 -2
- package/dist/commands/createTicket.js +0 -10
- package/dist/commands/doctor.js +53 -120
- package/dist/commands/evals.js +187 -0
- package/dist/commands/inbox.js +0 -2
- package/dist/commands/library.js +0 -3
- package/dist/commands/pack.js +573 -0
- package/dist/commands/ping.js +0 -2
- package/dist/commands/pull.js +6 -10
- package/dist/commands/push.js +2 -12
- package/dist/commands/search.js +0 -4
- package/dist/commands/send.js +0 -5
- package/dist/commands/share.js +0 -4
- package/dist/commands/shared.js +0 -35
- package/dist/commands/traces.js +344 -0
- package/dist/commands/tracesLabel.js +348 -0
- package/dist/configDir.js +18 -11
- package/dist/connect.js +55 -118
- package/dist/connectFlow.js +35 -9
- package/dist/copilotHooks.js +391 -0
- package/dist/copilotInstallation.js +64 -0
- package/dist/cursorHooks.js +38 -30
- package/dist/cursorLifecycle.js +109 -0
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +77 -0
- package/dist/hook.js +256 -445
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +150 -0
- package/dist/launcher.js +168 -0
- package/dist/limitEvent.js +44 -13
- package/dist/limitEventReporter.js +1 -1
- package/dist/managedPi.js +256 -0
- package/dist/mcp.js +5 -384
- package/dist/nativeSteering.js +24 -0
- package/dist/packs/codie.js +182 -0
- package/dist/packs/harnesses.js +411 -0
- package/dist/packs/hookGate.js +256 -0
- package/dist/packs/install.js +286 -0
- package/dist/packs/manifest.js +126 -0
- package/dist/packs/paths.js +81 -0
- package/dist/packs/shim.js +214 -0
- package/dist/packs/store.js +155 -0
- package/dist/packs/sync.js +170 -0
- package/dist/piHooks.js +216 -0
- package/dist/piRuntime.js +120 -0
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/selfUpdate.js +376 -0
- package/dist/skillMarker.js +23 -0
- package/dist/subagents.js +135 -0
- package/dist/teamSkillContext.js +10 -0
- package/dist/transcriptModels.js +205 -0
- package/dist/upgradeNudge.js +0 -30
- package/dist/utils.js +502 -828
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +8 -9
- package/dist/backup/cache.d.ts +0 -14
- package/dist/backup/match.d.ts +0 -2
- package/dist/backup/run.d.ts +0 -25
- package/dist/captureExclusions.d.ts +0 -30
- package/dist/captureLog.d.ts +0 -20
- package/dist/captureReadiness.d.ts +0 -65
- package/dist/cli.d.ts +0 -16
- package/dist/codexHookTrust.d.ts +0 -34
- package/dist/codie.d.ts +0 -2
- package/dist/codieLauncher.d.ts +0 -53
- package/dist/codieRuntime.d.ts +0 -29
- package/dist/codieRuntimeInstall.d.ts +0 -28
- package/dist/codieStartup.d.ts +0 -26
- package/dist/codieStartup.js +0 -30
- package/dist/commands/ask.d.ts +0 -1
- package/dist/commands/capture.d.ts +0 -14
- package/dist/commands/createTicket.d.ts +0 -27
- package/dist/commands/delete.d.ts +0 -1
- package/dist/commands/doctor.d.ts +0 -1
- package/dist/commands/inbox.d.ts +0 -3
- package/dist/commands/library.d.ts +0 -2
- package/dist/commands/note.d.ts +0 -1
- package/dist/commands/ping.d.ts +0 -1
- package/dist/commands/promote.d.ts +0 -1
- package/dist/commands/promote.js +0 -53
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/push.d.ts +0 -33
- package/dist/commands/react.d.ts +0 -2
- package/dist/commands/react.js +0 -40
- package/dist/commands/reverseTicket.d.ts +0 -2
- package/dist/commands/reverseTicket.js +0 -477
- package/dist/commands/search.d.ts +0 -2
- package/dist/commands/security.d.ts +0 -1
- package/dist/commands/security.js +0 -156
- package/dist/commands/send.d.ts +0 -2
- package/dist/commands/share.d.ts +0 -2
- package/dist/commands/shared.d.ts +0 -64
- package/dist/configDir.d.ts +0 -1
- package/dist/connect.d.ts +0 -1
- package/dist/connectFlow.d.ts +0 -13
- package/dist/cursorHooks.d.ts +0 -23
- package/dist/detection.d.ts +0 -30
- package/dist/hook.d.ts +0 -6
- package/dist/inboxFormat.d.ts +0 -38
- package/dist/limitEvent.d.ts +0 -16
- package/dist/limitEventReporter.d.ts +0 -21
- package/dist/mcp.d.ts +0 -12
- package/dist/prUrl.d.ts +0 -9
- package/dist/prUrl.js +0 -33
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/security.d.ts +0 -102
- package/dist/security.js +0 -437
- package/dist/securityDeepScan.d.ts +0 -41
- package/dist/securityDeepScan.js +0 -248
- package/dist/securityDoctor.d.ts +0 -32
- package/dist/securityDoctor.js +0 -63
- package/dist/securityFeature.d.ts +0 -5
- package/dist/securityFeature.js +0 -7
- package/dist/securityInstall.d.ts +0 -63
- package/dist/securityInstall.js +0 -239
- package/dist/securityInventory.d.ts +0 -54
- package/dist/securityInventory.js +0 -556
- package/dist/securityPilot.d.ts +0 -19
- package/dist/securityPilot.js +0 -61
- package/dist/securityPolicy.d.ts +0 -33
- package/dist/securityPolicy.js +0 -188
- package/dist/securitySession.d.ts +0 -6
- package/dist/securitySession.js +0 -72
- package/dist/upgradeNudge.d.ts +0 -25
- package/dist/utils.d.ts +0 -342
- package/dist/version.d.ts +0 -1
- package/dist/versionCheck.d.ts +0 -68
package/dist/inboxFormat.js
CHANGED
|
@@ -2,32 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatInbox = formatInbox;
|
|
4
4
|
const shared_1 = require("./commands/shared");
|
|
5
|
-
/**
|
|
6
|
-
* Render the inbox for BOTH surfaces — `codiedev inbox` and the MCP
|
|
7
|
-
* `codiedev_inbox` tool an agent calls for "any messages?". Shared so the
|
|
8
|
-
* agent path can never drift back to pings-only while the human path shows
|
|
9
|
-
* mentions.
|
|
10
|
-
*/
|
|
11
5
|
function formatInbox(opts) {
|
|
12
6
|
const mentions = opts.mentions ?? [];
|
|
13
|
-
// The backend applies `limit` to each source independently, so asking for N
|
|
14
|
-
// can return up to 2N — and with no `--limit` it defaults to 50 per source,
|
|
15
|
-
// i.e. 100 rows, twice the pre-change maximum. Cap the COMBINED list by
|
|
16
|
-
// recency, always (matching the backend's own default), so the header is
|
|
17
|
-
// truthful and `--limit` actually holds.
|
|
18
|
-
//
|
|
19
|
-
// Selected by identity rather than by a `createdAt >= cutoff` filter: rows
|
|
20
|
-
// tied on the cutoff millisecond are reachable (Convex freezes Date.now()
|
|
21
|
-
// per transaction, and seeded activity carries synthetic stamps) and a
|
|
22
|
-
// threshold filter lets every tied row through, overshooting the limit.
|
|
23
7
|
const DEFAULT_LIMIT = 50;
|
|
24
8
|
const cap = opts.limit ?? DEFAULT_LIMIT;
|
|
25
|
-
// Pings claim the budget first, then mentions fill whatever is left — both
|
|
26
|
-
// newest-first. Before this change pings owned the whole budget, so this is
|
|
27
|
-
// purely additive and can never hide a ping that used to be visible. A flat
|
|
28
|
-
// recency cap would instead let a busy feed evict every direct ping, and
|
|
29
|
-
// pings are the actionable half: they carry the id you reply to, and losing
|
|
30
|
-
// them all takes the mark-read footer with them.
|
|
31
9
|
const byRecency = (xs) => [...xs].sort((a, b) => b.createdAt - a.createdAt);
|
|
32
10
|
const keptPings = byRecency(opts.pings).slice(0, cap);
|
|
33
11
|
const keptMentions = byRecency(mentions).slice(0, Math.max(0, cap - keptPings.length));
|
|
@@ -50,8 +28,6 @@ function formatInbox(opts) {
|
|
|
50
28
|
lines.push(` id: ${p.pingId}`);
|
|
51
29
|
lines.push("");
|
|
52
30
|
}
|
|
53
|
-
// Mentions carry no CLI-side body to reply to — the thread lives in the feed
|
|
54
|
-
// — so each row ends in the deep link rather than an id.
|
|
55
31
|
for (const m of keptMentions) {
|
|
56
32
|
const dot = m.readAt ? "·" : "●";
|
|
57
33
|
const from = m.from?.name ?? "someone";
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.codieLaunchFromArgv = codieLaunchFromArgv;
|
|
4
|
+
exports.cursorLaunchFromCommand = cursorLaunchFromCommand;
|
|
5
|
+
exports.copilotLaunchFromCommand = copilotLaunchFromCommand;
|
|
6
|
+
exports.windowsAncestors = windowsAncestors;
|
|
7
|
+
exports.detectCursorLaunch = detectCursorLaunch;
|
|
8
|
+
exports.detectCopilotLaunch = detectCopilotLaunch;
|
|
9
|
+
exports.hookLaunch = hookLaunch;
|
|
10
|
+
const node_child_process_1 = require("node:child_process");
|
|
11
|
+
const VALUE = /^[a-z0-9][a-z0-9_.:-]{0,39}$/;
|
|
12
|
+
const CODIE_SUBCOMMANDS = ["run", "serve", "acp", "web", "attach"];
|
|
13
|
+
function codieLaunchFromArgv(argv) {
|
|
14
|
+
const sub = argv.find((a) => CODIE_SUBCOMMANDS.includes(a));
|
|
15
|
+
return sub ? `codie:${sub}` : "codie:tui";
|
|
16
|
+
}
|
|
17
|
+
function tokenize(command) {
|
|
18
|
+
const tokens = [];
|
|
19
|
+
for (const m of command.matchAll(/"([^"]*)"|(\S+)/g))
|
|
20
|
+
tokens.push(m[1] ?? m[2]);
|
|
21
|
+
return tokens;
|
|
22
|
+
}
|
|
23
|
+
const CURSOR_AGENT_PATH = /(^|[/\\])cursor-agent([/\\]|\.(exe|cmd|ps1)$|$)/i;
|
|
24
|
+
const AGENT_BIN = /(^|[/\\])(cursor-)?agent(\.(exe|cmd|ps1))?$/i;
|
|
25
|
+
function cursorLaunchFromCommand(command) {
|
|
26
|
+
const tokens = tokenize(command);
|
|
27
|
+
const isAgent = tokens.some((t) => CURSOR_AGENT_PATH.test(t) || /[/\\]\.local[/\\]share[/\\]cursor/i.test(t))
|
|
28
|
+
&& tokens.some((t) => AGENT_BIN.test(t) || /index\.js$/i.test(t));
|
|
29
|
+
if (isAgent) {
|
|
30
|
+
return cursorFlags(tokens).some((f) => f === "-p" || f === "--print" || f.startsWith("--print="))
|
|
31
|
+
? "cursor:print"
|
|
32
|
+
: "cursor:cli";
|
|
33
|
+
}
|
|
34
|
+
if (/Cursor\.app|Cursor Helper|[/\\]cursor(\.exe)?(\s|"|$)/i.test(command))
|
|
35
|
+
return "cursor:ide";
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const CURSOR_VALUE_FLAGS = new Set(["--model", "-m", "--output-format", "--api-key", "--resume", "--workspace", "--mode", "-H", "--header"]);
|
|
39
|
+
function cursorFlags(tokens) {
|
|
40
|
+
let start = tokens.findIndex((t) => /index\.js$/i.test(t));
|
|
41
|
+
if (start < 0)
|
|
42
|
+
start = tokens.findIndex((t) => AGENT_BIN.test(t));
|
|
43
|
+
const flags = [];
|
|
44
|
+
for (let i = (start >= 0 ? start : 0) + 1; i < tokens.length; i++) {
|
|
45
|
+
const t = tokens[i];
|
|
46
|
+
if (!t.startsWith("-"))
|
|
47
|
+
break;
|
|
48
|
+
flags.push(t);
|
|
49
|
+
if (CURSOR_VALUE_FLAGS.has(t))
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
return flags;
|
|
53
|
+
}
|
|
54
|
+
const COPILOT_BIN = /(^|[/\\])copilot(\.(exe|cmd|ps1|js))?$/i;
|
|
55
|
+
const NODE_BIN = /(^|[/\\])node(\.exe)?$/i;
|
|
56
|
+
function copilotLaunchFromCommand(command) {
|
|
57
|
+
const tokens = tokenize(command);
|
|
58
|
+
const bin = COPILOT_BIN.test(tokens[0] ?? "")
|
|
59
|
+
? 0
|
|
60
|
+
: NODE_BIN.test(tokens[0] ?? "") && COPILOT_BIN.test(tokens[1] ?? "")
|
|
61
|
+
? 1
|
|
62
|
+
: -1;
|
|
63
|
+
if (bin < 0)
|
|
64
|
+
return undefined;
|
|
65
|
+
for (let i = bin + 1; i < tokens.length; i++) {
|
|
66
|
+
const t = tokens[i];
|
|
67
|
+
if (t === "-p" || t === "--prompt" || t.startsWith("--prompt="))
|
|
68
|
+
return "copilot:print";
|
|
69
|
+
if (!t.startsWith("-"))
|
|
70
|
+
break;
|
|
71
|
+
if (COPILOT_VALUE_FLAGS.has(t))
|
|
72
|
+
i++;
|
|
73
|
+
}
|
|
74
|
+
return "copilot:cli";
|
|
75
|
+
}
|
|
76
|
+
const COPILOT_VALUE_FLAGS = new Set([
|
|
77
|
+
"--model", "--add-dir", "--allow-tool", "--deny-tool", "--resume", "--log-dir",
|
|
78
|
+
"--log-level", "--agent", "--config-dir", "--allow-url", "--deny-url",
|
|
79
|
+
"--additional-mcp-config", "--stream", "--output-format",
|
|
80
|
+
]);
|
|
81
|
+
const psPosix = (pid) => {
|
|
82
|
+
const result = (0, node_child_process_1.spawnSync)("ps", ["-o", "ppid=,args=", "-p", String(pid)], { encoding: "utf8", timeout: 500 });
|
|
83
|
+
const line = result.status === 0 ? result.stdout.trim() : "";
|
|
84
|
+
const match = line.match(/^(\d+)\s+(.*)$/s);
|
|
85
|
+
return match ? { ppid: Number(match[1]), command: match[2] } : null;
|
|
86
|
+
};
|
|
87
|
+
function windowsAncestors(startPid, depth) {
|
|
88
|
+
const script = `$p=${Math.trunc(startPid)};$o=@();for($i=0;$i -lt ${Math.trunc(depth)} -and $p -gt 0;$i++){` +
|
|
89
|
+
`$x=Get-CimInstance Win32_Process -Filter "ProcessId=$p" -ErrorAction SilentlyContinue;if(!$x){break};` +
|
|
90
|
+
`$o+=[pscustomobject]@{pid=[int]$p;ppid=[int]$x.ParentProcessId;command=[string]$x.CommandLine};$p=$x.ParentProcessId};` +
|
|
91
|
+
`ConvertTo-Json -InputObject @($o) -Compress`;
|
|
92
|
+
const result = (0, node_child_process_1.spawnSync)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
93
|
+
encoding: "utf8",
|
|
94
|
+
timeout: 10000,
|
|
95
|
+
windowsHide: true,
|
|
96
|
+
});
|
|
97
|
+
if (result.status !== 0 || !result.stdout.trim())
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
const rows = JSON.parse(result.stdout);
|
|
101
|
+
return rows.map((r) => ({ pid: Number(r.pid), ppid: Number(r.ppid), command: r.command ?? "" }));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function detectLaunch(fromCommand, startPid, deps) {
|
|
108
|
+
const depth = deps.depth ?? 5;
|
|
109
|
+
if ((deps.platform ?? process.platform) === "win32" && !deps.ps) {
|
|
110
|
+
const chain = (deps.windows ?? windowsAncestors)(startPid, depth);
|
|
111
|
+
if (!chain)
|
|
112
|
+
return undefined;
|
|
113
|
+
for (const row of chain) {
|
|
114
|
+
const launch = fromCommand(row.command);
|
|
115
|
+
if (launch)
|
|
116
|
+
return launch;
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const ps = deps.ps ?? psPosix;
|
|
121
|
+
let pid = startPid;
|
|
122
|
+
for (let i = 0; i < depth && pid > 1; i++) {
|
|
123
|
+
const row = ps(pid);
|
|
124
|
+
if (!row)
|
|
125
|
+
return undefined;
|
|
126
|
+
const launch = fromCommand(row.command);
|
|
127
|
+
if (launch)
|
|
128
|
+
return launch;
|
|
129
|
+
pid = row.ppid;
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
function detectCursorLaunch(startPid = process.ppid, deps = {}) {
|
|
134
|
+
return detectLaunch(cursorLaunchFromCommand, startPid, deps);
|
|
135
|
+
}
|
|
136
|
+
function detectCopilotLaunch(startPid = process.ppid, deps = {}) {
|
|
137
|
+
return detectLaunch(copilotLaunchFromCommand, startPid, deps);
|
|
138
|
+
}
|
|
139
|
+
function hookLaunch(hookCommand, input, deps = {}) {
|
|
140
|
+
if (typeof input.launch === "string" && VALUE.test(input.launch))
|
|
141
|
+
return input.launch;
|
|
142
|
+
if (hookCommand?.endsWith("-cursor"))
|
|
143
|
+
return detectCursorLaunch();
|
|
144
|
+
if (hookCommand?.endsWith("-copilot")) {
|
|
145
|
+
if (deps.copilotClientName === "vscode-agent-host")
|
|
146
|
+
return "copilot:vscode";
|
|
147
|
+
return (deps.detectCopilot ?? detectCopilotLaunch)();
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
package/dist/launcher.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LAUNCHER_FILE = void 0;
|
|
37
|
+
exports.launcherPath = launcherPath;
|
|
38
|
+
exports.usesLauncher = usesLauncher;
|
|
39
|
+
exports.readInstallRecord = readInstallRecord;
|
|
40
|
+
exports.stableHookScript = stableHookScript;
|
|
41
|
+
exports.recordCurrentInstall = recordCurrentInstall;
|
|
42
|
+
exports.ensureLauncher = ensureLauncher;
|
|
43
|
+
exports.resetLauncherCacheForTests = resetLauncherCacheForTests;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const configDir_1 = require("./configDir");
|
|
47
|
+
exports.LAUNCHER_FILE = "codiedev-hook-launcher.cjs";
|
|
48
|
+
const LAUNCHER_REVISION = 1;
|
|
49
|
+
function launcherPath() {
|
|
50
|
+
return path.join((0, configDir_1.codiedevStateDir)(), "bin", exports.LAUNCHER_FILE);
|
|
51
|
+
}
|
|
52
|
+
function installRecordPath() {
|
|
53
|
+
return path.join((0, configDir_1.codiedevStateDir)(), "install.json");
|
|
54
|
+
}
|
|
55
|
+
function usesLauncher(cmd) {
|
|
56
|
+
return typeof cmd === "string" && cmd.includes(exports.LAUNCHER_FILE);
|
|
57
|
+
}
|
|
58
|
+
function launcherSource(fallback) {
|
|
59
|
+
return `// codiedev-hook-launcher revision ${LAUNCHER_REVISION}. Managed by codiedev; safe to delete (re-run \`codiedev connect\`).
|
|
60
|
+
"use strict";
|
|
61
|
+
const fs = require("fs");
|
|
62
|
+
const path = require("path");
|
|
63
|
+
const FALLBACK = ${JSON.stringify(fallback)};
|
|
64
|
+
let target = null;
|
|
65
|
+
try {
|
|
66
|
+
const rec = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "install.json"), "utf8"));
|
|
67
|
+
if (rec && typeof rec.hookScript === "string" && fs.existsSync(rec.hookScript)) target = rec.hookScript;
|
|
68
|
+
} catch {}
|
|
69
|
+
if (!target && fs.existsSync(FALLBACK)) target = FALLBACK;
|
|
70
|
+
if (!target) process.exit(0);
|
|
71
|
+
process.env.CODIEDEV_VIA_LAUNCHER = "1";
|
|
72
|
+
process.argv[1] = target;
|
|
73
|
+
require(target);
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
function writeAtomic(target, contents) {
|
|
77
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
78
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
79
|
+
fs.writeFileSync(tmp, contents, "utf8");
|
|
80
|
+
fs.renameSync(tmp, target);
|
|
81
|
+
}
|
|
82
|
+
function readInstallRecord() {
|
|
83
|
+
try {
|
|
84
|
+
const parsed = JSON.parse(fs.readFileSync(installRecordPath(), "utf8"));
|
|
85
|
+
return typeof parsed.hookScript === "string" ? parsed : null;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function packageVersionFor(hookScript) {
|
|
92
|
+
try {
|
|
93
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(path.dirname(path.dirname(hookScript)), "package.json"), "utf8"));
|
|
94
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function stableHookScript(hookScript, globalCandidates = globalHookScripts()) {
|
|
101
|
+
if (!hookScript || !path.isAbsolute(hookScript) || hookScript.includes(`${path.sep}~${path.sep}`))
|
|
102
|
+
return null;
|
|
103
|
+
if (!fs.existsSync(hookScript))
|
|
104
|
+
return null;
|
|
105
|
+
if (hookScript.includes(`${path.sep}_npx${path.sep}`)) {
|
|
106
|
+
const global = globalCandidates.find((p) => path.isAbsolute(p) && fs.existsSync(p));
|
|
107
|
+
if (global)
|
|
108
|
+
return global;
|
|
109
|
+
}
|
|
110
|
+
return hookScript;
|
|
111
|
+
}
|
|
112
|
+
function globalHookScripts() {
|
|
113
|
+
const prefix = path.dirname(path.dirname(process.execPath));
|
|
114
|
+
return [
|
|
115
|
+
path.join(prefix, "lib", "node_modules", "codiedev", "dist", "hook.js"),
|
|
116
|
+
path.join(prefix, "node_modules", "codiedev", "dist", "hook.js"),
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
function recordCurrentInstall(requested) {
|
|
120
|
+
const hookScript = stableHookScript(requested);
|
|
121
|
+
if (!hookScript)
|
|
122
|
+
return false;
|
|
123
|
+
try {
|
|
124
|
+
const record = {
|
|
125
|
+
hookScript,
|
|
126
|
+
version: packageVersionFor(hookScript),
|
|
127
|
+
recordedAt: Date.now(),
|
|
128
|
+
};
|
|
129
|
+
writeAtomic(installRecordPath(), JSON.stringify(record, null, 2));
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
let ensuredFor;
|
|
137
|
+
function ensureLauncher(requested) {
|
|
138
|
+
const hookScript = stableHookScript(requested);
|
|
139
|
+
if (!hookScript)
|
|
140
|
+
return null;
|
|
141
|
+
if (ensuredFor !== undefined && ensuredFor === hookScript)
|
|
142
|
+
return launcherPath();
|
|
143
|
+
try {
|
|
144
|
+
const target = launcherPath();
|
|
145
|
+
if (!path.isAbsolute(target))
|
|
146
|
+
return null;
|
|
147
|
+
const source = launcherSource(hookScript);
|
|
148
|
+
let current = null;
|
|
149
|
+
try {
|
|
150
|
+
current = fs.readFileSync(target, "utf8");
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
}
|
|
154
|
+
if (current !== source)
|
|
155
|
+
writeAtomic(target, source);
|
|
156
|
+
if (readInstallRecord()?.hookScript !== hookScript && !recordCurrentInstall(hookScript)) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
ensuredFor = hookScript;
|
|
160
|
+
return target;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function resetLauncherCacheForTests() {
|
|
167
|
+
ensuredFor = undefined;
|
|
168
|
+
}
|
package/dist/limitEvent.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.classifyLimitKind = classifyLimitKind;
|
|
4
4
|
exports.parseLimitEventFromTranscript = parseLimitEventFromTranscript;
|
|
5
5
|
exports.parseCodexLimitEventFromTranscript = parseCodexLimitEventFromTranscript;
|
|
6
|
+
exports.parseNativeLimitError = parseNativeLimitError;
|
|
7
|
+
exports.parseNativeLimitEventFromTranscript = parseNativeLimitEventFromTranscript;
|
|
6
8
|
exports.tailForLimitEvent = tailForLimitEvent;
|
|
7
9
|
function classifyLimitKind(text) {
|
|
8
10
|
const t = text.toLowerCase();
|
|
@@ -12,7 +14,6 @@ function classifyLimitKind(text) {
|
|
|
12
14
|
return "org_spend";
|
|
13
15
|
return "other";
|
|
14
16
|
}
|
|
15
|
-
// "… · resets 9:50pm (UTC)" → "9:50pm (UTC)". Null when absent.
|
|
16
17
|
function parseResetText(text) {
|
|
17
18
|
const m = text.match(/resets\s+(.+?)\s*$/i);
|
|
18
19
|
return m ? m[1].trim() : null;
|
|
@@ -25,8 +26,6 @@ function messageText(entry) {
|
|
|
25
26
|
return c.map((x) => (x && typeof x === "object" ? x.text ?? "" : "")).join(" ");
|
|
26
27
|
return "";
|
|
27
28
|
}
|
|
28
|
-
// Scans transcript JSONL for the LAST top-level `error: "rate_limit"` entry.
|
|
29
|
-
// (Validated shape: error/isApiErrorMessage are top-level, not under message.)
|
|
30
29
|
function parseLimitEventFromTranscript(transcript) {
|
|
31
30
|
let found = null;
|
|
32
31
|
for (const line of transcript.split("\n")) {
|
|
@@ -54,8 +53,10 @@ function parseLimitEventFromTranscript(transcript) {
|
|
|
54
53
|
function codexLimitKind(reason, spendControlReached) {
|
|
55
54
|
if (spendControlReached || reason.startsWith("workspace_owner_"))
|
|
56
55
|
return "org_spend";
|
|
57
|
-
if (reason
|
|
56
|
+
if (reason === "workspace_member_usage_limit_reached")
|
|
58
57
|
return "user_spend";
|
|
58
|
+
if (reason === "workspace_member_credits_depleted")
|
|
59
|
+
return "session";
|
|
59
60
|
return reason === "rate_limit_reached" ? "session" : "other";
|
|
60
61
|
}
|
|
61
62
|
function codexResetText(rateLimits) {
|
|
@@ -69,11 +70,6 @@ function codexResetText(rateLimits) {
|
|
|
69
70
|
.sort((a, b) => a - b)[0];
|
|
70
71
|
return resetAt ? new Date(resetAt * 1000).toISOString() : null;
|
|
71
72
|
}
|
|
72
|
-
/**
|
|
73
|
-
* Codex writes a structured RateLimitSnapshot on token_count events. A normal
|
|
74
|
-
* turn has `rate_limit_reached_type: null`; a blocked turn names the exact
|
|
75
|
-
* boundary. Reading that field avoids locale-dependent terminal copy.
|
|
76
|
-
*/
|
|
77
73
|
function parseCodexLimitEventFromTranscript(transcript) {
|
|
78
74
|
let found = null;
|
|
79
75
|
for (const line of transcript.split("\n")) {
|
|
@@ -108,10 +104,45 @@ function parseCodexLimitEventFromTranscript(transcript) {
|
|
|
108
104
|
}
|
|
109
105
|
return found;
|
|
110
106
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
function parseNativeLimitError(input, now = Date.now()) {
|
|
108
|
+
const context = input.errorContext ?? input.error_context;
|
|
109
|
+
if (context !== undefined && context !== "model_call")
|
|
110
|
+
return null;
|
|
111
|
+
const error = input.error;
|
|
112
|
+
const fields = error && typeof error === "object" ? error : {};
|
|
113
|
+
const code = String(fields.code ?? fields.name ?? input.error_code ?? "");
|
|
114
|
+
const text = typeof error === "string" ? error
|
|
115
|
+
: typeof fields.message === "string" ? fields.message
|
|
116
|
+
: typeof input.error_message === "string" ? input.error_message : "";
|
|
117
|
+
if (!/^(?:429|rate[_-]?limit(?:ed|_exceeded|_error)?|RateLimitError|quota_exceeded)$/i.test(code)
|
|
118
|
+
&& !/\b(?:rate limit (?:exceeded|reached)|too many requests|usage limit (?:exceeded|reached)|premium requests? (?:exhausted|limit reached))\b/i.test(text))
|
|
119
|
+
return null;
|
|
120
|
+
const rawAt = input.timestamp;
|
|
121
|
+
const parsedAt = typeof rawAt === "number" ? rawAt : typeof rawAt === "string" ? Date.parse(rawAt) : NaN;
|
|
122
|
+
return { kind: classifyLimitKind(text), at: Number.isFinite(parsedAt) && parsedAt > 0 ? parsedAt : now,
|
|
123
|
+
resetText: parseResetText(text), reason: code || "rate_limit" };
|
|
124
|
+
}
|
|
125
|
+
function parseNativeLimitEventFromTranscript(transcript) {
|
|
126
|
+
let found = null;
|
|
127
|
+
for (const line of transcript.split("\n")) {
|
|
128
|
+
try {
|
|
129
|
+
const entry = JSON.parse(line);
|
|
130
|
+
if (entry.type === "agent.limit" && Number.isFinite(entry.at) && entry.at > 0
|
|
131
|
+
&& ["session", "user_spend", "org_spend", "other"].includes(entry.kind)) {
|
|
132
|
+
found = { kind: entry.kind, at: entry.at, resetText: typeof entry.resetText === "string" ? entry.resetText : null,
|
|
133
|
+
...(typeof entry.reason === "string" ? { reason: entry.reason } : {}) };
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (!entry.timestamp)
|
|
137
|
+
continue;
|
|
138
|
+
if (entry.type === "agent.error" || entry.type === "session.error") {
|
|
139
|
+
found = parseNativeLimitError({ ...(entry.data ?? entry), timestamp: entry.timestamp }) ?? found;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch { }
|
|
143
|
+
}
|
|
144
|
+
return found;
|
|
145
|
+
}
|
|
115
146
|
const DEFAULT_TAIL_CHARS = 65536;
|
|
116
147
|
function tailForLimitEvent(transcript, maxChars = DEFAULT_TAIL_CHARS) {
|
|
117
148
|
if (transcript.length <= maxChars)
|
|
@@ -76,7 +76,7 @@ function postLimitEvent(config, payload, timeoutMs = 5_000) {
|
|
|
76
76
|
async function reportTranscriptLimitEvent(args) {
|
|
77
77
|
const parse = args.source === "codex"
|
|
78
78
|
? limitEvent_1.parseCodexLimitEventFromTranscript
|
|
79
|
-
: limitEvent_1.parseLimitEventFromTranscript;
|
|
79
|
+
: args.source === "cursor" || args.source === "copilot" || args.source === "pi" ? limitEvent_1.parseNativeLimitEventFromTranscript : limitEvent_1.parseLimitEventFromTranscript;
|
|
80
80
|
const parsed = parse(args.transcript);
|
|
81
81
|
if (!parsed && !args.emitMinimalOnMiss)
|
|
82
82
|
return false;
|