@homespunapps/cli 1.0.1 → 1.4.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.
@@ -20,46 +20,10 @@
20
20
  // an agent on a too-old CLI must be able to read the upgrade instructions
21
21
  // even before it has registered (or before its key was minted).
22
22
  import { assertKnownFlags } from "../argv.js";
23
+ import { specFor } from "../help-catalog.js";
23
24
  import { resolveRelayUrl } from "../config.js";
24
25
  import { fail } from "../output.js";
25
- const NO_FLAGS = [];
26
- const NO_BOOLS = [];
27
- const VERSION_BOOLS = ["plain"];
28
26
  import { VERSION } from "../version.js";
29
- export const skillHelp = `homespun skill — fetch the relay's SKILL.md (or its version)
30
-
31
- Usage:
32
- homespun skill show Print the full skill to stdout.
33
- homespun skill version [--plain] Print just the relay's skill version.
34
-
35
- The skill is auto-updating: the relay's deployed image owns the version,
36
- so this is always the skill that matches the relay you are talking to.
37
-
38
- Unauthenticated — no API key needed. An agent can call either form
39
- before 'homespun agent register' to bootstrap or refresh its local skill copy.
40
-
41
- Verbs:
42
- show Fetch GET /skills/homespun/SKILL.md and write the raw
43
- markdown to stdout. Pipe to your local skill path:
44
- homespun skill show > ~/.claude/skills/homespun/SKILL.md
45
- version Fetch GET /skills/homespun/SKILL.md/version and print
46
- the relay's skill version. Default output is the
47
- JSON envelope; --plain prints just the version
48
- string so an agent can compare it inline in shell.
49
-
50
- Options:
51
- --plain (with 'version' only) print the bare version
52
- string on stdout, no JSON envelope. Useful inside
53
- a shell pipeline: \`if [ "$(homespun skill version
54
- --plain)" != "$LOCAL" ]; then ...\`.
55
- --url <url> Relay base URL (overrides HOMESPUN_URL).
56
- -h, --help Show this help.
57
-
58
- Output (stdout):
59
- (bare) Raw markdown, as served by the relay.
60
- version { "version": "1.0.0" } — or '1.0.0\\n' with --plain.
61
-
62
- Errors (stderr): { "error": { "code", "message" } } and non-zero exit.`;
63
27
  // Shared fetch with the consistent x-homespun-cli-version header (the skill
64
28
  // routes are exempt from the version-skew middleware, but sending it lets
65
29
  // access logs see which CLI versions are reading the skill).
@@ -84,7 +48,7 @@ async function failOnNon2xx(res, target) {
84
48
  }
85
49
  // `homespun skill show` — print the full skill.
86
50
  async function runSkillFetch(args) {
87
- assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "homespun skill show");
51
+ assertKnownFlags(args, ...specFor("skill", "show"));
88
52
  const url = resolveRelayUrl(args);
89
53
  const target = url + "/skills/homespun/SKILL.md";
90
54
  const res = await fetchOrFail(target);
@@ -99,7 +63,7 @@ async function runSkillFetch(args) {
99
63
  }
100
64
  // `homespun skill version [--plain]` — print just the version.
