@oevery/rsp 2.0.2 → 2.0.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/README.md CHANGED
@@ -71,6 +71,9 @@ Managed block example:
71
71
  <!-- rsp:begin -->
72
72
  ## RSP Entry
73
73
 
74
+ RSP keeps durable rules, specs, and current work under `.rsp/`.
75
+ Treat AGENTS.md as navigation only; keep durable rules and design in `.rsp/`.
76
+
74
77
  Read in order:
75
78
  1. .rsp/rules/rsp-rules.md
76
79
  2. .rsp/focus.d/
@@ -78,6 +81,9 @@ Read in order:
78
81
  4. .rsp/specs/design.md
79
82
  5. .rsp/specs/INDEX.md
80
83
  6. only the relevant additional .rsp/rules/*.md and .rsp/specs/*.md files
84
+
85
+ If `.rsp/focus.d/` is empty, ask what to work on or suggest `npx -y @oevery/rsp create <name>`.
86
+ If your agent supports Agent Skills, load `rsp` for setup, repair, and durable-decision tasks.
81
87
  <!-- rsp:end -->
82
88
  ```
83
89
 
package/README.zh-CN.md CHANGED
@@ -71,6 +71,9 @@ npx -y @oevery/rsp doctor
71
71
  <!-- rsp:begin -->
72
72
  ## RSP Entry
73
73
 
74
+ RSP keeps durable rules, specs, and current work under `.rsp/`.
75
+ Treat AGENTS.md as navigation only; keep durable rules and design in `.rsp/`.
76
+
74
77
  Read in order:
75
78
  1. .rsp/rules/rsp-rules.md
76
79
  2. .rsp/focus.d/
@@ -78,6 +81,9 @@ Read in order:
78
81
  4. .rsp/specs/design.md
79
82
  5. .rsp/specs/INDEX.md
80
83
  6. only the relevant additional .rsp/rules/*.md and .rsp/specs/*.md files
84
+
85
+ If `.rsp/focus.d/` is empty, ask what to work on or suggest `npx -y @oevery/rsp create <name>`.
86
+ If your agent supports Agent Skills, load `rsp` for setup, repair, and durable-decision tasks.
81
87
  <!-- rsp:end -->
82
88
  ```
83
89
 
package/dist/cli.mjs CHANGED
@@ -19,7 +19,7 @@ import pc from "picocolors";
19
19
 
20
20
  // src/core/helpers.ts
21
21
  import { existsSync } from "fs";
22
- import { readdir, readFile, rmdir, stat } from "fs/promises";
22
+ import { readdir, readFile, rmdir } from "fs/promises";
23
23
  import { basename, dirname, join, relative, sep } from "path";
24
24
  import { parse } from "yaml";
25
25
 
@@ -166,6 +166,7 @@ kind: ops
166
166
 
167
167
  ## Tasks
168
168
  - [ ] Review the repository structure, entrypoints, and primary outputs
169
+ - [ ] Review AGENTS.md and confirm the RSP entry points to the right project files
169
170
  - [ ] Fill .rsp/specs/design.md with durable architecture facts
170
171
  - [ ] Add .rsp/rules/project-rules.md if stable local rules or validation steps exist
171
172
 
@@ -209,12 +210,15 @@ ${template.acceptanceSection}
209
210
  - Approach:
210
211
  - ${template.approach}
211
212
  - Affected areas:
212
- - ${template.affectedAreas}
213
+ - ${template.affectedArea1}
214
+ - ${template.affectedArea2}
213
215
  - Constraints:
214
216
  - ${template.constraints}
215
217
 
216
218
  ## Tasks
219
+ - [ ] Finalize the proposal, spec, and design details for this change
217
220
  - [ ] ${template.task}
221
+ - [ ] Verify the result and update any required durable docs or rules
218
222
 
219
223
  ## Verify
220
224
  - Automated:
@@ -231,6 +235,51 @@ ${template.acceptanceSection}
231
235
  }
232
236
  function getChangeTemplateByKind(kind) {
233
237
  switch (kind) {
238
+ case "feature":
239
+ return {
240
+ why: "<what user need or capability gap this addresses>",
241
+ scope: "<what new behavior or capability will be delivered>",
242
+ nonGoals: "<what related capabilities are explicitly out of scope>",
243
+ specSection: "### ADDED\n- Requirement: <new user-facing behavior>\n - <verifiable requirement for the new capability>",
244
+ acceptanceSection: "#### Scenario: user exercises the new capability\n- GIVEN <context>\n- WHEN <user action>\n- THEN <expected new behavior>",
245
+ approach: "<how the new capability will be implemented>",
246
+ affectedArea1: "<concrete file path, directory, module, or subsystem 1>",
247
+ affectedArea2: "<concrete file path, directory, module, or subsystem 2 if needed>",
248
+ constraints: "<behavior, compatibility, performance, safety, or scope constraint that must hold>",
249
+ task: "<implement the new behavior and its acceptance scenario in the affected areas>",
250
+ automatedVerify: "<exact test, lint, build, or check command for the new behavior>",
251
+ manualVerify: "<exact end-to-end user scenario to validate the new capability>"
252
+ };
253
+ case "fix":
254
+ return {
255
+ why: "<what current behavior is wrong or broken>",
256
+ scope: "<what specific defect is being corrected>",
257
+ nonGoals: "<what related but separate issues are out of scope>",
258
+ specSection: "### MODIFIED\n- Requirement: correct behavior\n - <expected correct behavior after the fix>",
259
+ acceptanceSection: "#### Scenario: defect is resolved\n- GIVEN <conditions that trigger the defect>\n- WHEN <action that previously failed>\n- THEN <expected correct outcome>\n- AND the original broken outcome no longer occurs",
260
+ approach: "<root cause analysis and fix strategy>",
261
+ affectedArea1: "<concrete file path, directory, module, or subsystem containing the defect>",
262
+ affectedArea2: "<secondary path, dependency, or test file if needed>",
263
+ constraints: "<regression, backward-compatibility, safety, or scope constraint that must hold>",
264
+ task: "<identify the root cause and apply the minimal fix>",
265
+ automatedVerify: "<exact regression test, lint, build, or check command that proves the fix>",
266
+ manualVerify: "<exact steps to reproduce the original issue and confirm it no longer occurs>"
267
+ };
268
+ case "refactor":
269
+ return {
270
+ why: "<what maintainability, readability, or structural issue motivates this>",
271
+ scope: "<what code areas are being restructured>",
272
+ nonGoals: "<no behavior change is expected or intended>",
273
+ specSection: "### MODIFIED\n- Requirement: internal structure improvement\n - <desired structural outcome without observable behavior change>",
274
+ acceptanceSection: "#### Scenario: behavior is preserved after restructuring\n- GIVEN the existing codebase before the refactor\n- WHEN the refactored code runs against existing tests\n- THEN all existing tests pass unchanged",
275
+ approach: "<how the code will be restructured (rename, extract, move, etc.)>",
276
+ affectedArea1: "<concrete file path, directory, module, or subsystem being refactored>",
277
+ affectedArea2: "<secondary path, dependency, or test file if needed>",
278
+ constraints: "<observable behavior must remain unchanged; compatibility, performance, and safety constraints must still hold>",
279
+ task: "<restructure the code while keeping behavior identical>",
280
+ automatedVerify: "<exact existing test, lint, build, or check command that must continue to pass>",
281
+ manualVerify: "<exact scenario to spot-check that behavior is unchanged after the refactor>"
282
+ };
234
283
  case "docs":
235
284
  return {
236
285
  why: "<why the documentation change matters>",
@@ -239,11 +288,12 @@ function getChangeTemplateByKind(kind) {
239
288
  specSection: "### MODIFIED\n- Requirement: documentation accuracy\n - <what durable reader-facing behavior or explanation changes>",
240
289
  acceptanceSection: "#### Scenario: reader follows the updated guidance\n- GIVEN the updated documentation\n- WHEN a reader follows the documented workflow\n- THEN the steps are accurate and sufficient",
241
290
  approach: "<how the documentation will be updated and organized>",
242
- affectedAreas: "<doc path or documentation area>",
243
- constraints: "<durable wording, consistency, or scope constraint>",
291
+ affectedArea1: "<concrete doc path, directory, module doc, or documentation surface 1>",
292
+ affectedArea2: "<secondary doc path or reference file if needed>",
293
+ constraints: "<durable wording, consistency, scope, or audience constraint that must hold>",
244
294
  task: "<update the target documentation and supporting references>",
245
- automatedVerify: "<run markdown, docs, or link checks if applicable>",
246
- manualVerify: "<review the updated doc as a reader and confirm it is accurate>"
295
+ automatedVerify: "<exact markdown, docs, link, lint, build, or check command if applicable>",
296
+ manualVerify: "<exact reader or operator scenario to confirm the updated guidance is accurate>"
247
297
  };
248
298
  case "research":
249
299
  return {
@@ -253,11 +303,12 @@ function getChangeTemplateByKind(kind) {
253
303
  specSection: "### ADDED\n- Requirement: research outcome recording\n - <what finding, option, or decision must be captured clearly>",
254
304
  acceptanceSection: "#### Scenario: research question is resolved\n- GIVEN the current uncertainty or open question\n- WHEN the investigation is completed\n- THEN the result is recorded clearly enough to guide follow-up work",
255
305
  approach: "<how the investigation will be performed and what evidence will be gathered>",
256
- affectedAreas: "<code path, subsystem, or source being investigated>",
257
- constraints: "<time, evidence, or scope constraint for the investigation>",
258
- task: "<gather evidence and record the resulting recommendation or finding>",
259
- automatedVerify: "<run any command needed to confirm the observed behavior>",
260
- manualVerify: "<review the findings and confirm they answer the original question>"
306
+ affectedArea1: "<concrete file path, directory, module, subsystem, or source under investigation>",
307
+ affectedArea2: "<secondary path, dependency, environment, or evidence source if needed>",
308
+ constraints: "<time, evidence, safety, or scope constraint for the investigation>",
309
+ task: "<gather evidence, record the recommendation or finding, and note any follow-up implementation work if needed>",
310
+ automatedVerify: "<exact command, script, query, or check used to confirm the observed behavior>",
311
+ manualVerify: "<exact review of the findings to confirm they answer the original question and identify follow-up work if needed>"
261
312
  };
262
313
  case "ops":
263
314
  return {
@@ -267,11 +318,12 @@ function getChangeTemplateByKind(kind) {
267
318
  specSection: "### MODIFIED\n- Requirement: operational behavior\n - <what reliable operational outcome should change or stay true>",
268
319
  acceptanceSection: "#### Scenario: operational path succeeds\n- GIVEN the target environment or workflow\n- WHEN the operational change is applied\n- THEN the expected operational outcome is reliable",
269
320
  approach: "<how the operational change will be applied safely>",
270
- affectedAreas: "<script, config, workflow, or environment path>",
271
- constraints: "<rollback, safety, or environment constraint>",
321
+ affectedArea1: "<concrete script, config path, workflow, environment path, or operational surface 1>",
322
+ affectedArea2: "<secondary script, config path, dependency, or environment surface if needed>",
323
+ constraints: "<rollback, safety, reliability, environment, or scope constraint that must hold>",
272
324
  task: "<apply and verify the operational change>",
273
- automatedVerify: "<run the relevant operational validation command>",
274
- manualVerify: "<exercise the target workflow and confirm the operational result>"
325
+ automatedVerify: "<exact operational validation, lint, build, deploy, or check command>",
326
+ manualVerify: "<exact operator workflow or environment scenario to confirm the operational result>"
275
327
  };
276
328
  default:
277
329
  return {
@@ -281,11 +333,12 @@ function getChangeTemplateByKind(kind) {
281
333
  specSection: "### ADDED\n- Requirement: <new or updated behavior>\n - <verifiable requirement>",
282
334
  acceptanceSection: "#### Scenario: <name>\n- GIVEN <context>\n- WHEN <action>\n- THEN <expected outcome>",
283
335
  approach: "<how the change will be implemented>",
284
- affectedAreas: "<path or subsystem>",
285
- constraints: "<binding technical or product constraint>",
286
- task: "<implementation task>",
287
- automatedVerify: "<test command or automated check>",
288
- manualVerify: "<manual scenario to validate>"
336
+ affectedArea1: "<concrete file path, directory, module, or subsystem 1>",
337
+ affectedArea2: "<concrete file path, directory, module, or subsystem 2 if needed>",
338
+ constraints: "<behavior, compatibility, performance, safety, or scope constraint that must hold>",
339
+ task: "<implement the core change in the affected areas>",
340
+ automatedVerify: "<exact test, lint, build, or check command>",
341
+ manualVerify: "<exact end-to-end scenario to validate>"
289
342
  };
290
343
  }
291
344
  }
@@ -293,6 +346,9 @@ function renderRspAgentsBlock() {
293
346
  return `${RSP_AGENTS_BEGIN}
294
347
  ## RSP Entry
295
348
 
349
+ RSP keeps durable rules, specs, and current work under \`.rsp/\`.
350
+ Treat AGENTS.md as navigation only; keep durable rules and design in \`.rsp/\`.
351
+
296
352
  Read in order:
297
353
  1. .rsp/rules/rsp-rules.md
298
354
  2. .rsp/focus.d/
@@ -300,6 +356,9 @@ Read in order:
300
356
  4. .rsp/specs/design.md
301
357
  5. .rsp/specs/INDEX.md
302
358
  6. only the relevant additional .rsp/rules/*.md and .rsp/specs/*.md files
359
+
360
+ If \`.rsp/focus.d/\` is empty, ask what to work on or suggest \`npx -y @oevery/rsp create <name>\`.
361
+ If your agent supports Agent Skills, load \`rsp\` for setup, repair, and durable-decision tasks.
303
362
  ${RSP_AGENTS_END}`;
304
363
  }
305
364
  function upsertRspAgentsBlock(content) {
@@ -332,6 +391,16 @@ function guardRspInitialized() {
332
391
  process.exit(1);
333
392
  }
334
393
  }
394
+ async function getFocusedChangeNames(options = {}) {
395
+ const names = /* @__PURE__ */ new Set();
396
+ const focusDir = join(RSP_DIR, "focus.d");
397
+ if (!existsSync(focusDir))
398
+ return names;
399
+ const entries = await walkFiles(focusDir, options);
400
+ for (const entryPath of entries)
401
+ names.add(normalizeLogicalPath(relative(focusDir, entryPath)));
402
+ return names;
403
+ }
335
404
  function getOpenCheckboxes(sectionText) {
336
405
  return sectionText.split("\n").map((line) => line.trim()).filter((line) => /^- \[[ /]\]/.test(line));
337
406
  }
