codiedev 0.10.0-beta.4 → 0.10.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +11 -5
  2. package/assets/tui-brand-plugin.tsx +14 -2
  3. package/dist/backup/cache.js +1 -5
  4. package/dist/backup/match.js +0 -6
  5. package/dist/backup/run.js +3 -35
  6. package/dist/captureExclusions.js +0 -12
  7. package/dist/captureLog.js +0 -28
  8. package/dist/captureReadiness.js +0 -58
  9. package/dist/captureSignals.js +68 -3
  10. package/dist/cli.js +75 -64
  11. package/dist/codexHookTrust.js +125 -6
  12. package/dist/codexLimitScan.js +2 -109
  13. package/dist/codie.js +50 -114
  14. package/dist/codieBrandInstall.js +0 -18
  15. package/dist/codieLauncher.js +20 -92
  16. package/dist/codieRuntime.js +19 -23
  17. package/dist/codieRuntimeInstall.js +108 -23
  18. package/dist/codieUsage.js +38 -41
  19. package/dist/commands/agentTemplates.generated.js +136 -0
  20. package/dist/commands/agents.js +1066 -0
  21. package/dist/commands/agentsSdk.generated.js +7 -0
  22. package/dist/commands/ask.js +0 -3
  23. package/dist/commands/capture.js +0 -2
  24. package/dist/commands/createTicket.js +0 -10
  25. package/dist/commands/doctor.js +53 -120
  26. package/dist/commands/evals.js +187 -0
  27. package/dist/commands/inbox.js +0 -2
  28. package/dist/commands/library.js +0 -3
  29. package/dist/commands/pack.js +573 -0
  30. package/dist/commands/ping.js +0 -2
  31. package/dist/commands/pull.js +6 -10
  32. package/dist/commands/push.js +2 -12
  33. package/dist/commands/search.js +0 -4
  34. package/dist/commands/send.js +0 -5
  35. package/dist/commands/share.js +0 -4
  36. package/dist/commands/shared.js +0 -35
  37. package/dist/commands/traces.js +344 -0
  38. package/dist/commands/tracesLabel.js +348 -0
  39. package/dist/configDir.js +0 -10
  40. package/dist/connect.js +19 -116
  41. package/dist/connectFlow.js +0 -9
  42. package/dist/copilotHooks.js +391 -0
  43. package/dist/copilotInstallation.js +64 -0
  44. package/dist/cursorHooks.js +38 -30
  45. package/dist/cursorLifecycle.js +109 -0
  46. package/dist/detection.js +0 -30
  47. package/dist/harnessDirs.js +77 -0
  48. package/dist/hook.js +182 -469
  49. package/dist/inboxFormat.js +0 -24
  50. package/dist/launchContext.js +150 -0
  51. package/dist/launcher.js +140 -0
  52. package/dist/limitEvent.js +41 -35
  53. package/dist/limitEventReporter.js +1 -1
  54. package/dist/managedPi.js +240 -0
  55. package/dist/mcp.js +3 -384
  56. package/dist/nativeSteering.js +24 -0
  57. package/dist/packs/codie.js +182 -0
  58. package/dist/packs/harnesses.js +411 -0
  59. package/dist/packs/hookGate.js +256 -0
  60. package/dist/packs/install.js +286 -0
  61. package/dist/packs/manifest.js +126 -0
  62. package/dist/packs/paths.js +81 -0
  63. package/dist/packs/shim.js +214 -0
  64. package/dist/packs/store.js +155 -0
  65. package/dist/packs/sync.js +170 -0
  66. package/dist/piHooks.js +216 -0
  67. package/dist/piRuntime.js +120 -0
  68. package/dist/repoResolver.js +0 -19
  69. package/dist/secret.js +0 -3
  70. package/dist/selfUpdate.js +376 -0
  71. package/dist/skillMarker.js +23 -0
  72. package/dist/subagents.js +135 -0
  73. package/dist/teamSkillContext.js +10 -0
  74. package/dist/transcriptModels.js +6 -8
  75. package/dist/upgradeNudge.js +0 -30
  76. package/dist/utils.js +494 -824
  77. package/dist/version.js +0 -10
  78. package/dist/versionCheck.js +0 -33
  79. package/package.json +8 -9
  80. package/dist/backup/cache.d.ts +0 -14
  81. package/dist/backup/match.d.ts +0 -2
  82. package/dist/backup/run.d.ts +0 -25
  83. package/dist/captureExclusions.d.ts +0 -30
  84. package/dist/captureLog.d.ts +0 -20
  85. package/dist/captureReadiness.d.ts +0 -65
  86. package/dist/captureSignals.d.ts +0 -19
  87. package/dist/cli.d.ts +0 -16
  88. package/dist/codexHookTrust.d.ts +0 -34
  89. package/dist/codexLimitScan.d.ts +0 -64
  90. package/dist/codie.d.ts +0 -2
  91. package/dist/codieBrandInstall.d.ts +0 -11
  92. package/dist/codieLauncher.d.ts +0 -86
  93. package/dist/codieRuntime.d.ts +0 -29
  94. package/dist/codieRuntimeInstall.d.ts +0 -28
  95. package/dist/codieStartup.d.ts +0 -26
  96. package/dist/codieStartup.js +0 -30
  97. package/dist/codieUsage.d.ts +0 -57
  98. package/dist/commands/ask.d.ts +0 -1
  99. package/dist/commands/capture.d.ts +0 -14
  100. package/dist/commands/createTicket.d.ts +0 -27
  101. package/dist/commands/delete.d.ts +0 -1
  102. package/dist/commands/doctor.d.ts +0 -1
  103. package/dist/commands/inbox.d.ts +0 -3
  104. package/dist/commands/library.d.ts +0 -2
  105. package/dist/commands/note.d.ts +0 -1
  106. package/dist/commands/ping.d.ts +0 -1
  107. package/dist/commands/promote.d.ts +0 -1
  108. package/dist/commands/promote.js +0 -53
  109. package/dist/commands/pull.d.ts +0 -2
  110. package/dist/commands/push.d.ts +0 -33
  111. package/dist/commands/react.d.ts +0 -2
  112. package/dist/commands/react.js +0 -40
  113. package/dist/commands/reverseTicket.d.ts +0 -2
  114. package/dist/commands/reverseTicket.js +0 -477
  115. package/dist/commands/search.d.ts +0 -2
  116. package/dist/commands/security.d.ts +0 -1
  117. package/dist/commands/security.js +0 -156
  118. package/dist/commands/send.d.ts +0 -2
  119. package/dist/commands/share.d.ts +0 -2
  120. package/dist/commands/shared.d.ts +0 -64
  121. package/dist/configDir.d.ts +0 -1
  122. package/dist/connect.d.ts +0 -1
  123. package/dist/connectFlow.d.ts +0 -13
  124. package/dist/cursorHooks.d.ts +0 -23
  125. package/dist/detection.d.ts +0 -30
  126. package/dist/hook.d.ts +0 -6
  127. package/dist/inboxFormat.d.ts +0 -38
  128. package/dist/limitEvent.d.ts +0 -16
  129. package/dist/limitEventReporter.d.ts +0 -21
  130. package/dist/mcp.d.ts +0 -12
  131. package/dist/prUrl.d.ts +0 -9
  132. package/dist/prUrl.js +0 -33
  133. package/dist/repoResolver.d.ts +0 -17
  134. package/dist/secret.d.ts +0 -1
  135. package/dist/security.d.ts +0 -102
  136. package/dist/security.js +0 -437
  137. package/dist/securityDeepScan.d.ts +0 -41
  138. package/dist/securityDeepScan.js +0 -248
  139. package/dist/securityDoctor.d.ts +0 -32
  140. package/dist/securityDoctor.js +0 -63
  141. package/dist/securityFeature.d.ts +0 -5
  142. package/dist/securityFeature.js +0 -7
  143. package/dist/securityInstall.d.ts +0 -63
  144. package/dist/securityInstall.js +0 -239
  145. package/dist/securityInventory.d.ts +0 -54
  146. package/dist/securityInventory.js +0 -556
  147. package/dist/securityPilot.d.ts +0 -19
  148. package/dist/securityPilot.js +0 -61
  149. package/dist/securityPolicy.d.ts +0 -33
  150. package/dist/securityPolicy.js +0 -188
  151. package/dist/securitySession.d.ts +0 -6
  152. package/dist/securitySession.js +0 -72
  153. package/dist/transcriptModels.d.ts +0 -18
  154. package/dist/upgradeNudge.d.ts +0 -25
  155. package/dist/utils.d.ts +0 -346
  156. package/dist/version.d.ts +0 -1
  157. package/dist/versionCheck.d.ts +0 -68