101
65
  async function runSkillVersion(args) {
102
- assertKnownFlags(args, NO_FLAGS, VERSION_BOOLS, "homespun skill version");
66
+ assertKnownFlags(args, ...specFor("skill", "version"));
103
67
  const url = resolveRelayUrl(args);
104
68
  const target = url + "/skills/homespun/SKILL.md/version";
105
69
  const res = await fetchOrFail(target);
@@ -19,54 +19,9 @@
19
19
  // when app gains first-class humans, this may move to per-human.
20
20
  import { readFileSync } from "node:fs";
21
21
  import { assertKnownFlags } from "../argv.js";
22
+ import { specFor } from "../help-catalog.js";
22
23
  import { makeClient } from "../config.js";
23
24
  import { printJson, fail, failFromError } from "../output.js";
24
- const NO_FLAGS = [];
25
- const NO_BOOLS = [];
26
- const SET_FLAGS = ["file"];
27
- const CLEAR_BOOLS = ["yes"];
28
- export const tasteHelp = `homespun taste — read / write / clear YOUR agent's UI taste notes
29
-
30
- Taste notes are a small markdown attachment storing presentation preferences your
31
- agent has picked up from human feedback ("denser table", "no rounded corners",
32
- "use a dark header"). Read them before generating an app template so prior
33
- feedback shapes the output; rewrite them whenever the human gives new
34
- presentation feedback. Keep entries about UI/presentation taste only — not
35
- project context, todos, or homespun state.
36
-
37
- Usage:
38
- homespun taste <subcommand> [options]
39
-
40
- Subcommands:
41
- get Print the current notes attachment:
42
- { taste: string|null, updated_at: string|null, bytes: number }.
43
- taste is null and bytes is 0 when notes have never been written.
44
-
45
- set Whole-attachment replace. Source the markdown via --file <path>,
46
- --file - (read stdin), or by piping into 'homespun taste set' with
47
- no flag. The relay rejects empty/whitespace-only payloads and
48
- caps the attachment at MAX_TASTE_BYTES (utf8). To clear the notes,
49
- use 'homespun taste clear', not 'set' with an empty body.
50
-
51
- clear Delete the notes. Requires --yes (it is destructive). Prints
52
- { cleared: true }.
53
-
54
- Options:
55
- --file <path|-> Source for 'set' — a file path, or '-' to read stdin
56
- explicitly. Omit to fall back to piped stdin.
57
- --yes Confirm 'clear'.
58
- --url <url> Relay base URL (overrides HOMESPUN_URL).
59
- --api-key <key> Agent API key (overrides HOMESPUN_API_KEY).
60
- -h, --help Show this help.
61
-
62
- Examples:
63
- homespun taste get
64
- homespun taste set --file ./taste.md
65
- homespun taste set --file - # explicit stdin
66
- echo "- denser layout" | homespun taste set
67
- homespun taste clear --yes
68
-
69
- Output: stdout is machine-readable JSON.`;
70
25
  // Drain process.stdin to a utf8 string. The caller is responsible for
71
26
  // deciding that stdin should be read (e.g. an explicit `--file -`, or a
72
27
  // non-TTY stdin where data is actually piped). In a TTY this would block
@@ -79,7 +34,7 @@ async function readStdin() {
79
34
  return Buffer.concat(chunks).toString("utf8");
80
35
  }
81
36
  async function runTasteGet(args) {
82
- assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "homespun taste get");
37
+ assertKnownFlags(args, ...specFor("taste", "get"));
83
38
  const client = makeClient(args);
84
39
  try {
85
40
  const info = await client.getTaste();
@@ -90,7 +45,7 @@ async function runTasteGet(args) {
90
45
  }
91
46
  }
92
47
  async function runTasteSet(args) {
93
- assertKnownFlags(args, SET_FLAGS, NO_BOOLS, "homespun taste set");
48
+ assertKnownFlags(args, ...specFor("taste", "set"));
94
49
  const filePath = args.flags.get("file");
95
50
  // Source the attachment deterministically — no isTTY-flag fusing, because
96
51
  // `!process.stdin.isTTY` is true under every non-interactive caller
@@ -131,7 +86,7 @@ async function runTasteSet(args) {
131
86
  }
132
87
  }
133
88
  async function runTasteClear(args) {
134
- assertKnownFlags(args, NO_FLAGS, CLEAR_BOOLS, "homespun taste clear");
89
+ assertKnownFlags(args, ...specFor("taste", "clear"));
135
90
  if (!args.bools.has("yes")) {
136
91
  fail("'homespun taste clear' deletes YOUR agent's taste notes — it is destructive. Pass --yes to confirm.", "confirmation_required");
137
92
  }