analyzthis_design 2.0.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/HOW-TO-USE.md +436 -0
- package/README.md +29 -13
- package/agents/cards/evolve-check.md +38 -0
- package/agents/manifests/evolve-check.json +16 -0
- package/dist/HOW-TO-USE.md +15 -3
- package/dist/README.md +29 -13
- package/dist/agents/cards/evolve-check.md +38 -0
- package/dist/agents/manifests/evolve-check.json +16 -0
- package/dist/bin/cli.js +1225 -1
- package/dist/lib/cache.js +111 -1
- package/dist/lib/chunk-executor.js +219 -1
- package/dist/lib/chunk-models.js +228 -1
- package/dist/lib/chunk-planner.js +328 -1
- package/dist/lib/chunk-router.js +66 -1
- package/dist/lib/chunk-run.js +199 -1
- package/dist/lib/chunk-synthesis.js +176 -1
- package/dist/lib/chunk-telemetry.js +88 -1
- package/dist/lib/collect.js +858 -1
- package/dist/lib/cost.js +119 -1
- package/dist/lib/dedup.js +167 -1
- package/dist/lib/deliberation.js +721 -1
- package/dist/lib/design-spec.js +236 -1
- package/dist/lib/evolution-metrics.js +197 -0
- package/dist/lib/evolve.js +361 -1
- package/dist/lib/export.js +77 -1
- package/dist/lib/feedback-submit.js +324 -1
- package/dist/lib/feedback.js +182 -1
- package/dist/lib/host-llm.js +251 -1
- package/dist/lib/install.js +301 -1
- package/dist/lib/knowledge.js +384 -1
- package/dist/lib/lessons.js +217 -1
- package/dist/lib/moodboard.js +563 -1
- package/dist/lib/orchestrator/run.js +935 -1
- package/dist/lib/outcome.js +193 -1
- package/dist/lib/platforms.js +166 -1
- package/dist/lib/provider.js +57 -1
- package/dist/lib/query-expander.js +83 -1
- package/dist/lib/ranker.js +105 -1
- package/dist/lib/reference-pack.js +221 -0
- package/dist/lib/research.js +143 -1
- package/dist/lib/retrieve.js +131 -1
- package/dist/lib/session.js +185 -1
- package/dist/lib/source-discovery.js +486 -1
- package/dist/lib/synthesis.js +155 -1
- package/dist/lib/token-gate.js +46 -1
- package/dist/skills/design-reference/google-fonts.csv +1924 -1924
- package/dist/skills/design-reference/products.csv +162 -162
- package/dist/skills/design-reference/schema.json +159 -0
- package/dist/skills/design-reference/stacks/angular.csv +1 -1
- package/dist/skills/design-reference/stacks/astro.csv +1 -1
- package/dist/skills/design-reference/stacks/laravel.csv +2 -2
- package/dist/skills/design-reference/stacks/threejs.csv +54 -54
- package/dist/skills/design-reference/styles.csv +85 -85
- package/dist/skills/design-reference/typography.csv +75 -74
- package/dist/skills/design-reference/ui-reasoning.csv +1 -1
- package/dist/skills/evolve-check/SKILL.md +106 -0
- package/package.json +8 -8
- package/scripts/validate-csvs.js +197 -0
- package/skills/design-reference/google-fonts.csv +1924 -1924
- package/skills/design-reference/products.csv +162 -162
- package/skills/design-reference/schema.json +159 -0
- package/skills/design-reference/stacks/angular.csv +1 -1
- package/skills/design-reference/stacks/astro.csv +1 -1
- package/skills/design-reference/stacks/laravel.csv +2 -2
- package/skills/design-reference/stacks/threejs.csv +54 -54
- package/skills/design-reference/styles.csv +85 -85
- package/skills/design-reference/typography.csv +75 -74
- package/skills/design-reference/ui-reasoning.csv +1 -1
- package/skills/evolve-check/SKILL.md +106 -0
|
@@ -1 +1,176 @@
|
|
|
1
|
-
'use strict';
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chunk synthesis (v2.0).
|
|
5
|
+
*
|
|
6
|
+
* Merges chunk outputs into a final verdict. Uses the cheapest capable model
|
|
7
|
+
* from the chunk pool. Escalates to the planner-tier model if outputs
|
|
8
|
+
* contradict or if chunk success rate is low.
|
|
9
|
+
*
|
|
10
|
+
* CommonJS, 'use strict', var.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
var chunkModels = require('./chunk-models');
|
|
14
|
+
var chunkRouter = require('./chunk-router');
|
|
15
|
+
var synthesis = require('./synthesis');
|
|
16
|
+
|
|
17
|
+
function buildSynthesisPrompt(plan, results, contextPack) {
|
|
18
|
+
var lines = [
|
|
19
|
+
'You are the synthesis engine. Merge the following persona chunk outputs into a final verdict.',
|
|
20
|
+
'',
|
|
21
|
+
'Task: ' + (contextPack.task || plan.task_summary || ''),
|
|
22
|
+
'',
|
|
23
|
+
'Chunk outputs:',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
for (var i = 0; i < results.length; i++) {
|
|
27
|
+
var r = results[i];
|
|
28
|
+
lines.push('--- ' + r.chunk_id + ' (' + r.persona + ') ---');
|
|
29
|
+
lines.push(r.output.slice(0, 1200));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
lines.push('',
|
|
33
|
+
'Produce:',
|
|
34
|
+
'- Verdict: SHIP | REVISE | BLOCK',
|
|
35
|
+
'- Composite score out of 5 if applicable',
|
|
36
|
+
'- Top 3 actionable changes',
|
|
37
|
+
'- Brief reasoning',
|
|
38
|
+
'',
|
|
39
|
+
'Use the same format as the design-critic synthesis.'
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
system: 'You synthesize multi-persona design critique outputs. Be concise and cite the most important conflicts.',
|
|
44
|
+
user: lines.join('\n'),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function hasContradictions(results) {
|
|
49
|
+
var verdicts = [];
|
|
50
|
+
for (var i = 0; i < results.length; i++) {
|
|
51
|
+
var v = results[i].structured_output && results[i].structured_output.verdict;
|
|
52
|
+
if (v) verdicts.push(v);
|
|
53
|
+
}
|
|
54
|
+
if (verdicts.length < 2) return false;
|
|
55
|
+
var allSame = verdicts.every(function(v) { return v === verdicts[0]; });
|
|
56
|
+
return !allSame;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function synthesize(opts) {
|
|
60
|
+
opts = opts || {};
|
|
61
|
+
var plan = opts.plan;
|
|
62
|
+
var results = opts.results || [];
|
|
63
|
+
var contextPack = opts.contextPack;
|
|
64
|
+
var config = opts.config || chunkModels.loadConfig();
|
|
65
|
+
var budget = opts.budget || 'auto';
|
|
66
|
+
var callLlmFn = opts.callLlmFn;
|
|
67
|
+
|
|
68
|
+
if (!callLlmFn) {
|
|
69
|
+
var orchestrator = require('./orchestrator/run');
|
|
70
|
+
callLlmFn = orchestrator.callLlm;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
var successful = results.filter(function(r) { return r.success; });
|
|
74
|
+
if (!successful.length) {
|
|
75
|
+
return {
|
|
76
|
+
verdict: 'BLOCK',
|
|
77
|
+
total: 0,
|
|
78
|
+
max_total: 0,
|
|
79
|
+
top3: [{ change: 'All chunk models failed', owner: 'user', reason: 'No model produced output' }],
|
|
80
|
+
composite: { verdict: 'BLOCK', total: 0, max_total: 0, top3: [] },
|
|
81
|
+
markdown: '## Synthesis\n\nAll chunk models failed. No verdict possible.',
|
|
82
|
+
model_used: null,
|
|
83
|
+
contradictions: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
var contradictions = hasContradictions(successful);
|
|
88
|
+
var synChunk = plan.synthesis || { persona: 'raj', goal: 'resolve conflicts', system_prompt: '', user_prompt: '' };
|
|
89
|
+
|
|
90
|
+
// Try cheap synthesis first.
|
|
91
|
+
var prompts = buildSynthesisPrompt(plan, successful, contextPack);
|
|
92
|
+
var model;
|
|
93
|
+
try {
|
|
94
|
+
var resolved = await chunkRouter.resolveChunkModel({
|
|
95
|
+
effort: 'hard',
|
|
96
|
+
chunkType: 'synthesis',
|
|
97
|
+
budget: budget,
|
|
98
|
+
config: config,
|
|
99
|
+
});
|
|
100
|
+
model = resolved.selected;
|
|
101
|
+
} catch (e) {
|
|
102
|
+
// Fall back to planner-tier.
|
|
103
|
+
model = chunkModels.resolvePlannerModel(config);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (contradictions) {
|
|
107
|
+
// Escalate to planner-tier for arbitration.
|
|
108
|
+
model = chunkModels.resolvePlannerModel(config);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var text = '';
|
|
112
|
+
try {
|
|
113
|
+
text = await callLlmFn({
|
|
114
|
+
provider: model.provider,
|
|
115
|
+
model: model.model,
|
|
116
|
+
system: prompts.system,
|
|
117
|
+
user: prompts.user,
|
|
118
|
+
maxTokens: 1800,
|
|
119
|
+
personaId: synChunk.persona || 'raj',
|
|
120
|
+
});
|
|
121
|
+
} catch (e) {
|
|
122
|
+
// Last-resort: try to use the existing synthesis module on raw text.
|
|
123
|
+
return fallbackSynthesis(successful);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
var inTok = Math.ceil((prompts.system.length + prompts.user.length) / 4);
|
|
127
|
+
var outTok = Math.ceil(text.length / 4);
|
|
128
|
+
|
|
129
|
+
var syn = synthesis.buildSynthesis ? synthesis.buildSynthesis(successful) : null;
|
|
130
|
+
if (!syn) syn = fallbackSynthesis(successful);
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
verdict: syn.composite.verdict || 'REVISE',
|
|
134
|
+
total: syn.composite.total || 0,
|
|
135
|
+
max_total: syn.composite.max_total || 0,
|
|
136
|
+
top3: syn.composite.top3 || [],
|
|
137
|
+
composite: syn.composite,
|
|
138
|
+
markdown: syn.markdown || text,
|
|
139
|
+
model_used: { provider: model.provider, model: model.model, cost: model.cost },
|
|
140
|
+
contradictions: contradictions,
|
|
141
|
+
tokens: { input: inTok, output: outTok },
|
|
142
|
+
cost: chunkModels.estimateCost(model, inTok, outTok),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function fallbackSynthesis(results) {
|
|
147
|
+
var lines = ['## Synthesis\n'];
|
|
148
|
+
var verdict = 'REVISE';
|
|
149
|
+
var score = 0;
|
|
150
|
+
var count = 0;
|
|
151
|
+
for (var i = 0; i < results.length; i++) {
|
|
152
|
+
var r = results[i];
|
|
153
|
+
lines.push('### ' + r.persona);
|
|
154
|
+
lines.push(r.output.slice(0, 500));
|
|
155
|
+
if (r.structured_output && r.structured_output.score) {
|
|
156
|
+
score += r.structured_output.score;
|
|
157
|
+
count++;
|
|
158
|
+
}
|
|
159
|
+
if (r.structured_output && r.structured_output.verdict) {
|
|
160
|
+
if (r.structured_output.verdict === 'BLOCK') verdict = 'BLOCK';
|
|
161
|
+
else if (r.structured_output.verdict === 'REVISE' && verdict === 'SHIP') verdict = 'REVISE';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var avgScore = count ? (score / count) : 0;
|
|
165
|
+
lines.push('', '**Verdict:** ' + verdict, '**Score:** ' + avgScore.toFixed(1) + '/5');
|
|
166
|
+
return {
|
|
167
|
+
composite: { verdict: verdict, total: Math.round(avgScore), max_total: 5, top3: [] },
|
|
168
|
+
markdown: lines.join('\n'),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = {
|
|
173
|
+
synthesize: synthesize,
|
|
174
|
+
buildSynthesisPrompt: buildSynthesisPrompt,
|
|
175
|
+
hasContradictions: hasContradictions,
|
|
176
|
+
};
|
|
@@ -1 +1,88 @@
|
|
|
1
|
-
'use strict';
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chunk telemetry (v2.0).
|
|
5
|
+
*
|
|
6
|
+
* Records per-chunk model performance so the router can learn which
|
|
7
|
+
* model+persona combinations work best.
|
|
8
|
+
*
|
|
9
|
+
* CommonJS, 'use strict', var, try/catch around JSON.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
var fs = require('fs');
|
|
13
|
+
var path = require('path');
|
|
14
|
+
var os = require('os');
|
|
15
|
+
|
|
16
|
+
var TELEMETRY_FILE = path.join(os.homedir(), '.analyzthis_design', 'chunk-telemetry.jsonl');
|
|
17
|
+
var MAX_LINES = 10000;
|
|
18
|
+
|
|
19
|
+
function ensureDir() {
|
|
20
|
+
fs.mkdirSync(path.dirname(TELEMETRY_FILE), { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function loadLines() {
|
|
24
|
+
if (!fs.existsSync(TELEMETRY_FILE)) return [];
|
|
25
|
+
try {
|
|
26
|
+
var text = fs.readFileSync(TELEMETRY_FILE, 'utf8');
|
|
27
|
+
return text.trim().split('\n').filter(function(l) { return l.trim(); });
|
|
28
|
+
} catch (e) { return []; }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function append(record) {
|
|
32
|
+
ensureDir();
|
|
33
|
+
var line = JSON.stringify(record);
|
|
34
|
+
fs.appendFileSync(TELEMETRY_FILE, line + '\n');
|
|
35
|
+
|
|
36
|
+
// Simple rotation: if file gets too large, keep last half.
|
|
37
|
+
var lines = loadLines();
|
|
38
|
+
if (lines.length > MAX_LINES) {
|
|
39
|
+
var keep = lines.slice(Math.floor(MAX_LINES / 2));
|
|
40
|
+
fs.writeFileSync(TELEMETRY_FILE, keep.join('\n') + '\n');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function record(record) {
|
|
45
|
+
var r = Object.assign({
|
|
46
|
+
at: new Date().toISOString(),
|
|
47
|
+
}, record);
|
|
48
|
+
append(r);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getStatsForChunkType(chunkType) {
|
|
52
|
+
var lines = loadLines();
|
|
53
|
+
var byModel = {};
|
|
54
|
+
|
|
55
|
+
for (var i = 0; i < lines.length; i++) {
|
|
56
|
+
try {
|
|
57
|
+
var r = JSON.parse(lines[i]);
|
|
58
|
+
if (!r.model) continue;
|
|
59
|
+
var key = r.model;
|
|
60
|
+
if (!byModel[key]) byModel[key] = { model: key, attempts: 0, successful: 0, total_cost: 0 };
|
|
61
|
+
byModel[key].attempts++;
|
|
62
|
+
if (r.success) byModel[key].successful++;
|
|
63
|
+
byModel[key].total_cost += r.cost || 0;
|
|
64
|
+
} catch (e) { /* skip corrupt line */ }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return Object.keys(byModel).map(function(k) { return byModel[k]; });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getRecentFailures(limit) {
|
|
71
|
+
limit = limit || 20;
|
|
72
|
+
var lines = loadLines();
|
|
73
|
+
var failures = [];
|
|
74
|
+
for (var i = lines.length - 1; i >= 0 && failures.length < limit; i--) {
|
|
75
|
+
try {
|
|
76
|
+
var r = JSON.parse(lines[i]);
|
|
77
|
+
if (!r.success) failures.push(r);
|
|
78
|
+
} catch (e) { /* skip */ }
|
|
79
|
+
}
|
|
80
|
+
return failures;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
record: record,
|
|
85
|
+
getStatsForChunkType: getStatsForChunkType,
|
|
86
|
+
getRecentFailures: getRecentFailures,
|
|
87
|
+
TELEMETRY_FILE: TELEMETRY_FILE,
|
|
88
|
+
};
|