felenova-backlog 0.1.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.
Files changed (147) hide show
  1. package/README.md +58 -0
  2. package/bin/backlog.js +2 -0
  3. package/dist/_core/criteria.d.ts +13 -0
  4. package/dist/_core/criteria.js +44 -0
  5. package/dist/_core/criteria.js.map +1 -0
  6. package/dist/_core/errors.d.ts +53 -0
  7. package/dist/_core/errors.js +91 -0
  8. package/dist/_core/errors.js.map +1 -0
  9. package/dist/_core/index.d.ts +24 -0
  10. package/dist/_core/index.js +27 -0
  11. package/dist/_core/index.js.map +1 -0
  12. package/dist/_core/loop.d.ts +73 -0
  13. package/dist/_core/loop.js +46 -0
  14. package/dist/_core/loop.js.map +1 -0
  15. package/dist/_core/markdown/items.d.ts +35 -0
  16. package/dist/_core/markdown/items.js +256 -0
  17. package/dist/_core/markdown/items.js.map +1 -0
  18. package/dist/_core/markdown/matrix.d.ts +20 -0
  19. package/dist/_core/markdown/matrix.js +147 -0
  20. package/dist/_core/markdown/matrix.js.map +1 -0
  21. package/dist/_core/markdown/track.d.ts +71 -0
  22. package/dist/_core/markdown/track.js +79 -0
  23. package/dist/_core/markdown/track.js.map +1 -0
  24. package/dist/_core/matrix-status.d.ts +9 -0
  25. package/dist/_core/matrix-status.js +31 -0
  26. package/dist/_core/matrix-status.js.map +1 -0
  27. package/dist/_core/matrix.d.ts +46 -0
  28. package/dist/_core/matrix.js +0 -0
  29. package/dist/_core/matrix.js.map +1 -0
  30. package/dist/_core/permissions.d.ts +14 -0
  31. package/dist/_core/permissions.js +87 -0
  32. package/dist/_core/permissions.js.map +1 -0
  33. package/dist/_core/promote.d.ts +20 -0
  34. package/dist/_core/promote.js +47 -0
  35. package/dist/_core/promote.js.map +1 -0
  36. package/dist/_core/ready.d.ts +8 -0
  37. package/dist/_core/ready.js +22 -0
  38. package/dist/_core/ready.js.map +1 -0
  39. package/dist/_core/review.d.ts +49 -0
  40. package/dist/_core/review.js +137 -0
  41. package/dist/_core/review.js.map +1 -0
  42. package/dist/_core/schema.d.ts +636 -0
  43. package/dist/_core/schema.js +304 -0
  44. package/dist/_core/schema.js.map +1 -0
  45. package/dist/_core/ship.d.ts +23 -0
  46. package/dist/_core/ship.js +31 -0
  47. package/dist/_core/ship.js.map +1 -0
  48. package/dist/_core/spec-diff.d.ts +19 -0
  49. package/dist/_core/spec-diff.js +25 -0
  50. package/dist/_core/spec-diff.js.map +1 -0
  51. package/dist/_core/status.d.ts +7 -0
  52. package/dist/_core/status.js +25 -0
  53. package/dist/_core/status.js.map +1 -0
  54. package/dist/_core/util/deep-equal.d.ts +8 -0
  55. package/dist/_core/util/deep-equal.js +31 -0
  56. package/dist/_core/util/deep-equal.js.map +1 -0
  57. package/dist/api.d.ts +46 -0
  58. package/dist/api.js +104 -0
  59. package/dist/api.js.map +1 -0
  60. package/dist/cache.d.ts +53 -0
  61. package/dist/cache.js +114 -0
  62. package/dist/cache.js.map +1 -0
  63. package/dist/commands/common.d.ts +59 -0
  64. package/dist/commands/common.js +94 -0
  65. package/dist/commands/common.js.map +1 -0
  66. package/dist/commands/export.d.ts +20 -0
  67. package/dist/commands/export.js +56 -0
  68. package/dist/commands/export.js.map +1 -0
  69. package/dist/commands/matrix.d.ts +16 -0
  70. package/dist/commands/matrix.js +48 -0
  71. package/dist/commands/matrix.js.map +1 -0
  72. package/dist/commands/next.d.ts +14 -0
  73. package/dist/commands/next.js +30 -0
  74. package/dist/commands/next.js.map +1 -0
  75. package/dist/commands/promote.d.ts +15 -0
  76. package/dist/commands/promote.js +172 -0
  77. package/dist/commands/promote.js.map +1 -0
  78. package/dist/commands/report.d.ts +18 -0
  79. package/dist/commands/report.js +45 -0
  80. package/dist/commands/report.js.map +1 -0
  81. package/dist/commands/ship.d.ts +15 -0
  82. package/dist/commands/ship.js +231 -0
  83. package/dist/commands/ship.js.map +1 -0
  84. package/dist/commands/status.d.ts +13 -0
  85. package/dist/commands/status.js +141 -0
  86. package/dist/commands/status.js.map +1 -0
  87. package/dist/commands/sync.d.ts +17 -0
  88. package/dist/commands/sync.js +90 -0
  89. package/dist/commands/sync.js.map +1 -0
  90. package/dist/conductor/registry.d.ts +45 -0
  91. package/dist/conductor/registry.js +164 -0
  92. package/dist/conductor/registry.js.map +1 -0
  93. package/dist/config.d.ts +47 -0
  94. package/dist/config.js +137 -0
  95. package/dist/config.js.map +1 -0
  96. package/dist/doctor.d.ts +28 -0
  97. package/dist/doctor.js +377 -0
  98. package/dist/doctor.js.map +1 -0
  99. package/dist/errors.d.ts +23 -0
  100. package/dist/errors.js +114 -0
  101. package/dist/errors.js.map +1 -0
  102. package/dist/export.d.ts +1 -0
  103. package/dist/export.js +9 -0
  104. package/dist/export.js.map +1 -0
  105. package/dist/import.d.ts +3 -0
  106. package/dist/import.js +89 -0
  107. package/dist/import.js.map +1 -0
  108. package/dist/index.d.ts +1 -0
  109. package/dist/index.js +183 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/init/auth.d.ts +85 -0
  112. package/dist/init/auth.js +194 -0
  113. package/dist/init/auth.js.map +1 -0
  114. package/dist/init/claudemd.d.ts +16 -0
  115. package/dist/init/claudemd.js +62 -0
  116. package/dist/init/claudemd.js.map +1 -0
  117. package/dist/init/index.d.ts +47 -0
  118. package/dist/init/index.js +159 -0
  119. package/dist/init/index.js.map +1 -0
  120. package/dist/init/mcp.d.ts +18 -0
  121. package/dist/init/mcp.js +97 -0
  122. package/dist/init/mcp.js.map +1 -0
  123. package/dist/init/plugin.d.ts +60 -0
  124. package/dist/init/plugin.js +120 -0
  125. package/dist/init/plugin.js.map +1 -0
  126. package/dist/init/scaffold.d.ts +19 -0
  127. package/dist/init/scaffold.js +46 -0
  128. package/dist/init/scaffold.js.map +1 -0
  129. package/dist/init/templates.d.ts +48 -0
  130. package/dist/init/templates.js +147 -0
  131. package/dist/init/templates.js.map +1 -0
  132. package/dist/plugin/.claude-plugin/plugin.json +11 -0
  133. package/dist/plugin/README.md +117 -0
  134. package/dist/plugin/commands/next.md +28 -0
  135. package/dist/plugin/commands/promote.md +30 -0
  136. package/dist/plugin/commands/report.md +26 -0
  137. package/dist/plugin/commands/ship.md +30 -0
  138. package/dist/plugin/skills/backlog-management/SKILL.md +63 -0
  139. package/dist/plugin/skills/backlog-query/SKILL.md +57 -0
  140. package/dist/plugin/skills/feature-kickoff/SKILL.md +112 -0
  141. package/dist/snapshot.d.ts +24 -0
  142. package/dist/snapshot.js +2 -0
  143. package/dist/snapshot.js.map +1 -0
  144. package/dist/token.d.ts +29 -0
  145. package/dist/token.js +99 -0
  146. package/dist/token.js.map +1 -0
  147. package/package.json +52 -0
