@haaaiawd/loom 0.10.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +147 -74
- package/cli/bin/loom.js +428 -105
- package/cli/help/asset.md +36 -0
- package/cli/help/atelier.md +37 -0
- package/cli/help/capability.md +68 -0
- package/cli/help/concepts.md +100 -72
- package/cli/help/doctor.md +71 -121
- package/cli/help/loop.md +120 -135
- package/cli/help/patch.md +33 -0
- package/cli/help/preview.md +2 -1
- package/cli/help/proposals.md +21 -0
- package/cli/help/version.md +92 -16
- package/cli/help/workflow.md +101 -100
- package/cli/src/activate.js +349 -73
- package/cli/src/asset-library.js +384 -0
- package/cli/src/atelier.js +331 -0
- package/cli/src/capability-graph.js +351 -0
- package/cli/src/capability-proposals.js +225 -0
- package/cli/src/diagnostics.js +240 -44
- package/cli/src/guide.js +155 -40
- package/cli/src/init.js +58 -32
- package/cli/src/intent-draft.js +303 -0
- package/cli/src/intent-map.js +560 -54
- package/cli/src/patch.js +214 -0
- package/cli/src/philosophy.js +177 -154
- package/cli/src/preview-prompt.md +13 -6
- package/cli/src/preview.js +1 -0
- package/cli/src/shared/intent-ref.js +38 -0
- package/cli/src/shared/proof-reference.js +19 -0
- package/cli/src/shared/verification-method.js +32 -0
- package/cli/src/verify.js +202 -62
- package/cli/src/version.js +5 -4
- package/dimensions/AUTHORSHIP.md +45 -0
- package/dimensions/PART_DECOMPOSITION.md +42 -203
- package/dimensions/SEARCH_METHODOLOGY.md +101 -97
- package/dimensions/examples/AGENT_SYSTEM/README.md +1 -1
- package/dimensions/examples/CLI_TOOL/README.md +1 -1
- package/dimensions/universal/COLLABORATION_PHILOSOPHY.md +28 -77
- package/dimensions/universal/ENGINEERING_CREED.md +30 -74
- package/dimensions/universal/PRODUCT_PHILOSOPHY.md +32 -70
- package/meta/BASELINE.md +91 -276
- package/meta/INTENT_LOOP.md +289 -737
- package/meta/PHILOSOPHY_WEAVER.md +110 -343
- package/meta/ROLE_ACTIVATION.md +109 -267
- package/package.json +13 -7
- package/roles/architect.md +84 -111
- package/roles/forge.md +105 -126
- package/roles/keeper.md +109 -223
- package/roles/visionary.md +57 -86
- package/templates/ASSET_LIBRARY_MANIFEST_TEMPLATE.json +10 -0
- package/templates/ATELIER_RECORD_TEMPLATE.json +48 -0
- package/templates/CAPABILITY_BRIEF_TEMPLATE.md +34 -0
- package/templates/CAPABILITY_GRAPH_TEMPLATE.json +11 -0
- package/templates/INTENT_MAP_TEMPLATE.json +26 -10
- package/templates/PHILOSOPHY_TEMPLATE.md +44 -75
- package/templates/VISION_TEMPLATE.md +44 -67
package/cli/bin/loom.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// loom — LOOM 框架的 CLI 传感器层
|
|
3
3
|
// Agent 通过这个 CLI 访问 Intent Map / 哲学 / 验证记录,不直接读文件。
|
|
4
4
|
|
|
5
|
-
import { argv, cwd, exit } from 'node:process';
|
|
5
|
+
import { argv, cwd, env, exit } from 'node:process';
|
|
6
6
|
import { resolve, join, dirname } from 'node:path';
|
|
7
7
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
@@ -10,9 +10,9 @@ import { findLoomRoot, findVersionDir, readCurrentPointer } from '../src/shared/
|
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
|
|
13
|
-
import { getNextIntent, getStatus, getDependencyGraph, getIntent, loadIntentMap, updateIntentStatus, getNarrative } from '../src/intent-map.js';
|
|
14
|
-
import { getPhilosophy, listPhilosophyFiles,
|
|
15
|
-
import { writeVerification, createQuickVerification, getVerificationHistory, getPendingVerifications, listVerifications, getVerificationContract } from '../src/verify.js';
|
|
13
|
+
import { deprecateIntent, getNextIntent, getStatus, getDependencyGraph, getIntent, loadIntentMap, updateIntentStatus, getNarrative, diffIntentVersions } from '../src/intent-map.js';
|
|
14
|
+
import { assessPhilosophyImpact, getPhilosophy, listPhilosophyFiles, revisePhilosophy, validateInspirationSources } from '../src/philosophy.js';
|
|
15
|
+
import { writeVerification, createQuickVerification, getVerificationHistory, getAcrossVersionVerificationHistory, getPendingVerifications, listVerifications, getVerificationContract, isVerificationCurrent } from '../src/verify.js';
|
|
16
16
|
import { initProject } from '../src/init.js';
|
|
17
17
|
import { activateRole } from '../src/activate.js';
|
|
18
18
|
import { listVersions, newVersion, useVersion, diffVersions } from '../src/version.js';
|
|
@@ -20,7 +20,14 @@ import { doctor, contextSummary, traceIntent, reverseDep, reverseRef } from '../
|
|
|
20
20
|
import { getHelpTopic, listHelpTopics } from '../src/help.js';
|
|
21
21
|
import { guideProject } from '../src/guide.js';
|
|
22
22
|
import { isAutoOn, autoOn, autoOff, autoStatus, getAutoMode } from '../src/auto.js';
|
|
23
|
-
import { generatePreviewPrompt, getPreviewStatus } from '../src/preview.js';
|
|
23
|
+
import { generatePreviewPrompt, getPreviewStatus } from '../src/preview.js';
|
|
24
|
+
import { getPatch, listPatches, recordPatch, validatePatches } from '../src/patch.js';
|
|
25
|
+
import { addIntentDraft, finalizeIntentDraft, getIntentDraft, reviseIntentDraft } from '../src/intent-draft.js';
|
|
26
|
+
import { resolveIntentRef } from '../src/shared/intent-ref.js';
|
|
27
|
+
import { compileCapabilityInputs, getCapabilityCoverage, getCapabilityFrontier, getCapabilityGraphProjection, getCapabilityNode } from '../src/capability-graph.js';
|
|
28
|
+
import { getAsset, importAsset, listAssets, recoverAssetImportTransaction, searchAssets, validateAssetLibrary } from '../src/asset-library.js';
|
|
29
|
+
import { closeCapabilityProposal, decideCapabilityProposal, getCapabilityProposal, listCapabilityProposals, submitCapabilityProposal } from '../src/capability-proposals.js';
|
|
30
|
+
import { getAtelierRecord, initAtelierRecord, validateAtelierRecord } from '../src/atelier.js';
|
|
24
31
|
|
|
25
32
|
// ─── 路径解析 ──────────────────────────────────────────
|
|
26
33
|
// findLoomRoot / findVersionDir / readCurrentPointer 已提取到 shared/paths.js
|
|
@@ -55,18 +62,197 @@ const [cmd, sub, ...rest] = argv.slice(2);
|
|
|
55
62
|
|
|
56
63
|
try {
|
|
57
64
|
switch (cmd) {
|
|
58
|
-
case '--version':
|
|
65
|
+
case '--version':
|
|
59
66
|
case '-v': {
|
|
60
67
|
// 从根 package.json 读版本号(cli/bin -> cli -> LOOM root)
|
|
61
68
|
const pkgPath = resolve(__dirname, '..', '..', 'package.json');
|
|
62
69
|
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
63
70
|
console.log(`loom ${pkg.version}`);
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
case '
|
|
68
|
-
const versionDir = findVersionDir();
|
|
69
|
-
switch (sub) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
case 'capability': {
|
|
75
|
+
const versionDir = findVersionDir();
|
|
76
|
+
switch (sub) {
|
|
77
|
+
case 'graph':
|
|
78
|
+
output(getCapabilityGraphProjection(versionDir));
|
|
79
|
+
break;
|
|
80
|
+
case 'frontier':
|
|
81
|
+
output(getCapabilityFrontier(versionDir));
|
|
82
|
+
break;
|
|
83
|
+
case 'get': {
|
|
84
|
+
const id = rest[0];
|
|
85
|
+
if (!id) die('用法: loom capability get <node-id>');
|
|
86
|
+
output(getCapabilityNode(versionDir, id));
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case 'coverage':
|
|
90
|
+
output(getCapabilityCoverage(versionDir));
|
|
91
|
+
break;
|
|
92
|
+
case 'compile': {
|
|
93
|
+
const intentId = rest[0];
|
|
94
|
+
if (!intentId) die('用法: loom capability compile <intent-id>');
|
|
95
|
+
output(compileCapabilityInputs(versionDir, intentId));
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case 'proposal': {
|
|
99
|
+
const action = rest[0];
|
|
100
|
+
if (action === 'list') output(listCapabilityProposals(versionDir));
|
|
101
|
+
else if (action === 'get') {
|
|
102
|
+
if (!rest[1]) die('用法: loom capability proposal get <CGP-ID>');
|
|
103
|
+
output(getCapabilityProposal(versionDir, rest[1]));
|
|
104
|
+
} else if (action === 'submit') {
|
|
105
|
+
const fileIndex = argv.indexOf('--json-file');
|
|
106
|
+
const path = fileIndex === -1 ? null : argv[fileIndex + 1];
|
|
107
|
+
if (!path) die('用法: loom capability proposal submit --json-file <proposal.json>');
|
|
108
|
+
output(submitCapabilityProposal(versionDir, JSON.parse(readFileSync(path, 'utf-8'))));
|
|
109
|
+
} else if (action === 'decide') {
|
|
110
|
+
const rationaleIndex = argv.indexOf('--rationale');
|
|
111
|
+
if (!rest[1] || !rest[2] || rationaleIndex === -1 || !argv[rationaleIndex + 1]) die('用法: loom capability proposal decide <CGP-ID> <decision> --rationale <text>');
|
|
112
|
+
output(decideCapabilityProposal(versionDir, rest[1], rest[2], argv[rationaleIndex + 1]));
|
|
113
|
+
} else if (action === 'close') {
|
|
114
|
+
const resolutionIndex = argv.indexOf('--resolution-file');
|
|
115
|
+
if (!rest[1] || resolutionIndex === -1 || !argv[resolutionIndex + 1]) die('用法: loom capability proposal close <CGP-ID> --resolution-file <resolution.json>');
|
|
116
|
+
output(closeCapabilityProposal(versionDir, rest[1], JSON.parse(readFileSync(argv[resolutionIndex + 1], 'utf-8'))));
|
|
117
|
+
} else die('用法: loom capability proposal [list|get|submit|decide|close]');
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
default:
|
|
121
|
+
die(`未知 capability 子命令: ${sub}\n用法: loom capability [graph|frontier|get|coverage|compile|proposal]`);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
case 'asset': {
|
|
127
|
+
const versionDir = findVersionDir();
|
|
128
|
+
switch (sub) {
|
|
129
|
+
case 'import': {
|
|
130
|
+
const filePath = rest[0];
|
|
131
|
+
const option = (name) => {
|
|
132
|
+
const index = argv.indexOf(name);
|
|
133
|
+
return index === -1 ? undefined : argv[index + 1];
|
|
134
|
+
};
|
|
135
|
+
if (!filePath || filePath.startsWith('--')) die('用法: loom asset import <本地文件> --tags <标签,...> --source <来源> --author <作者> --license <许可> --approval approved [--kind image] [--evidence <节点,...>]');
|
|
136
|
+
output(importAsset(versionDir, filePath, {
|
|
137
|
+
tags: option('--tags'), source: option('--source'), author: option('--author'), license: option('--license'),
|
|
138
|
+
approval: option('--approval'), kind: option('--kind'), evidenceRefs: option('--evidence'),
|
|
139
|
+
failureInjection: env.NODE_ENV === 'test' && option('--test-fail-after') === 'manifest' ? 'after_manifest'
|
|
140
|
+
: env.NODE_ENV === 'test' && option('--test-fail-after') === 'crash-manifest' ? 'crash_after_manifest' : undefined,
|
|
141
|
+
}));
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
case 'list': output(listAssets(versionDir)); break;
|
|
145
|
+
case 'search': {
|
|
146
|
+
const query = rest[0];
|
|
147
|
+
if (!query) die('用法: loom asset search <查询>');
|
|
148
|
+
output(searchAssets(versionDir, query));
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case 'get': {
|
|
152
|
+
const id = rest[0];
|
|
153
|
+
if (!id) die('用法: loom asset get <asset-id>');
|
|
154
|
+
output(getAsset(versionDir, id));
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case 'validate': {
|
|
158
|
+
const recovery = recoverAssetImportTransaction(versionDir);
|
|
159
|
+
output({ valid: true, assets: Object.keys(validateAssetLibrary(versionDir).assets).length, recovered_transaction: recovery.recovered ? recovery : null });
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
default: die(`未知 asset 子命令: ${sub}\n用法: loom asset [import|list|search|get|validate]`);
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
case 'atelier': {
|
|
168
|
+
const versionDir = findVersionDir();
|
|
169
|
+
const intentId = rest[0];
|
|
170
|
+
if (!intentId) die(`用法: loom atelier ${sub || '<init|get|validate>'} <intent-id>`);
|
|
171
|
+
switch (sub) {
|
|
172
|
+
case 'init':
|
|
173
|
+
output(initAtelierRecord(versionDir, intentId));
|
|
174
|
+
break;
|
|
175
|
+
case 'get':
|
|
176
|
+
output(getAtelierRecord(versionDir, intentId));
|
|
177
|
+
break;
|
|
178
|
+
case 'validate':
|
|
179
|
+
output(validateAtelierRecord(versionDir, intentId));
|
|
180
|
+
break;
|
|
181
|
+
default:
|
|
182
|
+
die(`未知 atelier 子命令: ${sub}\n用法: loom atelier [init|get|validate] <intent-id>`);
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
case 'intent': {
|
|
188
|
+
const versionDir = findVersionDir();
|
|
189
|
+
switch (sub) {
|
|
190
|
+
case 'add': {
|
|
191
|
+
const titleIdx = argv.indexOf('--title');
|
|
192
|
+
const dependsIdx = argv.indexOf('--depends-on');
|
|
193
|
+
const title = titleIdx !== -1 ? argv[titleIdx + 1] : null;
|
|
194
|
+
const dependencies = dependsIdx !== -1 && argv[dependsIdx + 1]
|
|
195
|
+
? argv[dependsIdx + 1].split(',').map((id) => id.trim()).filter(Boolean)
|
|
196
|
+
: [];
|
|
197
|
+
if (!title) die('用法: loom intent add --title <text> [--depends-on INT-001,INT-002]');
|
|
198
|
+
output(addIntentDraft(versionDir, title, dependencies));
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case 'revise': {
|
|
202
|
+
const id = rest[0];
|
|
203
|
+
const reasonIdx = argv.indexOf('--reason');
|
|
204
|
+
const reason = reasonIdx !== -1 ? argv[reasonIdx + 1] : null;
|
|
205
|
+
if (!id || !reason) die('用法: loom intent revise <id> --reason <text>');
|
|
206
|
+
output(reviseIntentDraft(versionDir, id, reason));
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case 'draft': {
|
|
210
|
+
const id = rest[0];
|
|
211
|
+
if (!id) die('用法: loom intent draft <id>');
|
|
212
|
+
output(getIntentDraft(versionDir, id));
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
case 'finalize': {
|
|
216
|
+
const id = rest[0];
|
|
217
|
+
if (!id) die('用法: loom intent finalize <id>');
|
|
218
|
+
const parseIds = (name) => {
|
|
219
|
+
const index = argv.indexOf(name);
|
|
220
|
+
if (index === -1) return [];
|
|
221
|
+
const value = argv[index + 1];
|
|
222
|
+
if (!value || value.startsWith('--')) die(`${name} 需要逗号分隔的 Intent ID`);
|
|
223
|
+
return value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
224
|
+
};
|
|
225
|
+
output(finalizeIntentDraft(versionDir, id, {
|
|
226
|
+
review: parseIds('--review'),
|
|
227
|
+
unaffected: parseIds('--unaffected'),
|
|
228
|
+
}));
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
case 'deprecate': {
|
|
232
|
+
const id = rest[0];
|
|
233
|
+
const readFlag = (name) => {
|
|
234
|
+
const index = argv.indexOf(name);
|
|
235
|
+
return index === -1 ? null : argv[index + 1];
|
|
236
|
+
};
|
|
237
|
+
const parseIds = (name) => {
|
|
238
|
+
const value = readFlag(name);
|
|
239
|
+
if (value === null) return [];
|
|
240
|
+
if (!value || value.startsWith('--')) die(`${name} 需要逗号分隔的 Intent ID`);
|
|
241
|
+
return value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
242
|
+
};
|
|
243
|
+
const reason = readFlag('--reason');
|
|
244
|
+
if (!id || !reason || reason.startsWith('--')) die('用法: loom intent deprecate <id> --reason <text> [--confirm [--replacement <id>] [--review <ids>] [--unaffected <ids>]]');
|
|
245
|
+
const replacement = readFlag('--replacement');
|
|
246
|
+
if (argv.includes('--replacement') && (!replacement || replacement.startsWith('--'))) die('--replacement 需要当前版本的 Intent ID');
|
|
247
|
+
output(deprecateIntent(versionDir, id, {
|
|
248
|
+
reason,
|
|
249
|
+
confirm: argv.includes('--confirm'),
|
|
250
|
+
replacement,
|
|
251
|
+
review: parseIds('--review'),
|
|
252
|
+
unaffected: parseIds('--unaffected'),
|
|
253
|
+
}));
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
70
256
|
case 'next':
|
|
71
257
|
output(getNextIntent(versionDir) ?? '没有可执行的 Intent');
|
|
72
258
|
break;
|
|
@@ -76,25 +262,36 @@ try {
|
|
|
76
262
|
console.log(`进度: ${s.counts.completed}/${s.counts.total} 完成`);
|
|
77
263
|
console.log(` pending: ${s.counts.pending} ${fmt(s.ids.pending)}`);
|
|
78
264
|
console.log(` in_progress: ${s.counts.in_progress} ${fmt(s.ids.in_progress)}`);
|
|
79
|
-
console.log(` completed: ${s.counts.completed} ${fmt(s.ids.completed)}`);
|
|
80
|
-
console.log(` blocked: ${s.counts.blocked} ${fmt(s.ids.blocked)}`);
|
|
81
|
-
|
|
265
|
+
console.log(` completed: ${s.counts.completed} ${fmt(s.ids.completed)}`);
|
|
266
|
+
console.log(` blocked: ${s.counts.blocked} ${fmt(s.ids.blocked)}`);
|
|
267
|
+
console.log(` needs_review: ${s.counts.needs_review} ${fmt(s.ids.needs_review)}`);
|
|
268
|
+
console.log(` deprecated: ${s.counts.deprecated} ${fmt(s.deprecated)}`);
|
|
269
|
+
break;
|
|
82
270
|
}
|
|
83
271
|
case 'graph':
|
|
84
272
|
output(getDependencyGraph(versionDir));
|
|
85
273
|
break;
|
|
86
|
-
case 'get': {
|
|
87
|
-
const id = rest[0];
|
|
88
|
-
if (!id) die('用法: loom intent get <id>');
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
274
|
+
case 'get': {
|
|
275
|
+
const id = rest[0];
|
|
276
|
+
if (!id) die('用法: loom intent get <id>');
|
|
277
|
+
const resolved = resolveIntentRef(versionDir, id);
|
|
278
|
+
output(getIntent(resolved.versionDir, resolved.intentId));
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
92
281
|
case 'narrative': {
|
|
93
282
|
const id = rest[0];
|
|
94
283
|
if (!id) die('用法: loom intent narrative <id>');
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
284
|
+
const resolved = resolveIntentRef(versionDir, id);
|
|
285
|
+
output(getNarrative(resolved.versionDir, resolved.intentId));
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
case 'diff': {
|
|
289
|
+
const from = rest[0];
|
|
290
|
+
const to = rest[1];
|
|
291
|
+
if (!from || !to) die('用法: loom intent diff <v1> <v2>');
|
|
292
|
+
output(diffIntentVersions(findLoomRoot(), from, to));
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
98
295
|
case 'validate':
|
|
99
296
|
loadIntentMap(versionDir);
|
|
100
297
|
console.log('Intent Map 校验通过');
|
|
@@ -102,7 +299,8 @@ try {
|
|
|
102
299
|
case 'trace': {
|
|
103
300
|
const id = rest[0];
|
|
104
301
|
if (!id) die('用法: loom intent trace <id>');
|
|
105
|
-
|
|
302
|
+
const resolved = resolveIntentRef(versionDir, id);
|
|
303
|
+
output(traceIntent(resolved.versionDir, getVerificationsDir(resolved.versionDir), getPhilosophyDir(resolved.versionDir), resolved.intentId));
|
|
106
304
|
break;
|
|
107
305
|
}
|
|
108
306
|
case 'reverse-dep': {
|
|
@@ -136,14 +334,28 @@ try {
|
|
|
136
334
|
if (!history || history.records.length === 0) {
|
|
137
335
|
die(`${id} 没有验证记录。先跑: loom verify pass ${id} --summary "..."`);
|
|
138
336
|
}
|
|
139
|
-
//
|
|
140
|
-
const latest = history.records[history.records.length - 1];
|
|
141
|
-
if (latest.verdict !== 'passed') {
|
|
142
|
-
die(`${id} 最新验证记录是 ${latest.verdict}(非 passed)。只有 passed 的 Intent 才能 done。`);
|
|
143
|
-
}
|
|
144
|
-
// 获取当前状态,自动走两步
|
|
145
|
-
const intent = getIntent(versionDir, id);
|
|
146
|
-
|
|
337
|
+
// 最新记录必须针对当前 revision 且通过,旧 revision 的通过不能闭合 Intent。
|
|
338
|
+
const latest = history.records[history.records.length - 1];
|
|
339
|
+
if (latest.verdict !== 'passed') {
|
|
340
|
+
die(`${id} 最新验证记录是 ${latest.verdict}(非 passed)。只有 passed 的 Intent 才能 done。`);
|
|
341
|
+
}
|
|
342
|
+
// 获取当前状态,自动走两步
|
|
343
|
+
const intent = getIntent(versionDir, id);
|
|
344
|
+
if (!isVerificationCurrent(intent, latest)) {
|
|
345
|
+
die(`${id} 最新 passed 验证不属于当前 Intent revision ${intent.revision ?? 1}。先重新验证。`);
|
|
346
|
+
}
|
|
347
|
+
if (intent.quality_strategy === 'atelier') {
|
|
348
|
+
const atelier = validateAtelierRecord(versionDir, id);
|
|
349
|
+
if (!['selected', 'baseline_retained'].includes(atelier.status)) {
|
|
350
|
+
die(`${id} 的 Atelier Record 尚未完成选择(当前: ${atelier.status})`);
|
|
351
|
+
}
|
|
352
|
+
if (latest.atelier?.record_ref !== `09_ATELIER/${id}.json`
|
|
353
|
+
|| latest.atelier?.stance_revision !== atelier.stance_revision
|
|
354
|
+
|| latest.atelier?.status !== atelier.status) {
|
|
355
|
+
die(`${id} 最新 passed 未绑定当前 Atelier Record 与 stance_revision。请在新的 Keeper task 中重新验证。`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const currentStatus = intent.status;
|
|
147
359
|
if (currentStatus === 'completed') {
|
|
148
360
|
console.log(`${id} 已经是 completed,无需操作`);
|
|
149
361
|
break;
|
|
@@ -156,13 +368,17 @@ try {
|
|
|
156
368
|
break;
|
|
157
369
|
}
|
|
158
370
|
default:
|
|
159
|
-
die(`未知子命令: intent ${sub}\n用法: loom intent [next|status|graph|get
|
|
371
|
+
die(`未知子命令: intent ${sub}\n用法: loom intent [add|revise|draft|finalize|deprecate|next|status|graph|get|narrative|diff|validate|trace|reverse-dep|reverse-ref|update|done]`);
|
|
160
372
|
}
|
|
161
373
|
break;
|
|
162
374
|
}
|
|
163
375
|
|
|
164
|
-
case 'init': {
|
|
165
|
-
|
|
376
|
+
case 'init': {
|
|
377
|
+
if (sub === '--help' || sub === '-h') {
|
|
378
|
+
console.log('用法: loom init\\n\\n在当前目录创建 LOOM 项目骨架。若目录已有 .loom/,不会覆盖现有文件。');
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
const result = initProject(cwd());
|
|
166
382
|
console.log('LOOM 项目已初始化');
|
|
167
383
|
for (const c of result.created) console.log(` [created] ${c}`);
|
|
168
384
|
for (const s of result.skipped) console.log(` [skipped] ${s} (already exists)`);
|
|
@@ -179,7 +395,7 @@ try {
|
|
|
179
395
|
}
|
|
180
396
|
|
|
181
397
|
case 'activate': {
|
|
182
|
-
const role = sub;
|
|
398
|
+
const role = sub;
|
|
183
399
|
if (!role) die('用法: loom activate <role>\n角色: weaver | visionary | architect | forge | keeper');
|
|
184
400
|
// weaver 不需要 versionDir(项目还没初始化时也能激活)
|
|
185
401
|
let versionDir = null;
|
|
@@ -191,7 +407,10 @@ try {
|
|
|
191
407
|
if (!String(e.message).includes('找不到 .loom')) throw e;
|
|
192
408
|
}
|
|
193
409
|
}
|
|
194
|
-
const
|
|
410
|
+
const intentIdx = argv.indexOf('--intent');
|
|
411
|
+
const intentId = intentIdx !== -1 ? argv[intentIdx + 1] : null;
|
|
412
|
+
if (intentIdx !== -1 && !intentId) die('用法: loom activate <role> --intent <id>');
|
|
413
|
+
const prompt = activateRole(role, versionDir, intentId);
|
|
195
414
|
output(prompt);
|
|
196
415
|
break;
|
|
197
416
|
}
|
|
@@ -205,24 +424,54 @@ try {
|
|
|
205
424
|
output(getPhilosophy(getPhilosophyDir(versionDir), anchor));
|
|
206
425
|
break;
|
|
207
426
|
}
|
|
208
|
-
case 'list':
|
|
209
|
-
output(listPhilosophyFiles(getPhilosophyDir(versionDir)));
|
|
210
|
-
break;
|
|
427
|
+
case 'list':
|
|
428
|
+
output(listPhilosophyFiles(getPhilosophyDir(versionDir)));
|
|
429
|
+
break;
|
|
430
|
+
case 'impact': {
|
|
431
|
+
const anchor = rest[0];
|
|
432
|
+
if (!anchor) die('用法: loom philosophy impact <anchor>');
|
|
433
|
+
output(assessPhilosophyImpact(versionDir, anchor));
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
case 'revise': {
|
|
437
|
+
const anchor = rest[0];
|
|
438
|
+
const readFlag = (name) => {
|
|
439
|
+
const index = argv.indexOf(name);
|
|
440
|
+
return index === -1 ? null : argv[index + 1];
|
|
441
|
+
};
|
|
442
|
+
const parseIds = (name) => {
|
|
443
|
+
const value = readFlag(name);
|
|
444
|
+
if (value === null) return [];
|
|
445
|
+
if (!value || value.startsWith('--')) die(`${name} 需要逗号分隔的 Intent ID`);
|
|
446
|
+
return value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
447
|
+
};
|
|
448
|
+
const classification = readFlag('--classification');
|
|
449
|
+
const reason = readFlag('--reason');
|
|
450
|
+
if (!anchor || !classification || classification.startsWith('--') || !reason || reason.startsWith('--')) {
|
|
451
|
+
die('用法: loom philosophy revise <anchor> --classification <clarification|minor|major> --reason <text> [--confirm --review <ids> --unaffected <ids>]');
|
|
452
|
+
}
|
|
453
|
+
output(revisePhilosophy(versionDir, anchor, {
|
|
454
|
+
classification,
|
|
455
|
+
reason,
|
|
456
|
+
confirm: argv.includes('--confirm'),
|
|
457
|
+
review: parseIds('--review'),
|
|
458
|
+
unaffected: parseIds('--unaffected'),
|
|
459
|
+
}));
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
211
462
|
case 'check': {
|
|
212
|
-
const philDir = getPhilosophyDir(versionDir);
|
|
213
|
-
const inspiration = validateInspirationSources(philDir);
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const allPassed = inspiration.passed && decomposition.passed;
|
|
463
|
+
const philDir = getPhilosophyDir(versionDir);
|
|
464
|
+
const inspiration = validateInspirationSources(philDir);
|
|
465
|
+
const allIssues = inspiration.issues;
|
|
466
|
+
const allPassed = inspiration.passed;
|
|
217
467
|
|
|
218
468
|
// --json: 结构化输出,供 Agent 程序化消费
|
|
219
469
|
if (argv.includes('--json')) {
|
|
220
470
|
output({
|
|
221
|
-
passed: allPassed,
|
|
222
|
-
issues: allIssues,
|
|
223
|
-
sources: inspiration.sources.map(({ file, sources }) => ({ file, count: sources.length })),
|
|
224
|
-
|
|
225
|
-
});
|
|
471
|
+
passed: allPassed,
|
|
472
|
+
issues: allIssues,
|
|
473
|
+
sources: inspiration.sources.map(({ file, sources }) => ({ file, count: sources.length })),
|
|
474
|
+
});
|
|
226
475
|
exit(allPassed ? 0 : 1);
|
|
227
476
|
}
|
|
228
477
|
|
|
@@ -232,10 +481,6 @@ try {
|
|
|
232
481
|
for (const { file, sources } of inspiration.sources) {
|
|
233
482
|
console.log(` ${file}: ${sources.length} 个源`);
|
|
234
483
|
}
|
|
235
|
-
console.log(' 实现部分拆解:');
|
|
236
|
-
for (const part of decomposition.parts) {
|
|
237
|
-
console.log(` - ${part}`);
|
|
238
|
-
}
|
|
239
484
|
} else {
|
|
240
485
|
const high = allIssues.filter((i) => i.severity === 'high').length;
|
|
241
486
|
const medium = allIssues.filter((i) => i.severity === 'medium').length;
|
|
@@ -244,13 +489,13 @@ try {
|
|
|
244
489
|
const icon = issue.severity === 'high' ? '⚠' : '·';
|
|
245
490
|
console.log(` ${icon} [${issue.severity}] ${issue.msg}`);
|
|
246
491
|
}
|
|
247
|
-
console.log('\n参见 meta/PHILOSOPHY_WEAVER.md + dimensions/
|
|
492
|
+
console.log('\n参见 meta/PHILOSOPHY_WEAVER.md + dimensions/SEARCH_METHODOLOGY.md。');
|
|
248
493
|
exit(1);
|
|
249
494
|
}
|
|
250
495
|
break;
|
|
251
496
|
}
|
|
252
497
|
default:
|
|
253
|
-
die(`未知子命令: philosophy ${sub}\n用法: loom philosophy [get <anchor>|list|check]`);
|
|
498
|
+
die(`未知子命令: philosophy ${sub}\n用法: loom philosophy [get <anchor>|list|check|impact <anchor>|revise <anchor> --classification <clarification|minor|major> --reason <text>]`);
|
|
254
499
|
}
|
|
255
500
|
break;
|
|
256
501
|
}
|
|
@@ -265,11 +510,16 @@ try {
|
|
|
265
510
|
output(getVerificationContract(versionDir, id));
|
|
266
511
|
break;
|
|
267
512
|
}
|
|
268
|
-
case 'history': {
|
|
269
|
-
const id = rest[0];
|
|
270
|
-
if (!id) die('用法: loom verify history <id>');
|
|
271
|
-
|
|
272
|
-
|
|
513
|
+
case 'history': {
|
|
514
|
+
const id = rest[0];
|
|
515
|
+
if (!id) die('用法: loom verify history <id>');
|
|
516
|
+
if (argv.includes('--across-versions')) {
|
|
517
|
+
output(getAcrossVersionVerificationHistory(versionDir, id));
|
|
518
|
+
} else {
|
|
519
|
+
const resolved = resolveIntentRef(versionDir, id);
|
|
520
|
+
const history = getVerificationHistory(getVerificationsDir(resolved.versionDir), resolved.intentId);
|
|
521
|
+
output(history ?? `没有 ${resolved.ref} 的验证记录`);
|
|
522
|
+
}
|
|
273
523
|
break;
|
|
274
524
|
}
|
|
275
525
|
case 'pending':
|
|
@@ -299,41 +549,54 @@ try {
|
|
|
299
549
|
} else {
|
|
300
550
|
die('用法: loom verify write --json-file <path> | --json <json-string>');
|
|
301
551
|
}
|
|
302
|
-
const result = writeVerification(verificationsDir, record);
|
|
552
|
+
const result = writeVerification(versionDir, verificationsDir, record);
|
|
303
553
|
console.log(`验证记录已写入: ${result.filePath}`);
|
|
304
554
|
console.log(` 轮次: ${result.round}, verdict: ${record.verdict}`);
|
|
305
|
-
if (record.verdict === 'deviated') {
|
|
306
|
-
console.log(` deviated 累计: ${result.deviated_count} 轮`);
|
|
307
|
-
if (result.should_escalate) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
555
|
+
if (record.verdict === 'deviated') {
|
|
556
|
+
console.log(` deviated 累计: ${result.deviated_count} 轮`);
|
|
557
|
+
if (result.should_escalate) {
|
|
558
|
+
updateIntentStatus(versionDir, record.intent_id, 'blocked');
|
|
559
|
+
console.log(` ⚠ 已达到 3 轮上限,${record.intent_id} 已自动升级为 blocked`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
311
562
|
break;
|
|
312
563
|
}
|
|
313
564
|
case 'pass':
|
|
314
565
|
case 'fail': {
|
|
315
|
-
// loom verify pass <id> --summary "..." [--reproduction-command "..."]
|
|
316
|
-
// loom verify fail <id> --summary "..." [--deviation "..."] [--reproduction-command "..."]
|
|
317
|
-
const id = rest[0];
|
|
318
|
-
if (!id) die(`用法: loom verify ${sub} <id> --summary "..." [--reproduction-command "..."]${sub === '
|
|
319
|
-
const summaryIdx = argv.indexOf('--summary');
|
|
320
|
-
const reproIdx = argv.indexOf('--reproduction-command');
|
|
321
|
-
const deviationIdx = argv.indexOf('--deviation');
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
326
|
-
|
|
566
|
+
// loom verify pass <id> --summary "..." [--reproduction-command "..."] [--preservation-evidence "..."] [--quality-proof "..."]
|
|
567
|
+
// loom verify fail <id> --summary "..." [--deviation "..."] [--reproduction-command "..."]
|
|
568
|
+
const id = rest[0];
|
|
569
|
+
if (!id) die(`用法: loom verify ${sub} <id> --summary "..." [--reproduction-command "..."]${sub === 'pass' ? ' [--preservation-evidence "..."] [--quality-proof "..."]' : ' [--deviation "..."]'}`);
|
|
570
|
+
const summaryIdx = argv.indexOf('--summary');
|
|
571
|
+
const reproIdx = argv.indexOf('--reproduction-command');
|
|
572
|
+
const deviationIdx = argv.indexOf('--deviation');
|
|
573
|
+
const qualityProofIdx = argv.indexOf('--quality-proof');
|
|
574
|
+
const preservationIdx = argv.indexOf('--preservation-evidence');
|
|
575
|
+
const summary = summaryIdx !== -1 ? argv[summaryIdx + 1] : null;
|
|
576
|
+
if (!summary) die(`缺少 --summary: loom verify ${sub} ${id} --summary "..."`);
|
|
577
|
+
const intent = getIntent(versionDir, id);
|
|
578
|
+
if (sub === 'pass' && intent.continuity_required && !(preservationIdx !== -1 && argv[preservationIdx + 1])) {
|
|
579
|
+
die(`Intent ${id} 声明了 continuity_required;通过前必须提供 --preservation-evidence,证明旧状态 → 新操作后的完整序列未发生未授权丢失。`);
|
|
580
|
+
}
|
|
581
|
+
if (sub === 'pass' && intent.quality_contract && !(qualityProofIdx !== -1 && argv[qualityProofIdx + 1])) {
|
|
582
|
+
die(`Intent ${id} 声明了 quality_contract;通过前必须提供 --quality-proof,指向项目内真实的 Quality Proof Markdown 锚点。`);
|
|
583
|
+
}
|
|
584
|
+
const extras = {};
|
|
585
|
+
if (reproIdx !== -1 && argv[reproIdx + 1]) extras.reproduction_command = argv[reproIdx + 1];
|
|
586
|
+
if (sub === 'fail' && deviationIdx !== -1 && argv[deviationIdx + 1]) extras.deviation_detail = argv[deviationIdx + 1];
|
|
587
|
+
if (sub === 'pass' && qualityProofIdx !== -1 && argv[qualityProofIdx + 1]) extras.quality_proof_ref = argv[qualityProofIdx + 1];
|
|
588
|
+
if (sub === 'pass' && preservationIdx !== -1 && argv[preservationIdx + 1]) extras.preservation_evidence = argv[preservationIdx + 1];
|
|
327
589
|
const verdict = sub === 'pass' ? 'passed' : 'deviated';
|
|
328
|
-
const result = createQuickVerification(verificationsDir, id, verdict, summary, extras);
|
|
590
|
+
const result = createQuickVerification(versionDir, verificationsDir, id, verdict, summary, extras);
|
|
329
591
|
console.log(`验证记录已写入: ${result.filePath}`);
|
|
330
592
|
console.log(` 轮次: ${result.round}, verdict: ${verdict}`);
|
|
331
|
-
if (verdict === 'deviated') {
|
|
332
|
-
console.log(` deviated 累计: ${result.deviated_count} 轮`);
|
|
333
|
-
if (result.should_escalate) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
593
|
+
if (verdict === 'deviated') {
|
|
594
|
+
console.log(` deviated 累计: ${result.deviated_count} 轮`);
|
|
595
|
+
if (result.should_escalate) {
|
|
596
|
+
updateIntentStatus(versionDir, id, 'blocked');
|
|
597
|
+
console.log(` ⚠ 已达到 3 轮上限,${id} 已自动升级为 blocked`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
337
600
|
break;
|
|
338
601
|
}
|
|
339
602
|
default:
|
|
@@ -342,7 +605,7 @@ try {
|
|
|
342
605
|
break;
|
|
343
606
|
}
|
|
344
607
|
|
|
345
|
-
case 'version': {
|
|
608
|
+
case 'version': {
|
|
346
609
|
const loomRoot = findLoomRoot();
|
|
347
610
|
switch (sub) {
|
|
348
611
|
case 'list': {
|
|
@@ -389,8 +652,42 @@ try {
|
|
|
389
652
|
default:
|
|
390
653
|
die(`未知子命令: version ${sub}\n用法: loom version [list|current|new|use <v>|diff <v1> <v2>]`);
|
|
391
654
|
}
|
|
392
|
-
break;
|
|
393
|
-
}
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
case 'patch': {
|
|
659
|
+
const versionDir = findVersionDir();
|
|
660
|
+
switch (sub) {
|
|
661
|
+
case 'record': {
|
|
662
|
+
const fileFlagIdx = argv.indexOf('--json-file');
|
|
663
|
+
const inputPath = fileFlagIdx !== -1 ? argv[fileFlagIdx + 1] : null;
|
|
664
|
+
if (!inputPath) die('用法: loom patch record --json-file <path>');
|
|
665
|
+
let record;
|
|
666
|
+
try {
|
|
667
|
+
record = JSON.parse(readFileSync(inputPath, 'utf-8'));
|
|
668
|
+
} catch (e) {
|
|
669
|
+
die(`JSON 文件解析失败: ${inputPath}\n原因: ${e.message}`);
|
|
670
|
+
}
|
|
671
|
+
output(recordPatch(versionDir, record));
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
case 'list':
|
|
675
|
+
output(listPatches(versionDir));
|
|
676
|
+
break;
|
|
677
|
+
case 'get': {
|
|
678
|
+
const id = rest[0];
|
|
679
|
+
if (!id) die('用法: loom patch get <id>');
|
|
680
|
+
output(getPatch(versionDir, id));
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
case 'validate':
|
|
684
|
+
output(validatePatches(versionDir));
|
|
685
|
+
break;
|
|
686
|
+
default:
|
|
687
|
+
die(`未知子命令: patch ${sub}\n用法: loom patch [record --json-file <path>|list|get <id>|validate]`);
|
|
688
|
+
}
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
394
691
|
|
|
395
692
|
case 'doctor': {
|
|
396
693
|
const versionDir = findVersionDir();
|
|
@@ -406,7 +703,7 @@ try {
|
|
|
406
703
|
console.log(` → 修复: ${issue.fix_hint}`);
|
|
407
704
|
}
|
|
408
705
|
}
|
|
409
|
-
console.log(`\n参见 meta/PHILOSOPHY_WEAVER.md + dimensions/
|
|
706
|
+
console.log(`\n参见 meta/PHILOSOPHY_WEAVER.md + dimensions/SEARCH_METHODOLOGY.md。`);
|
|
410
707
|
}
|
|
411
708
|
break;
|
|
412
709
|
}
|
|
@@ -614,25 +911,46 @@ To Human:
|
|
|
614
911
|
loom init 初始化项目(创建 .loom/v1/ 骨架 + 模板)
|
|
615
912
|
loom guide 诊断当前阶段,输出下一步引导
|
|
616
913
|
loom guide --dry-run 只读诊断当前阶段,不写 heartbeat
|
|
617
|
-
loom auto on|off|status AUTO
|
|
618
|
-
loom activate <role>
|
|
914
|
+
loom auto on|off|status AUTO 编排协议开关(由 Agent/runtime 消费,不由 CLI 自行执行)
|
|
915
|
+
loom activate <role> [--intent <id>] 输出普通或 Intent-scoped 角色激活提示词
|
|
619
916
|
|
|
620
917
|
loom version list 列出所有版本(* 标记当前)
|
|
621
918
|
loom version current 显示当前版本
|
|
622
919
|
loom version new 创建 v{N+1} + 自动切换为当前
|
|
623
920
|
loom version use <v> 切换当前版本
|
|
624
|
-
loom version diff <v1> <v2> 对比两个版本的文件差异
|
|
625
|
-
|
|
626
|
-
loom
|
|
921
|
+
loom version diff <v1> <v2> 对比两个版本的文件差异
|
|
922
|
+
|
|
923
|
+
loom patch record --json-file <path> 记录 Patch 并生成 Markdown 投影
|
|
924
|
+
loom patch list 列出当前版本的 Patch
|
|
925
|
+
loom patch get <id> 返回指定 Patch
|
|
926
|
+
loom patch validate 校验 Patch ledger 和 Markdown 投影
|
|
927
|
+
|
|
928
|
+
loom capability graph 输出 Capability Graph 的 Mermaid 投影与摘要
|
|
929
|
+
loom capability frontier 列出尚未路由的高影响节点
|
|
930
|
+
loom capability get <id> 返回节点、关系、Brief 与 Intent 回链
|
|
931
|
+
loom capability coverage 检查图谱覆盖、Brief 和 Intent 回链
|
|
932
|
+
loom capability compile <id> 只读显示会进入该 Intent 的能力输入
|
|
933
|
+
loom atelier init <id> 为 atelier Intent 创建唯一创作记录
|
|
934
|
+
loom atelier get <id> 返回并校验当前 Atelier Record
|
|
935
|
+
loom atelier validate <id> 校验 Record、revision、候选与证据引用
|
|
936
|
+
|
|
937
|
+
loom intent next 返回下一个可执行 Intent
|
|
938
|
+
loom intent add --title <text> [--depends-on <ids>] 创建新增 draft
|
|
939
|
+
loom intent revise <id> --reason <text> 创建修订 draft 并报告反向依赖
|
|
940
|
+
loom intent draft <id> 查看 draft
|
|
941
|
+
loom intent finalize <id> 校验并原子写入官方 Intent Map
|
|
942
|
+
loom intent deprecate <id> --reason <text> 只读评估;加 --confirm 才弃用
|
|
627
943
|
loom intent status 返回进度概览
|
|
628
944
|
loom intent graph 输出 Mermaid 依赖图
|
|
629
945
|
loom intent get <id> 返回某 Intent 完整信息
|
|
630
|
-
loom intent narrative <id> 返回某 Intent 的意图叙事(解析 narrative_ref)
|
|
946
|
+
loom intent narrative <id> 返回某 Intent 的意图叙事(解析 narrative_ref)
|
|
947
|
+
loom intent diff <v1> <v2> 按显式 lineage 对比 Intent 语义
|
|
631
948
|
loom intent validate 校验 Intent Map 结构
|
|
632
949
|
loom intent trace <id> 返回某 Intent 的完整追溯链(依赖+验证+哲学+叙事)
|
|
633
950
|
loom intent reverse-dep <id> 返回依赖某 Intent 的所有 Intent(变更影响评估)
|
|
634
951
|
loom intent reverse-ref <anchor> 返回引用某哲学锚点的所有 Intent
|
|
635
|
-
loom intent update <id> --status <s> 更新 Intent 状态(Keeper 用)
|
|
952
|
+
loom intent update <id> --status <s> 更新 Intent 状态(Keeper 用)
|
|
953
|
+
loom intent done <id> 当前 revision 验证通过后闭合 Intent
|
|
636
954
|
|
|
637
955
|
loom doctor 项目健康检查(一致性+孤儿引用+循环依赖+僵尸)
|
|
638
956
|
loom context 上下文摘要(进度+下一步+待验证+风险)
|
|
@@ -640,18 +958,23 @@ To Human:
|
|
|
640
958
|
loom preview status 检查 preview 是否存在、是否新鲜
|
|
641
959
|
loom preview --regen 强制重新输出提示词(让 AI 重新生成 HTML)
|
|
642
960
|
loom preview --stale 强行打开过期 preview
|
|
643
|
-
loom help <topic>
|
|
961
|
+
loom help <topic> 分层指南(含 patch 工作流)
|
|
644
962
|
|
|
645
|
-
loom philosophy get <anchor> 按锚点加载哲学章节
|
|
646
|
-
loom philosophy list 列出哲学文档文件
|
|
647
|
-
loom philosophy check 校验灵感来源质量(源数量/多样性/理由)
|
|
963
|
+
loom philosophy get <anchor> 按锚点加载哲学章节
|
|
964
|
+
loom philosophy list 列出哲学文档文件
|
|
965
|
+
loom philosophy check 校验灵感来源质量(源数量/多样性/理由)
|
|
966
|
+
loom philosophy impact <anchor> 只读分析直接引用和传递影响
|
|
967
|
+
loom philosophy revise <anchor> --classification <type> --reason <text> 只读评估;加 --confirm 才记录 clarification/minor
|
|
648
968
|
|
|
649
969
|
loom verify contract <id> 返回某 Intent 的验收契约(解析引用)
|
|
650
|
-
loom verify history <id> 返回某 Intent
|
|
970
|
+
loom verify history <id> 返回某 Intent 本地验证历史
|
|
971
|
+
loom verify history <ref> --across-versions 递归返回 lineage 各版本的本地历史
|
|
651
972
|
loom verify pending 返回待验证的 Intent
|
|
652
973
|
loom verify list 列出所有验证记录
|
|
653
974
|
loom verify write --json-file <path> 从文件读入并写入验证记录
|
|
654
|
-
loom verify write --json <string> 从命令行字符串写入验证记录
|
|
975
|
+
loom verify write --json <string> 从命令行字符串写入验证记录
|
|
976
|
+
loom verify pass|fail <id> --summary <text> 快捷写入验证结果
|
|
977
|
+
--quality-proof <ref> 声明相对质量提升时,指向基线比较与稳定性证据
|
|
655
978
|
|
|
656
979
|
参数:
|
|
657
980
|
--loom-dir <path> 指定 .loom/v{N} 目录(默认读 .loom/current 指针)`);
|