@wooojin/forgen 0.4.13 → 0.5.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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +94 -0
- package/README.ja.md +4 -4
- package/README.md +89 -27
- package/README.zh.md +4 -4
- package/assets/claude/commands/forge-loop.md +7 -1
- package/assets/claude/commands/ship.md +18 -1
- package/assets/opencode/forgen.ts +52 -0
- package/dist/checks/_shared/meta-guard-dispatch.d.ts +7 -0
- package/dist/checks/_shared/meta-guard-dispatch.js +12 -2
- package/dist/checks/_shared/model-profile.d.ts +25 -0
- package/dist/checks/_shared/model-profile.js +63 -0
- package/dist/cli.js +99 -153
- package/dist/core/auto-compound-runner.d.ts +0 -11
- package/dist/core/auto-compound-runner.js +127 -79
- package/dist/core/compound-consent.d.ts +15 -0
- package/dist/core/compound-consent.js +48 -0
- package/dist/core/compound-sweep-cli.d.ts +57 -0
- package/dist/core/compound-sweep-cli.js +354 -0
- package/dist/core/config-injector.d.ts +16 -1
- package/dist/core/config-injector.js +47 -28
- package/dist/core/dashboard-cli.js +40 -16
- package/dist/core/dashboard.d.ts +3 -4
- package/dist/core/dashboard.js +15 -34
- package/dist/core/dev-cli.d.ts +13 -0
- package/dist/core/dev-cli.js +70 -0
- package/dist/core/doctor.d.ts +16 -5
- package/dist/core/doctor.js +161 -176
- package/dist/core/drift-score.d.ts +2 -0
- package/dist/core/drift-score.js +9 -1
- package/dist/core/harness.js +115 -43
- package/dist/core/health-cli.d.ts +2 -0
- package/dist/core/health-cli.js +6 -1
- package/dist/core/host-detect.d.ts +3 -1
- package/dist/core/host-detect.js +26 -1
- package/dist/core/migrate-cli.js +15 -0
- package/dist/core/migrate-evidence-host.d.ts +2 -1
- package/dist/core/migrate-tenetx.d.ts +50 -0
- package/dist/core/migrate-tenetx.js +262 -0
- package/dist/core/probe-workflow-cli.d.ts +3 -3
- package/dist/core/probe-workflow-cli.js +13 -13
- package/dist/core/recall-cli.js +1 -1
- package/dist/core/regress-map-cli.js +1 -1
- package/dist/core/rendered-rules-manifest.d.ts +29 -0
- package/dist/core/rendered-rules-manifest.js +60 -0
- package/dist/core/session-store.js +14 -3
- package/dist/core/settings-injector.d.ts +3 -0
- package/dist/core/settings-injector.js +12 -16
- package/dist/core/spawn.d.ts +11 -1
- package/dist/core/spawn.js +79 -7
- package/dist/core/state-gc.js +1 -0
- package/dist/core/status-cli.d.ts +20 -0
- package/dist/core/status-cli.js +100 -0
- package/dist/core/statusline-cli.d.ts +7 -0
- package/dist/core/statusline-cli.js +63 -19
- package/dist/core/transcript-summary.d.ts +18 -0
- package/dist/core/transcript-summary.js +81 -0
- package/dist/core/trust-layer-intent.d.ts +21 -1
- package/dist/core/trust-layer-intent.js +7 -0
- package/dist/core/types.d.ts +3 -2
- package/dist/core/uninstall.js +12 -0
- package/dist/core/usage-telemetry.d.ts +7 -1
- package/dist/core/usage-telemetry.js +7 -9
- package/dist/core/v1-bootstrap.js +1 -1
- package/dist/core/watch-cli.js +1 -1
- package/dist/engine/compound-extractor.js +10 -0
- package/dist/engine/compound-loop.js +35 -6
- package/dist/engine/compound-share.d.ts +85 -0
- package/dist/engine/compound-share.js +606 -0
- package/dist/engine/correction-cluster-runner.d.ts +38 -0
- package/dist/engine/correction-cluster-runner.js +188 -0
- package/dist/engine/correction-clustering.d.ts +80 -0
- package/dist/engine/correction-clustering.js +167 -0
- package/dist/engine/enforce-classifier.d.ts +10 -1
- package/dist/engine/enforce-classifier.js +111 -22
- package/dist/engine/extraction-session.js +10 -3
- package/dist/engine/private-filter.d.ts +36 -0
- package/dist/engine/private-filter.js +100 -0
- package/dist/engine/ranking-pipeline.js +4 -2
- package/dist/engine/relevance-gate.d.ts +12 -0
- package/dist/engine/relevance-gate.js +12 -0
- package/dist/engine/roi-demotion.d.ts +79 -0
- package/dist/engine/roi-demotion.js +159 -0
- package/dist/engine/solution-format.d.ts +1 -0
- package/dist/engine/solution-format.js +26 -0
- package/dist/engine/solution-matcher.js +10 -1
- package/dist/fgx.js +7 -6
- package/dist/forge/cli.js +8 -2
- package/dist/hooks/compound-reflection.js +6 -1
- package/dist/hooks/context-guard.d.ts +16 -1
- package/dist/hooks/context-guard.js +92 -46
- package/dist/hooks/post-tool-use.js +2 -3
- package/dist/hooks/pre-compact.js +14 -0
- package/dist/hooks/pre-tool-use.js +5 -1
- package/dist/hooks/shared/stop-triggers.d.ts +29 -2
- package/dist/hooks/shared/stop-triggers.js +35 -2
- package/dist/hooks/solution-injector.d.ts +28 -0
- package/dist/hooks/solution-injector.js +126 -28
- package/dist/hooks/stop-guard.js +5 -2
- package/dist/hooks/subagent-stop-guard.js +4 -1
- package/dist/host/capabilities-claude.js +1 -0
- package/dist/host/capabilities-codex.js +1 -0
- package/dist/host/capabilities-opencode.d.ts +26 -0
- package/dist/host/capabilities-opencode.js +78 -0
- package/dist/host/capabilities-registry.d.ts +7 -0
- package/dist/host/capabilities-registry.js +14 -0
- package/dist/host/exec-host.d.ts +4 -3
- package/dist/host/exec-host.js +2 -0
- package/dist/host/host-binding.d.ts +27 -0
- package/dist/host/host-binding.js +11 -0
- package/dist/host/host-runtime.js +18 -0
- package/dist/host/install-codex.d.ts +8 -0
- package/dist/host/install-codex.js +2 -2
- package/dist/host/install-opencode.d.ts +38 -0
- package/dist/host/install-opencode.js +148 -0
- package/dist/host/install-orchestrator.d.ts +4 -1
- package/dist/host/install-orchestrator.js +20 -1
- package/dist/host/invoke-agent.d.ts +3 -2
- package/dist/host/opencode/context-cli.d.ts +15 -0
- package/dist/host/opencode/context-cli.js +25 -0
- package/dist/host/opencode/guard-cli.d.ts +13 -0
- package/dist/host/opencode/guard-cli.js +39 -0
- package/dist/host/opencode/plugin/forgen.d.ts +31 -0
- package/dist/host/opencode/plugin/forgen.js +60 -0
- package/dist/host/opencode/translate.d.ts +49 -0
- package/dist/host/opencode/translate.js +96 -0
- package/dist/host/parity-harness.d.ts +10 -2
- package/dist/host/projection.js +11 -0
- package/dist/mcp/tools.js +17 -4
- package/dist/store/evidence-store.d.ts +2 -6
- package/dist/store/evidence-store.js +68 -14
- package/dist/store/host-mismatch.d.ts +2 -1
- package/dist/store/host-mismatch.js +8 -8
- package/dist/store/profile-store.d.ts +3 -2
- package/dist/store/types.d.ts +9 -2
- package/package.json +3 -2
- package/plugin.json +2 -2
- package/skills/forge-loop/SKILL.md +7 -1
- package/skills/ship/SKILL.md +18 -1
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ const runtime = launchContext.runtime;
|
|
|
20
20
|
const commands = [
|
|
21
21
|
{
|
|
22
22
|
name: 'forge',
|
|
23
|
-
description: 'Personalization
|
|
23
|
+
description: 'Personalization single entry (--onboarding|--profile|--export|--reset)',
|
|
24
24
|
handler: async (args) => {
|
|
25
25
|
const { handleForge } = await import('./forge/cli.js');
|
|
26
26
|
await handleForge(args);
|
|
@@ -28,8 +28,31 @@ const commands = [
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
name: 'compound',
|
|
31
|
-
description: 'Preview/save compound insights and manage accumulated knowledge',
|
|
31
|
+
description: 'Preview/save compound insights and manage accumulated knowledge (subcmd: sweep)',
|
|
32
32
|
handler: async (args) => {
|
|
33
|
+
// ADR-011: 시간-기반 compound backstop. cron 에서 `forgen compound sweep` 호출.
|
|
34
|
+
if (args[0] === 'sweep') {
|
|
35
|
+
const { compoundSweepCli } = await import('./core/compound-sweep-cli.js');
|
|
36
|
+
compoundSweepCli(args.slice(1));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// ADR-012: Haiku 추출 동의 토글. `forgen compound consent on|off|status`
|
|
40
|
+
if (args[0] === 'consent') {
|
|
41
|
+
const { getHaikuConsentState, setHaikuCompoundConsent } = await import('./core/compound-consent.js');
|
|
42
|
+
const sub = args[1];
|
|
43
|
+
if (sub === 'on' || sub === 'off') {
|
|
44
|
+
setHaikuCompoundConsent(sub === 'on');
|
|
45
|
+
console.log(`[forgen] auto-compound Haiku 추출: ${sub === 'on' ? '활성(ON)' : '비활성(OFF)'}. (결정론 룰 승급은 항상 동작)`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const s = getHaikuConsentState();
|
|
49
|
+
console.log(`[forgen] auto-compound Haiku 추출: ${s.enabled ? 'ON' : 'OFF'} (source: ${s.source})\n` +
|
|
50
|
+
' ON = 세션 요약을 Haiku 로 전송해 행동패턴 추론 (본인 쿼터, redaction 적용)\n' +
|
|
51
|
+
' OFF = 결정론 교정→룰 승급만 (egress 0, 입증된 δ 경로는 유지)\n' +
|
|
52
|
+
' 변경: forgen compound consent on|off (env: FORGEN_AUTO_COMPOUND=1 / FORGEN_NO_AUTO_COMPOUND=1)');
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
33
56
|
const { handleCompound } = await import('./engine/compound-loop.js');
|
|
34
57
|
await handleCompound(args);
|
|
35
58
|
},
|
|
@@ -72,11 +95,11 @@ const commands = [
|
|
|
72
95
|
},
|
|
73
96
|
},
|
|
74
97
|
{
|
|
75
|
-
name: '
|
|
76
|
-
description: '
|
|
77
|
-
handler: async (
|
|
78
|
-
const {
|
|
79
|
-
await
|
|
98
|
+
name: 'status',
|
|
99
|
+
description: 'Unified status: forgen status [--compound|--profile|--rules|--blocks [N]|--overview|--live]',
|
|
100
|
+
handler: async (args) => {
|
|
101
|
+
const { handleStatus } = await import('./core/status-cli.js');
|
|
102
|
+
await handleStatus(args);
|
|
80
103
|
},
|
|
81
104
|
},
|
|
82
105
|
{
|
|
@@ -87,14 +110,6 @@ const commands = [
|
|
|
87
110
|
await handleLearn(args);
|
|
88
111
|
},
|
|
89
112
|
},
|
|
90
|
-
{
|
|
91
|
-
name: 'me',
|
|
92
|
-
description: 'Personal dashboard (→ inspect profile)',
|
|
93
|
-
handler: async (_args) => {
|
|
94
|
-
const { handleInspect } = await import('./core/inspect-cli.js');
|
|
95
|
-
await handleInspect(['profile']);
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
113
|
{
|
|
99
114
|
name: 'statusline',
|
|
100
115
|
description: 'Compact HUD for Claude Code statusLine (reads stdin JSON)',
|
|
@@ -137,7 +152,7 @@ const commands = [
|
|
|
137
152
|
const { setDefaultHost } = await import('./store/profile-store.js');
|
|
138
153
|
const ok = setDefaultHost(value);
|
|
139
154
|
if (!ok) {
|
|
140
|
-
console.log(' ✗ Profile not found. Run `forgen onboarding` first.');
|
|
155
|
+
console.log(' ✗ Profile not found. Run `forgen forge --onboarding` first.');
|
|
141
156
|
process.exit(1);
|
|
142
157
|
}
|
|
143
158
|
console.log(` ✓ default_host set to: ${value}`);
|
|
@@ -166,12 +181,12 @@ const commands = [
|
|
|
166
181
|
},
|
|
167
182
|
{
|
|
168
183
|
name: 'install',
|
|
169
|
-
description: 'Install forgen into a host. Usage: forgen install [claude|codex|both] [--dry-run] [--no-mcp]',
|
|
184
|
+
description: 'Install forgen into a host. Usage: forgen install [claude|codex|opencode|both] [--dry-run] [--no-mcp]',
|
|
170
185
|
handler: async (args) => {
|
|
171
|
-
const knownSubs = new Set(['claude', 'codex', 'both']);
|
|
186
|
+
const knownSubs = new Set(['claude', 'codex', 'opencode', 'both']);
|
|
172
187
|
const target = args[0] && knownSubs.has(args[0]) ? args[0] : args[0]?.startsWith('--') ? undefined : args[0];
|
|
173
188
|
if (target !== undefined && !knownSubs.has(target)) {
|
|
174
|
-
console.log('Usage:\n forgen install [claude|codex|both] [--dry-run] [--no-mcp]\n\n No arg → interactive 3-choice (Claude/Codex/Both).');
|
|
189
|
+
console.log('Usage:\n forgen install [claude|codex|opencode|both] [--dry-run] [--no-mcp]\n\n No arg → interactive 3-choice (Claude/Codex/Both). opencode: 명시 타겟(P1 실험적).');
|
|
175
190
|
return;
|
|
176
191
|
}
|
|
177
192
|
const dryRun = args.includes('--dry-run');
|
|
@@ -186,18 +201,6 @@ const commands = [
|
|
|
186
201
|
console.log(renderResult(result, dryRun));
|
|
187
202
|
},
|
|
188
203
|
},
|
|
189
|
-
{
|
|
190
|
-
name: 'status',
|
|
191
|
-
description: 'Observability dashboard (--watch, --json, --interval N)',
|
|
192
|
-
handler: async (args) => {
|
|
193
|
-
const { runDashboard } = await import('./core/dashboard-cli.js');
|
|
194
|
-
const watch = args.includes('--watch');
|
|
195
|
-
const json = args.includes('--json');
|
|
196
|
-
const intervalIdx = args.indexOf('--interval');
|
|
197
|
-
const intervalSec = intervalIdx !== -1 ? Number(args[intervalIdx + 1]) || 5 : 5;
|
|
198
|
-
await runDashboard({ watch, json, intervalSec });
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
204
|
{
|
|
202
205
|
name: 'maintenance',
|
|
203
206
|
description: 'Maintenance utilities (--backfill [--phase A|B|all] [--force] [--dry-run])',
|
|
@@ -229,28 +232,11 @@ const commands = [
|
|
|
229
232
|
},
|
|
230
233
|
},
|
|
231
234
|
{
|
|
232
|
-
name: '
|
|
233
|
-
description: '
|
|
235
|
+
name: 'dev',
|
|
236
|
+
description: 'Developer/maintenance utilities: dev <probe-workflow|parity|migrate|regress-map>',
|
|
234
237
|
handler: async (args) => {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
console.log('Usage:\n forgen parity codex [--dry-run]\n\nNotes:\n - source 체크아웃에서만 작동합니다 (tests/ 디렉토리 필요).\n - npm install 로 설치된 패키지에서는 run-parity.sh 가 없습니다.');
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
241
|
-
const scriptPath = path.resolve(here, '..', 'tests', 'e2e', 'codex', 'run-parity.sh');
|
|
242
|
-
if (!fs.existsSync(scriptPath)) {
|
|
243
|
-
console.error('[forgen] run-parity.sh 는 source 체크아웃에서만 작동. 직접 git clone 후 실행하세요.');
|
|
244
|
-
console.error(` expected: ${scriptPath}`);
|
|
245
|
-
process.exit(1);
|
|
246
|
-
}
|
|
247
|
-
const { spawnSync } = await import('node:child_process');
|
|
248
|
-
const dryRun = args.includes('--dry-run');
|
|
249
|
-
const spawnArgs = dryRun ? ['--dry-run'] : [];
|
|
250
|
-
const result = spawnSync('bash', [scriptPath, ...spawnArgs], { stdio: 'inherit' });
|
|
251
|
-
if (result.status !== 0) {
|
|
252
|
-
process.exit(result.status ?? 1);
|
|
253
|
-
}
|
|
238
|
+
const { handleDev } = await import('./core/dev-cli.js');
|
|
239
|
+
await handleDev(args);
|
|
254
240
|
},
|
|
255
241
|
},
|
|
256
242
|
{
|
|
@@ -269,23 +255,17 @@ const commands = [
|
|
|
269
255
|
await handleInspect(args);
|
|
270
256
|
},
|
|
271
257
|
},
|
|
272
|
-
{
|
|
273
|
-
name: 'onboarding',
|
|
274
|
-
description: 'v1 4-question onboarding flow',
|
|
275
|
-
handler: async (_args) => {
|
|
276
|
-
const { runOnboarding } = await import('./forge/onboarding-cli.js');
|
|
277
|
-
await runOnboarding();
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
258
|
{
|
|
281
259
|
name: 'doctor',
|
|
282
|
-
description: 'Diagnostics (--quick
|
|
260
|
+
description: 'Diagnostics (--quick fast check, --prune-state GC, --repair auto-fix, --reclaim legacy-rules scan)',
|
|
283
261
|
handler: async (args) => {
|
|
284
262
|
const { runDoctor } = await import('./core/doctor.js');
|
|
285
263
|
await runDoctor({
|
|
286
264
|
pruneState: args.includes('--prune-state'),
|
|
287
265
|
repair: args.includes('--repair'),
|
|
288
266
|
quick: args.includes('--quick'),
|
|
267
|
+
reclaim: args.includes('--reclaim'),
|
|
268
|
+
verbose: args.includes('--verbose'),
|
|
289
269
|
});
|
|
290
270
|
},
|
|
291
271
|
},
|
|
@@ -334,38 +314,6 @@ const commands = [
|
|
|
334
314
|
await handleLifecycleScan(args);
|
|
335
315
|
},
|
|
336
316
|
},
|
|
337
|
-
{
|
|
338
|
-
name: 'stats',
|
|
339
|
-
description: 'One-screen dashboard: active rules, corrections, blocks/bypass/drift (7d).',
|
|
340
|
-
handler: async (args) => {
|
|
341
|
-
const { handleStats } = await import('./core/stats-cli.js');
|
|
342
|
-
await handleStats(args);
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
name: 'watch',
|
|
347
|
-
description: 'Real-time hook event stream (hook firings, blocks, solution matches)',
|
|
348
|
-
handler: async () => {
|
|
349
|
-
const { handleWatch } = await import('./core/watch-cli.js');
|
|
350
|
-
await handleWatch();
|
|
351
|
-
},
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
name: 'health',
|
|
355
|
-
description: 'Single-line health score (0-100) combining utilization, effectiveness, growth.',
|
|
356
|
-
handler: async () => {
|
|
357
|
-
const { handleHealth } = await import('./core/health-cli.js');
|
|
358
|
-
await handleHealth();
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
{
|
|
362
|
-
name: 'probe-workflow',
|
|
363
|
-
description: 'ADR-009 §1: measure whether dynamic-workflow subagents fire forgen hooks (arm|report|status).',
|
|
364
|
-
handler: async (args) => {
|
|
365
|
-
const { handleProbeWorkflow } = await import('./core/probe-workflow-cli.js');
|
|
366
|
-
await handleProbeWorkflow(args);
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
317
|
{
|
|
370
318
|
name: 'workflows',
|
|
371
319
|
description: 'Install/list forgen dynamic-workflow templates (install [--project] | list).',
|
|
@@ -374,14 +322,6 @@ const commands = [
|
|
|
374
322
|
await handleWorkflows(args);
|
|
375
323
|
},
|
|
376
324
|
},
|
|
377
|
-
{
|
|
378
|
-
name: 'explain',
|
|
379
|
-
description: 'Explain the most recent block — what rule, why, and how to resolve.',
|
|
380
|
-
handler: async (args) => {
|
|
381
|
-
const { handleExplain } = await import('./core/explain-cli.js');
|
|
382
|
-
await handleExplain(args);
|
|
383
|
-
},
|
|
384
|
-
},
|
|
385
325
|
{
|
|
386
326
|
name: 'changelog',
|
|
387
327
|
description: 'Auto-summarize changes since last release tag (conventional commits).',
|
|
@@ -390,38 +330,6 @@ const commands = [
|
|
|
390
330
|
await handleChangelog();
|
|
391
331
|
},
|
|
392
332
|
},
|
|
393
|
-
{
|
|
394
|
-
name: 'last-block',
|
|
395
|
-
description: 'Show the most recent Mech-A/B block event with rule detail (R6-UX2).',
|
|
396
|
-
handler: async (_args) => {
|
|
397
|
-
const { handleInspect } = await import('./core/inspect-cli.js');
|
|
398
|
-
await handleInspect(['violations', '--last', '1']);
|
|
399
|
-
},
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
name: 'recall',
|
|
403
|
-
description: 'Show recent compound recalls (matched solutions) with optional body preview.',
|
|
404
|
-
handler: async (args) => {
|
|
405
|
-
const { handleRecall } = await import('./core/recall-cli.js');
|
|
406
|
-
await handleRecall(args);
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
{
|
|
410
|
-
name: 'migrate',
|
|
411
|
-
description: 'One-shot schema migrations (implicit-feedback category backfill).',
|
|
412
|
-
handler: async (args) => {
|
|
413
|
-
const { handleMigrate } = await import('./core/migrate-cli.js');
|
|
414
|
-
await handleMigrate(args);
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
{
|
|
418
|
-
name: 'regress-map',
|
|
419
|
-
description: 'Top fix-touched files in the last N days (--days 30 --top 10 --json).',
|
|
420
|
-
handler: async (args) => {
|
|
421
|
-
const { handleRegressMap } = await import('./core/regress-map-cli.js');
|
|
422
|
-
await handleRegressMap(args);
|
|
423
|
-
},
|
|
424
|
-
},
|
|
425
333
|
{
|
|
426
334
|
name: 'suppress-rule',
|
|
427
335
|
description: '[alias: rule suppress] Disable a rule by id/prefix. Hard rules refused.',
|
|
@@ -460,6 +368,7 @@ async function handleRuleNamespace(args) {
|
|
|
460
368
|
forgen rule health-scan [--apply] Scan drift → Mech downgrade candidates
|
|
461
369
|
forgen rule classify [--apply] [--force]
|
|
462
370
|
Propose enforce_via for legacy rules
|
|
371
|
+
forgen rule unmerge-cluster <id> Undo a W3-2 correction-cluster merge (restore originals)
|
|
463
372
|
`);
|
|
464
373
|
return;
|
|
465
374
|
}
|
|
@@ -494,6 +403,24 @@ async function handleRuleNamespace(args) {
|
|
|
494
403
|
await handleClassifyEnforce(rest);
|
|
495
404
|
return;
|
|
496
405
|
}
|
|
406
|
+
case 'unmerge-cluster': {
|
|
407
|
+
// W3-2: 교정 클러스터 통합 취소 — 원본 룰 복원 + 재통합 억제.
|
|
408
|
+
const mergedId = rest[0];
|
|
409
|
+
if (!mergedId) {
|
|
410
|
+
console.error('[forgen] usage: forgen rule unmerge-cluster <merged-rule-id>');
|
|
411
|
+
process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
const { unmergeCluster } = await import('./engine/correction-cluster-runner.js');
|
|
414
|
+
const res = unmergeCluster(mergedId);
|
|
415
|
+
if (res.ok) {
|
|
416
|
+
console.log(`✓ [forgen] 클러스터 통합 취소 — 원본 ${res.restored.length}룰 복원 (재통합 억제됨)`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
console.error(`[forgen] unmerge 실패: ${res.reason}`);
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
497
424
|
default: {
|
|
498
425
|
console.error(`[forgen] Unknown rule subcommand: ${sub}\n Run "forgen rule help" for options.`);
|
|
499
426
|
process.exit(1);
|
|
@@ -532,6 +459,18 @@ async function main() {
|
|
|
532
459
|
console.log(PKG_VERSION);
|
|
533
460
|
return;
|
|
534
461
|
}
|
|
462
|
+
// W3-3: OpenCode plugin 슬림이 per-tool-call 로 호출하는 경량 브릿지 (heavy init 우회).
|
|
463
|
+
if (args[0] === 'opencode-guard') {
|
|
464
|
+
const { runOpencodeGuard } = await import('./host/opencode/guard-cli.js');
|
|
465
|
+
await runOpencodeGuard();
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
// W3-3: OpenCode plugin 이 compaction 시 주입할 forgen context (forge-loop 상태) 출력.
|
|
469
|
+
if (args[0] === 'opencode-context') {
|
|
470
|
+
const { runOpencodeContext } = await import('./host/opencode/context-cli.js');
|
|
471
|
+
runOpencodeContext();
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
535
474
|
const cmd = findCommand(args[0]);
|
|
536
475
|
if (cmd) {
|
|
537
476
|
await cmd.handler(args.slice(1));
|
|
@@ -540,11 +479,24 @@ async function main() {
|
|
|
540
479
|
// 등록되지 않은 서브커맨드는 에러 처리
|
|
541
480
|
// 플래그(--resume 등), 따옴표 프롬프트, 인자 없는 실행은 하네스로 통과
|
|
542
481
|
if (args[0] && !args[0].startsWith('-') && !args[0].startsWith('"') && !args[0].startsWith("'")) {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
482
|
+
// Wave 1 통합(feature-audit): 제거된 명령 → 새 위치 명시 매핑 (levenshtein 오유도 방지).
|
|
483
|
+
const RENAMED = {
|
|
484
|
+
stats: 'status', health: 'status', dashboard: 'status --overview', me: 'status --profile',
|
|
485
|
+
recall: 'status --compound', explain: 'status --blocks', 'last-block': 'status --blocks',
|
|
486
|
+
watch: 'status --live', 'probe-workflow': 'dev probe-workflow', parity: 'dev parity',
|
|
487
|
+
migrate: 'dev migrate', 'regress-map': 'dev regress-map', onboarding: 'forge --onboarding',
|
|
488
|
+
};
|
|
489
|
+
let hint;
|
|
490
|
+
if (RENAMED[args[0]]) {
|
|
491
|
+
hint = `\n → moved: forgen ${RENAMED[args[0]]}`;
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
const suggestion = commands
|
|
495
|
+
.map(c => ({ name: c.name, dist: levenshtein(args[0], c.name) }))
|
|
496
|
+
.filter(c => c.dist <= 3)
|
|
497
|
+
.sort((a, b) => a.dist - b.dist)[0];
|
|
498
|
+
hint = suggestion ? `\n Did you mean: forgen ${suggestion.name}` : '';
|
|
499
|
+
}
|
|
548
500
|
console.error(`[forgen] Unknown command: ${args[0]}${hint}\n Run "forgen help" for available commands.`);
|
|
549
501
|
process.exit(1);
|
|
550
502
|
}
|
|
@@ -621,28 +573,22 @@ function printHelp() {
|
|
|
621
573
|
forgen --runtime claude|codex Select launch runtime
|
|
622
574
|
|
|
623
575
|
Commands:
|
|
624
|
-
forgen forge
|
|
625
|
-
|
|
576
|
+
forgen forge [--onboarding|--profile|--reset]
|
|
577
|
+
Personalization single entry (first run = 4-question onboarding)
|
|
626
578
|
forgen inspect [profile|rules|corrections|session]
|
|
627
579
|
Inspect v1 state (alias: evidence → corrections)
|
|
628
580
|
forgen rule <list|suppress|activate|scan|health-scan|classify>
|
|
629
581
|
Rule management (see: forgen rule help)
|
|
630
|
-
forgen
|
|
631
|
-
|
|
632
|
-
|
|
582
|
+
forgen status [view] Unified status — one screen; views:
|
|
583
|
+
--compound compound health + recent recalls
|
|
584
|
+
--profile 4-axis profile + recent corrections
|
|
585
|
+
--rules active rules
|
|
586
|
+
--blocks [N] recent block(s): rule/reason/fix
|
|
587
|
+
--overview rich dashboard (hooks·history·curve)
|
|
588
|
+
--live real-time hook event stream
|
|
633
589
|
forgen workflows install|list Install forgen dynamic-workflow templates to .claude/workflows/
|
|
634
|
-
forgen watch Real-time hook event stream (tail logs live)
|
|
635
|
-
forgen explain [N] Explain the last N block(s) — rule, reason, resolution
|
|
636
590
|
forgen changelog Auto-summarize commits since last release tag
|
|
637
|
-
forgen last-block Show the most recent block event
|
|
638
|
-
forgen recall [--limit N] [--show]
|
|
639
|
-
최근 compound 주입 이력 (solution body preview)
|
|
640
|
-
forgen migrate [implicit-feedback|evidence-host|all]
|
|
641
|
-
One-shot schema migration (category backfill / host backfill)
|
|
642
|
-
forgen parity codex [--dry-run] Run codex parity checks (source checkout only)
|
|
643
591
|
forgen compound Manage accumulated knowledge
|
|
644
|
-
forgen dashboard Compound system dashboard
|
|
645
|
-
forgen me Personal dashboard
|
|
646
592
|
forgen init Initialize project (+ starter-pack solutions)
|
|
647
593
|
forgen config hooks Hook management
|
|
648
594
|
forgen mcp MCP server management
|
|
@@ -10,15 +10,4 @@
|
|
|
10
10
|
* 인자: [cwd] [transcriptPath] [sessionId]
|
|
11
11
|
*/
|
|
12
12
|
import { type ExecFileOptions } from 'node:child_process';
|
|
13
|
-
/**
|
|
14
|
-
* 0.4.6 perf #12 — async 변형. 3 LLM 호출 (solution / user-pattern / learning) 을
|
|
15
|
-
* Promise.allSettled 로 병렬 실행하여 wall-clock 을 sum → max 로 단축 (~3x).
|
|
16
|
-
*
|
|
17
|
-
* 0.4.6 에서는 adaptive cooldown 으로 wasted runs 차단을 우선 적용했고, 호출부
|
|
18
|
-
* full parallelization 은 0.4.7 로 분리 (refactor surface 큼 — solution call 의
|
|
19
|
-
* `--allowedTools` sandbox 와 file-write 순서 invariant 검증 필요).
|
|
20
|
-
*
|
|
21
|
-
* 본 함수는 0.4.7 작업의 foundation 으로 박제 — export 하여 unused warning 회피.
|
|
22
|
-
* 동작은 sync 버전과 동일: Claude/Codex 분기 + retry on transient.
|
|
23
|
-
*/
|
|
24
13
|
export declare function execClaudeRetryAsync(args: string[], opts: ExecFileOptions): Promise<string>;
|