opennori 0.1.4 → 0.1.6
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 +17 -14
- package/README.md +7 -0
- package/bin/opennori.js +3 -1
- package/package.json +1 -1
- package/src/cli.js +178 -3
package/.opennori/protocol.md
CHANGED
|
@@ -145,7 +145,7 @@ OpenNori exposes a Skill Pack for agent use. The user should not need to remembe
|
|
|
145
145
|
the root `nori` Skill routes natural-language requests to focused Skills:
|
|
146
146
|
|
|
147
147
|
- `nori`: root router for OpenNori turns
|
|
148
|
-
- `nori-acceptance`: brainstorm, draft, approve, and revise human-facing ACs
|
|
148
|
+
- `nori-acceptance`: discover AC gaps, brainstorm, draft, approve, and revise human-facing ACs
|
|
149
149
|
- `nori-evidence`: record reviewable evidence without forcing fixed adapters
|
|
150
150
|
- `nori-capability-profile`: record required Skills, preferred stacks, avoided tools, and install policy
|
|
151
151
|
- `nori-project-health`: install, uninstall, doctor, manifest, and Skill Pack sync
|
|
@@ -239,23 +239,26 @@ all evidence through a narrow adapter taxonomy.
|
|
|
239
239
|
|
|
240
240
|
On every turn:
|
|
241
241
|
|
|
242
|
-
1. If the user
|
|
243
|
-
2.
|
|
244
|
-
3. If the user
|
|
245
|
-
4.
|
|
246
|
-
5.
|
|
247
|
-
6.
|
|
248
|
-
7.
|
|
249
|
-
8.
|
|
250
|
-
9.
|
|
251
|
-
10.
|
|
252
|
-
11.
|
|
253
|
-
12.
|
|
254
|
-
13.
|
|
242
|
+
1. If the user gives a fuzzy goal or candidate AC, run `opennori discover --goal "<goal>" --root <repo> --json` before drafting.
|
|
243
|
+
2. Ask only the discovery questions that affect completion judgment. Do not turn discovery gaps into implementation tasks or completion evidence.
|
|
244
|
+
3. If the user wants to discuss, brainstorm, explore, or is not ready to define acceptance criteria, run `opennori brainstorm --idea "<idea>" --root <repo> --json`.
|
|
245
|
+
4. Show only candidate acceptance directions and ask the user to choose or revise a direction. Brainstorm output is not a contract or completion evidence.
|
|
246
|
+
5. If the user chooses a candidate, run `opennori draft --from-brainstorm <brainstorm-id> --candidate <A|B|C> --root <repo> --json`.
|
|
247
|
+
6. If the user starts with "use OpenNori" / "用 OpenNori 跑这个任务" and discovery gaps are answered or explicitly accepted as assumptions, run `opennori draft --goal "<goal>" --root <repo> --json`.
|
|
248
|
+
7. Show the draft acceptance criteria and ask the user to approve or revise them.
|
|
249
|
+
8. After approval, run `opennori approve --root <repo> --summary "<approval>" --json`.
|
|
250
|
+
9. 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.
|
|
251
|
+
10. If the user revises a criterion later, run `opennori criterion update --root <repo> --criterion <id> ... --json`; old evidence for the changed criterion is cleared.
|
|
252
|
+
11. Run `opennori resume --root <repo>` or `opennori next --root <repo>` to recover the active goal and current acceptance gap from repository files.
|
|
253
|
+
12. Work only to produce evidence for that gap.
|
|
254
|
+
13. 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.
|
|
255
|
+
14. Run `opennori evaluate`.
|
|
256
|
+
15. Report acceptance state, profile compliance, and evidence, not implementation steps.
|
|
255
257
|
|
|
256
258
|
Useful commands:
|
|
257
259
|
|
|
258
260
|
- `opennori brainstorm --idea "<idea>" --root <repo>`: create selectable acceptance directions before a contract exists.
|
|
261
|
+
- `opennori discover --goal "<goal>" --root <repo>`: find underspecified acceptance gaps before drafting a contract.
|
|
259
262
|
- `opennori draft --goal "<goal>" --root <repo>`: create a draft Nori Contract that needs user approval.
|
|
260
263
|
- `opennori draft --from-brainstorm <brainstorm-id> --candidate <A|B|C> --root <repo>`: convert a selected brainstorm direction into a draft contract.
|
|
261
264
|
- `opennori approve --root <repo>`: mark the acceptance basis as approved so completion can be decided.
|
package/README.md
CHANGED
|
@@ -45,6 +45,10 @@ Use OpenNori for this project. Start from my goal, define a Nori Contract,
|
|
|
45
45
|
and keep working only from acceptance gaps until the report says whether it is complete.
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
For fuzzy goals, ask Nori to discover the real acceptance gaps first. It should ask about missing
|
|
49
|
+
field scope, validation rules, success signals, persistence, failure cases, and out-of-scope
|
|
50
|
+
boundaries before it turns the goal into a Nori Contract.
|
|
51
|
+
|
|
48
52
|
## What Gets Added
|
|
49
53
|
|
|
50
54
|
OpenNori uses one project-local state directory:
|
|
@@ -69,6 +73,7 @@ It does not create a `process/` directory as the main workflow surface.
|
|
|
69
73
|
```bash
|
|
70
74
|
opennori bootstrap
|
|
71
75
|
opennori doctor --root .
|
|
76
|
+
opennori discover --goal "Ship a settings page" --root .
|
|
72
77
|
opennori brainstorm --idea "Explore this goal" --root .
|
|
73
78
|
opennori draft --goal "Ship a user-visible result" --root .
|
|
74
79
|
opennori approve --root . --summary "User approved the acceptance checks."
|
|
@@ -87,6 +92,8 @@ language requests to the deterministic CLI state layer.
|
|
|
87
92
|
require explicit confirmation.
|
|
88
93
|
- In a human terminal, `npx opennori` is interactive. With `--json` or non-interactive stdio it
|
|
89
94
|
returns structured JSON for agents and automation.
|
|
95
|
+
- `discover` finds underspecified acceptance gaps before draft, so vague ACs such as "modify fields"
|
|
96
|
+
or "show an error" become user questions instead of weak contracts.
|
|
90
97
|
- `doctor` reports whether project state is `ready`, `needs-action`, or `broken`, with recovery
|
|
91
98
|
actions.
|
|
92
99
|
- Nori Profile records required Skills, preferred stacks, avoided tools, and install policy without
|
package/bin/opennori.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
import { main } from "../src/cli.js";
|
|
3
3
|
|
|
4
4
|
const args = process.argv.slice(2);
|
|
5
|
-
const commandArgs = args.length
|
|
5
|
+
const commandArgs = args.length === 0 || (args[0].startsWith("-") && !["--help", "-h"].includes(args[0]))
|
|
6
|
+
? ["bootstrap", ...args]
|
|
7
|
+
: args;
|
|
6
8
|
|
|
7
9
|
main(commandArgs).catch((error) => {
|
|
8
10
|
console.error(JSON.stringify({
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -38,6 +38,7 @@ const NORI_CAPABILITIES = [
|
|
|
38
38
|
"reviewable-evidence",
|
|
39
39
|
"skill-pack",
|
|
40
40
|
"brainstorm",
|
|
41
|
+
"acceptance-discovery",
|
|
41
42
|
"capability-profile",
|
|
42
43
|
"profile-check",
|
|
43
44
|
"archive",
|
|
@@ -371,6 +372,103 @@ const DEFAULT_CRITERIA = [
|
|
|
371
372
|
}
|
|
372
373
|
];
|
|
373
374
|
|
|
375
|
+
const DISCOVERY_GAPS = [
|
|
376
|
+
{
|
|
377
|
+
id: "missing-field-scope",
|
|
378
|
+
patterns: ["设置", "资料", "个人资料", "profile", "settings", "字段", "field"],
|
|
379
|
+
question: "本轮用户可以修改或查看哪些具体字段?哪些字段明确不在范围内?",
|
|
380
|
+
why: "没有字段范围,用户无法判断修改能力是否完整。"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: "missing-validation-rule",
|
|
384
|
+
patterns: ["修改", "输入", "保存", "上传", "表单", "edit", "input", "save", "upload", "form"],
|
|
385
|
+
question: "每个可输入内容的有效规则是什么,例如长度、必填、格式、文件类型或大小?",
|
|
386
|
+
why: "没有校验规则,失败和边界输入无法验收。"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
id: "missing-success-signal",
|
|
390
|
+
patterns: ["保存", "提交", "创建", "更新", "完成", "save", "submit", "create", "update"],
|
|
391
|
+
question: "操作成功后,用户会看到什么明确反馈或结果变化?",
|
|
392
|
+
why: "没有成功反馈,用户无法判断操作是否真的完成。"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
id: "missing-persistence-scope",
|
|
396
|
+
patterns: ["保存", "刷新", "重新打开", "重新登录", "持久", "save", "refresh", "reload", "reopen", "login", "persist"],
|
|
397
|
+
question: "结果需要在刷新、重新打开、重新登录或跨设备后仍然存在吗?",
|
|
398
|
+
why: "没有持久化范围,完成判断会在当前页面和真实保存之间摇摆。"
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: "missing-failure-case",
|
|
402
|
+
patterns: ["失败", "错误", "提示", "网络", "权限", "error", "fail", "failure", "invalid", "permission", "network"],
|
|
403
|
+
question: "哪些失败情况必须覆盖,用户分别应该看到什么提示或保留什么原状态?",
|
|
404
|
+
why: "没有失败场景,错误体验可能被一句“有提示”掩盖。"
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
id: "missing-out-of-scope-boundary",
|
|
408
|
+
patterns: ["页面", "页", "设置", "功能", "支持", "完成", "page", "feature", "support", "complete"],
|
|
409
|
+
question: "哪些相关能力明确不属于本轮完成范围?",
|
|
410
|
+
why: "没有范围边界,agent 可能扩大实现,也可能漏掉用户真正期待的部分。"
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
id: "missing-user-entry",
|
|
414
|
+
patterns: ["使用", "打开", "查看", "进入", "run", "open", "view", "use", "entry"],
|
|
415
|
+
question: "用户从哪个入口开始操作,最终在哪里查看结果?",
|
|
416
|
+
why: "没有用户入口,AC 容易变成内部状态而不是可执行验收。"
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
id: "missing-review-method",
|
|
420
|
+
patterns: ["判断", "验收", "完成", "review", "accept", "done", "complete"],
|
|
421
|
+
question: "用户或评审者应该用什么可复查方式判断这条 AC 通过?",
|
|
422
|
+
why: "没有复查方式,完成判断会退化成 agent 自我总结。"
|
|
423
|
+
}
|
|
424
|
+
];
|
|
425
|
+
|
|
426
|
+
function sentenceHasSpecifics(text, terms) {
|
|
427
|
+
const value = String(text || "").toLowerCase();
|
|
428
|
+
return terms.some((term) => value.includes(term.toLowerCase()));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function discoverAcceptance(goal, explicitId = undefined) {
|
|
432
|
+
const text = String(goal || "").trim();
|
|
433
|
+
const lowered = text.toLowerCase();
|
|
434
|
+
const gaps = DISCOVERY_GAPS
|
|
435
|
+
.filter((gap) => gap.patterns.some((pattern) => lowered.includes(pattern.toLowerCase())))
|
|
436
|
+
.filter((gap) => {
|
|
437
|
+
if (gap.id === "missing-field-scope") return !sentenceHasSpecifics(text, ["昵称", "头像", "简介", "邮箱", "手机号", "name", "avatar", "bio", "email", "phone"]);
|
|
438
|
+
if (gap.id === "missing-validation-rule") return !sentenceHasSpecifics(text, ["长度", "必填", "格式", "大小", "类型", "字符", "required", "format", "length", "size", "type"]);
|
|
439
|
+
if (gap.id === "missing-success-signal") return !sentenceHasSpecifics(text, ["成功", "保存成功", "成功反馈", "result", "success"]);
|
|
440
|
+
if (gap.id === "missing-persistence-scope") return !sentenceHasSpecifics(text, ["刷新", "重新打开", "重新登录", "跨设备", "refresh", "reload", "reopen", "login"]);
|
|
441
|
+
if (gap.id === "missing-failure-case") return !sentenceHasSpecifics(text, ["网络", "权限", "无效", "错误码", "保留原", "network", "permission", "invalid"]);
|
|
442
|
+
if (gap.id === "missing-out-of-scope-boundary") return !sentenceHasSpecifics(text, ["不在范围", "不包含", "本轮不", "out of scope", "exclude"]);
|
|
443
|
+
if (gap.id === "missing-user-entry") return !sentenceHasSpecifics(text, ["设置页", "登录页", "report", "dashboard", "页面", "page"]);
|
|
444
|
+
if (gap.id === "missing-review-method") return !sentenceHasSpecifics(text, ["截图", "浏览器", "报告", "测试", "review", "screenshot", "browser", "report"]);
|
|
445
|
+
return true;
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const selectedGaps = gaps.length > 0 ? gaps : [
|
|
449
|
+
{
|
|
450
|
+
id: "missing-review-method",
|
|
451
|
+
question: "用户或评审者应该用什么可复查方式判断这个目标完成?",
|
|
452
|
+
why: "OpenNori 需要先知道完成判断方式,才能形成真正可验收的 AC。"
|
|
453
|
+
}
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
protocol_version: "opennori/discovery-v1",
|
|
458
|
+
id: explicitId || slugify(text.slice(0, 40) || "acceptance-discovery"),
|
|
459
|
+
goal: text,
|
|
460
|
+
status: selectedGaps.length > 0 ? "needs-user-answers" : "ready-for-draft",
|
|
461
|
+
is_acceptance_contract: false,
|
|
462
|
+
gaps: selectedGaps.map((gap, index) => ({
|
|
463
|
+
id: gap.id,
|
|
464
|
+
question: gap.question,
|
|
465
|
+
why: gap.why,
|
|
466
|
+
priority: index < 3 ? "must-answer" : "can-default"
|
|
467
|
+
})),
|
|
468
|
+
next: "Ask the must-answer questions before drafting a Nori Contract. Use assumptions only when the user accepts them."
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
374
472
|
function printJson(payload) {
|
|
375
473
|
console.log(JSON.stringify(payload, null, 2));
|
|
376
474
|
}
|
|
@@ -398,7 +496,7 @@ function isInteractive(args) {
|
|
|
398
496
|
}
|
|
399
497
|
|
|
400
498
|
const CLI_NAME = "opennori";
|
|
401
|
-
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>`;
|
|
499
|
+
const TOP_LEVEL_USAGE = `${CLI_NAME} <bootstrap|doctor|install|upgrade|uninstall|brainstorm|discover|draft|init|list|check|approve|criterion|profile|resume|next|evidence|evaluate|status|report|context|changes|archive|skill>`;
|
|
402
500
|
|
|
403
501
|
function wantsHelp(args) {
|
|
404
502
|
return args.includes("--help") || args.includes("-h");
|
|
@@ -413,6 +511,7 @@ function usageFor(args) {
|
|
|
413
511
|
if (command === "uninstall") return `${CLI_NAME} uninstall --root <project> [--include-state] [--dry-run] [--confirm] [--json]`;
|
|
414
512
|
if (command === "doctor") return `${CLI_NAME} doctor --root <project> [--json]`;
|
|
415
513
|
if (command === "brainstorm") return `${CLI_NAME} brainstorm --idea "<idea>" --root <project> [--id <id>] [--json]`;
|
|
514
|
+
if (command === "discover") return `${CLI_NAME} discover --goal "<goal>" --root <project> [--id <id>] [--json]`;
|
|
416
515
|
if (command === "draft") return `${CLI_NAME} draft --goal "<goal>" --root <project> [--goal-id <id>] [--json]`;
|
|
417
516
|
if (command === "init") return `${CLI_NAME} init <brief.json> --root <project> [--json]`;
|
|
418
517
|
if (command === "criterion" && subcommand === "update") return `${CLI_NAME} criterion update --root <project> --criterion <id> --user-story ... --measurement ... --threshold ... [--json]`;
|
|
@@ -573,7 +672,7 @@ const SKILL_PACK = [
|
|
|
573
672
|
"Use when the user mentions OpenNori, asks to use OpenNori for a task, continue OpenNori, check completion, inspect project health, define acceptance criteria, record evidence, manage capability preferences, or produce an OpenNori report.",
|
|
574
673
|
"",
|
|
575
674
|
"## Route",
|
|
576
|
-
"- Goal, brainstorm, approval, or AC revision -> use `nori-acceptance`.",
|
|
675
|
+
"- Goal, acceptance discovery, brainstorm, approval, or AC revision -> use `nori-acceptance`.",
|
|
577
676
|
"- Verification, evidence sufficiency, human confirmation, waiver, or why an AC is passing -> use `nori-evidence`.",
|
|
578
677
|
"- Required Skills, preferred stacks, avoided tools, or install policy -> use `nori-capability-profile`.",
|
|
579
678
|
"- Install, uninstall, doctor, manifest, Skill sync, or project recoverability -> use `nori-project-health`.",
|
|
@@ -596,9 +695,10 @@ const SKILL_PACK = [
|
|
|
596
695
|
description: "Create, review, approve, and revise OpenNori human-centered acceptance criteria from natural language goals.",
|
|
597
696
|
body: [
|
|
598
697
|
"## When to use",
|
|
599
|
-
"Use when the user gives a goal, wants to brainstorm acceptance directions, approves criteria, revises completion criteria, or says the AC is wrong.",
|
|
698
|
+
"Use when the user gives a goal, wants to discover real acceptance criteria, wants to brainstorm acceptance directions, approves criteria, revises completion criteria, or says the AC is wrong.",
|
|
600
699
|
"",
|
|
601
700
|
"## Commands",
|
|
701
|
+
"- Before drafting from a fuzzy goal: `opennori discover --goal \"<goal>\" --root <repo> --json`.",
|
|
602
702
|
"- Fuzzy idea or discussion: `opennori brainstorm --idea \"<idea>\" --root <repo> --json`.",
|
|
603
703
|
"- Start from a goal: `opennori draft --goal \"<goal>\" --root <repo> --json`.",
|
|
604
704
|
"- Start from a chosen brainstorm candidate: `opennori draft --from-brainstorm <brainstorm-id> --candidate <A|B|C> --root <repo> --json`.",
|
|
@@ -606,6 +706,9 @@ const SKILL_PACK = [
|
|
|
606
706
|
"- User revises a criterion: `opennori criterion update --root <repo> --criterion <id> --user-story ... --measurement ... --threshold ... --json`.",
|
|
607
707
|
"",
|
|
608
708
|
"## Rules",
|
|
709
|
+
"Run discovery before draft when the goal or candidate AC contains vague verbs such as modify, save, support, show an error, or improve.",
|
|
710
|
+
"Discovery gaps are questions for the user, not implementation tasks and not completion evidence.",
|
|
711
|
+
"Do not draft generic ACs like 'modify fields' or 'show failure prompt' until field scope, validation rules, success signal, persistence scope, failure cases, and out-of-scope boundaries are clear enough for the user to judge.",
|
|
609
712
|
"ACs must describe user actions or judgments, not implementation files, commands, modules, fields, tests, Skills, or technology choices.",
|
|
610
713
|
"Capability preferences belong in the Nori Profile, not user ACs.",
|
|
611
714
|
"Do not treat brainstorm output as a Nori Contract or completion evidence."
|
|
@@ -1354,6 +1457,47 @@ function brainstormPaths(root, brainstormId) {
|
|
|
1354
1457
|
};
|
|
1355
1458
|
}
|
|
1356
1459
|
|
|
1460
|
+
function discoveryPaths(root, discoveryId) {
|
|
1461
|
+
const dir = path.join(root, ".opennori", "brainstorms");
|
|
1462
|
+
return {
|
|
1463
|
+
jsonPath: path.join(dir, `${discoveryId}.discovery.json`),
|
|
1464
|
+
markdownPath: path.join(dir, `${discoveryId}.discovery.md`)
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
function renderDiscoveryMarkdown(discovery) {
|
|
1469
|
+
const lines = [
|
|
1470
|
+
`# ${discovery.id} Acceptance Discovery`,
|
|
1471
|
+
"",
|
|
1472
|
+
"## Goal",
|
|
1473
|
+
"",
|
|
1474
|
+
discovery.goal,
|
|
1475
|
+
"",
|
|
1476
|
+
"## Rule",
|
|
1477
|
+
"",
|
|
1478
|
+
"This is an acceptance discovery source, not a Nori Contract, process plan, or completion evidence.",
|
|
1479
|
+
"",
|
|
1480
|
+
"## Acceptance Gaps",
|
|
1481
|
+
""
|
|
1482
|
+
];
|
|
1483
|
+
|
|
1484
|
+
for (const gap of discovery.gaps) {
|
|
1485
|
+
lines.push(
|
|
1486
|
+
`### ${gap.id}`,
|
|
1487
|
+
"",
|
|
1488
|
+
`Priority: ${gap.priority}`,
|
|
1489
|
+
"",
|
|
1490
|
+
`Question: ${gap.question}`,
|
|
1491
|
+
"",
|
|
1492
|
+
`Why it matters: ${gap.why}`,
|
|
1493
|
+
""
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
lines.push("## Next", "", discovery.next);
|
|
1498
|
+
return `${lines.join("\n")}\n`;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1357
1501
|
function renderBrainstormMarkdown(brainstorm) {
|
|
1358
1502
|
const lines = [
|
|
1359
1503
|
`# ${brainstorm.id} Brainstorm`,
|
|
@@ -1764,6 +1908,37 @@ export async function main(args) {
|
|
|
1764
1908
|
return;
|
|
1765
1909
|
}
|
|
1766
1910
|
|
|
1911
|
+
if (command === "discover") {
|
|
1912
|
+
const root = resolveRoot(args);
|
|
1913
|
+
const goal = String(argValue(args, "--goal", argValue(args, "--idea", ""))).trim();
|
|
1914
|
+
if (!goal) throw new Error("--goal is required");
|
|
1915
|
+
const discovery = discoverAcceptance(goal, argValue(args, "--id"));
|
|
1916
|
+
const paths = discoveryPaths(root, discovery.id);
|
|
1917
|
+
writeJson(paths.jsonPath, discovery);
|
|
1918
|
+
fs.mkdirSync(path.dirname(paths.markdownPath), { recursive: true });
|
|
1919
|
+
fs.writeFileSync(paths.markdownPath, renderDiscoveryMarkdown(discovery));
|
|
1920
|
+
refreshManifest(root);
|
|
1921
|
+
printJson(ok(
|
|
1922
|
+
{
|
|
1923
|
+
discovery_id: discovery.id,
|
|
1924
|
+
status: discovery.status,
|
|
1925
|
+
goal: discovery.goal,
|
|
1926
|
+
gaps: discovery.gaps,
|
|
1927
|
+
questions: discovery.gaps.map((gap) => gap.question),
|
|
1928
|
+
discovery_path: paths.jsonPath,
|
|
1929
|
+
markdown_path: paths.markdownPath,
|
|
1930
|
+
is_acceptance_contract: false
|
|
1931
|
+
},
|
|
1932
|
+
[
|
|
1933
|
+
{ kind: "acceptance_discovery", path: paths.jsonPath },
|
|
1934
|
+
{ kind: "acceptance_discovery_markdown", path: paths.markdownPath }
|
|
1935
|
+
],
|
|
1936
|
+
[],
|
|
1937
|
+
[discovery.next]
|
|
1938
|
+
));
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1767
1942
|
if (command === "draft") {
|
|
1768
1943
|
const root = resolveRoot(args);
|
|
1769
1944
|
const brainstormId = argValue(args, "--from-brainstorm");
|