synergyspec-selfevolving 1.4.0 → 2.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/README.md +31 -18
- package/dist/commands/learn.d.ts +12 -1
- package/dist/commands/learn.js +158 -11
- package/dist/commands/self-evolution-episode.d.ts +177 -0
- package/dist/commands/self-evolution-episode.js +431 -0
- package/dist/commands/self-evolution.d.ts +12 -190
- package/dist/commands/self-evolution.js +114 -866
- package/dist/core/archive.d.ts +0 -1
- package/dist/core/archive.js +0 -58
- package/dist/core/artifact-graph/instruction-loader.d.ts +2 -4
- package/dist/core/artifact-graph/instruction-loader.js +3 -31
- package/dist/core/fitness/loss.d.ts +5 -5
- package/dist/core/fitness/loss.js +4 -4
- package/dist/core/fitness/test-failures.js +10 -2
- package/dist/core/project-config.d.ts +19 -0
- package/dist/core/project-config.js +96 -0
- package/dist/core/self-evolution/candidate-fitness.d.ts +23 -1
- package/dist/core/self-evolution/candidate-fitness.js +31 -5
- package/dist/core/self-evolution/candidates.d.ts +0 -9
- package/dist/core/self-evolution/critic-agent.d.ts +192 -0
- package/dist/core/self-evolution/critic-agent.js +568 -0
- package/dist/core/self-evolution/edits-contract.d.ts +53 -0
- package/dist/core/self-evolution/edits-contract.js +89 -0
- package/dist/core/self-evolution/episode-orchestrator.d.ts +234 -0
- package/dist/core/self-evolution/episode-orchestrator.js +681 -0
- package/dist/core/self-evolution/episode-store.d.ts +266 -0
- package/dist/core/self-evolution/episode-store.js +573 -0
- package/dist/core/self-evolution/evolution-switches.d.ts +1 -1
- package/dist/core/self-evolution/evolution-switches.js +5 -10
- package/dist/core/self-evolution/evolving-agent.d.ts +208 -0
- package/dist/core/self-evolution/evolving-agent.js +535 -0
- package/dist/core/self-evolution/host-harness.d.ts +14 -15
- package/dist/core/self-evolution/host-harness.js +48 -23
- package/dist/core/self-evolution/index.d.ts +11 -6
- package/dist/core/self-evolution/index.js +20 -6
- package/dist/core/self-evolution/line-diff.d.ts +60 -0
- package/dist/core/self-evolution/line-diff.js +130 -0
- package/dist/core/self-evolution/policy/fs-safe.d.ts +19 -0
- package/dist/core/self-evolution/policy/fs-safe.js +89 -0
- package/dist/core/self-evolution/policy/index.d.ts +13 -0
- package/dist/core/self-evolution/policy/index.js +13 -0
- package/dist/core/self-evolution/policy/policy-store.d.ts +217 -0
- package/dist/core/self-evolution/policy/policy-store.js +774 -0
- package/dist/core/self-evolution/policy/prediction-reconcile.d.ts +54 -0
- package/dist/core/self-evolution/policy/prediction-reconcile.js +191 -0
- package/dist/core/self-evolution/policy/reject-buffer.d.ts +55 -0
- package/dist/core/self-evolution/policy/reject-buffer.js +170 -0
- package/dist/core/self-evolution/promote.d.ts +1 -1
- package/dist/core/self-evolution/promote.js +6 -33
- package/dist/core/self-evolution/promotion.js +1 -2
- package/dist/core/self-evolution/reward-agent.d.ts +379 -0
- package/dist/core/self-evolution/reward-agent.js +940 -0
- package/dist/core/self-evolution/reward-aggregator.d.ts +59 -0
- package/dist/core/self-evolution/reward-aggregator.js +262 -0
- package/dist/core/self-evolution/scope-gate.d.ts +66 -0
- package/dist/core/self-evolution/scope-gate.js +107 -0
- package/dist/core/self-evolution/success-channel.js +2 -2
- package/dist/core/self-evolution/tamper-check.d.ts +24 -0
- package/dist/core/self-evolution/tamper-check.js +236 -0
- package/dist/core/self-evolution/tool-evolution.js +2 -13
- package/dist/core/self-evolution/verdict.d.ts +8 -5
- package/dist/core/self-evolution/verdict.js +4 -7
- package/dist/core/templates/workflows/gen-tests.js +1 -1
- package/dist/core/templates/workflows/learn.d.ts +3 -2
- package/dist/core/templates/workflows/learn.js +21 -18
- package/dist/core/templates/workflows/self-evolving.d.ts +6 -4
- package/dist/core/templates/workflows/self-evolving.js +62 -172
- package/dist/core/trajectory/scrub.d.ts +27 -0
- package/dist/core/trajectory/scrub.js +79 -0
- package/dist/core/trajectory/skeleton.d.ts +27 -1
- package/dist/core/trajectory/skeleton.js +152 -8
- package/dist/dashboard/data.d.ts +25 -51
- package/dist/dashboard/data.js +68 -180
- package/dist/dashboard/react-client.js +458 -503
- package/dist/dashboard/react-styles.js +3 -3
- package/dist/dashboard/server.js +23 -17
- package/dist/ui/ascii-patterns.d.ts +7 -15
- package/dist/ui/ascii-patterns.js +123 -54
- package/dist/ui/welcome-screen.d.ts +0 -14
- package/dist/ui/welcome-screen.js +16 -35
- package/package.json +1 -1
- package/dist/core/self-evolution/ga-selection.d.ts +0 -94
- package/dist/core/self-evolution/ga-selection.js +0 -153
- package/dist/core/self-evolution/proposer-agent.d.ts +0 -182
- package/dist/core/self-evolution/proposer-agent.js +0 -326
- package/dist/core/self-evolution/replay-runner.d.ts +0 -100
- package/dist/core/self-evolution/replay-runner.js +0 -170
- package/dist/core/self-evolution/replay.d.ts +0 -45
- package/dist/core/self-evolution/replay.js +0 -56
- package/dist/core/self-evolution/template-variants.d.ts +0 -62
- package/dist/core/self-evolution/template-variants.js +0 -171
- package/dist/core/self-evolution/trajectory.d.ts +0 -65
- package/dist/core/self-evolution/trajectory.js +0 -185
|
@@ -831,7 +831,7 @@ h1 {
|
|
|
831
831
|
}
|
|
832
832
|
.evolve-main .panel-title,
|
|
833
833
|
.evolve-main .metric-value,
|
|
834
|
-
.evolve-main .
|
|
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
|
-
.
|
|
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
|
-
.
|
|
2401
|
+
.episode-name,
|
|
2402
2402
|
.interface-plan h2,
|
|
2403
2403
|
.workflow-step strong,
|
|
2404
2404
|
.agent-phase strong,
|
package/dist/dashboard/server.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
237
|
-
|
|
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/
|
|
310
|
-
sendJson(res, await
|
|
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/
|
|
314
|
-
const id = decodeURIComponent(url.pathname.slice('/api/
|
|
315
|
-
|
|
316
|
-
|
|
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: '
|
|
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/
|
|
326
|
-
sendJson(res, (await
|
|
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
|
|
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
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
|
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
|
|
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
|
-
//
|
|
19
|
-
//
|
|
20
|
-
const
|
|
21
|
-
? {
|
|
22
|
-
: {
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
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
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
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:
|
|
58
|
-
frames:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
14
|
+
function getWelcomeText() {
|
|
18
15
|
return [
|
|
19
16
|
chalk.white.bold('Welcome to SynergySpec-SelfEvolving'),
|
|
20
|
-
chalk.dim('
|
|
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:
|
|
30
|
-
` ${chalk.yellow('/synspec:
|
|
31
|
-
` ${chalk.yellow('/synspec:
|
|
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
|
-
|
|
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
|
|
40
|
+
// Pad the art column to fixed width
|
|
49
41
|
const paddedArt = artLine.padEnd(ART_COLUMN_WIDTH);
|
|
50
|
-
// Color the
|
|
51
|
-
const coloredArt =
|
|
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
|
|
123
|
-
const frame = WELCOME_ANIMATION.frames[
|
|
124
|
-
process.stdout.write('\n' + renderFrame(frame, textLines
|
|
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
|
|
148
|
-
|
|
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,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GA selection step for the online self-evolution outer loop.
|
|
3
|
-
*
|
|
4
|
-
* When several candidate template-variants compete to evolve the SAME canonical
|
|
5
|
-
* target (e.g. two proposed edits to `artifact-template:design`), the genetic
|
|
6
|
-
* algorithm must rank them by ACCUMULATED real-usage fitness and pick winners.
|
|
7
|
-
* "Fitness" here is the retrospective outcome data each candidate accrues in its
|
|
8
|
-
* `fitness-record.jsonl` sidecar (see {@link readCandidateFitness}): one sample
|
|
9
|
-
* per real change the candidate was active for.
|
|
10
|
-
*
|
|
11
|
-
* Ranking convention (best-first):
|
|
12
|
-
* 1. Lower meanLoss is better. A candidate with no records (count === 0, hence
|
|
13
|
-
* meanLoss === null) is UNPROVEN and sorts LAST regardless of pass rate.
|
|
14
|
-
* 2. Tie-break by higher meanPassRate.
|
|
15
|
-
* 3. Then by higher count (more evidence behind the same loss/pass numbers).
|
|
16
|
-
* 4. Finally by candidateId (lexicographic) so the order is fully
|
|
17
|
-
* deterministic even when every fitness signal ties.
|
|
18
|
-
*
|
|
19
|
-
* Pure-ish: the only I/O is reading each candidate's fitness sidecar (and, for
|
|
20
|
-
* {@link groupCandidatesByTarget}, enumerating candidate dirs) via the supplied
|
|
21
|
-
* {@link CandidateRepoLayout}. No timestamps, no randomness.
|
|
22
|
-
*/
|
|
23
|
-
import { type CandidateRepoLayout } from './candidates.js';
|
|
24
|
-
/**
|
|
25
|
-
* One row of a per-target candidate ranking. `meanLoss`/`meanPassRate` are
|
|
26
|
-
* `null` for an unproven candidate (no accumulated fitness records yet).
|
|
27
|
-
*/
|
|
28
|
-
export interface RankedCandidate {
|
|
29
|
-
candidateId: string;
|
|
30
|
-
/**
|
|
31
|
-
* The canonical target this ranking row is about. Populated by
|
|
32
|
-
* {@link groupCandidatesByTarget}-driven flows; the plain
|
|
33
|
-
* {@link rankCandidatesForTarget} entry point leaves it as `''` because it
|
|
34
|
-
* ranks an explicit candidate list without re-reading their `targetIds`.
|
|
35
|
-
*/
|
|
36
|
-
targetId: string;
|
|
37
|
-
/** Accumulated mean loss in [0,1]; null when unproven. Lower is better. */
|
|
38
|
-
meanLoss: number | null;
|
|
39
|
-
/** Accumulated mean pass rate in [0,1]; null when unproven. Higher is better. */
|
|
40
|
-
meanPassRate: number | null;
|
|
41
|
-
/** Number of accumulated fitness records (evidence count). */
|
|
42
|
-
count: number;
|
|
43
|
-
/** Loss trend from the fitness sidecar: improving | stable | declining | unknown. */
|
|
44
|
-
trend: string;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Read each candidate's accumulated fitness and return the candidates sorted
|
|
48
|
-
* BEST-FIRST (see module doc for the full key order). Deterministic.
|
|
49
|
-
*
|
|
50
|
-
* @param layout Resolved candidate-repo layout (file I/O happens through it).
|
|
51
|
-
* @param candidateIds The competing candidate ids to rank. Duplicates are
|
|
52
|
-
* de-duplicated (first occurrence wins) so the same id is
|
|
53
|
-
* never read twice.
|
|
54
|
-
* @param targetId Optional canonical target id to stamp onto each row.
|
|
55
|
-
*/
|
|
56
|
-
export declare function rankCandidatesForTarget(layout: CandidateRepoLayout, candidateIds: string[], targetId?: string): Promise<RankedCandidate[]>;
|
|
57
|
-
/**
|
|
58
|
-
* Convenience: the single best candidate for a target, or `null` when the
|
|
59
|
-
* candidate list is empty.
|
|
60
|
-
*/
|
|
61
|
-
export declare function selectBestCandidate(layout: CandidateRepoLayout, candidateIds: string[], targetId?: string): Promise<RankedCandidate | null>;
|
|
62
|
-
/**
|
|
63
|
-
* Enumerate every candidate in the repo (via {@link listCandidates}) and group
|
|
64
|
-
* their ids by the canonical target id they intend to touch. A candidate that
|
|
65
|
-
* declares multiple `targetIds` appears under each of them.
|
|
66
|
-
*
|
|
67
|
-
* The candidateId arrays are sorted lexicographically for determinism. Returns
|
|
68
|
-
* an empty map when there are no candidates (or the base dir does not exist —
|
|
69
|
-
* {@link listCandidates} handles that case).
|
|
70
|
-
*/
|
|
71
|
-
export declare function groupCandidatesByTarget(layout: CandidateRepoLayout): Promise<Map<string, string[]>>;
|
|
72
|
-
/**
|
|
73
|
-
* The accumulated baseline reading for a target's de-facto canonical variant:
|
|
74
|
-
* the promoted candidate whose fitness sidecar supplies the baseline loss.
|
|
75
|
-
*/
|
|
76
|
-
export interface PromotedBaseline {
|
|
77
|
-
candidateId: string;
|
|
78
|
-
meanLoss: number;
|
|
79
|
-
/** createdAt of the baseline candidate (for reporting). */
|
|
80
|
-
recordedAt: string;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* The de-facto canonical baseline loss for a target: the accumulated mean loss
|
|
84
|
-
* of the MOST RECENTLY promoted candidate that has measured fitness. Returns
|
|
85
|
-
* null when no promoted candidate for the target has a non-null meanLoss (⇒
|
|
86
|
-
* downstream gates/trajectory cannot use a baseline). Rolled-back candidates are
|
|
87
|
-
* excluded automatically (they are status 'rolled-back', not 'promoted').
|
|
88
|
-
*
|
|
89
|
-
* `listCandidates` already returns promoted candidates sorted by `createdAt`
|
|
90
|
-
* DESCENDING (ties by id), so the first proven candidate in iteration order is
|
|
91
|
-
* the most recently promoted one with fitness.
|
|
92
|
-
*/
|
|
93
|
-
export declare function readPromotedBaselineLoss(layout: CandidateRepoLayout, targetId: string): Promise<PromotedBaseline | null>;
|
|
94
|
-
//# sourceMappingURL=ga-selection.d.ts.map
|