codiedev 0.3.3 → 0.3.5

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 CHANGED
@@ -22,9 +22,14 @@ const ping_1 = require("./commands/ping");
22
22
  const inbox_1 = require("./commands/inbox");
23
23
  const note_1 = require("./commands/note");
24
24
  const promote_1 = require("./commands/promote");
25
+ const reverseTicket_1 = require("./commands/reverseTicket");
25
26
  const HELP = `
26
27
  CodieDev CLI
27
28
 
29
+ The team artifact layer for agent-coded work. Share specs and reviews
30
+ with teammates, get pinged when they need your input, pick up where
31
+ someone left off across sessions and providers.
32
+
28
33
  Connect:
29
34
  codiedev connect Link Claude Code / Codex to your org
30
35
 
@@ -34,6 +39,8 @@ Artifacts:
34
39
  Fetch an artifact (stdout by default)
35
40
  codiedev promote <artifact-id> Promote an auto-extracted artifact
36
41
  to an authored one
42
+ codiedev reverse-ticket <pr-url> Generate a Jira ticket from a merged PR
43
+ (auto-matches spec + thread + transcript)
37
44
 
38
45
  Messaging:
39
46
  codiedev ping <user> "<msg>" [--with <key>]
@@ -45,19 +52,260 @@ Capture:
45
52
  codiedev note "<text>" Capture a passing thought
46
53
 
47
54
  Other:
48
- codiedev help Show this help
55
+ codiedev help [command] Show this help, or details for one command
56
+ codiedev docs Print the full usage guide
49
57
  codiedev version Show version
50
58
 
59
+ Filename conventions:
60
+ spec-*.md → spec review-*.md → review
61
+ decision-*.md → decision proposal-*.md → proposal
62
+ bugfix-*.md → bugfix anything else → note
63
+
64
+ Examples:
65
+ codiedev push docs/specs/spec-cart-clear.md
66
+ codiedev pull spec-cart-clear.md
67
+ codiedev ping maya "thoughts on batch vs parallel?" --with spec-cart-clear.md
68
+ codiedev inbox --unread
69
+ codiedev note "idempotency key is worth a follow-up"
70
+
51
71
  Backend: ${process.env.CODIEDEV_URL ?? "https://codiedev.com"}
72
+ Token: https://codiedev.com/portal/integrations/claude-code
73
+ Docs: codiedev docs
74
+ `.trim();
75
+ const COMMAND_HELP = {
76
+ connect: `
77
+ codiedev connect — link your agent CLI to CodieDev
78
+
79
+ Interactive setup. Prompts for an API token, then installs:
80
+ - ~/.codiedev/config.json (token + org + tracked repos)
81
+ - ~/.claude/settings.json hook (captures session transcripts)
82
+ - ~/.claude/CLAUDE.md instructions (teaches Claude the commands)
83
+ - ~/.codex/hooks.json hook (same, for Codex)
84
+ - ~/.codex/AGENTS.md instructions (same, for Codex)
85
+
86
+ Re-run anytime to swap accounts or refresh the instruction block.
87
+
88
+ Get your token: https://codiedev.com/portal/integrations/claude-code
89
+ `.trim(),
90
+ push: `
91
+ codiedev push — author or update an artifact
92
+
93
+ Usage:
94
+ codiedev push <file.md> [--type spec|review|decision|proposal|bugfix|note]
95
+
96
+ The file's basename becomes its key (unique per company). Pushing the
97
+ same key again creates a new version — full history is preserved.
98
+
99
+ Type is inferred from the filename prefix unless you override with --type.
100
+
101
+ Examples:
102
+ codiedev push spec-cart-clear.md
103
+ codiedev push docs/review-auth.md --type review
104
+ codiedev push notes/random.md --type note
105
+ `.trim(),
106
+ pull: `
107
+ codiedev pull — fetch an artifact
108
+
109
+ Usage:
110
+ codiedev pull <key> [--version N] [--out path.md]
111
+
112
+ By default prints to stdout (pipe-friendly). --out writes to a file.
113
+ --version gets a specific historical version; omit for the latest.
114
+
115
+ Examples:
116
+ codiedev pull spec-cart-clear.md
117
+ codiedev pull spec-cart-clear.md --version 2
118
+ codiedev pull spec-cart-clear.md --out ./local-copy.md
119
+ codiedev pull spec-cart-clear.md | less
120
+ `.trim(),
121
+ ping: `
122
+ codiedev ping — send a teammate a message, optionally attached to an artifact
123
+
124
+ Usage:
125
+ codiedev ping <user> "<message>" [--with <artifact-key>]
126
+
127
+ <user> resolves to a teammate in your org by first name, full name,
128
+ or email. Ambiguous matches return a list — retry with the full email.
129
+
130
+ Teammates are notified by email and can reply from their own agent.
131
+
132
+ Examples:
133
+ codiedev ping maya "thoughts on batch vs parallel?" --with spec-cart-clear.md
134
+ codiedev ping nic@signalandcode.co "can you take this one?"
135
+ `.trim(),
136
+ inbox: `
137
+ codiedev inbox — show messages from teammates
138
+
139
+ Usage:
140
+ codiedev inbox [--unread] [--limit N]
141
+
142
+ Lists pings with sender, subject artifact, and preview. Each row
143
+ shows a ping-id you can pass to 'codiedev read'.
144
+
145
+ Unread rows show as ● ; read rows as · .
146
+
147
+ Examples:
148
+ codiedev inbox
149
+ codiedev inbox --unread
150
+ codiedev inbox --limit 10
151
+ `.trim(),
152
+ read: `
153
+ codiedev read — mark a ping as read and show its full content
154
+
155
+ Usage:
156
+ codiedev read <ping-id>
157
+
158
+ Grab the ping-id from 'codiedev inbox'. After reading, the ping will
159
+ drop out of 'codiedev inbox --unread' and the portal inbox badge
160
+ decrements for you.
161
+ `.trim(),
162
+ note: `
163
+ codiedev note — capture a passing thought, linked to your session
164
+
165
+ Usage:
166
+ codiedev note "<text>"
167
+
168
+ Stores the note in your org memory so you can search it later or
169
+ reference it in a ticket. Notes appear in the portal under the
170
+ Agent Inbox → My authored artifacts.
171
+
172
+ Examples:
173
+ codiedev note "idempotency key is worth a follow-up"
174
+ codiedev note "timeout threshold feels arbitrary — validate on slow networks"
175
+ `.trim(),
176
+ promote: `
177
+ codiedev promote — promote an auto-extracted artifact to authored
178
+
179
+ Usage:
180
+ codiedev promote <artifact-id> [--key filename.md]
181
+
182
+ The session-capture pipeline auto-extracts spec/bugfix/decision
183
+ artifacts from each agent session. Promote turns one of those into
184
+ a first-class authored artifact your team can ping, pull, and
185
+ update versions of.
186
+
187
+ Find artifact-ids in the portal under Knowledge → Memory, or via
188
+ the portal search.
189
+ `.trim(),
190
+ };
191
+ const DOCS = `
192
+ CodieDev — usage guide
193
+
194
+ ## What this is
195
+
196
+ CodieDev is a team artifact layer on top of your coding agent (Claude
197
+ Code, Codex, etc.). It persists the *durable* outputs of agent work —
198
+ specs, reviews, decisions, proposals, and captured thoughts — so:
199
+
200
+ - Your teammates can pick up where you left off without a handoff call.
201
+ - Your manager can see what's shipping and why, grounded in real
202
+ session evidence.
203
+ - Your future self can search "what did we decide about X?" and get
204
+ a real answer with citations.
205
+
206
+ ## Core loop
207
+
208
+ 1. You push an artifact:
209
+ codiedev push spec-cart-clear.md
210
+
211
+ 2. Your teammate gets pinged (either directly by you, or because
212
+ they asked to be kept in the loop on that key):
213
+ codiedev ping maya "thoughts?" --with spec-cart-clear.md
214
+
215
+ 3. They check their inbox:
216
+ codiedev inbox
217
+
218
+ 4. They pull your artifact, edit it, and push back:
219
+ codiedev pull spec-cart-clear.md > my-copy.md
220
+ # ...edit...
221
+ codiedev push my-copy.md (saves as v2 of the same key)
222
+
223
+ 5. You pull the updated version and keep building.
224
+
225
+ ## Versions
226
+
227
+ Every push of the same filename creates a new version. Latest is the
228
+ default on pull; use --version N to get a historical one. All versions
229
+ are preserved — you can always roll back.
230
+
231
+ ## Lifecycle
232
+
233
+ Artifacts have a status that auto-advances as PRs reference them:
234
+
235
+ draft → accepted → implementing → shipped
236
+ → archived
237
+
238
+ Artifacts stay editable at every stage, including after merge —
239
+ lessons-learned and follow-up notes append as new versions.
240
+
241
+ ## Portal
242
+
243
+ Everything you do in the CLI is visible at:
244
+
245
+ https://codiedev.com/portal/inbox
246
+
247
+ Your CTO (or any non-technical teammate) can follow along without ever
248
+ touching a terminal — they read the artifacts in the portal and get
249
+ email notifications when pinged.
250
+
251
+ ## Agent-native
252
+
253
+ If you use Claude Code or Codex, the agent already knows the commands —
254
+ 'codiedev connect' installs instructions into your user-level config.
255
+ Just say things like:
256
+
257
+ "push this spec and ping Nic"
258
+ "any messages?"
259
+ "pull Maya's latest spec"
260
+
261
+ The agent will run the right command via Bash.
262
+
263
+ ## Command reference
264
+
265
+ Run 'codiedev help <command>' for each, or see the quick list:
266
+
267
+ codiedev help
268
+
269
+ ## Getting a token
270
+
271
+ 1. Log in to https://codiedev.com/portal/integrations/claude-code
272
+ 2. Click "Create token"
273
+ 3. Copy the cdv_... string and paste it into 'codiedev connect'
274
+
275
+ Tokens are per-user. Rotate any time by revoking + creating a new one.
52
276
  `.trim();
