codiedev 0.10.0-beta.4 → 0.10.0-beta.6
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/tui-brand-plugin.tsx +14 -2
- 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 +68 -3
- package/dist/cli.js +75 -64
- package/dist/codexHookTrust.js +125 -6
- package/dist/codexLimitScan.js +2 -109
- package/dist/codie.js +50 -114
- package/dist/codieBrandInstall.js +0 -18
- package/dist/codieLauncher.js +20 -92
- package/dist/codieRuntime.js +19 -23
- package/dist/codieRuntimeInstall.js +108 -23
- package/dist/codieUsage.js +38 -41
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1066 -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 +0 -10
- package/dist/connect.js +19 -116
- package/dist/connectFlow.js +0 -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 +182 -469
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +150 -0
- package/dist/launcher.js +140 -0
- package/dist/limitEvent.js +41 -35
- package/dist/limitEventReporter.js +1 -1
- package/dist/managedPi.js +240 -0
- package/dist/mcp.js +3 -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 +6 -8
- package/dist/upgradeNudge.js +0 -30
- package/dist/utils.js +494 -824
- 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/captureSignals.d.ts +0 -19
- package/dist/cli.d.ts +0 -16
- package/dist/codexHookTrust.d.ts +0 -34
- package/dist/codexLimitScan.d.ts +0 -64
- package/dist/codie.d.ts +0 -2
- package/dist/codieBrandInstall.d.ts +0 -11
- package/dist/codieLauncher.d.ts +0 -86
- 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/codieUsage.d.ts +0 -57
- 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/transcriptModels.d.ts +0 -18
- package/dist/upgradeNudge.d.ts +0 -25
- package/dist/utils.d.ts +0 -346
- 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,140 @@
|
|
|
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.recordCurrentInstall = recordCurrentInstall;
|
|
41
|
+
exports.ensureLauncher = ensureLauncher;
|
|
42
|
+
exports.resetLauncherCacheForTests = resetLauncherCacheForTests;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const configDir_1 = require("./configDir");
|
|
46
|
+
exports.LAUNCHER_FILE = "codiedev-hook-launcher.cjs";
|
|
47
|
+
const LAUNCHER_REVISION = 1;
|
|
48
|
+
function launcherPath() {
|
|
49
|
+
return path.join((0, configDir_1.codiedevStateDir)(), "bin", exports.LAUNCHER_FILE);
|
|
50
|
+
}
|
|
51
|
+
function installRecordPath() {
|
|
52
|
+
return path.join((0, configDir_1.codiedevStateDir)(), "install.json");
|
|
53
|
+
}
|
|
54
|
+
function usesLauncher(cmd) {
|
|
55
|
+
return typeof cmd === "string" && cmd.includes(exports.LAUNCHER_FILE);
|
|
56
|
+
}
|
|
57
|
+
function launcherSource(fallback) {
|
|
58
|
+
return `// codiedev-hook-launcher revision ${LAUNCHER_REVISION}. Managed by codiedev; safe to delete (re-run \`codiedev connect\`).
|
|
59
|
+
"use strict";
|
|
60
|
+
const fs = require("fs");
|
|
61
|
+
const path = require("path");
|
|
62
|
+
const FALLBACK = ${JSON.stringify(fallback)};
|
|
63
|
+
let target = null;
|
|
64
|
+
try {
|
|
65
|
+
const rec = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "install.json"), "utf8"));
|
|
66
|
+
if (rec && typeof rec.hookScript === "string" && fs.existsSync(rec.hookScript)) target = rec.hookScript;
|
|
67
|
+
} catch {}
|
|
68
|
+
if (!target && fs.existsSync(FALLBACK)) target = FALLBACK;
|
|
69
|
+
if (!target) process.exit(0);
|
|
70
|
+
process.env.CODIEDEV_VIA_LAUNCHER = "1";
|
|
71
|
+
process.argv[1] = target;
|
|
72
|
+
require(target);
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
function writeAtomic(target, contents) {
|
|
76
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
77
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
78
|
+
fs.writeFileSync(tmp, contents, "utf8");
|
|
79
|
+
fs.renameSync(tmp, target);
|
|
80
|
+
}
|
|
81
|
+
function readInstallRecord() {
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(fs.readFileSync(installRecordPath(), "utf8"));
|
|
84
|
+
return typeof parsed.hookScript === "string" ? parsed : null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function packageVersionFor(hookScript) {
|
|
91
|
+
try {
|
|
92
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(path.dirname(path.dirname(hookScript)), "package.json"), "utf8"));
|
|
93
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function recordCurrentInstall(hookScript) {
|
|
100
|
+
try {
|
|
101
|
+
const record = {
|
|
102
|
+
hookScript,
|
|
103
|
+
version: packageVersionFor(hookScript),
|
|
104
|
+
recordedAt: Date.now(),
|
|
105
|
+
};
|
|
106
|
+
writeAtomic(installRecordPath(), JSON.stringify(record, null, 2));
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
let ensuredFor;
|
|
114
|
+
function ensureLauncher(hookScript) {
|
|
115
|
+
if (ensuredFor !== undefined && ensuredFor === hookScript)
|
|
116
|
+
return launcherPath();
|
|
117
|
+
try {
|
|
118
|
+
const target = launcherPath();
|
|
119
|
+
const source = launcherSource(hookScript);
|
|
120
|
+
let current = null;
|
|
121
|
+
try {
|
|
122
|
+
current = fs.readFileSync(target, "utf8");
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
}
|
|
126
|
+
if (current !== source)
|
|
127
|
+
writeAtomic(target, source);
|
|
128
|
+
if (readInstallRecord()?.hookScript !== hookScript && !recordCurrentInstall(hookScript)) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
ensuredFor = hookScript;
|
|
132
|
+
return target;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function resetLauncherCacheForTests() {
|
|
139
|
+
ensuredFor = undefined;
|
|
140
|
+
}
|
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")) {
|
|
@@ -51,29 +50,6 @@ function parseLimitEventFromTranscript(transcript) {
|
|
|
51
50
|
}
|
|
52
51
|
return found;
|
|
53
52
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Codex's `rate_limit_reached_type` is exactly five values (read off the 0.154
|
|
56
|
-
* binary): `rate_limit_reached`, `workspace_{owner,member}_credits_depleted`
|
|
57
|
-
* and `workspace_{owner,member}_usage_limit_reached`.
|
|
58
|
-
*
|
|
59
|
-
* The split that matters to a reader of the dashboard is "someone must act on
|
|
60
|
-
* money" vs "this dev is throttled and it will reset" — so map on what the
|
|
61
|
-
* snapshot actually asserts, not on the word "credits":
|
|
62
|
-
*
|
|
63
|
-
* - A member out of their OWN allowance is a rate limit. Real snapshots carry
|
|
64
|
-
* `spend_control_reached: null` and `individual_limit: null` — nobody
|
|
65
|
-
* configured a budget, the window is simply used up. Calling that personal
|
|
66
|
-
* spend tells a manager the dev overspent, which is not what happened.
|
|
67
|
-
*
|
|
68
|
-
* Deliberately NOT gated on `individual_limit`: it has only ever been
|
|
69
|
-
* observed null, so its populated shape and meaning are unknown, and a
|
|
70
|
-
* wrong guess reinstates the mislabel this exists to remove. The reason
|
|
71
|
-
* string is the causal signal; `individual_limit` is at best correlative.
|
|
72
|
-
* - A member whose ADMIN capped them (`usage_limit_reached`) is personal spend:
|
|
73
|
-
* there really is a cap, and someone can raise it.
|
|
74
|
-
* - Anything owner-scoped is org spend — the org's allowance or credits are
|
|
75
|
-
* gone and somebody has to act.
|
|
76
|
-
*/
|
|
77
53
|
function codexLimitKind(reason, spendControlReached) {
|
|
78
54
|
if (spendControlReached || reason.startsWith("workspace_owner_"))
|
|
79
55
|
return "org_spend";
|
|
@@ -94,11 +70,6 @@ function codexResetText(rateLimits) {
|
|
|
94
70
|
.sort((a, b) => a - b)[0];
|
|
95
71
|
return resetAt ? new Date(resetAt * 1000).toISOString() : null;
|
|
96
72
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Codex writes a structured RateLimitSnapshot on token_count events. A normal
|
|
99
|
-
* turn has `rate_limit_reached_type: null`; a blocked turn names the exact
|
|
100
|
-
* boundary. Reading that field avoids locale-dependent terminal copy.
|
|
101
|
-
*/
|
|
102
73
|
function parseCodexLimitEventFromTranscript(transcript) {
|
|
103
74
|
let found = null;
|
|
104
75
|
for (const line of transcript.split("\n")) {
|
|
@@ -133,10 +104,45 @@ function parseCodexLimitEventFromTranscript(transcript) {
|
|
|
133
104
|
}
|
|
134
105
|
return found;
|
|
135
106
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
}
|
|
140
146
|
const DEFAULT_TAIL_CHARS = 65536;
|
|
141
147
|
function tailForLimitEvent(transcript, maxChars = DEFAULT_TAIL_CHARS) {
|
|
142
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;
|