codiedev 0.8.2 → 0.9.0-beta.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # codiedev
2
2
 
3
- Connect Claude Code or Codex to CodieDev for org-wide session capture.
3
+ Connect Claude Code or Codex to Codiedev for org-wide session capture.
4
4
 
5
5
  ## Usage
6
6
 
package/dist/cli.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * CodieDev CLI dispatcher.
3
+ * Codiedev CLI dispatcher.
4
4
  *
5
5
  * Subcommands:
6
6
  * codiedev connect — link agent CLIs to your org
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * CodieDev CLI dispatcher.
4
+ * Codiedev CLI dispatcher.
5
5
  *
6
6
  * Subcommands:
7
7
  * codiedev connect — link agent CLIs to your org
@@ -35,7 +35,7 @@ const send_1 = require("./commands/send");
35
35
  const react_1 = require("./commands/react");
36
36
  const version_1 = require("./version");
37
37
  const HELP = `
38
- CodieDev CLI
38
+ Codiedev CLI
39
39
 
40
40
  The team artifact layer for agent-coded work. Share specs and reviews
41
41
  with teammates, get pinged when they need your input, pick up where
@@ -132,7 +132,7 @@ Docs: codiedev docs
132
132
  `.trim();
133
133
  const COMMAND_HELP = {
134
134
  connect: `
135
- codiedev connect — link your agent CLI to CodieDev
135
+ codiedev connect — link your agent CLI to Codiedev
136
136
 
137
137
  Interactive setup. Prompts for an API token, then installs:
138
138
  - ~/.codiedev/config.json (token + org + tracked repos)
@@ -272,11 +272,11 @@ codiedev create-ticket — forward-write a scoped ticket plan
272
272
  `.trim(),
273
273
  };
274
274
  const DOCS = `
275
- CodieDev — usage guide
275
+ Codiedev — usage guide
276
276
 
277
277
  ## What this is
278
278
 
279
- CodieDev is a team artifact layer on top of your coding agent (Claude
279
+ Codiedev is a team artifact layer on top of your coding agent (Claude
280
280
  Code, Codex, etc.). It persists the *durable* outputs of agent work —
281
281
  specs, reviews, decisions, proposals, and captured thoughts — so:
282
282
 
@@ -65,7 +65,7 @@ function resolveRepoIds(fullNames, repos) {
65
65
  for (const fn of fullNames) {
66
66
  const id = lookup.get(fn.toLowerCase());
67
67
  if (!id) {
68
- throw new Error(`Repo "${fn}" is not connected to your CodieDev account. Run \`codiedev connect\` to refresh, or push the missing repo through Settings.`);
68
+ throw new Error(`Repo "${fn}" is not connected to your Codiedev account. Run \`codiedev connect\` to refresh, or push the missing repo through Settings.`);
69
69
  }
70
70
  ids.push(id);
71
71
  }
@@ -134,13 +134,13 @@ function hasGlabCli() {
134
134
  }
