@pebblehouse/odin-cli 0.17.0 → 0.18.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/README.md +8 -0
- package/dist/index.js +62 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,6 +65,14 @@ odin search "authentication" # Cross-pebble
|
|
|
65
65
|
odin search "RLS policies" --pebble odin # Scoped
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
### Tickets
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
odin tickets resolve ODIN-12 # Resolve a ticket key to its bet or task
|
|
72
|
+
odin tasks promote <slug> <task-id> --file ./bet.md # Promote a task to a bet (keeps its ticket ID)
|
|
73
|
+
odin tasks create <slug> "Fix" --follow-up-of ODIN-12 # Allocate ODIN-12A as a follow-up
|
|
74
|
+
```
|
|
75
|
+
|
|
68
76
|
### Auth
|
|
69
77
|
|
|
70
78
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command24 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/auth/login.ts
|
|
7
7
|
import open from "open";
|
|
@@ -407,10 +407,10 @@ pebblesCmd.command("get <slug>").description("Get pebble details").action(async
|
|
|
407
407
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
408
408
|
if (res.error) process.exit(1);
|
|
409
409
|
});
|
|
410
|
-
pebblesCmd.command("create <slug>").description("Create a pebble").requiredOption("--name <name>", "Pebble name").option("--status <status>", "Initial status", "idea").option("--summary <summary>", "Summary").action(async (slug, opts) => {
|
|
410
|
+
pebblesCmd.command("create <slug>").description("Create a pebble").requiredOption("--name <name>", "Pebble name").option("--status <status>", "Initial status", "idea").option("--summary <summary>", "Summary").option("--ticket-prefix <PREFIX>", "Four uppercase letters for ticket IDs (derived from slug when omitted)").action(async (slug, opts) => {
|
|
411
411
|
const res = await apiRequest("/pebbles", {
|
|
412
412
|
method: "POST",
|
|
413
|
-
body: { slug, name: opts.name, status: opts.status, summary: opts.summary }
|
|
413
|
+
body: { slug, name: opts.name, status: opts.status, summary: opts.summary, ticket_prefix: opts.ticketPrefix }
|
|
414
414
|
});
|
|
415
415
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
416
416
|
if (res.error) process.exit(1);
|
|
@@ -1242,11 +1242,11 @@ betsCmd.command("get <slug> <id>").description("Get a bet by ID").action(async (
|
|
|
1242
1242
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1243
1243
|
if (res.error) process.exit(1);
|
|
1244
1244
|
});
|
|
1245
|
-
betsCmd.command("create <slug> <title>").description("Create a bet").option("--source <source>", "Source agent", "claude-code").option("--content <content>", "Bet content").option("--file <path>", "Read content from file").option("--status <status>", "Bet status (pitch, shaped, betting, active, blocked, building, done, archived)").option("--priority <priority>", "Bet priority").option("--appetite <appetite>", "Bet appetite").action(async (slug, title, opts) => {
|
|
1245
|
+
betsCmd.command("create <slug> <title>").description("Create a bet").option("--source <source>", "Source agent", "claude-code").option("--content <content>", "Bet content").option("--file <path>", "Read content from file").option("--status <status>", "Bet status (pitch, shaped, betting, active, blocked, building, done, archived)").option("--priority <priority>", "Bet priority").option("--appetite <appetite>", "Bet appetite").option("--follow-up-of <key-or-uuid>", "Allocate a suffixed follow-up ticket in this ticket's family (e.g. ODIN-12 \u2192 ODIN-12A)").action(async (slug, title, opts) => {
|
|
1246
1246
|
const content = opts.file ? readFileSync10(opts.file, "utf-8") : opts.content ?? "";
|
|
1247
1247
|
const res = await apiRequest(`/pebbles/${slug}/bets`, {
|
|
1248
1248
|
method: "POST",
|
|
1249
|
-
body: { title, source: opts.source, content, status: opts.status, priority: opts.priority, appetite: opts.appetite }
|
|
1249
|
+
body: { title, source: opts.source, content, status: opts.status, priority: opts.priority, appetite: opts.appetite, follow_up_of: opts.followUpOf }
|
|
1250
1250
|
});
|
|
1251
1251
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1252
1252
|
if (res.error) process.exit(1);
|
|
@@ -1275,10 +1275,24 @@ betsCmd.command("delete <slug> <id>").description("Delete a bet").action(async (
|
|
|
1275
1275
|
});
|
|
1276
1276
|
betsCmd.addCommand(depsCmd);
|
|
1277
1277
|
|
|
1278
|
-
// src/commands/
|
|
1278
|
+
// src/commands/tickets.ts
|
|
1279
1279
|
import { Command as Command15 } from "commander";
|
|
1280
|
+
var ticketsCmd = new Command15("tickets").description("Resolve human-readable ticket IDs");
|
|
1281
|
+
ticketsCmd.command("resolve <key>").description("Resolve a ticket key (e.g. ODIN-12, RATE-36A) to its bet or task, with historical candidates").action(async (key) => {
|
|
1282
|
+
const res = await apiRequest(`/tickets/${encodeURIComponent(key.trim().toUpperCase())}`);
|
|
1283
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1284
|
+
if (res.data?.legacy_ambiguous) {
|
|
1285
|
+
const others = res.data.candidates.filter((c) => c.entity_id !== res.data.entity_id);
|
|
1286
|
+
process.stderr.write(`note: ${key.toUpperCase()} was a duplicated legacy label; also matches ${others.map((c) => c.ticket_key ?? c.entity_id).join(", ")}
|
|
1287
|
+
`);
|
|
1288
|
+
}
|
|
1289
|
+
if (res.error) process.exit(1);
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
// src/commands/bet-comments.ts
|
|
1293
|
+
import { Command as Command16 } from "commander";
|
|
1280
1294
|
import { readFileSync as readFileSync11 } from "fs";
|
|
1281
|
-
var betCommentsCmd = new
|
|
1295
|
+
var betCommentsCmd = new Command16("bet-comments").description("Manage bet comments");
|
|
1282
1296
|
betCommentsCmd.command("list <slug> <betId>").description("List comments for a bet (oldest first)").action(async (slug, betId) => {
|
|
1283
1297
|
const res = await apiRequest(`/pebbles/${slug}/bets/${betId}/comments`);
|
|
1284
1298
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
@@ -1305,8 +1319,9 @@ betCommentsCmd.command("create <slug> <betId> [body]").description("Post a comme
|
|
|
1305
1319
|
});
|
|
1306
1320
|
|
|
1307
1321
|
// src/commands/tasks.ts
|
|
1308
|
-
import { Command as
|
|
1309
|
-
|
|
1322
|
+
import { Command as Command17 } from "commander";
|
|
1323
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
1324
|
+
var tasksCmd = new Command17("tasks").description("Manage tasks");
|
|
1310
1325
|
withListFlags(
|
|
1311
1326
|
tasksCmd.command("list <slug>").description("List tasks for a pebble").option("--status <status>", "Filter by status").option("--bet <bet-id>", "Filter by bet ID")
|
|
1312
1327
|
).action(async (slug, opts) => {
|
|
@@ -1327,10 +1342,10 @@ tasksCmd.command("get <slug> <id>").description("Get a task by ID").action(async
|
|
|
1327
1342
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1328
1343
|
if (res.error) process.exit(1);
|
|
1329
1344
|
});
|
|
1330
|
-
tasksCmd.command("create <slug> <title>").description("Create a task").option("--source <source>", "Source agent", "claude-code").option("--description <description>", "Task description").option("--bet <bet-id>", "Parent bet ID").option("--status <status>", "Task status").option("--priority <priority>", "Task priority").action(async (slug, title, opts) => {
|
|
1345
|
+
tasksCmd.command("create <slug> <title>").description("Create a task").option("--source <source>", "Source agent", "claude-code").option("--description <description>", "Task description").option("--bet <bet-id>", "Parent bet ID").option("--status <status>", "Task status").option("--priority <priority>", "Task priority").option("--follow-up-of <key-or-uuid>", "Allocate a suffixed follow-up ticket in this ticket's family (e.g. ODIN-12 \u2192 ODIN-12A)").action(async (slug, title, opts) => {
|
|
1331
1346
|
const res = await apiRequest(`/pebbles/${slug}/tasks`, {
|
|
1332
1347
|
method: "POST",
|
|
1333
|
-
body: { title, source: opts.source, description: opts.description, bet_id: opts.bet, status: opts.status, priority: opts.priority }
|
|
1348
|
+
body: { title, source: opts.source, description: opts.description, bet_id: opts.bet, status: opts.status, priority: opts.priority, follow_up_of: opts.followUpOf }
|
|
1334
1349
|
});
|
|
1335
1350
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1336
1351
|
if (res.error) process.exit(1);
|
|
@@ -1349,6 +1364,15 @@ tasksCmd.command("update <slug> <id>").description("Update a task").option("--ti
|
|
|
1349
1364
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1350
1365
|
if (res.error) process.exit(1);
|
|
1351
1366
|
});
|
|
1367
|
+
tasksCmd.command("promote <slug> <id>").description("Promote a task to a bet, keeping its ticket ID and history").option("--content <content>", "Shaped bet markdown").option("--file <path>", "Read bet markdown from file").option("--status <status>", "Bet status (pitch | shaped)", "shaped").option("--priority <priority>", "Bet priority").action(async (slug, id, opts) => {
|
|
1368
|
+
const content = opts.file ? readFileSync12(opts.file, "utf-8") : opts.content;
|
|
1369
|
+
const res = await apiRequest(`/pebbles/${slug}/tasks/${id}/promote`, {
|
|
1370
|
+
method: "POST",
|
|
1371
|
+
body: { content, status: opts.status, priority: opts.priority }
|
|
1372
|
+
});
|
|
1373
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
1374
|
+
if (res.error) process.exit(1);
|
|
1375
|
+
});
|
|
1352
1376
|
tasksCmd.command("delete <slug> <id>").description("Delete a task").action(async (slug, id) => {
|
|
1353
1377
|
const res = await apiRequest(`/pebbles/${slug}/tasks/${id}`, {
|
|
1354
1378
|
method: "DELETE"
|
|
@@ -1358,9 +1382,9 @@ tasksCmd.command("delete <slug> <id>").description("Delete a task").action(async
|
|
|
1358
1382
|
});
|
|
1359
1383
|
|
|
1360
1384
|
// src/commands/roadmaps.ts
|
|
1361
|
-
import { Command as
|
|
1362
|
-
import { readFileSync as
|
|
1363
|
-
var roadmapsCmd = new
|
|
1385
|
+
import { Command as Command18 } from "commander";
|
|
1386
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
1387
|
+
var roadmapsCmd = new Command18("roadmaps").description("Manage roadmaps");
|
|
1364
1388
|
roadmapsCmd.command("list <slug>").description("List roadmaps for a pebble").option("--status <status>", "Filter by status").action(async (slug, opts) => {
|
|
1365
1389
|
const params = {};
|
|
1366
1390
|
if (opts.status) params.status = opts.status;
|
|
@@ -1374,7 +1398,7 @@ roadmapsCmd.command("get <slug> <id>").description("Get a roadmap by ID (include
|
|
|
1374
1398
|
if (res.error) process.exit(1);
|
|
1375
1399
|
});
|
|
1376
1400
|
roadmapsCmd.command("create <slug> <title>").description("Create a roadmap").option("--source <source>", "Source agent", "claude-code").option("--content <content>", "Roadmap content").option("--file <path>", "Read content from file").option("--status <status>", "Roadmap status").action(async (slug, title, opts) => {
|
|
1377
|
-
const content = opts.file ?
|
|
1401
|
+
const content = opts.file ? readFileSync13(opts.file, "utf-8") : opts.content ?? "";
|
|
1378
1402
|
const res = await apiRequest(`/pebbles/${slug}/roadmaps`, {
|
|
1379
1403
|
method: "POST",
|
|
1380
1404
|
body: { title, source: opts.source, content, status: opts.status }
|
|
@@ -1385,7 +1409,7 @@ roadmapsCmd.command("create <slug> <title>").description("Create a roadmap").opt
|
|
|
1385
1409
|
roadmapsCmd.command("update <slug> <id>").description("Update a roadmap").option("--title <title>", "New title").option("--content <content>", "New content").option("--file <path>", "Read content from file").option("--status <status>", "New status").action(async (slug, id, opts) => {
|
|
1386
1410
|
const body = {};
|
|
1387
1411
|
if (opts.title) body.title = opts.title;
|
|
1388
|
-
if (opts.file) body.content =
|
|
1412
|
+
if (opts.file) body.content = readFileSync13(opts.file, "utf-8");
|
|
1389
1413
|
else if (opts.content) body.content = opts.content;
|
|
1390
1414
|
if (opts.status) body.status = opts.status;
|
|
1391
1415
|
const res = await apiRequest(`/pebbles/${slug}/roadmaps/${id}`, {
|
|
@@ -1404,11 +1428,11 @@ roadmapsCmd.command("delete <slug> <id>").description("Delete a roadmap").action
|
|
|
1404
1428
|
});
|
|
1405
1429
|
|
|
1406
1430
|
// src/commands/persona-runs.ts
|
|
1407
|
-
import { Command as
|
|
1408
|
-
import { readFileSync as
|
|
1431
|
+
import { Command as Command19 } from "commander";
|
|
1432
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
1409
1433
|
import { join as join2 } from "path";
|
|
1410
1434
|
import { homedir as homedir2 } from "os";
|
|
1411
|
-
var personaRunsCmd = new
|
|
1435
|
+
var personaRunsCmd = new Command19("persona-runs").description(
|
|
1412
1436
|
"Manage per-persona per-session token usage rows"
|
|
1413
1437
|
);
|
|
1414
1438
|
personaRunsCmd.command("list <slug>").description("List persona runs for a pebble").option("--bet-id <id>", "Filter by bet_id").option("--plan-id <id>", "Filter by plan_id").option("--persona <name>", "Filter by persona name").option("--limit <n>", "Max rows", "50").action(async (slug, opts) => {
|
|
@@ -1432,7 +1456,7 @@ personaRunsCmd.command("get <slug> <id>").description("Get a persona run by id")
|
|
|
1432
1456
|
if (res.error) process.exit(1);
|
|
1433
1457
|
});
|
|
1434
1458
|
personaRunsCmd.command("create <slug>").description("Create/upsert a persona run from a JSON file").requiredOption("--file <path>", "JSON payload matching PersonaRunCreate").action(async (slug, opts) => {
|
|
1435
|
-
const body = JSON.parse(
|
|
1459
|
+
const body = JSON.parse(readFileSync14(opts.file, "utf-8"));
|
|
1436
1460
|
const res = await apiRequest(`/pebbles/${slug}/persona-runs`, {
|
|
1437
1461
|
method: "POST",
|
|
1438
1462
|
body
|
|
@@ -1444,7 +1468,7 @@ personaRunsCmd.command("capture").description("Read marker + transcript, compute
|
|
|
1444
1468
|
const markerPath = opts.marker ?? join2(homedir2(), ".claude", "odin-context", `${opts.sessionId}.json`);
|
|
1445
1469
|
let marker = {};
|
|
1446
1470
|
try {
|
|
1447
|
-
marker = JSON.parse(
|
|
1471
|
+
marker = JSON.parse(readFileSync14(markerPath, "utf-8"));
|
|
1448
1472
|
} catch {
|
|
1449
1473
|
process.exit(0);
|
|
1450
1474
|
}
|
|
@@ -1454,7 +1478,7 @@ personaRunsCmd.command("capture").description("Read marker + transcript, compute
|
|
|
1454
1478
|
let input = 0, output = 0, cacheRead = 0, cacheCreate = 0;
|
|
1455
1479
|
let minTs = null, maxTs = null;
|
|
1456
1480
|
try {
|
|
1457
|
-
const raw =
|
|
1481
|
+
const raw = readFileSync14(opts.transcript, "utf-8");
|
|
1458
1482
|
for (const line of raw.split("\n")) {
|
|
1459
1483
|
if (!line.trim()) continue;
|
|
1460
1484
|
let obj;
|
|
@@ -1505,9 +1529,9 @@ personaRunsCmd.command("capture").description("Read marker + transcript, compute
|
|
|
1505
1529
|
});
|
|
1506
1530
|
|
|
1507
1531
|
// src/commands/blog.ts
|
|
1508
|
-
import { Command as
|
|
1509
|
-
import { readFileSync as
|
|
1510
|
-
var blogCmd = new
|
|
1532
|
+
import { Command as Command20 } from "commander";
|
|
1533
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
1534
|
+
var blogCmd = new Command20("blog").description("Manage blog posts");
|
|
1511
1535
|
blogCmd.command("list <slug>").description("List blog posts for a pebble").option("--status <status>", "Filter by status (draft, review, scheduled, published, archived)").option("--tag <tag>", "Filter by tag").option("--page <page>", "Page number", "1").option("--per-page <perPage>", "Results per page", "20").action(async (slug, opts) => {
|
|
1512
1536
|
const params = {};
|
|
1513
1537
|
if (opts.status) params.status = opts.status;
|
|
@@ -1526,7 +1550,7 @@ blogCmd.command("get <slug> <idOrSlug>").description("Get a blog post by UUID or
|
|
|
1526
1550
|
blogCmd.command("create <slug> <title>").description("Create a blog post").requiredOption("--post-slug <postSlug>", "URL slug for the post").option("--blocks <blocks>", "Content blocks as JSON string").option("--file <path>", "Read content blocks from JSON file").option("--status <status>", "Initial status (draft, review, scheduled)", "draft").option("--scheduled-publish-at <iso>", "UTC ISO timestamp for scheduled publishing (required when --status scheduled)").option("--metadata <metadata>", "Post metadata as JSON string").option("--campaign-id <campaignId>", "Link to a marketing campaign").action(async (slug, title, opts) => {
|
|
1527
1551
|
let blocks = [];
|
|
1528
1552
|
if (opts.file) {
|
|
1529
|
-
blocks = JSON.parse(
|
|
1553
|
+
blocks = JSON.parse(readFileSync15(opts.file, "utf-8"));
|
|
1530
1554
|
} else if (opts.blocks) {
|
|
1531
1555
|
blocks = JSON.parse(opts.blocks);
|
|
1532
1556
|
}
|
|
@@ -1550,7 +1574,7 @@ blogCmd.command("update <slug> <id>").description("Update a blog post").option("
|
|
|
1550
1574
|
const body = {};
|
|
1551
1575
|
if (opts.title) body.title = opts.title;
|
|
1552
1576
|
if (opts.postSlug) body.slug = opts.postSlug;
|
|
1553
|
-
if (opts.file) body.blocks = JSON.parse(
|
|
1577
|
+
if (opts.file) body.blocks = JSON.parse(readFileSync15(opts.file, "utf-8"));
|
|
1554
1578
|
else if (opts.blocks) body.blocks = JSON.parse(opts.blocks);
|
|
1555
1579
|
if (opts.status) body.status = opts.status;
|
|
1556
1580
|
if (opts.scheduledPublishAt !== void 0)
|
|
@@ -1572,8 +1596,8 @@ blogCmd.command("delete <slug> <id>").description("Delete a blog post").action(a
|
|
|
1572
1596
|
});
|
|
1573
1597
|
|
|
1574
1598
|
// src/commands/api-keys.ts
|
|
1575
|
-
import { Command as
|
|
1576
|
-
var apiKeysCmd = new
|
|
1599
|
+
import { Command as Command21 } from "commander";
|
|
1600
|
+
var apiKeysCmd = new Command21("api-keys").description("Manage API keys for server-to-server access");
|
|
1577
1601
|
apiKeysCmd.command("list <slug>").description("List API keys for a pebble").action(async (slug) => {
|
|
1578
1602
|
const res = await apiRequest(`/pebbles/${slug}/api-keys`);
|
|
1579
1603
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
@@ -1615,7 +1639,7 @@ apiKeysCmd.command("delete <slug> <id>").description("Permanently delete an API
|
|
|
1615
1639
|
});
|
|
1616
1640
|
|
|
1617
1641
|
// src/commands/pebble/index.ts
|
|
1618
|
-
import { Command as
|
|
1642
|
+
import { Command as Command22 } from "commander";
|
|
1619
1643
|
|
|
1620
1644
|
// src/commands/pebble/provisioner.ts
|
|
1621
1645
|
async function runProvisioner(ctx, steps) {
|
|
@@ -2028,7 +2052,7 @@ Hand off: /odin:eng-manager bet:${bet.data.id}
|
|
|
2028
2052
|
}
|
|
2029
2053
|
|
|
2030
2054
|
// src/commands/pebble/index.ts
|
|
2031
|
-
var pebbleCmd = new
|
|
2055
|
+
var pebbleCmd = new Command22("pebble").description(
|
|
2032
2056
|
"Provision and initialize pebbles (eng-infra, run-once)"
|
|
2033
2057
|
);
|
|
2034
2058
|
pebbleCmd.command("new <name>").description("Provision a new pebble from pebble-template (day-one)").option("--run", "Hand off to eng-manager on the init bet").option("--dir <path>", "Parent dir to clone into").option("--dry-run", "Print the plan; mutate nothing").action(async (name, opts) => {
|
|
@@ -2049,7 +2073,7 @@ pebbleCmd.command("provision <provider> <slug>").description("Run one provider s
|
|
|
2049
2073
|
});
|
|
2050
2074
|
|
|
2051
2075
|
// src/commands/create/index.ts
|
|
2052
|
-
import { Command as
|
|
2076
|
+
import { Command as Command23 } from "commander";
|
|
2053
2077
|
|
|
2054
2078
|
// src/commands/create/topology.ts
|
|
2055
2079
|
var ENVS = ["prd", "stg", "dev"];
|
|
@@ -2514,22 +2538,22 @@ function assembleInputs(ctx) {
|
|
|
2514
2538
|
}
|
|
2515
2539
|
|
|
2516
2540
|
// src/commands/create/index.ts
|
|
2517
|
-
var createCmd = new
|
|
2541
|
+
var createCmd = new Command23("create").description(
|
|
2518
2542
|
"Create and provision a new project end to end"
|
|
2519
2543
|
);
|
|
2520
2544
|
createCmd.command("project [name]").description("Guided self-serve project + parallel-env provisioning").option("--dry-run", "Print the plan; mutate nothing").action(
|
|
2521
2545
|
async (name, opts) => process.exit(await runCreate(name, { dryRun: opts.dryRun }))
|
|
2522
2546
|
);
|
|
2523
|
-
var setupCmd = new
|
|
2547
|
+
var setupCmd = new Command23("setup").description("Alias for `create project`").arguments("[name]").option("--dry-run", "Print the plan; mutate nothing").action(
|
|
2524
2548
|
async (name, opts) => process.exit(await runCreate(name, { dryRun: opts.dryRun }))
|
|
2525
2549
|
);
|
|
2526
2550
|
|
|
2527
2551
|
// src/index.ts
|
|
2528
|
-
import { readFileSync as
|
|
2552
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
2529
2553
|
import { fileURLToPath } from "url";
|
|
2530
2554
|
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
2531
2555
|
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
2532
|
-
var pkg = JSON.parse(
|
|
2556
|
+
var pkg = JSON.parse(readFileSync16(resolve2(__dirname, "../package.json"), "utf-8"));
|
|
2533
2557
|
var GOLD = "\x1B[33m";
|
|
2534
2558
|
var DIM = "\x1B[2m";
|
|
2535
2559
|
var RESET = "\x1B[0m";
|
|
@@ -2547,7 +2571,7 @@ ${RESET}
|
|
|
2547
2571
|
${DIM}${cwd}${RESET}
|
|
2548
2572
|
`);
|
|
2549
2573
|
}
|
|
2550
|
-
var program = new
|
|
2574
|
+
var program = new Command24();
|
|
2551
2575
|
program.name("odin").description("CLI for Odin \u2014 the knowledge backbone for Pebble House").version(VERSION);
|
|
2552
2576
|
program.command("login").description("Authenticate with Odin via browser").option("--device", "Use the device-code flow (for headless or remote machines)").action(async (options) => {
|
|
2553
2577
|
printBanner();
|
|
@@ -2576,6 +2600,7 @@ program.addCommand(rulesCmd);
|
|
|
2576
2600
|
program.addCommand(briefsCmd);
|
|
2577
2601
|
program.addCommand(blueprintsCmd);
|
|
2578
2602
|
program.addCommand(betsCmd);
|
|
2603
|
+
program.addCommand(ticketsCmd);
|
|
2579
2604
|
program.addCommand(betCommentsCmd);
|
|
2580
2605
|
program.addCommand(tasksCmd);
|
|
2581
2606
|
program.addCommand(roadmapsCmd);
|