@pebblehouse/odin-cli 0.9.0 → 0.10.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/index.js +112 -4
- package/package.json +8 -3
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 Command13 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/auth/login.ts
|
|
7
7
|
import { createServer } from "http";
|
|
@@ -757,13 +757,120 @@ briefsCmd.command("versions <slug>").description("List version history for a peb
|
|
|
757
757
|
process.stdout.write(JSON.stringify(res) + "\n");
|
|
758
758
|
if (res.error) process.exit(1);
|
|
759
759
|
});
|
|
760
|
+
briefsCmd.command("generate [slug]").description("Generate/regenerate brief for a pebble (or all pebbles)").option("--secret <secret>", "Worker secret (defaults to ODIN_WORKER_SECRET env var)").action(async (slug, opts) => {
|
|
761
|
+
const secret = opts.secret ?? process.env.ODIN_WORKER_SECRET;
|
|
762
|
+
if (!secret) {
|
|
763
|
+
console.error("error: ODIN_WORKER_SECRET env var or --secret flag required");
|
|
764
|
+
process.exit(1);
|
|
765
|
+
}
|
|
766
|
+
const apiUrl = process.env.ODIN_API_URL ?? "https://odin.mu";
|
|
767
|
+
const url = slug ? `${apiUrl}/api/internal/briefs/generate?slug=${slug}` : `${apiUrl}/api/internal/briefs/generate`;
|
|
768
|
+
try {
|
|
769
|
+
const res = await fetch(url, {
|
|
770
|
+
method: "POST",
|
|
771
|
+
headers: { Authorization: `Bearer ${secret}` }
|
|
772
|
+
});
|
|
773
|
+
const body = await res.json();
|
|
774
|
+
if (!res.ok) {
|
|
775
|
+
console.error(`error: ${body.error ?? res.statusText}`);
|
|
776
|
+
process.exit(1);
|
|
777
|
+
}
|
|
778
|
+
process.stdout.write(JSON.stringify(body, null, 2) + "\n");
|
|
779
|
+
} catch (err) {
|
|
780
|
+
console.error(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
781
|
+
process.exit(1);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
760
784
|
|
|
761
|
-
// src/
|
|
785
|
+
// src/commands/blueprints.ts
|
|
786
|
+
import { Command as Command12 } from "commander";
|
|
762
787
|
import { readFileSync as readFileSync9 } from "fs";
|
|
788
|
+
var blueprintsCmd = new Command12("blueprints").description("Manage global blueprints");
|
|
789
|
+
blueprintsCmd.command("list").description("List blueprints").option("--tag <tag>", "Filter by tag").option("--status <status>", "Filter by status (default: active)").option("--all", "Include deprecated/experimental blueprints").action(async (opts) => {
|
|
790
|
+
const params = new URLSearchParams();
|
|
791
|
+
if (opts.tag) params.set("tag", opts.tag);
|
|
792
|
+
if (opts.all) params.set("status", "all");
|
|
793
|
+
else if (opts.status) params.set("status", opts.status);
|
|
794
|
+
const qs = params.toString();
|
|
795
|
+
const res = await apiRequest(`/blueprints${qs ? `?${qs}` : ""}`);
|
|
796
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
797
|
+
if (res.error) process.exit(1);
|
|
798
|
+
});
|
|
799
|
+
blueprintsCmd.command("get <id>").description("Get a blueprint by ID (includes assets)").action(async (id) => {
|
|
800
|
+
const res = await apiRequest(`/blueprints/${id}`);
|
|
801
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
802
|
+
if (res.error) process.exit(1);
|
|
803
|
+
});
|
|
804
|
+
blueprintsCmd.command("create <title>").description("Create a blueprint").option("--content <content>", "Blueprint content").option("--file <path>", "Read content from file").option("--tags <tags>", "Comma-separated tags").option("--status <status>", "Status (active|experimental)", "active").option("--source <source>", "Source", "manual").action(async (title, opts) => {
|
|
805
|
+
const content = opts.file ? readFileSync9(opts.file, "utf-8") : opts.content ?? "";
|
|
806
|
+
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()) : [];
|
|
807
|
+
const res = await apiRequest("/blueprints", {
|
|
808
|
+
method: "POST",
|
|
809
|
+
body: { title, content, tags, status: opts.status, source: opts.source }
|
|
810
|
+
});
|
|
811
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
812
|
+
if (res.error) process.exit(1);
|
|
813
|
+
});
|
|
814
|
+
blueprintsCmd.command("update <id>").description("Update a blueprint").option("--title <title>", "New title").option("--content <content>", "New content").option("--file <path>", "Read content from file").option("--tags <tags>", "Comma-separated tags (replaces all)").option("--status <status>", "New status (active|deprecated|experimental)").option("--source <source>", "Source").action(async (id, opts) => {
|
|
815
|
+
const body = {};
|
|
816
|
+
if (opts.title) body.title = opts.title;
|
|
817
|
+
if (opts.file) body.content = readFileSync9(opts.file, "utf-8");
|
|
818
|
+
else if (opts.content) body.content = opts.content;
|
|
819
|
+
if (opts.tags) body.tags = opts.tags.split(",").map((t) => t.trim());
|
|
820
|
+
if (opts.status) body.status = opts.status;
|
|
821
|
+
if (opts.source) body.source = opts.source;
|
|
822
|
+
const res = await apiRequest(`/blueprints/${id}`, {
|
|
823
|
+
method: "PUT",
|
|
824
|
+
body
|
|
825
|
+
});
|
|
826
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
827
|
+
if (res.error) process.exit(1);
|
|
828
|
+
});
|
|
829
|
+
blueprintsCmd.command("delete <id>").description("Delete a blueprint").action(async (id) => {
|
|
830
|
+
const res = await apiRequest(`/blueprints/${id}`, {
|
|
831
|
+
method: "DELETE"
|
|
832
|
+
});
|
|
833
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
834
|
+
if (res.error) process.exit(1);
|
|
835
|
+
});
|
|
836
|
+
blueprintsCmd.command("versions <id>").description("List version history for a blueprint").action(async (id) => {
|
|
837
|
+
const res = await apiRequest(`/blueprints/${id}/versions`);
|
|
838
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
839
|
+
if (res.error) process.exit(1);
|
|
840
|
+
});
|
|
841
|
+
blueprintsCmd.command("deprecate <id>").description("Deprecate a blueprint").action(async (id) => {
|
|
842
|
+
const res = await apiRequest(`/blueprints/${id}`, {
|
|
843
|
+
method: "PUT",
|
|
844
|
+
body: { status: "deprecated" }
|
|
845
|
+
});
|
|
846
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
847
|
+
if (res.error) process.exit(1);
|
|
848
|
+
});
|
|
849
|
+
blueprintsCmd.command("add-asset <id>").description("Add an asset reference to a blueprint").requiredOption("--title <title>", "Asset title").requiredOption("--url <url>", "Asset URL").option("--type <type>", "Asset type (screenshot|diagram|code-snippet|figma-link|github-link|raw-text|other)", "other").option("--description <description>", "Asset description").action(async (id, opts) => {
|
|
850
|
+
const res = await apiRequest(`/blueprints/${id}/assets`, {
|
|
851
|
+
method: "POST",
|
|
852
|
+
body: {
|
|
853
|
+
title: opts.title,
|
|
854
|
+
asset_url: opts.url,
|
|
855
|
+
type: opts.type,
|
|
856
|
+
description: opts.description ?? ""
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
860
|
+
if (res.error) process.exit(1);
|
|
861
|
+
});
|
|
862
|
+
blueprintsCmd.command("assets <id>").description("List assets for a blueprint").action(async (id) => {
|
|
863
|
+
const res = await apiRequest(`/blueprints/${id}/assets`);
|
|
864
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
865
|
+
if (res.error) process.exit(1);
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
// src/index.ts
|
|
869
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
763
870
|
import { fileURLToPath } from "url";
|
|
764
871
|
import { dirname as dirname2, resolve } from "path";
|
|
765
872
|
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
766
|
-
var pkg = JSON.parse(
|
|
873
|
+
var pkg = JSON.parse(readFileSync10(resolve(__dirname, "../package.json"), "utf-8"));
|
|
767
874
|
var GOLD = "\x1B[33m";
|
|
768
875
|
var DIM = "\x1B[2m";
|
|
769
876
|
var RESET = "\x1B[0m";
|
|
@@ -781,7 +888,7 @@ ${RESET}
|
|
|
781
888
|
${DIM}${cwd}${RESET}
|
|
782
889
|
`);
|
|
783
890
|
}
|
|
784
|
-
var program = new
|
|
891
|
+
var program = new Command13();
|
|
785
892
|
program.name("odin").description("CLI for Odin \u2014 the knowledge backbone for Pebble House").version(VERSION);
|
|
786
893
|
program.command("login").description("Authenticate with Odin via browser").action(async () => {
|
|
787
894
|
printBanner();
|
|
@@ -808,6 +915,7 @@ program.addCommand(versionsCmd);
|
|
|
808
915
|
program.addCommand(guidelinesCmd);
|
|
809
916
|
program.addCommand(rulesCmd);
|
|
810
917
|
program.addCommand(briefsCmd);
|
|
918
|
+
program.addCommand(blueprintsCmd);
|
|
811
919
|
process.on("exit", () => {
|
|
812
920
|
process.stderr.write("\n\n\n\n\n");
|
|
813
921
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pebblehouse/odin-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for Odin — the knowledge backbone for Pebble House",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsup",
|
|
14
|
-
"dev": "tsup --watch"
|
|
14
|
+
"dev": "tsup --watch",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
"test:coverage": "vitest run --coverage"
|
|
15
18
|
},
|
|
16
19
|
"keywords": [
|
|
17
20
|
"odin",
|
|
@@ -36,7 +39,9 @@
|
|
|
36
39
|
"open": "^10.0.0"
|
|
37
40
|
},
|
|
38
41
|
"devDependencies": {
|
|
42
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
39
43
|
"tsup": "^8.0.0",
|
|
40
|
-
"typescript": "^5.3.3"
|
|
44
|
+
"typescript": "^5.3.3",
|
|
45
|
+
"vitest": "^4.1.2"
|
|
41
46
|
}
|
|
42
47
|
}
|