spovishun-skills 1.2.2 → 1.2.3

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
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.3] — 2026-06-05
9
+
10
+ Patch release. Fixes a contract drift between `scripts/notion/get-task.js` and the
11
+ `notion-task-to-code` skill surfaced during Spovishun dogfooding: the skill documented
12
+ a `<N-or-pageId>` shorthand that the script never actually supported.
13
+
14
+ ### Fixed
15
+
16
+ - **`scripts/notion/get-task.js`** now accepts a bare numeric arg (`get-task.js 93`) and
17
+ normalizes it to `<projectPrefix()>-93` before resolving via the board query. Previously
18
+ a bare number fell through to `toDashed()` and Notion rejected it with
19
+ `path.page_id should be a valid uuid`.
20
+ - **`scripts/notion/get-task.js`** gains the `text` output format (`--format=text`), matching
21
+ the parity already offered by `get-board.js` and `list-epics.js`. Default remains `json`.
22
+ - **`skills/notion-task-to-code/SKILL.md`** Step 1d now spells out the three accepted forms
23
+ (`<prefix>-N` / `N` / `pageId`) and the available formats. The misleading `<N-or-pageId>`
24
+ shorthand is gone.
25
+
26
+ ### Changed
27
+
28
+ - **`scripts/notion/get-task.js`** is now a dual CLI + module: it exports
29
+ `normalizeTaskArg`, `renderText`, `renderMd`, `resolvePageId`, and `VALID_FORMATS` for
30
+ unit testing while keeping its `main()` entrypoint behind a `require.main === module`
31
+ guard.
32
+
33
+ ### Added
34
+
35
+ - **`test/scripts-notion-get-task.test.js`** — unit coverage for `normalizeTaskArg`
36
+ (bare-number rewrite, prefixed pass-through, pageId untouched, config-derived prefix),
37
+ for the regex contract with `lib/project-prefix.js`, for the new `text` format, and for
38
+ `renderText` body shape (with and without optional fields).
39
+
40
+ ### Manifests bumped
41
+
42
+ - `notion-task-to-code` 1.0.1 → 1.0.2
43
+ - `scripts/notion/package.json` 1.0.0 → 1.0.1
44
+
8
45
  ## [1.2.2] — 2026-06-04
9
46
 
10
47
  Patch release with two breaking-but-necessary changes:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spovishun-skills",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Portable Claude Code skills, agents, hooks and rules — bootstrapped from the Spovishun project. Installs into Claude Code, Codex, Windsurf and Cursor via per-assistant adapters.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -10,7 +10,7 @@ const { toDashed } = require('./lib/page-id');
10
10
  const { resolveRelationIds, extractRelationIds } = require('./lib/resolve-relations');
11
11
  const { taskIdRegex, projectPrefix } = require('./lib/project-prefix');
12
12
 
13
- const VALID_FORMATS = ['json', 'md'];
13
+ const VALID_FORMATS = ['json', 'md', 'text'];
14
14
 
