analyzthis_design 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HOW-TO-USE.md +26 -8
- package/README.md +48 -4
- package/agents/cards/anuj.md +13 -0
- package/agents/cards/arjun.md +13 -0
- package/agents/cards/devi.md +22 -0
- package/agents/cards/kavi.md +13 -0
- package/agents/cards/meera.md +13 -0
- package/agents/cards/noor.md +13 -0
- package/agents/cards/priya.md +13 -0
- package/agents/cards/raj.md +13 -0
- package/agents/cards/zara.md +13 -0
- package/dist/HOW-TO-USE.md +26 -8
- package/dist/README.md +48 -4
- package/dist/agents/cards/anuj.md +13 -0
- package/dist/agents/cards/arjun.md +13 -0
- package/dist/agents/cards/devi.md +22 -0
- package/dist/agents/cards/kavi.md +13 -0
- package/dist/agents/cards/meera.md +13 -0
- package/dist/agents/cards/noor.md +13 -0
- package/dist/agents/cards/priya.md +13 -0
- package/dist/agents/cards/raj.md +13 -0
- package/dist/agents/cards/zara.md +13 -0
- package/dist/bin/cli.js +184 -0
- package/dist/lib/accept.js +108 -0
- package/dist/lib/evolution-metrics.js +303 -87
- package/dist/lib/evolve.js +5 -2
- package/dist/lib/feedback-submit.js +99 -17
- package/dist/lib/host-llm.js +16 -0
- package/dist/lib/install.js +7 -0
- package/dist/lib/lessons.js +48 -5
- package/dist/lib/mcp-server.js +90 -11
- package/dist/lib/receipt.js +102 -0
- package/dist/lib/session.js +52 -1
- package/dist/lib/share.js +131 -0
- package/dist/skills/accept/SKILL.md +64 -0
- package/dist/skills/devi/SKILL.md +22 -0
- package/dist/skills/evolve-check/SKILL.md +29 -13
- package/dist/skills/getting-started/SKILL.md +3 -0
- package/dist/skills/share/SKILL.md +54 -0
- package/package.json +6 -2
- package/scripts/validate-csvs.js +20 -0
- package/skills/accept/SKILL.md +64 -0
- package/skills/devi/SKILL.md +22 -0
- package/skills/evolve-check/SKILL.md +29 -13
- package/skills/getting-started/SKILL.md +3 -0
- package/skills/share/SKILL.md +54 -0
package/dist/bin/cli.js
CHANGED
|
@@ -60,6 +60,10 @@ Usage:
|
|
|
60
60
|
session accept Mark a persona's last output accepted, for training export
|
|
61
61
|
(--persona <id>, optional --reject to unmark)
|
|
62
62
|
Optional feedback: --comment, --correction, --rating 1-5, --tags a,b
|
|
63
|
+
accept Designer keep / skip (same as /accept). --keep or --fix
|
|
64
|
+
Optional: --persona, --because "one sentence", --liked (keep, not shipped)
|
|
65
|
+
share Designer send-to-package (same as /share). Preview, then --send
|
|
66
|
+
Optional: --because "one sentence", --persona
|
|
63
67
|
|
|
64
68
|
── Persona feedback commands ─────────────────────────────────
|
|
65
69
|
feedback record Record unhappiness or a correction for a persona output
|
|
@@ -220,6 +224,10 @@ Usage:
|
|
|
220
224
|
npx analyzthis_design devi respond --run ~/.analyzthis_design/runs/... --step 001-arjun --file out.md
|
|
221
225
|
npx analyzthis_design run-unchunked --task "Review this screen" --provider anthropic
|
|
222
226
|
|
|
227
|
+
npx analyzthis_design accept --keep --persona zara
|
|
228
|
+
npx analyzthis_design accept --fix --persona zara --because "too much motion on the table"
|
|
229
|
+
npx analyzthis_design share
|
|
230
|
+
npx analyzthis_design share --send
|
|
223
231
|
npx analyzthis_design session accept --persona arjun
|
|
224
232
|
npx analyzthis_design session accept --persona arjun --reject \\
|
|
225
233
|
--comment "Invented tokens not in our DS" \\
|
|
@@ -322,6 +330,11 @@ const budgetVal = getFlag('budget');
|
|
|
322
330
|
const sequentialFlag = flags.includes('--sequential');
|
|
323
331
|
const maxChunksVal = getFlag('max-chunks');
|
|
324
332
|
const unchunkedFlag = flags.includes('--unchunked');
|
|
333
|
+
const keepFlag = flags.includes('--keep');
|
|
334
|
+
const fixFlag = flags.includes('--fix') || flags.includes('--no');
|
|
335
|
+
const likedFlag = flags.includes('--liked');
|
|
336
|
+
const becauseVal = getFlag('because');
|
|
337
|
+
const sendFlag = flags.includes('--send');
|
|
325
338
|
|
|
326
339
|
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
327
340
|
|
|
@@ -987,12 +1000,183 @@ switch (cmd) {
|
|
|
987
1000
|
break;
|
|
988
1001
|
}
|
|
989
1002
|
|
|
1003
|
+
case 'scores': {
|
|
1004
|
+
const em = require('../lib/evolution-metrics');
|
|
1005
|
+
if (flags.includes('--submit') || flags.includes('--submit-dry-run')) {
|
|
1006
|
+
const submitter = require('../lib/feedback-submit');
|
|
1007
|
+
const dry = flags.includes('--submit-dry-run');
|
|
1008
|
+
submitter.submitScores({ dryRun: dry })
|
|
1009
|
+
.then((r) => {
|
|
1010
|
+
if (r.skipped) console.log(`\n Not sent: ${r.skipped}\n`);
|
|
1011
|
+
else if (r.dryRun) console.log(`\n Would send ${r.rows.length} persona score row(s). Counts only — no note text.\n`);
|
|
1012
|
+
else console.log(`\n Sent ${r.sent} persona score row(s).\n`);
|
|
1013
|
+
})
|
|
1014
|
+
.catch((e) => console.log(`\n Submit failed: ${e.message}\n`));
|
|
1015
|
+
break;
|
|
1016
|
+
}
|
|
1017
|
+
const metrics = em.computeEvolutionMetrics(projectVal ? { project: projectVal } : undefined);
|
|
1018
|
+
if (personaVal) {
|
|
1019
|
+
const m = metrics.personas[personaVal];
|
|
1020
|
+
if (!m) {
|
|
1021
|
+
console.log(`\n Unknown persona "${personaVal}". Use: ${em.PERSONAS.join(', ')}\n`);
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
console.log(`\n ${personaVal}: ${m.score}/100 ${m.level}` +
|
|
1025
|
+
(m.sufficient_evidence ? '' : ' (insufficient evidence)'));
|
|
1026
|
+
console.log(` ${m.evidence_count} signal(s) · shipped ${m.outcome_breakdown.shipped}` +
|
|
1027
|
+
` · revised ${m.outcome_breakdown.revised} · missed ${m.outcome_breakdown.missed}` +
|
|
1028
|
+
(m.avg_rating != null ? ` · avg rating ${m.avg_rating}` : ''));
|
|
1029
|
+
console.log(` contributions: ${JSON.stringify(m.contributions)}\n`);
|
|
1030
|
+
break;
|
|
1031
|
+
}
|
|
1032
|
+
console.log('\n' + em.formatEvolutionSummary(metrics));
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
case 'system-prompt': {
|
|
1037
|
+
// The only path into the personas for browser-only tools (Lovable, v0, Bolt,
|
|
1038
|
+
// Replit, ChatGPT). They cannot reach the MCP server — it speaks stdio, and a
|
|
1039
|
+
// cloud-hosted tool cannot spawn a process on the user's machine.
|
|
1040
|
+
const builder = require('../lib/system-prompt');
|
|
1041
|
+
const mode = getFlag('mode') || 'both';
|
|
1042
|
+
if (!['create', 'critique', 'both'].includes(mode)) {
|
|
1043
|
+
console.log(`\n Unknown mode "${mode}". Use: create, critique, or both.\n`);
|
|
1044
|
+
break;
|
|
1045
|
+
}
|
|
1046
|
+
const prompt = builder.buildPrompt({ mode });
|
|
1047
|
+
const out = getFlag('out');
|
|
1048
|
+
if (out) {
|
|
1049
|
+
require('fs').writeFileSync(out, prompt);
|
|
1050
|
+
console.log(`\n Wrote ${prompt.length} chars to ${out}\n Paste it into your tool's system instructions.\n`);
|
|
1051
|
+
} else {
|
|
1052
|
+
console.log(prompt);
|
|
1053
|
+
}
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
990
1057
|
case 'receipt': {
|
|
991
1058
|
const receipt = require('../lib/receipt');
|
|
992
1059
|
console.log('\n' + receipt.report({ project: projectVal }) + '\n');
|
|
993
1060
|
break;
|
|
994
1061
|
}
|
|
995
1062
|
|
|
1063
|
+
case 'accept': {
|
|
1064
|
+
const accept = require('../lib/accept');
|
|
1065
|
+
const wantKeep = keepFlag || yesFlag;
|
|
1066
|
+
const wantFix = fixFlag;
|
|
1067
|
+
try {
|
|
1068
|
+
if (wantKeep && wantFix) {
|
|
1069
|
+
console.error('\n ✗ Use --keep or --fix, not both.\n');
|
|
1070
|
+
process.exit(1);
|
|
1071
|
+
}
|
|
1072
|
+
if (!wantKeep && !wantFix) {
|
|
1073
|
+
const peek = accept.preview({ project: projectVal });
|
|
1074
|
+
console.log('\n Keep the last note?');
|
|
1075
|
+
console.log(' Yes: npx analyzthis_design accept --keep' + (peek.persona ? ` --persona ${peek.persona}` : ''));
|
|
1076
|
+
console.log(' No: npx analyzthis_design accept --fix --because "one sentence"');
|
|
1077
|
+
if (peek.persona) console.log(` Last persona: ${peek.persona}`);
|
|
1078
|
+
else console.log(' Last persona: not sure — add --persona zara (or arjun, meera, …)');
|
|
1079
|
+
console.log('');
|
|
1080
|
+
break;
|
|
1081
|
+
}
|
|
1082
|
+
if (wantKeep) {
|
|
1083
|
+
const result = accept.keep({
|
|
1084
|
+
project: projectVal,
|
|
1085
|
+
persona: personaVal,
|
|
1086
|
+
comment: commentVal || becauseVal || '',
|
|
1087
|
+
shipped: !likedFlag,
|
|
1088
|
+
note: commentVal || '',
|
|
1089
|
+
});
|
|
1090
|
+
console.log(`\n✅ Kept ${result.persona}'s note.` + (result.shipped ? ' Marked as shipped for evolution.' : ' Saved as liked (not shipped).') + '\n');
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
const result = accept.fix({
|
|
1094
|
+
project: projectVal,
|
|
1095
|
+
persona: personaVal,
|
|
1096
|
+
because: becauseVal || commentVal || '',
|
|
1097
|
+
correction: correctionVal || '',
|
|
1098
|
+
rating: ratingVal,
|
|
1099
|
+
tags: parseFeedbackTags(tagsVal),
|
|
1100
|
+
});
|
|
1101
|
+
console.log(`\n✅ Logged your fix for ${result.persona}. The team can learn from it.\n`);
|
|
1102
|
+
} catch (err) {
|
|
1103
|
+
if (err.code === 'NEED_PERSONA') {
|
|
1104
|
+
console.error('\n ✗ Which note? Add --persona zara (or arjun, meera, priya, noor, anuj, raj).\n');
|
|
1105
|
+
process.exit(1);
|
|
1106
|
+
}
|
|
1107
|
+
if (err.code === 'NEED_BECAUSE') {
|
|
1108
|
+
console.error('\n ✗ Add one sentence: --because "what was wrong or what you did instead"\n');
|
|
1109
|
+
process.exit(1);
|
|
1110
|
+
}
|
|
1111
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
1112
|
+
process.exit(1);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
break;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
case 'share': {
|
|
1119
|
+
const share = require('../lib/share');
|
|
1120
|
+
const acceptMod = require('../lib/accept');
|
|
1121
|
+
const wantSend = sendFlag || yesFlag;
|
|
1122
|
+
(async () => {
|
|
1123
|
+
try {
|
|
1124
|
+
if (!wantSend) {
|
|
1125
|
+
if (becauseVal || commentVal) {
|
|
1126
|
+
acceptMod.fix({
|
|
1127
|
+
project: projectVal,
|
|
1128
|
+
persona: personaVal,
|
|
1129
|
+
because: becauseVal || commentVal,
|
|
1130
|
+
correction: correctionVal || becauseVal || commentVal,
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
const peek = share.preview({ project: projectVal, persona: personaVal, all: allFlag });
|
|
1134
|
+
if (!peek.count) {
|
|
1135
|
+
console.log('\n Nothing to send yet. After a critique: /accept no plus one sentence, then /share.\n');
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
console.log(`\n Ready to send ${peek.count} note(s) to the package (redacted — no folders, emails, or keys).`);
|
|
1139
|
+
peek.rows.slice(0, 5).forEach((r) => {
|
|
1140
|
+
console.log(` • ${r.persona}: ${(r.comment || r.correction || '').slice(0, 100)}`);
|
|
1141
|
+
});
|
|
1142
|
+
if (peek.rows.length > 5) console.log(` … and ${peek.rows.length - 5} more`);
|
|
1143
|
+
console.log(peek.hasHttp ? ' Path: configured HTTP endpoint.' : ' Path: GitHub issue on joshirishi/analyzthis_design.');
|
|
1144
|
+
console.log(' Send? Run: npx analyzthis_design share --send\n');
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
const result = await share.send({
|
|
1148
|
+
project: projectVal,
|
|
1149
|
+
persona: personaVal,
|
|
1150
|
+
because: becauseVal || commentVal || '',
|
|
1151
|
+
correction: correctionVal || '',
|
|
1152
|
+
all: allFlag,
|
|
1153
|
+
});
|
|
1154
|
+
if (result.via === 'github-link') {
|
|
1155
|
+
console.log(`\n ${result.message}`);
|
|
1156
|
+
console.log(` ${result.url}\n`);
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
console.log(`\n✅ ${result.message}` + (result.url ? `\n ${result.url}` : '') + '\n');
|
|
1160
|
+
} catch (err) {
|
|
1161
|
+
if (err.code === 'NOTHING') {
|
|
1162
|
+
console.error('\n ✗ Nothing to send yet. /accept no plus one sentence, then /share.\n');
|
|
1163
|
+
process.exit(1);
|
|
1164
|
+
}
|
|
1165
|
+
if (err.code === 'NEED_PERSONA') {
|
|
1166
|
+
console.error('\n ✗ Which note? Add --persona zara (or arjun, meera, priya, noor, anuj, raj).\n');
|
|
1167
|
+
process.exit(1);
|
|
1168
|
+
}
|
|
1169
|
+
if (err.code === 'NEED_BECAUSE') {
|
|
1170
|
+
console.error('\n ✗ Add one sentence: --because "what was wrong or what you did instead"\n');
|
|
1171
|
+
process.exit(1);
|
|
1172
|
+
}
|
|
1173
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
1174
|
+
process.exit(1);
|
|
1175
|
+
}
|
|
1176
|
+
})();
|
|
1177
|
+
break;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
996
1180
|
// ── Persona feedback (v1.16) ────────────────────────────────────────────
|
|
997
1181
|
|
|
998
1182
|
case 'feedback': {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Designer keep / skip for evolution.
|
|
5
|
+
* Slash /accept talks in yes/no. This module writes the session flags.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
var session = require('./session');
|
|
9
|
+
var feedback = require('./feedback');
|
|
10
|
+
var outcome = require('./outcome');
|
|
11
|
+
var lessons = require('./lessons');
|
|
12
|
+
|
|
13
|
+
var PERSONA_IDS = session.PERSONA_IDS;
|
|
14
|
+
|
|
15
|
+
function resolvePersona(opts) {
|
|
16
|
+
var raw = String(opts.persona || '').toLowerCase().trim();
|
|
17
|
+
if (raw && PERSONA_IDS.indexOf(raw) === -1) {
|
|
18
|
+
var err = new Error('Unknown persona. Use: ' + PERSONA_IDS.join(', '));
|
|
19
|
+
err.code = 'BAD_PERSONA';
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
var id = raw || session.inferLastPersona({ project: opts.project });
|
|
23
|
+
if (!id) {
|
|
24
|
+
var need = new Error('NEED_PERSONA');
|
|
25
|
+
need.code = 'NEED_PERSONA';
|
|
26
|
+
throw need;
|
|
27
|
+
}
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Lesson extraction must never break a designer's keep/skip.
|
|
32
|
+
function safeExtract(project, persona) {
|
|
33
|
+
try {
|
|
34
|
+
var r = lessons.extractLessons({ project: project, persona: persona });
|
|
35
|
+
return (r && r.extracted) || 0;
|
|
36
|
+
} catch (e) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function keep(opts) {
|
|
42
|
+
opts = opts || {};
|
|
43
|
+
var persona = resolvePersona(opts);
|
|
44
|
+
session.ensurePersonaOutput({
|
|
45
|
+
project: opts.project,
|
|
46
|
+
persona: persona,
|
|
47
|
+
text: opts.note,
|
|
48
|
+
});
|
|
49
|
+
session.markAccepted({ project: opts.project, persona: persona, accepted: true });
|
|
50
|
+
// Always record — a bare "/accept yes" is still a rating, and scoring reads it.
|
|
51
|
+
feedback.recordFeedback({
|
|
52
|
+
project: opts.project,
|
|
53
|
+
persona: persona,
|
|
54
|
+
satisfied: true,
|
|
55
|
+
rating: opts.rating != null ? Number(opts.rating) : 5,
|
|
56
|
+
comment: opts.comment || '',
|
|
57
|
+
correction: '',
|
|
58
|
+
tags: ['positive'],
|
|
59
|
+
markRejected: false,
|
|
60
|
+
});
|
|
61
|
+
var shipped = opts.shipped !== false;
|
|
62
|
+
if (shipped) {
|
|
63
|
+
outcome.confirmOutcome({ project: opts.project, persona: persona, outcome: 'shipped' });
|
|
64
|
+
}
|
|
65
|
+
var learned = safeExtract(opts.project, persona);
|
|
66
|
+
return { persona: persona, kept: true, shipped: shipped, lessons: learned };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function fix(opts) {
|
|
70
|
+
opts = opts || {};
|
|
71
|
+
var persona = resolvePersona(opts);
|
|
72
|
+
var because = String(opts.because || opts.comment || '').trim();
|
|
73
|
+
var correction = String(opts.correction || because).trim();
|
|
74
|
+
if (!because) {
|
|
75
|
+
var need = new Error('NEED_BECAUSE');
|
|
76
|
+
need.code = 'NEED_BECAUSE';
|
|
77
|
+
throw need;
|
|
78
|
+
}
|
|
79
|
+
session.ensurePersonaOutput({
|
|
80
|
+
project: opts.project,
|
|
81
|
+
persona: persona,
|
|
82
|
+
text: opts.note,
|
|
83
|
+
});
|
|
84
|
+
feedback.recordFeedback({
|
|
85
|
+
project: opts.project,
|
|
86
|
+
persona: persona,
|
|
87
|
+
satisfied: false,
|
|
88
|
+
rating: opts.rating != null ? Number(opts.rating) : 2,
|
|
89
|
+
comment: because,
|
|
90
|
+
correction: correction,
|
|
91
|
+
tags: opts.tags || ['other'],
|
|
92
|
+
markRejected: true,
|
|
93
|
+
});
|
|
94
|
+
outcome.confirmOutcome({ project: opts.project, persona: persona, outcome: 'revised' });
|
|
95
|
+
var learnedFix = safeExtract(opts.project, persona);
|
|
96
|
+
return { persona: persona, kept: false, because: because, lessons: learnedFix };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function preview(opts) {
|
|
100
|
+
opts = opts || {};
|
|
101
|
+
var state = session.show({ project: opts.project });
|
|
102
|
+
return {
|
|
103
|
+
persona: session.inferLastPersona({ project: opts.project }),
|
|
104
|
+
hasSession: !!state,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = { keep, fix, preview, PERSONA_IDS };
|