synergyspec-selfevolving 1.3.0 → 2.0.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.
Files changed (113) hide show
  1. package/README.md +50 -19
  2. package/dist/commands/learn.d.ts +12 -1
  3. package/dist/commands/learn.js +373 -31
  4. package/dist/commands/self-evolution-episode.d.ts +177 -0
  5. package/dist/commands/self-evolution-episode.js +423 -0
  6. package/dist/commands/self-evolution.d.ts +12 -190
  7. package/dist/commands/self-evolution.js +179 -786
  8. package/dist/commands/workflow/status.js +3 -1
  9. package/dist/core/archive.d.ts +0 -1
  10. package/dist/core/archive.js +0 -58
  11. package/dist/core/artifact-graph/instruction-loader.d.ts +2 -4
  12. package/dist/core/artifact-graph/instruction-loader.js +3 -31
  13. package/dist/core/config-prompts.js +4 -0
  14. package/dist/core/fitness/health/health-metrics.d.ts +26 -56
  15. package/dist/core/fitness/health/health-metrics.js +19 -58
  16. package/dist/core/fitness/health/index.d.ts +15 -2
  17. package/dist/core/fitness/health/index.js +25 -1
  18. package/dist/core/fitness/health/local-source.d.ts +43 -4
  19. package/dist/core/fitness/health/local-source.js +181 -25
  20. package/dist/core/fitness/health/metric-source.d.ts +48 -19
  21. package/dist/core/fitness/health/metric-source.js +8 -18
  22. package/dist/core/fitness/health/resolve-source.js +4 -1
  23. package/dist/core/fitness/loss.d.ts +7 -7
  24. package/dist/core/fitness/loss.js +6 -6
  25. package/dist/core/fitness/sample.d.ts +10 -0
  26. package/dist/core/fitness/test-failures.d.ts +30 -0
  27. package/dist/core/fitness/test-failures.js +123 -0
  28. package/dist/core/learn/credit-path.d.ts +36 -0
  29. package/dist/core/learn/credit-path.js +198 -0
  30. package/dist/core/learn/trajectory-discovery.d.ts +39 -0
  31. package/dist/core/learn/trajectory-discovery.js +140 -0
  32. package/dist/core/learn.d.ts +39 -5
  33. package/dist/core/learn.js +131 -14
  34. package/dist/core/project-config.d.ts +4 -0
  35. package/dist/core/project-config.js +52 -1
  36. package/dist/core/self-evolution/candidate-fitness.d.ts +23 -1
  37. package/dist/core/self-evolution/candidate-fitness.js +31 -5
  38. package/dist/core/self-evolution/candidates.d.ts +0 -9
  39. package/dist/core/self-evolution/canonical-targets.d.ts +8 -4
  40. package/dist/core/self-evolution/canonical-targets.js +8 -4
  41. package/dist/core/self-evolution/critic-agent.d.ts +150 -0
  42. package/dist/core/self-evolution/critic-agent.js +487 -0
  43. package/dist/core/self-evolution/edits-contract.d.ts +53 -0
  44. package/dist/core/self-evolution/edits-contract.js +89 -0
  45. package/dist/core/self-evolution/episode-orchestrator.d.ts +197 -0
  46. package/dist/core/self-evolution/episode-orchestrator.js +534 -0
  47. package/dist/core/self-evolution/episode-store.d.ts +266 -0
  48. package/dist/core/self-evolution/episode-store.js +573 -0
  49. package/dist/core/self-evolution/evolution-switches.d.ts +1 -1
  50. package/dist/core/self-evolution/evolution-switches.js +5 -10
  51. package/dist/core/self-evolution/evolving-agent.d.ts +162 -0
  52. package/dist/core/self-evolution/evolving-agent.js +449 -0
  53. package/dist/core/self-evolution/health-baseline.d.ts +25 -6
  54. package/dist/core/self-evolution/health-baseline.js +30 -6
  55. package/dist/core/self-evolution/host-harness.d.ts +1 -2
  56. package/dist/core/self-evolution/host-harness.js +1 -2
  57. package/dist/core/self-evolution/index.d.ts +10 -6
  58. package/dist/core/self-evolution/index.js +19 -6
  59. package/dist/core/self-evolution/learn-hints.d.ts +31 -0
  60. package/dist/core/self-evolution/learn-hints.js +16 -0
  61. package/dist/core/self-evolution/learn-observation-adapter.d.ts +35 -0
  62. package/dist/core/self-evolution/learn-observation-adapter.js +285 -10
  63. package/dist/core/self-evolution/line-diff.d.ts +60 -0
  64. package/dist/core/self-evolution/line-diff.js +130 -0
  65. package/dist/core/self-evolution/policy/fs-safe.d.ts +19 -0
  66. package/dist/core/self-evolution/policy/fs-safe.js +89 -0
  67. package/dist/core/self-evolution/policy/index.d.ts +13 -0
  68. package/dist/core/self-evolution/policy/index.js +13 -0
  69. package/dist/core/self-evolution/policy/policy-store.d.ts +217 -0
  70. package/dist/core/self-evolution/policy/policy-store.js +774 -0
  71. package/dist/core/self-evolution/policy/reject-buffer.d.ts +48 -0
  72. package/dist/core/self-evolution/policy/reject-buffer.js +168 -0
  73. package/dist/core/self-evolution/promote.d.ts +1 -1
  74. package/dist/core/self-evolution/promote.js +6 -33
  75. package/dist/core/self-evolution/promotion.js +1 -2
  76. package/dist/core/self-evolution/proposer-agent.d.ts +41 -0
  77. package/dist/core/self-evolution/proposer-agent.js +94 -13
  78. package/dist/core/self-evolution/proposer-slice.d.ts +26 -0
  79. package/dist/core/self-evolution/proposer-slice.js +54 -0
  80. package/dist/core/self-evolution/reward-agent.d.ts +234 -0
  81. package/dist/core/self-evolution/reward-agent.js +564 -0
  82. package/dist/core/self-evolution/scope-gate.d.ts +66 -0
  83. package/dist/core/self-evolution/scope-gate.js +107 -0
  84. package/dist/core/self-evolution/success-channel.d.ts +79 -0
  85. package/dist/core/self-evolution/success-channel.js +361 -0
  86. package/dist/core/self-evolution/target-evolution.d.ts +11 -0
  87. package/dist/core/self-evolution/target-evolution.js +2 -0
  88. package/dist/core/self-evolution/tool-evolution.js +2 -13
  89. package/dist/core/self-evolution/verdict.d.ts +8 -5
  90. package/dist/core/self-evolution/verdict.js +4 -7
  91. package/dist/core/templates/skill-templates.d.ts +1 -0
  92. package/dist/core/templates/skill-templates.js +1 -0
  93. package/dist/core/templates/workflow-manifest.js +2 -0
  94. package/dist/core/templates/workflows/learn.d.ts +4 -2
  95. package/dist/core/templates/workflows/learn.js +25 -166
  96. package/dist/core/templates/workflows/self-evolving.d.ts +13 -0
  97. package/dist/core/templates/workflows/self-evolving.js +127 -0
  98. package/dist/core/trajectory/facts.d.ts +16 -0
  99. package/dist/core/trajectory/facts.js +12 -4
  100. package/dist/core/trajectory/skeleton.d.ts +43 -0
  101. package/dist/core/trajectory/skeleton.js +239 -0
  102. package/dist/dashboard/data.d.ts +25 -51
  103. package/dist/dashboard/data.js +68 -180
  104. package/dist/dashboard/react-client.js +458 -503
  105. package/dist/dashboard/react-styles.js +3 -3
  106. package/dist/dashboard/server.js +23 -17
  107. package/dist/ui/ascii-patterns.d.ts +7 -15
  108. package/dist/ui/ascii-patterns.js +123 -54
  109. package/dist/ui/welcome-screen.d.ts +0 -14
  110. package/dist/ui/welcome-screen.js +16 -35
  111. package/package.json +3 -1
  112. package/scripts/code-health.py +1066 -638
  113. package/scripts/slop_rules.yaml +2151 -0