53
277
  async function main() {
54
278
  const [, , command, ...rest] = process.argv;
55
- if (!command || command === "help" || command === "--help" || command === "-h") {
279
+ if (!command || command === "--help" || command === "-h") {
56
280
  console.log(HELP);
57
281
  return;
58
282
  }
283
+ if (command === "help") {
284
+ const sub = rest[0];
285
+ if (sub && COMMAND_HELP[sub]) {
286
+ console.log(COMMAND_HELP[sub]);
287
+ return;
288
+ }
289
+ if (sub) {
290
+ console.log(`No help for "${sub}". Valid commands:`);
291
+ console.log(Object.keys(COMMAND_HELP).join(", "));
292
+ return;
293
+ }
294
+ console.log(HELP);
295
+ return;
296
+ }
297
+ if (command === "docs") {
298
+ console.log(DOCS);
299
+ return;
300
+ }
301
+ // Support `codiedev <command> --help` too.
302
+ if (rest.includes("--help") || rest.includes("-h")) {
303
+ if (COMMAND_HELP[command]) {
304
+ console.log(COMMAND_HELP[command]);
305
+ return;
306
+ }
307
+ }
59
308
  if (command === "version" || command === "--version" || command === "-v") {
60
- // Package version is replaced at publish via tsc — for now, print the source-of-truth.
61
309
  console.log("codiedev cli");
62
310
  return;
63
311
  }
@@ -94,6 +342,10 @@ async function main() {
94
342
  case "promote":
95
343
  await (0, promote_1.runPromote)(rest);
96
344
  return;
345
+ case "reverse-ticket":
346
+ case "reverseTicket":
347
+ await (0, reverseTicket_1.runReverseTicket)(rest);
348
+ return;
97
349
  default:
98
350
  console.error(`Unknown command: ${command}`);
99
351
  console.error(HELP);
@@ -0,0 +1 @@
1
+ export declare function runReverseTicket(args: string[]): Promise<void>;
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runReverseTicket = runReverseTicket;
4
+ const child_process_1 = require("child_process");
5
+ const shared_1 = require("./shared");
6
+ function parsePrUrl(url) {
7
+ const m = url.match(/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/);
8
+ if (!m)
9
+ return null;
10
+ return { owner: m[1], repo: m[2], number: Number(m[3]) };
11
+ }
12
+ function checkGhCli() {
13
+ try {
14
+ (0, child_process_1.execSync)("gh --version", { stdio: ["pipe", "pipe", "pipe"] });
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ function ghApi(path) {
22
+ const out = (0, child_process_1.execSync)(`gh api "${path}"`, {
23
+ stdio: ["pipe", "pipe", "pipe"],
24
+ maxBuffer: 50 * 1024 * 1024,
25
+ }).toString("utf8");
26
+ return JSON.parse(out);
27
+ }
28
+ function ghRaw(path) {
29
+ return (0, child_process_1.execSync)(`gh api -H "Accept: application/vnd.github.v3.diff" "${path}"`, {
30
+ stdio: ["pipe", "pipe", "pipe"],
31
+ maxBuffer: 50 * 1024 * 1024,
32
+ }).toString("utf8");
33
+ }
34
+ function parseArgs(args) {
35
+ let prUrl;
36
+ let forcedKey;
37
+ let noTruncate = false;
38
+ for (let i = 0; i < args.length; i++) {
39
+ const a = args[i];
40
+ if ((a === "--with" || a === "-w") && i + 1 < args.length) {
41
+ forcedKey = args[++i];
42
+ }
43
+ else if (a.startsWith("--with=")) {
44
+ forcedKey = a.slice("--with=".length);
45
+ }
46
+ else if (a === "--full") {
47
+ noTruncate = true;
48
+ }
49
+ else if (!a.startsWith("--") && !prUrl) {
50
+ prUrl = a;
51
+ }
52
+ }
53
+ if (!prUrl) {
54
+ console.error("Usage: codiedev reverse-ticket <pr-url> [--with <artifact-key>] [--full]");
55
+ console.error("");
56
+ console.error("Example: codiedev reverse-ticket https://github.com/signalandcode/repo/pull/42");
57
+ process.exit(1);
58
+ }
59
+ return { prUrl, forcedKey, noTruncate };
60
+ }
61
+ async function runReverseTicket(args) {
62
+ const { prUrl, forcedKey, noTruncate } = parseArgs(args);
63
+ const parsed = parsePrUrl(prUrl);
64
+ if (!parsed) {
65
+ console.error("Couldn't parse PR URL. Expected format: https://github.com/<owner>/<repo>/pull/<number>");
66
+ process.exit(1);
67
+ }
68
+ if (!checkGhCli()) {
69
+ console.error("This command needs the `gh` CLI installed and authenticated.");
70
+ console.error(" brew install gh (macOS)");
71
+ console.error(" gh auth login");
72
+ process.exit(1);
73
+ }
74
+ const config = (0, shared_1.requireConfig)();
75
+ console.log(`Fetching PR ${parsed.owner}/${parsed.repo}#${parsed.number}…`);
76
+ let prJson;
77
+ let filesJson;
78
+ let diff;
79
+ try {
80
+ prJson = ghApi(`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}`);
81
+ filesJson = ghApi(`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}/files`);
82
+ // Diff is nice-to-have; truncate if huge.
83
+ try {
84
+ const rawDiff = ghRaw(`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}`);
85
+ diff = noTruncate ? rawDiff : rawDiff.slice(0, 12_000);
86
+ }
87
+ catch {
88
+ // Skip diff on failure — the writer works without it.
89
+ }
90
+ }
91
+ catch (err) {
92
+ console.error(`Failed to fetch PR via gh api: ${err.message}`);
93
+ process.exit(1);
94
+ }
95
+ const bundle = {
96
+ repo: `${parsed.owner}/${parsed.repo}`,
97
+ number: parsed.number,
98
+ title: prJson.title ?? "",
99
+ body: prJson.body ?? "",
100
+ author: prJson.user?.login ?? "unknown",
101
+ authorEmail: prJson.user?.email ?? undefined,
102
+ mergedAt: prJson.merged_at
103
+ ? Date.parse(prJson.merged_at)
104
+ : prJson.closed_at
105
+ ? Date.parse(prJson.closed_at)
106
+ : Date.now(),
107
+ filesChanged: (filesJson ?? []).map((f) => f.filename),
108
+ diff,
109
+ htmlUrl: prJson.html_url ?? prUrl,
110
+ };
111
+ console.log(` title: ${bundle.title}`);
112
+ console.log(` author: ${bundle.author}`);
113
+ console.log(` files: ${bundle.filesChanged.length}`);
114
+ console.log(` merged: ${new Date(bundle.mergedAt).toISOString()}`);
115
+ console.log("");
116
+ console.log("Generating ticket…");
117
+ console.log("");
118
+ try {
119
+ const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reverseTicket", {
120
+ config,
121
+ body: {
122
+ pr: bundle,
123
+ forcedArtifactKey: forcedKey,
124
+ },
125
+ });
126
+ if (res.match) {
127
+ console.log(`✓ Matched artifact: ${res.match.key} (score=${res.match.score.toFixed(2)})`);
128
+ console.log(` signals · body=${res.match.signals.bodyMention} · files=${res.match.signals.fileOverlap.toFixed(2)} · transcript=${res.match.signals.transcriptEdit}`);
129
+ }
130
+ else if (res.candidates.length > 0) {
131
+ console.log(`? Ambiguous / low confidence. Candidates:`);
132
+ for (const c of res.candidates.slice(0, 3)) {
133
+ console.log(` - ${c.key} (score=${c.score.toFixed(2)})`);
134
+ }
135
+ console.log(` Re-run with --with <key> to force a specific artifact.`);
136
+ }
137
+ else {
138
+ console.log("· No matched artifact. Ticket generated from PR diff alone.");
139
+ }
140
+ console.log(` prompt tokens (est): ${res.tokensInEstimate}`);
141
+ console.log("");
142
+ console.log("─────────── Generated ticket ───────────");
143
+ console.log("");
144
+ console.log(res.ticket);
145
+ }
146
+ catch (err) {
147
+ console.error(`Reverse-ticket failed: ${err.message}`);
148
+ process.exit(1);
149
+ }
150
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Connect Claude Code or Codex to CodieDev for org-wide session capture and artifact collaboration",
5
5
  "bin": {
6
6
  "codiedev": "./dist/cli.js",