@@ -785,6 +854,7 @@ async function archiveChange(name) {
785
854
  console.error(` ${pc.red("Error:")} change name must be kebab-case with optional subdirectory (lowercase, digits, hyphens, slashes)`);
786
855
  process.exit(1);
787
856
  }
857
+ guardRspInitialized();
788
858
  const srcPath = join7(CHANGES_DIR, `${name}.md`);
789
859
  if (!existsSync7(srcPath)) {
790
860
  console.error(` ${pc.red("Change not found:")} .rsp/changes/${name}.md`);
@@ -1188,7 +1258,7 @@ async function createChange(name, summary = "", kind) {
1188
1258
  console.log(` ${pc.dim("Unchanged focus.")} Run: rsp focus ${name}`);
1189
1259
  else
1190
1260
  console.log(` ${pc.dim("focused via focus.d")} \u2192 ${name}`);
1191
- console.log(` ${pc.cyan("Next:")} edit the change file and complete the tasks
1261
+ console.log(` ${pc.cyan("Next:")} fill proposal/spec/design first, then implement and complete the tasks
1192
1262
  `);
1193
1263
  });
1194
1264
  }
@@ -1390,8 +1460,7 @@ function reportConfigListField(checks, parsed, key) {
1390
1460
  async function checkActiveChangeConsistency(checks, reportRuntime) {
1391
1461
  const changeFiles = existsSync10(CHANGES_DIR) ? await walkMarkdownFiles(CHANGES_DIR, { onError: reportRuntime }) : [];
1392
1462
  const changeNames = new Set(changeFiles.map((fp) => changeNameFromPath(CHANGES_DIR, fp)));
1393
- const focusEntries = existsSync10(FOCUS_DIR) ? await walkFiles(FOCUS_DIR, { onError: reportRuntime }) : [];
1394
- const focusNames = new Set(focusEntries.map((fp) => normalizeLogicalPath(relative5(FOCUS_DIR, fp))));
1463
+ const focusNames = await getFocusedChangeNames({ onError: reportRuntime });
1395
1464
  const missingChangeFiles = [...focusNames].filter((name) => !changeNames.has(name));
1396
1465
  const unfocusedChangeFiles = [...changeNames].filter((name) => !focusNames.has(name));
1397
1466
  if (missingChangeFiles.length === 0) {
@@ -1598,21 +1667,16 @@ ${managed}
1598
1667
 
1599
1668
  // src/commands/status.ts
1600
1669
  import { existsSync as existsSync13 } from "fs";
1601
- import { readFile as readFile10, stat as stat2 } from "fs/promises";
1602
- import { join as join13, relative as relative6 } from "path";
1670
+ import { readFile as readFile10, stat } from "fs/promises";
1671
+ import { join as join13 } from "path";
1603
1672
  var COL_CHANGE = 32;
1604
1673
  var COL_KIND = 10;
1605
1674
  var COL_AGE = 7;
1606
1675
  var COL_PROGRESS = 10;
1607
1676
  async function showStatus(options = {}, runOptions = {}) {
1608
- const focusedSet = /* @__PURE__ */ new Set();
1609
1677
  const runtime = [];
1610
1678
  const reportRuntime = (diagnostic) => recordRuntimeDiagnostic(runtime, diagnostic, Boolean(runOptions.verbose) && !runOptions.json);
1611
- if (existsSync13(FOCUS_DIR)) {
1612
- const entries = await walkFiles(FOCUS_DIR, { onError: reportRuntime });
1613
- for (const entryPath of entries)
1614
- focusedSet.add(normalizeLogicalPath(relative6(FOCUS_DIR, entryPath)));
1615
- }
1679
+ const focusedSet = await getFocusedChangeNames({ onError: reportRuntime });
1616
1680
  const changeFiles = existsSync13(CHANGES_DIR) ? await walkMarkdownFiles(CHANGES_DIR, { onError: reportRuntime }) : [];
1617
1681
  const changeMap = {};
1618
1682
  for (const fp of changeFiles)
@@ -1658,7 +1722,7 @@ async function showStatus(options = {}, runOptions = {}) {
1658
1722
  });
1659
1723
  }
1660
1724
  try {
1661
- const s = await stat2(fp);
1725
+ const s = await stat(fp);
1662
1726
  ageDays = Math.floor((Date.now() - s.mtime.getTime()) / (1e3 * 60 * 60 * 24));
1663
1727
  } catch (error) {
1664
1728
  reportRuntime({
@@ -1822,7 +1886,8 @@ import { join as join14 } from "path";
1822
1886
  var SKILL_REFRESH_HINT = " Note: if you use the published RSP skill, refresh it too:\n npx skills add oevery/rsp\n";
1823
1887
  async function updateProject() {
1824
1888
  if (!existsSync14(RSP_DIR)) {
1825
- console.log(` ${pc.red("Error:")} RSP is not initialized. Run: rsp init`);
1889
+ console.error(` ${pc.red("Error:")} RSP is not initialized in this project`);
1890
+ console.error(` ${pc.dim("Run: rsp init")}`);
1826
1891
  process.exit(1);
1827
1892
  }
1828
1893
  return withRspLock("update", async () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oevery/rsp",
3
3
  "type": "module",
4
- "version": "2.0.2",
4
+ "version": "2.0.3",
5
5
  "description": "RSP (Rules, Specs, Plans) workflow for lightweight AI-assisted change management",
6
6
  "author": "oevery",
7
7
  "license": "MIT",
@@ -7,6 +7,12 @@ description: Core RSP rules for Rules, Specs, and Plans driven development.
7
7
 
8
8
  This file is the canonical RSP rules source.
9
9
 
10
+ ## Scope
11
+
12
+ - Paths in this file are relative to the project root unless stated otherwise.
13
+ - These rules are tool-agnostic and apply even when the agent does not support skills.
14
+ - If the agent supports Agent Skills, load the `rsp` skill for initialization, audit or repair, and durable-decision tasks.
15
+
10
16
  ## Read order
11
17
 
12
18
  1. Read `AGENTS.md`.
@@ -1,6 +1,18 @@
1
1
  ---
2
2
  name: rsp
3
- description: Use this skill when adopting, operating, auditing, or repairing an RSP project and its .rsp structure.
3
+ description: Use this skill when initializing RSP in a repository, operating an existing .rsp project, auditing or repairing .rsp state, or deciding whether a change needs durable updates before archive.
4
+ compatibility:
5
+ agents:
6
+ - any agent that supports the Agent Skills format
7
+ requirements:
8
+ - Node.js 18+
9
+ - local filesystem read/write access
10
+ - shell access for `rsp` or `npx -y @oevery/rsp`
11
+ optional_requirements:
12
+ - network access for first-run `npx` installation or skill refresh
13
+ metadata:
14
+ author: oevery
15
+ version: 2.0.3
4
16
  ---
5
17
 
6
18
  # RSP Skill
@@ -11,6 +23,19 @@ This skill operationalizes the rules in `.rsp/rules/rsp-rules.md`. Always load a
11
23
 
12
24
  Prefer exact file paths, exact commands, and exact durable facts over vague summaries.
13
25
 
26
+ ## When to use
27
+
28
+ - Use this skill when a repository already contains `.rsp/` and the task is to operate within that workflow.
29
+ - Use this skill when adopting RSP in a repository that does not yet have `.rsp/`.
30
+ - Use this skill when the task is to audit or repair `.rsp/`, `AGENTS.md`, generated indices, or focus markers.
31
+ - Use this skill when deciding whether a completed change needs durable updates before archive.
32
+
33
+ ## When not to use
34
+
35
+ - Do not load this skill for general coding tasks unrelated to `.rsp/`.
36
+ - Do not use this skill as a substitute for reading `.rsp/rules/rsp-rules.md` during a focused RSP task.
37
+ - Do not use this skill when the repository does not use RSP and the user did not ask to adopt it.
38
+
14
39
  ## Workflow
15
40
 
16
41
  ### Adopt or initialize
@@ -44,6 +69,19 @@ Prefer exact file paths, exact commands, and exact durable facts over vague summ
44
69
  5. Check that `focus.d/` markers and `changes/` files are in sync.
45
70
  6. If generated indices or the managed AGENTS block drift, run `npx -y @oevery/rsp update`.
46
71
 
72
+ ## Expected outputs
73
+
74
+ - exact file paths to read or update
75
+ - exact RSP commands to run
76
+ - a single durable-decision result in the required template when evaluating archive readiness
77
+
78
+ ## Trigger examples
79
+
80
+ - "Set up RSP in this repository."
81
+ - "Repair the broken .rsp state in this project."
82
+ - "Check whether this change needs spec or rule writeback before archive."
83
+ - "Audit the RSP setup and tell me what is missing."
84
+
47
85
  ## Durable decision
48
86
 
49
87
  Before `npx -y @oevery/rsp archive <name>`: