@pebblehouse/odin-cli 0.2.0 → 0.2.2
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/index.js +37 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ function clearCredentials() {
|
|
|
37
37
|
// src/auth/login.ts
|
|
38
38
|
var API_URL = process.env.ODIN_API_URL ?? "https://www.odin.mu";
|
|
39
39
|
async function login() {
|
|
40
|
-
return new Promise((
|
|
40
|
+
return new Promise((resolve2, reject) => {
|
|
41
41
|
const server = createServer(async (req, res) => {
|
|
42
42
|
if (req.method === "POST" && req.url?.startsWith("/callback")) {
|
|
43
43
|
let body = "";
|
|
@@ -70,7 +70,7 @@ async function login() {
|
|
|
70
70
|
</div>
|
|
71
71
|
</body></html>`);
|
|
72
72
|
server.close();
|
|
73
|
-
|
|
73
|
+
resolve2();
|
|
74
74
|
} else {
|
|
75
75
|
res.writeHead(404);
|
|
76
76
|
res.end();
|
|
@@ -336,24 +336,28 @@ plansCmd.command("delete <slug> <id>").description("Delete a plan").action(async
|
|
|
336
336
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
337
337
|
if (res.error) process.exit(1);
|
|
338
338
|
});
|
|
339
|
-
plansCmd.command("add-phase <slug> <planId> <title>").description("Add a phase to a plan").requiredOption("--phase-number <number>", "Phase number", parseInt).option("--description <description>", "Phase description").action(async (slug, planId, title, opts) => {
|
|
339
|
+
plansCmd.command("add-phase <slug> <planId> <title>").description("Add a phase to a plan").requiredOption("--phase-number <number>", "Phase number", parseInt).option("--description <description>", "Phase description").option("--detail-type <type>", "Detail type (e.g. agent_spec, document)").option("--detail-id <id>", "Detail ID (UUID of linked entity)").action(async (slug, planId, title, opts) => {
|
|
340
340
|
const res = await apiRequest(`/pebbles/${slug}/plans/${planId}/phases`, {
|
|
341
341
|
method: "POST",
|
|
342
342
|
body: {
|
|
343
343
|
phase_number: opts.phaseNumber,
|
|
344
344
|
title,
|
|
345
|
-
description: opts.description ?? null
|
|
345
|
+
description: opts.description ?? null,
|
|
346
|
+
detail_type: opts.detailType ?? null,
|
|
347
|
+
detail_id: opts.detailId ?? null
|
|
346
348
|
}
|
|
347
349
|
});
|
|
348
350
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
349
351
|
if (res.error) process.exit(1);
|
|
350
352
|
});
|
|
351
|
-
plansCmd.command("update-phase <slug> <planId> <phaseId>").description("Update a phase").option("--title <title>", "Phase title").option("--status <status>", "Phase status (pending|in_progress|completed|skipped)").option("--notes <notes>", "Phase notes").option("--description <description>", "Phase description").action(async (slug, planId, phaseId, opts) => {
|
|
353
|
+
plansCmd.command("update-phase <slug> <planId> <phaseId>").description("Update a phase").option("--title <title>", "Phase title").option("--status <status>", "Phase status (pending|in_progress|completed|skipped)").option("--notes <notes>", "Phase notes").option("--description <description>", "Phase description").option("--detail-type <type>", "Detail type (e.g. agent_spec, document)").option("--detail-id <id>", "Detail ID (UUID of linked entity)").action(async (slug, planId, phaseId, opts) => {
|
|
352
354
|
const body = {};
|
|
353
355
|
if (opts.title) body.title = opts.title;
|
|
354
356
|
if (opts.status) body.status = opts.status;
|
|
355
357
|
if (opts.notes) body.notes = opts.notes;
|
|
356
358
|
if (opts.description) body.description = opts.description;
|
|
359
|
+
if (opts.detailType) body.detail_type = opts.detailType;
|
|
360
|
+
if (opts.detailId) body.detail_id = opts.detailId;
|
|
357
361
|
const res = await apiRequest(`/pebbles/${slug}/plans/${planId}/phases/${phaseId}`, {
|
|
358
362
|
method: "PUT",
|
|
359
363
|
body
|
|
@@ -371,6 +375,9 @@ plansCmd.command("delete-phase <slug> <planId> <phaseId>").description("Delete a
|
|
|
371
375
|
|
|
372
376
|
// src/commands/conversations.ts
|
|
373
377
|
import { Command as Command8 } from "commander";
|
|
378
|
+
function collect(value, previous) {
|
|
379
|
+
return previous.concat([value]);
|
|
380
|
+
}
|
|
374
381
|
var conversationsCmd = new Command8("conversations").description("Manage conversations");
|
|
375
382
|
conversationsCmd.command("list <slug>").description("List conversations for a pebble").action(async (slug) => {
|
|
376
383
|
const res = await apiRequest(`/pebbles/${slug}/conversations`);
|
|
@@ -382,12 +389,14 @@ conversationsCmd.command("get <slug> <id>").description("Get a conversation by I
|
|
|
382
389
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
383
390
|
if (res.error) process.exit(1);
|
|
384
391
|
});
|
|
385
|
-
conversationsCmd.command("create <slug> <title>").description("Create a conversation").option("--summary <summary>", "Conversation summary").option("--source-url <url>", "Source URL").option("--session-id <id>", "Link to active session").action(async (slug, title, opts) => {
|
|
392
|
+
conversationsCmd.command("create <slug> <title>").description("Create a conversation").option("--summary <summary>", "Conversation summary").option("--key-point <point>", "Key point (repeatable)", collect, []).option("--decision <decision>", "Decision made (repeatable)", collect, []).option("--source-url <url>", "Source URL").option("--session-id <id>", "Link to active session").action(async (slug, title, opts) => {
|
|
386
393
|
const res = await apiRequest(`/pebbles/${slug}/conversations`, {
|
|
387
394
|
method: "POST",
|
|
388
395
|
body: {
|
|
389
396
|
title,
|
|
390
397
|
summary: opts.summary ?? null,
|
|
398
|
+
key_points: opts.keyPoint,
|
|
399
|
+
decisions_made: opts.decision,
|
|
391
400
|
source_url: opts.sourceUrl ?? null,
|
|
392
401
|
session_id: opts.sessionId ?? null
|
|
393
402
|
}
|
|
@@ -395,10 +404,12 @@ conversationsCmd.command("create <slug> <title>").description("Create a conversa
|
|
|
395
404
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
396
405
|
if (res.error) process.exit(1);
|
|
397
406
|
});
|
|
398
|
-
conversationsCmd.command("update <slug> <id>").description("Update a conversation").option("--title <title>", "New title").option("--summary <summary>", "New summary").option("--source-url <url>", "New source URL").action(async (slug, id, opts) => {
|
|
407
|
+
conversationsCmd.command("update <slug> <id>").description("Update a conversation").option("--title <title>", "New title").option("--summary <summary>", "New summary").option("--key-point <point>", "Key point (repeatable, replaces existing)", collect, []).option("--decision <decision>", "Decision made (repeatable, replaces existing)", collect, []).option("--source-url <url>", "New source URL").action(async (slug, id, opts) => {
|
|
399
408
|
const body = {};
|
|
400
409
|
if (opts.title) body.title = opts.title;
|
|
401
410
|
if (opts.summary) body.summary = opts.summary;
|
|
411
|
+
if (opts.keyPoint.length > 0) body.key_points = opts.keyPoint;
|
|
412
|
+
if (opts.decision.length > 0) body.decisions_made = opts.decision;
|
|
402
413
|
if (opts.sourceUrl) body.source_url = opts.sourceUrl;
|
|
403
414
|
const res = await apiRequest(`/pebbles/${slug}/conversations/${id}`, {
|
|
404
415
|
method: "PUT",
|
|
@@ -418,24 +429,27 @@ conversationsCmd.command("delete <slug> <id>").description("Delete a conversatio
|
|
|
418
429
|
// src/commands/specs.ts
|
|
419
430
|
import { Command as Command9 } from "commander";
|
|
420
431
|
import { readFileSync as readFileSync4 } from "fs";
|
|
421
|
-
var specsCmd = new Command9("specs").description("Manage
|
|
422
|
-
specsCmd.command("list <slug>").description("List specs for a pebble").action(async (slug) => {
|
|
423
|
-
const
|
|
432
|
+
var specsCmd = new Command9("specs").description("Manage agent specs");
|
|
433
|
+
specsCmd.command("list <slug>").description("List specs for a pebble").option("--source <source>", "Filter by source (claude-code, superpowers, etc.)").action(async (slug, opts) => {
|
|
434
|
+
const params = {};
|
|
435
|
+
if (opts.source) params.source = opts.source;
|
|
436
|
+
const res = await apiRequest(`/pebbles/${slug}/agent-specs`, { params });
|
|
424
437
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
425
438
|
if (res.error) process.exit(1);
|
|
426
439
|
});
|
|
427
440
|
specsCmd.command("get <slug> <id>").description("Get a spec by ID").action(async (slug, id) => {
|
|
428
|
-
const res = await apiRequest(`/pebbles/${slug}/
|
|
441
|
+
const res = await apiRequest(`/pebbles/${slug}/agent-specs/${id}`);
|
|
429
442
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
430
443
|
if (res.error) process.exit(1);
|
|
431
444
|
});
|
|
432
|
-
specsCmd.command("create <slug> <title>").description("Create a spec").requiredOption("--spec-type <type>", "Spec type (e.g. brainstorm, plan, research)").option("--content <content>", "Spec content").option("--file <path>", "Read content from file").option("--session-id <id>", "Link to active session").action(async (slug, title, opts) => {
|
|
445
|
+
specsCmd.command("create <slug> <title>").description("Create a spec").requiredOption("--spec-type <type>", "Spec type (e.g. brainstorm, plan, research)").option("--source <source>", "Source agent", "claude-code").option("--content <content>", "Spec content").option("--file <path>", "Read content from file").option("--session-id <id>", "Link to active session").action(async (slug, title, opts) => {
|
|
433
446
|
const content = opts.file ? readFileSync4(opts.file, "utf-8") : opts.content ?? "";
|
|
434
|
-
const res = await apiRequest(`/pebbles/${slug}/
|
|
447
|
+
const res = await apiRequest(`/pebbles/${slug}/agent-specs`, {
|
|
435
448
|
method: "POST",
|
|
436
449
|
body: {
|
|
437
450
|
title,
|
|
438
451
|
spec_type: opts.specType,
|
|
452
|
+
source: opts.source,
|
|
439
453
|
content,
|
|
440
454
|
session_id: opts.sessionId ?? null
|
|
441
455
|
}
|
|
@@ -443,13 +457,14 @@ specsCmd.command("create <slug> <title>").description("Create a spec").requiredO
|
|
|
443
457
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
444
458
|
if (res.error) process.exit(1);
|
|
445
459
|
});
|
|
446
|
-
specsCmd.command("update <slug> <id>").description("Update a spec").option("--title <title>", "New title").option("--spec-type <type>", "New spec type").option("--content <content>", "New content").option("--file <path>", "Read content from file").action(async (slug, id, opts) => {
|
|
460
|
+
specsCmd.command("update <slug> <id>").description("Update a spec").option("--title <title>", "New title").option("--spec-type <type>", "New spec type").option("--source <source>", "New source").option("--content <content>", "New content").option("--file <path>", "Read content from file").action(async (slug, id, opts) => {
|
|
447
461
|
const body = {};
|
|
448
462
|
if (opts.title) body.title = opts.title;
|
|
449
463
|
if (opts.specType) body.spec_type = opts.specType;
|
|
464
|
+
if (opts.source) body.source = opts.source;
|
|
450
465
|
if (opts.file) body.content = readFileSync4(opts.file, "utf-8");
|
|
451
466
|
else if (opts.content) body.content = opts.content;
|
|
452
|
-
const res = await apiRequest(`/pebbles/${slug}/
|
|
467
|
+
const res = await apiRequest(`/pebbles/${slug}/agent-specs/${id}`, {
|
|
453
468
|
method: "PUT",
|
|
454
469
|
body
|
|
455
470
|
});
|
|
@@ -457,7 +472,7 @@ specsCmd.command("update <slug> <id>").description("Update a spec").option("--ti
|
|
|
457
472
|
if (res.error) process.exit(1);
|
|
458
473
|
});
|
|
459
474
|
specsCmd.command("delete <slug> <id>").description("Delete a spec").action(async (slug, id) => {
|
|
460
|
-
const res = await apiRequest(`/pebbles/${slug}/
|
|
475
|
+
const res = await apiRequest(`/pebbles/${slug}/agent-specs/${id}`, {
|
|
461
476
|
method: "DELETE"
|
|
462
477
|
});
|
|
463
478
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
@@ -498,10 +513,15 @@ versionsCmd.command("get <slug> <docType> <versionId>").description("Get a speci
|
|
|
498
513
|
});
|
|
499
514
|
|
|
500
515
|
// src/index.ts
|
|
516
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
517
|
+
import { fileURLToPath } from "url";
|
|
518
|
+
import { dirname, resolve } from "path";
|
|
519
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
520
|
+
var pkg = JSON.parse(readFileSync5(resolve(__dirname, "../package.json"), "utf-8"));
|
|
501
521
|
var GOLD = "\x1B[33m";
|
|
502
522
|
var DIM = "\x1B[2m";
|
|
503
523
|
var RESET = "\x1B[0m";
|
|
504
|
-
var VERSION =
|
|
524
|
+
var VERSION = pkg.version;
|
|
505
525
|
function printBanner() {
|
|
506
526
|
const cwd = process.cwd();
|
|
507
527
|
console.error(`${GOLD}
|