opennori 0.1.1 → 0.1.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/.opennori/protocol.md +43 -43
- package/README.md +68 -48
- package/bin/{nori.js → opennori.js} +4 -1
- package/examples/opennori-self.json +41 -33
- package/package.json +3 -3
- package/src/cli.js +147 -81
package/.opennori/protocol.md
CHANGED
|
@@ -38,10 +38,10 @@ current gap, risk gate, and report.
|
|
|
38
38
|
| ID | Tool / entrypoint | User operation | User acceptance criterion | Passing threshold |
|
|
39
39
|
| --- | --- | --- | --- | --- |
|
|
40
40
|
| AC-P-1 | Editor / file browser | Open the active Nori Contract | The user understands goal, layered ACs, each status, and the current gap. | No chat history or implementation explanation required; understandable within 60 seconds. |
|
|
41
|
-
| AC-P-2 | CLI | Run `
|
|
42
|
-
| AC-P-3 | CLI | Run `
|
|
41
|
+
| AC-P-2 | CLI | Run `opennori check` | The user can reject technical implementation details masquerading as ACs. | Files, fields, commands, tests, or modules cannot be accepted as user ACs by themselves. |
|
|
42
|
+
| AC-P-3 | CLI | Run `opennori next` or `opennori status` | The user sees the current acceptance gap and completion answer, not a process-step list. | Output answers which AC is missing, whether complete, and whether human action is required. |
|
|
43
43
|
| AC-P-4 | CLI / report | Inspect a high-risk AC | The user sees that weak evidence cannot make it passing. | High-risk passing cannot rely only on agent self-summary. |
|
|
44
|
-
| AC-P-5 | CLI / Codex | Trigger `
|
|
44
|
+
| AC-P-5 | CLI / Codex | Trigger `opennori report` | The user sees goal, layered AC statuses, evidence summaries, current gap, intervention, and conclusion. | Report is organized by acceptance state and evidence, not process steps. |
|
|
45
45
|
| AC-P-6 | CLI / report | Inspect evidence basis | The user can tell what evidence supports passing, blocked, or waived ACs. | Report/status shows evidence summary, basis, confidence, and limitations, not only an agent conclusion. |
|
|
46
46
|
| AC-P-7 | CLI / report | Review evidence sources | The user can review evidence sources without constraining how the agent gathered them. | Sources can be commands, artifacts, URLs, screenshots, diffs, human confirmations, or other reviewable references. |
|
|
47
47
|
| AC-P-8 | CLI / report | Compare evidence basis types | The user can distinguish tool observations, human confirmations, artifact reviews, protocol checks, and agent observations. | Evidence basis is shown clearly and agent judgment is not disguised as tool or human verification. |
|
|
@@ -71,18 +71,18 @@ a durable workflow asset.
|
|
|
71
71
|
|
|
72
72
|
| ID | Tool / entrypoint | User operation | User acceptance criterion | Passing threshold |
|
|
73
73
|
| --- | --- | --- | --- | --- |
|
|
74
|
-
| AC-Z-1 | CLI | Run `
|
|
75
|
-
| AC-Z-2 | CLI | Run `
|
|
74
|
+
| AC-Z-1 | CLI | Run `opennori skill export` | The user gets a usable Codex Skill draft for OpenNori. | The Skill tells agents to drive work through resume, next, evidence, evaluate, status, and report. |
|
|
75
|
+
| AC-Z-2 | CLI | Run `opennori install` | The user can install OpenNori into a project without unexpected overwrites. | Install shows created/skipped assets; existing user content is not overwritten by default. |
|
|
76
76
|
| AC-Z-3 | Git / PR diff | Review the agent's changes | The user can separate acceptance evidence changes from implementation noise. | Summary defaults to AC status changes, evidence changes, and user impact. |
|
|
77
|
-
| AC-Z-4 | CLI | Run `
|
|
77
|
+
| AC-Z-4 | CLI | Run `opennori list` and select a goal | The user can see multiple active goals and choose one explicitly. | Multiple active goals are listed with status, gap, and paths; `--goal` selects the target. |
|
|
78
78
|
| AC-Z-5 | CLI | Archive a completed or blocked goal | The user removes it from active work while preserving evidence and report. | Active no longer lists the goal; contract, ledger, and report remain recoverable. |
|
|
79
79
|
| AC-Z-6 | Project file browser | Inspect the project after running OpenNori | The user sees OpenNori-owned state under `.opennori/` instead of a generic project `process/` directory. | Install, draft, brainstorm, report, and archive write OpenNori state under `.opennori/` by default. |
|
|
80
|
-
| AC-Z-7 | CLI / project file browser | Run `
|
|
81
|
-
| AC-Z-8 | CLI | Run `
|
|
82
|
-
| AC-Z-9 | CLI | Preview install with `
|
|
83
|
-
| AC-Z-10 | CLI | Apply force install | The user must preview and explicitly confirm destructive install actions before files are overwritten. | Real `
|
|
80
|
+
| AC-Z-7 | CLI / project file browser | Run `opennori install` | The user can inspect project OpenNori registration and judge version, managed entries, active goals, Skill status, and protocol capabilities. | Install output uses create, skip, overwrite, or update semantics; `.opennori/manifest.json` records version, managed files, active goals, Skill state, and capabilities. |
|
|
81
|
+
| AC-Z-8 | CLI | Run `opennori doctor` | The user can judge whether the project is `ready`, `needs-action`, or `broken`, and see the next recovery action. | Doctor checks `.opennori` structure, manifest consistency, active goal recoverability, Skill sync, CLI runtime, and recovery suggestions. |
|
|
82
|
+
| AC-Z-9 | CLI | Preview install with `opennori install --dry-run` | The user can judge what OpenNori would create, skip, update, or overwrite before writing to the project. | Install plan lists action, kind, managed status, write intent, destructive flag, and reason; dry-run reports zero actual writes. |
|
|
83
|
+
| AC-Z-10 | CLI | Apply force install | The user must preview and explicitly confirm destructive install actions before files are overwritten. | Real `opennori install --force` fails without confirmation; dry-run previews destructive overwrites; confirmed force install may write. |
|
|
84
84
|
| AC-Z-11 | CLI | Preview and apply uninstall | The user can uninstall OpenNori entry assets without losing acceptance state by default. | Uninstall plan shows removals and preserved state; real uninstall requires confirmation; `.opennori` state is deleted only with `--include-state --confirm`. |
|
|
85
|
-
| AC-Z-12 | CLI / Codex Skills | Install OpenNori Skill Pack | The agent gets focused OpenNori Skills for acceptance, evidence, Nori Profile, project health, and reporting while the user keeps using natural language. | `
|
|
85
|
+
| AC-Z-12 | CLI / Codex Skills | Install OpenNori Skill Pack | The agent gets focused OpenNori Skills for acceptance, evidence, Nori Profile, project health, and reporting while the user keeps using natural language. | `opennori skill export --pack` exposes the pack; `opennori install --skill` writes it; manifest records `skill_pack`; doctor detects missing or stale pack Skills. |
|
|
86
86
|
|
|
87
87
|
## Required Artifact Pair
|
|
88
88
|
|
|
@@ -116,10 +116,10 @@ Each active goal has:
|
|
|
116
116
|
- optional repo-local OpenNori Skill Pack state
|
|
117
117
|
- protocol capabilities exposed by this CLI
|
|
118
118
|
|
|
119
|
-
`
|
|
119
|
+
`opennori install` creates or refreshes the manifest. State-changing OpenNori commands refresh it when
|
|
120
120
|
`.opennori/` already exists.
|
|
121
121
|
|
|
122
|
-
`
|
|
122
|
+
`opennori install --dry-run` returns an install plan. The plan uses deterministic action semantics:
|
|
123
123
|
|
|
124
124
|
- `create`: missing OpenNori asset would be created
|
|
125
125
|
- `exists`: required OpenNori directory already exists
|
|
@@ -130,11 +130,11 @@ Each active goal has:
|
|
|
130
130
|
Each planned action also reports `kind`, `managed`, `would_write`, `will_write`, `destructive`,
|
|
131
131
|
and a short human-readable reason.
|
|
132
132
|
|
|
133
|
-
Real `
|
|
134
|
-
Run `
|
|
133
|
+
Real `opennori install --force` can overwrite OpenNori-managed files, so it requires explicit confirmation.
|
|
134
|
+
Run `opennori install --dry-run --force` first to inspect destructive actions, then rerun with
|
|
135
135
|
`--confirm` only if those writes are acceptable.
|
|
136
136
|
|
|
137
|
-
`
|
|
137
|
+
`opennori uninstall --dry-run` returns an uninstall plan. By default it removes entry assets such as the
|
|
138
138
|
repo-local OpenNori Skill and manifest, while preserving Nori Contracts, evidence records,
|
|
139
139
|
reports, archives, and brainstorms. Real uninstall requires `--confirm`. Deleting the whole `.opennori`
|
|
140
140
|
state directory requires both `--include-state` and `--confirm`.
|
|
@@ -151,8 +151,8 @@ the root `nori` Skill routes natural-language requests to focused Skills:
|
|
|
151
151
|
- `nori-project-health`: install, uninstall, doctor, manifest, and Skill Pack sync
|
|
152
152
|
- `nori-reporting`: status, report, current gap, user intervention, and changes
|
|
153
153
|
|
|
154
|
-
`
|
|
155
|
-
state, and `
|
|
154
|
+
`opennori install --skill` installs the pack under `.agents/skills/`. The manifest records `skill_pack`
|
|
155
|
+
state, and `opennori doctor` checks whether the pack is installed and in sync.
|
|
156
156
|
|
|
157
157
|
## Nori Profile
|
|
158
158
|
|
|
@@ -179,7 +179,7 @@ Completion rules:
|
|
|
179
179
|
- `avoid` blocks completion if violated.
|
|
180
180
|
|
|
181
181
|
Agents translate the user's natural-language preferences into profile records. Users should not
|
|
182
|
-
need to remember `
|
|
182
|
+
need to remember `opennori profile` commands.
|
|
183
183
|
|
|
184
184
|
## Status Model
|
|
185
185
|
|
|
@@ -239,34 +239,34 @@ all evidence through a narrow adapter taxonomy.
|
|
|
239
239
|
|
|
240
240
|
On every turn:
|
|
241
241
|
|
|
242
|
-
1. If the user wants to discuss, brainstorm, explore, or is not ready to define acceptance criteria, run `
|
|
242
|
+
1. If the user wants to discuss, brainstorm, explore, or is not ready to define acceptance criteria, run `opennori brainstorm --idea "<idea>" --root <repo> --json`.
|
|
243
243
|
2. Show only candidate acceptance directions and ask the user to choose or revise a direction. Brainstorm output is not a contract or completion evidence.
|
|
244
|
-
3. If the user chooses a candidate, run `
|
|
245
|
-
4. If the user starts with "use OpenNori" / "用 OpenNori 跑这个任务", run `
|
|
244
|
+
3. If the user chooses a candidate, run `opennori draft --from-brainstorm <brainstorm-id> --candidate <A|B|C> --root <repo> --json`.
|
|
245
|
+
4. If the user starts with "use OpenNori" / "用 OpenNori 跑这个任务", run `opennori draft --goal "<goal>" --root <repo> --json`.
|
|
246
246
|
5. Show the draft acceptance criteria and ask the user to approve or revise them.
|
|
247
|
-
6. After approval, run `
|
|
248
|
-
7. If the user states required Skills, preferred stacks, avoided tools, install policy, or execution constraints, run `
|
|
249
|
-
8. If the user revises a criterion later, run `
|
|
250
|
-
9. Run `
|
|
247
|
+
6. After approval, run `opennori approve --root <repo> --summary "<approval>" --json`.
|
|
248
|
+
7. If the user states required Skills, preferred stacks, avoided tools, install policy, or execution constraints, run `opennori profile add --root <repo> ... --json` and keep those items out of the user acceptance criteria.
|
|
249
|
+
8. If the user revises a criterion later, run `opennori criterion update --root <repo> --criterion <id> ... --json`; old evidence for the changed criterion is cleared.
|
|
250
|
+
9. Run `opennori resume --root <repo>` or `opennori next --root <repo>` to recover the active goal and current acceptance gap from repository files.
|
|
251
251
|
10. Work only to produce evidence for that gap.
|
|
252
|
-
11. Add acceptance evidence with `
|
|
253
|
-
12. Run `
|
|
252
|
+
11. Add acceptance evidence with `opennori evidence add`; choose any suitable verification method, but record basis, sources, reviewability, confidence, and limitations. Add profile compliance evidence with `opennori profile evidence` when profile items exist.
|
|
253
|
+
12. Run `opennori evaluate`.
|
|
254
254
|
13. Report acceptance state, profile compliance, and evidence, not implementation steps.
|
|
255
255
|
|
|
256
256
|
Useful commands:
|
|
257
257
|
|
|
258
|
-
- `
|
|
259
|
-
- `
|
|
260
|
-
- `
|
|
261
|
-
- `
|
|
262
|
-
- `
|
|
263
|
-
- `
|
|
264
|
-
- `
|
|
265
|
-
- `
|
|
266
|
-
- `
|
|
267
|
-
- `
|
|
268
|
-
- `
|
|
269
|
-
- `
|
|
270
|
-
- `
|
|
271
|
-
- `
|
|
272
|
-
- `
|
|
258
|
+
- `opennori brainstorm --idea "<idea>" --root <repo>`: create selectable acceptance directions before a contract exists.
|
|
259
|
+
- `opennori draft --goal "<goal>" --root <repo>`: create a draft Nori Contract that needs user approval.
|
|
260
|
+
- `opennori draft --from-brainstorm <brainstorm-id> --candidate <A|B|C> --root <repo>`: convert a selected brainstorm direction into a draft contract.
|
|
261
|
+
- `opennori approve --root <repo>`: mark the acceptance basis as approved so completion can be decided.
|
|
262
|
+
- `opennori criterion update --root <repo> --criterion <id> ...`: preserve a user revision as the new acceptance basis.
|
|
263
|
+
- `opennori evidence add --root <repo> --criterion <id> --kind <kind> --summary "<summary>" --result <passing|failing|blocked|waived> --basis <basis> --source '<json-or-label>' --reviewability "<how to review>" --limitations "<known limits>"`: attach user-understandable, reviewable evidence without forcing a fixed adapter.
|
|
264
|
+
- `opennori profile add --root <repo> --type <skill|stack|constraint> --name "<name>" --strength <must|prefer|avoid>`: record user execution preferences separately from ACs.
|
|
265
|
+
- `opennori profile evidence --root <repo> --item <item-id> --result <satisfied|violated|waived>`: record whether the agent followed the profile.
|
|
266
|
+
- `opennori profile show --root <repo>`: show profile compliance and blocking items.
|
|
267
|
+
- `opennori list --root <repo>`: list active OpenNori goals.
|
|
268
|
+
- `opennori install --root <repo>`: create or refresh project-local OpenNori assets and manifest.
|
|
269
|
+
- `opennori doctor --root <repo>`: inspect project OpenNori health and recovery actions.
|
|
270
|
+
- `opennori resume --root <repo>`: recover the active goal, current gap, completion answer, and intervention state.
|
|
271
|
+
- `opennori status --root <repo>`: answer whether the goal is complete and whether the user needs to act.
|
|
272
|
+
- `opennori report --root <repo>`: generate the human acceptance report.
|
package/README.md
CHANGED
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
# OpenNori
|
|
2
2
|
|
|
3
|
-
OpenNori.
|
|
3
|
+
OpenNori helps coding agents deliver results that humans can actually accept.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
You describe a goal and constraints in natural language. Nori turns that into a Nori Contract:
|
|
6
|
+
human-centered acceptance checks, evidence, and a completion report. The agent can still plan
|
|
7
|
+
internally, but OpenNori treats progress as proven only when the acceptance checks have reviewable
|
|
8
|
+
evidence.
|
|
8
9
|
|
|
9
|
-
##
|
|
10
|
+
## Why It Exists
|
|
11
|
+
|
|
12
|
+
AI agents often do a lot of work while leaving the user unsure whether the original goal is done.
|
|
13
|
+
OpenNori keeps the conversation centered on:
|
|
14
|
+
|
|
15
|
+
- what the user wants to achieve
|
|
16
|
+
- what the user can open, run, see, or judge
|
|
17
|
+
- what evidence supports each acceptance check
|
|
18
|
+
- what is still blocked or missing
|
|
19
|
+
- whether the goal is complete
|
|
20
|
+
|
|
21
|
+
OpenNori is not a phase system, task planner, or process archive. It borrows productization ideas
|
|
22
|
+
from mature agent workflow kits, but the main storyline stays acceptance, evidence, and completion
|
|
23
|
+
judgment.
|
|
24
|
+
|
|
25
|
+
## Try It
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx opennori
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For a project install:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -D opennori
|
|
35
|
+
npx opennori
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then talk to your agent:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
Use OpenNori for this project. Start from my goal, define a Nori Contract,
|
|
42
|
+
and keep working only from acceptance gaps until the report says whether it is complete.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## What Gets Added
|
|
46
|
+
|
|
47
|
+
OpenNori uses one project-local state directory:
|
|
10
48
|
|
|
11
49
|
```text
|
|
12
50
|
.opennori/
|
|
@@ -21,55 +59,37 @@ plan internally, but progress is determined by acceptance evidence.
|
|
|
21
59
|
brainstorms/
|
|
22
60
|
```
|
|
23
61
|
|
|
24
|
-
|
|
62
|
+
It does not create a `process/` directory as the main workflow surface.
|
|
63
|
+
|
|
64
|
+
## Core Commands
|
|
25
65
|
|
|
26
66
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
node ./bin/nori.js init examples/opennori-self.json --root . --json
|
|
36
|
-
node ./bin/nori.js resume --root . --json
|
|
37
|
-
node ./bin/nori.js next --root . --json
|
|
38
|
-
node ./bin/nori.js status --root . --json
|
|
39
|
-
node ./bin/nori.js criterion update --root . --criterion AC-P-1 --user-story "作为用户,我能判断当前验收缺口。" --json
|
|
40
|
-
node ./bin/nori.js evidence add --root . --criterion AC-P-1 --kind test-summary --summary "User can inspect the Nori Contract." --result passing --basis tool-observation --source '{"type":"command","label":"npm test","command":"npm test","outcome":"passed"}' --reviewability "User can rerun the command." --limitations "Does not prove visual UX." --json
|
|
41
|
-
node ./bin/nori.js profile add --root . --type skill --name design-taste-frontend --strength must --purpose "Use this Skill for the design read and theme token pass." --install-policy existing_only --json
|
|
42
|
-
node ./bin/nori.js profile add --root . --type stack --name radix-ui --strength prefer --purpose "Use accessible primitives for custom components." --install-policy ask_before_install --json
|
|
43
|
-
node ./bin/nori.js profile show --root . --json
|
|
44
|
-
node ./bin/nori.js profile evidence --root . --item skill-design-taste-frontend --result satisfied --summary "Agent used the required Skill before implementation." --json
|
|
45
|
-
node ./bin/nori.js evaluate --root . --json
|
|
46
|
-
node ./bin/nori.js report --root . --json
|
|
67
|
+
opennori bootstrap
|
|
68
|
+
opennori doctor --root .
|
|
69
|
+
opennori brainstorm --idea "Explore this goal" --root .
|
|
70
|
+
opennori draft --goal "Ship a user-visible result" --root .
|
|
71
|
+
opennori approve --root . --summary "User approved the acceptance checks."
|
|
72
|
+
opennori status --root .
|
|
73
|
+
opennori evidence add --root . --criterion AC-1 --kind review-result --summary "..." --result passing
|
|
74
|
+
opennori report --root .
|
|
47
75
|
```
|
|
48
76
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
project is `ready`, `needs-action`, or `broken`, with recovery actions for missing structure, stale
|
|
52
|
-
manifest data, broken active goals, and stale Skills.
|
|
53
|
-
|
|
54
|
-
`nori install --dry-run` returns an `install_plan` that shows each planned action, asset kind,
|
|
55
|
-
managed status, write intent, destructive overwrite flag, and reason. Dry-run plans report
|
|
56
|
-
`will_write: 0` so users can review install impact before applying it.
|
|
57
|
-
|
|
58
|
-
Real `nori install --force` requires `--confirm`. Preview destructive actions with
|
|
59
|
-
`nori install --force --dry-run --json` before applying a confirmed overwrite.
|
|
60
|
-
|
|
61
|
-
`nori uninstall --dry-run --json` previews removals. Default uninstall removes entry assets while
|
|
62
|
-
preserving active goals, evidence, reports, archives, and brainstorms; deleting `.opennori` state
|
|
63
|
-
requires `nori uninstall --include-state --confirm --json`.
|
|
77
|
+
Users should not need to memorize these commands. The OpenNori Skill Pack lets an agent map natural
|
|
78
|
+
language requests to the deterministic CLI state layer.
|
|
64
79
|
|
|
65
|
-
|
|
66
|
-
URLs, human confirmation, AW doctor, or any other useful signal. OpenNori only requires the submitted
|
|
67
|
-
evidence to be reviewable by the user: include a basis, one or more sources, reviewability,
|
|
68
|
-
confidence, and limitations when the evidence affects completion.
|
|
80
|
+
## Productized Boundaries
|
|
69
81
|
|
|
70
|
-
`
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
- `bootstrap` gives agents one short entry for readiness checks and first-time preview. Lower-level
|
|
83
|
+
`install`, `upgrade`, and `uninstall` still support preview-first workflows; destructive writes
|
|
84
|
+
require explicit confirmation.
|
|
85
|
+
- `doctor` reports whether project state is `ready`, `needs-action`, or `broken`, with recovery
|
|
86
|
+
actions.
|
|
87
|
+
- Nori Profile records required Skills, preferred stacks, avoided tools, and install policy without
|
|
88
|
+
turning those preferences into user acceptance checks.
|
|
89
|
+
- Evidence stays flexible: tests, screenshots, URLs, artifacts, logs, human confirmation, waivers, or
|
|
90
|
+
other reviewable sources can support an acceptance check.
|
|
91
|
+
- Context export can give review tools the current goal, checks, profile, evidence, and report, but
|
|
92
|
+
review tools do not take over the agent loop.
|
|
73
93
|
|
|
74
94
|
## Development
|
|
75
95
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { main } from "../src/cli.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
const commandArgs = args.length > 0 ? args : ["bootstrap"];
|
|
6
|
+
|
|
7
|
+
main(commandArgs).catch((error) => {
|
|
5
8
|
console.error(JSON.stringify({
|
|
6
9
|
ok: false,
|
|
7
10
|
error: {
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
{
|
|
18
18
|
"id": "AC-P-2",
|
|
19
19
|
"layer": "protocol",
|
|
20
|
-
"user_story": "作为用户,我运行
|
|
21
|
-
"measurement": "对当前 active goal 或故意写坏的验收草案运行
|
|
20
|
+
"user_story": "作为用户,我运行 opennori check 后,能知道验收标准是否仍然是用户视角,而不是技术实现清单。",
|
|
21
|
+
"measurement": "对当前 active goal 或故意写坏的验收草案运行 opennori check。",
|
|
22
22
|
"threshold": "“存在文件、字段、命令、测试通过、实现某模块”这类内容不能作为用户验收标准通过校验。",
|
|
23
23
|
"risk": "medium"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"id": "AC-P-3",
|
|
27
27
|
"layer": "protocol",
|
|
28
|
-
"user_story": "作为用户,我运行
|
|
29
|
-
"measurement": "运行
|
|
28
|
+
"user_story": "作为用户,我运行 opennori next 或 opennori status 后,看到的是当前验收缺口和完成判断,而不是任务步骤列表。",
|
|
29
|
+
"measurement": "运行 opennori next/status 并查看返回的 current_gap、completion 和 intervention。",
|
|
30
30
|
"threshold": "输出默认回答“当前差哪条 AC、是否完成、是否需要人类动作”,不把过程任务当作主线。",
|
|
31
31
|
"risk": "medium"
|
|
32
32
|
},
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
{
|
|
42
42
|
"id": "AC-P-5",
|
|
43
43
|
"layer": "protocol",
|
|
44
|
-
"user_story": "作为用户,我运行
|
|
45
|
-
"measurement": "运行
|
|
44
|
+
"user_story": "作为用户,我运行 opennori report 后,能看到目标、分层 AC 状态、证据摘要、当前缺口、是否需要我介入和结论。",
|
|
45
|
+
"measurement": "运行 opennori report 或让 Codex 生成 OpenNori 报告。",
|
|
46
46
|
"threshold": "报告默认围绕验收状态和证据组织,不把过程任务当作主线。",
|
|
47
47
|
"risk": "medium"
|
|
48
48
|
},
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"id": "AC-P-6",
|
|
51
51
|
"layer": "protocol",
|
|
52
52
|
"user_story": "作为用户,我查看 OpenNori 报告时,能知道每条通过、阻塞或豁免的 AC 是基于什么证据判断的。",
|
|
53
|
-
"measurement": "给 AC 添加不同来源的证据后运行
|
|
53
|
+
"measurement": "给 AC 添加不同来源的证据后运行 opennori report 或 opennori status。",
|
|
54
54
|
"threshold": "报告或状态输出展示证据摘要、判断基础、证据强度和剩余限制;不会只显示 agent 自我结论。",
|
|
55
55
|
"risk": "high"
|
|
56
56
|
},
|
|
@@ -97,16 +97,16 @@
|
|
|
97
97
|
{
|
|
98
98
|
"id": "AC-P-12",
|
|
99
99
|
"layer": "protocol",
|
|
100
|
-
"user_story": "作为用户,我运行
|
|
101
|
-
"measurement": "对包含“测试通过”“字段存在”等内部完成条件的验收草案运行
|
|
100
|
+
"user_story": "作为用户,我运行 opennori check 后,能发现 AC 是否缺少真实用户操作或可观察结果,而不是只检查是否以“作为用户”开头。",
|
|
101
|
+
"measurement": "对包含“测试通过”“字段存在”等内部完成条件的验收草案运行 opennori check,再对包含真实用户操作和报告结果的草案运行 opennori check。",
|
|
102
102
|
"threshold": "内部完成条件会被拒绝;包含用户运行、打开、查看、确认等操作,并说明用户能看到或判断什么结果的 AC 可以通过。",
|
|
103
103
|
"risk": "high"
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
"id": "AC-P-13",
|
|
107
107
|
"layer": "protocol",
|
|
108
|
-
"user_story": "作为用户,我打开
|
|
109
|
-
"measurement": "运行
|
|
108
|
+
"user_story": "作为用户,我打开 opennori report 后,能先看到完成结论、当前缺口和是否需要我介入,再查看详细 AC 表格。",
|
|
109
|
+
"measurement": "运行 opennori report 并阅读报告顶部内容,再向下查看 Acceptance Status 表格。",
|
|
110
110
|
"threshold": "报告在详细表格前显示 Decision Summary,包含 completion、current gap、user intervention 和 workflow status;blocked 报告也先显示需要用户采取的动作。",
|
|
111
111
|
"risk": "medium"
|
|
112
112
|
},
|
|
@@ -177,15 +177,15 @@
|
|
|
177
177
|
{
|
|
178
178
|
"id": "AC-Z-1",
|
|
179
179
|
"layer": "productization",
|
|
180
|
-
"user_story": "作为用户,我运行
|
|
181
|
-
"measurement": "运行
|
|
180
|
+
"user_story": "作为用户,我运行 opennori skill export 后,能得到可放入 Codex Skills 的 OpenNori 使用说明。",
|
|
181
|
+
"measurement": "运行 opennori skill export --json 并查看输出内容。",
|
|
182
182
|
"threshold": "输出说明能指导 agent 使用 resume、next、evidence、evaluate、status 和 report,不要求用户追踪过程任务。",
|
|
183
183
|
"risk": "medium"
|
|
184
184
|
},
|
|
185
185
|
{
|
|
186
186
|
"id": "AC-Z-2",
|
|
187
187
|
"layer": "productization",
|
|
188
|
-
"user_story": "作为用户,我运行
|
|
188
|
+
"user_story": "作为用户,我运行 opennori install 后,能把 OpenNori 放入当前项目的可用入口,并且不会意外覆盖已有内容。",
|
|
189
189
|
"measurement": "在一个已有项目中运行安装入口并查看安装结果。",
|
|
190
190
|
"threshold": "安装前能看到将创建或跳过的入口;已有内容默认不被覆盖;失败时说明用户需要做什么。",
|
|
191
191
|
"risk": "high"
|
|
@@ -201,8 +201,8 @@
|
|
|
201
201
|
{
|
|
202
202
|
"id": "AC-Z-4",
|
|
203
203
|
"layer": "productization",
|
|
204
|
-
"user_story": "作为用户,我运行
|
|
205
|
-
"measurement": "创建多个 active goals 后运行
|
|
204
|
+
"user_story": "作为用户,我运行 opennori list 后,能看到多个 active goals,并能明确选择要继续的目标。",
|
|
205
|
+
"measurement": "创建多个 active goals 后运行 opennori list,并用 --goal 指定 resume/status/report 的目标。",
|
|
206
206
|
"threshold": "多个目标不会被 agent 随机选择;用户能看见目标列表、状态、当前缺口和对应路径。",
|
|
207
207
|
"risk": "high"
|
|
208
208
|
},
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
"id": "AC-Z-5",
|
|
211
211
|
"layer": "productization",
|
|
212
212
|
"user_story": "作为用户,我运行归档入口后,completed 或 blocked 中保留报告,active 中不再出现这个目标。",
|
|
213
|
-
"measurement": "对 complete 或 blocked goal 执行归档,再运行
|
|
213
|
+
"measurement": "对 complete 或 blocked goal 执行归档,再运行 opennori list 并打开归档产物。",
|
|
214
214
|
"threshold": "归档不会丢失 Nori Contract、evidence record 或 report;active 列表只显示仍需推进的目标。",
|
|
215
215
|
"risk": "high"
|
|
216
216
|
},
|
|
@@ -218,23 +218,23 @@
|
|
|
218
218
|
"id": "AC-Z-6",
|
|
219
219
|
"layer": "productization",
|
|
220
220
|
"user_story": "作为用户,我在项目目录运行 OpenNori 后,能看到 OpenNori 状态集中在 .opennori 目录里,而不是散落到通用 process 目录。",
|
|
221
|
-
"measurement": "运行
|
|
221
|
+
"measurement": "运行 opennori install、draft、brainstorm、report 或 archive 后查看项目目录。",
|
|
222
222
|
"threshold": "OpenNori 默认只把协议、active goal、报告、归档和 brainstorm 写入 .opennori;不创建 process/acceptance 或 process/development-protocols。",
|
|
223
223
|
"risk": "medium"
|
|
224
224
|
},
|
|
225
225
|
{
|
|
226
226
|
"id": "AC-Z-7",
|
|
227
227
|
"layer": "productization",
|
|
228
|
-
"user_story": "作为用户,我运行
|
|
229
|
-
"measurement": "运行
|
|
228
|
+
"user_story": "作为用户,我运行 opennori install 后,能看到当前项目的 OpenNori 接入登记信息,并判断版本、托管入口、active goals 和 Skill 状态是否可信。",
|
|
229
|
+
"measurement": "运行 opennori install --dry-run 或 opennori install 后查看输出和项目中的接入登记。",
|
|
230
230
|
"threshold": "输出包含 create、skip、overwrite 或 update 语义;接入登记说明 OpenNori 版本、managed files、active goals、Skill 状态和协议能力;已有用户内容默认不被覆盖。",
|
|
231
231
|
"risk": "high"
|
|
232
232
|
},
|
|
233
233
|
{
|
|
234
234
|
"id": "AC-Z-8",
|
|
235
235
|
"layer": "productization",
|
|
236
|
-
"user_story": "作为用户,我运行
|
|
237
|
-
"measurement": "在已安装项目、缺少接入登记的项目或 active goal 异常的项目中运行
|
|
236
|
+
"user_story": "作为用户,我运行 opennori doctor 后,能判断当前项目是 ready、needs-action 还是 broken,并知道下一步修复动作。",
|
|
237
|
+
"measurement": "在已安装项目、缺少接入登记的项目或 active goal 异常的项目中运行 opennori doctor。",
|
|
238
238
|
"threshold": "输出包含整体健康状态、逐项检查结果、active goal 可恢复性、Skill 同步状态和可执行的 recovery 建议。",
|
|
239
239
|
"risk": "high"
|
|
240
240
|
},
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
"id": "AC-Z-9",
|
|
243
243
|
"layer": "productization",
|
|
244
244
|
"user_story": "作为用户,我预览 OpenNori 安装时,能判断每个项目入口会被创建、跳过、更新还是覆盖,并确认 dry-run 不会写入项目。",
|
|
245
|
-
"measurement": "运行
|
|
245
|
+
"measurement": "运行 opennori install --dry-run,查看 install plan,再检查项目文件是否未被写入。",
|
|
246
246
|
"threshold": "install plan 对每个入口显示 action、kind、managed、would_write、will_write、destructive 和 reason;dry-run 下 will_write 为 0;覆盖类动作必须被标记为 destructive。",
|
|
247
247
|
"risk": "high"
|
|
248
248
|
},
|
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
"id": "AC-Z-10",
|
|
251
251
|
"layer": "productization",
|
|
252
252
|
"user_story": "作为用户,我执行可能覆盖已有 OpenNori 入口的安装时,必须先看到预览并显式确认,才能真正写入项目。",
|
|
253
|
-
"measurement": "在已有 OpenNori 入口的项目中运行
|
|
253
|
+
"measurement": "在已有 OpenNori 入口的项目中运行 opennori install --force、opennori install --force --dry-run 和确认后的安装。",
|
|
254
254
|
"threshold": "未确认的真实 --force 安装会失败并提示先 dry-run;dry-run 可展示 destructive overwrite;只有带显式确认的 --force 才会执行覆盖写入。",
|
|
255
255
|
"risk": "high"
|
|
256
256
|
},
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
"id": "AC-Z-11",
|
|
259
259
|
"layer": "productization",
|
|
260
260
|
"user_story": "作为用户,我卸载 OpenNori 前,能预览将移除什么,并确认默认卸载不会丢失 active goals、证据、报告或归档。",
|
|
261
|
-
"measurement": "在已安装且有 active goal 的项目中运行
|
|
261
|
+
"measurement": "在已安装且有 active goal 的项目中运行 opennori uninstall --dry-run、未确认 uninstall、确认 uninstall 和 include-state uninstall。",
|
|
262
262
|
"threshold": "默认 uninstall plan 标明 entry assets 会被移除、验收状态会被 preserve;未确认真实卸载会失败;确认后只移除入口资产;只有显式 --include-state --confirm 才会删除 .opennori 状态目录。",
|
|
263
263
|
"risk": "high"
|
|
264
264
|
},
|
|
@@ -266,15 +266,15 @@
|
|
|
266
266
|
"id": "AC-Z-12",
|
|
267
267
|
"layer": "productization",
|
|
268
268
|
"user_story": "作为用户,我安装 OpenNori 后,agent 能获得一组职责清晰的 OpenNori Skills 来处理验收、证据、能力偏好、项目健康和报告,而我不需要记住这些 Skill 名。",
|
|
269
|
-
"measurement": "运行
|
|
269
|
+
"measurement": "运行 opennori skill export --pack、opennori install --skill 和 opennori doctor,查看 Skill Pack、manifest 和 doctor 结果。",
|
|
270
270
|
"threshold": "Skill Pack 包含总入口和 acceptance、evidence、capability-profile、project-health、reporting 子 Skill;install 会写入这些 Skill;manifest 记录 skill_pack;doctor 能发现缺失或不同步的 Skill。",
|
|
271
271
|
"risk": "high"
|
|
272
272
|
},
|
|
273
273
|
{
|
|
274
274
|
"id": "AC-Z-13",
|
|
275
275
|
"layer": "productization",
|
|
276
|
-
"user_story": "作为用户,我运行
|
|
277
|
-
"measurement": "分别制造缺失 Skill Pack、缺失 manifest、stale manifest 和损坏 active goal 的项目,然后运行
|
|
276
|
+
"user_story": "作为用户,我运行 opennori doctor 后,如果项目状态不健康,能直接看到一组可执行恢复动作。",
|
|
277
|
+
"measurement": "分别制造缺失 Skill Pack、缺失 manifest、stale manifest 和损坏 active goal 的项目,然后运行 opennori doctor。",
|
|
278
278
|
"threshold": "doctor 输出 status、失败 check、active_goal_issues 和 recovery_actions;recovery_actions 说明要运行的 OpenNori 命令或要检查的 .opennori/active 文件位置。",
|
|
279
279
|
"risk": "high"
|
|
280
280
|
},
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
"id": "AC-Z-14",
|
|
283
283
|
"layer": "productization",
|
|
284
284
|
"user_story": "作为用户,我让 agent 继续 OpenNori 工作时,不需要每轮都追问下一步是什么。",
|
|
285
|
-
"measurement": "运行
|
|
285
|
+
"measurement": "运行 opennori resume、opennori status、opennori next 和 opennori report,分别查看未完成、阻塞和已完成 goal 的输出。",
|
|
286
286
|
"threshold": "输出包含 next_recommendation 或顶部推荐动作;未完成时指向当前验收缺口,阻塞时指向需要用户介入的事项,完成时提示 agent 可进入下一轮 OpenNori loop。",
|
|
287
287
|
"risk": "high"
|
|
288
288
|
},
|
|
@@ -290,16 +290,24 @@
|
|
|
290
290
|
"id": "AC-Z-15",
|
|
291
291
|
"layer": "productization",
|
|
292
292
|
"user_story": "作为用户,我让 agent 记录验收证据时,不需要 agent 为常见来源手写复杂结构。",
|
|
293
|
-
"measurement": "运行
|
|
293
|
+
"measurement": "运行 opennori evidence add,分别使用 --source-command、--source-path、--source-url 和自由 --source 记录证据,再查看 status/report。",
|
|
294
294
|
"threshold": "证据来源能显示为 command、artifact、url 或自由 reference;report/status 中仍保留 basis、reviewability、limitations 和 confidence。",
|
|
295
295
|
"risk": "medium"
|
|
296
296
|
},
|
|
297
297
|
{
|
|
298
298
|
"id": "AC-Z-16",
|
|
299
299
|
"layer": "productization",
|
|
300
|
-
"user_story": "作为用户,我通过 npm 获取 OpenNori
|
|
301
|
-
"measurement": "
|
|
302
|
-
"threshold": "npm
|
|
300
|
+
"user_story": "作为用户,我通过 npm 获取 OpenNori 后,能用 npx opennori 这个短入口开始,而不需要理解 install、root、dry-run 或 Skill Pack 参数。",
|
|
301
|
+
"measurement": "在全新临时项目中运行 npx opennori 或本地等价 opennori bin,再确认 bootstrap 后运行 opennori doctor。",
|
|
302
|
+
"threshold": "npm 包只提供 opennori 这个 bin;短入口默认只返回首次接入 preview 且不写入项目;显式确认后才创建 .opennori 和项目 Skill Pack;doctor 为 ready。",
|
|
303
|
+
"risk": "high"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"id": "AC-Z-17",
|
|
307
|
+
"layer": "productization",
|
|
308
|
+
"user_story": "作为用户,我第一次打开 README 或官网 Quick Start 时,能看到短到可以直接复制的 npx opennori 入口,而不是一串内部安装参数。",
|
|
309
|
+
"measurement": "阅读 README Try It 和官网首屏 Quick Start / Start 区域。",
|
|
310
|
+
"threshold": "README 和官网第一眼 Quick Start 展示 npx opennori;更详细的 opennori bootstrap、install、dry-run、confirm 只作为 agent 或高级用户的底层安全路径出现。",
|
|
303
311
|
"risk": "high"
|
|
304
312
|
}
|
|
305
313
|
]
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opennori",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "OpenNori: human-centered Nori Contracts and evidence records for coding agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
7
|
+
"opennori": "bin/opennori.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
".opennori/protocol.md",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
],
|
|
17
17
|
"scripts": {
|
|
18
18
|
"test": "node --test",
|
|
19
|
-
"check": "node --test && node ./bin/
|
|
19
|
+
"check": "node --test && node ./bin/opennori.js doctor --json"
|
|
20
20
|
},
|
|
21
21
|
"publishConfig": {
|
|
22
22
|
"access": "public"
|
package/src/cli.js
CHANGED
|
@@ -41,6 +41,7 @@ const NORI_CAPABILITIES = [
|
|
|
41
41
|
"capability-profile",
|
|
42
42
|
"profile-check",
|
|
43
43
|
"archive",
|
|
44
|
+
"bootstrap",
|
|
44
45
|
"report",
|
|
45
46
|
"doctor",
|
|
46
47
|
"upgrade",
|
|
@@ -384,7 +385,8 @@ function hasFlag(args, name) {
|
|
|
384
385
|
return args.includes(name);
|
|
385
386
|
}
|
|
386
387
|
|
|
387
|
-
const
|
|
388
|
+
const CLI_NAME = "opennori";
|
|
389
|
+
const TOP_LEVEL_USAGE = `${CLI_NAME} <bootstrap|doctor|install|upgrade|uninstall|brainstorm|draft|init|list|check|approve|criterion|profile|resume|next|evidence|evaluate|status|report|context|changes|archive|skill>`;
|
|
388
390
|
|
|
389
391
|
function wantsHelp(args) {
|
|
390
392
|
return args.includes("--help") || args.includes("-h");
|
|
@@ -393,25 +395,26 @@ function wantsHelp(args) {
|
|
|
393
395
|
function usageFor(args) {
|
|
394
396
|
const [command, subcommand] = args;
|
|
395
397
|
if (!command || command === "--help" || command === "-h") return TOP_LEVEL_USAGE;
|
|
396
|
-
if (command === "
|
|
397
|
-
if (command === "
|
|
398
|
-
if (command === "
|
|
399
|
-
if (command === "
|
|
400
|
-
if (command === "
|
|
401
|
-
if (command === "
|
|
402
|
-
if (command === "
|
|
403
|
-
if (command === "
|
|
404
|
-
if (command === "
|
|
405
|
-
if (command === "profile" && subcommand === "
|
|
406
|
-
if (command === "profile") return
|
|
407
|
-
if (command === "
|
|
408
|
-
if (command === "evidence") return
|
|
409
|
-
if (command === "
|
|
410
|
-
if (command === "context") return
|
|
411
|
-
if (command === "
|
|
412
|
-
if (command === "skill") return
|
|
398
|
+
if (command === "bootstrap") return `${CLI_NAME} bootstrap --root <project> [--confirm] [--json]`;
|
|
399
|
+
if (command === "install") return `${CLI_NAME} install --root <project> [--skill] [--dry-run] [--force] [--confirm] [--json]`;
|
|
400
|
+
if (command === "upgrade") return `${CLI_NAME} upgrade --root <project> [--skill] [--dry-run] [--confirm] [--json]`;
|
|
401
|
+
if (command === "uninstall") return `${CLI_NAME} uninstall --root <project> [--include-state] [--dry-run] [--confirm] [--json]`;
|
|
402
|
+
if (command === "doctor") return `${CLI_NAME} doctor --root <project> [--json]`;
|
|
403
|
+
if (command === "brainstorm") return `${CLI_NAME} brainstorm --idea "<idea>" --root <project> [--id <id>] [--json]`;
|
|
404
|
+
if (command === "draft") return `${CLI_NAME} draft --goal "<goal>" --root <project> [--goal-id <id>] [--json]`;
|
|
405
|
+
if (command === "init") return `${CLI_NAME} init <brief.json> --root <project> [--json]`;
|
|
406
|
+
if (command === "criterion" && subcommand === "update") return `${CLI_NAME} criterion update --root <project> --criterion <id> --user-story ... --measurement ... --threshold ... [--json]`;
|
|
407
|
+
if (command === "profile" && subcommand === "add") return `${CLI_NAME} profile add --root <project> --type <skill|stack|constraint> --name <name> --strength <must|prefer|avoid> --purpose <purpose> [--json]`;
|
|
408
|
+
if (command === "profile" && subcommand === "evidence") return `${CLI_NAME} profile evidence --root <project> --item <item-id> --result <satisfied|violated|waived> --summary <summary> [--json]`;
|
|
409
|
+
if (command === "profile") return `${CLI_NAME} profile <add|evidence|show|check> --root <project> [--json]`;
|
|
410
|
+
if (command === "evidence" && subcommand === "add") return `${CLI_NAME} evidence add --root <project> --criterion <id> --kind <kind> --summary <summary> --result <passing|failing|blocked|waived> [--json]`;
|
|
411
|
+
if (command === "evidence") return `${CLI_NAME} evidence add --root <project> --criterion <id> --kind <kind> --summary <summary> --result <passing|failing|blocked|waived> [--json]`;
|
|
412
|
+
if (command === "context" && subcommand === "export") return `${CLI_NAME} context export --root <project> [--json]`;
|
|
413
|
+
if (command === "context") return `${CLI_NAME} context export --root <project> [--json]`;
|
|
414
|
+
if (command === "skill" && subcommand === "export") return `${CLI_NAME} skill export [--pack] [--json]`;
|
|
415
|
+
if (command === "skill") return `${CLI_NAME} skill export [--pack] [--json]`;
|
|
413
416
|
if (["list", "check", "approve", "resume", "next", "evaluate", "status", "report", "changes", "archive"].includes(command)) {
|
|
414
|
-
return
|
|
417
|
+
return `${CLI_NAME} ${command} --root <project> [--goal <goal-id>] [--json]`;
|
|
415
418
|
}
|
|
416
419
|
return TOP_LEVEL_USAGE;
|
|
417
420
|
}
|
|
@@ -477,9 +480,10 @@ const SKILL_PACK = [
|
|
|
477
480
|
"- Status, report, current gap, completion answer, user intervention, or change summary -> use `nori-reporting`.",
|
|
478
481
|
"",
|
|
479
482
|
"## Baseline",
|
|
480
|
-
"At the start of each OpenNori turn, run `
|
|
483
|
+
"At the start of each OpenNori turn, run `opennori bootstrap --root <repo> --json` if project readiness is unknown; otherwise run `opennori resume --root <repo> --json` or `opennori status --root <repo> --json`.",
|
|
484
|
+
"If bootstrap returns `needs_confirm`, show the preview briefly and ask the user before rerunning with `--confirm`.",
|
|
481
485
|
"Use `next_recommendation` and top-level `next_actions` to continue the OpenNori loop; do not make the user repeatedly ask what the next step is.",
|
|
482
|
-
"If `
|
|
486
|
+
"If `opennori` is not on PATH, use the installed package binary such as `node ./node_modules/opennori/bin/opennori.js` or this repository's `node ./bin/opennori.js` with the same arguments.",
|
|
483
487
|
"",
|
|
484
488
|
"## Rule",
|
|
485
489
|
"Progress is determined by acceptance evidence, not implementation steps.",
|
|
@@ -495,11 +499,11 @@ const SKILL_PACK = [
|
|
|
495
499
|
"Use when the user gives a goal, wants to brainstorm acceptance directions, approves criteria, revises completion criteria, or says the AC is wrong.",
|
|
496
500
|
"",
|
|
497
501
|
"## Commands",
|
|
498
|
-
"- Fuzzy idea or discussion: `
|
|
499
|
-
"- Start from a goal: `
|
|
500
|
-
"- Start from a chosen brainstorm candidate: `
|
|
501
|
-
"- User approves criteria: `
|
|
502
|
-
"- User revises a criterion: `
|
|
502
|
+
"- Fuzzy idea or discussion: `opennori brainstorm --idea \"<idea>\" --root <repo> --json`.",
|
|
503
|
+
"- Start from a goal: `opennori draft --goal \"<goal>\" --root <repo> --json`.",
|
|
504
|
+
"- Start from a chosen brainstorm candidate: `opennori draft --from-brainstorm <brainstorm-id> --candidate <A|B|C> --root <repo> --json`.",
|
|
505
|
+
"- User approves criteria: `opennori approve --root <repo> --summary \"<approval>\" --json`.",
|
|
506
|
+
"- User revises a criterion: `opennori criterion update --root <repo> --criterion <id> --user-story ... --measurement ... --threshold ... --json`.",
|
|
503
507
|
"",
|
|
504
508
|
"## Rules",
|
|
505
509
|
"ACs must describe user actions or judgments, not implementation files, commands, modules, fields, tests, Skills, or technology choices.",
|
|
@@ -519,7 +523,7 @@ const SKILL_PACK = [
|
|
|
519
523
|
"When submitting evidence, explain basis, sources, reviewability, confidence, and limitations.",
|
|
520
524
|
"",
|
|
521
525
|
"## Command",
|
|
522
|
-
"`
|
|
526
|
+
"`opennori evidence add --root <repo> --criterion <id> --kind <kind> --summary \"...\" --result <passing|failing|blocked|waived> --basis <basis> --source '<json-or-label>' --source-command '<command>' --source-path '<path>' --source-url '<url>' --reviewability \"...\" --limitations \"...\" --json`",
|
|
523
527
|
"",
|
|
524
528
|
"Use multiple source flags when one AC is supported by several signals; prefer typed `--source-command`, `--source-path`, or `--source-url` when they fit, and use raw `--source` for anything else.",
|
|
525
529
|
"For high-risk passing evidence, use a strong evidence kind or explicit strong confidence only when justified.",
|
|
@@ -534,9 +538,9 @@ const SKILL_PACK = [
|
|
|
534
538
|
"Use when the user says a task must use a Skill, prefers a technology stack, wants to avoid a tool/library, or requires asking before installs.",
|
|
535
539
|
"",
|
|
536
540
|
"## Commands",
|
|
537
|
-
"- Add preference: `
|
|
538
|
-
"- Add compliance evidence: `
|
|
539
|
-
"- Show profile: `
|
|
541
|
+
"- Add preference: `opennori profile add --root <repo> --type <skill|stack|constraint> --name \"<name>\" --strength <must|prefer|avoid> --purpose \"<why>\" --install-policy <existing_only|ask_before_install|allowed> --json`.",
|
|
542
|
+
"- Add compliance evidence: `opennori profile evidence --root <repo> --item <item-id> --result <satisfied|violated|waived> --summary \"<evidence>\" --json`.",
|
|
543
|
+
"- Show profile: `opennori profile show --root <repo> --json`.",
|
|
540
544
|
"",
|
|
541
545
|
"## Rules",
|
|
542
546
|
"Do not turn Skills or stack preferences into user ACs.",
|
|
@@ -552,14 +556,16 @@ const SKILL_PACK = [
|
|
|
552
556
|
"Use when the user asks to install OpenNori, uninstall OpenNori, check whether OpenNori is ready, diagnose broken OpenNori state, inspect manifest, or sync project Skills.",
|
|
553
557
|
"",
|
|
554
558
|
"## Commands",
|
|
555
|
-
"-
|
|
556
|
-
"-
|
|
557
|
-
"- Preview
|
|
558
|
-
"-
|
|
559
|
-
"-
|
|
560
|
-
"-
|
|
561
|
-
"-
|
|
562
|
-
"-
|
|
559
|
+
"- Short readiness / first-time preview: `opennori bootstrap --root <repo> --json`.",
|
|
560
|
+
"- Confirm first-time setup after user approval: `opennori bootstrap --root <repo> --confirm --json`.",
|
|
561
|
+
"- Preview install: `opennori install --root <repo> --dry-run --json`.",
|
|
562
|
+
"- Install Skill Pack: `opennori install --root <repo> --skill --json`.",
|
|
563
|
+
"- Preview destructive install: `opennori install --root <repo> --skill --force --dry-run --json`.",
|
|
564
|
+
"- Confirm destructive install: `opennori install --root <repo> --skill --force --confirm --json`.",
|
|
565
|
+
"- Doctor: `opennori doctor --root <repo> --json`.",
|
|
566
|
+
"- Preview uninstall: `opennori uninstall --root <repo> --dry-run --json`.",
|
|
567
|
+
"- Remove entry assets while preserving state: `opennori uninstall --root <repo> --confirm --json`.",
|
|
568
|
+
"- Remove all OpenNori state only after explicit user acceptance: `opennori uninstall --root <repo> --include-state --confirm --json`.",
|
|
563
569
|
"",
|
|
564
570
|
"## Rules",
|
|
565
571
|
"Always show dry-run plans before destructive writes.",
|
|
@@ -574,12 +580,12 @@ const SKILL_PACK = [
|
|
|
574
580
|
"Use when the user asks whether work is complete, what remains, what they need to do, what changed, or asks for an OpenNori report.",
|
|
575
581
|
"",
|
|
576
582
|
"## Commands",
|
|
577
|
-
"- Resume: `
|
|
578
|
-
"- Next gap: `
|
|
579
|
-
"- Status: `
|
|
580
|
-
"- Report: `
|
|
581
|
-
"- Changes: `
|
|
582
|
-
"- List goals: `
|
|
583
|
+
"- Resume: `opennori resume --root <repo> --json`.",
|
|
584
|
+
"- Next gap: `opennori next --root <repo> --json`.",
|
|
585
|
+
"- Status: `opennori status --root <repo> --json`.",
|
|
586
|
+
"- Report: `opennori report --root <repo> --json`.",
|
|
587
|
+
"- Changes: `opennori changes --root <repo> --json`.",
|
|
588
|
+
"- List goals: `opennori list --root <repo> --json`.",
|
|
583
589
|
"",
|
|
584
590
|
"## Rules",
|
|
585
591
|
"Lead with completion state, current gap, evidence basis, and required human intervention.",
|
|
@@ -732,7 +738,7 @@ function protocolTemplate() {
|
|
|
732
738
|
"",
|
|
733
739
|
"Progress is determined by human-centered acceptance evidence, not by implementation steps.",
|
|
734
740
|
"",
|
|
735
|
-
"Use `
|
|
741
|
+
"Use `opennori init`, `opennori resume`, `opennori next`, `opennori evidence add`, `opennori evaluate`, `opennori status`, and `opennori report`.",
|
|
736
742
|
""
|
|
737
743
|
].join("\n");
|
|
738
744
|
}
|
|
@@ -1084,7 +1090,7 @@ function doctor(root) {
|
|
|
1084
1090
|
"opennori_directory",
|
|
1085
1091
|
fs.existsSync(noriDir),
|
|
1086
1092
|
fs.existsSync(noriDir) ? ".opennori directory exists." : ".opennori directory is missing.",
|
|
1087
|
-
"Run
|
|
1093
|
+
"Run opennori bootstrap --root <project> --json."
|
|
1088
1094
|
));
|
|
1089
1095
|
|
|
1090
1096
|
for (const dir of REQUIRED_NORI_DIRS) {
|
|
@@ -1093,7 +1099,7 @@ function doctor(root) {
|
|
|
1093
1099
|
`dir_${dir}`,
|
|
1094
1100
|
fs.existsSync(dirPath),
|
|
1095
1101
|
fs.existsSync(dirPath) ? `.opennori/${dir} exists.` : `.opennori/${dir} is missing.`,
|
|
1096
|
-
"Run
|
|
1102
|
+
"Run opennori bootstrap --root <project> --json."
|
|
1097
1103
|
));
|
|
1098
1104
|
}
|
|
1099
1105
|
|
|
@@ -1101,7 +1107,7 @@ function doctor(root) {
|
|
|
1101
1107
|
"protocol_file",
|
|
1102
1108
|
fs.existsSync(protocolPath),
|
|
1103
1109
|
fs.existsSync(protocolPath) ? ".opennori/protocol.md exists." : ".opennori/protocol.md is missing.",
|
|
1104
|
-
"Run
|
|
1110
|
+
"Run opennori bootstrap --root <project> --json."
|
|
1105
1111
|
));
|
|
1106
1112
|
|
|
1107
1113
|
let manifest = null;
|
|
@@ -1114,7 +1120,7 @@ function doctor(root) {
|
|
|
1114
1120
|
"manifest_file",
|
|
1115
1121
|
false,
|
|
1116
1122
|
fs.existsSync(manifestFile) ? `.opennori/manifest.json is unreadable: ${error.message}` : ".opennori/manifest.json is missing.",
|
|
1117
|
-
"Run
|
|
1123
|
+
"Run opennori bootstrap --root <project> --json to preview setup or refresh the OpenNori manifest.",
|
|
1118
1124
|
fs.existsSync(manifestFile) ? "broken" : "needs-action"
|
|
1119
1125
|
));
|
|
1120
1126
|
}
|
|
@@ -1124,27 +1130,27 @@ function doctor(root) {
|
|
|
1124
1130
|
"manifest_file",
|
|
1125
1131
|
manifest.schema_version === MANIFEST_SCHEMA_VERSION,
|
|
1126
1132
|
`.opennori/manifest.json uses schema ${manifest.schema_version || "<missing>"}.`,
|
|
1127
|
-
"Refresh the manifest with
|
|
1133
|
+
"Refresh the manifest with opennori bootstrap --root <project> --json.",
|
|
1128
1134
|
"broken"
|
|
1129
1135
|
));
|
|
1130
1136
|
checks.push(doctorCheck(
|
|
1131
1137
|
"manifest_protocol",
|
|
1132
1138
|
manifest.protocol_version === PROTOCOL_VERSION,
|
|
1133
1139
|
`.opennori/manifest.json records protocol ${manifest.protocol_version || "<missing>"}.`,
|
|
1134
|
-
"Refresh the manifest with
|
|
1140
|
+
"Refresh the manifest with opennori bootstrap --root <project> --json.",
|
|
1135
1141
|
"broken"
|
|
1136
1142
|
));
|
|
1137
1143
|
checks.push(doctorCheck(
|
|
1138
1144
|
"manifest_cli_version",
|
|
1139
1145
|
manifest.opennori_version === PACKAGE_JSON.version,
|
|
1140
1146
|
`.opennori/manifest.json records OpenNori version ${manifest.opennori_version || "<missing>"}.`,
|
|
1141
|
-
"Refresh the manifest with
|
|
1147
|
+
"Refresh the manifest with opennori bootstrap --root <project> --json."
|
|
1142
1148
|
));
|
|
1143
1149
|
checks.push(doctorCheck(
|
|
1144
1150
|
"manifest_capabilities",
|
|
1145
1151
|
sameStringSet(manifest.capabilities, NORI_CAPABILITIES),
|
|
1146
1152
|
Array.isArray(manifest.capabilities) ? "Manifest protocol capabilities are readable." : "Manifest protocol capabilities are missing.",
|
|
1147
|
-
"Refresh the manifest with
|
|
1153
|
+
"Refresh the manifest with opennori bootstrap --root <project> --json."
|
|
1148
1154
|
));
|
|
1149
1155
|
|
|
1150
1156
|
const currentGoals = new Set(active.details.filter((goal) => goal.recoverable).map((goal) => goal.goal_id));
|
|
@@ -1157,7 +1163,7 @@ function doctor(root) {
|
|
|
1157
1163
|
"manifest_active_goals",
|
|
1158
1164
|
staleGoals.length === 0,
|
|
1159
1165
|
staleGoals.length === 0 ? "Manifest active goals match recoverable active goals." : `Manifest active goals differ: ${staleGoals.join(", ")}.`,
|
|
1160
|
-
"Run any OpenNori state-changing command, or run
|
|
1166
|
+
"Run any OpenNori state-changing command, or run opennori bootstrap --root <project> --json, to refresh the manifest."
|
|
1161
1167
|
));
|
|
1162
1168
|
|
|
1163
1169
|
const missingManaged = (manifest.managed_files || [])
|
|
@@ -1168,7 +1174,7 @@ function doctor(root) {
|
|
|
1168
1174
|
"managed_files",
|
|
1169
1175
|
missingManaged.length === 0,
|
|
1170
1176
|
missingManaged.length === 0 ? "Required OpenNori managed files are present." : `Missing managed files: ${missingManaged.join(", ")}.`,
|
|
1171
|
-
"Run
|
|
1177
|
+
"Run opennori bootstrap --root <project> --json."
|
|
1172
1178
|
));
|
|
1173
1179
|
}
|
|
1174
1180
|
|
|
@@ -1176,7 +1182,7 @@ function doctor(root) {
|
|
|
1176
1182
|
"active_goals_recoverable",
|
|
1177
1183
|
active.issues.length === 0,
|
|
1178
1184
|
active.issues.length === 0 ? `${active.details.length} active goal(s) are recoverable.` : `${active.issues.length} active goal issue(s) found.`,
|
|
1179
|
-
"Inspect active_goal_issues, fix the reported .opennori/active/<goal>.acceptance.md and .opennori/active/<goal>.evidence.json pair, then rerun
|
|
1185
|
+
"Inspect active_goal_issues, fix the reported .opennori/active/<goal>.acceptance.md and .opennori/active/<goal>.evidence.json pair, then rerun opennori doctor --root <project> --json.",
|
|
1180
1186
|
"broken"
|
|
1181
1187
|
));
|
|
1182
1188
|
|
|
@@ -1189,7 +1195,7 @@ function doctor(root) {
|
|
|
1189
1195
|
"manifest_skill_state",
|
|
1190
1196
|
Boolean(manifest.skill) && manifest.skill.installed === skill.installed && manifest.skill.path === skill.path,
|
|
1191
1197
|
"Manifest Skill state matches the project Skill location.",
|
|
1192
|
-
"Refresh the manifest with
|
|
1198
|
+
"Refresh the manifest with opennori bootstrap --root <project> --json."
|
|
1193
1199
|
));
|
|
1194
1200
|
}
|
|
1195
1201
|
checks.push(doctorCheck(
|
|
@@ -1198,7 +1204,7 @@ function doctor(root) {
|
|
|
1198
1204
|
skill.installed
|
|
1199
1205
|
? (skill.in_sync ? "Project OpenNori Skill is installed and in sync." : "Project OpenNori Skill is installed but stale.")
|
|
1200
1206
|
: "Project OpenNori Skill is not installed; this is optional unless the manifest expects it.",
|
|
1201
|
-
"Run
|
|
1207
|
+
"Run opennori install --root <project> --skill --force --json."
|
|
1202
1208
|
));
|
|
1203
1209
|
const manifestPackNames = new Set((manifest?.skill_pack?.skills || []).map((entry) => entry.name));
|
|
1204
1210
|
const packNames = new Set(skillPack.skills.map((entry) => entry.name));
|
|
@@ -1210,7 +1216,7 @@ function doctor(root) {
|
|
|
1210
1216
|
"skill_pack_manifest",
|
|
1211
1217
|
manifestPackMatches,
|
|
1212
1218
|
manifestPackMatches ? "Manifest Skill Pack state is readable." : "Manifest Skill Pack state is missing or stale.",
|
|
1213
|
-
"Refresh the manifest with
|
|
1219
|
+
"Refresh the manifest with opennori install --root <project> --skill --json."
|
|
1214
1220
|
));
|
|
1215
1221
|
const packExpected = manifest?.skill_pack?.installed === true || skillPack.skills.some((entry) => entry.installed);
|
|
1216
1222
|
const packOk = packExpected ? skillPack.installed && skillPack.in_sync : true;
|
|
@@ -1220,7 +1226,7 @@ function doctor(root) {
|
|
|
1220
1226
|
skillPack.installed
|
|
1221
1227
|
? (skillPack.in_sync ? "OpenNori Skill Pack is installed and in sync." : "OpenNori Skill Pack is installed but stale.")
|
|
1222
1228
|
: "OpenNori Skill Pack is not installed; this is optional unless the manifest expects it.",
|
|
1223
|
-
"Run
|
|
1229
|
+
"Run opennori install --root <project> --skill --force --json."
|
|
1224
1230
|
));
|
|
1225
1231
|
|
|
1226
1232
|
const status = checks.every((check) => check.ok)
|
|
@@ -1372,6 +1378,71 @@ function refreshManifest(root) {
|
|
|
1372
1378
|
}
|
|
1373
1379
|
}
|
|
1374
1380
|
|
|
1381
|
+
function installActions(root, { dryRun = false, force = false, requestedSkill = false } = {}) {
|
|
1382
|
+
const actions = [
|
|
1383
|
+
ensureDir(path.join(root, ".opennori", "active"), { dryRun }),
|
|
1384
|
+
ensureDir(path.join(root, ".opennori", "completed"), { dryRun }),
|
|
1385
|
+
ensureDir(path.join(root, ".opennori", "blocked"), { dryRun }),
|
|
1386
|
+
ensureDir(path.join(root, ".opennori", "reports"), { dryRun }),
|
|
1387
|
+
ensureDir(path.join(root, ".opennori", "brainstorms"), { dryRun }),
|
|
1388
|
+
writeIfSafe(path.join(root, ".opennori", "protocol.md"), protocolTemplate(), { dryRun, force, kind: "protocol" })
|
|
1389
|
+
];
|
|
1390
|
+
|
|
1391
|
+
if (requestedSkill) {
|
|
1392
|
+
actions.push(...skillPackInstallActions(root, { dryRun, force }));
|
|
1393
|
+
}
|
|
1394
|
+
actions.push(writeManifest(root, { dryRun }));
|
|
1395
|
+
return actions;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
function bootstrap(root, { confirmed = false } = {}) {
|
|
1399
|
+
const health = doctor(root);
|
|
1400
|
+
if (health.status === "ready") {
|
|
1401
|
+
return ok({
|
|
1402
|
+
root,
|
|
1403
|
+
status: "ready",
|
|
1404
|
+
confirmed,
|
|
1405
|
+
side_effect: "none",
|
|
1406
|
+
doctor: health,
|
|
1407
|
+
next: "OpenNori is ready. Continue from opennori resume/status, brainstorm, or draft based on the user's goal."
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
const hasState = fs.existsSync(path.join(root, ".opennori"));
|
|
1412
|
+
const needsConfirm = !confirmed;
|
|
1413
|
+
const actions = installActions(root, {
|
|
1414
|
+
dryRun: needsConfirm,
|
|
1415
|
+
force: false,
|
|
1416
|
+
requestedSkill: true
|
|
1417
|
+
});
|
|
1418
|
+
const installPlan = buildInstallPlan(root, actions, {
|
|
1419
|
+
dryRun: needsConfirm,
|
|
1420
|
+
force: false,
|
|
1421
|
+
requestedSkill: true
|
|
1422
|
+
});
|
|
1423
|
+
const next = needsConfirm
|
|
1424
|
+
? "Show this preview to the user and ask for confirmation before writing OpenNori project assets."
|
|
1425
|
+
: "OpenNori project assets are installed. Continue with the user's goal.";
|
|
1426
|
+
|
|
1427
|
+
return ok(
|
|
1428
|
+
{
|
|
1429
|
+
root,
|
|
1430
|
+
status: needsConfirm ? "needs_confirm" : "installed",
|
|
1431
|
+
confirmed,
|
|
1432
|
+
existing_state: hasState,
|
|
1433
|
+
install_plan: installPlan,
|
|
1434
|
+
actions: installPlan.actions,
|
|
1435
|
+
doctor: needsConfirm ? health : doctor(root),
|
|
1436
|
+
next
|
|
1437
|
+
},
|
|
1438
|
+
[],
|
|
1439
|
+
hasState && health.status === "broken"
|
|
1440
|
+
? ["Existing OpenNori state was not ready before bootstrap; review doctor output after install."]
|
|
1441
|
+
: [],
|
|
1442
|
+
[next]
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1375
1446
|
function loadPair(args) {
|
|
1376
1447
|
const explicitAcceptance = argValue(args, "--acceptance");
|
|
1377
1448
|
const explicitEvidence = argValue(args, "--evidence");
|
|
@@ -1423,10 +1494,17 @@ export async function main(args) {
|
|
|
1423
1494
|
return;
|
|
1424
1495
|
}
|
|
1425
1496
|
|
|
1497
|
+
if (command === "bootstrap") {
|
|
1498
|
+
const root = resolveRoot(args);
|
|
1499
|
+
const confirmed = hasFlag(args, "--confirm");
|
|
1500
|
+
printJson(bootstrap(root, { confirmed }));
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1426
1504
|
if (command === "doctor") {
|
|
1427
1505
|
const root = resolveRoot(args);
|
|
1428
1506
|
printJson(ok({
|
|
1429
|
-
name: "
|
|
1507
|
+
name: "opennori",
|
|
1430
1508
|
root,
|
|
1431
1509
|
...doctor(root),
|
|
1432
1510
|
side_effect: "none"
|
|
@@ -1460,25 +1538,13 @@ export async function main(args) {
|
|
|
1460
1538
|
printJson(fail(
|
|
1461
1539
|
"confirm_required",
|
|
1462
1540
|
"Install --force may overwrite existing OpenNori-managed files.",
|
|
1463
|
-
"Run
|
|
1541
|
+
"Run opennori install --root <project> --dry-run --force --json first, then rerun with --confirm if the destructive actions are acceptable."
|
|
1464
1542
|
));
|
|
1465
1543
|
process.exitCode = 1;
|
|
1466
1544
|
return;
|
|
1467
1545
|
}
|
|
1468
|
-
const actions =
|
|
1469
|
-
|
|
1470
|
-
ensureDir(path.join(root, ".opennori", "completed"), { dryRun }),
|
|
1471
|
-
ensureDir(path.join(root, ".opennori", "blocked"), { dryRun }),
|
|
1472
|
-
ensureDir(path.join(root, ".opennori", "reports"), { dryRun }),
|
|
1473
|
-
ensureDir(path.join(root, ".opennori", "brainstorms"), { dryRun }),
|
|
1474
|
-
writeIfSafe(path.join(root, ".opennori", "protocol.md"), protocolTemplate(), { dryRun, force, kind: "protocol" })
|
|
1475
|
-
];
|
|
1476
|
-
|
|
1477
|
-
if (requestedSkill) {
|
|
1478
|
-
actions.push(...skillPackInstallActions(root, { dryRun, force }));
|
|
1479
|
-
}
|
|
1480
|
-
const manifestAction = writeManifest(root, { dryRun });
|
|
1481
|
-
actions.push(manifestAction);
|
|
1546
|
+
const actions = installActions(root, { dryRun, force, requestedSkill });
|
|
1547
|
+
const manifestAction = actions.find((action) => action.kind === "manifest");
|
|
1482
1548
|
const installPlan = buildInstallPlan(root, actions, { dryRun, force, requestedSkill });
|
|
1483
1549
|
|
|
1484
1550
|
printJson(ok({
|
|
@@ -1505,7 +1571,7 @@ export async function main(args) {
|
|
|
1505
1571
|
printJson(fail(
|
|
1506
1572
|
"confirm_required",
|
|
1507
1573
|
"Uninstall removes OpenNori-managed project assets.",
|
|
1508
|
-
"Run
|
|
1574
|
+
"Run opennori uninstall --root <project> --dry-run --json first, then rerun with --confirm if the planned removals are acceptable."
|
|
1509
1575
|
));
|
|
1510
1576
|
process.exitCode = 1;
|
|
1511
1577
|
return;
|
|
@@ -1538,7 +1604,7 @@ export async function main(args) {
|
|
|
1538
1604
|
printJson(fail(
|
|
1539
1605
|
"confirm_required",
|
|
1540
1606
|
"Upgrade refreshes OpenNori manifest, protocol, and optionally Skill Pack assets.",
|
|
1541
|
-
"Run
|
|
1607
|
+
"Run opennori upgrade --root <project> --dry-run --json first, then rerun with --confirm if the planned updates are acceptable."
|
|
1542
1608
|
));
|
|
1543
1609
|
process.exitCode = 1;
|
|
1544
1610
|
return;
|
|
@@ -1548,7 +1614,7 @@ export async function main(args) {
|
|
|
1548
1614
|
printJson(fail(
|
|
1549
1615
|
"install_required",
|
|
1550
1616
|
"Upgrade found missing OpenNori entry assets.",
|
|
1551
|
-
"Run
|
|
1617
|
+
"Run opennori install --root <project> --dry-run --json before upgrading missing assets."
|
|
1552
1618
|
));
|
|
1553
1619
|
process.exitCode = 1;
|
|
1554
1620
|
return;
|
|
@@ -1595,7 +1661,7 @@ export async function main(args) {
|
|
|
1595
1661
|
{ kind: "brainstorm_markdown", path: paths.markdownPath }
|
|
1596
1662
|
],
|
|
1597
1663
|
[],
|
|
1598
|
-
["Ask the user to choose or revise a candidate before running
|
|
1664
|
+
["Ask the user to choose or revise a candidate before running opennori draft."]
|
|
1599
1665
|
));
|
|
1600
1666
|
return;
|
|
1601
1667
|
}
|
|
@@ -1677,7 +1743,7 @@ export async function main(args) {
|
|
|
1677
1743
|
{ kind: "evidence_ledger", path: paths.evidencePath }
|
|
1678
1744
|
],
|
|
1679
1745
|
[],
|
|
1680
|
-
["Run
|
|
1746
|
+
["Run opennori next --acceptance <path> --evidence <path> --json before choosing implementation work."]
|
|
1681
1747
|
));
|
|
1682
1748
|
return;
|
|
1683
1749
|
}
|