@oevery/rsp 3.3.0 → 4.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 (76) hide show
  1. package/README.md +24 -17
  2. package/README.zh-CN.md +25 -18
  3. package/dist/chunk-JO6NDJM4.mjs +360 -0
  4. package/dist/chunk-LGDCIQYL.mjs +725 -0
  5. package/dist/{chunk-7HXQNBIG.mjs → chunk-P3KO3GZW.mjs} +420 -268
  6. package/dist/chunk-U56XMIOO.mjs +66 -0
  7. package/dist/{chunk-TSUDEX5Y.mjs → chunk-VDRXFKBP.mjs} +142 -867
  8. package/dist/cli.mjs +1111 -2347
  9. package/dist/client-EHRWH5Q7.mjs +108 -0
  10. package/dist/{entry-GIDNR7CJ.mjs → entry-NDASTAI5.mjs} +128 -38
  11. package/dist/viewer/NOTICE.txt +299 -0
  12. package/dist/viewer/app.css +2 -0
  13. package/dist/viewer/app.js +670 -0
  14. package/dist/viewer-build.json +1 -0
  15. package/dist/viewer-service.mjs +551 -0
  16. package/package.json +51 -25
  17. package/skills/rsp/SKILL.md +44 -38
  18. package/skills/rsp/references/architecture.md +39 -0
  19. package/skills/rsp/references/closeout.md +38 -0
  20. package/skills/rsp/references/context-migration.md +22 -0
  21. package/skills/rsp/references/control-outcome.md +3 -29
  22. package/skills/rsp/references/coordination-recovery.md +25 -0
  23. package/skills/rsp/references/coordination-review.md +15 -0
  24. package/skills/rsp/references/coordination.md +59 -0
  25. package/skills/rsp/references/durable-review.md +60 -12
  26. package/skills/rsp/references/focus-continuation.md +12 -4
  27. package/skills/rsp/references/groups-dependencies.md +6 -4
  28. package/skills/rsp/references/response-language.md +2 -0
  29. package/skills/rsp/references/setup-repair.md +42 -7
  30. package/skills/rsp/references/work-model.md +37 -0
  31. package/skills/rsp-commit/SKILL.md +76 -31
  32. package/skills/rsp-commit/references/message.md +34 -0
  33. package/skills/rsp-doc/SKILL.md +68 -0
  34. package/skills/rsp-doc/agents/openai.yaml +3 -0
  35. package/skills/rsp-doc/references/release-communication.md +39 -0
  36. package/skills/rsp-doc/references/skill-authoring.md +36 -0
  37. package/skills/rsp-implement/SKILL.md +60 -25
  38. package/skills/rsp-implement/references/diagnosis.md +10 -0
  39. package/skills/rsp-implement/references/finding-resolution.md +21 -0
  40. package/skills/rsp-implement/references/test-first.md +7 -0
  41. package/skills/rsp-review/SKILL.md +46 -45
  42. package/skills/rsp-review/references/code-review.md +30 -9
  43. package/skills/rsp-review/references/document-review.md +24 -9
  44. package/skills/rsp-review/references/release-communication.md +21 -0
  45. package/skills/rsp-shape/SKILL.md +26 -45
  46. package/skills/rsp-shape/references/complex-shaping.md +3 -1
  47. package/skills/rsp-shape/references/deep-clarification.md +4 -4
  48. package/skills/rsp-shape/references/domain-modeling.md +13 -0
  49. package/skills/rsp-shape/references/module-seams.md +13 -0
  50. package/skills/rsp-shape/references/planning.md +42 -0
  51. package/skills/{rsp-design → rsp-shape}/references/reversible-exploration.md +2 -2
  52. package/skills/rsp-verify/SKILL.md +39 -12
  53. package/dist/chunk-JOMFFQRG.mjs +0 -99
  54. package/dist/chunk-QM2UVPQK.mjs +0 -375
  55. package/dist/entry-YAW3PYFA.mjs +0 -174
  56. package/rules/rsp-rules.md +0 -48
  57. package/skills/rsp/references/implementation-evidence.md +0 -12
  58. package/skills/rsp/references/managed-routing.md +0 -45
  59. package/skills/rsp-design/SKILL.md +0 -53
  60. package/skills/rsp-design/references/domain-modeling.md +0 -11
  61. package/skills/rsp-design/references/module-seams.md +0 -11
  62. package/skills/rsp-diagnose/SKILL.md +0 -48
  63. package/skills/rsp-manage/SKILL.md +0 -101
  64. package/skills/rsp-manage/references/closeout.md +0 -13
  65. package/skills/rsp-manage/references/delegation.md +0 -47
  66. package/skills/rsp-manage/references/interruption-recovery.md +0 -19
  67. package/skills/rsp-manage/references/review-convergence.md +0 -9
  68. package/skills/rsp-release-docs/SKILL.md +0 -77
  69. package/skills/rsp-release-docs/references/convention-discovery.md +0 -65
  70. package/skills/rsp-release-docs/references/evidence-and-surfaces.md +0 -21
  71. package/skills/rsp-release-docs/references/output-contracts.md +0 -97
  72. package/skills/rsp-release-docs/references/publication-lifecycle.md +0 -28
  73. package/skills/rsp-resolve-findings/SKILL.md +0 -61
  74. package/skills/rsp-structural-audit/SKILL.md +0 -71
  75. package/skills/rsp-structural-audit/references/structural-lenses.md +0 -41
  76. package/skills/rsp-tdd/SKILL.md +0 -56
