codiedev 0.10.0-beta.1 → 0.10.0-beta.11
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/opencode-plugin.mjs +6 -0
- package/assets/session-key.mjs +48 -0
- package/assets/tui-brand-plugin.tsx +73 -0
- 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 +184 -0
- package/dist/cli.js +135 -72
- package/dist/cliSession.js +456 -0
- package/dist/codexHookTrust.js +125 -6
- package/dist/codexLimitScan.js +359 -0
- package/dist/codie.js +77 -130
- package/dist/codieBrandInstall.js +80 -0
- package/dist/codieLauncher.js +76 -79
- package/dist/codieRuntime.js +19 -23
- package/dist/codieRuntimeInstall.js +108 -23
- package/dist/codieUsage.js +181 -0
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1101 -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 +18 -11
- package/dist/connect.js +55 -118
- package/dist/connectFlow.js +35 -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 +256 -445
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +150 -0
- package/dist/launcher.js +168 -0
- package/dist/limitEvent.js +44 -13
- package/dist/limitEventReporter.js +1 -1
- package/dist/managedPi.js +256 -0
- package/dist/mcp.js +5 -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 +205 -0
- package/dist/upgradeNudge.js +0 -30
- package/dist/utils.js +502 -828
- 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/cli.d.ts +0 -16
- package/dist/codexHookTrust.d.ts +0 -34
- package/dist/codie.d.ts +0 -2
- package/dist/codieLauncher.d.ts +0 -53
- 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/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/upgradeNudge.d.ts +0 -25
- package/dist/utils.d.ts +0 -342
- 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,16 +35,16 @@ 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"));
|
|
51
42
|
const path = __importStar(require("path"));
|
|
52
43
|
const utils_1 = require("./utils");
|
|
44
|
+
const cliSession_1 = require("./cliSession");
|
|
53
45
|
const shared_1 = require("./commands/shared");
|
|
54
46
|
const inboxFormat_1 = require("./inboxFormat");
|
|
55
47
|
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
48
|
const PKG_VERSION = (() => {
|
|
59
49
|
try {
|
|
60
50
|
const pkgPath = path.resolve(__dirname, "..", "package.json");
|
|
@@ -64,10 +54,6 @@ const PKG_VERSION = (() => {
|
|
|
64
54
|
return "unknown";
|
|
65
55
|
}
|
|
66
56
|
})();
|
|
67
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
68
|
-
// Tool definitions — descriptions tuned so Claude/Codex resolve natural-language
|
|
69
|
-
// requests into the right tool without manual steering.
|
|
70
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
71
57
|
const TOOLS = [
|
|
72
58
|
{
|
|
73
59
|
name: "codiedev_push",
|
|
@@ -237,29 +223,6 @@ const TOOLS = [
|
|
|
237
223
|
required: ["body"],
|
|
238
224
|
},
|
|
239
225
|
},
|
|
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
226
|
{
|
|
264
227
|
name: "codiedev_share_with",
|
|
265
228
|
description: "Grant a teammate persistent read (or edit) access to an artifact " +
|
|
@@ -306,27 +269,6 @@ const TOOLS = [
|
|
|
306
269
|
required: ["filename", "to"],
|
|
307
270
|
},
|
|
308
271
|
},
|
|
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
272
|
{
|
|
331
273
|
name: "codiedev_search",
|
|
332
274
|
description: "Search the team's artifact library by natural-language query. Use " +
|
|
@@ -413,53 +355,11 @@ const TOOLS = [
|
|
|
413
355
|
},
|
|
414
356
|
},
|
|
415
357
|
},
|
|
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
358
|
];
|
|
452
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
453
|
-
// Server
|
|
454
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
455
359
|
const server = new index_js_1.Server({ name: PKG_NAME, version: PKG_VERSION }, { capabilities: { tools: {} } });
|
|
456
360
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
457
361
|
tools: TOOLS,
|
|
458
362
|
}));
|
|
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
363
|
function emitTelemetry(config, event) {
|
|
464
364
|
if (!config)
|
|
465
365
|
return;
|
|
@@ -473,10 +373,10 @@ function emitTelemetry(config, event) {
|
|
|
473
373
|
mcpVersion: PKG_VERSION,
|
|
474
374
|
},
|
|
475
375
|
}).catch(() => {
|
|
476
|
-
// Swallow — telemetry should never affect the user's session.
|
|
477
376
|
});
|
|
478
377
|
}
|
|
479
378
|
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
379
|
+
await (0, cliSession_1.ensureFreshToken)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
|
|
480
380
|
const config = (0, utils_1.readConfig)();
|
|
481
381
|
if (!config) {
|
|
482
382
|
return {
|
|
@@ -538,22 +438,16 @@ async function dispatchTool(name, args, config) {
|
|
|
538
438
|
return await handleInbox(args, config);
|
|
539
439
|
case "codiedev_note":
|
|
540
440
|
return await handleNote(args, config);
|
|
541
|
-
case "codiedev_promote":
|
|
542
|
-
return await handlePromote(args, config);
|
|
543
441
|
case "codiedev_share_with":
|
|
544
442
|
return await handleShareWith(args, config);
|
|
545
443
|
case "codiedev_send_to":
|
|
546
444
|
return await handleSendTo(args, config);
|
|
547
|
-
case "codiedev_react":
|
|
548
|
-
return await handleReact(args, config);
|
|
549
445
|
case "codiedev_ask":
|
|
550
446
|
return await handleAsk(args, config);
|
|
551
447
|
case "codiedev_search":
|
|
552
448
|
return await handleSearch(args, config);
|
|
553
449
|
case "codiedev_get_library":
|
|
554
450
|
return await handleGetLibrary(args, config);
|
|
555
|
-
case "codiedev_reverse_ticket":
|
|
556
|
-
return await handleReverseTicket(args, config);
|
|
557
451
|
default:
|
|
558
452
|
return {
|
|
559
453
|
isError: true,
|
|
@@ -577,7 +471,7 @@ async function handlePush(args, config) {
|
|
|
577
471
|
}
|
|
578
472
|
const res = await (0, shared_1.apiRequest)("POST", "/api/cli/push", {
|
|
579
473
|
config,
|
|
580
|
-
body: { filename, markdown, type, kind, tags, force },
|
|
474
|
+
body: { filename, markdown: (0, skillMarker_1.stripSkillMarker)(markdown), type, kind, tags, force },
|
|
581
475
|
});
|
|
582
476
|
const tagSummary = res.tags && res.tags.length > 0 ? `, tags=[${res.tags.join(", ")}]` : "";
|
|
583
477
|
return {
|
|
@@ -598,10 +492,6 @@ async function handlePull(args, config) {
|
|
|
598
492
|
throw new Error("key required");
|
|
599
493
|
const res = await (0, shared_1.apiRequest)("GET", "/api/cli/pull", { config, query: { key, version } });
|
|
600
494
|
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
495
|
const kindLabel = a.kind ?? "doc";
|
|
606
496
|
const tagList = (a.tags ?? []).filter((t) => t).join(", ");
|
|
607
497
|
const tagSuffix = tagList ? ` · tags: ${tagList}` : "";
|
|
@@ -609,7 +499,7 @@ async function handlePull(args, config) {
|
|
|
609
499
|
`**${kindLabel}** · v${a.version ?? 1} · ${a.lifecycle ?? "draft"}${tagSuffix} · ` +
|
|
610
500
|
`updated ${(0, shared_1.timeAgo)(a.updatedAt ?? a.createdAt)}\n\n---\n\n`;
|
|
611
501
|
return {
|
|
612
|
-
content: [{ type: "text", text: header + a.markdown }],
|
|
502
|
+
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
503
|
};
|
|
614
504
|
}
|
|
615
505
|
async function handleDelete(args, config) {
|
|
@@ -685,9 +575,6 @@ async function handleInbox(args, config) {
|
|
|
685
575
|
config,
|
|
686
576
|
query: { unreadOnly: unreadOnly ? "1" : undefined, limit },
|
|
687
577
|
});
|
|
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
578
|
const text = (0, inboxFormat_1.formatInbox)({
|
|
692
579
|
pings: res.pings,
|
|
693
580
|
mentions: res.mentions,
|
|
@@ -705,21 +592,6 @@ async function handleNote(args, config) {
|
|
|
705
592
|
content: [{ type: "text", text: `✓ Noted (${res.key})` }],
|
|
706
593
|
};
|
|
707
594
|
}
|
|
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
595
|
async function handleShareWith(args, config) {
|
|
724
596
|
const filename = asString(args.filename);
|
|
725
597
|
const to = asString(args.to);
|
|
@@ -754,8 +626,6 @@ async function handleShareWith(args, config) {
|
|
|
754
626
|
],
|
|
755
627
|
};
|
|
756
628
|
}
|
|
757
|
-
// noop / duplicate path — surface where the existing grant came from so
|
|
758
|
-
// the user knows whether to expect it next time.
|
|
759
629
|
const e = res.existing;
|
|
760
630
|
let why = "";
|
|
761
631
|
if (e) {
|
|
@@ -810,26 +680,6 @@ async function handleSendTo(args, config) {
|
|
|
810
680
|
return formatAmbiguousRecipient(err, to);
|
|
811
681
|
}
|
|
812
682
|
}
|
|
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
683
|
async function handleSearch(args, config) {
|
|
834
684
|
const query = asString(args.query);
|
|
835
685
|
const limit = asIntOrUndefined(args.limit);
|
|
@@ -908,9 +758,6 @@ async function handleGetLibrary(args, config) {
|
|
|
908
758
|
const v = a.version ? ` v${a.version}` : "";
|
|
909
759
|
const life = a.lifecycle ? ` · ${a.lifecycle}` : "";
|
|
910
760
|
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
761
|
const k = a.kind ?? (a.type === "note" ? "doc" : "doc");
|
|
915
762
|
const tagList = (a.tags ?? []).length > 0 ? ` [${a.tags.join(", ")}]` : "";
|
|
916
763
|
lines.push(`[${k}]${tagList} ${loc}${a.key ?? a.title}${v}${life}${when}`);
|
|
@@ -937,226 +784,6 @@ function formatAmbiguousRecipient(err, to) {
|
|
|
937
784
|
}
|
|
938
785
|
throw err;
|
|
939
786
|
}
|
|
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
787
|
function asString(v) {
|
|
1161
788
|
return typeof v === "string" ? v : "";
|
|
1162
789
|
}
|
|
@@ -1174,20 +801,14 @@ function asStringArrayOrUndefined(v) {
|
|
|
1174
801
|
return undefined;
|
|
1175
802
|
return v.filter((x) => typeof x === "string");
|
|
1176
803
|
}
|
|
1177
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
1178
|
-
// Main
|
|
1179
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
1180
804
|
async function main() {
|
|
1181
805
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1182
806
|
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
807
|
process.stderr.write(`[codiedev-mcp] ready (v${PKG_VERSION}, config ${(0, utils_1.readConfig)() ? "present" : "missing"})\n`);
|
|
1186
808
|
}
|
|
1187
809
|
main().catch((err) => {
|
|
1188
810
|
process.stderr.write(`[codiedev-mcp] fatal: ${err.message}\n`);
|
|
1189
811
|
process.exit(1);
|
|
1190
812
|
});
|
|
1191
|
-
// Avoid "Cannot find name 'path', 'fs'" since we imported them but may not use.
|
|
1192
813
|
void path;
|
|
1193
814
|
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
|
+
}
|