synergyspec-selfevolving 2.1.4 → 2.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.
Files changed (71) hide show
  1. package/dist/commands/config.js +4 -0
  2. package/dist/commands/learn.js +80 -24
  3. package/dist/commands/self-evolution-dream.d.ts +54 -0
  4. package/dist/commands/self-evolution-dream.js +265 -0
  5. package/dist/commands/self-evolution-episode.d.ts +5 -0
  6. package/dist/commands/self-evolution-episode.js +160 -107
  7. package/dist/commands/self-evolution.js +127 -4
  8. package/dist/commands/workflow/status.js +38 -7
  9. package/dist/core/archive.js +27 -9
  10. package/dist/core/change-readiness.d.ts +63 -6
  11. package/dist/core/change-readiness.js +912 -23
  12. package/dist/core/completions/command-registry.js +1 -1
  13. package/dist/core/fitness/loss.d.ts +10 -5
  14. package/dist/core/fitness/loss.js +11 -4
  15. package/dist/core/fitness/test-metrics.d.ts +3 -0
  16. package/dist/core/fitness/test-metrics.js +78 -1
  17. package/dist/core/learn/trajectory-discovery.js +5 -0
  18. package/dist/core/learn.js +131 -13
  19. package/dist/core/migration.d.ts +6 -14
  20. package/dist/core/migration.js +63 -21
  21. package/dist/core/profiles.d.ts +1 -1
  22. package/dist/core/profiles.js +1 -0
  23. package/dist/core/runner-evidence.d.ts +53 -0
  24. package/dist/core/runner-evidence.js +613 -0
  25. package/dist/core/self-evolution/candidates.d.ts +1 -1
  26. package/dist/core/self-evolution/candidates.js +1 -2
  27. package/dist/core/self-evolution/canonical-targets.js +1 -0
  28. package/dist/core/self-evolution/dream.d.ts +132 -0
  29. package/dist/core/self-evolution/dream.js +1093 -0
  30. package/dist/core/self-evolution/episode-orchestrator.d.ts +7 -0
  31. package/dist/core/self-evolution/episode-orchestrator.js +162 -12
  32. package/dist/core/self-evolution/episode-store.d.ts +21 -0
  33. package/dist/core/self-evolution/episode-store.js +16 -3
  34. package/dist/core/self-evolution/evolving-agent.js +8 -0
  35. package/dist/core/self-evolution/host-harness.d.ts +46 -12
  36. package/dist/core/self-evolution/host-harness.js +198 -55
  37. package/dist/core/self-evolution/index.d.ts +1 -0
  38. package/dist/core/self-evolution/index.js +1 -0
  39. package/dist/core/self-evolution/policy/policy-store.d.ts +19 -2
  40. package/dist/core/self-evolution/policy/policy-store.js +85 -0
  41. package/dist/core/self-evolution/promote.d.ts +7 -5
  42. package/dist/core/self-evolution/promote.js +111 -19
  43. package/dist/core/self-evolution/reward-agent.js +11 -9
  44. package/dist/core/self-evolution/reward-aggregator.js +2 -2
  45. package/dist/core/shared/skill-generation.d.ts +37 -0
  46. package/dist/core/shared/skill-generation.js +91 -0
  47. package/dist/core/templates/skill-templates.d.ts +1 -0
  48. package/dist/core/templates/skill-templates.js +1 -0
  49. package/dist/core/templates/workflow-manifest.js +2 -0
  50. package/dist/core/templates/workflows/archive-change.js +76 -39
  51. package/dist/core/templates/workflows/ci.js +47 -1
  52. package/dist/core/templates/workflows/dream.d.ts +10 -0
  53. package/dist/core/templates/workflows/dream.js +123 -0
  54. package/dist/core/templates/workflows/gen-tests.js +9 -3
  55. package/dist/core/templates/workflows/learn.js +11 -7
  56. package/dist/core/templates/workflows/run-tests.js +99 -4
  57. package/dist/core/templates/workflows/self-evolving.js +118 -115
  58. package/dist/core/templates/workflows/verify-change.js +130 -22
  59. package/dist/core/trajectory/adapters/codex.js +87 -29
  60. package/dist/core/trajectory/adapters/opencode.js +69 -23
  61. package/dist/core/trajectory/facts.d.ts +1 -1
  62. package/dist/core/trajectory/facts.js +23 -5
  63. package/dist/core/trajectory/registry.d.ts +16 -2
  64. package/dist/core/trajectory/registry.js +104 -29
  65. package/dist/core/trajectory/source.d.ts +27 -4
  66. package/dist/dashboard/react-client.js +4 -4
  67. package/dist/utils/change-utils.d.ts +2 -0
  68. package/dist/utils/change-utils.js +53 -2
  69. package/package.json +99 -99
  70. package/schemas/spec-driven/templates/design.md +6 -0
  71. package/scripts/nl2repo_synergyspec-selfevolving_wrapper.py +170 -0