@@ -831,7 +831,7 @@ h1 {
831
831
  }
832
832
  .evolve-main .panel-title,
833
833
  .evolve-main .metric-value,
834
- .evolve-main .benchmark,
834
+ .evolve-main .episode-name,
835
835
  .evolve-main .lineage-node strong { color: #fff; }
836
836
  .evolve-main .head-meta,
837
837
  .evolve-main .metric-label,
@@ -1424,7 +1424,7 @@ h1 {
1424
1424
  }
1425
1425
  .run-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--line-strong); }
1426
1426
  .run-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
1427
- .benchmark { color: var(--ink); font-weight: var(--w-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1427
+ .episode-name { color: var(--ink); font-weight: var(--w-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1428
1428
  .run-id { margin-top: 3px; color: var(--muted); font: 11px/1.35 var(--mono); word-break: break-all; }
1429
1429
  .donut-wrap { width: 66px; height: 66px; position: relative; flex: 0 0 66px; }
1430
1430
  .donut-center { position: absolute; inset: 0; display: grid; place-items: center; color: var(--ink); font-weight: var(--w-semibold); font-size: 13px; }
@@ -2398,7 +2398,7 @@ h1,
2398
2398
  .panel-title,
2399
2399
  .change-name,
2400
2400
  .empty-title,
2401
- .benchmark,
2401
+ .episode-name,
2402
2402
  .interface-plan h2,
2403
2403
  .workflow-step strong,
2404
2404
  .agent-phase strong,
@@ -5,7 +5,8 @@ import { createRequire } from 'module';
5
5
  import { dirname, isAbsolute, relative, resolve } from 'path';
6
6
  import { tailFile, readAllJsonLines } from './tail.js';
7
7
  import { renderDashboardHtml } from './index-html.js';
8
- import { readOverview, readProjectInfo, listChanges, readChange, readCliHistory, readAgentInterfacePlan, listEvolveRuns, readEvolveRun, readEvolveArchive, readArchitecture, } from './data.js';
8
+ import { readOverview, readProjectInfo, listChanges, readChange, readCliHistory, readAgentInterfacePlan, readSelfEvolution, readArchitecture, } from './data.js';
9
+ import { listEpisodes, readEpisode, readRejectBufferAll, } from '../core/self-evolution/index.js';
9
10
  const requireFromHere = createRequire(import.meta.url);
10
11
  const vendorPackageRoots = new Map();
11
12
  const vendorAssets = new Map([
@@ -219,12 +220,11 @@ async function handle(req, res, tracePath, projectRoot, clients) {
219
220
  }
220
221
  }
221
222
  if (req.method === 'GET' && url.pathname === '/') {
222
- const [project, changes, cliHistory, runs, archive, history, agentInterface, architecture] = await Promise.all([
223
+ const [project, changes, cliHistory, se, history, agentInterface, architecture] = await Promise.all([
223
224
  readProjectInfo(projectRoot).catch(() => ({})),
224
225
  listChanges(projectRoot).catch(() => []),
225
226
  readCliHistory(projectRoot, 500).catch(() => []),
226
- listEvolveRuns(projectRoot).catch(() => []),
227
- readEvolveArchive(projectRoot).catch(() => ({ entries: [], generations: [] })),
227
+ readSelfEvolution(projectRoot).catch(() => ({ episodes: [], policyLineages: [], rejectBuffer: [] })),
228
228
  readAllJsonLines(tracePath).catch(() => []),
229
229
  readAgentInterfacePlan(projectRoot).catch(() => null),
230
230
  readArchitecture(projectRoot).catch(() => null),
@@ -233,8 +233,9 @@ async function handle(req, res, tracePath, projectRoot, clients) {
233
233
  project,
234
234
  changes,
235
235
  cliHistory,
236
- runs,
237
- archive: archive ?? { entries: [], generations: [] },
236
+ episodes: se.episodes,
237
+ policyLineages: se.policyLineages,
238
+ rejectBuffer: se.rejectBuffer,
238
239
  history,
239
240
  agentInterface,
240
241
  architecture,
@@ -306,24 +307,29 @@ async function handle(req, res, tracePath, projectRoot, clients) {
306
307
  sendJson(res, await readArchitecture(projectRoot));
307
308
  return;
308
309
  }
309
- if (req.method === 'GET' && url.pathname === '/api/evolve/runs') {
310
- sendJson(res, await listEvolveRuns(projectRoot));
310
+ if (req.method === 'GET' && url.pathname === '/api/episodes') {
311
+ sendJson(res, await listEpisodes(projectRoot));
311
312
  return;
312
313
  }
313
- if (req.method === 'GET' && url.pathname.startsWith('/api/evolve/runs/')) {
314
- const id = decodeURIComponent(url.pathname.slice('/api/evolve/runs/'.length));
315
- const run = await readEvolveRun(projectRoot, id);
316
- if (!run) {
314
+ if (req.method === 'GET' && url.pathname.startsWith('/api/episodes/')) {
315
+ const id = decodeURIComponent(url.pathname.slice('/api/episodes/'.length));
316
+ try {
317
+ const episode = await readEpisode(projectRoot, id);
318
+ sendJson(res, episode);
319
+ }
320
+ catch {
317
321
  res.statusCode = 404;
318
322
  res.setHeader('content-type', 'application/json; charset=utf-8');
319
- res.end(JSON.stringify({ error: 'run not found', id }));
320
- return;
323
+ res.end(JSON.stringify({ error: 'episode not found', id }));
321
324
  }
322
- sendJson(res, run);
323
325
  return;
324
326
  }
325
- if (req.method === 'GET' && url.pathname === '/api/evolve/archive') {
326
- sendJson(res, (await readEvolveArchive(projectRoot)) ?? { entries: [], generations: [] });
327
+ if (req.method === 'GET' && url.pathname === '/api/policy/ledger') {
328
+ sendJson(res, (await readSelfEvolution(projectRoot)).policyLineages);
329
+ return;
330
+ }
331
+ if (req.method === 'GET' && url.pathname === '/api/reject-buffer') {
332
+ sendJson(res, await readRejectBufferAll(projectRoot));
327
333
  return;
328
334
  }
329
335
  if (req.method === 'GET' && url.pathname === '/api/history') {
@@ -1,21 +1,13 @@
1
1
  /**
2
- * ASCII art animation for the `synergyspec-selfevolving init` welcome screen.
3
- *
4
- * A self-evolving DNA double-helix: two strands twist continuously while a
5
- * generation counter and a fitness bar climb — a nod to the genetic-algorithm /
6
- * fitness machinery that actually drives self-evolution. Deliberately distinct
7
- * from the upstream diamond logo so the product reads as its own thing.
8
- *
9
- * INVARIANT: every frame has the SAME number of rows. `showWelcomeScreen`
10
- * (welcome-screen.ts) moves the cursor up by a fixed height derived from
11
- * `frames[0].length` between redraws, so unequal-height frames corrupt the
12
- * animation. Enforced by test/ui/welcome-animation.test.ts.
2
+ * ASCII art animation patterns for the welcome screen.
3
+ * SynergySpec-SelfEvolving logo animation - diamond/rhombus shape with hollow center "O".
13
4
  */
14
5
  /**
15
- * Welcome animation frames a self-evolving double helix.
16
- * Each frame: 9 helix rows + a generation row + a fitness row (11 rows total).
17
- * The helix twists, the generation counter climbs 01→08, and the fitness bar
18
- * fills, then the cycle loops.
6
+ * Welcome animation frames - SynergySpec-SelfEvolving logo building from center
7
+ * 7 rows × 6 columns diamond with hollow center "O"
8
+ * Center bar is 2 cols × 3 rows (rows 3,4,5 cols 3,4)
9
+ * Each frame is an array of strings (lines of ASCII art)
10
+ * Grid: 6 cols × 2 chars = 12 chars wide
19
11
  */
20
12
  export declare const WELCOME_ANIMATION: {
21
13
  interval: number;
@@ -1,64 +1,133 @@
1
1
  /**
2
- * ASCII art animation for the `synergyspec-selfevolving init` welcome screen.
3
- *
4
- * A self-evolving DNA double-helix: two strands twist continuously while a
5
- * generation counter and a fitness bar climb — a nod to the genetic-algorithm /
6
- * fitness machinery that actually drives self-evolution. Deliberately distinct
7
- * from the upstream diamond logo so the product reads as its own thing.
8
- *
9
- * INVARIANT: every frame has the SAME number of rows. `showWelcomeScreen`
10
- * (welcome-screen.ts) moves the cursor up by a fixed height derived from
11
- * `frames[0].length` between redraws, so unequal-height frames corrupt the
12
- * animation. Enforced by test/ui/welcome-animation.test.ts.
2
+ * ASCII art animation patterns for the welcome screen.
3
+ * SynergySpec-SelfEvolving logo animation - diamond/rhombus shape with hollow center "O".
13
4
  */
14
- // Detect if full Unicode is supported (Windows Terminal / modern terminals).
5
+ // Detect if full Unicode is supported
15
6
  const supportsUnicode = process.platform !== 'win32' ||
16
7
  !!process.env.WT_SESSION || // Windows Terminal
17
8
  !!process.env.TERM_PROGRAM; // Modern terminal
18
- // Helix glyphs with an ASCII fallback for legacy terminals (mirrors the old
19
- // full/dim/empty fallback pattern never assume Unicode).
20
- const G = supportsUnicode
21
- ? { node: '', up: '', down: '', cross: '╳' }
22
- : { node: 'o', up: '/', down: '\\', cross: 'X' };
23
- // Ascending "fuller" glyphs for the fitness bar; ASCII fallback for legacy terms.
24
- const FITNESS_RAMP = supportsUnicode ? '▁▂▃▄▅▆▇█' : '.:-=+*#@';
25
- // One vertical slice of the twisting double helix, at four phases. Scrolling
26
- // these downward one phase per frame reads as a continuous twist.
27
- const PHASES = [
28
- ` ${G.cross} `, // crossover
29
- ` ${G.up} ${G.down} `, // diverging (just below a crossover)
30
- ` ${G.node} ${G.node} `, // strands at max separation
31
- ` ${G.down} ${G.up} `, // converging (just above a crossover)
32
- ];
33
- const HELIX_ROWS = 9;
34
- const FRAME_COUNT = 8;
35
- // Nine rows of helix, phase-shifted by `offset` so the braid scrolls/twists.
36
- function helixFrame(offset) {
37
- const rows = [];
38
- for (let i = 0; i < HELIX_ROWS; i++) {
39
- rows.push(PHASES[(offset + i) % PHASES.length]);
40
- }
41
- return rows;
42
- }
43
- function generationRow(generation) {
44
- return ` gen ${String(generation).padStart(2, '0')}`;
45
- }
46
- // Fill `step` (1..FRAME_COUNT) ascending cells of the fitness bar.
47
- function fitnessRow(step) {
48
- return ` fit ${FITNESS_RAMP.slice(0, step)}`;
49
- }
9
+ // Character set based on Unicode support
10
+ // Block characters for pixel-art aesthetic
11
+ const CHARS = supportsUnicode
12
+ ? { full: '██', dim: '░░', empty: ' ' }
13
+ : { full: '##', dim: '++', empty: ' ' };
14
+ const _ = CHARS.empty;
15
+ const F = CHARS.full;
16
+ const D = CHARS.dim;
50
17
  /**
51
- * Welcome animation frames a self-evolving double helix.
52
- * Each frame: 9 helix rows + a generation row + a fitness row (11 rows total).
53
- * The helix twists, the generation counter climbs 01→08, and the fitness bar
54
- * fills, then the cycle loops.
18
+ * Welcome animation frames - SynergySpec-SelfEvolving logo building from center
19
+ * 7 rows × 6 columns diamond with hollow center "O"
20
+ * Center bar is 2 cols × 3 rows (rows 3,4,5 cols 3,4)
21
+ * Each frame is an array of strings (lines of ASCII art)
22
+ * Grid: 6 cols × 2 chars = 12 chars wide
55
23
  */
56
24
  export const WELCOME_ANIMATION = {
57
- interval: 110,
58
- frames: Array.from({ length: FRAME_COUNT }, (_unused, k) => [
59
- ...helixFrame(k),
60
- generationRow(k + 1),
61
- fitnessRow(k + 1),
62
- ]),
25
+ interval: 120,
26
+ frames: [
27
+ // Frame 1: Empty
28
+ [
29
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
30
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
31
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
32
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
33
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
34
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
35
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
36
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
37
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
38
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
39
+ ],
40
+ // Frame 2: Center blocks appear (dim) - 2x3 center bar
41
+ [
42
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
43
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
44
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
45
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
46
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
47
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
48
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
49
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
50
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
51
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
52
+ ],
53
+ // Frame 3: Center blocks solidify
54
+ [
55
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
56
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
57
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
58
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
59
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
60
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
61
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
62
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
63
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
64
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
65
+ ],
66
+ // Frame 4: Top and bottom points appear
67
+ [
68
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
69
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
70
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
71
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
72
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
73
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
74
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
75
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
76
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
77
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
78
+ ],
79
+ // Frame 5: Inner ring forming
80
+ [
81
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
82
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
83
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
84
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
85
+ `${_}${_}${_}${D}${_}${_}${D}${_}`,
86
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
87
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
88
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
89
+ `${_}${_}${_}${D}${_}${_}${D}${_}`,
90
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
91
+ ],
92
+ // Frame 6: Outer ring appearing
93
+ [
94
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
95
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
96
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
97
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
98
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
99
+ `${_}${_}${D}${_}${F}${F}${_}${D}`,
100
+ `${_}${_}${D}${_}${F}${F}${_}${D}`,
101
+ `${_}${_}${D}${_}${F}${F}${_}${D}`,
102
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
103
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
104
+ ],
105
+ // Frame 7: Full logo
106
+ [
107
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
108
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
109
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
110
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
111
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
112
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
113
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
114
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
115
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
116
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
117
+ ],
118
+ // Frame 8: Hold complete logo
119
+ [
120
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
121
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
122
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
123
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
124
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
125
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
126
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
127
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
128
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
129
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
130
+ ],
131
+ ],
63
132
  };
64
133
  //# sourceMappingURL=ascii-patterns.js.map
@@ -2,20 +2,6 @@
2
2
  * Animated welcome screen for the experimental artifact workflow setup.
3
3
  * Shows side-by-side layout with animated ASCII art on left and welcome text on right.
4
4
  */
5
- /**
6
- * Welcome text content (right column).
7
- * Leads with the self-evolving loop — the thing that sets this apart.
8
- * Keep each line ≤ 35 visible chars so it never wraps at the 60-col MIN_WIDTH
9
- * after the 24-col art gutter (locked by test/ui/welcome-animation.test.ts).
10
- */
11
- export declare function getWelcomeText(): string[];
12
- /**
13
- * Renders a single frame with side-by-side layout.
14
- * `artColor` lets the caller pulse the helix color per frame; the raw art is
15
- * padded to the column width BEFORE coloring so ANSI codes never count toward
16
- * the width and the text column stays aligned.
17
- */
18
- export declare function renderFrame(artLines: string[], textLines: string[], artColor?: (s: string) => string): string;
19
5
  /**
20
6
  * Shows the animated welcome screen.
21
7
  * Returns when user presses Enter.
@@ -9,61 +9,43 @@ const MIN_WIDTH = 60;
9
9
  // Width of the ASCII art column (with padding)
10
10
  const ART_COLUMN_WIDTH = 24;
11
11
  /**
12
- * Welcome text content (right column).
13
- * Leads with the self-evolving loop — the thing that sets this apart.
14
- * Keep each line ≤ 35 visible chars so it never wraps at the 60-col MIN_WIDTH
15
- * after the 24-col art gutter (locked by test/ui/welcome-animation.test.ts).
12
+ * Welcome text content (right column)
16
13
  */
17
- export function getWelcomeText() {
14
+ function getWelcomeText() {
18
15
  return [
19
16
  chalk.white.bold('Welcome to SynergySpec-SelfEvolving'),
20
- chalk.dim('Specs that evolve as you work'),
17
+ chalk.dim('A lightweight spec-driven framework'),
21
18
  '',
22
19
  chalk.white('This setup will configure:'),
23
20
  chalk.dim(' • Agent Skills for AI tools'),
24
21
  chalk.dim(' • /synspec:* slash commands'),
25
- chalk.green(' • A self-evolution loop'),
26
- chalk.dim(' that improves its own prompts'),
27
22
  '',
28
23
  chalk.white('Quick start after setup:'),
29
- ` ${chalk.yellow('/synspec:propose')} ${chalk.dim('Start a change')}`,
30
- ` ${chalk.yellow('/synspec:apply')} ${chalk.dim('Implement tasks')}`,
31
- ` ${chalk.yellow('/synspec:learn')} ${chalk.green('Evolve from runs')}`,
24
+ ` ${chalk.yellow('/synspec:new')} ${chalk.dim('Create a change')}`,
25
+ ` ${chalk.yellow('/synspec:continue')} ${chalk.dim('Next artifact')}`,
26
+ ` ${chalk.yellow('/synspec:apply')} ${chalk.dim('Implement tasks')}`,
32
27
  '',
33
28
  chalk.cyan('Press Enter to select tools...'),
34
29
  ];
35
30
  }
36
31
  /**
37
- * Renders a single frame with side-by-side layout.
38
- * `artColor` lets the caller pulse the helix color per frame; the raw art is
39
- * padded to the column width BEFORE coloring so ANSI codes never count toward
40
- * the width and the text column stays aligned.
32
+ * Renders a single frame with side-by-side layout
41
33
  */
42
- export function renderFrame(artLines, textLines, artColor = chalk.cyan) {
34
+ function renderFrame(artLines, textLines) {
43
35
  const maxLines = Math.max(artLines.length, textLines.length);
44
36
  const lines = [];
45
37
  for (let i = 0; i < maxLines; i++) {
46
38
  const artLine = artLines[i] || '';
47
39
  const textLine = textLines[i] || '';
48
- // Pad the art column to fixed width (raw, before color)
40
+ // Pad the art column to fixed width
49
41
  const paddedArt = artLine.padEnd(ART_COLUMN_WIDTH);
50
- // Color the helix art (caller-supplied so it can "pulse" between frames)
51
- const coloredArt = artColor(paddedArt);
42
+ // Color the ASCII art with cyan for visual appeal
43
+ const coloredArt = chalk.cyan(paddedArt);
52
44
  // Clear line before writing to prevent residual characters
53
45
  lines.push(`\x1b[2K${coloredArt}${textLine}`);
54
46
  }
55
47
  return lines.join('\n');
56
48
  }
57
- /**
58
- * Per-frame color cycle that makes the helix look alive/evolving
59
- * (cyan → bright cyan → green → bright green → …).
60
- */
61
- const PULSE_COLORS = [
62
- chalk.cyan,
63
- chalk.cyanBright,
64
- chalk.green,
65
- chalk.greenBright,
66
- ];
67
49
  /**
68
50
  * Checks if the terminal supports animation
69
51
  */
@@ -119,9 +101,9 @@ function waitForEnter() {
119
101
  export async function showWelcomeScreen() {
120
102
  const textLines = getWelcomeText();
121
103
  if (!canAnimate()) {
122
- // Fallback: show the fully-evolved final frame (greenBright = "evolved").
123
- const frame = WELCOME_ANIMATION.frames[WELCOME_ANIMATION.frames.length - 1];
124
- process.stdout.write('\n' + renderFrame(frame, textLines, chalk.greenBright) + '\n\n');
104
+ // Fallback: show static welcome
105
+ const frame = WELCOME_ANIMATION.frames[3]; // Peak frame
106
+ process.stdout.write('\n' + renderFrame(frame, textLines) + '\n\n');
125
107
  return;
126
108
  }
127
109
  let frameIndex = 0;
@@ -144,9 +126,8 @@ export async function showWelcomeScreen() {
144
126
  process.stdout.write(`\x1b[${frameHeight}A`);
145
127
  }
146
128
  isFirstRender = false;
147
- // Render current frame with a pulsing helix color (alive/evolving)
148
- const color = PULSE_COLORS[frameIndex % PULSE_COLORS.length];
149
- process.stdout.write(renderFrame(frame, textLines, color) + '\n\n');
129
+ // Render current frame
130
+ process.stdout.write(renderFrame(frame, textLines) + '\n\n');
150
131
  // Advance to next frame
151
132
  frameIndex = (frameIndex + 1) % WELCOME_ANIMATION.frames.length;
152
133
  }, WELCOME_ANIMATION.interval);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synergyspec-selfevolving",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "synergyspec-selfevolving",
@@ -38,6 +38,7 @@
38
38
  "scripts/postinstall.js",
39
39
  "scripts/nl2repo_synergyspec-selfevolving_wrapper.py",
40
40
  "scripts/code-health.py",
41
+ "scripts/slop_rules.yaml",
41
42
  "!dist/**/*.test.js",
42
43
  "!dist/**/__tests__",
43
44
  "!dist/**/*.map"
@@ -79,6 +80,7 @@
79
80
  "vitest": "^3.2.4"
80
81
  },
81
82
  "dependencies": {
83
+ "@ast-grep/cli": "0.43.0",
82
84
  "@inquirer/core": "^10.2.2",
83
85
  "@inquirer/prompts": "^7.8.0",
84
86
  "ansi-regex": "^5.0.1",