codiedev 0.6.0 → 0.7.0
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/dist/commands/doctor.js +10 -5
- package/dist/connect.js +21 -2
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +117 -38
- package/package.json +6 -2
package/dist/commands/doctor.js
CHANGED
|
@@ -76,6 +76,14 @@ function hasCursorMcpEntry() {
|
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
// Match both legacy `npx codiedev-hook ...` and absolute-path forms
|
|
80
|
+
// `<node> <.../codiedev/dist/hook.js> ...` — installer switched to absolute
|
|
81
|
+
// paths in 0.6.1 to work in GUI-launched contexts where shell PATH is missing.
|
|
82
|
+
function isCodiedevHookCommand(cmd) {
|
|
83
|
+
if (!cmd)
|
|
84
|
+
return false;
|
|
85
|
+
return cmd.includes("codiedev-hook") || /codiedev[\\/]dist[\\/]hook/.test(cmd);
|
|
86
|
+
}
|
|
79
87
|
// Cursor's hooks.json schema is { hooks: { sessionEnd: [{ command, ... }] } }
|
|
80
88
|
// — flat array of objects with `command`, not the Claude/Codex nested
|
|
81
89
|
// `{ hooks: [{ command }] }` wrapper.
|
|
@@ -88,10 +96,7 @@ function hasCursorHook() {
|
|
|
88
96
|
const arr = parsed.hooks?.sessionEnd;
|
|
89
97
|
if (!Array.isArray(arr))
|
|
90
98
|
return false;
|
|
91
|
-
return arr.some((h) =>
|
|
92
|
-
const cmd = h.command;
|
|
93
|
-
return (cmd ?? "").includes("codiedev-hook");
|
|
94
|
-
});
|
|
99
|
+
return arr.some((h) => isCodiedevHookCommand(h.command));
|
|
95
100
|
}
|
|
96
101
|
catch {
|
|
97
102
|
return false;
|
|
@@ -110,7 +115,7 @@ function hasCodiedevHook(settingsPath, hookKey) {
|
|
|
110
115
|
const inner = h.hooks;
|
|
111
116
|
if (!Array.isArray(inner))
|
|
112
117
|
return false;
|
|
113
|
-
return inner.some((x) => (x.command
|
|
118
|
+
return inner.some((x) => isCodiedevHookCommand(x.command));
|
|
114
119
|
});
|
|
115
120
|
}
|
|
116
121
|
catch {
|
package/dist/connect.js
CHANGED
|
@@ -142,7 +142,9 @@ async function runConnect() {
|
|
|
142
142
|
const hasClaude = (0, utils_1.claudeCodeInstalled)();
|
|
143
143
|
const hasCodex = (0, utils_1.codexInstalled)();
|
|
144
144
|
const hasCursor = (0, utils_1.cursorInstalled)();
|
|
145
|
+
const hasVSCodeCopilot = (0, utils_1.vscodeCopilotInstalled)();
|
|
145
146
|
const installed = [];
|
|
147
|
+
let vscodeMcpInstalled = false;
|
|
146
148
|
if (hasClaude) {
|
|
147
149
|
try {
|
|
148
150
|
(0, utils_1.installHook)();
|
|
@@ -212,8 +214,18 @@ async function runConnect() {
|
|
|
212
214
|
console.error(`\nWarning: Failed to install Cursor MCP server — ${err.message}`);
|
|
213
215
|
}
|
|
214
216
|
}
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
+
if (hasVSCodeCopilot) {
|
|
218
|
+
try {
|
|
219
|
+
(0, utils_1.installVSCodeMcp)();
|
|
220
|
+
installed.push("VS Code Copilot MCP server (~/Library/Application Support/Code/User/mcp.json)");
|
|
221
|
+
vscodeMcpInstalled = true;
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
console.error(`\nWarning: Failed to install VS Code Copilot MCP server — ${err.message}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!hasClaude && !hasCodex && !hasCursor && !hasVSCodeCopilot) {
|
|
228
|
+
console.warn("\nNo Claude Code (~/.claude), Codex (~/.codex), Cursor (~/.cursor), or VS Code Copilot install detected.");
|
|
217
229
|
console.warn("Config saved. Install one, then re-run `npx codiedev connect` to wire up capture hooks.");
|
|
218
230
|
}
|
|
219
231
|
console.log(`\nConnected to ${companyName}`);
|
|
@@ -225,6 +237,13 @@ async function runConnect() {
|
|
|
225
237
|
}
|
|
226
238
|
console.log("Sessions will be captured automatically.");
|
|
227
239
|
}
|
|
240
|
+
if (vscodeMcpInstalled) {
|
|
241
|
+
console.log();
|
|
242
|
+
console.log("VS Code: open Copilot Chat — it will prompt you to trust the codiedev MCP server.");
|
|
243
|
+
console.log("Click Allow once, then ask Copilot: \"create a reverse ticket from my current changes\".");
|
|
244
|
+
console.log("Note: Copilot doesn't expose chat transcripts to MCP, so on-demand tools (reverse_ticket,");
|
|
245
|
+
console.log("push, pull, ask, ping) work fully — auto-captured decisions need Claude Code or Codex.");
|
|
246
|
+
}
|
|
228
247
|
console.log();
|
|
229
248
|
console.log("Run `codiedev doctor` to verify everything's wired up.");
|
|
230
249
|
console.log();
|
package/dist/utils.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ export declare function hashToken(token: string): string;
|
|
|
27
27
|
export declare function claudeCodeInstalled(): boolean;
|
|
28
28
|
export declare function codexInstalled(): boolean;
|
|
29
29
|
export declare function cursorInstalled(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* VS Code with the GitHub Copilot Chat extension installed. The extension
|
|
32
|
+
* directory pattern is `~/.vscode/extensions/github.copilot-chat-*`. We treat
|
|
33
|
+
* the presence of any `github.copilot*` directory as the Copilot fingerprint.
|
|
34
|
+
*/
|
|
35
|
+
export declare function vscodeCopilotInstalled(): boolean;
|
|
30
36
|
export declare function installHook(): void;
|
|
31
37
|
export declare function installClaudeCodeInstructions(): void;
|
|
32
38
|
export declare function installCodexInstructions(): void;
|
|
@@ -43,6 +49,18 @@ export declare function installClaudeCodeMcp(): void;
|
|
|
43
49
|
* <project>/.cursor/mcp.json — we only manage the user-scope one.
|
|
44
50
|
*/
|
|
45
51
|
export declare function installCursorMcp(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Install the CodieDev MCP server into VS Code's user-scope MCP config so
|
|
54
|
+
* GitHub Copilot Chat picks it up. VS Code uses a different schema than
|
|
55
|
+
* Claude / Cursor: top-level key is `servers` (not `mcpServers`). On first
|
|
56
|
+
* Copilot Chat run after install, VS Code prompts the user to trust the
|
|
57
|
+
* server — that's expected and documented in the connect success message.
|
|
58
|
+
*
|
|
59
|
+
* Reverse-ticket and the other on-demand verbs work in Copilot identically
|
|
60
|
+
* to Claude Code since the MCP server's reverse_ticket handler is already
|
|
61
|
+
* 100% diff-driven (no transcript dependency).
|
|
62
|
+
*/
|
|
63
|
+
export declare function installVSCodeMcp(): void;
|
|
46
64
|
/**
|
|
47
65
|
* Best-effort append of the CodieDev MCP server block to ~/.codex/config.toml.
|
|
48
66
|
*
|
package/dist/utils.js
CHANGED
|
@@ -42,12 +42,14 @@ exports.hashToken = hashToken;
|
|
|
42
42
|
exports.claudeCodeInstalled = claudeCodeInstalled;
|
|
43
43
|
exports.codexInstalled = codexInstalled;
|
|
44
44
|
exports.cursorInstalled = cursorInstalled;
|
|
45
|
+
exports.vscodeCopilotInstalled = vscodeCopilotInstalled;
|
|
45
46
|
exports.installHook = installHook;
|
|
46
47
|
exports.installClaudeCodeInstructions = installClaudeCodeInstructions;
|
|
47
48
|
exports.installCodexInstructions = installCodexInstructions;
|
|
48
49
|
exports.installCursorInstructions = installCursorInstructions;
|
|
49
50
|
exports.installClaudeCodeMcp = installClaudeCodeMcp;
|
|
50
51
|
exports.installCursorMcp = installCursorMcp;
|
|
52
|
+
exports.installVSCodeMcp = installVSCodeMcp;
|
|
51
53
|
exports.installCodexMcp = installCodexMcp;
|
|
52
54
|
exports.installCodexHook = installCodexHook;
|
|
53
55
|
exports.installCursorHook = installCursorHook;
|
|
@@ -142,6 +144,52 @@ const CURSOR_HOOKS_PATH = path.join(CURSOR_DIR, "hooks.json");
|
|
|
142
144
|
const CURSOR_MCP_PATH = path.join(CURSOR_DIR, "mcp.json");
|
|
143
145
|
const CURSOR_RULES_DIR = path.join(CURSOR_DIR, "rules");
|
|
144
146
|
const CURSOR_RULES_PATH = path.join(CURSOR_RULES_DIR, "codiedev.mdc");
|
|
147
|
+
// VS Code Copilot Chat: detected by the github.copilot* extension dir, then
|
|
148
|
+
// MCP wired via VS Code's user-scope mcp.json (top-level key is "servers",
|
|
149
|
+
// not "mcpServers" like Claude/Cursor).
|
|
150
|
+
const VSCODE_EXTENSIONS_DIR = path.join(os.homedir(), ".vscode", "extensions");
|
|
151
|
+
const VSCODE_USER_DIR = (() => {
|
|
152
|
+
const home = os.homedir();
|
|
153
|
+
if (process.platform === "darwin") {
|
|
154
|
+
return path.join(home, "Library", "Application Support", "Code", "User");
|
|
155
|
+
}
|
|
156
|
+
if (process.platform === "win32") {
|
|
157
|
+
const appData = process.env.APPDATA ?? path.join(home, "AppData", "Roaming");
|
|
158
|
+
return path.join(appData, "Code", "User");
|
|
159
|
+
}
|
|
160
|
+
return path.join(home, ".config", "Code", "User");
|
|
161
|
+
})();
|
|
162
|
+
const VSCODE_USER_MCP_PATH = path.join(VSCODE_USER_DIR, "mcp.json");
|
|
163
|
+
// GUI-launched agents (Cursor.app, future JetBrains plugins) don't source the
|
|
164
|
+
// user's shell rc, so nvm-managed `npx` and `node` aren't on PATH. Resolve the
|
|
165
|
+
// absolute path to the current node binary and our hook.js at install time and
|
|
166
|
+
// write that into hook configs so execution doesn't depend on the spawned
|
|
167
|
+
// shell's PATH. Falls back to `npx` if we can't resolve dist/hook.js.
|
|
168
|
+
function shellQuote(s) {
|
|
169
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
170
|
+
}
|
|
171
|
+
function resolveHookCommand(subcommand) {
|
|
172
|
+
try {
|
|
173
|
+
const cliEntry = process.argv[1];
|
|
174
|
+
if (cliEntry) {
|
|
175
|
+
const realCli = fs.realpathSync(cliEntry);
|
|
176
|
+
const distDir = path.dirname(realCli);
|
|
177
|
+
const hookScript = path.join(distDir, "hook.js");
|
|
178
|
+
if (fs.existsSync(hookScript)) {
|
|
179
|
+
return `${shellQuote(process.execPath)} ${shellQuote(hookScript)} ${subcommand}`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Fall through to npx fallback.
|
|
185
|
+
}
|
|
186
|
+
return `npx codiedev-hook ${subcommand}`;
|
|
187
|
+
}
|
|
188
|
+
function isCodiedevHookCommand(cmd) {
|
|
189
|
+
if (!cmd)
|
|
190
|
+
return false;
|
|
191
|
+
return cmd.includes("codiedev-hook") || /codiedev[\\/]dist[\\/]hook/.test(cmd);
|
|
192
|
+
}
|
|
145
193
|
function claudeCodeInstalled() {
|
|
146
194
|
return fs.existsSync(CLAUDE_DIR);
|
|
147
195
|
}
|
|
@@ -151,6 +199,23 @@ function codexInstalled() {
|
|
|
151
199
|
function cursorInstalled() {
|
|
152
200
|
return fs.existsSync(CURSOR_DIR);
|
|
153
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* VS Code with the GitHub Copilot Chat extension installed. The extension
|
|
204
|
+
* directory pattern is `~/.vscode/extensions/github.copilot-chat-*`. We treat
|
|
205
|
+
* the presence of any `github.copilot*` directory as the Copilot fingerprint.
|
|
206
|
+
*/
|
|
207
|
+
function vscodeCopilotInstalled() {
|
|
208
|
+
if (!fs.existsSync(VSCODE_EXTENSIONS_DIR))
|
|
209
|
+
return false;
|
|
210
|
+
try {
|
|
211
|
+
return fs
|
|
212
|
+
.readdirSync(VSCODE_EXTENSIONS_DIR)
|
|
213
|
+
.some((name) => name.startsWith("github.copilot"));
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
154
219
|
function installHook() {
|
|
155
220
|
let settings = {};
|
|
156
221
|
try {
|
|
@@ -169,30 +234,27 @@ function installHook() {
|
|
|
169
234
|
if (!hooks.SessionEnd) {
|
|
170
235
|
hooks.SessionEnd = [];
|
|
171
236
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
});
|
|
237
|
+
// Drop any prior codiedev entries (legacy `npx` form or older absolute
|
|
238
|
+
// paths) before re-adding so connect re-runs upgrade the resolved binary
|
|
239
|
+
// path instead of leaving stale entries behind.
|
|
240
|
+
const existing = hooks.SessionEnd;
|
|
241
|
+
const filtered = existing.filter((hook) => {
|
|
242
|
+
const inner = hook.hooks;
|
|
243
|
+
if (Array.isArray(inner)) {
|
|
244
|
+
return !inner.some((h) => isCodiedevHookCommand(h.command));
|
|
181
245
|
}
|
|
182
|
-
return
|
|
246
|
+
return !isCodiedevHookCommand(hook.matcher);
|
|
183
247
|
});
|
|
184
|
-
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
sessionEndHooks.push({
|
|
248
|
+
filtered.push({
|
|
188
249
|
matcher: ".*",
|
|
189
250
|
hooks: [
|
|
190
251
|
{
|
|
191
252
|
type: "command",
|
|
192
|
-
command: "
|
|
253
|
+
command: resolveHookCommand("capture"),
|
|
193
254
|
},
|
|
194
255
|
],
|
|
195
256
|
});
|
|
257
|
+
hooks.SessionEnd = filtered;
|
|
196
258
|
if (!fs.existsSync(CLAUDE_DIR)) {
|
|
197
259
|
fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
198
260
|
}
|
|
@@ -420,6 +482,33 @@ function installCursorMcp() {
|
|
|
420
482
|
config.mcpServers = mcpServers;
|
|
421
483
|
fs.writeFileSync(CURSOR_MCP_PATH, JSON.stringify(config, null, 2), "utf8");
|
|
422
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Install the CodieDev MCP server into VS Code's user-scope MCP config so
|
|
487
|
+
* GitHub Copilot Chat picks it up. VS Code uses a different schema than
|
|
488
|
+
* Claude / Cursor: top-level key is `servers` (not `mcpServers`). On first
|
|
489
|
+
* Copilot Chat run after install, VS Code prompts the user to trust the
|
|
490
|
+
* server — that's expected and documented in the connect success message.
|
|
491
|
+
*
|
|
492
|
+
* Reverse-ticket and the other on-demand verbs work in Copilot identically
|
|
493
|
+
* to Claude Code since the MCP server's reverse_ticket handler is already
|
|
494
|
+
* 100% diff-driven (no transcript dependency).
|
|
495
|
+
*/
|
|
496
|
+
function installVSCodeMcp() {
|
|
497
|
+
if (!fs.existsSync(VSCODE_USER_DIR)) {
|
|
498
|
+
fs.mkdirSync(VSCODE_USER_DIR, { recursive: true });
|
|
499
|
+
}
|
|
500
|
+
const config = readMcpConfigSafely(VSCODE_USER_MCP_PATH);
|
|
501
|
+
const servers = config.servers ?? {};
|
|
502
|
+
if (servers.codiedev)
|
|
503
|
+
return;
|
|
504
|
+
servers.codiedev = {
|
|
505
|
+
type: "stdio",
|
|
506
|
+
command: "npx",
|
|
507
|
+
args: ["codiedev-mcp"],
|
|
508
|
+
};
|
|
509
|
+
config.servers = servers;
|
|
510
|
+
fs.writeFileSync(VSCODE_USER_MCP_PATH, JSON.stringify(config, null, 2), "utf8");
|
|
511
|
+
}
|
|
423
512
|
/**
|
|
424
513
|
* Best-effort append of the CodieDev MCP server block to ~/.codex/config.toml.
|
|
425
514
|
*
|
|
@@ -469,28 +558,23 @@ function installCodexHook() {
|
|
|
469
558
|
if (!hooks.Stop) {
|
|
470
559
|
hooks.Stop = [];
|
|
471
560
|
}
|
|
472
|
-
const
|
|
473
|
-
const
|
|
561
|
+
const existing = hooks.Stop;
|
|
562
|
+
const filtered = existing.filter((hook) => {
|
|
474
563
|
const inner = hook.hooks;
|
|
475
|
-
if (!inner)
|
|
476
|
-
return
|
|
477
|
-
return inner.some((h) =>
|
|
478
|
-
const cmd = h.command;
|
|
479
|
-
return cmd && cmd.includes("codiedev-hook");
|
|
480
|
-
});
|
|
564
|
+
if (!Array.isArray(inner))
|
|
565
|
+
return true;
|
|
566
|
+
return !inner.some((h) => isCodiedevHookCommand(h.command));
|
|
481
567
|
});
|
|
482
|
-
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
stopHooks.push({
|
|
568
|
+
filtered.push({
|
|
486
569
|
hooks: [
|
|
487
570
|
{
|
|
488
571
|
type: "command",
|
|
489
|
-
command: "
|
|
572
|
+
command: resolveHookCommand("capture-codex"),
|
|
490
573
|
timeout: 30,
|
|
491
574
|
},
|
|
492
575
|
],
|
|
493
576
|
});
|
|
577
|
+
hooks.Stop = filtered;
|
|
494
578
|
if (!fs.existsSync(CODEX_DIR)) {
|
|
495
579
|
fs.mkdirSync(CODEX_DIR, { recursive: true });
|
|
496
580
|
}
|
|
@@ -524,19 +608,14 @@ function installCursorHook() {
|
|
|
524
608
|
if (!hooks.sessionEnd) {
|
|
525
609
|
hooks.sessionEnd = [];
|
|
526
610
|
}
|
|
527
|
-
const
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
});
|
|
532
|
-
if (alreadyInstalled) {
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
sessionEndHooks.push({
|
|
536
|
-
command: "npx codiedev-hook capture-cursor",
|
|
611
|
+
const existing = hooks.sessionEnd;
|
|
612
|
+
const filtered = existing.filter((h) => !isCodiedevHookCommand(h.command));
|
|
613
|
+
filtered.push({
|
|
614
|
+
command: resolveHookCommand("capture-cursor"),
|
|
537
615
|
type: "command",
|
|
538
616
|
timeout: 30,
|
|
539
617
|
});
|
|
618
|
+
hooks.sessionEnd = filtered;
|
|
540
619
|
fs.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(hooksFile, null, 2), "utf8");
|
|
541
620
|
}
|
|
542
621
|
function parseClaudeCodeStats(content) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codiedev",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Connect Claude Code, Codex, or
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Connect Claude Code, Codex, Cursor, or VS Code Copilot to CodieDev for org-wide session capture and artifact collaboration",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codiedev": "./dist/cli.js",
|
|
7
7
|
"codiedev-hook": "./dist/hook.js"
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"codex",
|
|
23
23
|
"openai",
|
|
24
24
|
"cursor",
|
|
25
|
+
"copilot",
|
|
26
|
+
"github-copilot",
|
|
27
|
+
"vscode",
|
|
28
|
+
"mcp",
|
|
25
29
|
"ai",
|
|
26
30
|
"session-capture"
|
|
27
31
|
],
|