codiedev 0.9.0-beta.0 → 0.9.1

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/connect.js CHANGED
@@ -278,7 +278,7 @@ async function runConnect(args = []) {
278
278
  }
279
279
  };
280
280
  if (hasClaude) {
281
- runInstall("claude-code-hook", utils_1.installHook, "Claude Code SessionEnd hook (~/.claude/settings.json)", "claudeCode-hook");
281
+ runInstall("claude-code-hook", utils_1.installHook, "Claude Code SessionEnd (capture) + UserPromptSubmit (skill discovery) hooks (~/.claude/settings.json)", "claudeCode-hook");
282
282
  runInstall("claude-code-instructions", utils_1.installClaudeCodeInstructions, "Claude Code agent instructions (~/.claude/CLAUDE.md)", "claudeCode-instructions");
283
283
  }
284
284
  if (hasCodex) {
@@ -319,7 +319,7 @@ async function runConnect(args = []) {
319
319
  console.log(`\nConnected to ${companyName}`);
320
320
  console.log(`Tracking ${repos.length} repo${repos.length === 1 ? "" : "s"}`);
321
321
  if (installed.length > 0) {
322
- console.log("Installed capture hook(s):");
322
+ console.log("Installed hook(s):");
323
323
  for (const target of installed) {
324
324
  console.log(` - ${target}`);
325
325
  }
package/dist/hook.js CHANGED
@@ -35,8 +35,11 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  const fs = __importStar(require("fs"));
38
+ const os = __importStar(require("os"));
39
+ const path = __importStar(require("path"));
38
40
  const https = __importStar(require("https"));
39
41
  const http = __importStar(require("http"));
42
+ const child_process_1 = require("child_process");
40
43
  const utils_1 = require("./utils");
41
44
  const version_1 = require("./version");
42
45
  function getJson(url, bearerToken) {
@@ -86,9 +89,10 @@ async function runDiscover(prompt) {
86
89
  .slice(0, 3)
87
90
  .map((s) => `- ${s.key} — ${(s.score * 100).toFixed(0)}% match`)
88
91
  .join("\n");
89
- const additionalContext = "A CodieDev team skill may apply to this task:\n" +
92
+ const additionalContext = "Your team has a CodieDev skill that fits this task — prefer it over improvising:\n" +
90
93
  lines +
91
- "\nIf one fits, pull and use it before improvising: `codiedev pull <key>`.";
94
+ "\nPull and follow it now: `codiedev pull <key>`. It encodes the team's vetted " +
95
+ "approach. Skip it only if it clearly doesn't apply.";
92
96
  process.stdout.write(JSON.stringify({
93
97
  hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext },
94
98
  }));
@@ -154,6 +158,20 @@ function resolveMode(arg) {
154
158
  return "claude-code";
155
159
  }
156
160
  async function main() {
161
+ // Detached uploader child (spawned by the capture path below). The job —
162
+ // including transcript and token — is on disk; no stdin is needed, so handle
163
+ // this before readStdin() to avoid blocking on the ignored stdin pipe.
164
+ if (process.argv[2] === "upload") {
165
+ const jobFile = process.argv[3];
166
+ if (jobFile) {
167
+ await (0, utils_1.runCaptureUpload)(jobFile, {
168
+ post: postJson,
169
+ readFileSync: fs.readFileSync,
170
+ unlinkSync: fs.unlinkSync,
171
+ });
172
+ }
173
+ process.exit(0);
174
+ }
157
175
  let hookInput = {};
158
176
  try {
159
177
  const raw = await readStdin();
@@ -225,11 +243,18 @@ async function main() {
225
243
  capturedAt: Date.now(),
226
244
  source: mode,
227
245
  };
246
+ // Fire the upload from a fully detached child and exit immediately. Awaiting
247
+ // it inline let Claude Code's SessionEnd shutdown window elapse and kill the
248
+ // still-running hook ("Hook cancelled") on large transcripts — even though
249
+ // the body had already reached the server. The detached child outlives this
250
+ // process and finishes the POST in the background.
228
251
  try {
229
- await postJson(`${config.backendUrl}/api/captureSession`, payload, config.token);
252
+ const hookScriptPath = process.argv[1];
253
+ const tmpFile = path.join(os.tmpdir(), `codiedev-capture-${session_id ?? process.pid}.json`);
254
+ (0, utils_1.dispatchCaptureDetached)({ url: `${config.backendUrl}/api/captureSession`, token: config.token, body: payload }, hookScriptPath, { spawn: child_process_1.spawn, writeFileSync: fs.writeFileSync, tmpFile });
230
255
  }
231
256
  catch (err) {
232
- process.stderr.write(`[codiedev-hook] Warning: Failed to capture session — ${err.message}\n`);
257
+ process.stderr.write(`[codiedev-hook] Warning: Failed to dispatch session capture — ${err.message}\n`);
233
258
  }
234
259
  process.exit(0);
235
260
  }
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import * as fs from "fs";
2
+ import { spawn as nodeSpawn } from "child_process";
1
3
  export interface CodiedevConfig {
2
4
  token: string;
3
5
  companyId: string;
@@ -101,3 +103,22 @@ export interface ParsedStats {
101
103
  export declare function parseClaudeCodeStats(content: string): ParsedStats;
102
104
  export declare function parseCodexStats(content: string): ParsedStats;
103
105
  export declare function extractCodexRepoUrl(content: string): string | null;
106
+ export interface CaptureUploadJob {
107
+ url: string;
108
+ token: string;
109
+ body: Record<string, unknown>;
110
+ }
111
+ interface DispatchDeps {
112
+ spawn: typeof nodeSpawn;
113
+ writeFileSync: typeof fs.writeFileSync;
114
+ tmpFile: string;
115
+ nodePath?: string;
116
+ }
117
+ export declare function dispatchCaptureDetached(job: CaptureUploadJob, hookScriptPath: string, deps: DispatchDeps): void;
118
+ interface UploadDeps {
119
+ post: (url: string, body: Record<string, unknown>, token: string) => Promise<void>;
120
+ readFileSync: typeof fs.readFileSync;
121
+ unlinkSync: typeof fs.unlinkSync;
122
+ }
123
+ export declare function runCaptureUpload(jobFile: string, deps: UploadDeps): Promise<void>;
124
+ export {};
package/dist/utils.js CHANGED
@@ -62,6 +62,8 @@ exports.installCursorHook = installCursorHook;
62
62
  exports.parseClaudeCodeStats = parseClaudeCodeStats;
63
63
  exports.parseCodexStats = parseCodexStats;
64
64
  exports.extractCodexRepoUrl = extractCodexRepoUrl;
65
+ exports.dispatchCaptureDetached = dispatchCaptureDetached;
66
+ exports.runCaptureUpload = runCaptureUpload;
65
67
  const fs = __importStar(require("fs"));
66
68
  const path = __importStar(require("path"));
67
69
  const os = __importStar(require("os"));
@@ -854,3 +856,34 @@ function extractCodexRepoUrl(content) {
854
856
  }
855
857
  return null;
856
858
  }
859
+ // Fire-and-forget the session-capture upload from a fully detached child so the
860
+ // SessionEnd hook can exit 0 immediately. Awaiting the upload inline let Claude
861
+ // Code's shutdown window elapse and kill the hook ("Hook cancelled") on large
862
+ // transcripts. The job (incl. bearer token) is written to a file rather than
863
+ // passed via argv so it never shows up in the process list.
864
+ function dispatchCaptureDetached(job, hookScriptPath, deps) {
865
+ deps.writeFileSync(deps.tmpFile, JSON.stringify(job), { mode: 0o600 });
866
+ const child = deps.spawn(deps.nodePath ?? process.execPath, [hookScriptPath, "upload", deps.tmpFile], { detached: true, stdio: "ignore" });
867
+ child.unref();
868
+ }
869
+ // Runs inside the detached child spawned by `dispatchCaptureDetached`: read the
870
+ // persisted job, POST it, and ALWAYS delete the temp file afterwards (even on
871
+ // failure) so we don't litter the tmp dir. Never throws — capture is
872
+ // best-effort.
873
+ async function runCaptureUpload(jobFile, deps) {
874
+ try {
875
+ const job = JSON.parse(deps.readFileSync(jobFile, "utf8"));
876
+ await deps.post(job.url, job.body, job.token);
877
+ }
878
+ catch {
879
+ // best-effort — the parent already exited; nothing to report to.
880
+ }
881
+ finally {
882
+ try {
883
+ deps.unlinkSync(jobFile);
884
+ }
885
+ catch {
886
+ // temp file already gone — fine.
887
+ }
888
+ }
889
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.0-beta.0",
3
+ "version": "0.9.1",
4
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",