@@ -1,375 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- ManagedPathError,
4
- PKG_ROOT,
5
- emitJson,
6
- inspectManagedDirectory,
7
- inspectManagedFileTree,
8
- resolveManagedDirectoryChain
9
- } from "./chunk-7HXQNBIG.mjs";
10
-
11
- // src/cli/presenters/skills.ts
12
- function presentPackagedSkillInventory(inventory, json = false) {
13
- if (json) {
14
- emitJson(inventory);
15
- return;
16
- }
17
- console.log(` ${inventory.package.name}@${inventory.package.version}`);
18
- console.log(` target: ${inventory.target}`);
19
- for (const group of [
20
- { heading: "Default suite Skills", kind: "default" },
21
- { heading: "Optional project Skills", kind: "optional" }
22
- ]) {
23
- console.log("");
24
- console.log(` ${group.heading}`);
25
- const skills = inventory.skills.filter((skill) => skill.kind === group.kind);
26
- if (skills.length === 0)
27
- console.log(" none");
28
- for (const skill of skills)
29
- console.log(` ${skill.name} ${skill.status}`);
30
- }
31
- }
32
- function presentSkillInstallResult(result, dryRun = false) {
33
- const prefix = dryRun ? "would be " : "";
34
- for (const status of ["installed", "unchanged", "replaced", "removed"]) {
35
- if (result[status].length > 0)
36
- console.log(` ${prefix}${status}: ${result[status].join(", ")}`);
37
- }
38
- }
39
-
40
- // src/commands/skills.ts
41
- import { randomUUID } from "crypto";
42
- import { lstatSync, realpathSync } from "fs";
43
- import { chmod, copyFile, mkdir, readdir, readFile, rename, rm } from "fs/promises";
44
- import { dirname, join, relative } from "path";
45
- var DEFAULT_PACKAGED_SKILL_NAMES = [
46
- "rsp",
47
- "rsp-commit",
48
- "rsp-design",
49
- "rsp-diagnose",
50
- "rsp-implement",
51
- "rsp-manage",
52
- "rsp-release-docs",
53
- "rsp-resolve-findings",
54
- "rsp-review",
55
- "rsp-shape",
56
- "rsp-tdd",
57
- "rsp-verify"
58
- ];
59
- var OBSOLETE_PACKAGED_SKILL_RENAMES = {
60
- "rsp-address-review": "rsp-resolve-findings",
61
- "rsp-codebase-audit": "rsp-structural-audit"
62
- };
63
- function unsupportedEntry(path, label) {
64
- return new ManagedPathError(path, `unsupported entry in the ${label} tree: ${path}`);
65
- }
66
- function inspectDirectoryIdentity(path, label) {
67
- const inspection = inspectManagedDirectory(path, label);
68
- if (inspection.issue)
69
- throw inspection.issue;
70
- const stats = lstatSync(path);
71
- return { path, dev: stats.dev, ino: stats.ino };
72
- }
73
- function assertDirectoryIdentities(identities, label) {
74
- for (const identity of identities) {
75
- const current = inspectDirectoryIdentity(identity.path, label);
76
- if (current.dev !== identity.dev || current.ino !== identity.ino)
77
- throw new ManagedPathError(identity.path, `${label} changed after validation: ${identity.path}`);
78
- }
79
- }
80
- async function prepareTargetRoot(projectRoot, targetRoot) {
81
- const projectIdentity = inspectDirectoryIdentity(projectRoot, "project Skills root");
82
- const agentsRoot = join(projectRoot, ".agents");
83
- const identities = [projectIdentity];
84
- assertDirectoryIdentities(identities, "project Skills root");
85
- await mkdir(agentsRoot).catch((error) => {
86
- if (error.code !== "EEXIST")
87
- throw error;
88
- });
89
- assertDirectoryIdentities(identities, "project Skills root");
90
- identities.push(inspectDirectoryIdentity(agentsRoot, "project Skills root"));
91
- assertDirectoryIdentities(identities, "project Skills root");
92
- await mkdir(targetRoot).catch((error) => {
93
- if (error.code !== "EEXIST")
94
- throw error;
95
- });
96
- assertDirectoryIdentities(identities, "project Skills root");
97
- identities.push(inspectDirectoryIdentity(targetRoot, "project Skills root"));
98
- return identities;
99
- }
100
- async function inspectPackagedSkills(packageRoot) {
101
- const skillsRoot = join(packageRoot, "skills");
102
- const rootInspection = inspectManagedDirectory(skillsRoot, "packaged Skills root");
103
- if (rootInspection.issue)
104
- throw rootInspection.issue;
105
- const entries = await readdir(skillsRoot, { withFileTypes: true });
106
- const skills = [];
107
- for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
108
- if (entry.name.startsWith("."))
109
- continue;
110
- const root = join(skillsRoot, entry.name);
111
- if (!entry.isDirectory())
112
- throw unsupportedEntry(root, "packaged Skills");
113
- const inspection = await inspectManagedFileTree(root, `packaged Skill ${entry.name}`);
114
- if (inspection.issues.length > 0)
115
- throw inspection.issues[0];
116
- skills.push({
117
- name: entry.name,
118
- root,
119
- files: inspection.files.map((path) => relative(root, path))
120
- });
121
- }
122
- return skills;
123
- }
124
- function inspectTarget(path, name) {
125
- try {
126
- const stats = lstatSync(path);
127
- if (stats.isDirectory())
128
- return "directory";
129
- throw unsupportedEntry(path, `installed Skill ${name}`);
130
- } catch (error) {
131
- if (error.code === "ENOENT")
132
- return "missing";
133
- throw error;
134
- }
135
- }
136
- function inspectInventoryTarget(path) {
137
- try {
138
- return lstatSync(path).isDirectory() ? "directory" : "divergent";
139
- } catch (error) {
140
- if (error.code === "ENOENT")
141
- return "missing";
142
- throw error;
143
- }
144
- }
145
- function isCanonicalSourceProjection(sourceRoot, targetRoot) {
146
- try {
147
- if (!lstatSync(targetRoot).isSymbolicLink())
148
- return false;
149
- return realpathSync(targetRoot) === realpathSync(sourceRoot);
150
- } catch {
151
- return false;
152
- }
153
- }
154
- async function treesEqual(source, targetRoot) {
155
- const target = await inspectManagedFileTree(targetRoot, `installed Skill ${source.name}`);
156
- if (target.issues.length > 0)
157
- throw target.issues[0];
158
- const targetFiles = target.files.map((path) => relative(targetRoot, path));
159
- if (source.files.length !== targetFiles.length || source.files.some((path, index) => path !== targetFiles[index]))
160
- return false;
161
- for (const path of source.files) {
162
- const sourcePath = join(source.root, path);
163
- const targetPath = join(targetRoot, path);
164
- const [sourceStats, targetStats] = [lstatSync(sourcePath), lstatSync(targetPath)];
165
- if (!sourceStats.isFile() || !targetStats.isFile())
166
- throw unsupportedEntry(!sourceStats.isFile() ? sourcePath : targetPath, `Skill ${source.name}`);
167
- if ((sourceStats.mode & 511) !== (targetStats.mode & 511))
168
- return false;
169
- const [sourceContent, targetContent] = await Promise.all([readFile(sourcePath), readFile(targetPath)]);
170
- if (!sourceContent.equals(targetContent))
171
- return false;
172
- }
173
- return true;
174
- }
175
- async function inspectPackagedSkillInventory(options = {}) {
176
- const packageRoot = options.packageRoot ?? PKG_ROOT;
177
- const projectRoot = options.projectRoot ?? process.cwd();
178
- const packagedSkills = await inspectPackagedSkills(packageRoot);
179
- const packagedNames = new Set(packagedSkills.map((skill) => skill.name));
180
- const missingDefaults = DEFAULT_PACKAGED_SKILL_NAMES.filter((name) => !packagedNames.has(name));
181
- if (missingDefaults.length > 0)
182
- throw new Error(`packaged Skills missing default Skills: ${missingDefaults.join(", ")}`);
183
- const manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
184
- if (typeof manifest.name !== "string" || typeof manifest.version !== "string")
185
- throw new Error("package.json must contain string name and version fields");
186
- const targetRoot = resolveManagedDirectoryChain(projectRoot, [".agents", "skills"], "project Skills root");
187
- const defaults = new Set(DEFAULT_PACKAGED_SKILL_NAMES);
188
- const skills = [];
189
- for (const skill of packagedSkills) {
190
- const target = join(targetRoot, skill.name);
191
- const targetStatus = inspectInventoryTarget(target);
192
- skills.push({
193
- name: skill.name,
194
- kind: defaults.has(skill.name) ? "default" : "optional",
195
- status: targetStatus === "missing" ? "missing" : targetStatus === "divergent" ? isCanonicalSourceProjection(skill.root, target) ? "unchanged" : "divergent" : await treesEqual(skill, target) ? "unchanged" : "divergent"
196
- });
197
- }
198
- return {
199
- package: { name: manifest.name, version: manifest.version },
200
- target: relative(projectRoot, targetRoot) || ".",
201
- skills
202
- };
203
- }
204
- async function copySkillTree(source, targetRoot) {
205
- await mkdir(targetRoot, { recursive: true });
206
- for (const path of source.files) {
207
- const sourcePath = join(source.root, path);
208
- const targetPath = join(targetRoot, path);
209
- const stats = lstatSync(sourcePath);
210
- if (!stats.isFile())
211
- throw unsupportedEntry(sourcePath, `packaged Skill ${source.name}`);
212
- await mkdir(dirname(targetPath), { recursive: true });
213
- await copyFile(sourcePath, targetPath);
214
- await chmod(targetPath, stats.mode & 511);
215
- }
216
- }
217
- async function installPackagedSkills(args = {}, options = {}) {
218
- const packageRoot = options.packageRoot ?? PKG_ROOT;
219
- const projectRoot = options.projectRoot ?? process.cwd();
220
- const renamePath = options.renamePath ?? rename;
221
- const packagedSkills = await inspectPackagedSkills(packageRoot);
222
- const requestedNames = args.names?.length ? [...new Set(args.names)] : [...DEFAULT_PACKAGED_SKILL_NAMES];
223
- const packagedSkillsByName = new Map(packagedSkills.map((skill) => [skill.name, skill]));
224
- for (const name of requestedNames) {
225
- if (!packagedSkillsByName.has(name))
226
- throw new Error(`unknown packaged Skill: ${name}`);
227
- }
228
- const skills = requestedNames.map((name) => packagedSkillsByName.get(name)).sort((a, b) => a.name.localeCompare(b.name));
229
- const targetRoot = resolveManagedDirectoryChain(projectRoot, [".agents", "skills"], "project Skills root");
230
- const result = { installed: [], removed: [], unchanged: [], replaced: [] };
231
- const conflicts = [];
232
- const obsoleteConflicts = [];
233
- const targetTreeIdentities = /* @__PURE__ */ new Map();
234
- for (const skill of skills) {
235
- const target = join(targetRoot, skill.name);
236
- if (inspectTarget(target, skill.name) === "missing") {
237
- result.installed.push(skill.name);
238
- continue;
239
- }
240
- const targetIdentity = inspectDirectoryIdentity(target, `installed Skill ${skill.name}`);
241
- if (await treesEqual(skill, target)) {
242
- result.unchanged.push(skill.name);
243
- continue;
244
- }
245
- assertDirectoryIdentities([targetIdentity], `installed Skill ${skill.name}`);
246
- if (args.force) {
247
- result.replaced.push(skill.name);
248
- targetTreeIdentities.set(skill.name, targetIdentity);
249
- } else {
250
- conflicts.push(skill.name);
251
- }
252
- }
253
- const selectedNames = new Set(skills.map((skill) => skill.name));
254
- const obsoleteTreeIdentities = /* @__PURE__ */ new Map();
255
- for (const [obsolete, replacement] of Object.entries(OBSOLETE_PACKAGED_SKILL_RENAMES)) {
256
- if (!selectedNames.has(replacement))
257
- continue;
258
- const target = join(targetRoot, obsolete);
259
- if (inspectTarget(target, obsolete) === "missing")
260
- continue;
261
- const targetIdentity = inspectDirectoryIdentity(target, `obsolete installed Skill ${obsolete}`);
262
- assertDirectoryIdentities([targetIdentity], `obsolete installed Skill ${obsolete}`);
263
- if (args.force) {
264
- result.removed.push(obsolete);
265
- obsoleteTreeIdentities.set(obsolete, targetIdentity);
266
- } else {
267
- obsoleteConflicts.push(`${obsolete} -> ${replacement}`);
268
- }
269
- }
270
- const conflictMessages = [];
271
- if (conflicts.length > 0)
272
- conflictMessages.push(`conflicting packaged Skills: ${conflicts.join(", ")}`);
273
- if (obsoleteConflicts.length > 0)
274
- conflictMessages.push(`obsolete packaged Skill renames: ${obsoleteConflicts.join(", ")}`);
275
- if (conflictMessages.length > 0)
276
- throw new Error(`${conflictMessages.join("; ")}; rerun with --force to replace or remove only these package-owned directories`);
277
- if (args.dryRun)
278
- return result;
279
- await options.onMutationStep?.({ phase: "before-target-root-mutation", targetRoot });
280
- const targetIdentities = await prepareTargetRoot(projectRoot, targetRoot);
281
- const stagingRoot = join(targetRoot, `.rsp-skills-install-${randomUUID()}`);
282
- const nextRoot = join(stagingRoot, "next");
283
- const previousRoot = join(stagingRoot, "previous");
284
- const failedRoot = join(stagingRoot, "failed");
285
- const movedPrevious = [];
286
- const activated = [];
287
- let removeStaging = true;
288
- try {
289
- assertDirectoryIdentities(targetIdentities, "project Skills root");
290
- await mkdir(nextRoot, { recursive: true });
291
- await mkdir(previousRoot);
292
- await mkdir(failedRoot);
293
- for (const skill of skills) {
294
- if (result.unchanged.includes(skill.name))
295
- continue;
296
- await copySkillTree(skill, join(nextRoot, skill.name));
297
- }
298
- for (const name of result.installed) {
299
- const target = join(targetRoot, name);
300
- if (inspectTarget(target, name) !== "missing")
301
- throw new ManagedPathError(target, `installed Skill changed after preflight: ${target}`);
302
- }
303
- for (const name of result.replaced) {
304
- assertDirectoryIdentities([targetTreeIdentities.get(name)], `installed Skill ${name}`);
305
- }
306
- for (const name of result.removed) {
307
- assertDirectoryIdentities([obsoleteTreeIdentities.get(name)], `obsolete installed Skill ${name}`);
308
- }
309
- for (const name of result.removed) {
310
- assertDirectoryIdentities(targetIdentities, "project Skills root");
311
- assertDirectoryIdentities([obsoleteTreeIdentities.get(name)], `obsolete installed Skill ${name}`);
312
- await renamePath(join(targetRoot, name), join(previousRoot, name));
313
- movedPrevious.push(name);
314
- }
315
- for (const name of result.replaced) {
316
- assertDirectoryIdentities(targetIdentities, "project Skills root");
317
- assertDirectoryIdentities([targetTreeIdentities.get(name)], `installed Skill ${name}`);
318
- await renamePath(join(targetRoot, name), join(previousRoot, name));
319
- movedPrevious.push(name);
320
- }
321
- for (const name of [...result.installed, ...result.replaced].sort()) {
322
- const target = join(targetRoot, name);
323
- assertDirectoryIdentities(targetIdentities, "project Skills root");
324
- await options.onMutationStep?.({ phase: "before-activate", name, target });
325
- assertDirectoryIdentities(targetIdentities, "project Skills root");
326
- if (inspectTarget(target, name) !== "missing")
327
- throw new ManagedPathError(target, `installed Skill changed after preflight: ${target}`);
328
- await renamePath(join(nextRoot, name), target);
329
- activated.push(name);
330
- }
331
- } catch (error) {
332
- const rollbackErrors = [];
333
- for (const name of activated.reverse()) {
334
- const target = join(targetRoot, name);
335
- try {
336
- assertDirectoryIdentities(targetIdentities, "project Skills root");
337
- if (inspectTarget(target, name) === "directory")
338
- await renamePath(target, join(failedRoot, name));
339
- } catch (rollbackError) {
340
- rollbackErrors.push(rollbackError instanceof Error ? rollbackError.message : String(rollbackError));
341
- }
342
- }
343
- for (const name of movedPrevious.reverse()) {
344
- const target = join(targetRoot, name);
345
- const previous = join(previousRoot, name);
346
- try {
347
- assertDirectoryIdentities(targetIdentities, "project Skills root");
348
- await options.onMutationStep?.({ phase: "before-rollback-restore", name, target, previous });
349
- assertDirectoryIdentities(targetIdentities, "project Skills root");
350
- if (inspectTarget(target, name) !== "missing")
351
- throw new ManagedPathError(target, `cannot restore installed Skill because the target is occupied: ${target}`);
352
- await renamePath(previous, target);
353
- } catch (rollbackError) {
354
- rollbackErrors.push(rollbackError instanceof Error ? rollbackError.message : String(rollbackError));
355
- }
356
- }
357
- if (rollbackErrors.length > 0) {
358
- removeStaging = false;
359
- const message = error instanceof Error ? error.message : String(error);
360
- throw new Error(`${message}; rollback incomplete; recover original Skills from ${previousRoot}; ${rollbackErrors.join("; ")}`);
361
- }
362
- throw error;
363
- } finally {
364
- if (removeStaging)
365
- await rm(stagingRoot, { recursive: true, force: true });
366
- }
367
- return result;
368
- }
369
-
370
- export {
371
- presentPackagedSkillInventory,
372
- presentSkillInstallResult,
373
- inspectPackagedSkillInventory,
374
- installPackagedSkills
375
- };
@@ -1,174 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- inspectPackagedSkillInventory
4
- } from "./chunk-QM2UVPQK.mjs";
5
- import {
6
- openTerminalSession,
7
- truncateDisplay
8
- } from "./chunk-JOMFFQRG.mjs";
9
- import "./chunk-7HXQNBIG.mjs";
10
-
11
- // src/skills-tui/entry.tsx
12
- import process from "process";
13
- import { render } from "ink";
14
- import ReactRuntime from "react";
15
-
16
- // src/skills-tui/app.tsx
17
- import { Box, Text, useApp, useInput, useStdout } from "ink";
18
- import { useMemo, useState } from "react";
19
- import { jsx, jsxs } from "react/jsx-runtime";
20
- function SkillsApp({ initialWidth, inventory, messages, onComplete }) {
21
- const { exit } = useApp();
22
- const { stdout } = useStdout();
23
- const width = Math.max(40, initialWidth ?? stdout.columns ?? 80);
24
- const optional = useMemo(() => inventory.skills.filter((skill) => skill.kind === "optional"), [inventory]);
25
- const defaults = useMemo(() => inventory.skills.filter((skill) => skill.kind === "default"), [inventory]);
26
- const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
27
- const [cursor, setCursor] = useState(0);
28
- const [phase, setPhase] = useState("select");
29
- const finish = (selection) => {
30
- onComplete(selection);
31
- exit();
32
- };
33
- const selectedNames = () => [...defaults.map((skill) => skill.name), ...optional.filter((skill) => selected.has(skill.name)).map((skill) => skill.name)].sort();
34
- useInput((input, key) => {
35
- if (phase === "replace") {
36
- if (input.toLowerCase() === "y") {
37
- finish({ kind: "confirmed", names: selectedNames(), force: true });
38
- } else if (input.toLowerCase() === "n" || key.escape) {
39
- finish({ kind: "cancelled" });
40
- }
41
- return;
42
- }
43
- if (key.escape || input === "q" || key.ctrl && input === "c") {
44
- finish({ kind: "cancelled" });
45
- return;
46
- }
47
- if ((key.upArrow || input === "k") && optional.length > 0) {
48
- setCursor((value) => (value - 1 + optional.length) % optional.length);
49
- } else if ((key.downArrow || input === "j") && optional.length > 0) {
50
- setCursor((value) => (value + 1) % optional.length);
51
- } else if (input === " " && optional[cursor]) {
52
- const name = optional[cursor].name;
53
- setSelected((current) => {
54
- const next = new Set(current);
55
- if (next.has(name))
56
- next.delete(name);
57
- else
58
- next.add(name);
59
- return next;
60
- });
61
- } else if (key.return) {
62
- const names = selectedNames();
63
- const divergent = inventory.skills.some((skill) => names.includes(skill.name) && skill.status === "divergent");
64
- if (divergent)
65
- setPhase("replace");
66
- else
67
- finish({ kind: "confirmed", names, force: false });
68
- }
69
- });
70
- const status = (value) => messages[value];
71
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, children: [
72
- /* @__PURE__ */ jsx(Text, { bold: true, children: messages.title }),
73
- /* @__PURE__ */ jsx(Text, { children: truncateDisplay(`${inventory.package.name}@${inventory.package.version}`, width) }),
74
- /* @__PURE__ */ jsx(Text, { children: truncateDisplay(`${messages.target}: ${inventory.target}`, width) }),
75
- /* @__PURE__ */ jsx(Text, { children: " " }),
76
- /* @__PURE__ */ jsx(Text, { bold: true, children: messages.defaultHeading }),
77
- defaults.map((skill) => /* @__PURE__ */ jsx(Text, { children: truncateDisplay(` [x] ${skill.name} ${messages.locked} \xB7 ${status(skill.status)}`, width) }, skill.name)),
78
- /* @__PURE__ */ jsx(Text, { children: " " }),
79
- /* @__PURE__ */ jsx(Text, { bold: true, children: messages.optionalHeading }),
80
- optional.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${messages.none}` }),
81
- optional.map((skill, index) => /* @__PURE__ */ jsx(Text, { children: truncateDisplay(`${index === cursor ? "\u203A" : " "} ${selected.has(skill.name) ? "[x]" : "[ ]"} ${skill.name} ${status(skill.status)}`, width) }, skill.name)),
82
- /* @__PURE__ */ jsx(Text, { children: " " }),
83
- /* @__PURE__ */ jsx(Text, { color: phase === "replace" ? "yellow" : void 0, children: phase === "replace" ? messages.replaceTitle : messages.selectHelp }),
84
- phase === "replace" && /* @__PURE__ */ jsx(Text, { children: messages.replaceHelp })
85
- ] });
86
- }
87
-
88
- // src/skills-tui/messages.ts
89
- var skillsCatalogs = {
90
- "en": {
91
- title: "RSP Skill manager",
92
- target: "Target",
93
- defaultHeading: "Default suite Skills",
94
- optionalHeading: "Optional project Skills",
95
- missing: "missing",
96
- unchanged: "unchanged",
97
- divergent: "divergent",
98
- locked: "locked",
99
- none: "none",
100
- selectHelp: "\u2191/\u2193 move \xB7 Space select \xB7 Enter confirm \xB7 Esc cancel",
101
- replaceTitle: "Replace divergent selected Skills?",
102
- replaceHelp: "y replace \xB7 n cancel"
103
- },
104
- "zh-CN": {
105
- title: "RSP Skill \u7BA1\u7406\u5668",
106
- target: "\u76EE\u6807",
107
- defaultHeading: "\u9ED8\u8BA4\u5957\u4EF6 Skills",
108
- optionalHeading: "\u53EF\u9009\u9879\u76EE Skills",
109
- missing: "\u672A\u5B89\u88C5",
110
- unchanged: "\u4E00\u81F4",
111
- divergent: "\u6709\u5DEE\u5F02",
112
- locked: "\u9501\u5B9A",
113
- none: "\u65E0",
114
- selectHelp: "\u2191/\u2193 \u79FB\u52A8 \xB7 \u7A7A\u683C\u9009\u62E9 \xB7 \u56DE\u8F66\u786E\u8BA4 \xB7 Esc \u53D6\u6D88",
115
- replaceTitle: "\u66FF\u6362\u6240\u9009\u7684\u5DEE\u5F02 Skill\uFF1F",
116
- replaceHelp: "y \u66FF\u6362 \xB7 n \u53D6\u6D88"
117
- }
118
- };
119
-
120
- // src/skills-tui/entry.tsx
121
- var signalExitCodes = { SIGHUP: 129, SIGINT: 130, SIGTERM: 143 };
122
- var defaultRuntime = {
123
- inspect: inspectPackagedSkillInventory,
124
- render,
125
- openSession: openTerminalSession,
126
- host: process,
127
- reportError: (message) => console.error(message)
128
- };
129
- async function runSkillsTui(locale, runtime = defaultRuntime) {
130
- const screenReader = runtime.host.env.INK_SCREEN_READER === "true" || runtime.host.env.INK_SCREEN_READER === "1";
131
- const session = runtime.openSession(runtime.host.stdout, { screenReader });
132
- let instance;
133
- let selection = { kind: "cancelled" };
134
- const listeners = /* @__PURE__ */ new Map();
135
- let cleaned = false;
136
- const cleanup = () => {
137
- if (cleaned)
138
- return;
139
- cleaned = true;
140
- for (const [signal, listener] of listeners)
141
- runtime.host.off(signal, listener);
142
- listeners.clear();
143
- instance?.unmount();
144
- session.cleanup();
145
- };
146
- try {
147
- const inventory = await runtime.inspect();
148
- instance = runtime.render(ReactRuntime.createElement(SkillsApp, {
149
- inventory,
150
- messages: skillsCatalogs[locale],
151
- onComplete: (value) => {
152
- selection = value;
153
- }
154
- }), { exitOnCtrlC: false, patchConsole: false });
155
- for (const signal of Object.keys(signalExitCodes)) {
156
- const listener = () => {
157
- cleanup();
158
- runtime.host.exit(signalExitCodes[signal]);
159
- };
160
- listeners.set(signal, listener);
161
- runtime.host.once(signal, listener);
162
- }
163
- await instance.waitUntilExit();
164
- cleanup();
165
- return selection;
166
- } catch (error) {
167
- cleanup();
168
- runtime.reportError(` Error: ${error instanceof Error ? error.message : String(error)}`);
169
- return { kind: "error" };
170
- }
171
- }
172
- export {
173
- runSkillsTui
174
- };
@@ -1,48 +0,0 @@
1
- ---
2
- name: rsp-rules
3
- description: Minimal fallback protocol for Rules, Specs, and Plans driven development.
4
- ---
5
-
6
- # RSP fallback protocol
7
-
8
- This file is the minimal fallback protocol for agents that cannot load the `rsp` Skill. It is a compatibility and safety kernel, not a replacement for project instructions, installed Skills, or durable design documentation.
9
-
10
- ## Entry
11
-
12
- - Read the nearest `AGENTS.md` and relevant `CONTEXT.md` before RSP work. Use the root `CONTEXT-MAP.md` when present.
13
- - Apply this fallback before operating `.rsp/` only after the Core Skill is absent or cannot be used.
14
- - Treat each `focus.d/` marker path as the only current-focus source. A marker may contain a short optional Markdown Focus Capsule with Manager-accepted recovery pointers, but its prose never selects work or grants authority, acceptance, lifecycle, Git, or worker coordination. A valid non-empty v1 capsule contains only one leading `<!-- rsp-focus:v1 -->`, blank lines, exactly one non-empty single-line `Current`, `Evidence`, and `Next`, and at most one non-empty single-line `Resume check`; unknown non-empty lines or fields are invalid. Legacy unversioned content is warning-only compatibility and makes no structured recovery claim. For grouped work, read the sibling Group Brief before the explicitly focused child Change. Then read only the relevant Specs and Decision Records under the configured authoritative path.
15
- - If `focus.d/` is empty and the user has not provided a concrete task, ask what to work on or suggest `npx -y @oevery/rsp create <name>`. Do not infer current work from open Changes or filenames.
16
-
17
- ## Ownership
18
-
19
- - `changes/` owns open work, `archives/` owns completed history, `specs/` owns stable current facts, and the configured Decision Record path owns lasting rationale and tradeoffs.
20
- - A Change owns one executable outcome and its acceptance, Tasks, verification, and blockers. Executable WorkRefs are `<change>` or one direct `<group>/<change>` child. A Group Brief provides shared context but is not executable or focusable.
21
- - For a new inferred WorkRef, preserve explicit valid user input first, otherwise follow an explicit nearest project or domain naming convention, otherwise use ASCII lowercase kebab-case from stable domain or technical vocabulary. Language or locale settings never select or translate WorkRef language. Valid Unicode remains available through explicit input or project/domain convention, and existing identities are never renamed by later guidance.
22
- - Persist only `open` and `archived` lifecycle state. Readiness, blockers, routes, and acceptance remain derived from current artifacts and evidence. A Focus Capsule may project accepted current work, next action, evidence validity, and blockers for recovery without becoming lifecycle or controller state. Under `## Verify`, `### Required` owns acceptance-critical evidence and `### Optional` owns additional coverage; legacy unclassified items are Required. Incomplete Tasks, Required verification, or blockers fail the completion gate, while Optional omissions remain visible warnings.
23
- - Project-owned `AGENTS.md` and `CONTEXT.md` retain their own instruction and context authority. RSP does not replace them.
24
- - Prefer RSP commands for deterministic setup, status, validation, repair, focus, Spec-index, history, archive, and reopen operations. Invalid identity, structure, dependency, managed path, symlink, or incomplete inspection fails closed.
25
-
26
- ## One bounded action
27
-
28
- - Derive the next action from user intent, explicit authority, the selected WorkRef, its current Change and Group Brief when any, relevant durable facts, the worktree, and fresh status or verification evidence.
29
- - Perform at most one bounded ordinary Core action or one optional Discipline action against the same owner. A mutation requires one ready owner, an explicit boundary, settled acceptance criteria, and one decisive verification. Do not auto-continue a successor or widen the boundary because more work is visible.
30
- - When an optional Discipline Skill is unavailable, a compact manual fallback may cover only the same bounded owner and action. It never substitutes for a required managed worker, independent verification, unresolved product or authority decision, or missing acceptance.
31
- - When the next action is a read-only pass over a Change-declared evidence boundary, use `rsp-verify` when available. Verify owns the bounded result and evidence; Core retains routing, while Manage validates required results and derives acceptance and closeout. Any required identity or independence evidence comes from the host. If Verify is unavailable, a manual fallback may collect only the same declared evidence and must report the capability gap truthfully.
32
- - Before later mutation or a different WorkRef, rederive authority and inspect dirty product and durable-truth paths. Continue the same owner, use an explicitly authorized reopen or integration owner, or stop for boundary resolution when ownership overlaps or remains uncertain.
33
- - If the action becomes multi-owner, cross-boundary, dependent on managed coordination, or unsafe without an unavailable capability, stop. Return the missing capability or input, decisive evidence, next owner, and the condition for safe resumption.
34
-
35
- ## Durable routing
36
-
37
- - Route planned future design to the selected Change; stable implemented facts to the smallest authoritative Spec or explicitly authorized project context; lasting rationale to the configured Decision Record path when warranted; and temporary execution or continuation state to the response.
38
- - Keep a Change as a convergent current-plan and final-evidence snapshot, not an append-only execution log. Replace superseded plans and evidence; keep routine attempts, transcripts, and temporary probes out of durable artifacts.
39
- - Before archive, judge current-fact and rationale updates independently, then compress the Change to the delivered outcome, current design, completed Tasks, decisive final verification, unresolved blockers, and remaining risk. Required verification must pass; Optional omissions may remain as explicit coverage warnings. Reclassifying incomplete Required evidence as Optional changes acceptance and requires explicit owner authority plus fresh readiness and review. Change Spec deltas are never promoted automatically.
40
- - Use the response language for user-visible narration while preserving exact WorkRefs, paths, commands, headings, and machine values. Preserve each existing artifact's established language unless translation is explicitly authorized.
41
-
42
- ## Safety ceiling
43
-
44
- - This fallback does not emulate `rsp-manage`, ready-owner qualification, worker dispatch, convergence loops, managed resume, execution-environment selection, or configured closeout. Configuration selects no capability and grants no planning, product-mutation, lifecycle, Git, publication, deployment, approval, or human-acceptance authority. The fallback never selects, prepares, or integrates an execution environment; the host, user, and Git own execution location and cross-branch integration.
45
- - Do not create or repair command-owned RSP files directly. Do not create archives or restore archived content by editing files; use the owning RSP command only with explicit lifecycle authority.
46
- - This fallback never archives, closes a Group, stages, commits, tags, pushes, publishes, deploys, deletes unrelated work, or records external approval. Those actions require their own explicit authority and available owning capability.
47
- - On malformed or incomplete evidence, ambiguous focus or ownership, unresolved decisions, unavailable required capability, failed verification, or out-of-scope work, fail closed without mutation. State what was inspected, what is missing, who owns the next decision or action, and what evidence or authority permits resumption.
48
- - Return one outer `ControlOutcome` for the selected WorkRef with `mode: solo | delegated | coordinated`, `status: running | waiting | completed`, the current phase outcome or stop reason, decisive evidence, changed artifacts when present, next owner/action, and optional recovery. Status transitions are only `running -> waiting | completed` and `waiting -> running | completed`; route, strategy, lane result, acceptance, and closeout remain nested details or gates rather than peer statuses. This response is not durable truth or a second state store. The fallback reports these semantics but does not emulate Manage qualification, worker delegation, strategy selection, acceptance, or closeout.
@@ -1,12 +0,0 @@
1
- # Implementation evidence
2
-
3
- Load this reference only when implementation evidence is incomplete or failed and Core must select Diagnose, TDD, ordinary Implement, or Verify.
4
-
5
- Apply these routes in order:
6
-
7
- - **Diagnosis first:** diagnosis takes precedence over TDD for an evidenced but unexplained, conflicting, intermittent, or multi-layer failure. Use `rsp-diagnose` when available; its manual fallback reproduces, locates, and tests the smallest discriminating hypothesis. Do not encode an unexplained symptom as a guessed regression test.
8
- - **TDD when justified:** use `rsp-tdd` only when test-first is explicitly required by the user, Change, or project instructions, or when a concrete changed risk makes a pre-mutation RED materially safer; mere testability or being a fix does not qualify. Its manual fallback observes the focused RED, makes the minimum GREEN change, and refactors only while green.
9
- - **Ordinary implementation by default:** use `rsp-implement`, or the equivalent bounded edit and verification, once the behavior, cause, and owner are sufficiently evidenced.
10
- - **Verification as one bounded action:** use `rsp-verify` for a read-only pass over the Change-declared evidence boundary. Verify owns its result; Core retains routing and continuation, while Manage validates required results and derives acceptance and closeout. Any worker identity or independence evidence comes from the host, not Verify self-report.
11
-
12
- All branches return evidence, Tasks, Verify updates, and blockers to the same Change. Required verification proves acceptance or changed material risk; Optional verification adds environment, compatibility, scale, or confidence coverage. Fresh Required verification is mandatory, and optional omissions remain visible warnings.