package/dist/mcp.js CHANGED
@@ -1,15 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- /**
4
- * Codiedev MCP server.
5
- *
6
- * Exposes the Codiedev artifact-collaboration surface as Model Context
7
- * Protocol tools so Claude Code / Codex / any MCP-capable agent can invoke
8
- * them natively from natural language (e.g. "push the spec we just worked on").
9
- *
10
- * Reads the same ~/.codiedev/config.json the CLI uses. Install + wire up by
11
- * running `npx codiedev connect`.
12
- */
13
3
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
4
  if (k2 === undefined) k2 = k;
15
5
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -45,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
45
35
  })();
46
36
  Object.defineProperty(exports, "__esModule", { value: true });
47
37
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
38
+ const skillMarker_1 = require("./skillMarker");
48
39
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
49
40
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
50
41
  const fs = __importStar(require("fs"));
@@ -53,8 +44,6 @@ const utils_1 = require("./utils");
53
44
  const shared_1 = require("./commands/shared");
54
45
  const inboxFormat_1 = require("./inboxFormat");
55
46
  const PKG_NAME = "codiedev";
56
- // Read version from the bundled package.json so the startup log + tool reports
57
- // always reflect the actually-installed version, rather than a stale constant.
58
47
  const PKG_VERSION = (() => {
59
48
  try {
60
49
  const pkgPath = path.resolve(__dirname, "..", "package.json");
@@ -64,10 +53,6 @@ const PKG_VERSION = (() => {
64
53
  return "unknown";
65
54
  }
66
55
  })();
67
- // ─────────────────────────────────────────────────────────────────────────────
68
- // Tool definitions — descriptions tuned so Claude/Codex resolve natural-language
69
- // requests into the right tool without manual steering.
70
- // ─────────────────────────────────────────────────────────────────────────────
71
56
  const TOOLS = [
72
57
  {
73
58
  name: "codiedev_push",
@@ -237,29 +222,6 @@ const TOOLS = [
237
222
  required: ["body"],
238
223
  },
239
224
  },
240
- {
241
- name: "codiedev_promote",
242
- description: "Promote an auto-extracted Codiedev artifact (spec/bugfix/decision " +
243
- "produced by the session-capture pipeline) to an authored artifact " +
244
- "so teammates can collaborate on it. Use when the user says 'publish " +
245
- "the extracted spec', 'promote this', or 'make the auto-extracted X " +
246
- "shareable'.",
247
- inputSchema: {
248
- type: "object",
249
- properties: {
250
- artifactId: {
251
- type: "string",
252
- description: "The extracted artifact's id from Codiedev.",
253
- },
254
- keyOverride: {
255
- type: "string",
256
- description: "Optional filename key for the promoted artifact. If omitted, " +
257
- "one is generated from the artifact's type + session id.",
258
- },
259
- },
260
- required: ["artifactId"],
261
- },
262
- },
263
225
  {
264
226
  name: "codiedev_share_with",
265
227
  description: "Grant a teammate persistent read (or edit) access to an artifact " +
@@ -306,27 +268,6 @@ const TOOLS = [
306
268
  required: ["filename", "to"],
307
269
  },
308
270
  },
309
- {
310
- name: "codiedev_react",
311
- description: "React to a feed post with an emoji. Use when the user says 'react " +
312
- "to that post with X', 'mark as used', or 'upvote'. The 🛠 " +
313
- "reaction is the signal for 'I used this' and bumps the linked " +
314
- "artifact's reuse count. Pass the post id (get it from " +
315
- "codiedev_get_library or a previous feed response).",
316
- inputSchema: {
317
- type: "object",
318
- properties: {
319
- postId: { type: "string", description: "Feed post id." },
320
- emoji: {
321
- type: "string",
322
- enum: ["👍", "🔥", "💡", "🛠", "👑"],
323
- description: "Reaction emoji. 🛠 = 'I used this' (counts heaviest toward " +
324
- "the author's score and the artifact's reuse count).",
325
- },
326
- },
327
- required: ["postId", "emoji"],
328
- },
329
- },
330
271
  {
331
272
  name: "codiedev_search",
332
273
  description: "Search the team's artifact library by natural-language query. Use " +
@@ -413,53 +354,11 @@ const TOOLS = [
413
354
  },
414
355
  },
415
356
  },
416
- {
417
- name: "codiedev_reverse_ticket",
418
- description: "Generate a Jira-ready reverse-ticket draft from the work the user has " +
419
- "done in their CURRENT git branch — mid-session, before any PR exists. " +
420
- "Reads local git state (current branch, divergence from main, diff, " +
421
- "commits, files changed) and runs it through the codiedev reverse-" +
422
- "ticket writer. The draft lands in the user's portal at " +
423
- "/portal/agentic-ticketing where they can edit the title, description, " +
424
- "and scope, then push to Jira. Use when the user asks to 'create a " +
425
- "reverse ticket', 'draft a Jira ticket from this work', 'write up what " +
426
- "I've done in this branch', or runs `codiedev reverse-ticket` directly. " +
427
- "The webhook on PR-open later dedupes against this draft so the user " +
428
- "never gets a double ticket. The draft is intentionally not auto-pushed " +
429
- "to Jira — trust comes from the user reviewing in the portal first.",
430
- inputSchema: {
431
- type: "object",
432
- properties: {
433
- title: {
434
- type: "string",
435
- description: "Optional working title for the ticket. Defaults to the most " +
436
- "recent commit subject on the branch.",
437
- },
438
- base: {
439
- type: "string",
440
- description: "Optional base ref to diff against. Defaults to 'origin/main', " +
441
- "falls back to 'origin/master'.",
442
- },
443
- forcedArtifactKey: {
444
- type: "string",
445
- description: "Optional — force the writer to link to a specific artifact key " +
446
- "for context (e.g. 'spec-auth.md').",
447
- },
448
- },
449
- },
450
- },
451
357
  ];
452
- // ─────────────────────────────────────────────────────────────────────────────
453
- // Server
454
- // ─────────────────────────────────────────────────────────────────────────────
455
358
  const server = new index_js_1.Server({ name: PKG_NAME, version: PKG_VERSION }, { capabilities: { tools: {} } });
456
359
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
457
360
  tools: TOOLS,
458
361
  }));