15
15
  function parseArgs(argv) {
16
16
  let format = 'json';
@@ -23,7 +23,18 @@ function parseArgs(argv) {
23
23
  return { format, arg: positional[0] };
24
24
  }
25
25
 
26
- async function resolvePageId(token, arg) {
26
+ // A bare task number ("93") is shorthand for "<prefix>-93". Without this
27
+ // normalization the arg would fall through to toDashed() in resolvePageId
28
+ // and be sent as an invalid Notion page_id, producing
29
+ // "path.page_id should be a valid uuid".
30
+ function normalizeTaskArg(arg) {
31
+ if (typeof arg !== 'string') return arg;
32
+ if (/^\d+$/.test(arg)) return `${projectPrefix()}-${arg}`;
33
+ return arg;
34
+ }
35
+
36
+ async function resolvePageId(token, rawArg) {
37
+ const arg = normalizeTaskArg(rawArg);
27
38
  if (taskIdRegex().test(arg)) {
28
39
  const result = await http.post(token, `/v1/databases/${constants.DATABASE_ID}/query`, {
29
40
  filter: { property: 'Name', title: { contains: arg } },
@@ -56,6 +67,22 @@ function renderMd(task) {
56
67
  return parts.join('\n\n');
57
68
  }
58
69
 
70
+ function renderText(task) {
71
+ const lines = [task.title];
72
+ const meta = [task.status, task.priority, task.branch].filter(Boolean).join(' | ');
73
+ if (meta) lines.push(meta);
74
+ if (task.epic) lines.push(`Epic: ${task.epic.title ?? task.epic.id}`);
75
+ if (task.blockedBy && task.blockedBy.length > 0) {
76
+ const list = task.blockedBy.map(b => ` - ${b.title ?? b.id}`).join('\n');
77
+ lines.push(`Blocked by:\n${list}`);
78
+ }
79
+ if (task.content) {
80
+ lines.push('');
81
+ lines.push(task.content);
82
+ }
83
+ return lines.join('\n');
84
+ }
85
+
59
86
  async function main() {
60
87
  const token = loadToken();
61
88
  if (!token) {
@@ -71,7 +98,8 @@ async function main() {
71
98
  const { format, arg } = parseArgs(process.argv.slice(2));
72
99
 
73
100
  if (!arg) {
74
- process.stderr.write(`Usage: get-task.js <pageId | ${projectPrefix()}-N> [--format=json|md]\n`);
101
+ const p = projectPrefix();
102
+ process.stderr.write(`Usage: get-task.js <${p}-N | N | pageId> [--format=json|md|text]\n`);
75
103
  process.exit(1);
76
104
  }
77
105
 
@@ -114,12 +142,20 @@ async function main() {
114
142
 
115
143
  if (format === 'md') {
116
144
  process.stdout.write(renderMd(task) + '\n');
145
+ } else if (format === 'text') {
146
+ process.stdout.write(renderText(task) + '\n');
117
147
  } else {
118
148
  process.stdout.write(JSON.stringify(task) + '\n');
119
149
  }
120
150
  }
121
151
 
122
- main().catch(err => {
123
- process.stderr.write(`Error: ${err.message}\n`);
124
- process.exit(1);
125
- });
152
+ // Exported for unit tests. The CLI entry runs main() unconditionally below;
153
+ // the require.main guard keeps tests from triggering it.
154
+ module.exports = { normalizeTaskArg, renderMd, renderText, resolvePageId, VALID_FORMATS };
155
+
156
+ if (require.main === module) {
157
+ main().catch(err => {
158
+ process.stderr.write(`Error: ${err.message}\n`);
159
+ process.exit(1);
160
+ });
161
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spovishun-skills-notion-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "private": true,
5
5
  "type": "commonjs",
6
6
  "description": "Notion CLI helpers shipped by the spovishun-skills plugin. Installed into consumer projects under .claude/scripts/notion/. Skill bodies invoke these as `node .claude/scripts/notion/<script>.js`."
@@ -17,9 +17,13 @@ git rev-parse --abbrev-ref HEAD
17
17
 
18
18
  **1d.** Otherwise (standalone invocation or no cache) → fetch from Notion:
19
19
  ```
20
- node .claude/scripts/notion/get-task.js <N-or-pageId>
20
+ node .claude/scripts/notion/get-task.js <{{PROJECT_PREFIX}}-N | N | pageId> [--format=json|md|text]
21
21
  ```
22
- Accepts `{{PROJECT_PREFIX}}-19`, bare `19`, or a 32-char compact pageId.
22
+ - `{{PROJECT_PREFIX}}-19` fully-qualified task id (board lookup by name).
23
+ - `19` — bare number; resolves to `{{PROJECT_PREFIX}}-19` automatically.
24
+ - 32-char compact (or dashed) Notion `pageId` — direct fetch.
25
+
26
+ Default `--format=json`. Use `md` for a rendered markdown card or `text` for a plain human-readable summary.
23
27
 
24
28
  ### Step 2: Fetch CLAUDE.md (targeted)
25
29
  ```
@@ -1,5 +1,5 @@
1
1
  id: notion-task-to-code
2
- version: 1.0.1
2
+ version: 1.0.2
3
3
  category: stack-specific
4
4
  requires:
5
5
  - notion