@@ -51,6 +51,10 @@ const WORKFLOW_PROMPT_META = {
51
51
  name: 'Learn from change',
52
52
  description: 'Review verified work and capture reusable lessons',
53
53
  },
54
+ dream: {
55
+ name: 'Dream proposals',
56
+ description: 'Batch-mine completed evidence into proposal-only SS optimizer briefs',
57
+ },
54
58
  'verify-spec': {
55
59
  name: 'Verify spec traceability',
56
60
  description: 'Audit and fix use case traceability across all artifacts',
@@ -4,10 +4,10 @@ import { detectFrozenHealthRoutingObservations, detectUnbindableHintObservations
4
4
  import { readProjectConfig } from '../core/project-config.js';
5
5
  import { assembleTrajectoryContext, } from '../core/learn/trajectory-assembler.js';
6
6
  import { findTranscriptsForChange, resolveChangeDir, validateExplicitTrajectoryHandle, } from '../core/learn/trajectory-discovery.js';
7
- import { getTrajectoryForChange } from '../core/trajectory/registry.js';
7
+ import { getTrajectoryResultForChange } from '../core/trajectory/registry.js';
8
8
  import { toTrajectoryFacts, describeRunnerResults, extractExpectedTestPaths } from '../core/trajectory/facts.js';
9
9
  import { toActionSkeleton } from '../core/trajectory/skeleton.js';
10
- import { resolveHostHarness, resolveHostHarnessForRepo } from '../core/self-evolution/host-harness.js';
10
+ import { resolveHostHarness, resolveHostHarnessDetailsForRepo, persistHostHarness, seedHostHarnessForRepo, } from '../core/self-evolution/host-harness.js';
11
11
  import { mineSuccessSignals } from '../core/self-evolution/success-channel.js';
12
12
  import { captureMainArm, runEpisode, } from '../core/self-evolution/episode-orchestrator.js';
13
13
  import { buildLLMSummaryCandidates, ingestLearnHandoff, } from '../core/learn/llm-summary.js';
@@ -15,6 +15,13 @@ function collect(value, previous) {
15
15
  previous.push(value);
16
16
  return previous;
17
17
  }
18
+ function parseAgentHarness(value) {
19
+ if (value === undefined)
20
+ return undefined;
21
+ if (value === 'claude' || value === 'codex' || value === 'opencode')
22
+ return value;
23
+ throw new Error(`Invalid harness '${value}'. Expected one of: claude, codex, opencode`);
24
+ }
18
25
  export function registerLearnCommand(program, deps = {}) {
19
26
  const runEpisodeImpl = deps.runEpisode ?? runEpisode;
20
27
  const learnCmd = program
@@ -31,25 +38,32 @@ export function registerLearnCommand(program, deps = {}) {
31
38
  .option('--no-focus', 'Disable the evolution-focus switch for this run: when the policy is frozen-by-default, frozen-kind signals are dropped silently instead of being re-aimed at the explicitly evolvable target(s) as a policy-focus hint (config: selfEvolution.focus)')
32
39
  .option('--transcript <path>', 'Explicit transcript .jsonl to grade (bypasses change-window discovery; Claude transcript store only)')
33
40
  .option('--session-id <id>', 'Explicit Claude session id to grade (bypasses change-window discovery; Claude transcript store only)')
41
+ .option('--harness <name>', 'Force the observed-run/code-agent harness (claude|codex|opencode)')
42
+ .option('--rerun', 'Force a new loop-v2 episode instead of reusing a completed matching episode')
43
+ .option('--force-new-episode', 'Alias for --rerun')
34
44
  .option('--json', 'Output as JSON')
35
45
  .option('--no-interactive', 'Disable interactive prompts (learn is non-interactive by default)')
36
46
  .action(async (change, options) => {
37
47
  try {
38
48
  const projectRoot = process.cwd();
39
- // SEED the host harness for the env-less episode subagent. learn runs at
40
- // HOST level, where the OPENCODE_*/CODEX_* env that distinguishes the
41
- // host harness IS present; the downstream loop-v2 episode (and its
42
- // reward/evolving agent spawns) can run in an env-less Task subagent that
43
- // would otherwise default to the 'claude' binary. resolveHostHarnessForRepo
44
- // self-persists the confidently-resolved harness to
45
- // `.synergyspec-selfevolving/host-harness.json`, so the subagent reads it
46
- // back instead of guessing. Best-effort: a persistence failure must never
47
- // fail the learn run (a missing seed only degrades to today's behavior).
49
+ const forcedHarness = parseAgentHarness(options.harness);
50
+ let reportHarness = forcedHarness;
51
+ // Resolve the report harness without writing the repo sidecar. Preview
52
+ // and diagnostic learn runs are read-only: a weak ambient CODEX_*/
53
+ // OPENCODE_* signal must not be promoted into durable provenance before
54
+ // we know an episode will actually spawn.
48
55
  try {
49
- await resolveHostHarnessForRepo(projectRoot);
56
+ if (!forcedHarness) {
57
+ const resolution = await resolveHostHarnessDetailsForRepo(projectRoot);
58
+ if (resolution.source === 'override' ||
59
+ resolution.source === 'env' ||
60
+ resolution.source === 'persisted') {
61
+ reportHarness = resolution.harness;
62
+ }
63
+ }
50
64
  }
51
65
  catch {
52
- // best-effort seed only.
66
+ // best-effort read only.
53
67
  }
54
68
  // USER-TYPED handle flags are validated up front and fail LOUD
55
69
  // (exit 1) on a miss — unlike the env-var channel, which keeps the
@@ -68,8 +82,11 @@ export function registerLearnCommand(program, deps = {}) {
68
82
  // (same set/restore shape as debug-trajectory's --harness) so it
69
83
  // reaches the registry adapter inside generateLearnReport without
70
84
  // changing any core signature. Restored as soon as the report exists.
85
+ const prevHarnessEnv = process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS;
71
86
  const prevTranscriptEnv = process.env.SYNERGYSPEC_SELFEVOLVING_TRANSCRIPT;
72
87
  const prevSessionEnv = process.env.SYNERGYSPEC_SELFEVOLVING_SESSION_ID;
88
+ if (reportHarness)
89
+ process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS = reportHarness;
73
90
  if (options.transcript)
74
91
  process.env.SYNERGYSPEC_SELFEVOLVING_TRANSCRIPT = options.transcript;
75
92
  if (options.sessionId)
@@ -79,6 +96,14 @@ export function registerLearnCommand(program, deps = {}) {
79
96
  report = await generateLearnReport({ projectRoot, changeName: change });
80
97
  }
81
98
  finally {
99
+ if (reportHarness) {
100
+ if (prevHarnessEnv === undefined) {
101
+ delete process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS;
102
+ }
103
+ else {
104
+ process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS = prevHarnessEnv;
105
+ }
106
+ }
82
107
  if (options.transcript) {
83
108
  if (prevTranscriptEnv === undefined) {
84
109
  delete process.env.SYNERGYSPEC_SELFEVOLVING_TRANSCRIPT;
@@ -198,18 +223,19 @@ export function registerLearnCommand(program, deps = {}) {
198
223
  // orderSwap / tamperCheck / divergenceCheck). Omitted ⇒ the orchestrator's
199
224
  // single-sample, divergence-routing default (no extra spawns).
200
225
  const episodeConfig = readProjectConfig(projectRoot);
201
- // Pass the host-resolved harness EXPLICITLY into the in-process episode
202
- // (learn runs host-level where the harness is confidently resolvable),
203
- // so the orchestrator's reward/evolving agent spawns never fall back to
204
- // the default 'claude' binary on a non-claude host.
205
- const harness = await resolveHostHarnessForRepo(projectRoot);
226
+ // Pass the host-resolved harness EXPLICITLY only when the resolver has
227
+ // a real host signal. A silent default must remain "unknown" rather
228
+ // than being laundered into a concrete Claude provenance value.
229
+ const harness = forcedHarness
230
+ ? (await persistHostHarness(projectRoot, forcedHarness), forcedHarness)
231
+ : await seedHostHarnessForRepo(projectRoot).then((resolution) => resolution.source === 'default' ? undefined : resolution.harness);
206
232
  episodeOutcome = await runEpisodeImpl({
207
233
  repoRoot: projectRoot,
208
234
  targetId: concreteEvolveTarget.targetId,
209
235
  changeName: report.changeName,
210
236
  changeDirPath: report.changeDir,
211
237
  mainArm,
212
- harness,
238
+ ...(harness ? { harness } : {}),
213
239
  ...(episodeConfig?.selfEvolution?.reward
214
240
  ? { reward: episodeConfig.selfEvolution.reward }
215
241
  : {}),
@@ -218,6 +244,9 @@ export function registerLearnCommand(program, deps = {}) {
218
244
  ...(episodeConfig?.selfEvolution?.agentTimeoutMs !== undefined
219
245
  ? { agentTimeoutMs: episodeConfig.selfEvolution.agentTimeoutMs }
220
246
  : {}),
247
+ ...(options.rerun === true || options.forceNewEpisode === true
248
+ ? { forceNewEpisode: true }
249
+ : {}),
221
250
  });
222
251
  }
223
252
  if (options.json) {
@@ -261,6 +290,23 @@ export function registerLearnCommand(program, deps = {}) {
261
290
  // handle is honored either way.
262
291
  const opts = command.optsWithGlobals();
263
292
  try {
293
+ const forcedHarness = parseAgentHarness(opts.harness);
294
+ let debugHarness = forcedHarness;
295
+ let debugHarnessSource = forcedHarness ? 'override' : null;
296
+ try {
297
+ if (!forcedHarness) {
298
+ const resolution = await resolveHostHarnessDetailsForRepo(projectRoot);
299
+ debugHarnessSource = resolution.source;
300
+ if (resolution.source === 'override' ||
301
+ resolution.source === 'env' ||
302
+ resolution.source === 'persisted') {
303
+ debugHarness = resolution.harness;
304
+ }
305
+ }
306
+ }
307
+ catch {
308
+ // best-effort read only; the adapter block below will surface any miss.
309
+ }
264
310
  const discovered = await findTranscriptsForChange(change, projectRoot, {
265
311
  transcriptPath: opts.transcript,
266
312
  sessionId: opts.sessionId,
@@ -290,8 +336,8 @@ export function registerLearnCommand(program, deps = {}) {
290
336
  const prevHarnessEnv = process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS;
291
337
  const prevTranscriptEnv = process.env.SYNERGYSPEC_SELFEVOLVING_TRANSCRIPT;
292
338
  const prevSessionEnv = process.env.SYNERGYSPEC_SELFEVOLVING_SESSION_ID;
293
- if (opts.harness)
294
- process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS = opts.harness;
339
+ if (debugHarness)
340
+ process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS = debugHarness;
295
341
  // The explicit trajectory handle must reach the adapter's own discovery
296
342
  // call too (env is the only channel through the registry), so the
297
343
  // introspected payload reflects the same override as `discovery` above.
@@ -300,7 +346,8 @@ export function registerLearnCommand(program, deps = {}) {
300
346
  if (opts.sessionId)
301
347
  process.env.SYNERGYSPEC_SELFEVOLVING_SESSION_ID = opts.sessionId;
302
348
  try {
303
- const adapterTrajectory = await getTrajectoryForChange(projectRoot, change);
349
+ const adapterResult = await getTrajectoryResultForChange(projectRoot, change);
350
+ const adapterTrajectory = adapterResult.trajectory;
304
351
  // Change-scope guard input so debug-trajectory's facts + per-runner
305
352
  // detail reflect the same scope demotion the loop uses (surfaces a
306
353
  // green-but-out-of-scope graded run instead of hiding it).
@@ -309,6 +356,9 @@ export function registerLearnCommand(program, deps = {}) {
309
356
  .catch(() => undefined));
310
357
  payload.adapter = {
311
358
  resolvedHarness: resolveHostHarness(),
359
+ resolvedHarnessSource: debugHarnessSource,
360
+ sourceHarness: adapterResult.sourceHarness,
361
+ reason: adapterResult.reason ?? null,
312
362
  sessionId: adapterTrajectory?.sessionId ?? null,
313
363
  turns: adapterTrajectory?.turns.length ?? 0,
314
364
  sourcePaths: adapterTrajectory ? [...new Set(adapterTrajectory.sourcePaths)] : [],
@@ -324,7 +374,7 @@ export function registerLearnCommand(program, deps = {}) {
324
374
  };
325
375
  }
326
376
  finally {
327
- if (opts.harness) {
377
+ if (debugHarness) {
328
378
  if (prevHarnessEnv === undefined) {
329
379
  delete process.env.SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS;
330
380
  }
@@ -625,6 +675,7 @@ function printJson(report, applied, evolutionPreview, hintsPath, episodeOutcome)
625
675
  ? { busy: true, reason: episodeOutcome.reason }
626
676
  : {
627
677
  episodeId: episodeOutcome.episodeId,
678
+ ...(episodeOutcome.harness ? { harness: episodeOutcome.harness } : {}),
628
679
  baselineSkipped: episodeOutcome.baselineSkipped,
629
680
  advantage: episodeOutcome.advantage,
630
681
  decision: episodeOutcome.decision,
@@ -876,7 +927,8 @@ function renderLearnTransparency(report, applied, evolutionPreview, hintsPath, o
876
927
  }
877
928
  /**
878
929
  * The loop-v2 autonomous entrance command (CS6-F):
879
- * `self-evolution episode --change "<name>" [--target <id>] [--session-id <id>]`.
930
+ * `self-evolution episode --change "<name>" [--target <id>] [--harness <h>]
931
+ * [--session-id <id>]`.
880
932
  * Replaces the GA `auto-evolve` / autonomous `evolve-from-edits` suggestions as
881
933
  * the loop-v2 path. The `--target` pin is included only when a concrete target
882
934
  * id resolved; `--session-id` is threaded through when the operator pinned an
@@ -886,8 +938,12 @@ function renderEpisodeCommand(changeName, targetId, options) {
886
938
  const parts = [`synergyspec-selfevolving self-evolution episode --change "${changeName}"`];
887
939
  if (targetId)
888
940
  parts.push(`--target ${targetId}`);
941
+ if (options.harness)
942
+ parts.push(`--harness ${options.harness}`);
889
943
  if (options.sessionId)
890
944
  parts.push(`--session-id ${options.sessionId}`);
945
+ if (options.rerun === true || options.forceNewEpisode === true)
946
+ parts.push('--rerun');
891
947
  return parts.join(' ');
892
948
  }
893
949
  /** The loop-v2 next-step line shown when a concrete target is pinned. */
@@ -0,0 +1,54 @@
1
+ import { Command } from 'commander';
2
+ import { type DreamPolicyEditSynthesizer, type DreamPolicyUpdateResult, type DreamPreview, type DreamRunManifest } from '../core/self-evolution/index.js';
3
+ export declare function attachSelfEvolutionDreamCommands(parent: Command): void;
4
+ export interface RunDreamPreviewArgs {
5
+ target?: string;
6
+ limit?: number;
7
+ json?: boolean;
8
+ }
9
+ export interface RunDreamCommandOptions {
10
+ repoRoot: string;
11
+ stdout?: (line: string) => void;
12
+ stderr?: (line: string) => void;
13
+ now?: () => Date;
14
+ synthesizeEdits?: DreamPolicyEditSynthesizer;
15
+ }
16
+ export interface RunDreamPreviewResult {
17
+ exitCode: number;
18
+ preview?: DreamPreview;
19
+ error?: string;
20
+ }
21
+ export declare function runDreamPreviewCommand(args: RunDreamPreviewArgs, opts: RunDreamCommandOptions): Promise<RunDreamPreviewResult>;
22
+ export interface RunDreamRunArgs extends RunDreamPreviewArgs {
23
+ applyPolicy?: boolean;
24
+ yes?: boolean;
25
+ }
26
+ export interface RunDreamRunResult {
27
+ exitCode: number;
28
+ manifest?: DreamRunManifest;
29
+ error?: string;
30
+ }
31
+ export declare function runDreamRunCommand(args: RunDreamRunArgs, opts: RunDreamCommandOptions): Promise<RunDreamRunResult>;
32
+ export interface RunDreamPolicyUpdateArgs {
33
+ candidateId: string;
34
+ acceptedBy?: string;
35
+ yes?: boolean;
36
+ json?: boolean;
37
+ }
38
+ export interface RunDreamPolicyUpdateResult extends DreamPolicyUpdateResult {
39
+ exitCode: number;
40
+ error?: string;
41
+ }
42
+ export declare function runDreamPolicyUpdateCommand(args: RunDreamPolicyUpdateArgs, opts: RunDreamCommandOptions): Promise<RunDreamPolicyUpdateResult>;
43
+ export interface RunDreamShowArgs {
44
+ runId?: string;
45
+ json?: boolean;
46
+ }
47
+ export interface RunDreamShowResult {
48
+ exitCode: number;
49
+ manifest?: DreamRunManifest;
50
+ error?: string;
51
+ }
52
+ export declare function runDreamShowCommand(args: RunDreamShowArgs, opts: RunDreamCommandOptions): Promise<RunDreamShowResult>;
53
+ export declare function parseDreamLimitOption(value: string): number;
54
+ //# sourceMappingURL=self-evolution-dream.d.ts.map
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Offline Supervised Learning Dream commands.
3
+ *
4
+ * Dream reads accumulated evidence and writes review candidates by default.
5
+ * Explicit accepted-candidate paths can synthesize bounded edits, run the
6
+ * static gate, and promote through the existing ledger/rollback channel.
7
+ */
8
+ import { promises as fs } from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import { buildDreamPreview, readDreamRun, renderDreamPreview, renderDreamRun, resolveDreamRunsDir, runAcceptedDreamPolicyUpdate, writeDreamRun, } from '../core/self-evolution/index.js';
11
+ export function attachSelfEvolutionDreamCommands(parent) {
12
+ const dream = parent
13
+ .command('dream')
14
+ .description('Offline Supervised Learning Dream: batch-mine evidence into candidates and apply accepted policy updates');
15
+ dream
16
+ .command('preview')
17
+ .description('Preview Dream batch proposals without writing candidates or policy files')
18
+ .option('--target <id>', 'restrict Dream to one existing canonical target')
19
+ .option('--limit <n>', 'maximum number of Dream proposals to show', parseDreamLimitOption, 3)
20
+ .option('--json', 'output JSON')
21
+ .action(async (options) => {
22
+ const result = await runDreamPreviewCommand({
23
+ target: options.target,
24
+ limit: options.limit,
25
+ json: options.json,
26
+ }, { repoRoot: process.cwd() });
27
+ process.exitCode = result.exitCode;
28
+ });
29
+ dream
30
+ .command('run')
31
+ .description('Run Dream batch proposal generation; plain run writes drafts, --apply --yes attempts gated policy updates')
32
+ .option('--target <id>', 'restrict Dream to one existing canonical target')
33
+ .option('--limit <n>', 'maximum number of Dream candidates to write', parseDreamLimitOption, 3)
34
+ .option('--apply', 'synthesize bounded edits, run the static gate, and promote passing Dream candidates')
35
+ .option('--yes', 'confirm non-interactive Dream policy updates when --apply is used')
36
+ .option('--json', 'output JSON')
37
+ .action(async (options) => {
38
+ const result = await runDreamRunCommand({
39
+ target: options.target,
40
+ limit: options.limit,
41
+ applyPolicy: options.apply,
42
+ yes: options.yes,
43
+ json: options.json,
44
+ }, { repoRoot: process.cwd() });
45
+ process.exitCode = result.exitCode;
46
+ });
47
+ dream
48
+ .command('policy-update <candidateId>')
49
+ .description('Promote an accepted dream-batch candidate through bounded edits, static gate, and policy ledger update')
50
+ .option('--accepted-by <name>', 'actor that accepted the Dream candidate', 'maintainer')
51
+ .option('--yes', 'confirm non-interactive policy update')
52
+ .option('--json', 'output JSON')
53
+ .action(async (candidateId, options) => {
54
+ const result = await runDreamPolicyUpdateCommand({
55
+ candidateId,
56
+ acceptedBy: options.acceptedBy,
57
+ yes: options.yes,
58
+ json: options.json,
59
+ }, { repoRoot: process.cwd() });
60
+ process.exitCode = result.exitCode;
61
+ });
62
+ dream
63
+ .command('show [runId]')
64
+ .description('Show a Dream run record; omit runId to print the latest run when one exists')
65
+ .option('--json', 'output JSON')
66
+ .action(async (runId, options) => {
67
+ const result = await runDreamShowCommand({ runId, json: options.json }, { repoRoot: process.cwd() });
68
+ process.exitCode = result.exitCode;
69
+ });
70
+ }
71
+ export async function runDreamPreviewCommand(args, opts) {
72
+ const stdout = opts.stdout ?? ((line) => console.log(line));
73
+ const stderr = opts.stderr ?? ((line) => console.error(line));
74
+ try {
75
+ const preview = await buildDreamPreview({
76
+ projectRoot: opts.repoRoot,
77
+ target: args.target,
78
+ limit: args.limit,
79
+ now: opts.now,
80
+ });
81
+ stdout(args.json ? JSON.stringify(preview, null, 2) : renderDreamPreview(preview));
82
+ return { exitCode: 0, preview };
83
+ }
84
+ catch (err) {
85
+ const error = err instanceof Error ? err.message : String(err);
86
+ if (args.json)
87
+ stdout(JSON.stringify({ error }, null, 2));
88
+ else
89
+ stderr(error);
90
+ return { exitCode: 1, error };
91
+ }
92
+ }
93
+ export async function runDreamRunCommand(args, opts) {
94
+ const stdout = opts.stdout ?? ((line) => console.log(line));
95
+ const stderr = opts.stderr ?? ((line) => console.error(line));
96
+ if (args.applyPolicy && !args.yes) {
97
+ const error = '--yes is required when using dream run --apply because it can promote policy updates.';
98
+ if (args.json)
99
+ stdout(JSON.stringify({ error }, null, 2));
100
+ else
101
+ stderr(error);
102
+ return { exitCode: 2, error };
103
+ }
104
+ try {
105
+ const manifest = await writeDreamRun({
106
+ projectRoot: opts.repoRoot,
107
+ target: args.target,
108
+ limit: args.limit,
109
+ now: opts.now,
110
+ applyPolicy: args.applyPolicy,
111
+ });
112
+ stdout(args.json ? JSON.stringify(manifest, null, 2) : renderDreamRun(manifest));
113
+ return { exitCode: 0, manifest };
114
+ }
115
+ catch (err) {
116
+ const error = err instanceof Error ? err.message : String(err);
117
+ if (args.json)
118
+ stdout(JSON.stringify({ error }, null, 2));
119
+ else
120
+ stderr(error);
121
+ return { exitCode: 1, error };
122
+ }
123
+ }
124
+ export async function runDreamPolicyUpdateCommand(args, opts) {
125
+ const stdout = opts.stdout ?? ((line) => console.log(line));
126
+ const stderr = opts.stderr ?? ((line) => console.error(line));
127
+ if (!args.yes) {
128
+ const error = '--yes is required because Dream policy-update can modify local policy files.';
129
+ const result = {
130
+ exitCode: 2,
131
+ candidateId: args.candidateId,
132
+ targetId: '(unknown)',
133
+ outcome: 'error-runtime',
134
+ promoted: false,
135
+ gatePassed: false,
136
+ promotedFiles: [],
137
+ policyVersion: null,
138
+ error,
139
+ reason: error,
140
+ };
141
+ if (args.json)
142
+ stdout(JSON.stringify(result, null, 2));
143
+ else
144
+ stderr(error);
145
+ return result;
146
+ }
147
+ try {
148
+ const update = await runAcceptedDreamPolicyUpdate({
149
+ projectRoot: opts.repoRoot,
150
+ candidateId: args.candidateId,
151
+ acceptedBy: args.acceptedBy ?? 'maintainer',
152
+ synthesizeEdits: opts.synthesizeEdits,
153
+ now: opts.now,
154
+ });
155
+ const result = {
156
+ exitCode: update.outcome === 'error-runtime' ? 1 : 0,
157
+ ...update,
158
+ };
159
+ if (args.json)
160
+ stdout(JSON.stringify(result, null, 2));
161
+ else
162
+ stdout(renderDreamPolicyUpdateResult(result));
163
+ return result;
164
+ }
165
+ catch (err) {
166
+ const error = err instanceof Error ? err.message : String(err);
167
+ const result = {
168
+ exitCode: 1,
169
+ candidateId: args.candidateId,
170
+ targetId: '(unknown)',
171
+ outcome: 'error-runtime',
172
+ promoted: false,
173
+ gatePassed: false,
174
+ promotedFiles: [],
175
+ policyVersion: null,
176
+ error,
177
+ reason: error,
178
+ };
179
+ if (args.json)
180
+ stdout(JSON.stringify(result, null, 2));
181
+ else
182
+ stderr(error);
183
+ return result;
184
+ }
185
+ }
186
+ function renderDreamPolicyUpdateResult(result) {
187
+ const lines = [
188
+ `Dream policy update: ${result.outcome}`,
189
+ `Candidate: ${result.candidateId}`,
190
+ `Target: ${result.targetId}`,
191
+ `Gate passed: ${result.gatePassed ? 'yes' : 'no'}`,
192
+ `Policy version: ${result.policyVersion ?? '(unchanged)'}`,
193
+ ];
194
+ if (result.promotedFiles.length > 0) {
195
+ lines.push(`Promoted files: ${result.promotedFiles.join(', ')}`);
196
+ }
197
+ if (result.reason)
198
+ lines.push(`Reason: ${result.reason}`);
199
+ return lines.join('\n');
200
+ }
201
+ export async function runDreamShowCommand(args, opts) {
202
+ const stdout = opts.stdout ?? ((line) => console.log(line));
203
+ const stderr = opts.stderr ?? ((line) => console.error(line));
204
+ try {
205
+ const runId = args.runId ?? (await latestRunId(opts.repoRoot));
206
+ if (!runId) {
207
+ const error = 'No Dream runs found.';
208
+ if (args.json)
209
+ stdout(JSON.stringify({ error }, null, 2));
210
+ else
211
+ stderr(error);
212
+ return { exitCode: 1, error };
213
+ }
214
+ const manifest = await readDreamRun(opts.repoRoot, runId);
215
+ stdout(args.json ? JSON.stringify(manifest, null, 2) : renderDreamRun(manifest));
216
+ return { exitCode: 0, manifest };
217
+ }
218
+ catch (err) {
219
+ const error = err instanceof Error ? err.message : String(err);
220
+ if (args.json)
221
+ stdout(JSON.stringify({ error }, null, 2));
222
+ else
223
+ stderr(error);
224
+ return { exitCode: 1, error };
225
+ }
226
+ }
227
+ async function latestRunId(repoRoot) {
228
+ let entries;
229
+ const runsDir = resolveDreamRunsDir(repoRoot);
230
+ try {
231
+ entries = await fs.readdir(runsDir, { withFileTypes: true });
232
+ }
233
+ catch (err) {
234
+ if (err.code === 'ENOENT')
235
+ return null;
236
+ throw err;
237
+ }
238
+ const ids = [];
239
+ for (const entry of entries) {
240
+ if (!entry.isDirectory() || !isDreamRunId(entry.name))
241
+ continue;
242
+ try {
243
+ const stat = await fs.stat(path.join(runsDir, entry.name, 'dream-run.json'));
244
+ if (stat.isFile())
245
+ ids.push(entry.name);
246
+ }
247
+ catch (err) {
248
+ if (err.code !== 'ENOENT')
249
+ throw err;
250
+ }
251
+ }
252
+ ids.sort().reverse();
253
+ return ids[0] ?? null;
254
+ }
255
+ export function parseDreamLimitOption(value) {
256
+ if (!/^(0|[1-9]\d*)$/.test(value)) {
257
+ throw new Error(`expected a non-negative integer, got: ${value}`);
258
+ }
259
+ const parsed = Number(value);
260
+ return parsed;
261
+ }
262
+ function isDreamRunId(value) {
263
+ return /^dream-\d{8}t\d{6}z-[a-f0-9]{8}$/.test(value);
264
+ }
265
+ //# sourceMappingURL=self-evolution-dream.js.map
@@ -58,10 +58,14 @@ export interface RunEpisodeCommandArgs {
58
58
  target?: string;
59
59
  /** Skip the CRITIC AGENT(基线智能体 baseline agent)arm for this episode. */
60
60
  noBaseline?: boolean;
61
+ /** Force the observed-run/code-agent harness for this episode. */
62
+ harness?: string;
61
63
  /** Explicit transcript handle (Claude transcript store only). */
62
64
  transcript?: string;
63
65
  /** Explicit Claude session id handle. */
64
66
  sessionId?: string;
67
+ /** Force a new episode even when a completed matching run exists. */
68
+ forceNewEpisode?: boolean;
65
69
  json?: boolean;
66
70
  }
67
71
  export interface RunEpisodeCommandOptions {
@@ -106,6 +110,7 @@ export interface RunEpisodeCommandResult {
106
110
  export declare function runEpisodeCommand(args: RunEpisodeCommandArgs, opts: RunEpisodeCommandOptions): Promise<RunEpisodeCommandResult>;
107
111
  export interface RunResumeEpisodeCommandArgs {
108
112
  episodeId: string;
113
+ harness?: string;
109
114
  json?: boolean;
110
115
  }
111
116
  export interface RunResumeEpisodeCommandResult {