codiedev 0.9.80 → 0.10.0-beta.10
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 +12 -5
- 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 +0 -11
- package/dist/cli.js +11 -33
- package/dist/cliSession.js +3 -60
- package/dist/codexHookTrust.js +0 -28
- package/dist/codexLimitScan.js +0 -107
- package/dist/codie.js +64 -57
- package/dist/codieBrandInstall.js +0 -18
- package/dist/codieLauncher.js +1 -72
- package/dist/codieRuntime.js +27 -32
- package/dist/codieRuntimeInstall.js +11 -43
- package/dist/codieUsage.js +0 -49
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1088 -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 +2 -72
- package/dist/commands/evals.js +3 -9
- package/dist/commands/inbox.js +0 -2
- package/dist/commands/library.js +0 -3
- package/dist/commands/pack.js +0 -29
- package/dist/commands/ping.js +0 -2
- package/dist/commands/pull.js +0 -9
- package/dist/commands/push.js +0 -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 +0 -13
- package/dist/commands/tracesLabel.js +0 -8
- package/dist/configDir.js +1 -18
- package/dist/connect.js +3 -75
- package/dist/connectFlow.js +0 -15
- package/dist/copilotHooks.js +0 -67
- package/dist/copilotInstallation.js +0 -1
- package/dist/cursorHooks.js +1 -11
- package/dist/cursorLifecycle.js +1 -7
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +0 -19
- package/dist/hook.js +43 -293
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +0 -50
- package/dist/launcher.js +0 -33
- package/dist/limitEvent.js +2 -34
- package/dist/managedPi.js +2 -50
- package/dist/mcp.js +0 -48
- package/dist/nativeSteering.js +1 -4
- package/dist/packs/codie.js +0 -15
- package/dist/packs/harnesses.js +1 -38
- package/dist/packs/hookGate.js +0 -33
- package/dist/packs/install.js +0 -20
- package/dist/packs/manifest.js +1 -15
- package/dist/packs/paths.js +0 -8
- package/dist/packs/shim.js +0 -8
- package/dist/packs/store.js +0 -12
- package/dist/packs/sync.js +0 -20
- package/dist/piHooks.js +4 -45
- package/dist/piRuntime.js +0 -18
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/selfUpdate.js +2 -77
- package/dist/skillMarker.js +0 -14
- package/dist/subagents.js +0 -18
- package/dist/teamSkillContext.js +0 -1
- package/dist/transcriptModels.js +0 -8
- package/dist/upgradeNudge.js +1 -30
- package/dist/utils.js +165 -768
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +13 -8
- 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 -47
- package/dist/cli.d.ts +0 -15
- package/dist/cliSession.d.ts +0 -108
- package/dist/codexHookTrust.d.ts +0 -49
- 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 -87
- package/dist/codieRuntime.d.ts +0 -35
- package/dist/codieRuntimeInstall.d.ts +0 -56
- package/dist/codieUsage.d.ts +0 -64
- 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 -9
- package/dist/commands/evals.d.ts +0 -3
- 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/pack.d.ts +0 -54
- package/dist/commands/ping.d.ts +0 -1
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/push.d.ts +0 -33
- package/dist/commands/search.d.ts +0 -2
- 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/commands/traces.d.ts +0 -72
- package/dist/commands/tracesLabel.d.ts +0 -24
- package/dist/configDir.d.ts +0 -10
- package/dist/connect.d.ts +0 -1
- package/dist/connectFlow.d.ts +0 -34
- package/dist/copilotHooks.d.ts +0 -85
- package/dist/copilotInstallation.d.ts +0 -10
- package/dist/cursorHooks.d.ts +0 -13
- package/dist/cursorLifecycle.d.ts +0 -2
- package/dist/detection.d.ts +0 -30
- package/dist/harnessDirs.d.ts +0 -15
- package/dist/hook.d.ts +0 -6
- package/dist/inboxFormat.d.ts +0 -38
- package/dist/launchContext.d.ts +0 -46
- package/dist/launcher.d.ts +0 -25
- package/dist/limitEvent.d.ts +0 -15
- package/dist/limitEventReporter.d.ts +0 -21
- package/dist/managedPi.d.ts +0 -48
- package/dist/mcp.d.ts +0 -12
- package/dist/nativeSteering.d.ts +0 -5
- package/dist/packs/codie.d.ts +0 -45
- package/dist/packs/harnesses.d.ts +0 -74
- package/dist/packs/hookGate.d.ts +0 -53
- package/dist/packs/install.d.ts +0 -46
- package/dist/packs/manifest.d.ts +0 -52
- package/dist/packs/paths.d.ts +0 -17
- package/dist/packs/shim.d.ts +0 -26
- package/dist/packs/store.d.ts +0 -42
- package/dist/packs/sync.d.ts +0 -40
- package/dist/piHooks.d.ts +0 -22
- package/dist/piRuntime.d.ts +0 -26
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/selfUpdate.d.ts +0 -64
- package/dist/skillMarker.d.ts +0 -6
- package/dist/subagents.d.ts +0 -36
- package/dist/teamSkillContext.d.ts +0 -9
- package/dist/transcriptModels.d.ts +0 -20
- package/dist/upgradeNudge.d.ts +0 -24
- package/dist/utils.d.ts +0 -396
- package/dist/version.d.ts +0 -1
- package/dist/versionCheck.d.ts +0 -68
package/dist/commands/send.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// `codiedev send <filename> <recipient> [message]` — share an artifact AND
|
|
3
|
-
// send a short message that lands in the teammate's inbox. The active-
|
|
4
|
-
// handoff version of `codiedev share`. Use this when the user is actively
|
|
5
|
-
// looping someone in.
|
|
6
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
3
|
exports.runSend = runSend;
|
|
8
4
|
const shared_1 = require("./shared");
|
|
@@ -13,7 +9,6 @@ function parseArgs(args) {
|
|
|
13
9
|
console.error('Usage: codiedev send <filename> <recipient> ["<message>"]');
|
|
14
10
|
process.exit(1);
|
|
15
11
|
}
|
|
16
|
-
// Recombine remaining tokens — supports both quoted and unquoted messages.
|
|
17
12
|
const message = rest.length > 0 ? (0, shared_1.stripQuotes)(rest.join(" ")) : undefined;
|
|
18
13
|
return { filename, to, message };
|
|
19
14
|
}
|
package/dist/commands/share.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// `codiedev share <filename> <recipient> [--role read|edit]` — silently
|
|
3
|
-
// grant a teammate access to an artifact (no notification). Use
|
|
4
|
-
// `codiedev send` instead when the user wants to actively loop someone in.
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.runShare = runShare;
|
|
7
4
|
const shared_1 = require("./shared");
|
|
@@ -71,7 +68,6 @@ async function runShare(args, configOverride) {
|
|
|
71
68
|
latencyMs: Date.now() - start,
|
|
72
69
|
error: err.message,
|
|
73
70
|
});
|
|
74
|
-
// Ambiguous recipients return 409 with candidates in the body.
|
|
75
71
|
const body = err.body;
|
|
76
72
|
if (body && Array.isArray(body.candidates) && body.candidates.length > 0) {
|
|
77
73
|
console.error(`Recipient "${parsed.to}" is ambiguous. Candidates:`);
|
package/dist/commands/shared.js
CHANGED
|
@@ -45,13 +45,6 @@ const https = __importStar(require("https"));
|
|
|
45
45
|
const http = __importStar(require("http"));
|
|
46
46
|
const utils_1 = require("../utils");
|
|
47
47
|
const version_1 = require("../version");
|
|
48
|
-
/**
|
|
49
|
-
* Layer per-command env overrides on top of the on-disk config. Useful for
|
|
50
|
-
* ad-hoc testing — point a prod-connected CLI at a dev Convex deployment
|
|
51
|
-
* without re-running `codiedev connect`. Both CODIEDEV_URL and CODIEDEV_TOKEN
|
|
52
|
-
* must be set together (half-overrides would mismatch URL and auth realm).
|
|
53
|
-
* Other fields (companyId, repos[]) come from the file unchanged.
|
|
54
|
-
*/
|
|
55
48
|
function applyConfigEnvOverrides(config) {
|
|
56
49
|
const url = process.env.CODIEDEV_URL;
|
|
57
50
|
const token = process.env.CODIEDEV_TOKEN;
|
|
@@ -60,10 +53,6 @@ function applyConfigEnvOverrides(config) {
|
|
|
60
53
|
}
|
|
61
54
|
return config;
|
|
62
55
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Require a connected Codiedev config. Exits the process with a helpful
|
|
65
|
-
* message if the user hasn't run `codiedev connect` yet.
|
|
66
|
-
*/
|
|
67
56
|
function requireConfig() {
|
|
68
57
|
const config = (0, utils_1.readConfig)();
|
|
69
58
|
if (!config) {
|
|
@@ -72,10 +61,6 @@ function requireConfig() {
|
|
|
72
61
|
}
|
|
73
62
|
return applyConfigEnvOverrides(config);
|
|
74
63
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Perform an authenticated HTTP request against the Codiedev backend.
|
|
77
|
-
* Returns the parsed JSON response body. Throws on non-2xx.
|
|
78
|
-
*/
|
|
79
64
|
function apiRequest(method, path, options) {
|
|
80
65
|
return new Promise((resolve, reject) => {
|
|
81
66
|
const base = options.config.backendUrl;
|
|
@@ -135,12 +120,6 @@ function apiRequest(method, path, options) {
|
|
|
135
120
|
req.end();
|
|
136
121
|
});
|
|
137
122
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Fire-and-forget per-invocation telemetry from CLI subcommands. Mirrors
|
|
140
|
-
* the MCP server's emitTelemetry but stamps `source: "cli"` so adoption
|
|
141
|
-
* dashboards can distinguish between the two surfaces. Never blocks the
|
|
142
|
-
* user's command, never throws — telemetry must not change behavior.
|
|
143
|
-
*/
|
|
144
123
|
function recordAgentEvent(config, event) {
|
|
145
124
|
apiRequest("POST", "/api/telemetry/mcp-event", {
|
|
146
125
|
config,
|
|
@@ -153,7 +132,6 @@ function recordAgentEvent(config, event) {
|
|
|
153
132
|
source: "cli",
|
|
154
133
|
},
|
|
155
134
|
}).catch(() => {
|
|
156
|
-
// Swallow — telemetry must never affect user-facing flow.
|
|
157
135
|
});
|
|
158
136
|
}
|
|
159
137
|
function recordInstallEvent(config, event) {
|
|
@@ -169,14 +147,8 @@ function recordInstallEvent(config, event) {
|
|
|
169
147
|
cliVersion: version_1.CLI_VERSION,
|
|
170
148
|
},
|
|
171
149
|
}).catch(() => {
|
|
172
|
-
// Swallow — telemetry must never affect connect flow.
|
|
173
150
|
});
|
|
174
151
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Wraps a CLI subcommand body so success and failure both record telemetry
|
|
177
|
-
* and the original error propagates after the event is queued. Use this in
|
|
178
|
-
* each `runXxx` command instead of inline timing + try/catch boilerplate.
|
|
179
|
-
*/
|
|
180
152
|
async function withTelemetry(config, tool, fn) {
|
|
181
153
|
const start = Date.now();
|
|
182
154
|
try {
|
|
@@ -194,9 +166,6 @@ async function withTelemetry(config, tool, fn) {
|
|
|
194
166
|
throw err;
|
|
195
167
|
}
|
|
196
168
|
}
|
|
197
|
-
/**
|
|
198
|
-
* Relative-time formatter for inbox / listing output.
|
|
199
|
-
*/
|
|
200
169
|
function timeAgo(ts) {
|
|
201
170
|
const diff = Date.now() - ts;
|
|
202
171
|
const mins = Math.floor(diff / 60000);
|
|
@@ -210,10 +179,6 @@ function timeAgo(ts) {
|
|
|
210
179
|
const days = Math.floor(hours / 24);
|
|
211
180
|
return `${days}d ago`;
|
|
212
181
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Strip surrounding quotes from a CLI argument if the user wrapped it.
|
|
215
|
-
* `codiedev ping <name> "hey"` on some shells passes the quotes through.
|
|
216
|
-
*/
|
|
217
182
|
function stripQuotes(s) {
|
|
218
183
|
if ((s.startsWith('"') && s.endsWith('"')) ||
|
|
219
184
|
(s.startsWith("'") && s.endsWith("'"))) {
|
package/dist/commands/traces.js
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// `codiedev traces agents`
|
|
3
|
-
// `codiedev traces cases <agent> [--dataset name] [--model id] [--out dir] [--json]`
|
|
4
|
-
// `codiedev traces report <results.json> [--harness name]`
|
|
5
|
-
// (scores, review queues, automatic scoring and datasets: ./tracesLabel.ts)
|
|
6
|
-
//
|
|
7
|
-
// Test cases are runs an engineer saved from Codiedev → Traces. They run in
|
|
8
|
-
// the engineer's coding agent, not in the portal: `cases` writes them into the
|
|
9
|
-
// repo with a brief the agent follows to replay each one against the agent's
|
|
10
|
-
// own code, optionally on another model (a regression check before a model
|
|
11
|
-
// swap), and a results.json for `report` to send back so Traces shows pass
|
|
12
|
-
// rates by model.
|
|
13
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
3
|
if (k2 === undefined) k2 = k;
|
|
15
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -114,7 +103,6 @@ const recordedModel = (res) => res.cases.flatMap((c) => c.steps.map((s) => s.mod
|
|
|
114
103
|
function slugify(name) {
|
|
115
104
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
|
116
105
|
}
|
|
117
|
-
/** The brief a coding agent follows to run the cases and report back. */
|
|
118
106
|
function casesBrief(res, casesFile, opts = {}) {
|
|
119
107
|
const fix = res.cases.filter((c) => c.kind === "fix");
|
|
120
108
|
const keep = res.cases.filter((c) => c.kind === "keep");
|
|
@@ -148,7 +136,6 @@ function casesBrief(res, casesFile, opts = {}) {
|
|
|
148
136
|
}
|
|
149
137
|
return lines.filter((line, i, all) => !(line === "" && all[i - 1] === "")).join("\n") + "\n";
|
|
150
138
|
}
|
|
151
|
-
/** The results.json a run starts from: every case, passes to be filled in. */
|
|
152
139
|
function resultsTemplate(res, model) {
|
|
153
140
|
return {
|
|
154
141
|
agent: res.agent.name,
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// `codiedev traces overview | runs | run | score | scores | score-kinds |
|
|
3
|
-
// queue | judge | import | add-example | versions | save-version`: what the
|
|
4
|
-
// Traces portal shows and does (agents, runs, failures, scores, review
|
|
5
|
-
// queues, automatic scoring, datasets), so a coding agent can do it from
|
|
6
|
-
// plain words ("put this week's failed runs in the Week 44 queue"). Each
|
|
7
|
-
// calls a /api/cli/traces/* route that runs the portal's own code, with the
|
|
8
|
-
// same permissions.
|
|
9
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
3
|
if (k2 === undefined) k2 = k;
|
|
11
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -83,7 +76,6 @@ function parseArgs(args) {
|
|
|
83
76
|
}
|
|
84
77
|
return out;
|
|
85
78
|
}
|
|
86
|
-
/** "4" → 4, "true" → true, anything else as text (a category). */
|
|
87
79
|
function scoreValue(raw) {
|
|
88
80
|
const t = raw.trim();
|
|
89
81
|
if (/^(true|false)$/i.test(t))
|
package/dist/configDir.js
CHANGED
|
@@ -36,33 +36,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.realHome = realHome;
|
|
37
37
|
exports.pickHome = pickHome;
|
|
38
38
|
exports.codiedevStateDir = codiedevStateDir;
|
|
39
|
-
// Single source of truth for where the CLI's config/state lives on disk.
|
|
40
|
-
//
|
|
41
|
-
// Defaults to ~/.codiedev. The desktop app sets CODIEDEV_CONFIG_DIR to
|
|
42
|
-
// ~/.codiedev-desktop so a desktop session never touches the user's real
|
|
43
|
-
// prod config — env-based (not a flag) so detached capture-finish/upload
|
|
44
|
-
// children inherit the override automatically.
|
|
45
|
-
//
|
|
46
|
-
// Deliberately dependency-free (only node:path/os) so it can be imported
|
|
47
|
-
// by both utils.ts and modules utils.ts itself imports (e.g. captureLog.ts)
|
|
48
|
-
// without creating a circular import.
|
|
49
39
|
const path = __importStar(require("path"));
|
|
50
40
|
const os = __importStar(require("os"));
|
|
51
|
-
/**
|
|
52
|
-
* The user's home, always absolute. $HOME can arrive relative or unexpanded ("~", ".", "") from a
|
|
53
|
-
* sandboxed shell or a wrapper; trusting it once wrote hook commands like ".codiedev/bin/…" into
|
|
54
|
-
* ~/.claude/settings.json, which only resolve when Claude Code starts in the home folder, so
|
|
55
|
-
* capture silently failed in every project. Fall back to the account's home from the OS.
|
|
56
|
-
*/
|
|
57
41
|
function realHome() {
|
|
58
42
|
let fromOs;
|
|
59
43
|
try {
|
|
60
44
|
fromOs = os.userInfo().homedir;
|
|
61
45
|
}
|
|
62
|
-
catch {
|
|
46
|
+
catch { }
|
|
63
47
|
return pickHome(os.homedir(), fromOs);
|
|
64
48
|
}
|
|
65
|
-
/** $HOME when it's a real absolute path, else the OS account's home, else resolved against cwd. */
|
|
66
49
|
function pickHome(fromEnv, fromOs) {
|
|
67
50
|
if (fromEnv && path.isAbsolute(fromEnv) && !fromEnv.split(path.sep).includes("~"))
|
|
68
51
|
return fromEnv;
|
package/dist/connect.js
CHANGED
|
@@ -47,21 +47,7 @@ const version_1 = require("./version");
|
|
|
47
47
|
const upgradeNudge_1 = require("./upgradeNudge");
|
|
48
48
|
const shared_1 = require("./commands/shared");
|
|
49
49
|
const harnessDirs_1 = require("./harnessDirs");
|
|
50
|
-
// cli.codiedev.com is a Convex custom domain on the prod deployment; the
|
|
51
|
-
// underlying judicious-falcon-861.convex.site URL keeps serving, so configs
|
|
52
|
-
// written by older CLI versions stay valid without a re-connect.
|
|
53
50
|
const BACKEND_URL = process.env.CODIEDEV_URL || "https://cli.codiedev.com";
|
|
54
|
-
/**
|
|
55
|
-
* Reads a line from stdin without echoing the typed/pasted characters —
|
|
56
|
-
* for tokens, passwords, anything that shouldn't end up in terminal
|
|
57
|
-
* scrollback or screenshots. Echoes `*` per character so the user gets
|
|
58
|
-
* visual feedback that input is being received.
|
|
59
|
-
*
|
|
60
|
-
* Falls back to the regular `prompt()` if stdin isn't a TTY (e.g., piped
|
|
61
|
-
* input in CI). Without a TTY there's no echo to suppress anyway, and
|
|
62
|
-
* raw mode would error.
|
|
63
|
-
*/
|
|
64
|
-
/** One visible line from the terminal (for yes/no questions). */
|
|
65
51
|
function prompt(question) {
|
|
66
52
|
return new Promise((resolve) => {
|
|
67
53
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -76,7 +62,6 @@ function promptHidden(question) {
|
|
|
76
62
|
const stdin = process.stdin;
|
|
77
63
|
const stdout = process.stdout;
|
|
78
64
|
if (!stdin.isTTY) {
|
|
79
|
-
// CI / piped input — no terminal to mute. Fall back to readline.
|
|
80
65
|
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
81
66
|
rl.question(question, (answer) => {
|
|
82
67
|
rl.close();
|
|
@@ -93,23 +78,18 @@ function promptHidden(question) {
|
|
|
93
78
|
};
|
|
94
79
|
const onData = (chunk) => {
|
|
95
80
|
const key = chunk.toString("utf8");
|
|
96
|
-
// Iterate so a single `chunk` containing a multi-char paste still
|
|
97
|
-
// masks each character individually.
|
|
98
81
|
for (const ch of key) {
|
|
99
|
-
// Ctrl+C — abort like a normal terminal interrupt.
|
|
100
82
|
if (ch === "") {
|
|
101
83
|
cleanup();
|
|
102
84
|
stdout.write("\n");
|
|
103
85
|
process.exit(130);
|
|
104
86
|
}
|
|
105
|
-
// Enter — finalize.
|
|
106
87
|
if (ch === "\r" || ch === "\n") {
|
|
107
88
|
cleanup();
|
|
108
89
|
stdout.write("\n");
|
|
109
90
|
resolve(buf.trim());
|
|
110
91
|
return;
|
|
111
92
|
}
|
|
112
|
-
// Backspace / DEL — erase one masked char.
|
|
113
93
|
if (ch === "" || ch === "\b") {
|
|
114
94
|
if (buf.length > 0) {
|
|
115
95
|
buf = buf.slice(0, -1);
|
|
@@ -117,7 +97,6 @@ function promptHidden(question) {
|
|
|
117
97
|
}
|
|
118
98
|
continue;
|
|
119
99
|
}
|
|
120
|
-
// Ignore other control bytes (escape sequences from arrow keys, etc.)
|
|
121
100
|
if (ch.charCodeAt(0) < 0x20)
|
|
122
101
|
continue;
|
|
123
102
|
buf += ch;
|
|
@@ -173,24 +152,13 @@ function postJson(url, body, extraHeaders = {}) {
|
|
|
173
152
|
});
|
|
174
153
|
}
|
|
175
154
|
async function runConnect(args = []) {
|
|
176
|
-
// `--force` (or `-f`) re-prompts for a token even if `~/.codiedev/config.json`
|
|
177
|
-
// already has one. Default behavior reuses the saved token so users can
|
|
178
|
-
// re-run `connect` (e.g., after installing Claude Code) without having to
|
|
179
|
-
// mint a fresh token from the portal — which is what bit Sonifi's first
|
|
180
|
-
// engineer when he interpreted "no visible token" as "the old one is gone".
|
|
181
155
|
const force = args.includes("--force") || args.includes("-f");
|
|
182
|
-
// `--token`: paste an API token instead of signing in (CI). Otherwise sign
|
|
183
|
-
// in with the browser: a loopback redirect on a desktop, a device code
|
|
184
|
-
// (approve on any device) over SSH or with no display, detected
|
|
185
|
-
// automatically. `--no-browser` / `--browser` force one or the other.
|
|
186
156
|
const pasteToken = args.includes("--token");
|
|
187
157
|
const useDevice = args.includes("--no-browser") || (!args.includes("--browser") && (0, cliSession_1.isHeadless)());
|
|
188
158
|
console.log("\nWelcome to Codiedev CLI\n");
|
|
189
159
|
await (0, upgradeNudge_1.maybePrintUpgradeNudge)();
|
|
190
160
|
console.log("This will connect your coding agent to your Codiedev workspace and install");
|
|
191
161
|
console.log("the session capture hook for org-wide session sharing.\n");
|
|
192
|
-
// A saved browser sign-in is reused only if it still works: refresh it
|
|
193
|
-
// first (a revoked one comes back signed out, with an empty token).
|
|
194
162
|
await (0, cliSession_1.ensureFreshToken)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
|
|
195
163
|
const saved = (0, utils_1.readConfig)();
|
|
196
164
|
const decision = (0, connectFlow_1.resolveConnectToken)({ savedConfig: saved, force: force || pasteToken });
|
|
@@ -204,8 +172,6 @@ async function runConnect(args = []) {
|
|
|
204
172
|
: `Reusing API token from ~/.codiedev/config.json (run with --force to sign in again).\n`);
|
|
205
173
|
}
|
|
206
174
|
else if (!pasteToken) {
|
|
207
|
-
// Replacing a browser sign-in: end the old one so the portal doesn't
|
|
208
|
-
// keep listing it.
|
|
209
175
|
if (saved?.auth)
|
|
210
176
|
await (0, cliSession_1.logout)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
|
|
211
177
|
const result = await (0, connectFlow_1.signInWithTokenFallback)({
|
|
@@ -222,8 +188,6 @@ async function runConnect(args = []) {
|
|
|
222
188
|
auth = result.auth;
|
|
223
189
|
}
|
|
224
190
|
else {
|
|
225
|
-
// Hidden prompt — masks the token with `*` as it's typed/pasted so it
|
|
226
|
-
// doesn't end up in terminal scrollback or screenshots.
|
|
227
191
|
token = await promptHidden("Enter your Codiedev API token: ");
|
|
228
192
|
if (!token) {
|
|
229
193
|
console.error("Error: API token is required.");
|
|
@@ -241,7 +205,6 @@ async function runConnect(args = []) {
|
|
|
241
205
|
console.error(`\nError: Failed to validate token — ${err.message}`);
|
|
242
206
|
process.exit(1);
|
|
243
207
|
}
|
|
244
|
-
// Extract fields from response
|
|
245
208
|
const companyId = responseData.companyId;
|
|
246
209
|
const companyName = responseData.companyName;
|
|
247
210
|
const repos = responseData.repos ?? [];
|
|
@@ -268,15 +231,7 @@ async function runConnect(args = []) {
|
|
|
268
231
|
console.error(`\nError: Failed to save config — ${err.message}`);
|
|
269
232
|
process.exit(1);
|
|
270
233
|
}
|
|
271
|
-
// Once we have a valid token + config, every subsequent step posts a
|
|
272
|
-
// per-step row to /api/telemetry/install-event so the admin page can show
|
|
273
|
-
// a timeline when a customer says "it connected but it doesn't work."
|
|
274
|
-
// Fire-and-forget — never blocks the connect flow.
|
|
275
234
|
(0, shared_1.recordInstallEvent)(config, { step: "started", ok: true });
|
|
276
|
-
// One-way device status sync. Local config remains authoritative: a network
|
|
277
|
-
// failure here never removes or weakens an ignored path. This also registers
|
|
278
|
-
// a freshly connected device with an empty list so the portal can distinguish
|
|
279
|
-
// "connected, no exclusions" from "old CLI has never reported status".
|
|
280
235
|
try {
|
|
281
236
|
await postJson(`${BACKEND_URL}/api/cli/capture-exclusions`, {
|
|
282
237
|
deviceId: config.deviceId,
|
|
@@ -287,17 +242,6 @@ async function runConnect(args = []) {
|
|
|
287
242
|
catch (err) {
|
|
288
243
|
console.warn(`Warning: Local capture settings are active, but portal status did not sync — ${err.message}`);
|
|
289
244
|
}
|
|
290
|
-
// Migration: strip MCP server entries written by pre-CLI-only versions
|
|
291
|
-
// of `codiedev connect`. These pointed at `npx codiedev-mcp`, a binary
|
|
292
|
-
// that was removed in 0.3.4 and that 0.7.11+ no longer ships. Without
|
|
293
|
-
// cleanup, customers upgrading from any prior version see persistent
|
|
294
|
-
// "MCP server failed to start" errors in their agent UIs even though
|
|
295
|
-
// the CLI works fine. Each helper is idempotent and a no-op when the
|
|
296
|
-
// relevant config file doesn't exist.
|
|
297
|
-
//
|
|
298
|
-
// Each call is wrapped because the user's upgrade path matters more
|
|
299
|
-
// than the cleanup. A locked / wrong-owner config file (rare but real)
|
|
300
|
-
// shouldn't block the install loop or strand them on an old version.
|
|
301
245
|
for (const [label, fn] of [
|
|
302
246
|
["Claude Code", utils_1.cleanupClaudeCodeMcp],
|
|
303
247
|
["Codex", utils_1.cleanupCodexMcp],
|
|
@@ -325,13 +269,7 @@ async function runConnect(args = []) {
|
|
|
325
269
|
(0, shared_1.recordInstallEvent)(config, { step: "detect", target: "copilot", ok: hasCopilot });
|
|
326
270
|
(0, shared_1.recordInstallEvent)(config, { step: "detect", target: "pi", ok: hasPi });
|
|
327
271
|
const installed = [];
|
|
328
|
-
// Machine-readable target keys reported back to the backend via
|
|
329
|
-
// /api/cli/markInstalled so the portal's "Connected" state reflects
|
|
330
|
-
// what's actually wired up on this machine, not just "token validated."
|
|
331
272
|
const installedTargets = [];
|
|
332
|
-
// Wrap each per-target write so we emit one install_target row each. The
|
|
333
|
-
// existing user-visible behavior (console.warn on failure, continue) is
|
|
334
|
-
// unchanged — telemetry just observes the outcome.
|
|
335
273
|
const runInstall = (target, fn, label, targetKey) => {
|
|
336
274
|
try {
|
|
337
275
|
fn();
|
|
@@ -362,26 +300,15 @@ async function runConnect(args = []) {
|
|
|
362
300
|
runInstall("cursor-hook", utils_1.installCursorHook, "Cursor sessionStart + stop backup + sessionEnd capture hooks (~/.cursor/hooks.json)", "cursor-hook");
|
|
363
301
|
runInstall("cursor-instructions", utils_1.installCursorInstructions, "Cursor agent instructions (~/.cursor/rules/codiedev.mdc)", "cursor-instructions");
|
|
364
302
|
}
|
|
365
|
-
// One user-level hook file covers both VS Code Copilot Chat and the Copilot
|
|
366
|
-
// CLI (they share the runtime and its hooks).
|
|
367
303
|
if (hasCopilot) {
|
|
368
|
-
runInstall("copilot-hook",
|
|
304
|
+
runInstall("copilot-hook", utils_1.installCopilotHook, `GitHub Copilot (VS Code + CLI) sessionStart + agentStop backup + sessionEnd capture hooks (${(0, utils_1.copilotHooksPath)()})`, "copilot-hook");
|
|
369
305
|
runInstall("copilot-instructions", utils_1.installCopilotInstructions, "GitHub Copilot CLI team artifact instructions", "copilot-instructions");
|
|
370
306
|
}
|
|
371
|
-
|
|
372
|
-
// later needs no second `connect`.
|
|
373
|
-
runInstall("pi-extension", () => (0, utils_1.installPiExtension)(), `pi session start + prompt guard + capture extension (${(0, harnessDirs_1.displayPath)((0, utils_1.piExtensionPath)())})`, "pi-extension");
|
|
307
|
+
runInstall("pi-extension", utils_1.installPiExtension, `pi session start + skill discovery + capture extension (${(0, harnessDirs_1.displayPath)((0, utils_1.piExtensionPath)())})`, "pi-extension");
|
|
374
308
|
if (hasPi) {
|
|
375
309
|
runInstall("pi-instructions", utils_1.installPiInstructions, `pi agent instructions (${(0, harnessDirs_1.displayPath)((0, utils_1.piInstructionsPath)())})`, "pi-instructions");
|
|
376
310
|
}
|
|
377
|
-
// Always stage the adapter. It is dormant until OpenCode starts, which lets
|
|
378
|
-
// a user connect Claude Code today and install the Codie harness tomorrow
|
|
379
|
-
// without needing a second setup ritual.
|
|
380
311
|
runInstall("opencode-capture-adapter", utils_1.installOpenCodeCapturePlugin, `OpenCode session capture adapter (${(0, harnessDirs_1.displayPath)(path.join((0, harnessDirs_1.openCodeConfigDir)(), "plugins", "codiedev.js"))})`, "opencode-capture");
|
|
381
|
-
// Tell the backend which targets we wired up so the portal's onboarding
|
|
382
|
-
// card flips to "Connected" only when something actually installed —
|
|
383
|
-
// not on bare token validation. Best-effort: a network failure here
|
|
384
|
-
// doesn't undo the local install, and `codiedev doctor` still works.
|
|
385
312
|
if (installedTargets.length > 0) {
|
|
386
313
|
try {
|
|
387
314
|
await postJson(`${BACKEND_URL}/api/cli/markInstalled`, {
|
|
@@ -416,5 +343,6 @@ async function runConnect(args = []) {
|
|
|
416
343
|
}
|
|
417
344
|
console.log();
|
|
418
345
|
console.log("Run `codiedev doctor` to verify everything's wired up.");
|
|
346
|
+
console.log("If `codiedev` is not on PATH, run `npx codiedev@latest doctor` instead.");
|
|
419
347
|
console.log();
|
|
420
348
|
}
|
package/dist/connectFlow.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Pure helper for `npx codiedev connect` — decides where the API token
|
|
3
|
-
// comes from. Splitting this out lets us TDD the policy (re-use vs. re-prompt)
|
|
4
|
-
// without touching readline or fs at all.
|
|
5
|
-
//
|
|
6
|
-
// Motivation: Jackson hit a confusing flow where he had a working token in
|
|
7
|
-
// `~/.codiedev/config.json`, re-ran `connect` (to pick up Claude Code that
|
|
8
|
-
// he'd just installed), and was forced to paste a token again. Since the
|
|
9
|
-
// portal only displays the plaintext on creation, his only option was to
|
|
10
|
-
// generate a new one — leaving him thinking the old one had been lost.
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.resolveConnectToken = resolveConnectToken;
|
|
13
4
|
exports.signInWithTokenFallback = signInWithTokenFallback;
|
|
@@ -20,12 +11,6 @@ function resolveConnectToken(input) {
|
|
|
20
11
|
return { source: "prompt-required" };
|
|
21
12
|
return { source: "reused", token: input.savedConfig.token };
|
|
22
13
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Browser sign-in, with the API-token paste as the way out: if the browser
|
|
25
|
-
* flow fails (blocked page, expired code, proxy) an interactive user is asked
|
|
26
|
-
* whether to paste a token instead, rather than being sent to rerun connect.
|
|
27
|
-
* Returns null when there's nothing to continue with (caller exits 1).
|
|
28
|
-
*/
|
|
29
14
|
async function signInWithTokenFallback(deps) {
|
|
30
15
|
deps.log("Prefer an API token? Press Ctrl+C and run `codiedev connect --token`.\n");
|
|
31
16
|
try {
|
package/dist/copilotHooks.js
CHANGED
|
@@ -41,23 +41,12 @@ exports.parseCopilotWorkspace = parseCopilotWorkspace;
|
|
|
41
41
|
exports.readCopilotWorkspace = readCopilotWorkspace;
|
|
42
42
|
exports.copilotLaunch = copilotLaunch;
|
|
43
43
|
exports.normalizeCopilotHookInput = normalizeCopilotHookInput;
|
|
44
|
-
exports.copilotPreToolBlockResponse = copilotPreToolBlockResponse;
|
|
45
44
|
exports.isCopilotTranscriptEmpty = isCopilotTranscriptEmpty;
|
|
46
45
|
exports.hasCopilotShutdown = hasCopilotShutdown;
|
|
47
46
|
exports.normalizeCopilotTranscript = normalizeCopilotTranscript;
|
|
48
47
|
const fs = __importStar(require("node:fs"));
|
|
49
48
|
const os = __importStar(require("node:os"));
|
|
50
49
|
const path = __importStar(require("node:path"));
|
|
51
|
-
/**
|
|
52
|
-
* GitHub Copilot: VS Code Copilot Chat's agent and the Copilot CLI run on the
|
|
53
|
-
* same runtime and write the same session record,
|
|
54
|
-
* `$COPILOT_HOME/session-state/<sessionId>/events.jsonl` (plus
|
|
55
|
-
* `workspace.yaml`), and both read user hooks from `$COPILOT_HOME/hooks/*.json`.
|
|
56
|
-
* Everything Copilot-specific is translated here, at the process boundary, so
|
|
57
|
-
* the shared capture pipeline only ever sees the Claude-shaped transcript it
|
|
58
|
-
* already parses.
|
|
59
|
-
*/
|
|
60
|
-
/** `$COPILOT_HOME`, else `~/.copilot` (the runtime honours the same variable). */
|
|
61
50
|
function copilotHome(env = process.env, home = os.homedir()) {
|
|
62
51
|
const override = env.COPILOT_HOME?.trim();
|
|
63
52
|
return override ? path.resolve(override) : path.join(home, ".copilot");
|
|
@@ -66,12 +55,10 @@ const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
|
66
55
|
function copilotSessionDir(sessionId, home = copilotHome()) {
|
|
67
56
|
return SESSION_ID.test(sessionId) ? path.join(home, "session-state", sessionId) : undefined;
|
|
68
57
|
}
|
|
69
|
-
/** sessionEnd carries no transcript path; the session id names the file. */
|
|
70
58
|
function copilotTranscriptPath(sessionId, home = copilotHome()) {
|
|
71
59
|
const dir = sessionId ? copilotSessionDir(sessionId, home) : undefined;
|
|
72
60
|
return dir ? path.join(dir, "events.jsonl") : undefined;
|
|
73
61
|
}
|
|
74
|
-
/** workspace.yaml is flat `key: value` lines; no YAML dependency needed. */
|
|
75
62
|
function parseCopilotWorkspace(yaml) {
|
|
76
63
|
const fields = new Map();
|
|
77
64
|
for (const line of yaml.split(/\r?\n/)) {
|
|
@@ -93,7 +80,6 @@ function parseCopilotWorkspace(yaml) {
|
|
|
93
80
|
...(pick("client_name") ? { clientName: pick("client_name") } : {}),
|
|
94
81
|
};
|
|
95
82
|
}
|
|
96
|
-
/** The workspace.yaml beside a transcript (or for a session id); {} if absent. */
|
|
97
83
|
function readCopilotWorkspace(transcriptPathOrDir) {
|
|
98
84
|
if (!transcriptPathOrDir)
|
|
99
85
|
return {};
|
|
@@ -107,25 +93,12 @@ function readCopilotWorkspace(transcriptPathOrDir) {
|
|
|
107
93
|
}
|
|
108
94
|
exports.COPILOT_VSCODE_CLIENT = "vscode-agent-host";
|
|
109
95
|
const isVSCodeClient = (name) => name === exports.COPILOT_VSCODE_CLIENT || name === "vscode";
|
|
110
|
-
/**
|
|
111
|
-
* How the session was launched. VS Code names itself in workspace.yaml; the
|
|
112
|
-
* CLI doesn't record whether it ran headless, so that comes from the process
|
|
113
|
-
* that launched the hook (`detected`, see launchContext). Unknown stays
|
|
114
|
-
* unknown rather than guessing "human".
|
|
115
|
-
*/
|
|
116
96
|
function copilotLaunch(clientName, detected) {
|
|
117
97
|
if (isVSCodeClient(clientName))
|
|
118
98
|
return "copilot:vscode";
|
|
119
99
|
return detected;
|
|
120
100
|
}
|
|
121
101
|
const firstString = (...values) => values.find((value) => typeof value === "string" && value.trim().length > 0);
|
|
122
|
-
/**
|
|
123
|
-
* Copilot's hook payloads are camelCase (`sessionId`, `transcriptPath`,
|
|
124
|
-
* `toolName`/`toolArgs`/`toolResult`); preToolUse in the CLI batches calls as
|
|
125
|
-
* `toolCalls: [{id, name, args}]`. Translate to the shared snake_case shape.
|
|
126
|
-
* The FIRST tool call fills tool_name/tool_input; `copilotToolCalls` keeps all
|
|
127
|
-
* of them so security can check each.
|
|
128
|
-
*/
|
|
129
102
|
function normalizeCopilotHookInput(input, home = copilotHome()) {
|
|
130
103
|
const sessionId = firstString(input.session_id, input.sessionId);
|
|
131
104
|
const transcriptPath = firstString(input.transcript_path, input.transcriptPath)
|
|
@@ -166,21 +139,12 @@ function copilotToolCalls(input) {
|
|
|
166
139
|
const name = firstString(input.toolName, input.tool_name);
|
|
167
140
|
return name ? [{ name, input: parse(input.toolArgs ?? input.tool_input) }] : [];
|
|
168
141
|
}
|
|
169
|
-
/** Copilot's preToolUse deny output. */
|
|
170
|
-
function copilotPreToolBlockResponse(reason) {
|
|
171
|
-
return { permissionDecision: "deny", permissionDecisionReason: reason };
|
|
172
|
-
}
|
|
173
|
-
/** Only a byte-empty record is safe to discard (same rule as Cursor). */
|
|
174
142
|
function isCopilotTranscriptEmpty(content) {
|
|
175
143
|
return content.trim().length === 0;
|
|
176
144
|
}
|
|
177
|
-
/** session.shutdown carries the per-model token totals; written after sessionEnd. */
|
|
178
145
|
function hasCopilotShutdown(content) {
|
|
179
146
|
return content.includes('"session.shutdown"');
|
|
180
147
|
}
|
|
181
|
-
// Copilot tool names → the Claude names the shared parsers key on (Bash
|
|
182
|
-
// commands for git output and worktree dirs; Edit/Write for the dirs a session
|
|
183
|
-
// wrote to). Anything else keeps Copilot's own name.
|
|
184
148
|
function claudeTool(name, args) {
|
|
185
149
|
const a = (args && typeof args === "object" ? args : {});
|
|
186
150
|
const lower = name.toLowerCase();
|
|
@@ -195,15 +159,11 @@ function claudeTool(name, args) {
|
|
|
195
159
|
return { name: "Write", input: { ...a, file_path: file } };
|
|
196
160
|
if (lower === "view" && file)
|
|
197
161
|
return { name: "Read", input: { ...a, file_path: file } };
|
|
198
|
-
// The skill tool's runs are counted from skill.invoked (which also covers
|
|
199
|
-
// skills the user invoked directly); drop its argument so it isn't counted twice.
|
|
200
162
|
if (lower === "skill")
|
|
201
163
|
return { name: "skill", input: {} };
|
|
202
164
|
return { name, input: args ?? {} };
|
|
203
165
|
}
|
|
204
166
|
const num = (value) => (typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0);
|
|
205
|
-
/** Image-only prompts have empty content. Keep attachment descriptions without
|
|
206
|
-
* reading local files, uploading image bytes, or inventing OCR prompt text. */
|
|
207
167
|
function copilotUserContent(data) {
|
|
208
168
|
const content = [];
|
|
209
169
|
if (typeof data.content === "string" && data.content)
|
|
@@ -249,27 +209,11 @@ function sumAgentMetrics(agents) {
|
|
|
249
209
|
}
|
|
250
210
|
return Object.fromEntries(Object.entries(totals).map(([model, usage]) => [model, { usage }]));
|
|
251
211
|
}
|
|
252
|
-
/**
|
|
253
|
-
* events.jsonl → Claude-shaped JSONL:
|
|
254
|
-
* session.start → system record (cwd, branch, entrypoint for VS Code)
|
|
255
|
-
* user.message → user text
|
|
256
|
-
* assistant.message → assistant text + tool_use blocks (model on every call)
|
|
257
|
-
* tool.execution_complete→ user tool_result (git output feeds branch/sha joins)
|
|
258
|
-
* skill.invoked → copilot.skill_invoked (one skill run)
|
|
259
|
-
* session.shutdown → copilot.usage per model (tokens, sub-agents
|
|
260
|
-
* included; requests counted from the assistant
|
|
261
|
-
* calls, so 0 here) + copilot.usage_summary
|
|
262
|
-
* session.usage_checkpoint → copilot.usage_summary (premium requests and
|
|
263
|
-
* nano-AIU so far; superseded by shutdown)
|
|
264
|
-
* subagent.started → counted as a fleet sub-agent
|
|
265
|
-
* Hooks, permissions, system prompts and checkpoints are dropped.
|
|
266
|
-
*/
|
|
267
212
|
function normalizeCopilotTranscript(raw, opts = {}) {
|
|
268
213
|
const out = [];
|
|
269
214
|
const subagentCalls = new Set();
|
|
270
215
|
let shutdownAgents = 0;
|
|
271
216
|
let assistantModel = false;
|
|
272
|
-
// Copilot's subscription usage: the latest checkpoint, superseded by shutdown.
|
|
273
217
|
let premium;
|
|
274
218
|
let checkpointModels = [];
|
|
275
219
|
let final = false;
|
|
@@ -351,9 +295,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
|
|
|
351
295
|
id: firstString(data.apiCallId, data.messageId, uuid),
|
|
352
296
|
role: "assistant",
|
|
353
297
|
content,
|
|
354
|
-
// One model call. Copilot reports tokens only at shutdown. A record
|
|
355
|
-
// with no model is the runtime's own step (e.g. read_agent after a
|
|
356
|
-
// fleet sub-agent finishes), not a model call, so it isn't counted.
|
|
357
298
|
...(typeof data.model === "string" && data.model
|
|
358
299
|
? {
|
|
359
300
|
model: data.model,
|
|
@@ -368,8 +309,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
|
|
|
368
309
|
if (data.error?.code === "user_denied") {
|
|
369
310
|
out.push(JSON.stringify({ type: "agent.rejection", ...base, id: data.toolCallId ?? uuid }));
|
|
370
311
|
}
|
|
371
|
-
// A space after the array bracket keeps the shared git-output scan
|
|
372
|
-
// (`[branch sha]` commit lines) from anchoring on JSON's own "[".
|
|
373
312
|
out.push(JSON.stringify({
|
|
374
313
|
type: "user",
|
|
375
314
|
...base,
|
|
@@ -394,8 +333,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
|
|
|
394
333
|
premium = premiumOf(data, timestamp);
|
|
395
334
|
const agents = Object.entries(data.agentMetrics ?? {});
|
|
396
335
|
shutdownAgents = agents.filter(([agent]) => agent !== "main").length;
|
|
397
|
-
// modelMetrics is the whole session, sub-agents included; older
|
|
398
|
-
// records without it are summed from the per-agent metrics.
|
|
399
336
|
const metrics = data.modelMetrics ?? sumAgentMetrics(agents.map(([, agent]) => agent?.modelMetrics));
|
|
400
337
|
for (const [model, metric] of Object.entries(metrics)) {
|
|
401
338
|
const usage = metric?.usage ?? {};
|
|
@@ -410,8 +347,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
|
|
|
410
347
|
id: `copilot-usage:${model}`,
|
|
411
348
|
model,
|
|
412
349
|
usage: {
|
|
413
|
-
// Copilot's inputTokens include the cached prompt; the shared
|
|
414
|
-
// shape counts fresh input separately from cache reads.
|
|
415
350
|
input_tokens: Math.max(0, num(usage.inputTokens) - cacheRead),
|
|
416
351
|
output_tokens: num(usage.outputTokens),
|
|
417
352
|
cache_read_input_tokens: cacheRead,
|
|
@@ -426,8 +361,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
|
|
|
426
361
|
break;
|
|
427
362
|
}
|
|
428
363
|
}
|
|
429
|
-
// No model on any assistant call (seen in open VS Code chats): name the
|
|
430
|
-
// models from the last checkpoint. No tokens are invented; requests stay 0.
|
|
431
364
|
if (!assistantModel) {
|
|
432
365
|
for (const model of checkpointModels) {
|
|
433
366
|
out.push(JSON.stringify({
|
|
@@ -49,7 +49,6 @@ function inspectCopilotHooks(file = path.join((0, copilotHooks_1.copilotHome)(),
|
|
|
49
49
|
const missing = expected.filter(([event, subcommand]) => {
|
|
50
50
|
const entries = parsed.hooks?.[event];
|
|
51
51
|
return !Array.isArray(entries) || !entries.some((entry) => {
|
|
52
|
-
// Both platforms must have the managed command, not just the current one.
|
|
53
52
|
const commands = [entry.bash ?? entry.command, entry.powershell ?? entry.command];
|
|
54
53
|
return commands.every((command) => typeof command === "string"
|
|
55
54
|
&& (0, detection_1.isCodiedevHookCommand)(command) && command.trim().endsWith(subcommand));
|