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.
- package/README.md +11 -5
- package/assets/tui-brand-plugin.tsx +14 -2
- 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 +68 -3
- package/dist/cli.js +75 -64
- package/dist/codexHookTrust.js +125 -6
- package/dist/codexLimitScan.js +2 -109
- package/dist/codie.js +50 -114
- package/dist/codieBrandInstall.js +0 -18
- package/dist/codieLauncher.js +20 -92
- package/dist/codieRuntime.js +19 -23
- package/dist/codieRuntimeInstall.js +108 -23
- package/dist/codieUsage.js +38 -41
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1066 -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 +53 -120
- package/dist/commands/evals.js +187 -0
- package/dist/commands/inbox.js +0 -2
- package/dist/commands/library.js +0 -3
- package/dist/commands/pack.js +573 -0
- package/dist/commands/ping.js +0 -2
- package/dist/commands/pull.js +6 -10
- package/dist/commands/push.js +2 -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 +344 -0
- package/dist/commands/tracesLabel.js +348 -0
- package/dist/configDir.js +0 -10
- package/dist/connect.js +19 -116
- package/dist/connectFlow.js +0 -9
- package/dist/copilotHooks.js +391 -0
- package/dist/copilotInstallation.js +64 -0
- package/dist/cursorHooks.js +38 -30
- package/dist/cursorLifecycle.js +109 -0
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +77 -0
- package/dist/hook.js +182 -469
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +150 -0
- package/dist/launcher.js +140 -0
- package/dist/limitEvent.js +41 -35
- package/dist/limitEventReporter.js +1 -1
- package/dist/managedPi.js +240 -0
- package/dist/mcp.js +3 -384
- package/dist/nativeSteering.js +24 -0
- package/dist/packs/codie.js +182 -0
- package/dist/packs/harnesses.js +411 -0
- package/dist/packs/hookGate.js +256 -0
- package/dist/packs/install.js +286 -0
- package/dist/packs/manifest.js +126 -0
- package/dist/packs/paths.js +81 -0
- package/dist/packs/shim.js +214 -0
- package/dist/packs/store.js +155 -0
- package/dist/packs/sync.js +170 -0
- package/dist/piHooks.js +216 -0
- package/dist/piRuntime.js +120 -0
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/selfUpdate.js +376 -0
- package/dist/skillMarker.js +23 -0
- package/dist/subagents.js +135 -0
- package/dist/teamSkillContext.js +10 -0
- package/dist/transcriptModels.js +6 -8
- package/dist/upgradeNudge.js +0 -30
- package/dist/utils.js +494 -824
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +8 -9
- 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 -19
- package/dist/cli.d.ts +0 -16
- package/dist/codexHookTrust.d.ts +0 -34
- 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 -86
- package/dist/codieRuntime.d.ts +0 -29
- package/dist/codieRuntimeInstall.d.ts +0 -28
- package/dist/codieStartup.d.ts +0 -26
- package/dist/codieStartup.js +0 -30
- package/dist/codieUsage.d.ts +0 -57
- 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 -1
- 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/ping.d.ts +0 -1
- package/dist/commands/promote.d.ts +0 -1
- package/dist/commands/promote.js +0 -53
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/push.d.ts +0 -33
- package/dist/commands/react.d.ts +0 -2
- package/dist/commands/react.js +0 -40
- package/dist/commands/reverseTicket.d.ts +0 -2
- package/dist/commands/reverseTicket.js +0 -477
- package/dist/commands/search.d.ts +0 -2
- package/dist/commands/security.d.ts +0 -1
- package/dist/commands/security.js +0 -156
- 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/configDir.d.ts +0 -1
- package/dist/connect.d.ts +0 -1
- package/dist/connectFlow.d.ts +0 -13
- package/dist/cursorHooks.d.ts +0 -23
- package/dist/detection.d.ts +0 -30
- package/dist/hook.d.ts +0 -6
- package/dist/inboxFormat.d.ts +0 -38
- package/dist/limitEvent.d.ts +0 -16
- package/dist/limitEventReporter.d.ts +0 -21
- package/dist/mcp.d.ts +0 -12
- package/dist/prUrl.d.ts +0 -9
- package/dist/prUrl.js +0 -33
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/security.d.ts +0 -102
- package/dist/security.js +0 -437
- package/dist/securityDeepScan.d.ts +0 -41
- package/dist/securityDeepScan.js +0 -248
- package/dist/securityDoctor.d.ts +0 -32
- package/dist/securityDoctor.js +0 -63
- package/dist/securityFeature.d.ts +0 -5
- package/dist/securityFeature.js +0 -7
- package/dist/securityInstall.d.ts +0 -63
- package/dist/securityInstall.js +0 -239
- package/dist/securityInventory.d.ts +0 -54
- package/dist/securityInventory.js +0 -556
- package/dist/securityPilot.d.ts +0 -19
- package/dist/securityPilot.js +0 -61
- package/dist/securityPolicy.d.ts +0 -33
- package/dist/securityPolicy.js +0 -188
- package/dist/securitySession.d.ts +0 -6
- package/dist/securitySession.js +0 -72
- package/dist/transcriptModels.d.ts +0 -18
- package/dist/upgradeNudge.d.ts +0 -25
- package/dist/utils.d.ts +0 -346
- package/dist/version.d.ts +0 -1
- 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
|
+
}
|