reffy-cli 1.0.0 → 1.1.1
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 +20 -49
- package/dist/cli.js +58 -67
- package/dist/planning-workspace.js +36 -0
- package/package.json +13 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/RoskiDeluge/reffy-ts/actions/workflows/ci.yml)
|
|
6
6
|
|
|
7
|
-
Reffy is a CLI-first planning
|
|
7
|
+
Reffy is a CLI-first planning system for agent-friendly development workflows. It keeps ideation artifacts in straightforward version-controlled markdown files and manages formal planning files under `reffyspec/`.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -17,22 +17,22 @@ npm install -g reffy-cli@latest
|
|
|
17
17
|
Inside your project:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
+
cd your-project
|
|
20
21
|
reffy init
|
|
21
|
-
reffy bootstrap
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
Command summary:
|
|
25
25
|
|
|
26
|
-
- `reffy init`:
|
|
27
|
-
- `reffy bootstrap`:
|
|
28
|
-
- `reffy migrate`: migrates a legacy `.references/` workspace into
|
|
26
|
+
- `reffy init`: runs the canonical first-run setup flow, creates the `.reffy/` and `reffyspec/` structure, writes managed instructions, reindexes artifacts, and on first-run text output prints a copy/paste instruction for your agent harness.
|
|
27
|
+
- `reffy bootstrap`: compatibility alias for `reffy init`.
|
|
28
|
+
- `reffy migrate`: migrates a legacy `.references/` workspace into `.reffy/`.
|
|
29
29
|
- `reffy doctor`: diagnoses required Reffy setup and workspace health.
|
|
30
30
|
- `reffy reindex`: reconciles `.reffy/manifest.json` with `.reffy/artifacts` by adding missing files and removing stale entries.
|
|
31
31
|
- `reffy validate`: validates `.reffy/manifest.json` against manifest v1 contract.
|
|
32
32
|
- `reffy summarize`: generates a read-only handoff summary from indexed artifacts.
|
|
33
|
-
- `reffy plan create`: generates proposal
|
|
34
|
-
- `reffy plan validate|list|show|archive`:
|
|
35
|
-
- `reffy spec list|show`: inspects current spec state
|
|
33
|
+
- `reffy plan create`: generates proposal, task, design, and spec scaffolds from indexed Reffy artifacts.
|
|
34
|
+
- `reffy plan validate|list|show|archive`: manages the planning lifecycle under `reffyspec/`.
|
|
35
|
+
- `reffy spec list|show`: inspects current spec state under `reffyspec/`.
|
|
36
36
|
- `reffy diagram render`: renders Mermaid diagrams as SVG or ASCII, including spec-aware generation from compatible `spec.md` files.
|
|
37
37
|
|
|
38
38
|
Output modes:
|
|
@@ -59,22 +59,11 @@ reffy diagram render --input reffyspec/specs/auth/spec.md --format ascii
|
|
|
59
59
|
reffy diagram render --input reffyspec/specs/auth/spec.md --format svg --output .reffy/artifacts/auth-spec.svg
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
## Runtime Position
|
|
63
|
-
|
|
64
|
-
Reffy is the planning/runtime authority in this repository. `reffyspec/` is the native planning/spec surface that matches that runtime ownership.
|
|
65
|
-
|
|
66
|
-
That means:
|
|
67
|
-
|
|
68
|
-
1. Reffy owns ideation artifacts, planning scaffolds, inspection, validation, and archive lifecycle behavior.
|
|
69
|
-
2. The vendored fork at `.vendor/ReffySpec` is reference-only.
|
|
70
|
-
3. `reffyspec/` is canonical for active changes, archived changes, and current specs.
|
|
71
|
-
4. No external planning CLI is part of the normal workflow.
|
|
72
|
-
|
|
73
62
|
## Using Reffy With ReffySpec
|
|
74
63
|
|
|
75
64
|
A practical pattern is:
|
|
76
65
|
|
|
77
|
-
1. Use Reffy for ideation and context capture in `.reffy/`.
|
|
66
|
+
1. Use Reffy for ideation and context capture in `.reffy/artifacts/`.
|
|
78
67
|
2. Use Reffy to scaffold and manage planning files in `reffyspec/`.
|
|
79
68
|
3. Keep a clear traceable path from exploratory artifacts to formal specs.
|
|
80
69
|
4. Use Reffy commands for day-to-day workflow.
|
|
@@ -84,36 +73,9 @@ Reference implementation in this repo:
|
|
|
84
73
|
- `AGENTS.md`: contains both managed instruction blocks and encodes sequencing.
|
|
85
74
|
- `AGENTS.md`: Reffy block routes ideation/exploration requests to `@/.reffy/AGENTS.md`.
|
|
86
75
|
- `AGENTS.md`: ReffySpec block routes planning/proposal/spec requests to `@/reffyspec/AGENTS.md`.
|
|
87
|
-
- `.reffy/AGENTS.md`: defines
|
|
76
|
+
- `.reffy/AGENTS.md`: defines the artifact and ideation workflow.
|
|
88
77
|
- `reffyspec/AGENTS.md`: defines the ReffySpec planning/spec workflow conventions used in this repo.
|
|
89
|
-
- `
|
|
90
|
-
|
|
91
|
-
Practical connection pattern for any repo:
|
|
92
|
-
|
|
93
|
-
1. Run `reffy init` to install/refresh the Reffy instruction layer.
|
|
94
|
-
2. Keep ReffySpec instructions in the same root `AGENTS.md`.
|
|
95
|
-
3. During planning, cite only relevant Reffy artifacts from `.reffy/artifacts/` in your proposal/spec docs.
|
|
96
|
-
4. Prefer Reffy commands for day-to-day workflow.
|
|
97
|
-
|
|
98
|
-
## Current Boundary
|
|
99
|
-
|
|
100
|
-
The current project boundary is:
|
|
101
|
-
|
|
102
|
-
- Native Reffy ownership:
|
|
103
|
-
- `reffy plan create`
|
|
104
|
-
- `reffy plan validate`
|
|
105
|
-
- `reffy plan list`
|
|
106
|
-
- `reffy plan show`
|
|
107
|
-
- `reffy plan archive`
|
|
108
|
-
- `reffy spec list`
|
|
109
|
-
- `reffy spec show`
|
|
110
|
-
- Native ReffySpec surface:
|
|
111
|
-
- the on-disk `reffyspec/changes/` and `reffyspec/specs/` layout
|
|
112
|
-
- `reffyspec/AGENTS.md` as the planning/spec conventions file
|
|
113
|
-
- Unresolved runtime gaps:
|
|
114
|
-
- none identified for the normal local planning lifecycle in v1
|
|
115
|
-
|
|
116
|
-
That means the normal workflow is fully Reffy and ReffySpec native.
|
|
78
|
+
- `reffyspec/project.md`: captures durable project context for agents, including purpose, stack, architecture, conventions, and constraints.
|
|
117
79
|
|
|
118
80
|
## Develop
|
|
119
81
|
|
|
@@ -127,3 +89,12 @@ npm test
|
|
|
127
89
|
```
|
|
128
90
|
|
|
129
91
|
`npm install` runs this package's `prepare` step, which builds `dist/` automatically.
|
|
92
|
+
|
|
93
|
+
## Release Security
|
|
94
|
+
|
|
95
|
+
Reffy publishes from GitHub Actions using npm trusted publishing with provenance enabled.
|
|
96
|
+
|
|
97
|
+
To verify an installed package:
|
|
98
|
+
|
|
99
|
+
- Check the package provenance details on npm.
|
|
100
|
+
- Run `npm audit signatures` after install to verify registry signatures and available provenance attestations.
|
package/dist/cli.js
CHANGED
|
@@ -24,6 +24,10 @@ const REFFY_ASCII = [
|
|
|
24
24
|
"|_| \\___||_| |_| \\__, |",
|
|
25
25
|
" |___/ ",
|
|
26
26
|
].join("\n");
|
|
27
|
+
const BOOTSTRAP_AGENT_INSTRUCTION = [
|
|
28
|
+
'Please read `AGENTS.md` and help me fill out the project context template in `reffyspec/project.md`',
|
|
29
|
+
"with details about my project, tech stack, architecture, and conventions.",
|
|
30
|
+
].join(" ");
|
|
27
31
|
function buildReffyBlock(refsDirName) {
|
|
28
32
|
return `<!-- REFFY:START -->
|
|
29
33
|
# Reffy Instructions
|
|
@@ -355,6 +359,56 @@ function printBanner(mode) {
|
|
|
355
359
|
console.log("");
|
|
356
360
|
}
|
|
357
361
|
}
|
|
362
|
+
function shouldPrintBootstrapOnboarding(workspaceCreated, workspaceMigrated, planningCreated, planningMigrated) {
|
|
363
|
+
return workspaceCreated || workspaceMigrated || planningCreated || planningMigrated;
|
|
364
|
+
}
|
|
365
|
+
function printBootstrapOnboarding() {
|
|
366
|
+
console.log("");
|
|
367
|
+
console.log("Next step for your agent harness:");
|
|
368
|
+
console.log("Copy and paste this into your conversation with your chosen agent:");
|
|
369
|
+
console.log("");
|
|
370
|
+
console.log(BOOTSTRAP_AGENT_INSTRUCTION);
|
|
371
|
+
}
|
|
372
|
+
async function runSetupCommand(commandName, output, repoRoot) {
|
|
373
|
+
const workspace = await prepareCanonicalWorkspace(repoRoot);
|
|
374
|
+
const planning = await prepareCanonicalPlanningLayout(repoRoot);
|
|
375
|
+
const agents = await initAgents(repoRoot);
|
|
376
|
+
const store = new ReferencesStore(repoRoot);
|
|
377
|
+
const reindex = await store.reindexArtifacts();
|
|
378
|
+
const payload = {
|
|
379
|
+
status: "ok",
|
|
380
|
+
command: commandName,
|
|
381
|
+
workspace_mode: workspace.state.mode,
|
|
382
|
+
migrated_workspace: workspace.migrated,
|
|
383
|
+
created_workspace: workspace.created,
|
|
384
|
+
planning_mode: planning.state.mode,
|
|
385
|
+
migrated_planning_layout: planning.migrated,
|
|
386
|
+
created_planning_layout: planning.created,
|
|
387
|
+
...agents,
|
|
388
|
+
refs_dir: store.refsDir,
|
|
389
|
+
manifest_path: store.manifestPath,
|
|
390
|
+
reindex,
|
|
391
|
+
};
|
|
392
|
+
if (output === "json") {
|
|
393
|
+
printResult(output, payload);
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
if (workspace.message) {
|
|
397
|
+
console.log(workspace.message);
|
|
398
|
+
}
|
|
399
|
+
if (planning.message) {
|
|
400
|
+
console.log(planning.message);
|
|
401
|
+
}
|
|
402
|
+
console.log(`${commandName === "init" ? "Initialized" : "Bootstrapped"} ${store.refsDir}`);
|
|
403
|
+
console.log(`Updated ${agents.root_agents_path}`);
|
|
404
|
+
console.log(`Updated ${agents.reffy_agents_path}`);
|
|
405
|
+
console.log(`Updated ${agents.reffyspec_agents_path}`);
|
|
406
|
+
console.log(`Reindex: added=${String(reindex.added)} removed=${String(reindex.removed)} total=${String(reindex.total)}`);
|
|
407
|
+
if (shouldPrintBootstrapOnboarding(workspace.created, workspace.migrated, planning.created, planning.migrated)) {
|
|
408
|
+
printBootstrapOnboarding();
|
|
409
|
+
}
|
|
410
|
+
return 0;
|
|
411
|
+
}
|
|
358
412
|
function usage() {
|
|
359
413
|
return [
|
|
360
414
|
"Usage: reffy <command> [--repo PATH] [--output text|json]",
|
|
@@ -363,8 +417,8 @@ function usage() {
|
|
|
363
417
|
" --version Print the installed reffy package version.",
|
|
364
418
|
"",
|
|
365
419
|
"Commands:",
|
|
366
|
-
" init
|
|
367
|
-
" bootstrap
|
|
420
|
+
" init Run the canonical first-run setup flow and refresh managed instructions.",
|
|
421
|
+
" bootstrap Compatibility alias for init.",
|
|
368
422
|
" migrate Migrate a legacy .references workspace to the canonical .reffy layout.",
|
|
369
423
|
" doctor Diagnose required Reffy setup and optional tool availability.",
|
|
370
424
|
" reindex Scan .reffy/artifacts and add missing files to manifest.",
|
|
@@ -873,74 +927,11 @@ async function main() {
|
|
|
873
927
|
if (command === "init") {
|
|
874
928
|
printBanner(output);
|
|
875
929
|
const repoRoot = parseRepoArg(rest);
|
|
876
|
-
|
|
877
|
-
const planning = await prepareCanonicalPlanningLayout(repoRoot);
|
|
878
|
-
const agents = await initAgents(repoRoot);
|
|
879
|
-
const payload = {
|
|
880
|
-
status: "ok",
|
|
881
|
-
command: "init",
|
|
882
|
-
workspace_mode: workspace.state.mode,
|
|
883
|
-
migrated_workspace: workspace.migrated,
|
|
884
|
-
created_workspace: workspace.created,
|
|
885
|
-
planning_mode: planning.state.mode,
|
|
886
|
-
migrated_planning_layout: planning.migrated,
|
|
887
|
-
created_planning_layout: planning.created,
|
|
888
|
-
...agents,
|
|
889
|
-
};
|
|
890
|
-
if (output === "json") {
|
|
891
|
-
printResult(output, payload);
|
|
892
|
-
}
|
|
893
|
-
else {
|
|
894
|
-
if (workspace.message) {
|
|
895
|
-
console.log(workspace.message);
|
|
896
|
-
}
|
|
897
|
-
if (planning.message) {
|
|
898
|
-
console.log(planning.message);
|
|
899
|
-
}
|
|
900
|
-
console.log(`Updated ${agents.root_agents_path}`);
|
|
901
|
-
console.log(`Updated ${agents.reffy_agents_path}`);
|
|
902
|
-
console.log(`Updated ${agents.reffyspec_agents_path}`);
|
|
903
|
-
}
|
|
904
|
-
return 0;
|
|
930
|
+
return await runSetupCommand("init", output, repoRoot);
|
|
905
931
|
}
|
|
906
932
|
if (command === "bootstrap") {
|
|
907
933
|
const repoRoot = parseRepoArg(rest);
|
|
908
|
-
|
|
909
|
-
const planning = await prepareCanonicalPlanningLayout(repoRoot);
|
|
910
|
-
const agents = await initAgents(repoRoot);
|
|
911
|
-
const store = new ReferencesStore(repoRoot);
|
|
912
|
-
const reindex = await store.reindexArtifacts();
|
|
913
|
-
const payload = {
|
|
914
|
-
status: "ok",
|
|
915
|
-
command: "bootstrap",
|
|
916
|
-
workspace_mode: workspace.state.mode,
|
|
917
|
-
migrated_workspace: workspace.migrated,
|
|
918
|
-
created_workspace: workspace.created,
|
|
919
|
-
planning_mode: planning.state.mode,
|
|
920
|
-
migrated_planning_layout: planning.migrated,
|
|
921
|
-
created_planning_layout: planning.created,
|
|
922
|
-
...agents,
|
|
923
|
-
refs_dir: store.refsDir,
|
|
924
|
-
manifest_path: store.manifestPath,
|
|
925
|
-
reindex,
|
|
926
|
-
};
|
|
927
|
-
if (output === "json") {
|
|
928
|
-
printResult(output, payload);
|
|
929
|
-
}
|
|
930
|
-
else {
|
|
931
|
-
if (workspace.message) {
|
|
932
|
-
console.log(workspace.message);
|
|
933
|
-
}
|
|
934
|
-
if (planning.message) {
|
|
935
|
-
console.log(planning.message);
|
|
936
|
-
}
|
|
937
|
-
console.log(`Bootstrapped ${store.refsDir}`);
|
|
938
|
-
console.log(`Updated ${agents.root_agents_path}`);
|
|
939
|
-
console.log(`Updated ${agents.reffy_agents_path}`);
|
|
940
|
-
console.log(`Updated ${agents.reffyspec_agents_path}`);
|
|
941
|
-
console.log(`Reindex: added=${String(reindex.added)} removed=${String(reindex.removed)} total=${String(reindex.total)}`);
|
|
942
|
-
}
|
|
943
|
-
return 0;
|
|
934
|
+
return await runSetupCommand("bootstrap", output, repoRoot);
|
|
944
935
|
}
|
|
945
936
|
if (command === "migrate") {
|
|
946
937
|
const repoRoot = parseRepoArg(rest);
|
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { DEFAULT_PLANNING_DIRNAME, LEGACY_PLANNING_DIRNAME, detectPlanningState, resolveCanonicalPlanningDir, } from "./planning-paths.js";
|
|
4
|
+
const DEFAULT_PROJECT_CONTEXT_TEMPLATE = `# Project Context
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
[Describe your project's purpose and goals]
|
|
8
|
+
|
|
9
|
+
## Tech Stack
|
|
10
|
+
- [List your primary technologies]
|
|
11
|
+
- [e.g., TypeScript, React, Node.js]
|
|
12
|
+
|
|
13
|
+
## Project Conventions
|
|
14
|
+
|
|
15
|
+
### Code Style
|
|
16
|
+
[Describe your code style preferences, formatting rules, and naming conventions]
|
|
17
|
+
|
|
18
|
+
### Architecture Patterns
|
|
19
|
+
[Document your architectural decisions and patterns]
|
|
20
|
+
|
|
21
|
+
### Testing Strategy
|
|
22
|
+
[Explain your testing approach and requirements]
|
|
23
|
+
|
|
24
|
+
### Git Workflow
|
|
25
|
+
[Describe your branching strategy and commit conventions]
|
|
26
|
+
|
|
27
|
+
## Domain Context
|
|
28
|
+
[Add domain-specific knowledge that AI assistants need to understand]
|
|
29
|
+
|
|
30
|
+
## Important Constraints
|
|
31
|
+
[List any technical, business, or regulatory constraints]
|
|
32
|
+
|
|
33
|
+
## External Dependencies
|
|
34
|
+
[Document key external services, APIs, or systems]
|
|
35
|
+
`;
|
|
4
36
|
async function pathExists(targetPath) {
|
|
5
37
|
try {
|
|
6
38
|
await fs.access(targetPath);
|
|
@@ -12,12 +44,16 @@ async function pathExists(targetPath) {
|
|
|
12
44
|
}
|
|
13
45
|
async function ensureCanonicalPlanningStructure(repoRoot) {
|
|
14
46
|
const planningDir = resolveCanonicalPlanningDir(repoRoot);
|
|
47
|
+
const projectContextPath = path.join(planningDir, "project.md");
|
|
15
48
|
let created = false;
|
|
16
49
|
if (!(await pathExists(planningDir))) {
|
|
17
50
|
created = true;
|
|
18
51
|
}
|
|
19
52
|
await fs.mkdir(path.join(planningDir, "changes", "archive"), { recursive: true });
|
|
20
53
|
await fs.mkdir(path.join(planningDir, "specs"), { recursive: true });
|
|
54
|
+
if (!(await pathExists(projectContextPath))) {
|
|
55
|
+
await fs.writeFile(projectContextPath, DEFAULT_PROJECT_CONTEXT_TEMPLATE, "utf8");
|
|
56
|
+
}
|
|
21
57
|
return created;
|
|
22
58
|
}
|
|
23
59
|
export async function prepareCanonicalPlanningLayout(repoRoot) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reffy-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "CLI-first, framework-agnostic references workflow for any repo (TypeScript)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reffy",
|
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
"sdd"
|
|
13
13
|
],
|
|
14
14
|
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/RoskiDeluge/reffy.git"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/RoskiDeluge/reffy",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/RoskiDeluge/reffy/issues"
|
|
22
|
+
},
|
|
15
23
|
"type": "module",
|
|
16
24
|
"main": "dist/index.js",
|
|
17
25
|
"files": [
|
|
@@ -33,6 +41,10 @@
|
|
|
33
41
|
"engines": {
|
|
34
42
|
"node": ">=20"
|
|
35
43
|
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"provenance": true,
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
36
48
|
"dependencies": {
|
|
37
49
|
"beautiful-mermaid": "^0.1.3",
|
|
38
50
|
"mime-types": "^2.1.35",
|