codiedev 0.7.10 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +84 -7
- package/dist/commands/ask.js +12 -0
- package/dist/commands/createTicket.d.ts +27 -0
- package/dist/commands/createTicket.js +198 -0
- package/dist/commands/delete.js +12 -0
- package/dist/commands/doctor.js +6 -31
- package/dist/commands/inbox.js +30 -0
- package/dist/commands/library.d.ts +2 -0
- package/dist/commands/library.js +105 -0
- package/dist/commands/note.js +12 -0
- package/dist/commands/ping.js +12 -0
- package/dist/commands/post.d.ts +2 -0
- package/dist/commands/post.js +96 -0
- package/dist/commands/promote.js +12 -0
- package/dist/commands/pull.js +12 -0
- package/dist/commands/push.js +12 -0
- package/dist/commands/react.d.ts +2 -0
- package/dist/commands/react.js +40 -0
- package/dist/commands/reverseTicket.js +30 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +72 -0
- package/dist/commands/send.d.ts +2 -0
- package/dist/commands/send.js +67 -0
- package/dist/commands/share.d.ts +2 -0
- package/dist/commands/share.js +87 -0
- package/dist/commands/shared.d.ts +27 -1
- package/dist/commands/shared.js +63 -2
- package/dist/connect.js +49 -38
- package/dist/createTicketSkill.d.ts +12 -0
- package/dist/createTicketSkill.js +146 -0
- package/dist/detection.d.ts +18 -0
- package/dist/detection.js +28 -0
- package/dist/mcp.js +7 -7
- package/dist/utils.d.ts +22 -0
- package/dist/utils.js +128 -32
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,15 @@ const inbox_1 = require("./commands/inbox");
|
|
|
25
25
|
const note_1 = require("./commands/note");
|
|
26
26
|
const promote_1 = require("./commands/promote");
|
|
27
27
|
const reverseTicket_1 = require("./commands/reverseTicket");
|
|
28
|
+
const createTicket_1 = require("./commands/createTicket");
|
|
28
29
|
const doctor_1 = require("./commands/doctor");
|
|
30
|
+
const search_1 = require("./commands/search");
|
|
31
|
+
const library_1 = require("./commands/library");
|
|
32
|
+
const post_1 = require("./commands/post");
|
|
33
|
+
const share_1 = require("./commands/share");
|
|
34
|
+
const send_1 = require("./commands/send");
|
|
35
|
+
const react_1 = require("./commands/react");
|
|
36
|
+
const version_1 = require("./version");
|
|
29
37
|
const HELP = `
|
|
30
38
|
CodieDev CLI
|
|
31
39
|
|
|
@@ -56,13 +64,38 @@ Artifacts:
|
|
|
56
64
|
Draft lands in /portal/agentic-ticketing.
|
|
57
65
|
codiedev reverse-ticket --base <ref> Override the base ref in branch mode
|
|
58
66
|
(defaults to origin/main).
|
|
67
|
+
codiedev create-ticket [<prompt>] Forward-write a scoped ticket plan.
|
|
68
|
+
Claude investigates the codebase, asks
|
|
69
|
+
"single repo or multiple? where?", then
|
|
70
|
+
emits a plan with N+1 split. Lands in
|
|
71
|
+
/portal/research/<id>; push to Jira from there.
|
|
72
|
+
Beta — opt-in via betaCreateTicket.
|
|
73
|
+
codiedev create-ticket --submit <path|->
|
|
74
|
+
Internal: Claude calls this itself with
|
|
75
|
+
a plan JSON to submit. Use - for stdin.
|
|
59
76
|
|
|
60
77
|
Messaging:
|
|
61
78
|
codiedev ping <user> "<msg>" [--with <key>]
|
|
62
79
|
Send a message to a teammate
|
|
80
|
+
codiedev send <key> <user> ["<msg>"] Share an artifact + ping in one step
|
|
81
|
+
codiedev share <key> <user> [--role read|edit]
|
|
82
|
+
Silently grant access (no notification)
|
|
63
83
|
codiedev inbox [--unread] [--limit N] Show messages
|
|
64
84
|
codiedev read <ping-id> Mark read + show full message
|
|
65
85
|
|
|
86
|
+
Discovery:
|
|
87
|
+
codiedev search "<query>" Semantic search across the team's
|
|
88
|
+
captured sessions and artifacts
|
|
89
|
+
codiedev library [--scope mine|shared|all] [--kind doc|skill]
|
|
90
|
+
[--type T] [--tag X] [--limit N]
|
|
91
|
+
List artifacts in your workspace
|
|
92
|
+
|
|
93
|
+
Feed:
|
|
94
|
+
codiedev post --title "<t>" --body "<b>" [--intent share|request_review|
|
|
95
|
+
request_expertise|link_share|rfc] [--filename <key>]
|
|
96
|
+
[--mention <name>]... Publish to the team feed
|
|
97
|
+
codiedev react <postId> <emoji> Toggle a reaction on a feed post
|
|
98
|
+
|
|
66
99
|
Capture:
|
|
67
100
|
codiedev note "<text>" Capture a passing thought
|
|
68
101
|
|
|
@@ -90,7 +123,7 @@ Examples:
|
|
|
90
123
|
codiedev push spec-cart-clear.md # the typical case
|
|
91
124
|
codiedev push portal-design.md # with name:/description: → skill
|
|
92
125
|
codiedev pull spec-cart-clear.md
|
|
93
|
-
codiedev ping
|
|
126
|
+
codiedev ping <teammate> "thoughts?" --with spec-cart-clear.md
|
|
94
127
|
codiedev inbox --unread
|
|
95
128
|
codiedev note "idempotency key is worth a follow-up"
|
|
96
129
|
|
|
@@ -162,8 +195,8 @@ codiedev ping — send a teammate a message, optionally attached to an artifact
|
|
|
162
195
|
Teammates are notified by email and can reply from their own agent.
|
|
163
196
|
|
|
164
197
|
Examples:
|
|
165
|
-
codiedev ping
|
|
166
|
-
codiedev ping
|
|
198
|
+
codiedev ping <teammate> "thoughts on batch vs parallel?" --with spec-cart-clear.md
|
|
199
|
+
codiedev ping <teammate>@example.com "can you take this one?"
|
|
167
200
|
`.trim(),
|
|
168
201
|
inbox: `
|
|
169
202
|
codiedev inbox — show messages from teammates
|
|
@@ -218,6 +251,27 @@ codiedev promote — promote an auto-extracted artifact to authored
|
|
|
218
251
|
|
|
219
252
|
Find artifact-ids in the portal under Knowledge → Memory, or via
|
|
220
253
|
the portal search.
|
|
254
|
+
`.trim(),
|
|
255
|
+
"create-ticket": `
|
|
256
|
+
codiedev create-ticket — forward-write a scoped ticket plan
|
|
257
|
+
|
|
258
|
+
Default path:
|
|
259
|
+
codiedev create-ticket "I want to add SSO with Google"
|
|
260
|
+
|
|
261
|
+
Bare mode (no --submit) prints skill instructions for Claude to follow.
|
|
262
|
+
Claude asks where your repos live, investigates them locally, and emits a
|
|
263
|
+
plan as JSON. The CLI then re-invokes itself with --submit to upload it.
|
|
264
|
+
|
|
265
|
+
The plan lands at /portal/research/<id> as a ready-state research session.
|
|
266
|
+
Single ticket renders as one ticket; multi-ticket renders as a folder/group.
|
|
267
|
+
Push to Jira from the portal.
|
|
268
|
+
|
|
269
|
+
Beta. Opt-in by setting userProfiles.betaCreateTicket = true on your row.
|
|
270
|
+
|
|
271
|
+
Examples:
|
|
272
|
+
codiedev create-ticket
|
|
273
|
+
codiedev create-ticket "I want to add Google SSO"
|
|
274
|
+
codiedev create-ticket --submit /tmp/plan.json # internal, called by Claude
|
|
221
275
|
`.trim(),
|
|
222
276
|
};
|
|
223
277
|
const DOCS = `
|
|
@@ -242,7 +296,7 @@ specs, reviews, decisions, proposals, and captured thoughts — so:
|
|
|
242
296
|
|
|
243
297
|
2. Your teammate gets pinged (either directly by you, or because
|
|
244
298
|
they asked to be kept in the loop on that key):
|
|
245
|
-
codiedev ping
|
|
299
|
+
codiedev ping <teammate> "thoughts?" --with spec-cart-clear.md
|
|
246
300
|
|
|
247
301
|
3. They check their inbox:
|
|
248
302
|
codiedev inbox
|
|
@@ -305,9 +359,9 @@ If you use Claude Code or Codex, the agent already knows the commands —
|
|
|
305
359
|
'codiedev connect' installs instructions into your user-level config.
|
|
306
360
|
Just say things like:
|
|
307
361
|
|
|
308
|
-
"push this spec and ping
|
|
362
|
+
"push this spec and ping a teammate"
|
|
309
363
|
"any messages?"
|
|
310
|
-
"pull
|
|
364
|
+
"pull a teammate's latest spec"
|
|
311
365
|
|
|
312
366
|
The agent will run the right command via Bash.
|
|
313
367
|
|
|
@@ -357,7 +411,7 @@ async function main() {
|
|
|
357
411
|
}
|
|
358
412
|
}
|
|
359
413
|
if (command === "version" || command === "--version" || command === "-v") {
|
|
360
|
-
console.log(
|
|
414
|
+
console.log(`codiedev v${version_1.CLI_VERSION}`);
|
|
361
415
|
return;
|
|
362
416
|
}
|
|
363
417
|
try {
|
|
@@ -408,6 +462,29 @@ async function main() {
|
|
|
408
462
|
case "reverseTicket":
|
|
409
463
|
await (0, reverseTicket_1.runReverseTicket)(rest);
|
|
410
464
|
return;
|
|
465
|
+
case "create-ticket":
|
|
466
|
+
case "createTicket":
|
|
467
|
+
await (0, createTicket_1.runCreateTicket)(rest);
|
|
468
|
+
return;
|
|
469
|
+
case "search":
|
|
470
|
+
await (0, search_1.runSearch)(rest);
|
|
471
|
+
return;
|
|
472
|
+
case "library":
|
|
473
|
+
case "ls":
|
|
474
|
+
await (0, library_1.runLibrary)(rest);
|
|
475
|
+
return;
|
|
476
|
+
case "post":
|
|
477
|
+
await (0, post_1.runPost)(rest);
|
|
478
|
+
return;
|
|
479
|
+
case "share":
|
|
480
|
+
await (0, share_1.runShare)(rest);
|
|
481
|
+
return;
|
|
482
|
+
case "send":
|
|
483
|
+
await (0, send_1.runSend)(rest);
|
|
484
|
+
return;
|
|
485
|
+
case "react":
|
|
486
|
+
await (0, react_1.runReact)(rest);
|
|
487
|
+
return;
|
|
411
488
|
default:
|
|
412
489
|
console.error(`Unknown command: ${command}`);
|
|
413
490
|
console.error(HELP);
|
package/dist/commands/ask.js
CHANGED
|
@@ -20,11 +20,17 @@ function parseArgs(args) {
|
|
|
20
20
|
async function runAsk(args) {
|
|
21
21
|
const { question } = parseArgs(args);
|
|
22
22
|
const config = (0, shared_1.requireConfig)();
|
|
23
|
+
const start = Date.now();
|
|
23
24
|
try {
|
|
24
25
|
const res = await (0, shared_1.apiRequest)("POST", "/api/cli/ask", {
|
|
25
26
|
config,
|
|
26
27
|
body: { question },
|
|
27
28
|
});
|
|
29
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
30
|
+
tool: "codiedev_ask",
|
|
31
|
+
ok: true,
|
|
32
|
+
latencyMs: Date.now() - start,
|
|
33
|
+
});
|
|
28
34
|
console.log("");
|
|
29
35
|
console.log(res.answer);
|
|
30
36
|
if (res.citations.length > 0) {
|
|
@@ -40,6 +46,12 @@ async function runAsk(args) {
|
|
|
40
46
|
console.log("");
|
|
41
47
|
}
|
|
42
48
|
catch (err) {
|
|
49
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
50
|
+
tool: "codiedev_ask",
|
|
51
|
+
ok: false,
|
|
52
|
+
latencyMs: Date.now() - start,
|
|
53
|
+
error: err.message,
|
|
54
|
+
});
|
|
43
55
|
console.error(`Ask failed: ${err.message}`);
|
|
44
56
|
process.exit(1);
|
|
45
57
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CodiedevConfig } from "../utils";
|
|
2
|
+
export declare function substitutePrompt(protocol: string, prompt: string | undefined): string;
|
|
3
|
+
interface ConnectedRepo {
|
|
4
|
+
repoId: string;
|
|
5
|
+
fullName: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function validatePlanHasRepo(parsedPlan: any): string | null;
|
|
8
|
+
export declare function resolveRepoIds(fullNames: string[], repos: ConnectedRepo[]): string[];
|
|
9
|
+
export interface CreateTicketArgs {
|
|
10
|
+
mode: "bare" | "submit";
|
|
11
|
+
prompt?: string;
|
|
12
|
+
submitSource?: "stdin" | string;
|
|
13
|
+
}
|
|
14
|
+
export declare function parseCreateTicketArgs(args: string[]): CreateTicketArgs;
|
|
15
|
+
export declare function runCreateTicket(args: string[]): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Bare-mode entrypoint. Fetches the protocol body from the backend so we can
|
|
18
|
+
* iterate on it without shipping a new CLI, substitutes the user's prompt,
|
|
19
|
+
* and writes the result to stdout for the agent to follow. Hard-errors on
|
|
20
|
+
* fetch failure rather than falling back to a stale local copy — the whole
|
|
21
|
+
* point of moving the protocol server-side is that the freshest version is
|
|
22
|
+
* the only version.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runBare(config: CodiedevConfig, prompt: string | undefined): Promise<void>;
|
|
25
|
+
export declare function runSubmit(config: CodiedevConfig, rawJson: string): Promise<void>;
|
|
26
|
+
export declare function readSubmitInput(source: "stdin" | string): string;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.substitutePrompt = substitutePrompt;
|
|
37
|
+
exports.validatePlanHasRepo = validatePlanHasRepo;
|
|
38
|
+
exports.resolveRepoIds = resolveRepoIds;
|
|
39
|
+
exports.parseCreateTicketArgs = parseCreateTicketArgs;
|
|
40
|
+
exports.runCreateTicket = runCreateTicket;
|
|
41
|
+
exports.runBare = runBare;
|
|
42
|
+
exports.runSubmit = runSubmit;
|
|
43
|
+
exports.readSubmitInput = readSubmitInput;
|
|
44
|
+
const fs = __importStar(require("node:fs"));
|
|
45
|
+
const shared_1 = require("./shared");
|
|
46
|
+
const PROMPT_PLACEHOLDER = "{{USER_PROMPT}}";
|
|
47
|
+
const MISSING_PROMPT_FALLBACK = "(not yet provided — ask the user a single combined question that covers both the intent AND repo locations: \"What are you working on, and is this in a single repo or multiple? If multiple, give me the paths.\" Skip Step 1 since you've folded it into this question. Then proceed to Step 2.)";
|
|
48
|
+
function substitutePrompt(protocol, prompt) {
|
|
49
|
+
return protocol.replace(PROMPT_PLACEHOLDER, prompt && prompt.length > 0 ? prompt : MISSING_PROMPT_FALLBACK);
|
|
50
|
+
}
|
|
51
|
+
function validatePlanHasRepo(parsedPlan) {
|
|
52
|
+
const fullNames = Array.isArray(parsedPlan?.repoFullNames) ? parsedPlan.repoFullNames : [];
|
|
53
|
+
const explicitIds = Array.isArray(parsedPlan?.repoIds) ? parsedPlan.repoIds : [];
|
|
54
|
+
if (fullNames.length === 0 && explicitIds.length === 0) {
|
|
55
|
+
return "Plan must include at least one repo (repoFullNames: ['owner/name'] or repoIds: [...])";
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function resolveRepoIds(fullNames, repos) {
|
|
60
|
+
const lookup = new Map();
|
|
61
|
+
for (const r of repos) {
|
|
62
|
+
lookup.set(r.fullName.toLowerCase(), r.repoId);
|
|
63
|
+
}
|
|
64
|
+
const ids = [];
|
|
65
|
+
for (const fn of fullNames) {
|
|
66
|
+
const id = lookup.get(fn.toLowerCase());
|
|
67
|
+
if (!id) {
|
|
68
|
+
throw new Error(`Repo "${fn}" is not connected to your CodieDev account. Run \`codiedev connect\` to refresh, or push the missing repo through Settings.`);
|
|
69
|
+
}
|
|
70
|
+
ids.push(id);
|
|
71
|
+
}
|
|
72
|
+
return ids;
|
|
73
|
+
}
|
|
74
|
+
function parseCreateTicketArgs(args) {
|
|
75
|
+
let mode = "bare";
|
|
76
|
+
let prompt;
|
|
77
|
+
let submitSource;
|
|
78
|
+
for (let i = 0; i < args.length; i++) {
|
|
79
|
+
const a = args[i];
|
|
80
|
+
if (a === "--submit" && i + 1 < args.length) {
|
|
81
|
+
mode = "submit";
|
|
82
|
+
const next = args[++i];
|
|
83
|
+
submitSource = next === "-" ? "stdin" : next;
|
|
84
|
+
}
|
|
85
|
+
else if (a.startsWith("--submit=")) {
|
|
86
|
+
mode = "submit";
|
|
87
|
+
const v = a.slice("--submit=".length);
|
|
88
|
+
submitSource = v === "-" ? "stdin" : v;
|
|
89
|
+
}
|
|
90
|
+
else if (!a.startsWith("--") && !prompt && mode === "bare") {
|
|
91
|
+
prompt = a;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { mode, prompt, submitSource };
|
|
95
|
+
}
|
|
96
|
+
async function runCreateTicket(args) {
|
|
97
|
+
const parsed = parseCreateTicketArgs(args);
|
|
98
|
+
if (parsed.mode === "bare") {
|
|
99
|
+
const config = (0, shared_1.requireConfig)();
|
|
100
|
+
await runBare(config, parsed.prompt);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// submit mode
|
|
104
|
+
if (!parsed.submitSource) {
|
|
105
|
+
console.error("--submit requires a path or '-' for stdin");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
const config = (0, shared_1.requireConfig)();
|
|
109
|
+
let raw;
|
|
110
|
+
try {
|
|
111
|
+
raw = readSubmitInput(parsed.submitSource);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error(`Failed to read plan: ${err.message}`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
// Translate fullNames → IDs before submitting
|
|
118
|
+
let parsedPlan;
|
|
119
|
+
try {
|
|
120
|
+
parsedPlan = JSON.parse(raw);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
console.error(`Plan JSON did not parse: ${err.message}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
const validationError = validatePlanHasRepo(parsedPlan);
|
|
127
|
+
if (validationError) {
|
|
128
|
+
console.error(validationError);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
const fullNames = Array.isArray(parsedPlan.repoFullNames) ? parsedPlan.repoFullNames : [];
|
|
132
|
+
const explicitIds = Array.isArray(parsedPlan.repoIds) ? parsedPlan.repoIds : [];
|
|
133
|
+
if (fullNames.length > 0 && explicitIds.length === 0) {
|
|
134
|
+
parsedPlan.repoIds = resolveRepoIds(fullNames, config.repos);
|
|
135
|
+
}
|
|
136
|
+
for (const t of parsedPlan.plan?.tickets ?? []) {
|
|
137
|
+
if (t.targetRepoFullName && !t.targetRepoId) {
|
|
138
|
+
const ids = resolveRepoIds([t.targetRepoFullName], config.repos);
|
|
139
|
+
t.targetRepoId = ids[0];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
await runSubmit(config, JSON.stringify(parsedPlan));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Bare-mode entrypoint. Fetches the protocol body from the backend so we can
|
|
146
|
+
* iterate on it without shipping a new CLI, substitutes the user's prompt,
|
|
147
|
+
* and writes the result to stdout for the agent to follow. Hard-errors on
|
|
148
|
+
* fetch failure rather than falling back to a stale local copy — the whole
|
|
149
|
+
* point of moving the protocol server-side is that the freshest version is
|
|
150
|
+
* the only version.
|
|
151
|
+
*/
|
|
152
|
+
async function runBare(config, prompt) {
|
|
153
|
+
let res;
|
|
154
|
+
try {
|
|
155
|
+
res = await (0, shared_1.apiRequest)("GET", "/api/cli/createTicketProtocol", { config });
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
const status = err.status;
|
|
159
|
+
if (status === 403) {
|
|
160
|
+
console.error("create-ticket is in beta and not enabled for your account. Ask your CodieDev admin to flip betaCreateTicket on your profile.");
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.error(`Failed to fetch create-ticket protocol: ${err.message}. Check your network connection and re-run.`);
|
|
164
|
+
}
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
process.stdout.write(substitutePrompt(res.protocol, prompt));
|
|
168
|
+
}
|
|
169
|
+
async function runSubmit(config, rawJson) {
|
|
170
|
+
let payload;
|
|
171
|
+
try {
|
|
172
|
+
payload = JSON.parse(rawJson);
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
throw new Error(`Plan JSON did not parse — emit valid JSON matching the schema printed by \`codiedev create-ticket\`. Original error: ${err.message}`);
|
|
176
|
+
}
|
|
177
|
+
if (!payload.plan || !payload.prompt || !payload.repoIds) {
|
|
178
|
+
throw new Error("Plan JSON missing one of: plan, prompt, repoIds");
|
|
179
|
+
}
|
|
180
|
+
const res = await (0, shared_1.withTelemetry)(config, "codiedev_create_ticket", () => (0, shared_1.apiRequest)("POST", "/api/cli/createPlan", {
|
|
181
|
+
config,
|
|
182
|
+
body: payload,
|
|
183
|
+
}));
|
|
184
|
+
const portalHost = (process.env.CODIEDEV_PORTAL_URL || "https://codiedev.com").replace(/\/$/, "");
|
|
185
|
+
const portalLink = res.portalUrl.startsWith("http")
|
|
186
|
+
? res.portalUrl
|
|
187
|
+
: `${portalHost}${res.portalUrl}`;
|
|
188
|
+
console.log(`✓ Created ${res.ticketCount} ticket(s).`);
|
|
189
|
+
console.log(` portal: ${portalLink}`);
|
|
190
|
+
console.log("");
|
|
191
|
+
console.log("Open in your portal to review and push to Jira.");
|
|
192
|
+
}
|
|
193
|
+
function readSubmitInput(source) {
|
|
194
|
+
if (source === "stdin") {
|
|
195
|
+
return fs.readFileSync(0, "utf8");
|
|
196
|
+
}
|
|
197
|
+
return fs.readFileSync(source, "utf8");
|
|
198
|
+
}
|
package/dist/commands/delete.js
CHANGED
|
@@ -75,11 +75,17 @@ async function runDelete(args) {
|
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
const start = Date.now();
|
|
78
79
|
try {
|
|
79
80
|
const res = await (0, shared_1.apiRequest)("POST", "/api/cli/delete", {
|
|
80
81
|
config,
|
|
81
82
|
body: { key },
|
|
82
83
|
});
|
|
84
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
85
|
+
tool: "codiedev_delete",
|
|
86
|
+
ok: true,
|
|
87
|
+
latencyMs: Date.now() - start,
|
|
88
|
+
});
|
|
83
89
|
if (res.deleted === 0) {
|
|
84
90
|
console.log(`No artifact found with key '${key}'. Nothing to delete.`);
|
|
85
91
|
return;
|
|
@@ -90,6 +96,12 @@ async function runDelete(args) {
|
|
|
90
96
|
console.log(`✓ Deleted ${res.deleted} version${res.deleted === 1 ? "" : "s"}${cascaded} of '${res.key}'.`);
|
|
91
97
|
}
|
|
92
98
|
catch (err) {
|
|
99
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
100
|
+
tool: "codiedev_delete",
|
|
101
|
+
ok: false,
|
|
102
|
+
latencyMs: Date.now() - start,
|
|
103
|
+
error: err.message,
|
|
104
|
+
});
|
|
93
105
|
console.error(`Delete failed: ${err.message}`);
|
|
94
106
|
process.exit(1);
|
|
95
107
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -40,6 +40,7 @@ const os = __importStar(require("os"));
|
|
|
40
40
|
const child_process_1 = require("child_process");
|
|
41
41
|
const shared_1 = require("./shared");
|
|
42
42
|
const utils_1 = require("../utils");
|
|
43
|
+
const detection_1 = require("../detection");
|
|
43
44
|
const version_1 = require("../version");
|
|
44
45
|
const upgradeNudge_1 = require("../upgradeNudge");
|
|
45
46
|
const CLAUDE_SETTINGS_PATH = path.join(os.homedir(), ".claude", "settings.json");
|
|
@@ -48,7 +49,6 @@ const CODEX_HOOKS_PATH = path.join(os.homedir(), ".codex", "hooks.json");
|
|
|
48
49
|
const CODEX_INSTRUCTIONS_PATH = path.join(os.homedir(), ".codex", "AGENTS.md");
|
|
49
50
|
const CURSOR_HOOKS_PATH = path.join(os.homedir(), ".cursor", "hooks.json");
|
|
50
51
|
const CURSOR_INSTRUCTIONS_PATH = path.join(os.homedir(), ".cursor", "rules", "codiedev.mdc");
|
|
51
|
-
const CURSOR_MCP_PATH = path.join(os.homedir(), ".cursor", "mcp.json");
|
|
52
52
|
function symbol(status) {
|
|
53
53
|
if (status === "pass")
|
|
54
54
|
return "✓";
|
|
@@ -62,27 +62,9 @@ function codexInstalled() {
|
|
|
62
62
|
function cursorInstalled() {
|
|
63
63
|
return fs.existsSync(path.join(os.homedir(), ".cursor"));
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return false;
|
|
69
|
-
const raw = fs.readFileSync(CURSOR_MCP_PATH, "utf8");
|
|
70
|
-
const parsed = JSON.parse(raw);
|
|
71
|
-
const servers = parsed.mcpServers;
|
|
72
|
-
return !!servers && "codiedev" in servers;
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// Match both legacy `npx codiedev-hook ...` and absolute-path forms
|
|
79
|
-
// `<node> <.../codiedev/dist/hook.js> ...` — installer switched to absolute
|
|
80
|
-
// paths in 0.6.1 to work in GUI-launched contexts where shell PATH is missing.
|
|
81
|
-
function isCodiedevHookCommand(cmd) {
|
|
82
|
-
if (!cmd)
|
|
83
|
-
return false;
|
|
84
|
-
return cmd.includes("codiedev-hook") || /codiedev[\\/]dist[\\/]hook/.test(cmd);
|
|
85
|
-
}
|
|
65
|
+
// `isCodiedevHookCommand` lives in ../detection alongside detectClaudeCode
|
|
66
|
+
// so utils.ts and doctor.ts share one definition (they used to drift —
|
|
67
|
+
// each had its own copy).
|
|
86
68
|
// Cursor's hooks.json schema is { hooks: { sessionEnd: [{ command, ... }] } }
|
|
87
69
|
// — flat array of objects with `command`, not the Claude/Codex nested
|
|
88
70
|
// `{ hooks: [{ command }] }` wrapper.
|
|
@@ -95,7 +77,7 @@ function hasCursorHook() {
|
|
|
95
77
|
const arr = parsed.hooks?.sessionEnd;
|
|
96
78
|
if (!Array.isArray(arr))
|
|
97
79
|
return false;
|
|
98
|
-
return arr.some((h) => isCodiedevHookCommand(h.command));
|
|
80
|
+
return arr.some((h) => (0, detection_1.isCodiedevHookCommand)(h.command));
|
|
99
81
|
}
|
|
100
82
|
catch {
|
|
101
83
|
return false;
|
|
@@ -114,7 +96,7 @@ function hasCodiedevHook(settingsPath, hookKey) {
|
|
|
114
96
|
const inner = h.hooks;
|
|
115
97
|
if (!Array.isArray(inner))
|
|
116
98
|
return false;
|
|
117
|
-
return inner.some((x) => isCodiedevHookCommand(x.command));
|
|
99
|
+
return inner.some((x) => (0, detection_1.isCodiedevHookCommand)(x.command));
|
|
118
100
|
});
|
|
119
101
|
}
|
|
120
102
|
catch {
|
|
@@ -307,13 +289,6 @@ async function runDoctor(_args) {
|
|
|
307
289
|
? "~/.cursor/rules/codiedev.mdc"
|
|
308
290
|
: "missing — re-run `codiedev connect`",
|
|
309
291
|
});
|
|
310
|
-
checks.push({
|
|
311
|
-
name: "Cursor MCP server",
|
|
312
|
-
status: hasCursorMcpEntry() ? "pass" : "fail",
|
|
313
|
-
detail: hasCursorMcpEntry()
|
|
314
|
-
? "~/.cursor/mcp.json"
|
|
315
|
-
: "missing — re-run `codiedev connect`",
|
|
316
|
-
});
|
|
317
292
|
}
|
|
318
293
|
else {
|
|
319
294
|
checks.push({
|
package/dist/commands/inbox.js
CHANGED
|
@@ -26,6 +26,7 @@ function parseInboxArgs(args) {
|
|
|
26
26
|
async function runInbox(args) {
|
|
27
27
|
const { unreadOnly, limit } = parseInboxArgs(args);
|
|
28
28
|
const config = (0, shared_1.requireConfig)();
|
|
29
|
+
const start = Date.now();
|
|
29
30
|
try {
|
|
30
31
|
const res = await (0, shared_1.apiRequest)("GET", "/api/cli/inbox", {
|
|
31
32
|
config,
|
|
@@ -34,6 +35,11 @@ async function runInbox(args) {
|
|
|
34
35
|
limit,
|
|
35
36
|
},
|
|
36
37
|
});
|
|
38
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
39
|
+
tool: "codiedev_inbox",
|
|
40
|
+
ok: true,
|
|
41
|
+
latencyMs: Date.now() - start,
|
|
42
|
+
});
|
|
37
43
|
const pings = res.pings;
|
|
38
44
|
const unreadCount = pings.filter((p) => !p.readAt).length;
|
|
39
45
|
if (pings.length === 0) {
|
|
@@ -56,6 +62,12 @@ async function runInbox(args) {
|
|
|
56
62
|
console.log(`Mark read: codiedev read <ping-id>`);
|
|
57
63
|
}
|
|
58
64
|
catch (err) {
|
|
65
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
66
|
+
tool: "codiedev_inbox",
|
|
67
|
+
ok: false,
|
|
68
|
+
latencyMs: Date.now() - start,
|
|
69
|
+
error: err.message,
|
|
70
|
+
});
|
|
59
71
|
console.error(`Inbox failed: ${err.message}`);
|
|
60
72
|
process.exit(1);
|
|
61
73
|
}
|
|
@@ -67,6 +79,7 @@ async function runRead(args) {
|
|
|
67
79
|
process.exit(1);
|
|
68
80
|
}
|
|
69
81
|
const config = (0, shared_1.requireConfig)();
|
|
82
|
+
const start = Date.now();
|
|
70
83
|
try {
|
|
71
84
|
// First, fetch inbox so we can show the full body (markRead endpoint
|
|
72
85
|
// doesn't return content).
|
|
@@ -76,6 +89,12 @@ async function runRead(args) {
|
|
|
76
89
|
});
|
|
77
90
|
const ping = listRes.pings.find((p) => p.pingId === pingId);
|
|
78
91
|
if (!ping) {
|
|
92
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
93
|
+
tool: "codiedev_read",
|
|
94
|
+
ok: false,
|
|
95
|
+
latencyMs: Date.now() - start,
|
|
96
|
+
error: "ping not found",
|
|
97
|
+
});
|
|
79
98
|
console.error(`Ping not found: ${pingId}`);
|
|
80
99
|
process.exit(1);
|
|
81
100
|
}
|
|
@@ -83,6 +102,11 @@ async function runRead(args) {
|
|
|
83
102
|
config,
|
|
84
103
|
body: { pingId },
|
|
85
104
|
});
|
|
105
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
106
|
+
tool: "codiedev_read",
|
|
107
|
+
ok: true,
|
|
108
|
+
latencyMs: Date.now() - start,
|
|
109
|
+
});
|
|
86
110
|
const from = ping.from?.name ?? "unknown";
|
|
87
111
|
const when = (0, shared_1.timeAgo)(ping.createdAt);
|
|
88
112
|
const where = ping.subjectKey ? ` · on ${ping.subjectKey}` : "";
|
|
@@ -100,6 +124,12 @@ async function runRead(args) {
|
|
|
100
124
|
}
|
|
101
125
|
}
|
|
102
126
|
catch (err) {
|
|
127
|
+
(0, shared_1.recordAgentEvent)(config, {
|
|
128
|
+
tool: "codiedev_read",
|
|
129
|
+
ok: false,
|
|
130
|
+
latencyMs: Date.now() - start,
|
|
131
|
+
error: err.message,
|
|
132
|
+
});
|
|
103
133
|
console.error(`Read failed: ${err.message}`);
|
|
104
134
|
process.exit(1);
|
|
105
135
|
}
|