@@ -0,0 +1,26 @@
1
+ ---
2
+ description: Record an Evaluate-Loop transition for a track in the register.
3
+ argument-hint: "<slug> <PLAN|EVALUATE_PLAN|EXECUTE|EVALUATE_EXECUTION|COMPLETE> <IN_PROGRESS|PASS|FAIL|COMPLETE> [--note <text>]"
4
+ allowed-tools: Bash(backlog report:*)
5
+ ---
6
+
7
+ # /backlog:report
8
+
9
+ **Role required: Engineer, Product or Owner.** QA and Viewer are refused (PRODUCT-SPEC §3.1,
10
+ "Report track progress").
11
+
12
+ Run exactly this, from the repo root, and show the output:
13
+
14
+ ```bash
15
+ backlog report $ARGUMENTS
16
+ ```
17
+
18
+ It calls `report_progress` and mirrors the conductor's `loop_state`. The first `EXECUTE`
19
+ report flips the track's promoted items to `in-progress`. Report the transition that actually
20
+ happened — never a step ahead of the work.
21
+
22
+ ## Refusals
23
+
24
+ `invalid_transition` (that step/status is not legal from where the track is now — read
25
+ `backlog status` first), `forbidden` (role is short), `not_found` (no such track, or no role
26
+ on the project), `invalid_request` (an unknown step or status name), `conflict`, `unreachable`.
@@ -0,0 +1,30 @@
1
+ ---
2
+ description: Close a track — write the shipped commit and production date back to the register, subject to the QA matrix gate.
3
+ argument-hint: "<slug> --auto | --commit <sha> --date <YYYY-MM-DD>"
4
+ allowed-tools: Bash(backlog ship:*)
5
+ ---
6
+
7
+ # /backlog:ship
8
+
9
+ **Role required: Product or Owner only.** Engineers and QA are refused by the service
10
+ (PRODUCT-SPEC §3.1, "Ship"). If that is the caller, report the matrix state and hand the ship
11
+ to a Product role rather than retrying.
12
+
13
+ **A human must approve the ship first** (feature-kickoff's second checkpoint). Do not run this
14
+ to "finish the task".
15
+
16
+ Run exactly this, from the repo root, and show the output:
17
+
18
+ ```bash
19
+ backlog ship $ARGUMENTS
20
+ ```
21
+
22
+ It calls `ship_track`, surfaces the QA matrix gate result (strict or permissive per track) and
23
+ appends the track to `conductor/index.md` Recent Completions.
24
+
25
+ ## Refusals
26
+
27
+ `forbidden` (Engineer or QA cannot ship — name the role and stop), `conflict` (the matrix gate
28
+ is unmet under strict enforcement, or the track is not complete — print the coverage summary),
29
+ `invalid_request` (neither `--auto` nor both `--commit` and `--date`), `not_found` (no such
30
+ track, or no role on the project), `superseded`, `unreachable`.
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: backlog-management
3
+ description: Change the product register — file a new item as a draft, co-author a draft's spec fields, review criteria with a critique, comment on an item, or suggest a change to criteria that are already locked. Use when someone says "file an item for X", "add this to the backlog", "write acceptance criteria for TMN-004", "review these criteria", "leave a note on ACC-012", or "the criteria for X are wrong". Writes through MCP tools only; it never edits docs/backlog/.
4
+ ---
5
+
6
+ # backlog-management — writing to the register
7
+
8
+ Every write goes through the `backlog` MCP server. `docs/backlog/**` is an export: editing it
9
+ changes nothing and will be overwritten by the next `backlog export`.
10
+
11
+ ## Role required
12
+
13
+ Read the row before you call the tool (PRODUCT-SPEC §3.1):
14
+
15
+ | What you want to do | Tool | Role required |
16
+ |---|---|---|
17
+ | file an item (always lands as `draft`) | `create_item` | **Engineer or QA and above** |
18
+ | edit spec fields of a `draft` | `update_item` | **Engineer or QA and above** |
19
+ | edit spec fields of a `reviewed` item | `update_item` | **Product or Owner** |
20
+ | `draft → reviewed` (needs a non-empty critique) | `review_criteria` | **Engineer or QA and above** |
21
+ | `reviewed → locked` (needs ≥1 criterion) | `lock_criteria` | **Product or Owner** |
22
+ | unlock (`locked → reviewed`, reason required) | `unlock_criteria` | **Product or Owner** |
23
+ | schedule / deschedule, set priority | `schedule_item`, `deschedule_item`, `set_priority` | **Product or Owner** |
24
+ | reject (reason required) | `reject_item` | **Product or Owner** |
25
+ | suggest a change on a **locked** item | `suggest_change` | **Engineer or QA and above** |
26
+ | accept / decline a suggestion (note required) | `resolve_suggestion` | **Product or Owner** |
27
+ | comment on any item | `add_comment` | **Engineer or QA and above** |
28
+ | open a follow-up from a track | `add_follow_up` | **Engineer or QA and above** |
29
+
30
+ Viewers cannot write anything. If the caller's role is short, **say which role is needed and
31
+ stop** — do not try a different tool to get around it.
32
+
33
+ ## What the caller may not do
34
+
35
+ - **Locked means immutable.** Never call `update_item` on a locked item, and never edit the
36
+ copy of the criteria in `conductor/tracks/<slug>/spec.md`. File a `suggest_change` against
37
+ the item and let a Product role resolve it; `backlog sync <slug>` re-renders `spec.md` when
38
+ the register says the criteria moved.
39
+ - Never lock your own draft to unblock yourself if you are an Engineer or QA. That is the
40
+ review gate, not a formality.
41
+ - Never invent a criterion the human did not ask for, and never reword one that is already
42
+ `reviewed` to make it pass.
43
+ - Never write a status, a ship date or a commit SHA here — that is **feature-kickoff**.
44
+ - Never put a token, a PAT, or any credential into an item, a comment, or a suggestion.
45
+
46
+ ## Refusals you can hit, and what each means
47
+
48
+ | Code | What it means here |
49
+ |---|---|
50
+ | `forbidden` | the caller's role does not allow this write — name the role the table above requires and stop |
51
+ | `locked` | the criteria are locked; use `suggest_change` instead of an edit |
52
+ | `not_locked` | the item is not locked yet, and this call needs it to be |
53
+ | `invalid_transition` | the state machine refused the move — re-read the item's current status first |
54
+ | `reason_required` | unlock, reject and decline all need a written reason; ask the human for one |
55
+ | `superseded` | a newer revision exists — re-read the item and file it again against the current version |
56
+ | `conflict` | a precondition failed (e.g. a review with an empty critique) — read the item and act on what it says now |
57
+ | `invalid_request` | the arguments are malformed; check the tool's argument names |
58
+ | `read_only_token` | the PAT is read-only and this writes — a writable PAT must be minted in the web UI (`/me`) |
59
+ | `not_found` | no such ref, or no role on that project |
60
+ | `unreachable` | the service is down — nothing was written; say so and try again later |
61
+
62
+ Every refusal is one sentence from the service. Repeat it to the human rather than retrying
63
+ the same call.
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: backlog-query
3
+ description: Read the product register for this repo — what is in the backlog, what is ready to work on, what one item actually says. Use whenever someone asks "what's in the backlog", "what should I work on", "what's the status of TMN-004", "is ACC-012 locked yet", "which tracks are open", "what's blocked", or names a backlog ID and wants to know about it rather than change it. Read-only: it never writes to the register and never edits docs/backlog/.
4
+ ---
5
+
6
+ # backlog-query — the read-only front door
7
+
8
+ The product register (what / why / on what conditions) lives in the backlog service, not in
9
+ this repo. `docs/backlog/` is at most an exported snapshot: **never read it as the truth and
10
+ never edit it.** Ask the register.
11
+
12
+ ## Role required
13
+
14
+ **Viewer or above** on the project — every role can read (PRODUCT-SPEC §3.1, first row).
15
+ Nothing in this skill can be refused for being too small a role except by a token that has
16
+ no membership at all.
17
+
18
+ ## How to ask
19
+
20
+ Prefer the MCP tools on the `backlog` server, which `backlog init` wrote into `.mcp.json`:
21
+
22
+ | Question | Tool | Args |
23
+ |---|---|---|
24
+ | what is in the backlog | `list_items` | `project`, and any of `status`, `criteria_status`, `priority`, `domain`, `q` |
25
+ | what should I work on | `next_ready` | `project` — locked, unblocked, unpromoted, ranked by priority |
26
+ | what does TMN-004 say | `get_item` | `ref` — `TMN-004` or `tammeni/TMN-004` |
27
+ | which tracks are open | `list_tracks` | `project`, `active_only?` |
28
+ | what is track X doing | `get_track` | `track` |
29
+ | what decisions are owed | `list_decisions` | `project` |
30
+ | what changed lately | `get_activity` | `project`, `since?` |
31
+
32
+ The project slug is in `backlog.config.json` at the repo root. If the MCP server is not
33
+ connected, the same three answers are available from the CLI — `backlog status`,
34
+ `backlog next`, `backlog doctor` — and `backlog status` falls back to the last cached
35
+ result when the service is unreachable.
36
+
37
+ ## What you may not do here
38
+
39
+ - No writes. Filing, editing, reviewing, locking, commenting and suggesting belong to
40
+ **backlog-management**; promotion and ship belong to **feature-kickoff**.
41
+ - No editing `docs/backlog/**` to "fix" something you read. That directory is an export.
42
+ - No inventing an item's criteria from memory. If `get_item` did not say it, it is not in
43
+ the contract.
44
+
45
+ ## Refusals you can hit, and what each means
46
+
47
+ | Code | What it means here |
48
+ |---|---|
49
+ | `no_session` | no credential reached the service — the PAT comes from `$BACKLOG_TOKEN` or `~/.config/backlog/token`; run `backlog doctor` |
50
+ | `token_unknown` / `token_revoked` / `token_expired` | the PAT is no longer good — mint a new one in the web UI (`/me`) and re-run `backlog init` |
51
+ | `no_member` | the service has no org membership for this caller |
52
+ | `not_found` | the ref does not exist **or** the caller has no role on that project — a project's existence is privileged, so the two look the same on purpose |
53
+ | `rate_limited` | 120 requests per minute per token; wait and retry |
54
+ | `unreachable` | the service is down — say so, and use `backlog status` for the cached view |
55
+
56
+ Never paste a token value into a file, a command line, a commit or an answer. The register's
57
+ credential is referenced as `${BACKLOG_TOKEN}` and nowhere else.
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: feature-kickoff
3
+ description: Run a feature end to end against the register and the conductor — promote locked items into a track, write the plan, scaffold the QA matrix, report each Evaluate-Loop transition, and ship. Use when someone says "let's work on TMN-004", "start a track for ACC-012 and ACC-013", "kick off the next feature", "what's next — let's do it", "report the plan passed", or "ship the verification track". Keeps both human checkpoints.
4
+ ---
5
+
6
+ # feature-kickoff — promotion to ship
7
+
8
+ The register owns *what* and *why*; `conductor/` owns *how* and *now*. The only coupling is
9
+ the tool surface below. **"let's work on TMN-004" starts here.**
10
+
11
+ ## Role required
12
+
13
+ Each step has its own row in PRODUCT-SPEC §3.1, and they are not the same:
14
+
15
+ | Step | Role required |
16
+ |---|---|
17
+ | read what is ready (`backlog next`) | **Viewer or above** |
18
+ | promote (`backlog promote`) | **Engineer, Product or Owner** — QA and Viewer refused |
19
+ | matrix init (`backlog matrix init`) | **QA, Engineer, Product or Owner** |
20
+ | report progress (`backlog report`) | **Engineer, Product or Owner** |
21
+ | ship (`backlog ship`) | **Product or Owner only** |
22
+
23
+ If the caller's role is short for a step, say which role that step needs and stop there.
24
+
25
+ ## The loop
26
+
27
+ ```
28
+ next → PROMOTE → plan → [HUMAN CHECKPOINT 1] → matrix init → EXECUTE
29
+ ↑ │
30
+ └──────────────── report each transition ──────────────────────┘
31
+
32
+ [HUMAN CHECKPOINT 2] → SHIP
33
+ ```
34
+
35
+ ### 1. Find the work — role: **Viewer+**
36
+
37
+ `backlog next` (or `next_ready`) lists locked, unblocked, unpromoted items ranked by
38
+ priority. Nothing may be promoted until its criteria are **locked** in the register.
39
+
40
+ ### 2. Promote — role: **Engineer, Product or Owner**
41
+
42
+ ```
43
+ backlog promote <ID…> [--slug <slug>] [--type feature|fix|chore]
44
+ ```
45
+ Calls `promote_items`, then writes `conductor/tracks/<slug>/{spec.md,plan.md,metadata.json}`
46
+ from the payload the service returned and updates `conductor/tracks.md`. `spec.md` is
47
+ **generated** — hand-edit `plan.md`, never `spec.md`.
48
+
49
+ ### 3. Plan — no register call
50
+
51
+ Write the plan with `superpowers:writing-plans` into
52
+ `docs/superpowers/plans/<date>-<track>.md`. `plan.md` in the track points at it.
53
+
54
+ ### 4. **Human Checkpoint 1 — the human approves the plan.** Stop and ask.
55
+
56
+ Do not promote further, scaffold the matrix, or write code before a human has said yes to the
57
+ plan. This checkpoint is not yours to skip, delegate or infer from silence.
58
+
59
+ ### 5. Matrix init — role: **QA, Engineer, Product or Owner**
60
+
61
+ Immediately after the plan is approved:
62
+ ```
63
+ backlog matrix init <slug>
64
+ ```
65
+ Calls `matrix_init`: one `☐` row per criterion of every promoted item, IDs `{ID}-AC{n}.M1`.
66
+ It refuses if a matrix already exists.
67
+
68
+ ### 6. Execute and report — role: **Engineer, Product or Owner**
69
+
70
+ At every Evaluate-Loop transition:
71
+ ```
72
+ backlog report <slug> <PLAN|EVALUATE_PLAN|EXECUTE|EVALUATE_EXECUTION|COMPLETE> <IN_PROGRESS|PASS|FAIL|COMPLETE> [--note …]
73
+ ```
74
+ Calls `report_progress`; the first `EXECUTE` flips the promoted items to `in-progress`. If the
75
+ criteria moved under you (`spec_drift`), run `backlog sync <slug>` — it re-renders `spec.md`
76
+ and marks superseded matrix rows `⏭️`. Never patch `spec.md` by hand to make it agree.
77
+
78
+ ### 7. **Human Checkpoint 2 — the human approves the ship.** Stop and ask.
79
+
80
+ Ship writes a commit SHA and a production date into the register. Never ship on your own
81
+ judgement, and never to "finish the task".
82
+
83
+ ### 8. Ship — role: **Product or Owner only**
84
+
85
+ ```
86
+ backlog ship <slug> --auto | --commit <sha> --date <YYYY-MM-DD>
87
+ ```
88
+ Calls `ship_track`. The QA matrix gate applies (strict or permissive per track). **Engineers
89
+ and QA are refused here** — if that is the caller, report the matrix state and hand the ship
90
+ to a Product role.
91
+
92
+ ## What you may not do
93
+
94
+ - Promote an item whose criteria are not locked; ask for a lock instead.
95
+ - Edit `docs/backlog/**` or a track's `spec.md`.
96
+ - Change a criterion to match what was built — `suggest_change` (see **backlog-management**).
97
+ - Skip either human checkpoint.
98
+ - Put a token value into `.mcp.json`, a track file, a commit or a comment. The PAT lives in
99
+ `$BACKLOG_TOKEN` or `~/.config/backlog/token`; `.mcp.json` references `${BACKLOG_TOKEN}`.
100
+
101
+ ## Refusals you can hit, and what each means
102
+
103
+ | Code | What it means here |
104
+ |---|---|
105
+ | `not_locked` | an item in the promote list is not locked — stop and ask a Product role to lock it |
106
+ | `forbidden` | the role is short for this step (promote needs Engineer+, ship needs Product+) — name the role and stop |
107
+ | `conflict` | a precondition failed: a matrix already exists, the ship gate is unmet, or the track is not in that step — read `backlog status` and say what it says |
108
+ | `invalid_transition` | that loop step/status move is not legal from where the track is now |
109
+ | `superseded` | the criteria version moved — run `backlog sync <slug>` and re-read `spec.md` |
110
+ | `not_found` | no such track or ref, or no role on the project |
111
+ | `invalid_request` | bad arguments — e.g. a ship without both a commit and a date |
112
+ | `unreachable` | the service is down. Execution is local and continues; promotion, matrix edits and ship wait |
@@ -0,0 +1,24 @@
1
+ import type { Item, ItemSource, MatrixDoc, MatrixRow, Track } from './_core/index.js';
2
+ export interface ProjectSnapshot {
3
+ version: 1;
4
+ project: string;
5
+ root: string;
6
+ items: Array<{
7
+ item: Item;
8
+ source: ItemSource;
9
+ }>;
10
+ tracks: Array<{
11
+ track: Track;
12
+ metadataPath: string;
13
+ raw: string;
14
+ }>;
15
+ matrices: Array<{
16
+ doc: MatrixDoc;
17
+ rows: MatrixRow[];
18
+ }>;
19
+ docs: Record<'README.md' | 'decisions-owed.md' | '_schema.md', {
20
+ path: string;
21
+ raw: string;
22
+ } | null>;
23
+ warnings: string[];
24
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A refusal about the token *store* — never about the token value. Nothing in this module
3
+ * puts a token in a message, a log line or an error: the value only ever moves between the
4
+ * file and the caller.
5
+ */
6
+ export declare class TokenError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ /** `~/.config/backlog/token` — the one place a PAT lives on disk (PRODUCT-SPEC §6.4). */
10
+ export declare function tokenPath(home: string): string;
11
+ /**
12
+ * Reads `~/.config/backlog/token`, trimmed. Null when the file is absent or empty.
13
+ * On a POSIX platform a file any other user could read is refused outright rather than
14
+ * used — a leaked PAT is worse than a failed command.
15
+ */
16
+ export declare function readToken(home: string): string | null;
17
+ /**
18
+ * `$BACKLOG_TOKEN` wins (CI, a one-off shell), else the file. Null when neither has one —
19
+ * the caller turns that into `token_required`, which `errors.ts` renders.
20
+ */
21
+ export declare function resolveToken(env: NodeJS.ProcessEnv, home: string): string | null;
22
+ /**
23
+ * Writes the PAT with mode 0600 into a 0700 directory, and `chmod`s both explicitly because
24
+ * a permissive umask widens the create mode. Refuses a home that is inside a git work tree:
25
+ * a token must never land somewhere `git add -A` can pick it up.
26
+ */
27
+ export declare function saveToken(home: string, plaintext: string): string;
28
+ /** The plan's argument order (`writeToken(value, home)`); same behaviour as `saveToken`. */
29
+ export declare function writeToken(value: string, home: string): string;
package/dist/token.js ADDED
@@ -0,0 +1,99 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ /**
4
+ * A refusal about the token *store* — never about the token value. Nothing in this module
5
+ * puts a token in a message, a log line or an error: the value only ever moves between the
6
+ * file and the caller.
7
+ */
8
+ export class TokenError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = 'TokenError';
12
+ }
13
+ }
14
+ const POSIX = process.platform !== 'win32';
15
+ /** `~/.config/backlog/token` — the one place a PAT lives on disk (PRODUCT-SPEC §6.4). */
16
+ export function tokenPath(home) {
17
+ return join(home, '.config', 'backlog', 'token');
18
+ }
19
+ function tokenDir(home) {
20
+ return join(home, '.config', 'backlog');
21
+ }
22
+ /**
23
+ * Reads `~/.config/backlog/token`, trimmed. Null when the file is absent or empty.
24
+ * On a POSIX platform a file any other user could read is refused outright rather than
25
+ * used — a leaked PAT is worse than a failed command.
26
+ */
27
+ export function readToken(home) {
28
+ const path = tokenPath(home);
29
+ let stat;
30
+ try {
31
+ stat = statSync(path);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ if (POSIX) {
37
+ const mode = stat.mode & 0o777;
38
+ if ((mode & 0o077) !== 0) {
39
+ throw new TokenError(`${path} is mode ${mode.toString(8)} — group- or world-readable; run: chmod 600 ${path}`);
40
+ }
41
+ }
42
+ let raw;
43
+ try {
44
+ raw = readFileSync(path, 'utf8');
45
+ }
46
+ catch {
47
+ throw new TokenError(`cannot read ${path}`);
48
+ }
49
+ const value = raw.trim();
50
+ return value === '' ? null : value;
51
+ }
52
+ /**
53
+ * `$BACKLOG_TOKEN` wins (CI, a one-off shell), else the file. Null when neither has one —
54
+ * the caller turns that into `token_required`, which `errors.ts` renders.
55
+ */
56
+ export function resolveToken(env, home) {
57
+ const fromEnv = env.BACKLOG_TOKEN?.trim();
58
+ if (fromEnv)
59
+ return fromEnv;
60
+ return readToken(home);
61
+ }
62
+ function insideGitWorkTree(dir) {
63
+ let current = resolve(dir);
64
+ for (;;) {
65
+ if (existsSync(join(current, '.git')))
66
+ return true;
67
+ const parent = dirname(current);
68
+ if (parent === current)
69
+ return false;
70
+ current = parent;
71
+ }
72
+ }
73
+ /**
74
+ * Writes the PAT with mode 0600 into a 0700 directory, and `chmod`s both explicitly because
75
+ * a permissive umask widens the create mode. Refuses a home that is inside a git work tree:
76
+ * a token must never land somewhere `git add -A` can pick it up.
77
+ */
78
+ export function saveToken(home, plaintext) {
79
+ const value = plaintext.trim();
80
+ if (value === '')
81
+ throw new TokenError('refusing to write an empty token');
82
+ const dir = tokenDir(home);
83
+ if (insideGitWorkTree(home)) {
84
+ throw new TokenError(`${home} is inside a git work tree — refusing to write a token there; a PAT belongs outside any repository`);
85
+ }
86
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
87
+ const path = tokenPath(home);
88
+ writeFileSync(path, `${value}\n`, { mode: 0o600 });
89
+ if (POSIX) {
90
+ chmodSync(dir, 0o700);
91
+ chmodSync(path, 0o600);
92
+ }
93
+ return path;
94
+ }
95
+ /** The plan's argument order (`writeToken(value, home)`); same behaviour as `saveToken`. */
96
+ export function writeToken(value, home) {
97
+ return saveToken(home, value);
98
+ }
99
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "felenova-backlog",
3
+ "version": "0.1.0",
4
+ "description": "Felenova's backlog CLI: the repo-side bridge to the hosted product register, plus the backlog-execution plugin for Claude Code.",
5
+ "license": "UNLICENSED",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/felenova/backlog.git",
9
+ "directory": "packages/cli"
10
+ },
11
+ "homepage": "https://github.com/felenova/backlog#readme",
12
+ "keywords": [
13
+ "backlog",
14
+ "conductor",
15
+ "mcp",
16
+ "claude-code",
17
+ "felenova"
18
+ ],
19
+ "engines": {
20
+ "node": ">=22"
21
+ },
22
+ "type": "module",
23
+ "bin": {
24
+ "backlog": "./bin/backlog.js"
25
+ },
26
+ "main": "./dist/index.js",
27
+ "files": [
28
+ "dist",
29
+ "bin"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.json && node scripts/vendor-core.mjs && node scripts/copy-plugin-payload.mjs",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "test": "vitest run",
38
+ "clean": "rm -rf dist",
39
+ "prepublishOnly": "npm run clean && npm run build && npm run test"
40
+ },
41
+ "dependencies": {
42
+ "commander": "^15.0.0",
43
+ "yaml": "^2.9.0",
44
+ "zod": "^4.6.2"
45
+ },
46
+ "devDependencies": {
47
+ "@felenova/backlog-core": "workspace:*",
48
+ "@types/node": "^22.20.2",
49
+ "typescript": "^5.9.3",
50
+ "vitest": "^4.1.11"
51
+ }
52
+ }