codiedev 0.7.9 → 0.7.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.
@@ -0,0 +1,2 @@
1
+ import type { CodiedevConfig } from "../utils";
2
+ export declare function runReact(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ // `codiedev react <postId> <emoji>` — toggle a reaction on a feed post.
3
+ // Calling twice with the same emoji removes it.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.runReact = runReact;
6
+ const shared_1 = require("./shared");
7
+ async function runReact(args, configOverride) {
8
+ const positionals = args.filter((a) => !a.startsWith("--"));
9
+ const [postId, emoji] = positionals;
10
+ if (!postId || !emoji) {
11
+ console.error("Usage: codiedev react <postId> <emoji>");
12
+ process.exit(1);
13
+ }
14
+ const config = configOverride ?? (0, shared_1.requireConfig)();
15
+ const start = Date.now();
16
+ try {
17
+ const res = await (0, shared_1.apiRequest)("POST", "/api/cli/react", {
18
+ config,
19
+ body: { postId, emoji },
20
+ });
21
+ (0, shared_1.recordAgentEvent)(config, {
22
+ tool: "codiedev_react",
23
+ ok: true,
24
+ latencyMs: Date.now() - start,
25
+ });
26
+ console.log(res.action === "removed"
27
+ ? `Removed ${res.emoji ?? emoji} from post ${postId}.`
28
+ : `Reacted to post ${postId} with ${res.emoji ?? emoji}.`);
29
+ }
30
+ catch (err) {
31
+ (0, shared_1.recordAgentEvent)(config, {
32
+ tool: "codiedev_react",
33
+ ok: false,
34
+ latencyMs: Date.now() - start,
35
+ error: err.message,
36
+ });
37
+ console.error(`React failed: ${err.message}`);
38
+ process.exit(1);
39
+ }
40
+ }
@@ -183,6 +183,7 @@ async function runReverseTicket(args) {
183
183
  console.log("");
184
184
  console.log("Generating ticket…");
185
185
  console.log("");
186
+ const start = Date.now();
186
187
  try {
187
188
  const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reverseTicket", {
188
189
  config,
@@ -191,6 +192,11 @@ async function runReverseTicket(args) {
191
192
  forcedArtifactKey: forcedKey,
192
193
  },
193
194
  });
195
+ (0, shared_1.recordAgentEvent)(config, {
196
+ tool: "codiedev_reverse_ticket",
197
+ ok: true,
198
+ latencyMs: Date.now() - start,
199
+ });
194
200
  if (res.match) {
195
201
  console.log(`✓ Matched artifact: ${res.match.key} (score=${res.match.score.toFixed(2)})`);
196
202
  console.log(` signals · body=${res.match.signals.bodyMention} · files=${res.match.signals.fileOverlap.toFixed(2)} · transcript=${res.match.signals.transcriptEdit}`);
@@ -212,6 +218,12 @@ async function runReverseTicket(args) {
212
218
  console.log(res.ticket);
213
219
  }
214
220
  catch (err) {
221
+ (0, shared_1.recordAgentEvent)(config, {
222
+ tool: "codiedev_reverse_ticket",
223
+ ok: false,
224
+ latencyMs: Date.now() - start,
225
+ error: err.message,
226
+ });
215
227
  console.error(`Reverse-ticket failed: ${err.message}`);
216
228
  process.exit(1);
217
229
  }
@@ -367,6 +379,7 @@ async function runBranchMode(opts) {
367
379
  console.log("Generating ticket draft…");
368
380
  console.log("");
369
381
  const config = (0, shared_1.requireConfig)();
382
+ const start = Date.now();
370
383
  try {
371
384
  const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reverseTicketFromBranch", {
372
385
  config,
@@ -387,9 +400,20 @@ async function runBranchMode(opts) {
387
400
  },
388
401
  });
389
402
  if (!res.ok || !res.artifactId) {
403
+ (0, shared_1.recordAgentEvent)(config, {
404
+ tool: "codiedev_reverse_ticket",
405
+ ok: false,
406
+ latencyMs: Date.now() - start,
407
+ error: "no result",
408
+ });
390
409
  console.error("Reverse-ticket generation returned no result. The writer may have skipped due to missing context.");
391
410
  process.exit(1);
392
411
  }
412
+ (0, shared_1.recordAgentEvent)(config, {
413
+ tool: "codiedev_reverse_ticket",
414
+ ok: true,
415
+ latencyMs: Date.now() - start,
416
+ });
393
417
  const portalHost = (process.env.CODIEDEV_PORTAL_URL || "https://codiedev.com").replace(/\/$/, "");
394
418
  const portalLink = res.portalUrl.startsWith("http")
395
419
  ? res.portalUrl
@@ -403,6 +427,12 @@ async function runBranchMode(opts) {
403
427
  console.log("Each call creates a fresh draft — clean up duplicates from the portal if needed.");
404
428
  }
405
429
  catch (err) {
430
+ (0, shared_1.recordAgentEvent)(config, {
431
+ tool: "codiedev_reverse_ticket",
432
+ ok: false,
433
+ latencyMs: Date.now() - start,
434
+ error: err.message,
435
+ });
406
436
  console.error(`Reverse-ticket failed: ${err.message}`);
407
437
  process.exit(1);
408
438
  }
@@ -0,0 +1,2 @@
1
+ import type { CodiedevConfig } from "../utils";
2
+ export declare function runSearch(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // `codiedev search "<query>"` — semantic + keyword search across the org's
3
+ // captured sessions, artifacts, and skills. Hits are filtered by companyId
4
+ // server-side, so a single search surfaces results from every teammate's
5
+ // prior sessions in the same workspace.
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runSearch = runSearch;
8
+ const shared_1 = require("./shared");
9
+ function parseArgs(args) {
10
+ let query;
11
+ let limit;
12
+ for (let i = 0; i < args.length; i++) {
13
+ const a = args[i];
14
+ if (a === "--limit" && i + 1 < args.length) {
15
+ const n = Number(args[++i]);
16
+ if (Number.isInteger(n) && n > 0)
17
+ limit = n;
18
+ }
19
+ else if (a.startsWith("--limit=")) {
20
+ const n = Number(a.slice("--limit=".length));
21
+ if (Number.isInteger(n) && n > 0)
22
+ limit = n;
23
+ }
24
+ else if (!a.startsWith("--") && query === undefined) {
25
+ query = a;
26
+ }
27
+ }
28
+ if (!query || !query.trim()) {
29
+ console.error('Usage: codiedev search "<query>" [--limit N]');
30
+ process.exit(1);
31
+ }
32
+ return { query: query.trim(), limit };
33
+ }
34
+ async function runSearch(args, configOverride) {
35
+ const { query, limit } = parseArgs(args);
36
+ const config = configOverride ?? (0, shared_1.requireConfig)();
37
+ const start = Date.now();
38
+ try {
39
+ const res = await (0, shared_1.apiRequest)("GET", "/api/cli/search", {
40
+ config,
41
+ query: { q: query, limit },
42
+ });
43
+ (0, shared_1.recordAgentEvent)(config, {
44
+ tool: "codiedev_search",
45
+ ok: true,
46
+ latencyMs: Date.now() - start,
47
+ });
48
+ if (!res.hits || res.hits.length === 0) {
49
+ console.log(`No matches for "${query}".`);
50
+ return;
51
+ }
52
+ console.log(`Found ${res.hits.length} match${res.hits.length === 1 ? "" : "es"} for "${query}":\n`);
53
+ for (const h of res.hits) {
54
+ const keyOrId = h.key ?? h._id;
55
+ console.log(` ${h.title} (${h.type}, score ${h.score.toFixed(2)})`);
56
+ console.log(` ${keyOrId}`);
57
+ if (h.snippet)
58
+ console.log(` ${h.snippet.slice(0, 240)}`);
59
+ console.log();
60
+ }
61
+ }
62
+ catch (err) {
63
+ (0, shared_1.recordAgentEvent)(config, {
64
+ tool: "codiedev_search",
65
+ ok: false,
66
+ latencyMs: Date.now() - start,
67
+ error: err.message,
68
+ });
69
+ console.error(`Search failed: ${err.message}`);
70
+ process.exit(1);
71
+ }
72
+ }
@@ -0,0 +1,2 @@
1
+ import type { CodiedevConfig } from "../utils";
2
+ export declare function runSend(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ // `codiedev send <filename> <recipient> [message]` — share an artifact AND
3
+ // send a short message that lands in the teammate's inbox. The active-
4
+ // handoff version of `codiedev share`. Use this when the user is actively
5
+ // looping someone in.
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runSend = runSend;
8
+ const shared_1 = require("./shared");
9
+ function parseArgs(args) {
10
+ const positionals = args.filter((a) => !a.startsWith("--"));
11
+ const [filename, to, ...rest] = positionals;
12
+ if (!filename || !to) {
13
+ console.error('Usage: codiedev send <filename> <recipient> ["<message>"]');
14
+ process.exit(1);
15
+ }
16
+ // Recombine remaining tokens — supports both quoted and unquoted messages.
17
+ const message = rest.length > 0 ? (0, shared_1.stripQuotes)(rest.join(" ")) : undefined;
18
+ return { filename, to, message };
19
+ }
20
+ async function runSend(args, configOverride) {
21
+ const parsed = parseArgs(args);
22
+ const config = configOverride ?? (0, shared_1.requireConfig)();
23
+ const start = Date.now();
24
+ try {
25
+ const body = {
26
+ filename: parsed.filename,
27
+ to: parsed.to,
28
+ };
29
+ if (parsed.message)
30
+ body.message = parsed.message;
31
+ const res = await (0, shared_1.apiRequest)("POST", "/api/cli/send-to", {
32
+ config,
33
+ body,
34
+ });
35
+ (0, shared_1.recordAgentEvent)(config, {
36
+ tool: "codiedev_send_to",
37
+ ok: true,
38
+ latencyMs: Date.now() - start,
39
+ });
40
+ const who = res.recipient ? `${res.recipient.name} (${res.recipient.email})` : parsed.to;
41
+ if (parsed.message) {
42
+ console.log(`Sent ${parsed.filename} to ${who}.`);
43
+ }
44
+ else {
45
+ console.log(`Shared ${parsed.filename} with ${who} (no message).`);
46
+ }
47
+ }
48
+ catch (err) {
49
+ (0, shared_1.recordAgentEvent)(config, {
50
+ tool: "codiedev_send_to",
51
+ ok: false,
52
+ latencyMs: Date.now() - start,
53
+ error: err.message,
54
+ });
55
+ const body = err.body;
56
+ if (body && Array.isArray(body.candidates) && body.candidates.length > 0) {
57
+ console.error(`Recipient "${parsed.to}" is ambiguous. Candidates:`);
58
+ for (const c of body.candidates) {
59
+ console.error(` - ${c.name} (${c.email})`);
60
+ }
61
+ }
62
+ else {
63
+ console.error(`Send failed: ${err.message}`);
64
+ }
65
+ process.exit(1);
66
+ }
67
+ }
@@ -0,0 +1,2 @@
1
+ import type { CodiedevConfig } from "../utils";
2
+ export declare function runShare(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ // `codiedev share <filename> <recipient> [--role read|edit]` — silently
3
+ // grant a teammate access to an artifact (no notification). Use
4
+ // `codiedev send` instead when the user wants to actively loop someone in.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runShare = runShare;
7
+ const shared_1 = require("./shared");
8
+ const VALID_ROLES = new Set(["read", "edit"]);
9
+ function parseArgs(args) {
10
+ let filename;
11
+ let to;
12
+ let role;
13
+ for (let i = 0; i < args.length; i++) {
14
+ const a = args[i];
15
+ if (a === "--role" && i + 1 < args.length) {
16
+ role = args[++i];
17
+ }
18
+ else if (a.startsWith("--role=")) {
19
+ role = a.slice("--role=".length);
20
+ }
21
+ else if (!a.startsWith("--")) {
22
+ if (filename === undefined)
23
+ filename = a;
24
+ else if (to === undefined)
25
+ to = a;
26
+ }
27
+ }
28
+ if (!filename || !to) {
29
+ console.error("Usage: codiedev share <filename> <recipient> [--role read|edit]");
30
+ process.exit(1);
31
+ }
32
+ if (role && !VALID_ROLES.has(role)) {
33
+ console.error(`Invalid --role. Valid: ${[...VALID_ROLES].join(", ")}`);
34
+ process.exit(1);
35
+ }
36
+ return { filename, to, role: (role ?? "read") };
37
+ }
38
+ async function runShare(args, configOverride) {
39
+ const parsed = parseArgs(args);
40
+ const config = configOverride ?? (0, shared_1.requireConfig)();
41
+ const start = Date.now();
42
+ try {
43
+ const res = await (0, shared_1.apiRequest)("POST", "/api/cli/share-with", {
44
+ config,
45
+ body: {
46
+ filename: parsed.filename,
47
+ to: parsed.to,
48
+ role: parsed.role,
49
+ },
50
+ });
51
+ (0, shared_1.recordAgentEvent)(config, {
52
+ tool: "codiedev_share_with",
53
+ ok: true,
54
+ latencyMs: Date.now() - start,
55
+ });
56
+ const who = res.recipient ? `${res.recipient.name} (${res.recipient.email})` : parsed.to;
57
+ if (res.noop) {
58
+ console.log(`Already shared with ${who}.`);
59
+ }
60
+ else if (res.updated) {
61
+ console.log(`Updated access for ${who} to ${parsed.role}.`);
62
+ }
63
+ else {
64
+ console.log(`Shared ${parsed.filename} with ${who} (${parsed.role}).`);
65
+ }
66
+ }
67
+ catch (err) {
68
+ (0, shared_1.recordAgentEvent)(config, {
69
+ tool: "codiedev_share_with",
70
+ ok: false,
71
+ latencyMs: Date.now() - start,
72
+ error: err.message,
73
+ });
74
+ // Ambiguous recipients return 409 with candidates in the body.
75
+ const body = err.body;
76
+ if (body && Array.isArray(body.candidates) && body.candidates.length > 0) {
77
+ console.error(`Recipient "${parsed.to}" is ambiguous. Candidates:`);
78
+ for (const c of body.candidates) {
79
+ console.error(` - ${c.name} (${c.email})`);
80
+ }
81
+ }
82
+ else {
83
+ console.error(`Share failed: ${err.message}`);
84
+ }
85
+ process.exit(1);
86
+ }
87
+ }
@@ -13,12 +13,30 @@ export declare function apiRequest<T = unknown>(method: "GET" | "POST", path: st
13
13
  body?: Record<string, unknown>;
14
14
  query?: Record<string, string | number | undefined>;
15
15
  }): Promise<T>;
16
+ /**
17
+ * Fire-and-forget per-invocation telemetry from CLI subcommands. Mirrors
18
+ * the MCP server's emitTelemetry but stamps `source: "cli"` so adoption
19
+ * dashboards can distinguish between the two surfaces. Never blocks the
20
+ * user's command, never throws — telemetry must not change behavior.
21
+ */
22
+ export declare function recordAgentEvent(config: CodiedevConfig, event: {
23
+ tool: string;
24
+ ok: boolean;
25
+ latencyMs: number;
26
+ error?: string;
27
+ }): void;
28
+ /**
29
+ * Wraps a CLI subcommand body so success and failure both record telemetry
30
+ * and the original error propagates after the event is queued. Use this in
31
+ * each `runXxx` command instead of inline timing + try/catch boilerplate.
32
+ */
33
+ export declare function withTelemetry<T>(config: CodiedevConfig, tool: string, fn: () => Promise<T>): Promise<T>;
16
34
  /**
17
35
  * Relative-time formatter for inbox / listing output.
18
36
  */
19
37
  export declare function timeAgo(ts: number): string;
20
38
  /**
21
39
  * Strip surrounding quotes from a CLI argument if the user wrapped it.
22
- * `codiedev ping maya "hey"` on some shells passes the quotes through.
40
+ * `codiedev ping <name> "hey"` on some shells passes the quotes through.
23
41
  */
24
42
  export declare function stripQuotes(s: string): string;
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.requireConfig = requireConfig;
37
37
  exports.apiRequest = apiRequest;
38
+ exports.recordAgentEvent = recordAgentEvent;
39
+ exports.withTelemetry = withTelemetry;
38
40
  exports.timeAgo = timeAgo;
39
41
  exports.stripQuotes = stripQuotes;
40
42
  const https = __importStar(require("https"));
@@ -116,6 +118,49 @@ function apiRequest(method, path, options) {
116
118
  req.end();
117
119
  });
118
120
  }
121
+ /**
122
+ * Fire-and-forget per-invocation telemetry from CLI subcommands. Mirrors
123
+ * the MCP server's emitTelemetry but stamps `source: "cli"` so adoption
124
+ * dashboards can distinguish between the two surfaces. Never blocks the
125
+ * user's command, never throws — telemetry must not change behavior.
126
+ */
127
+ function recordAgentEvent(config, event) {
128
+ apiRequest("POST", "/api/telemetry/mcp-event", {
129
+ config,
130
+ body: {
131
+ tool: event.tool,
132
+ ok: event.ok,
133
+ latencyMs: event.latencyMs,
134
+ error: event.error,
135
+ mcpVersion: version_1.CLI_VERSION,
136
+ source: "cli",
137
+ },
138
+ }).catch(() => {
139
+ // Swallow — telemetry must never affect user-facing flow.
140
+ });
141
+ }
142
+ /**
143
+ * Wraps a CLI subcommand body so success and failure both record telemetry
144
+ * and the original error propagates after the event is queued. Use this in
145
+ * each `runXxx` command instead of inline timing + try/catch boilerplate.
146
+ */
147
+ async function withTelemetry(config, tool, fn) {
148
+ const start = Date.now();
149
+ try {
150
+ const result = await fn();
151
+ recordAgentEvent(config, { tool, ok: true, latencyMs: Date.now() - start });
152
+ return result;
153
+ }
154
+ catch (err) {
155
+ recordAgentEvent(config, {
156
+ tool,
157
+ ok: false,
158
+ latencyMs: Date.now() - start,
159
+ error: err.message?.slice(0, 240),
160
+ });
161
+ throw err;
162
+ }
163
+ }
119
164
  /**
120
165
  * Relative-time formatter for inbox / listing output.
121
166
  */
@@ -134,7 +179,7 @@ function timeAgo(ts) {
134
179
  }
135
180
  /**
136
181
  * Strip surrounding quotes from a CLI argument if the user wrapped it.
137
- * `codiedev ping maya "hey"` on some shells passes the quotes through.
182
+ * `codiedev ping <name> "hey"` on some shells passes the quotes through.
138
183
  */
139
184
  function stripQuotes(s) {
140
185
  if ((s.startsWith('"') && s.endsWith('"')) ||