@zhuk/spego 0.6.2 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.0] - 2026-05-22
4
+
5
+ ### Added
6
+ - Combined OpenSpec + spego workflow skills: `change-brainstorm`, `change-review`, `change-verify-report`, and `change-retro`.
7
+ - README guidance for before/during/after OpenSpec change lanes with spego persistence checkpoints.
8
+
9
+ ## [0.7.0] - 2026-05-14
10
+
11
+ ### Changed
12
+ - **CLI output modes**: every command now emits pretty human-friendly output by default and JSON when the global `--json` flag is supplied. Human output uses bordered boxes (`╭─ ─╮`), aligned tables, single-emoji section headers (`📦 📄 🛠️ 🧭 📚 ✅`), and `────` dividers. Errors render as `⚠️ [CODE] message` in human mode and as the existing `{ error: { code, message, details } }` envelope in JSON mode.
13
+ - **`spego commands` and `spego workflows` default-mode flip**: these commands used to print JSON unconditionally; they now print human output by default. Agents and scripts that pipe their stdout MUST pass `--json` to keep getting JSON.
14
+ - **`spego regenerate` → `spego skills`**: renamed for clarity. `spego regenerate` remains as a hidden alias for one minor release with a deprecation warning. Running `spego skills` also cleans up any legacy `spego-regenerate` generated paths.
15
+
16
+ ### Deprecated
17
+ - **`spego view --format <fmt>`**: superseded by the global `--json` flag. Continues to work for one minor release; emits a single `deprecated:` warning line to stderr in human mode. Will be removed in the next minor release.
18
+ - **`spego regenerate`**: renamed to `spego skills`. The hidden alias continues to work for one minor release and emits a deprecation warning in human mode. Will be removed in the next minor release.
19
+
3
20
  ## [0.6.2] - 2026-05-14
4
21
 
5
22
  ### Fixed
package/README.md CHANGED
@@ -22,14 +22,25 @@ spego init --agents claude --demo false
22
22
  | `spego delete --id <uuid>` | Soft-delete (preserves history) |
23
23
  | `spego list` | List artifacts |
24
24
  | `spego view` | Export bundle as markdown or JSON |
25
- | `spego commands` | List command metadata (JSON) |
26
- | `spego workflows` | List workflow skills metadata (JSON) |
27
- | `spego regenerate` | Regenerate agent skill files |
25
+ | `spego commands` | List command metadata |
26
+ | `spego workflows` | List workflow skills metadata |
27
+ | `spego skills` | Regenerate agent skill files |
28
28
  | `spego epics` | List delivery epics |
29
29
  | `spego tasks --change <name>` | List tasks for a change |
30
30
  | `spego index rebuild` | Rebuild SQLite index from files |
31
31
 
32
- All commands accept `--json` for structured output and `--cwd <dir>` to set the project root.
32
+ All commands accept `--cwd <dir>` to set the project root.
33
+
34
+ ### Output modes
35
+
36
+ Every spego command speaks two output modes:
37
+
38
+ - **Human (default)** — pretty, scannable output for terminals. Section headers use a single emoji prefix (`📦 📄 🛠️ 🧭 📚 ✅`), summaries render as bordered boxes (`╭─ … ─╮`), lists render as aligned tables, and `view` separates artifacts with `────` dividers. Errors print as `⚠️ [CODE] message` to stderr.
39
+ - **JSON (opt-in)** — pass the global `--json` flag to get deterministic, decoration-free JSON on stdout. Errors come back as `{ "error": { "code", "message", "details" } }` on stderr.
40
+
41
+ Agents calling spego MUST pass `--json` so they get parseable output. Humans normally do not.
42
+
43
+ The legacy `spego view --format markdown|json` flag is **deprecated** and will be removed in the next minor release. Use the global `--json` flag instead. The old flag still works during the deprecation window and prints a single `deprecated:` warning line to stderr.
33
44
 
