atris 3.35.0 → 3.36.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/AGENTS.md +37 -0
- package/README.md +5 -3
- package/atris/GETTING_STARTED.md +1 -1
- package/atris/atris.md +3 -0
- package/atris/policies/day-loop-voice.md +102 -0
- package/atris/policies/outbound-artifact-gate.md +2 -0
- package/atris/skills/design/SKILL.md +56 -32
- package/atris/skills/endgame/SKILL.md +12 -6
- package/atris/skills/engines/SKILL.md +22 -4
- package/atris/skills/fable-method/SKILL.md +66 -0
- package/atris/skills/improve/SKILL.md +65 -45
- package/atris/skills/youtube/SKILL.md +10 -1
- package/atris.md +2 -0
- package/ax +147 -19
- package/bin/atris.js +565 -265
- package/commands/activate.js +194 -88
- package/commands/agents.js +166 -0
- package/commands/autoland.js +459 -107
- package/commands/autopilot-front.js +20 -2
- package/commands/autopilot.js +118 -2
- package/commands/avail.js +407 -0
- package/commands/bench.js +188 -0
- package/commands/brain.js +3 -0
- package/commands/brief.js +651 -0
- package/commands/business-sync.js +192 -6
- package/commands/clean.js +50 -24
- package/commands/close.js +1083 -0
- package/commands/cloud.js +245 -0
- package/commands/compile.js +292 -1
- package/commands/computer.js +150 -3
- package/commands/dream.js +365 -0
- package/commands/drill.js +371 -0
- package/commands/engine.js +993 -32
- package/commands/experiments.js +28 -0
- package/commands/feedback.js +34 -12
- package/commands/fleet-report.js +206 -0
- package/commands/gm.js +23 -0
- package/commands/goal.js +247 -0
- package/commands/improve.js +642 -26
- package/commands/init.js +72 -44
- package/commands/interview.js +67 -1
- package/commands/land.js +152 -52
- package/commands/lifecycle.js +39 -3
- package/commands/log.js +84 -1
- package/commands/loops.js +220 -16
- package/commands/meet.js +220 -0
- package/commands/member.js +511 -34
- package/commands/mission.js +3029 -339
- package/commands/next.js +137 -0
- package/commands/now.js +220 -25
- package/commands/one-lap.js +776 -0
- package/commands/orb.js +314 -0
- package/commands/pack-craft.js +179 -0
- package/commands/pack.js +823 -0
- package/commands/play.js +3 -2
- package/commands/probe.js +30 -3
- package/commands/pulse.js +241 -46
- package/commands/push.js +260 -82
- package/commands/rainmaker.js +49 -0
- package/commands/report.js +415 -0
- package/commands/scout.js +147 -0
- package/commands/search.js +363 -0
- package/commands/skill.js +47 -3
- package/commands/slop.js +50 -2
- package/commands/soul.js +1 -1
- package/commands/stream.js +861 -0
- package/commands/study.js +693 -0
- package/commands/sync.js +67 -54
- package/commands/task.js +1346 -117
- package/commands/team.js +73 -0
- package/commands/verify.js +96 -0
- package/commands/watch.js +303 -0
- package/commands/wish.js +500 -0
- package/commands/workflow.js +11 -5
- package/commands/worktree.js +234 -13
- package/commands/xp.js +29 -11
- package/lib/auto-accept-certified.js +331 -34
- package/lib/autoland.js +319 -54
- package/lib/ax-auto-lane.js +79 -0
- package/lib/bench/context.js +147 -0
- package/lib/bench/engines.js +141 -0
- package/lib/bench/report.js +140 -0
- package/lib/bench/runner.js +512 -0
- package/lib/brief-ledger.js +350 -0
- package/lib/cloud-mission.js +259 -0
- package/lib/codex-flight.js +154 -0
- package/lib/default-runner.js +45 -0
- package/lib/default-verifier.js +70 -0
- package/lib/engine-registry.js +232 -0
- package/lib/experiments/daily.js +640 -0
- package/lib/fleet.js +2219 -67
- package/lib/improve-vitals-html.js +171 -0
- package/lib/known-commands.js +58 -0
- package/lib/loop-doctor.js +416 -0
- package/lib/member-switches.js +144 -0
- package/lib/mission-room.js +1 -0
- package/lib/mission-root.js +52 -0
- package/lib/next-moves.js +327 -10
- package/lib/one-lap-validator.js +60 -0
- package/lib/orb-context.js +477 -0
- package/lib/orb-scorecard.js +224 -0
- package/lib/policy-lessons.js +52 -1
- package/lib/pulse.js +277 -3
- package/lib/receipt-block.js +168 -0
- package/lib/receipt-evidence.js +65 -4
- package/lib/router-brain.js +352 -0
- package/lib/runner-command.js +10 -0
- package/lib/self-drive.js +258 -0
- package/lib/short-name.js +103 -0
- package/lib/spawn-env.js +18 -0
- package/lib/state-detection.js +56 -1
- package/lib/sync-status.js +59 -0
- package/lib/task-db.js +108 -29
- package/lib/task-proof.js +23 -1
- package/lib/team-presence.js +260 -0
- package/lib/tool-result-encode.js +7 -0
- package/lib/trust-tiers.js +90 -0
- package/lib/usage.js +107 -0
- package/lib/voice-gate.js +163 -0
- package/lib/wish-audit.js +1368 -0
- package/lib/wish-delegate.js +1840 -0
- package/lib/wish-design.js +110 -0
- package/lib/wish-stats.js +183 -0
- package/lib/wish-store.js +354 -0
- package/lib/zip.js +221 -0
- package/package.json +3 -1
- package/templates/loops/atris/loops/LOOPS.md +55 -0
- package/templates/loops/atris/loops/TICK.md +24 -0
- package/templates/loops/atris/loops/feedback.md +22 -0
- package/templates/loops/atris/loops/quality.md +22 -0
- package/templates/loops/atris/wiki/systems/loops.md +41 -0
- package/utils/api.js +5 -1
- package/utils/auth.js +57 -21
package/commands/wish.js
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
analyzeWishParts,
|
|
5
|
+
auditWish,
|
|
6
|
+
deriveVerifyPlan,
|
|
7
|
+
inferBudgetTier,
|
|
8
|
+
missingNamedInputs,
|
|
9
|
+
sharesMeaningfulWords,
|
|
10
|
+
verifyOutcomeText,
|
|
11
|
+
withWishAnswerAuditContext,
|
|
12
|
+
} = require('../lib/wish-audit');
|
|
13
|
+
const {
|
|
14
|
+
appendWishRecord,
|
|
15
|
+
improveWishes,
|
|
16
|
+
nextWishNumber,
|
|
17
|
+
readWishEvents,
|
|
18
|
+
readWishes,
|
|
19
|
+
stampIso,
|
|
20
|
+
stateFile,
|
|
21
|
+
wishLessonsSummary,
|
|
22
|
+
wishId,
|
|
23
|
+
} = require('../lib/wish-store');
|
|
24
|
+
const {
|
|
25
|
+
answerWish,
|
|
26
|
+
captureWishToJournal,
|
|
27
|
+
grantWish,
|
|
28
|
+
printBoard,
|
|
29
|
+
printList,
|
|
30
|
+
printReviewNudges,
|
|
31
|
+
printRewards,
|
|
32
|
+
reviewWish,
|
|
33
|
+
runAgainWish,
|
|
34
|
+
parseMetricExpression,
|
|
35
|
+
runCapturedWish,
|
|
36
|
+
sayWish,
|
|
37
|
+
sweepWishes,
|
|
38
|
+
waitingOperatorWishes,
|
|
39
|
+
REVIEW_WORD_SCORES,
|
|
40
|
+
} = require('../lib/wish-delegate');
|
|
41
|
+
const { enqueueCloudMission, VALID_CLOUD_LANES } = require('../lib/cloud-mission');
|
|
42
|
+
const { printWishStats } = require('../lib/wish-stats');
|
|
43
|
+
const { parseVerifyCommand } = require('../lib/auto-accept-certified');
|
|
44
|
+
|
|
45
|
+
function showHelp() {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log('Usage: atris wish "<plain sentence>" [--engine <id>] [--verify "<cmd>"] [--as builder] [--metric "<name><op><target>"] [--json] [--no-mission]');
|
|
48
|
+
console.log(' atris wish "<plain sentence>" --cloud [--lane fast|pro|max] [--agent <id>]');
|
|
49
|
+
console.log(' --metric example: --metric "stripe.active_subs>=10" (ops: >=, >, <=, <, ==)');
|
|
50
|
+
console.log(' atris wish list [--all]');
|
|
51
|
+
console.log(' atris wish show <n|id>');
|
|
52
|
+
console.log(' atris wish board');
|
|
53
|
+
console.log(' atris wish answer "<your answer>" [--engine <id>] [--json] [--no-mission]');
|
|
54
|
+
console.log(' atris wish grant <n> "<answer>" [--engine <id>] [--json] [--no-mission]');
|
|
55
|
+
console.log(' atris wish say "<note>" [wish-id]');
|
|
56
|
+
console.log(' atris wish close <n|id> [<n|id> ...]');
|
|
57
|
+
console.log(' atris wish again <id> "<tweak text>" [--engine <id>]');
|
|
58
|
+
console.log(' atris wish review [<id>|latest] "<one sentence>" [--score <-1|0|1 or 1-5>]');
|
|
59
|
+
console.log(' atris wish rewards');
|
|
60
|
+
console.log(' atris wish stats [--write]');
|
|
61
|
+
console.log(' atris wish improve');
|
|
62
|
+
console.log(' atris wish lessons');
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function cleanWishShowRef(value) {
|
|
67
|
+
return String(value || '').trim().replace(/^#/, '');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function wishShowHint(value) {
|
|
71
|
+
const suffix = cleanWishShowRef(value);
|
|
72
|
+
return suffix && /^\d+$/.test(suffix)
|
|
73
|
+
? `Use: atris wish show ${suffix}`
|
|
74
|
+
: 'Usage: atris wish show <n|id>';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function wishHistoryRows(root, wish) {
|
|
78
|
+
return readWishEvents(root).filter((event) => {
|
|
79
|
+
if (!event) return false;
|
|
80
|
+
if (event.id && event.id === wish.id) return true;
|
|
81
|
+
return event.wish_id && event.wish_id === wish.id;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function printWishShow(root, rawRef) {
|
|
86
|
+
const ref = cleanWishShowRef(rawRef);
|
|
87
|
+
if (!ref) {
|
|
88
|
+
console.error(wishShowHint(rawRef));
|
|
89
|
+
return 2;
|
|
90
|
+
}
|
|
91
|
+
const number = Number(ref);
|
|
92
|
+
const wishes = readWishes(root);
|
|
93
|
+
const wish = Number.isInteger(number) && number > 0
|
|
94
|
+
? wishes.find((row) => Number(row.n) === number)
|
|
95
|
+
: wishes.find((row) => String(row.id || '') === ref);
|
|
96
|
+
if (!wish) {
|
|
97
|
+
console.error(`No wish found for ${rawRef}. Try: atris wish list --all`);
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
const questions = Array.isArray(wish.questions) ? wish.questions.filter(Boolean) : [];
|
|
101
|
+
console.log(`Wish #${wish.n || '?'} ${wish.id}`);
|
|
102
|
+
console.log(`ID: ${wish.id}`);
|
|
103
|
+
console.log(`Status: ${wish.status || 'unknown'}`);
|
|
104
|
+
console.log(`Text: ${wish.text || ''}`);
|
|
105
|
+
console.log('Questions:');
|
|
106
|
+
if (questions.length) questions.forEach((question) => console.log(`- ${question}`));
|
|
107
|
+
else console.log('- none');
|
|
108
|
+
console.log('Rows:');
|
|
109
|
+
const history = wishHistoryRows(root, wish);
|
|
110
|
+
if (!history.length) console.log('- none');
|
|
111
|
+
history.forEach((event, index) => {
|
|
112
|
+
const parts = [event.ts || 'unknown-time', event.kind || event.status || 'event'];
|
|
113
|
+
if (event.answer) parts.push(`answer: ${event.answer}`);
|
|
114
|
+
if (event.review_text) parts.push(`review: ${event.review_text}`);
|
|
115
|
+
if (event.note) parts.push(`note: ${event.note}`);
|
|
116
|
+
if (Array.isArray(event.filled_slots) && event.filled_slots.length) {
|
|
117
|
+
parts.push(`filled: ${event.filled_slots.map((slot) => slot.value).join(', ')}`);
|
|
118
|
+
}
|
|
119
|
+
console.log(`- row ${index + 1}: ${parts.join(' | ')}`);
|
|
120
|
+
console.log(` text: ${event.text || wish.text || ''}`);
|
|
121
|
+
console.log(` status: ${event.status || event.kind || 'event'}`);
|
|
122
|
+
const rowQuestions = Array.isArray(event.questions) ? event.questions.filter(Boolean) : [];
|
|
123
|
+
console.log(` questions: ${rowQuestions.length ? rowQuestions.join(' | ') : 'none'}`);
|
|
124
|
+
console.log(` history: ${parts.slice(2).join(' | ') || 'none'}`);
|
|
125
|
+
});
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function closeWishes(root, refs) {
|
|
130
|
+
const cleaned = refs.map(cleanWishShowRef).filter(Boolean);
|
|
131
|
+
if (!cleaned.length) {
|
|
132
|
+
console.error('Usage: atris wish close <n|id> [<n|id> ...]');
|
|
133
|
+
return 2;
|
|
134
|
+
}
|
|
135
|
+
const wishes = readWishes(root);
|
|
136
|
+
const closedBy = process.env.ATRIS_AGENT_ID || process.env.USER || 'operator';
|
|
137
|
+
let missing = 0;
|
|
138
|
+
for (const ref of cleaned) {
|
|
139
|
+
const number = Number(ref);
|
|
140
|
+
const wish = Number.isInteger(number) && number > 0
|
|
141
|
+
? wishes.find((row) => Number(row.n) === number)
|
|
142
|
+
: wishes.find((row) => String(row.id || '') === ref);
|
|
143
|
+
if (!wish) {
|
|
144
|
+
console.error(`No wish found for ${ref}. Try: atris wish list --all`);
|
|
145
|
+
missing += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (String(wish.status || '') === 'closed') {
|
|
149
|
+
console.log(`Wish #${wish.n || '?'} is already closed.`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
appendWishRecord(root, {
|
|
153
|
+
id: wish.id,
|
|
154
|
+
n: wish.n || undefined,
|
|
155
|
+
ts: stampIso(),
|
|
156
|
+
text: wish.text || undefined,
|
|
157
|
+
kind: 'close',
|
|
158
|
+
status: 'closed',
|
|
159
|
+
closed_by: closedBy,
|
|
160
|
+
});
|
|
161
|
+
console.log(`Closed wish #${wish.n || '?'}: ${String(wish.text || '').slice(0, 60)}`);
|
|
162
|
+
}
|
|
163
|
+
return missing ? 1 : 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function appendFilledAnswerSlot(root, context) {
|
|
167
|
+
if (!context || !context.filled_slot || !context.wish_id) return;
|
|
168
|
+
appendWishRecord(root, {
|
|
169
|
+
id: context.wish_id,
|
|
170
|
+
n: context.n || undefined,
|
|
171
|
+
ts: stampIso(),
|
|
172
|
+
text: context.text || undefined,
|
|
173
|
+
kind: 'slot',
|
|
174
|
+
filled_slots: [context.filled_slot],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function unquote(value) {
|
|
179
|
+
const text = String(value);
|
|
180
|
+
if ((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"))) {
|
|
181
|
+
return text.slice(1, -1);
|
|
182
|
+
}
|
|
183
|
+
return text;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function parseFlagArgs(args, valueFlagNames = []) {
|
|
187
|
+
const valueFlags = new Set(valueFlagNames);
|
|
188
|
+
const values = {};
|
|
189
|
+
const positionals = [];
|
|
190
|
+
const missingValueFlags = [];
|
|
191
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
192
|
+
const arg = String(args[i] || '');
|
|
193
|
+
if (arg.startsWith('--')) {
|
|
194
|
+
const flagName = arg.split('=')[0];
|
|
195
|
+
if (valueFlags.has(flagName)) {
|
|
196
|
+
const prefix = flagName + '=';
|
|
197
|
+
if (arg.startsWith(prefix)) {
|
|
198
|
+
values[flagName] = unquote(arg.slice(prefix.length));
|
|
199
|
+
if (!String(values[flagName]).trim()) missingValueFlags.push(flagName);
|
|
200
|
+
}
|
|
201
|
+
else if (args[i + 1] && !String(args[i + 1]).startsWith('--')) {
|
|
202
|
+
values[flagName] = unquote(args[i + 1]);
|
|
203
|
+
i += 1;
|
|
204
|
+
} else missingValueFlags.push(flagName);
|
|
205
|
+
}
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
positionals.push(args[i]);
|
|
209
|
+
}
|
|
210
|
+
return { positionals, values, missingValueFlags };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function wishOptions(args) {
|
|
214
|
+
const cloud = args.includes('--cloud');
|
|
215
|
+
const parsed = parseFlagArgs(args, cloud
|
|
216
|
+
? ['--engine', '--as', '--metric', '--verify', '--lane', '--agent']
|
|
217
|
+
: ['--engine', '--as', '--metric', '--verify']);
|
|
218
|
+
return {
|
|
219
|
+
asJson: args.includes('--json'),
|
|
220
|
+
cloud,
|
|
221
|
+
noMission: args.includes('--no-mission'),
|
|
222
|
+
singleTask: args.includes('--one-lap'),
|
|
223
|
+
asMode: String(parsed.values['--as'] || '').trim(),
|
|
224
|
+
agentId: String(parsed.values['--agent'] || '').trim(),
|
|
225
|
+
engineOverride: String(parsed.values['--engine'] || '').trim(),
|
|
226
|
+
lane: String(parsed.values['--lane'] || '').trim() || 'fast',
|
|
227
|
+
metricRaw: String(parsed.values['--metric'] || '').trim(),
|
|
228
|
+
verifyRaw: String(parsed.values['--verify'] || '').trim(),
|
|
229
|
+
verifyMissing: parsed.missingValueFlags.includes('--verify'),
|
|
230
|
+
positionals: parsed.positionals,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function cloudWishOptionError(args, options) {
|
|
235
|
+
if (args.some((arg) => String(arg) === '--lane=')) {
|
|
236
|
+
return '--lane requires one of: fast, pro, max';
|
|
237
|
+
}
|
|
238
|
+
const laneIndex = args.findIndex((arg) => String(arg) === '--lane');
|
|
239
|
+
if (laneIndex >= 0 && (!args[laneIndex + 1] || String(args[laneIndex + 1]).startsWith('--'))) {
|
|
240
|
+
return '--lane requires one of: fast, pro, max';
|
|
241
|
+
}
|
|
242
|
+
const agentIndex = args.findIndex((arg) => String(arg) === '--agent');
|
|
243
|
+
if (args.some((arg) => String(arg) === '--agent=')) return '--agent requires an agent id';
|
|
244
|
+
if (agentIndex >= 0 && (!args[agentIndex + 1] || String(args[agentIndex + 1]).startsWith('--'))) {
|
|
245
|
+
return '--agent requires an agent id';
|
|
246
|
+
}
|
|
247
|
+
if (!VALID_CLOUD_LANES.has(options.lane)) {
|
|
248
|
+
return `invalid --lane "${options.lane}". expected fast, pro, or max`;
|
|
249
|
+
}
|
|
250
|
+
return '';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async function runCloudWish(text, root, options, deps = {}) {
|
|
254
|
+
try {
|
|
255
|
+
const mission = await enqueueCloudMission({
|
|
256
|
+
text,
|
|
257
|
+
lane: options.lane,
|
|
258
|
+
...(options.agentId ? { agentId: options.agentId } : {}),
|
|
259
|
+
}, deps);
|
|
260
|
+
const ts = deps.ts || stampIso();
|
|
261
|
+
const record = {
|
|
262
|
+
id: deps.wishId || wishId(text, ts),
|
|
263
|
+
n: nextWishNumber(root),
|
|
264
|
+
ts,
|
|
265
|
+
text,
|
|
266
|
+
status: 'delegated',
|
|
267
|
+
dispatched_at: ts,
|
|
268
|
+
cloud: true,
|
|
269
|
+
task_id: mission.task_id,
|
|
270
|
+
lane: mission.lane || options.lane,
|
|
271
|
+
};
|
|
272
|
+
captureWishToJournal(text, root);
|
|
273
|
+
appendWishRecord(root, record);
|
|
274
|
+
const log = deps.log || console.log;
|
|
275
|
+
const subject = String(text || '').trim().replace(/[.!?]+/g, '').replace(/\s+/g, ' ').toLowerCase();
|
|
276
|
+
log(`i sent ${JSON.stringify(subject)} to cloud work, and we know it is queued because the cloud accepted it.`);
|
|
277
|
+
log(`task_id: ${record.task_id}`);
|
|
278
|
+
log(`watch: atris mission status --cloud ${record.task_id} --watch`);
|
|
279
|
+
return 0;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
(deps.error || console.error)(error.message || String(error));
|
|
282
|
+
return error.exitCode || 1;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function resolveVerifyOption(options) {
|
|
287
|
+
if (options.verifyMissing) return 'wish --verify needs a command.';
|
|
288
|
+
if (!options.verifyRaw) return null;
|
|
289
|
+
const parsed = parseVerifyCommand(options.verifyRaw);
|
|
290
|
+
if (!parsed.ok) return `wish --verify is not allowed (${parsed.reason}).`;
|
|
291
|
+
options.verifyPlan = {
|
|
292
|
+
command: options.verifyRaw,
|
|
293
|
+
outcome: 'the supplied verifier passes',
|
|
294
|
+
status: 'explicit',
|
|
295
|
+
};
|
|
296
|
+
options.userVerifyProvided = true;
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Parses --metric into options.metric; returns an error message on malformed input.
|
|
301
|
+
function resolveMetricOption(options) {
|
|
302
|
+
if (!options.metricRaw) return null;
|
|
303
|
+
const parsed = parseMetricExpression(options.metricRaw);
|
|
304
|
+
if (!parsed.ok) return parsed.message;
|
|
305
|
+
options.metric = parsed;
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function parseReviewScore(args) {
|
|
310
|
+
const hasScore = args.some((arg) => {
|
|
311
|
+
const text = String(arg || '');
|
|
312
|
+
return text === '--score' || text.startsWith('--score=');
|
|
313
|
+
});
|
|
314
|
+
if (!hasScore) return { ok: true, value: null };
|
|
315
|
+
const parsed = parseFlagArgs(args, ['--score']);
|
|
316
|
+
const raw = String(parsed.values['--score'] || '').trim();
|
|
317
|
+
const allowed = new Set([-1, 0, 1, 2, 3, 4, 5]);
|
|
318
|
+
const value = Number(raw);
|
|
319
|
+
if (!raw || !Number.isInteger(value) || !allowed.has(value)) {
|
|
320
|
+
return {
|
|
321
|
+
ok: false,
|
|
322
|
+
message: 'wish review --score needs one of -1, 0, 1, 2, 3, 4, or 5.',
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
return { ok: true, value };
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function reviewOptions(args) {
|
|
329
|
+
const parsed = parseFlagArgs(args, ['--score']);
|
|
330
|
+
return {
|
|
331
|
+
score: parseReviewScore(args),
|
|
332
|
+
positionals: parsed.positionals,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function printLessons(root) {
|
|
337
|
+
const summary = wishLessonsSummary(root);
|
|
338
|
+
console.log('');
|
|
339
|
+
console.log(`Wish lessons: ${summary.reviews} scored reviews, average ${summary.avg_all === null ? 'none yet' : summary.avg_all} (last 5: ${summary.avg_last5 === null ? 'none yet' : summary.avg_last5})`);
|
|
340
|
+
console.log('');
|
|
341
|
+
console.log(summary.lessons.length ? 'Alive:' : 'Alive: none yet. Review a wish and the next run distills your review into a lesson.');
|
|
342
|
+
for (const line of summary.lessons) console.log(` ${line}`);
|
|
343
|
+
if (summary.pruned.length) {
|
|
344
|
+
console.log('');
|
|
345
|
+
console.log('Pruned (did not move the score):');
|
|
346
|
+
for (const line of summary.pruned) console.log(` ${line}`);
|
|
347
|
+
}
|
|
348
|
+
if (summary.inbox) {
|
|
349
|
+
console.log('');
|
|
350
|
+
console.log(`Inbox: ${summary.inbox} raw review${summary.inbox === 1 ? '' : 's'} waiting to be distilled on the next wish.`);
|
|
351
|
+
}
|
|
352
|
+
console.log('');
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function wishCommand(args = [], deps = {}) {
|
|
357
|
+
const first = String(args[0] || '').trim();
|
|
358
|
+
if (!first) {
|
|
359
|
+
showHelp();
|
|
360
|
+
printReviewNudges(process.cwd());
|
|
361
|
+
return 2;
|
|
362
|
+
}
|
|
363
|
+
if (first === '--help' || first === '-h' || first === 'help') {
|
|
364
|
+
showHelp();
|
|
365
|
+
return 0;
|
|
366
|
+
}
|
|
367
|
+
if (first === 'show') {
|
|
368
|
+
return printWishShow(process.cwd(), args[1]);
|
|
369
|
+
}
|
|
370
|
+
if (first === 'close') {
|
|
371
|
+
return closeWishes(process.cwd(), args.slice(1));
|
|
372
|
+
}
|
|
373
|
+
if ((first === 'status' || first === 'get') && /^\#?\d+$/.test(String(args[1] || '').trim())) {
|
|
374
|
+
console.error(wishShowHint(args[1]));
|
|
375
|
+
return 2;
|
|
376
|
+
}
|
|
377
|
+
if (first === 'get') {
|
|
378
|
+
console.error(wishShowHint(args[1]));
|
|
379
|
+
return 2;
|
|
380
|
+
}
|
|
381
|
+
if (first === 'list' || first === 'ls' || first === 'status') {
|
|
382
|
+
return printList(process.cwd(), { all: args.includes('--all') });
|
|
383
|
+
}
|
|
384
|
+
if (first === 'board') {
|
|
385
|
+
return printBoard(process.cwd());
|
|
386
|
+
}
|
|
387
|
+
if (first === 'rewards') {
|
|
388
|
+
return printRewards(process.cwd());
|
|
389
|
+
}
|
|
390
|
+
if (first === 'stats') {
|
|
391
|
+
return printWishStats(process.cwd(), { write: args.includes('--write') });
|
|
392
|
+
}
|
|
393
|
+
if (first === 'improve') {
|
|
394
|
+
return improveWishes(process.cwd());
|
|
395
|
+
}
|
|
396
|
+
if (first === 'lessons') {
|
|
397
|
+
return printLessons(process.cwd());
|
|
398
|
+
}
|
|
399
|
+
if (first === 'again') {
|
|
400
|
+
const options = wishOptions(args);
|
|
401
|
+
if (options.asMode && options.asMode !== 'builder') {
|
|
402
|
+
console.error('wish --as only supports builder.');
|
|
403
|
+
return 2;
|
|
404
|
+
}
|
|
405
|
+
return runAgainWish(options.positionals, process.cwd(), options);
|
|
406
|
+
}
|
|
407
|
+
if (first === 'answer') {
|
|
408
|
+
const options = wishOptions(args);
|
|
409
|
+
const root = process.cwd();
|
|
410
|
+
const context = {
|
|
411
|
+
root,
|
|
412
|
+
answer: options.positionals.slice(1).join(' ').trim(),
|
|
413
|
+
};
|
|
414
|
+
const code = withWishAnswerAuditContext(context, () => answerWish(options.positionals, root, options));
|
|
415
|
+
if (code !== 2) appendFilledAnswerSlot(root, context);
|
|
416
|
+
return code;
|
|
417
|
+
}
|
|
418
|
+
if (first === 'grant') {
|
|
419
|
+
const options = wishOptions(args);
|
|
420
|
+
return grantWish(options.positionals, process.cwd(), options);
|
|
421
|
+
}
|
|
422
|
+
if (first === 'review') {
|
|
423
|
+
const options = reviewOptions(args);
|
|
424
|
+
if (!options.score.ok) {
|
|
425
|
+
console.error(options.score.message);
|
|
426
|
+
return 2;
|
|
427
|
+
}
|
|
428
|
+
const reviewResult = reviewWish(options.positionals, process.cwd(), { reviewScore: options.score.value });
|
|
429
|
+
if (reviewResult === 0) {
|
|
430
|
+
try {
|
|
431
|
+
improveWishes(process.cwd(), { quiet: true });
|
|
432
|
+
} catch {
|
|
433
|
+
// best-effort: lessons ingest must never fail a review
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return reviewResult;
|
|
437
|
+
}
|
|
438
|
+
if (first === 'say') {
|
|
439
|
+
return sayWish(args, process.cwd());
|
|
440
|
+
}
|
|
441
|
+
const options = wishOptions(args);
|
|
442
|
+
if (options.cloud) {
|
|
443
|
+
const optionError = cloudWishOptionError(args, options);
|
|
444
|
+
if (optionError) {
|
|
445
|
+
(deps.error || console.error)(optionError);
|
|
446
|
+
return 2;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (options.asMode && options.asMode !== 'builder') {
|
|
450
|
+
console.error('wish --as only supports builder.');
|
|
451
|
+
return 2;
|
|
452
|
+
}
|
|
453
|
+
const metricError = resolveMetricOption(options);
|
|
454
|
+
if (metricError) {
|
|
455
|
+
console.error(metricError);
|
|
456
|
+
return 2;
|
|
457
|
+
}
|
|
458
|
+
const verifyError = resolveVerifyOption(options);
|
|
459
|
+
if (verifyError) {
|
|
460
|
+
console.error(verifyError);
|
|
461
|
+
return 2;
|
|
462
|
+
}
|
|
463
|
+
// "atris wish claim <text>" is command confusion; the word claim is not part of the wish.
|
|
464
|
+
const positionals = first === 'claim' && options.positionals.length > 1
|
|
465
|
+
? options.positionals.slice(1)
|
|
466
|
+
: options.positionals;
|
|
467
|
+
const text = positionals.join(' ').trim();
|
|
468
|
+
if (!text) {
|
|
469
|
+
showHelp();
|
|
470
|
+
return 2;
|
|
471
|
+
}
|
|
472
|
+
if (options.cloud) return runCloudWish(text, process.cwd(), options, deps);
|
|
473
|
+
return runCapturedWish(text, process.cwd(), options);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
module.exports = {
|
|
477
|
+
wishCommand,
|
|
478
|
+
analyzeWishParts,
|
|
479
|
+
auditWish,
|
|
480
|
+
captureWishToJournal,
|
|
481
|
+
deriveVerifyPlan,
|
|
482
|
+
improveWishes,
|
|
483
|
+
inferBudgetTier,
|
|
484
|
+
missingNamedInputs,
|
|
485
|
+
printBoard,
|
|
486
|
+
printReviewNudges,
|
|
487
|
+
printRewards,
|
|
488
|
+
readWishEvents,
|
|
489
|
+
readWishes,
|
|
490
|
+
runCloudWish,
|
|
491
|
+
runAgainWish,
|
|
492
|
+
sayWish,
|
|
493
|
+
sharesMeaningfulWords,
|
|
494
|
+
stateFile,
|
|
495
|
+
sweepWishes,
|
|
496
|
+
verifyOutcomeText,
|
|
497
|
+
withWishAnswerAuditContext,
|
|
498
|
+
waitingOperatorWishes,
|
|
499
|
+
REVIEW_WORD_SCORES,
|
|
500
|
+
};
|
package/commands/workflow.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { getLogPath } = require('../lib/journal');
|
|
4
|
+
const { encodeToolResult } = require('../lib/tool-result-encode');
|
|
4
5
|
|
|
5
6
|
function wrapWorkflowText(text, width = 76) {
|
|
6
7
|
const normalized = String(text || '').replace(/\s+/g, ' ').trim();
|
|
@@ -139,7 +140,7 @@ function postToolResult(callId, result, base = 'http://127.0.0.1:8000') {
|
|
|
139
140
|
const url = new URL('/api/atris2/turn/tool-result', base);
|
|
140
141
|
const transport = url.protocol === 'https:' ? require('https') : require('http');
|
|
141
142
|
return new Promise((resolve, reject) => {
|
|
142
|
-
const postData = JSON.stringify({ call_id: callId, result });
|
|
143
|
+
const postData = JSON.stringify({ call_id: callId, result_base64: encodeToolResult(result) });
|
|
143
144
|
const req = transport.request({
|
|
144
145
|
hostname: url.hostname,
|
|
145
146
|
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
@@ -630,9 +631,9 @@ async function planAtris(userInput = null) {
|
|
|
630
631
|
userPrompt += ` - Include file:line references from MAP.md\n`;
|
|
631
632
|
userPrompt += ` - List dependencies between tasks\n`;
|
|
632
633
|
userPrompt += ` - Add acceptance criteria for each task\n\n`;
|
|
633
|
-
userPrompt += `STEP 4:
|
|
634
|
-
userPrompt += ` -
|
|
635
|
-
userPrompt += ` -
|
|
634
|
+
userPrompt += `STEP 4: Create tasks through the task database\n`;
|
|
635
|
+
userPrompt += ` - Use bash to run 'atris task add' or the task database calls; do not hand-edit TODO.md\n`;
|
|
636
|
+
userPrompt += ` - The CLI will re-render atris/TODO.md after this workflow step completes\n`;
|
|
636
637
|
userPrompt += ` - Each task: one job, clear exit condition\n`;
|
|
637
638
|
userPrompt += ` - Include file:line references from MAP.md\n\n`;
|
|
638
639
|
userPrompt += `STEP 5: Log to your journal\n`;
|
|
@@ -651,7 +652,7 @@ async function planAtris(userInput = null) {
|
|
|
651
652
|
try {
|
|
652
653
|
await executeCodeExecution({
|
|
653
654
|
prompt: userPrompt,
|
|
654
|
-
allowedTools: ['Read', '
|
|
655
|
+
allowedTools: ['Read', 'Bash'], // Task creation must go through atris task / the database
|
|
655
656
|
permissionMode: 'default',
|
|
656
657
|
maxTurns: 15,
|
|
657
658
|
systemPrompt,
|
|
@@ -686,6 +687,11 @@ async function planAtris(userInput = null) {
|
|
|
686
687
|
console.error(`\n❌ Execution error: ${error.message}`);
|
|
687
688
|
},
|
|
688
689
|
});
|
|
690
|
+
try {
|
|
691
|
+
require('./task').autoRenderTodoFromDb(process.cwd());
|
|
692
|
+
} catch {
|
|
693
|
+
// Rendering is best-effort; task-db state remains authoritative.
|
|
694
|
+
}
|
|
689
695
|
|
|
690
696
|
console.log('\n');
|
|
691
697
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|