459
- /**
460
- * Fire-and-forget telemetry — POST one event per tool invocation. Never blocks,
461
- * never throws into the user-facing path. Drop silently on any failure.
462
- */
463
362
  function emitTelemetry(config, event) {
464
363
  if (!config)
465
364
  return;
@@ -473,7 +372,6 @@ function emitTelemetry(config, event) {
473
372
  mcpVersion: PKG_VERSION,
474
373
  },
475
374
  }).catch(() => {
476
- // Swallow — telemetry should never affect the user's session.
477
375
  });
478
376
  }
479
377
  server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
@@ -538,22 +436,16 @@ async function dispatchTool(name, args, config) {
538
436
  return await handleInbox(args, config);
539
437
  case "codiedev_note":
540
438
  return await handleNote(args, config);
541
- case "codiedev_promote":
542
- return await handlePromote(args, config);
543
439
  case "codiedev_share_with":
544
440
  return await handleShareWith(args, config);
545
441
  case "codiedev_send_to":
546
442
  return await handleSendTo(args, config);
547
- case "codiedev_react":
548
- return await handleReact(args, config);
549
443
  case "codiedev_ask":
550
444
  return await handleAsk(args, config);
551
445
  case "codiedev_search":
552
446
  return await handleSearch(args, config);
553
447
  case "codiedev_get_library":
554
448
  return await handleGetLibrary(args, config);
555
- case "codiedev_reverse_ticket":
556
- return await handleReverseTicket(args, config);
557
449
  default:
558
450
  return {
559
451
  isError: true,
@@ -577,7 +469,7 @@ async function handlePush(args, config) {
577
469
  }
578
470
  const res = await (0, shared_1.apiRequest)("POST", "/api/cli/push", {
579
471
  config,
580
- body: { filename, markdown, type, kind, tags, force },
472
+ body: { filename, markdown: (0, skillMarker_1.stripSkillMarker)(markdown), type, kind, tags, force },
581
473
  });
582
474
  const tagSummary = res.tags && res.tags.length > 0 ? `, tags=[${res.tags.join(", ")}]` : "";
583
475
  return {
@@ -598,10 +490,6 @@ async function handlePull(args, config) {
598
490
  throw new Error("key required");
599
491
  const res = await (0, shared_1.apiRequest)("GET", "/api/cli/pull", { config, query: { key, version } });
600
492
  const a = res.artifact;
601
- // Lead with the new-vocab kind. Legacy doc-shape (spec/decision/...) is
602
- // surfaced as a tag list after, so callers still see it but it's no
603
- // longer the primary label. Falls back to "doc" if the row pre-dates the
604
- // kind field.
605
493
  const kindLabel = a.kind ?? "doc";
606
494
  const tagList = (a.tags ?? []).filter((t) => t).join(", ");
607
495
  const tagSuffix = tagList ? ` · tags: ${tagList}` : "";
@@ -609,7 +497,7 @@ async function handlePull(args, config) {
609
497
  `**${kindLabel}** · v${a.version ?? 1} · ${a.lifecycle ?? "draft"}${tagSuffix} · ` +
610
498
  `updated ${(0, shared_1.timeAgo)(a.updatedAt ?? a.createdAt)}\n\n---\n\n`;
611
499
  return {
612
- content: [{ type: "text", text: header + a.markdown }],
500
+ content: [{ type: "text", text: header + (a.kind === "skill" || (!a.kind && (0, skillMarker_1.looksLikeSkill)(a.markdown)) ? (0, skillMarker_1.stampSkillMarker)(a.markdown, a._id) : a.markdown) }],
613
501
  };
614
502
  }
615
503
  async function handleDelete(args, config) {
@@ -685,9 +573,6 @@ async function handleInbox(args, config) {
685
573
  config,
686
574
  query: { unreadOnly: unreadOnly ? "1" : undefined, limit },
687
575
  });
688
- // Shared with `codiedev inbox` so this agent-facing path can never drift
689
- // back to pings-only. CLAUDE.md routes "any messages?" here, so a
690
- // mentions-blind version reproduces the bug for agents.
691
576
  const text = (0, inboxFormat_1.formatInbox)({
692
577
  pings: res.pings,
693
578
  mentions: res.mentions,
@@ -705,21 +590,6 @@ async function handleNote(args, config) {
705
590
  content: [{ type: "text", text: `✓ Noted (${res.key})` }],
706
591
  };
707
592
  }
708
- async function handlePromote(args, config) {
709
- const artifactId = asString(args.artifactId);
710
- const keyOverride = asStringOrUndefined(args.keyOverride);
711
- if (!artifactId)
712
- throw new Error("artifactId required");
713
- const res = await (0, shared_1.apiRequest)("POST", "/api/cli/promote", { config, body: { artifactId, keyOverride } });
714
- return {
715
- content: [
716
- {
717
- type: "text",
718
- text: `✓ Promoted to authored artifact ${res.key} (id=${res.artifactId}).`,
719
- },
720
- ],
721
- };
722
- }
723
593
  async function handleShareWith(args, config) {
724
594
  const filename = asString(args.filename);
725
595
  const to = asString(args.to);
@@ -754,8 +624,6 @@ async function handleShareWith(args, config) {
754
624
  ],
755
625
  };
756
626
  }
757
- // noop / duplicate path — surface where the existing grant came from so
758
- // the user knows whether to expect it next time.
759
627
  const e = res.existing;
760
628
  let why = "";
761
629
  if (e) {
@@ -810,26 +678,6 @@ async function handleSendTo(args, config) {
810
678
  return formatAmbiguousRecipient(err, to);
811
679
  }
812
680
  }
813
- async function handleReact(args, config) {
814
- const postId = asString(args.postId);
815
- const emoji = asString(args.emoji);
816
- if (!postId)
817
- throw new Error("postId required");
818
- if (!emoji)
819
- throw new Error("emoji required");
820
- const res = await (0, shared_1.apiRequest)("POST", "/api/cli/react", {
821
- config,
822
- body: { postId, emoji },
823
- });
824
- const verb = res.action === "added"
825
- ? "Reacted"
826
- : res.action === "removed"
827
- ? "Removed reaction"
828
- : "Swapped reaction to";
829
- return {
830
- content: [{ type: "text", text: `✓ ${verb} ${res.emoji}` }],
831
- };
832
- }
833
681
  async function handleSearch(args, config) {
834
682
  const query = asString(args.query);
835
683
  const limit = asIntOrUndefined(args.limit);
@@ -908,9 +756,6 @@ async function handleGetLibrary(args, config) {
908
756
  const v = a.version ? ` v${a.version}` : "";
909
757
  const life = a.lifecycle ? ` · ${a.lifecycle}` : "";
910
758
  const when = a.updatedAt ? ` · ${(0, shared_1.timeAgo)(a.updatedAt)}` : "";
911
- // Lead with the canonical kind (doc | skill). Tags carry the legacy
912
- // doc-shape (spec/decision/...) plus any author-added labels — surface
913
- // them after the kind so the row is self-describing.
914
759
  const k = a.kind ?? (a.type === "note" ? "doc" : "doc");
915
760
  const tagList = (a.tags ?? []).length > 0 ? ` [${a.tags.join(", ")}]` : "";
916
761
  lines.push(`[${k}]${tagList} ${loc}${a.key ?? a.title}${v}${life}${when}`);
@@ -937,226 +782,6 @@ function formatAmbiguousRecipient(err, to) {
937
782
  }
938
783
  throw err;
939
784
  }
940
- async function handleReverseTicket(args, config) {
941
- const explicitTitle = asStringOrUndefined(args.title);
942
- const explicitBase = asStringOrUndefined(args.base);
943
- const forcedKey = asStringOrUndefined(args.forcedArtifactKey);
944
- // Helper that runs git from cwd with a hard-fail on error.
945
- const { execSync } = await Promise.resolve().then(() => __importStar(require("child_process")));
946
- const git = (cmd) => {
947
- try {
948
- return execSync(`git ${cmd}`, {
949
- stdio: ["pipe", "pipe", "pipe"],
950
- maxBuffer: 32 * 1024 * 1024,
951
- })
952
- .toString("utf8")
953
- .trim();
954
- }
955
- catch (err) {
956
- throw new Error(`git ${cmd} failed: ${err.message}`);
957
- }
958
- };
959
- // Confirm we're in a git repo.
960
- try {
961
- git("rev-parse --is-inside-work-tree");
962
- }
963
- catch {
964
- throw new Error("Not inside a git repository. Run this from a checked-out repo.");
965
- }
966
- // Resolve base ref — explicit, then origin/main, then origin/master.
967
- const candidates = explicitBase
968
- ? [explicitBase]
969
- : ["origin/main", "origin/master"];
970
- let baseRef = null;
971
- for (const c of candidates) {
972
- try {
973
- git(`rev-parse --verify ${c}`);
974
- baseRef = c;
975
- break;
976
- }
977
- catch {
978
- // try next
979
- }
980
- }
981
- if (!baseRef) {
982
- throw new Error(`Couldn't find a base ref (tried ${candidates.join(", ")}). ` +
983
- `Pass an explicit base via the 'base' argument.`);
984
- }
985
- const branch = git("rev-parse --abbrev-ref HEAD");
986
- if (branch === "HEAD") {
987
- throw new Error("Detached HEAD — checkout a branch first.");
988
- }
989
- const baseSha = git(`merge-base HEAD ${baseRef}`);
990
- const headSha = git("rev-parse HEAD");
991
- // Filter generated/lockfile noise so the LLM's diff budget gets spent on
992
- // real source. The --stat block (collected separately below) still includes
993
- // every file untouched, so excluded files still appear in the ticket's
994
- // "Other files touched" section if relevant.
995
- const isNoise = (p) => /(^|\/)(node_modules|dist|build|\.next|\.turbo|coverage|out)\//.test(p) ||
996
- /(^|\/)package-lock\.json$/.test(p) ||
997
- /(^|\/)yarn\.lock$/.test(p) ||
998
- /(^|\/)pnpm-lock\.yaml$/.test(p) ||
999
- /(^|\/)bun\.lock(b)?$/.test(p) ||
1000
- /(^|\/)Cargo\.lock$/.test(p) ||
1001
- /(^|\/)Gemfile\.lock$/.test(p) ||
1002
- /(^|\/)poetry\.lock$/.test(p) ||
1003
- /(^|\/)go\.sum$/.test(p);
1004
- // Helper: run a shell command tolerating non-zero exit codes (git diff
1005
- // --no-index exits 1 when files differ, which is the normal case).
1006
- // Reuses the execSync already imported above for the git() helper.
1007
- const shellTolerant = (cmd) => {
1008
- try {
1009
- return execSync(`${cmd} || true`, {
1010
- stdio: ["pipe", "pipe", "pipe"],
1011
- maxBuffer: 32 * 1024 * 1024,
1012
- })
1013
- .toString("utf8")
1014
- .trim();
1015
- }
1016
- catch {
1017
- return "";
1018
- }
1019
- };
1020
- const shQuote = (s) => `'${s.replace(/'/g, "'\\''")}'`;
1021
- // Capture all work the developer has done relative to the base ref:
1022
- // - committed changes between base and HEAD
1023
- // - uncommitted modifications to tracked files
1024
- // - new untracked files (path listed + content via synthetic diff)
1025
- // Matches the user's intent ("ticket my current changes") rather than the
1026
- // narrower "only what's been committed" interpretation.
1027
- const trackedRaw = git(`diff --name-only ${baseSha}`);
1028
- const trackedFiles = trackedRaw ? trackedRaw.split("\n").filter(Boolean) : [];
1029
- const untrackedRaw = safeGit(() => git("ls-files --others --exclude-standard"));
1030
- const untrackedFiles = untrackedRaw
1031
- ? untrackedRaw.split("\n").filter(Boolean)
1032
- : [];
1033
- const filesChanged = Array.from(new Set([...trackedFiles, ...untrackedFiles]));
1034
- if (filesChanged.length === 0) {
1035
- throw new Error(`No changes detected between ${baseRef} and your working tree on ${branch}.`);
1036
- }
1037
- // --stat block: compact ground truth for "every file touched". Tracked
1038
- // changes from `git diff --stat baseSha`; untracked files appended as
1039
- // synthesized stat rows so the LLM sees them with line counts.
1040
- let stat = "";
1041
- try {
1042
- const trackedStat = git(`diff --stat=200 ${baseSha}`);
1043
- const untrackedStatLines = untrackedFiles.map((f) => {
1044
- const wc = shellTolerant(`wc -l < ${shQuote(f)}`);
1045
- const n = parseInt(wc.split(/\s+/)[0] || "0", 10) || 0;
1046
- return ` ${f} | ${n} ++++++++++ (new file)`;
1047
- });
1048
- stat = [trackedStat, ...untrackedStatLines]
1049
- .filter(Boolean)
1050
- .join("\n")
1051
- .slice(0, 8_000);
1052
- }
1053
- catch {
1054
- // Best effort.
1055
- }
1056
- // Diff body: 40k cap, noise-filtered. Tracked changes via `git diff baseSha`,
1057
- // plus synthetic add-only diffs for untracked files via `git diff --no-index`.
1058
- let diff = "";
1059
- try {
1060
- const sourceTracked = trackedFiles.filter((f) => !isNoise(f));
1061
- const trackedDiff = sourceTracked.length > 0
1062
- ? git(`diff ${baseSha} -- ${sourceTracked.map(shQuote).join(" ")}`)
1063
- : git(`diff ${baseSha}`);
1064
- const sourceUntracked = untrackedFiles.filter((f) => !isNoise(f));
1065
- const untrackedDiffs = sourceUntracked.map((f) => shellTolerant(`git diff --no-index --no-color -- /dev/null ${shQuote(f)}`));
1066
- diff = [trackedDiff, ...untrackedDiffs]
1067
- .filter(Boolean)
1068
- .join("\n")
1069
- .slice(0, 40_000);
1070
- }
1071
- catch {
1072
- // Best effort.
1073
- }
1074
- // Repo name from origin remote.
1075
- let repo;
1076
- try {
1077
- const remoteUrl = git("config --get remote.origin.url");
1078
- const m = remoteUrl.match(/[:/]([^/:]+)\/([^/:]+?)(?:\.git)?$/);
1079
- if (!m) {
1080
- throw new Error(`Couldn't parse owner/repo from remote: ${remoteUrl}`);
1081
- }
1082
- repo = `${m[1]}/${m[2]}`;
1083
- }
1084
- catch (err) {
1085
- throw new Error(`Couldn't read git remote.origin.url: ${err.message}`);
1086
- }
1087
- const title = explicitTitle ?? safeGit(() => git("log -1 --format=%s")) ?? `WIP: ${branch}`;
1088
- const author = safeGit(() => git("config --get user.name"));
1089
- const authorEmail = safeGit(() => git("config --get user.email"));
1090
- // Post to backend.
1091
- const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reverseTicketFromBranch", {
1092
- config,
1093
- body: {
1094
- branch: {
1095
- repo,
1096
- branch,
1097
- baseSha,
1098
- headSha,
1099
- title,
1100
- author,
1101
- authorEmail,
1102
- filesChanged,
1103
- diff: diff || undefined,
1104
- stat: stat || undefined,
1105
- },
1106
- forcedArtifactKey: forcedKey,
1107
- },
1108
- });
1109
- if (!res.ok || !res.artifactId) {
1110
- return {
1111
- isError: true,
1112
- content: [
1113
- {
1114
- type: "text",
1115
- text: "Reverse-ticket generation returned no result. The writer may have " +
1116
- "skipped due to missing context (no captured sessions, etc.). Try " +
1117
- "again after working on the branch a bit more, or check the " +
1118
- "server logs.",
1119
- },
1120
- ],
1121
- };
1122
- }
1123
- // Always return an absolute URL so MCP clients (Copilot Chat, Claude Code,
1124
- // etc.) can render the link correctly without guessing a host. Default to
1125
- // codiedev.com; allow override via CODIEDEV_PORTAL_URL for self-hosted.
1126
- const portalHost = (process.env.CODIEDEV_PORTAL_URL || "https://codiedev.com").replace(/\/$/, "");
1127
- const portalLink = res.portalUrl.startsWith("http")
1128
- ? res.portalUrl
1129
- : `${portalHost}${res.portalUrl.startsWith("/") ? "" : "/"}${res.portalUrl}`;
1130
- const verb = res.action === "overwritten" ? "Updated" : "Created";
1131
- return {
1132
- content: [
1133
- {
1134
- type: "text",
1135
- text: `✓ ${verb} reverse-ticket draft for branch \`${branch}\` (${repo}).\n` +
1136
- ` files changed: ${filesChanged.length}\n` +
1137
- ` base: ${baseSha.slice(0, 12)} → head: ${headSha.slice(0, 12)} (${baseRef})\n` +
1138
- ` diff size: ${diff.length} chars\n` +
1139
- ` artifact: ${res.artifactKey ?? res.artifactId}\n\n` +
1140
- `Open in your portal to review, edit, and push to Jira:\n` +
1141
- ` ${portalLink}\n\n` +
1142
- `Each call creates a fresh draft — if you've made several for the ` +
1143
- `same branch, clean them up from the portal.`,
1144
- },
1145
- ],
1146
- };
1147
- }
1148
- // Run a git invocation; return undefined instead of throwing.
1149
- function safeGit(fn) {
1150
- try {
1151
- return fn();
1152
- }
1153
- catch {
1154
- return undefined;
1155
- }
1156
- }
1157
- // ─────────────────────────────────────────────────────────────────────────────
1158
- // Helpers
1159
- // ─────────────────────────────────────────────────────────────────────────────
1160
785
  function asString(v) {
1161
786
  return typeof v === "string" ? v : "";
1162
787
  }
@@ -1174,20 +799,14 @@ function asStringArrayOrUndefined(v) {
1174
799
  return undefined;
1175
800
  return v.filter((x) => typeof x === "string");
1176
801
  }
1177
- // ─────────────────────────────────────────────────────────────────────────────
1178
- // Main
1179
- // ─────────────────────────────────────────────────────────────────────────────
1180
802
  async function main() {
1181
803
  const transport = new stdio_js_1.StdioServerTransport();
1182
804
  await server.connect(transport);
1183
- // stdio transport handles I/O until process exits.
1184
- // Log to stderr only — stdout is reserved for MCP protocol.
1185
805
  process.stderr.write(`[codiedev-mcp] ready (v${PKG_VERSION}, config ${(0, utils_1.readConfig)() ? "present" : "missing"})\n`);
1186
806
  }
1187
807
  main().catch((err) => {
1188
808
  process.stderr.write(`[codiedev-mcp] fatal: ${err.message}\n`);
1189
809
  process.exit(1);
1190
810
  });
1191
- // Avoid "Cannot find name 'path', 'fs'" since we imported them but may not use.
1192
811
  void path;
1193
812
  void fs;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseNativeSteering = parseNativeSteering;
4
+ function parseNativeSteering(content) {
5
+ const interrupts = new Set();
6
+ const abortedTurns = new Set();
7
+ const rejections = new Set();
8
+ for (const [index, line] of content.split("\n").entries()) {
9
+ try {
10
+ const event = JSON.parse(line);
11
+ const id = String(event.id ?? event.uuid ?? event.toolCallId ?? index);
12
+ if (event.type === "agent.interruption")
13
+ interrupts.add(id);
14
+ if (event.type === "turn_ended" && event.status === "aborted")
15
+ abortedTurns.add(id);
16
+ if (event.type === "agent.rejection")
17
+ rejections.add(id);
18
+ if (event.type === "tool_result" && event.error?.code === "user_denied")
19
+ rejections.add(id);
20
+ }
21
+ catch { }
22
+ }
23
+ return { interrupts: Math.max(interrupts.size, abortedTurns.size), rejections: rejections.size };
24
+ }