34
45
  ## Architecture
35
46
 
@@ -61,6 +72,21 @@ deliveryAdapter:
61
72
  options: {}
62
73
  ```
63
74
 
75
+ ## OpenSpec Delivery View
76
+
77
+ The default delivery adapter is OpenSpec. `spego epics` exposes active OpenSpec changes as delivery epics, and `spego tasks --change <name>` exposes checklist items from the change's `tasks.md`.
78
+
79
+ The adapter is read-only. It observes OpenSpec state but does not create, continue, apply, verify, sync, or archive OpenSpec changes.
80
+
81
+ | Source | spego view |
82
+ |--------|------------|
83
+ | `openspec/changes/<name>/proposal.md` | Epic title |
84
+ | `openspec/changes/<name>/tasks.md` | Task summaries |
85
+ | `openspec status --change <name> --json` | Preferred status source |
86
+ | Filesystem parsing | Fallback when the OpenSpec CLI is unavailable |
87
+
88
+ Archived changes under `openspec/changes/archive/` are excluded. A change with no `tasks.md` is reported as `planning-incomplete`.
89
+
64
90
  ## Generated Files
65
91
 
66
92
  For Claude agent targets, `spego init` generates:
@@ -68,7 +94,7 @@ For Claude agent targets, `spego init` generates:
68
94
  - `.claude/skills/spego-<command>/SKILL.md` — skill definitions following Claude Code conventions
69
95
  - `.claude/commands/spego/` — slash command wrappers
70
96
 
71
- Run `spego regenerate` to update generated files without reinitializing the workspace.
97
+ Run `spego skills` to update generated files without reinitializing the workspace.
72
98
 
73
99
  ## Workflow Skills
74
100
 
@@ -125,6 +151,42 @@ Use when you have a focused problem and want maximum idea throughput without per
125
151
  | One voice, fast iteration | `brainstorm-deep` |
126
152
  | Multiple viewpoints, stress-test ideas | `brainstorm-party` |
127
153
 
154
+ ### Combined OpenSpec + spego workflows
155
+
156
+ OpenSpec prompts and spego workflow skills are separate surfaces:
157
+
158
+ - OPSX/OpenSpec prompts live under `.claude/commands/opsx/` and `.claude/skills/openspec-*/`.
159
+ - spego-generated commands and workflow skills live under `.claude/commands/spego/` and `.claude/skills/spego-*/`.
160
+
161
+ OpenSpec owns change execution and lifecycle state: proposal, design, specs, tasks, apply, verify, sync, and archive. spego owns durable product-thinking artifacts: `brainstorm`, `qa`, `risk`, and `retro`. The OpenSpec delivery adapter exposed through `spego epics` and `spego tasks` is read-only.
162
+
163
+ Use combined workflows when an OpenSpec change needs durable thinking around it:
164
+
165
+ | Lane | OpenSpec action | spego action |
166
+ |------|-----------------|--------------|
167
+ | Before implementation | Create or continue a change with OPSX/OpenSpec, then read `proposal.md`, `design.md`, specs, and `tasks.md` | `spego-change-brainstorm` creates a `brainstorm` artifact |
168
+ | During implementation | Keep task state and artifact mutations in OPSX/OpenSpec | `spego-change-review` creates `qa` or `risk` findings |
169
+ | Before archive | Run OPSX/OpenSpec verification | `spego-change-verify-report` creates a `qa` verification report |
170
+ | After completion | Archive or complete the OpenSpec change | `spego-change-retro` creates a `retro` artifact |
171
+
172
+ Example read-only context commands:
173
+
174
+ ```sh
175
+ spego epics --json
176
+ spego tasks --change <change-name> --json
177
+ ```
178
+
179
+ Example spego persistence checkpoints:
180
+
181
+ ```sh
182
+ spego --json create --type brainstorm --title "<change-name> brainstorm" --body "<brainstorm output>"
183
+ spego --json create --type qa --title "<change-name> review" --body "<quality findings>"
184
+ spego --json create --type risk --title "<change-name> risks" --body "<risk findings>"
185
+ spego --json create --type retro --title "<change-name> retro" --body "<retrospective>"
186
+ ```
187
+
188
+ If a combined workflow discovers that OpenSpec artifacts need to change, use the matching OPSX/OpenSpec command. Do not mutate OpenSpec lifecycle state through spego.
189
+
128
190
  ### elicit
129
191
 
130
192
  Iterative refinement of an existing artifact using named methods (clarify, sharpen, generalize, specialize, stress-test, contextualize, simplify, formalize). A single Refiner persona proposes changes, confirms with the user, and applies via `spego update --expected-revision`. Maximum 5 cycles per session. Outputs a `qa` summary and in-place updates of the source artifact.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Pretty-rendering primitives for the spego CLI human output mode.
3
+ *
4
+ * All functions are pure: string in, string out. They MUST NOT read
5
+ * `process.env`, MUST NOT detect TTY, and MUST NOT emit ANSI color codes.
6
+ * Output is plain text plus a small fixed set of Unicode box-drawing and
7
+ * arrow characters so it stays scannable, copy-pasteable, and stable across
8
+ * terminals.
9
+ */
10
+ /** Truncate `value` to fit within `width` characters, appending `…` when cut. */
11
+ export declare function truncate(value: string, width: number): string;
12
+ /** Right-pad `value` with spaces to `width` characters. Strings longer than `width` are returned unchanged. */
13
+ export declare function padRight(value: string, width: number): string;
14
+ /**
15
+ * Render a bordered key/value summary box using rounded box-drawing characters.
16
+ *
17
+ * ```
18
+ * ╭─ Workspace ─────────────────────────╮
19
+ * │ root /tmp/proj │
20
+ * │ agents claude │
21
+ * ╰─────────────────────────────────────╯
22
+ * ```
23
+ */
24
+ export declare function renderBox(title: string, rows: Array<[string, string]>): string;
25
+ /**
26
+ * Render an aligned table with a header row separated from data rows by `─`.
27
+ *
28
+ * ```
29
+ * type/slug rev title
30
+ * ───────────── ─── ──────────────
31
+ * prd/test-prd 1 Test PRD
32
+ * ```
33
+ *
34
+ * `opts.maxWidth` caps each column width and truncates longer cells with `…`
35
+ * (default 60). An empty `rows` array still renders the header and divider
36
+ * so callers can prepend a "no rows" hint above if they choose.
37
+ */
38
+ export declare function renderTable(columns: string[], rows: string[][], opts?: {
39
+ maxWidth?: number;
40
+ }): string;
41
+ /** Render a single-line section header prefixed by an emoji. */
42
+ export declare function renderHeader(emoji: string, label: string): string;
43
+ /** Render a `─` divider of the given width (default 60). */
44
+ export declare function renderDivider(width?: number): string;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Pretty-rendering primitives for the spego CLI human output mode.
3
+ *
4
+ * All functions are pure: string in, string out. They MUST NOT read
5
+ * `process.env`, MUST NOT detect TTY, and MUST NOT emit ANSI color codes.
6
+ * Output is plain text plus a small fixed set of Unicode box-drawing and
7
+ * arrow characters so it stays scannable, copy-pasteable, and stable across
8
+ * terminals.
9
+ */
10
+ const DEFAULT_TABLE_MAX_WIDTH = 60;
11
+ /** Truncate `value` to fit within `width` characters, appending `…` when cut. */
12
+ export function truncate(value, width) {
13
+ if (width <= 0)
14
+ return '';
15
+ if (value.length <= width)
16
+ return value;
17
+ if (width === 1)
18
+ return '…';
19
+ return value.slice(0, width - 1) + '…';
20
+ }
21
+ /** Right-pad `value` with spaces to `width` characters. Strings longer than `width` are returned unchanged. */
22
+ export function padRight(value, width) {
23
+ if (value.length >= width)
24
+ return value;
25
+ return value + ' '.repeat(width - value.length);
26
+ }
27
+ /**
28
+ * Render a bordered key/value summary box using rounded box-drawing characters.
29
+ *
30
+ * ```
31
+ * ╭─ Workspace ─────────────────────────╮
32
+ * │ root /tmp/proj │
33
+ * │ agents claude │
34
+ * ╰─────────────────────────────────────╯
35
+ * ```
36
+ */
37
+ export function renderBox(title, rows) {
38
+ const keyWidth = rows.reduce((m, [k]) => Math.max(m, k.length), 0);
39
+ const valueWidth = rows.reduce((m, [, v]) => Math.max(m, v.length), 0);
40
+ // Inner content width: key + 2 spaces + value
41
+ const contentWidth = Math.max(keyWidth + 2 + valueWidth, title.length + 4);
42
+ const innerWidth = contentWidth + 2; // 1 space padding on each side
43
+ // Title row: `╭─ <title> <N×─>╮`. Body row width is `contentWidth + 4`
44
+ // (`│ ` + content + ` │`); title row width is `5 + title.length + N`,
45
+ // so N = contentWidth - title.length - 1 to keep both rows equal.
46
+ const titleLine = `╭─ ${title} ${'─'.repeat(Math.max(0, contentWidth - title.length - 1))}╮`;
47
+ const bottom = `╰${'─'.repeat(innerWidth)}╯`;
48
+ const body = rows
49
+ .map(([k, v]) => {
50
+ const line = `${padRight(k, keyWidth)} ${v}`;
51
+ return `│ ${padRight(line, contentWidth)} │`;
52
+ })
53
+ .join('\n');
54
+ return rows.length === 0 ? `${titleLine}\n${bottom}` : `${titleLine}\n${body}\n${bottom}`;
55
+ }
56
+ /**
57
+ * Render an aligned table with a header row separated from data rows by `─`.
58
+ *
59
+ * ```
60
+ * type/slug rev title
61
+ * ───────────── ─── ──────────────
62
+ * prd/test-prd 1 Test PRD
63
+ * ```
64
+ *
65
+ * `opts.maxWidth` caps each column width and truncates longer cells with `…`
66
+ * (default 60). An empty `rows` array still renders the header and divider
67
+ * so callers can prepend a "no rows" hint above if they choose.
68
+ */
69
+ export function renderTable(columns, rows, opts = {}) {
70
+ const maxWidth = opts.maxWidth ?? DEFAULT_TABLE_MAX_WIDTH;
71
+ const widths = columns.map((col, i) => {
72
+ const dataMax = rows.reduce((m, r) => Math.max(m, (r[i] ?? '').length), 0);
73
+ const target = Math.max(col.length, dataMax);
74
+ return Math.min(target, maxWidth);
75
+ });
76
+ const formatRow = (cells) => widths.map((w, i) => padRight(truncate(cells[i] ?? '', w), w)).join(' ').trimEnd();
77
+ const header = formatRow(columns);
78
+ const divider = widths.map((w) => '─'.repeat(w)).join(' ').trimEnd();
79
+ const body = rows.map(formatRow).join('\n');
80
+ return rows.length === 0 ? `${header}\n${divider}` : `${header}\n${divider}\n${body}`;
81
+ }
82
+ /** Render a single-line section header prefixed by an emoji. */
83
+ export function renderHeader(emoji, label) {
84
+ return `${emoji} ${label}`;
85
+ }
86
+ /** Render a `─` divider of the given width (default 60). */
87
+ export function renderDivider(width = 60) {
88
+ return '─'.repeat(Math.max(1, width));
89
+ }
90
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/cli/render.ts"],"names":[],"mappings":"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"}