135
135
  async function runDoctor(_args) {
136
136
  const checks = [];
137
- console.log("\nCodieDev doctor — checking your setup…\n");
137
+ console.log("\nCodiedev doctor — checking your setup…\n");
138
138
  await (0, upgradeNudge_1.maybePrintUpgradeNudge)();
139
139
  // 1. Config file
140
140
  const config = (0, utils_1.readConfig)();
141
141
  if (!config) {
142
142
  checks.push({
143
- name: "CodieDev config (~/.codiedev/config.json)",
143
+ name: "Codiedev config (~/.codiedev/config.json)",
144
144
  status: "fail",
145
145
  detail: "Not found. Run `codiedev connect` first.",
146
146
  });
@@ -148,7 +148,7 @@ async function runDoctor(_args) {
148
148
  process.exit(1);
149
149
  }
150
150
  checks.push({
151
- name: "CodieDev config",
151
+ name: "Codiedev config",
152
152
  status: "pass",
153
153
  detail: `connected to ${config.companyName}`,
154
154
  });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  // `codiedev library [--scope mine|shared|all] [--kind doc|skill] [--tag X]
3
- // [--type spec|...] [--limit N]` — list artifacts in your CodieDev workspace.
3
+ // [--type spec|...] [--limit N]` — list artifacts in your Codiedev workspace.
4
4
  // Server applies companyId scoping; --scope filters within that.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runLibrary = runLibrary;
@@ -8,12 +8,12 @@ import { CodiedevConfig } from "../utils";
8
8
  */
9
9
  export declare function applyConfigEnvOverrides(config: CodiedevConfig): CodiedevConfig;
10
10
  /**
11
- * Require a connected CodieDev config. Exits the process with a helpful
11
+ * Require a connected Codiedev config. Exits the process with a helpful
12
12
  * message if the user hasn't run `codiedev connect` yet.
13
13
  */
14
14
  export declare function requireConfig(): CodiedevConfig;
15
15
  /**
16
- * Perform an authenticated HTTP request against the CodieDev backend.
16
+ * Perform an authenticated HTTP request against the Codiedev backend.
17
17
  * Returns the parsed JSON response body. Throws on non-2xx.
18
18
  */
19
19
  export declare function apiRequest<T = unknown>(method: "GET" | "POST", path: string, options: {
@@ -61,7 +61,7 @@ function applyConfigEnvOverrides(config) {
61
61
  return config;
62
62
  }
63
63
  /**
64
- * Require a connected CodieDev config. Exits the process with a helpful
64
+ * Require a connected Codiedev config. Exits the process with a helpful
65
65
  * message if the user hasn't run `codiedev connect` yet.
66
66
  */
67
67
  function requireConfig() {
@@ -73,7 +73,7 @@ function requireConfig() {
73
73
  return applyConfigEnvOverrides(config);
74
74
  }
75
75
  /**
76
- * Perform an authenticated HTTP request against the CodieDev backend.
76
+ * Perform an authenticated HTTP request against the Codiedev backend.
77
77
  * Returns the parsed JSON response body. Throws on non-2xx.
78
78
  */
79
79
  function apiRequest(method, path, options) {
package/dist/connect.js CHANGED
@@ -161,9 +161,9 @@ async function runConnect(args = []) {
161
161
  // mint a fresh token from the portal — which is what bit Sonifi's first
162
162
  // engineer when he interpreted "no visible token" as "the old one is gone".
163
163
  const force = args.includes("--force") || args.includes("-f");
164
- console.log("\nWelcome to CodieDev CLI\n");
164
+ console.log("\nWelcome to Codiedev CLI\n");
165
165
  await (0, upgradeNudge_1.maybePrintUpgradeNudge)();
166
- console.log("This will connect your coding agent to your CodieDev workspace and install");
166
+ console.log("This will connect your coding agent to your Codiedev workspace and install");
167
167
  console.log("the session capture hook for org-wide session sharing.\n");
168
168
  const saved = (0, utils_1.readConfig)();
169
169
  const decision = (0, connectFlow_1.resolveConnectToken)({ savedConfig: saved, force });
@@ -175,7 +175,7 @@ async function runConnect(args = []) {
175
175
  else {
176
176
  // Hidden prompt — masks the token with `*` as it's typed/pasted so it
177
177
  // doesn't end up in terminal scrollback or screenshots.
178
- token = await promptHidden("Enter your CodieDev API token: ");
178
+ token = await promptHidden("Enter your Codiedev API token: ");
179
179
  if (!token) {
180
180
  console.error("Error: API token is required.");
181
181
  process.exit(1);
package/dist/hook.js CHANGED
@@ -39,6 +39,66 @@ const https = __importStar(require("https"));
39
39
  const http = __importStar(require("http"));
40
40
  const utils_1 = require("./utils");
41
41
  const version_1 = require("./version");
42
+ function getJson(url, bearerToken) {
43
+ return new Promise((resolve, reject) => {
44
+ const parsed = new URL(url);
45
+ const options = {
46
+ hostname: parsed.hostname,
47
+ port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
48
+ path: parsed.pathname + parsed.search,
49
+ method: "GET",
50
+ headers: {
51
+ Authorization: `Bearer ${bearerToken}`,
52
+ "X-Codiedev-Cli-Version": version_1.CLI_VERSION,
53
+ },
54
+ };
55
+ const lib = parsed.protocol === "https:" ? https : http;
56
+ const req = lib.request(options, (res) => {
57
+ let body = "";
58
+ res.on("data", (c) => (body += c));
59
+ res.on("end", () => {
60
+ try {
61
+ resolve(JSON.parse(body));
62
+ }
63
+ catch {
64
+ reject(new Error("bad json"));
65
+ }
66
+ });
67
+ });
68
+ req.on("error", reject);
69
+ req.end();
70
+ });
71
+ }
72
+ // UserPromptSubmit: query skill discovery for the prompt and, if a team skill
73
+ // clears the confidence threshold, inject it as additionalContext so the agent
74
+ // can offer to pull+run it. Fully silent on miss/error — never blocks input.
75
+ async function runDiscover(prompt) {
76
+ if (!prompt || !prompt.trim())
77
+ process.exit(0);
78
+ const config = (0, utils_1.readConfig)();
79
+ if (!config)
80
+ process.exit(0);
81
+ try {
82
+ const res = await getJson(`${config.backendUrl}/api/cli/skill-discovery?q=${encodeURIComponent(prompt)}`, config.token);
83
+ const skills = res?.skills ?? [];
84
+ if (skills.length > 0) {
85
+ const lines = skills
86
+ .slice(0, 3)
87
+ .map((s) => `- ${s.key} — ${(s.score * 100).toFixed(0)}% match`)
88
+ .join("\n");
89
+ const additionalContext = "A CodieDev team skill may apply to this task:\n" +
90
+ lines +
91
+ "\nIf one fits, pull and use it before improvising: `codiedev pull <key>`.";
92
+ process.stdout.write(JSON.stringify({
93
+ hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext },
94
+ }));
95
+ }
96
+ }
97
+ catch {
98
+ // silent — discovery is best-effort
99
+ }
100
+ process.exit(0);
101
+ }
42
102
  function postJson(url, body, bearerToken) {
43
103
  return new Promise((resolve, reject) => {
44
104
  const parsed = new URL(url);
@@ -94,7 +154,6 @@ function resolveMode(arg) {
94
154
  return "claude-code";
95
155
  }
96
156
  async function main() {
97
- const mode = resolveMode(process.argv[2]);
98
157
  let hookInput = {};
99
158
  try {
100
159
  const raw = await readStdin();
@@ -105,6 +164,15 @@ async function main() {
105
164
  catch {
106
165
  process.exit(0);
107
166
  }
167
+ // UserPromptSubmit discovery path — separate from session capture.
168
+ if (process.argv[2] === "discover") {
169
+ await runDiscover(hookInput.prompt);
170
+ return;
171
+ }
172
+ const mode = resolveMode(process.argv[2]);
173
+ // Self-heal: a user who upgraded the CLI but hasn't re-run `connect` gets the
174
+ // discovery hook wired on their next SessionEnd, without re-connecting.
175
+ (0, utils_1.ensureDiscoveryHookInstalled)();
108
176
  const { session_id, transcript_path, cwd, workspace_roots } = hookInput;
109
177
  const workspaceRoot = workspace_roots && workspace_roots.length > 0
110
178
  ? workspace_roots[0]
package/dist/mcp.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * CodieDev MCP server.
3
+ * Codiedev MCP server.
4
4
  *
5
- * Exposes the CodieDev artifact-collaboration surface as Model Context
5
+ * Exposes the Codiedev artifact-collaboration surface as Model Context
6
6
  * Protocol tools so Claude Code / Codex / any MCP-capable agent can invoke
7
7
  * them natively from natural language (e.g. "push the spec we just worked on").
8
8
  *
package/dist/mcp.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * CodieDev MCP server.
4
+ * Codiedev MCP server.
5
5
  *
6
- * Exposes the CodieDev artifact-collaboration surface as Model Context
6
+ * Exposes the Codiedev artifact-collaboration surface as Model Context
7
7
  * Protocol tools so Claude Code / Codex / any MCP-capable agent can invoke
8
8
  * them natively from natural language (e.g. "push the spec we just worked on").
9
9
  *
@@ -70,7 +70,7 @@ const PKG_VERSION = (() => {
70
70
  const TOOLS = [
71
71
  {
72
72
  name: "codiedev_push",
73
- description: "Push any markdown artifact (doc or skill) to the team's CodieDev " +
73
+ description: "Push any markdown artifact (doc or skill) to the team's Codiedev " +
74
74
  "artifact layer so teammates can see, discuss, and run it. Works for " +
75
75
  "specs, decisions, proposals, bugfixes, reviews, notes, AND " +
76
76
  "Claude Code / Codex skills (files with SKILL.md frontmatter — " +
@@ -127,7 +127,7 @@ const TOOLS = [
127
127
  },
128
128
  {
129
129
  name: "codiedev_pull",
130
- description: "Fetch any artifact (doc or skill) from the team's CodieDev artifact " +
130
+ description: "Fetch any artifact (doc or skill) from the team's Codiedev artifact " +
131
131
  "layer. Works for specs, decisions, proposals, bugfixes, reviews, " +
132
132
  "notes, AND skills (SKILL.md frontmatter files surfaced as slash " +
133
133
  "commands). Use when the user asks to pull, grab, fetch, or resume " +
@@ -171,7 +171,7 @@ const TOOLS = [
171
171
  },
172
172
  {
173
173
  name: "codiedev_ping",
174
- description: "Send a message to a teammate on CodieDev, optionally attached to a " +
174
+ description: "Send a message to a teammate on Codiedev, optionally attached to a " +
175
175
  "specific artifact. Use when the user asks to ping, ask, share with, " +
176
176
  "or get feedback from a teammate by name (e.g. 'ping a teammate about " +
177
177
  "this spec'). Recipients are resolved by first name, full name, or email " +
@@ -200,7 +200,7 @@ const TOOLS = [
200
200
  },
201
201
  {
202
202
  name: "codiedev_inbox",
203
- description: "Check the user's CodieDev inbox for messages from teammates. Use " +
203
+ description: "Check the user's Codiedev inbox for messages from teammates. Use " +
204
204
  "when the user asks 'any messages?', 'what did [name] say?', 'check " +
205
205
  "my inbox', or when they open a session and want to catch up on " +
206
206
  "what's waiting for them. Returns a list with sender, subject " +
@@ -224,7 +224,7 @@ const TOOLS = [
224
224
  description: "Capture a passing thought and link it to the current agent session. " +
225
225
  "Use when the user says 'note that', 'remember', 'worth capturing', " +
226
226
  "'jot this down', or drops a short observation that isn't a full " +
227
- "spec. Notes show up in the user's CodieDev memory feed.",
227
+ "spec. Notes show up in the user's Codiedev memory feed.",
228
228
  inputSchema: {
229
229
  type: "object",
230
230
  properties: {
@@ -238,7 +238,7 @@ const TOOLS = [
238
238
  },
239
239
  {
240
240
  name: "codiedev_promote",
241
- description: "Promote an auto-extracted CodieDev artifact (spec/bugfix/decision " +
241
+ description: "Promote an auto-extracted Codiedev artifact (spec/bugfix/decision " +
242
242
  "produced by the session-capture pipeline) to an authored artifact " +
243
243
  "so teammates can collaborate on it. Use when the user says 'publish " +
244
244
  "the extracted spec', 'promote this', or 'make the auto-extracted X " +
@@ -248,7 +248,7 @@ const TOOLS = [
248
248
  properties: {
249
249
  artifactId: {
250
250
  type: "string",
251
- description: "The extracted artifact's id from CodieDev.",
251
+ description: "The extracted artifact's id from Codiedev.",
252
252
  },
253
253
  keyOverride: {
254
254
  type: "string",
@@ -545,7 +545,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
545
545
  content: [
546
546
  {
547
547
  type: "text",
548
- text: "CodieDev is not connected on this machine. Ask the user to run " +
548
+ text: "Codiedev is not connected on this machine. Ask the user to run " +
549
549
  "`npx codiedev connect` with an API token from " +
550
550
  "https://codiedev.com/portal/integrations/claude-code.",
551
551
  },
@@ -579,7 +579,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
579
579
  content: [
580
580
  {
581
581
  type: "text",
582
- text: `CodieDev error: ${err.message}`,
582
+ text: `Codiedev error: ${err.message}`,
583
583
  },
584
584
  ],
585
585
  };
package/dist/utils.d.ts CHANGED
@@ -33,24 +33,26 @@ export declare function cursorInstalled(): boolean;
33
33
  * the presence of any `github.copilot*` directory as the Copilot fingerprint.
34
34
  */
35
35
  export declare function vscodeCopilotInstalled(): boolean;
36
+ export declare function upsertCodiedevHook(hooks: Record<string, unknown>, eventName: string, subcommand: string): void;
36
37
  export declare function installHook(): void;
38
+ export declare function ensureDiscoveryHookInstalled(): void;
37
39
  export declare function installClaudeCodeInstructions(): void;
38
40
  export declare function installCodexInstructions(): void;
39
41
  export declare function installCursorInstructions(): void;
40
42
  /**
41
- * Install the CodieDev MCP server into Claude Code's user-scope config.
43
+ * Install the Codiedev MCP server into Claude Code's user-scope config.
42
44
  * Safe to call multiple times — updates the existing entry if present.
43
45
  */
44
46
  export declare function installClaudeCodeMcp(): void;
45
47
  /**
46
- * Install the CodieDev MCP server into Cursor's user-scope config.
48
+ * Install the Codiedev MCP server into Cursor's user-scope config.
47
49
  * Cursor uses the same `mcpServers` schema as Claude Code; just a different
48
50
  * file path (~/.cursor/mcp.json). Project-scoped servers can also live at
49
51
  * <project>/.cursor/mcp.json — we only manage the user-scope one.
50
52
  */
51
53
  export declare function installCursorMcp(): void;
52
54
  /**
53
- * Install the CodieDev MCP server into VS Code's user-scope MCP config so
55
+ * Install the Codiedev MCP server into VS Code's user-scope MCP config so
54
56
  * GitHub Copilot Chat picks it up. VS Code uses a different schema than
55
57
  * Claude / Cursor: top-level key is `servers` (not `mcpServers`). On first
56
58
  * Copilot Chat run after install, VS Code prompts the user to trust the
@@ -84,7 +86,7 @@ export declare function cleanupVSCodeMcp(): void;
84
86
  */
85
87
  export declare function cleanupCodexMcp(): void;
86
88
  /**
87
- * Best-effort append of the CodieDev MCP server block to ~/.codex/config.toml.
89
+ * Best-effort append of the Codiedev MCP server block to ~/.codex/config.toml.
88
90
  *
89
91
  * Codex uses TOML and we don't want a full parser for such a small addition,
90
92
  * so we append a well-marked block if one isn't already present. Idempotent.
package/dist/utils.js CHANGED
@@ -43,7 +43,9 @@ exports.claudeCodeInstalled = claudeCodeInstalled;
43
43
  exports.codexInstalled = codexInstalled;
44
44
  exports.cursorInstalled = cursorInstalled;
45
45
  exports.vscodeCopilotInstalled = vscodeCopilotInstalled;
46
+ exports.upsertCodiedevHook = upsertCodiedevHook;
46
47
  exports.installHook = installHook;
48
+ exports.ensureDiscoveryHookInstalled = ensureDiscoveryHookInstalled;
47
49
  exports.installClaudeCodeInstructions = installClaudeCodeInstructions;
48
50
  exports.installCodexInstructions = installCodexInstructions;
49
51
  exports.installCursorInstructions = installCursorInstructions;
@@ -230,6 +232,27 @@ function vscodeCopilotInstalled() {
230
232
  return false;
231
233
  }
232
234
  }
235
+ // Idempotently put a single codiedev hook (matcher ".*", running our hook.js
236
+ // with `subcommand`) into the given hook event, stripping any prior codiedev
237
+ // entries first so connect re-runs / upgrades refresh the resolved binary path.
238
+ // Mutates `hooks` in place. Exported for unit testing.
239
+ function upsertCodiedevHook(hooks, eventName, subcommand) {
240
+ if (!hooks[eventName])
241
+ hooks[eventName] = [];
242
+ const existing = hooks[eventName];
243
+ const filtered = existing.filter((hook) => {
244
+ const inner = hook.hooks;
245
+ if (Array.isArray(inner)) {
246
+ return !inner.some((h) => (0, detection_1.isCodiedevHookCommand)(h.command));
247
+ }
248
+ return !(0, detection_1.isCodiedevHookCommand)(hook.matcher);
249
+ });
250
+ filtered.push({
251
+ matcher: ".*",
252
+ hooks: [{ type: "command", command: resolveHookCommand(subcommand) }],
253
+ });
254
+ hooks[eventName] = filtered;
255
+ }
233
256
  function installHook() {
234
257
  let settings = {};
235
258
  try {
@@ -245,35 +268,42 @@ function installHook() {
245
268
  settings.hooks = {};
246
269
  }
247
270
  const hooks = settings.hooks;
248
- if (!hooks.SessionEnd) {
249
- hooks.SessionEnd = [];
250
- }
251
- // Drop any prior codiedev entries (legacy `npx` form or older absolute
252
- // paths) before re-adding so connect re-runs upgrade the resolved binary
253
- // path instead of leaving stale entries behind.
254
- const existing = hooks.SessionEnd;
255
- const filtered = existing.filter((hook) => {
256
- const inner = hook.hooks;
257
- if (Array.isArray(inner)) {
258
- return !inner.some((h) => (0, detection_1.isCodiedevHookCommand)(h.command));
259
- }
260
- return !(0, detection_1.isCodiedevHookCommand)(hook.matcher);
261
- });
262
- filtered.push({
263
- matcher: ".*",
264
- hooks: [
265
- {
266
- type: "command",
267
- command: resolveHookCommand("capture"),
268
- },
269
- ],
270
- });
271
- hooks.SessionEnd = filtered;
271
+ // SessionEnd → capture (upload the finished session for the team library).
272
+ upsertCodiedevHook(hooks, "SessionEnd", "capture");
273
+ // UserPromptSubmit → discover (surface a matching team skill for the task).
274
+ upsertCodiedevHook(hooks, "UserPromptSubmit", "discover");
272
275
  if (!fs.existsSync(CLAUDE_DIR)) {
273
276
  fs.mkdirSync(CLAUDE_DIR, { recursive: true });
274
277
  }
275
278
  fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf8");
276
279
  }
280
+ // Self-heal: ensure the discovery (UserPromptSubmit) hook is present without a
281
+ // full `connect` re-run. Called from the capture hook on SessionEnd, so a user
282
+ // who upgrades the CLI gets the new hook wired on their next session. Only
283
+ // writes when missing, to avoid churning settings.json every run.
284
+ function ensureDiscoveryHookInstalled() {
285
+ try {
286
+ if (!fs.existsSync(CLAUDE_SETTINGS_PATH))
287
+ return; // not a Claude Code user
288
+ const raw = fs.readFileSync(CLAUDE_SETTINGS_PATH, "utf8");
289
+ const settings = JSON.parse(raw);
290
+ const hooks = (settings.hooks ?? {});
291
+ const ups = (hooks.UserPromptSubmit ?? []);
292
+ const present = ups.some((hook) => {
293
+ const inner = hook.hooks;
294
+ return (Array.isArray(inner) &&
295
+ inner.some((h) => (0, detection_1.isCodiedevHookCommand)(h.command)));
296
+ });
297
+ if (present)
298
+ return;
299
+ settings.hooks = hooks;
300
+ upsertCodiedevHook(hooks, "UserPromptSubmit", "discover");
301
+ fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf8");
302
+ }
303
+ catch {
304
+ // Best-effort — never block a session on self-heal.
305
+ }
306
+ }
277
307
  // ─────────────────────────────────────────────────────────────────────────────
278
308
  // MCP server installation — writes the codiedev MCP server config into each
279
309
  // agent CLI's expected location so "npx codiedev connect" wires it up once.
@@ -284,9 +314,9 @@ const CODEX_USER_INSTRUCTIONS_PATH = path.join(os.homedir(), ".codex", "AGENTS.m
284
314
  const CODEX_CONFIG_PATH = path.join(os.homedir(), ".codex", "config.toml");
285
315
  const CODIEDEV_INSTRUCTIONS_BEGIN = "<!-- codiedev-cli:begin -->";
286
316
  const CODIEDEV_INSTRUCTIONS_END = "<!-- codiedev-cli:end -->";
287
- const CODIEDEV_INSTRUCTIONS_BODY = `## CodieDev — team artifact layer
317
+ const CODIEDEV_INSTRUCTIONS_BODY = `## Codiedev — team artifact layer
288
318
 
289
- This machine is connected to CodieDev. Teammates share specs, reviews,
319
+ This machine is connected to Codiedev. Teammates share specs, reviews,
290
320
  decisions, and messages via a CLI on every dev's machine.
291
321
 
292
322
  **When the user asks to share, push, ping, check messages, or capture a
@@ -426,7 +456,7 @@ function installCodexInstructions() {
426
456
  // Cursor uses .mdc rule files with YAML frontmatter (description, alwaysApply,
427
457
  // globs). `.cursorrules` is deprecated and ignored by Agent mode as of 2026.
428
458
  const CURSOR_INSTRUCTIONS_FRONTMATTER = `---
429
- description: CodieDev team artifact layer — push, pull, search, ping, and share artifacts with teammates
459
+ description: Codiedev team artifact layer — push, pull, search, ping, and share artifacts with teammates
430
460
  alwaysApply: true
431
461
  ---
432
462
 
@@ -483,7 +513,7 @@ function readMcpConfigSafely(path) {
483
513
  }
484
514
  }
485
515
  /**
486
- * Install the CodieDev MCP server into Claude Code's user-scope config.
516
+ * Install the Codiedev MCP server into Claude Code's user-scope config.
487
517
  * Safe to call multiple times — updates the existing entry if present.
488
518
  */
489
519
  function installClaudeCodeMcp() {
@@ -499,7 +529,7 @@ function installClaudeCodeMcp() {
499
529
  fs.writeFileSync(CLAUDE_USER_CONFIG_PATH, JSON.stringify(config, null, 2), "utf8");
500
530
  }
501
531
  /**
502
- * Install the CodieDev MCP server into Cursor's user-scope config.
532
+ * Install the Codiedev MCP server into Cursor's user-scope config.
503
533
  * Cursor uses the same `mcpServers` schema as Claude Code; just a different
504
534
  * file path (~/.cursor/mcp.json). Project-scoped servers can also live at
505
535
  * <project>/.cursor/mcp.json — we only manage the user-scope one.
@@ -520,7 +550,7 @@ function installCursorMcp() {
520
550
  fs.writeFileSync(CURSOR_MCP_PATH, JSON.stringify(config, null, 2), "utf8");
521
551
  }
522
552
  /**
523
- * Install the CodieDev MCP server into VS Code's user-scope MCP config so
553
+ * Install the Codiedev MCP server into VS Code's user-scope MCP config so
524
554
  * GitHub Copilot Chat picks it up. VS Code uses a different schema than
525
555
  * Claude / Cursor: top-level key is `servers` (not `mcpServers`). On first
526
556
  * Copilot Chat run after install, VS Code prompts the user to trust the
@@ -635,7 +665,7 @@ function cleanupCodexMcp() {
635
665
  fs.writeFileSync(CODEX_CONFIG_PATH, out.join("\n"), "utf8");
636
666
  }
637
667
  /**
638
- * Best-effort append of the CodieDev MCP server block to ~/.codex/config.toml.
668
+ * Best-effort append of the Codiedev MCP server block to ~/.codex/config.toml.
639
669
  *
640
670
  * Codex uses TOML and we don't want a full parser for such a small addition,
641
671
  * so we append a well-marked block if one isn't already present. Idempotent.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.8.2",
4
- "description": "Connect Claude Code, Codex, Cursor, or VS Code Copilot to CodieDev for org-wide session capture and artifact collaboration",
3
+ "version": "0.9.0-beta.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"
@@ -1,13 +0,0 @@
1
- import * as http from "http";
2
- export declare const DEFAULT_HOOK_HTTP_TIMEOUT_MS = 8000;
3
- /** Hard cap for GET requests used in sync-context (e.g. auto-pull skill list).
4
- * If the backend accepts the connection but never writes a response the hook
5
- * would stall every Claude Code session start — we cap it well below any
6
- * reasonable UX threshold. */
7
- export declare const GET_JSON_TIMEOUT_MS = 5000;
8
- export declare function getHookHttpTimeoutMs(): number;
9
- type RequestImpl = typeof http.request;
10
- export declare function getJson<T>(url: string, bearerToken: string): Promise<T>;
11
- export declare function postJson(url: string, body: Record<string, unknown>, bearerToken: string, requestImpl?: RequestImpl): Promise<void>;
12
- export declare function postJsonWithHookTimeout(url: string, body: Record<string, unknown>, bearerToken: string, requestImpl?: RequestImpl): Promise<void>;
13
- export {};
@@ -1,136 +0,0 @@
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.GET_JSON_TIMEOUT_MS = exports.DEFAULT_HOOK_HTTP_TIMEOUT_MS = void 0;
37
- exports.getHookHttpTimeoutMs = getHookHttpTimeoutMs;
38
- exports.getJson = getJson;
39
- exports.postJson = postJson;
40
- exports.postJsonWithHookTimeout = postJsonWithHookTimeout;
41
- const http = __importStar(require("http"));
42
- const https = __importStar(require("https"));
43
- const version_1 = require("./version");
44
- exports.DEFAULT_HOOK_HTTP_TIMEOUT_MS = 8_000;
45
- /** Hard cap for GET requests used in sync-context (e.g. auto-pull skill list).
46
- * If the backend accepts the connection but never writes a response the hook
47
- * would stall every Claude Code session start — we cap it well below any
48
- * reasonable UX threshold. */
49
- exports.GET_JSON_TIMEOUT_MS = 5_000;
50
- function getHookHttpTimeoutMs() {
51
- const raw = process.env.CODIEDEV_HOOK_HTTP_TIMEOUT_MS;
52
- if (!raw)
53
- return exports.DEFAULT_HOOK_HTTP_TIMEOUT_MS;
54
- const parsed = Number(raw);
55
- if (!Number.isFinite(parsed) || parsed <= 0) {
56
- return exports.DEFAULT_HOOK_HTTP_TIMEOUT_MS;
57
- }
58
- return parsed;
59
- }
60
- function requestJson(method, url, bearerToken, body, requestImpl, useTimeout = false,
61
- /** When set, overrides getHookHttpTimeoutMs() for this request. */
62
- explicitTimeoutMs) {
63
- return new Promise((resolve, reject) => {
64
- const parsed = new URL(url);
65
- const data = body === undefined ? undefined : JSON.stringify(body);
66
- const headers = {
67
- Authorization: `Bearer ${bearerToken}`,
68
- "X-Codiedev-Cli-Version": version_1.CLI_VERSION,
69
- };
70
- if (data !== undefined) {
71
- headers["Content-Type"] = "application/json";
72
- headers["Content-Length"] = Buffer.byteLength(data);
73
- }
74
- const options = {
75
- hostname: parsed.hostname,
76
- port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
77
- path: parsed.pathname + parsed.search,
78
- method,
79
- headers,
80
- };
81
- const lib = parsed.protocol === "https:" ? https : http;
82
- const request = requestImpl ?? lib.request;
83
- let settled = false;
84
- const timeoutMs = explicitTimeoutMs ?? getHookHttpTimeoutMs();
85
- let timer;
86
- const finish = (fn) => {
87
- if (settled)
88
- return;
89
- settled = true;
90
- if (timer)
91
- clearTimeout(timer);
92
- fn();
93
- };
94
- const req = request(options, (res) => {
95
- let responseData = "";
96
- res.on("data", (chunk) => {
97
- responseData += chunk;
98
- });
99
- res.on("end", () => {
100
- if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
101
- try {
102
- const parsedBody = responseData.length === 0 ? undefined : JSON.parse(responseData);
103
- finish(() => resolve(parsedBody));
104
- }
105
- catch (e) {
106
- finish(() => reject(e));
107
- }
108
- }
109
- else {
110
- finish(() => reject(new Error(`HTTP ${res.statusCode}: ${responseData}`)));
111
- }
112
- });
113
- });
114
- if (useTimeout) {
115
- timer = setTimeout(() => {
116
- req.destroy(new Error(`request timed out after ${timeoutMs}ms`));
117
- }, timeoutMs);
118
- }
119
- req.on("error", (err) => finish(() => reject(err)));
120
- if (data !== undefined) {
121
- req.write(data);
122
- }
123
- req.end();
124
- });
125
- }
126
- function getJson(url, bearerToken) {
127
- // Always apply a 5-second cap so a hanging backend cannot stall a
128
- // SessionStart hook (which would freeze every Claude Code session start).
129
- return requestJson("GET", url, bearerToken, undefined, undefined, true, exports.GET_JSON_TIMEOUT_MS);
130
- }
131
- function postJson(url, body, bearerToken, requestImpl) {
132
- return requestJson("POST", url, bearerToken, body, requestImpl);
133
- }
134
- function postJsonWithHookTimeout(url, body, bearerToken, requestImpl) {
135
- return requestJson("POST", url, bearerToken, body, requestImpl, true);
136
- }