atris 3.35.0 → 3.37.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 +576 -267
- 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 +3144 -338
- 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 +96 -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/next.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
claimRoadmapItem,
|
|
5
|
+
nextCards,
|
|
6
|
+
markDreamCardConsumed,
|
|
7
|
+
parkNextCard,
|
|
8
|
+
recordDecision,
|
|
9
|
+
seedInboxFromMove,
|
|
10
|
+
} = require('../lib/next-moves');
|
|
11
|
+
|
|
12
|
+
function showHelp() {
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log('Usage: atris next [yes|no|skip]');
|
|
15
|
+
console.log('');
|
|
16
|
+
console.log('Shows one next move card.');
|
|
17
|
+
console.log('');
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function cardLabel(card) {
|
|
22
|
+
return String(card?.label || card?.title || '').trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function cardWhy(card) {
|
|
26
|
+
const why = String(card?.why || '').trim();
|
|
27
|
+
if (why) return why;
|
|
28
|
+
const status = String(card?.status || '').trim();
|
|
29
|
+
if (status) return status;
|
|
30
|
+
if (card?.source === 'task' || card?.source === 'mission') return 'working';
|
|
31
|
+
return 'new';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderCard(card) {
|
|
35
|
+
if (!card) return 'Nothing to do. Rest or wish.';
|
|
36
|
+
return [
|
|
37
|
+
cardLabel(card),
|
|
38
|
+
`Why now: ${cardWhy(card)}`,
|
|
39
|
+
'Do it? yes / no / skip',
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function printCard(card) {
|
|
44
|
+
console.log(renderCard(card));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function wishPromptTitle(label) {
|
|
48
|
+
return String(label || 'this').replace(/^(#\d+)\s+/, '$1: ');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function printWishAnswerPrompt(card) {
|
|
52
|
+
const action = card.next_action || {};
|
|
53
|
+
console.log(`Got it, wish ${wishPromptTitle(action.label || cardLabel(card))}.`);
|
|
54
|
+
console.log(String(action.question || 'What should be different when this wish comes true?'));
|
|
55
|
+
console.log('Answer with: atris wish answer "your words"');
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function approveMove(card, root) {
|
|
60
|
+
recordDecision(root, card, 'approve', new Date().toISOString());
|
|
61
|
+
if (['roadmap', 'inbox', 'endgame'].includes(card.source)) {
|
|
62
|
+
seedInboxFromMove(root, card);
|
|
63
|
+
if (card.source === 'roadmap') claimRoadmapItem(root, card.title);
|
|
64
|
+
console.log(`${cardLabel(card)} is working.`);
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const prompt = card.next_action && card.next_action.prompt;
|
|
68
|
+
console.log(prompt || `${cardLabel(card)} is working.`);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function completeMissionFromCard(card) {
|
|
73
|
+
const action = card.next_action || {};
|
|
74
|
+
if (!action.mission_id || !action.proof_path) {
|
|
75
|
+
console.log('Review the proof, then complete this mission.');
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
const { completeMission } = require('./mission');
|
|
79
|
+
completeMission([action.mission_id, '--proof', action.proof_path]);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function executeCard(card, root) {
|
|
84
|
+
const action = card && card.next_action;
|
|
85
|
+
if (!card) {
|
|
86
|
+
printCard(null);
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
if (action?.type === 'wish_answer_prompt') return printWishAnswerPrompt(card);
|
|
90
|
+
if (action?.type === 'mission_complete') return completeMissionFromCard(card);
|
|
91
|
+
if (action?.type === 'wish_review_prompt' || action?.type === 'mission_review_prompt') {
|
|
92
|
+
console.log(action.prompt || 'Review the proof, then choose done or stuck.');
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
return approveMove(card, root);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function nextCommand(args = [], root = process.cwd()) {
|
|
99
|
+
const action = String(args[0] || '').trim().toLowerCase();
|
|
100
|
+
if (action === 'help' || action === '--help' || action === '-h') return showHelp();
|
|
101
|
+
|
|
102
|
+
const current = nextCards(root, 1)[0] || null;
|
|
103
|
+
if (!action) {
|
|
104
|
+
printCard(current);
|
|
105
|
+
if (current?.source === 'dream') markDreamCardConsumed(root, current, new Date().toISOString(), 'dealt');
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (action === 'skip') {
|
|
110
|
+
const following = current ? nextCards(root, 1, { skipIds: [current.id] })[0] : null;
|
|
111
|
+
if (current?.source === 'dream') markDreamCardConsumed(root, current, new Date().toISOString(), 'skipped');
|
|
112
|
+
printCard(following);
|
|
113
|
+
if (following?.source === 'dream') markDreamCardConsumed(root, following, new Date().toISOString(), 'dealt');
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (action === 'no') {
|
|
118
|
+
if (!current) {
|
|
119
|
+
printCard(null);
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
parkNextCard(root, current);
|
|
123
|
+
console.log(`Parked ${cardLabel(current)}.`);
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (action === 'yes') return executeCard(current, root);
|
|
128
|
+
|
|
129
|
+
console.log('Say yes, no, or skip.');
|
|
130
|
+
return 2;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
cardLabel,
|
|
135
|
+
nextCommand,
|
|
136
|
+
renderCard,
|
|
137
|
+
};
|
package/commands/now.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { hasRenderedSections, isOpenSection } = require('../lib/todo-sections');
|
|
4
|
+
const { renderMorningCardRow } = require('../lib/receipt-block');
|
|
5
|
+
const { historicalLandingText } = require('../lib/autoland');
|
|
4
6
|
|
|
5
7
|
const NOW_PATH = path.join('atris', 'now.md');
|
|
6
8
|
const TASK_EPISODES_PATH = path.join('.atris', 'state', 'task_episodes.jsonl');
|
|
7
9
|
const CAREER_XP_RECEIPTS_PATH = path.join('.atris', 'state', 'career_xp_receipts.jsonl');
|
|
10
|
+
const MISSION_RUNS_PATH = path.join('atris', 'runs');
|
|
8
11
|
const EXECUTABLE_TASK_STATUSES = new Set(['open', 'claimed']);
|
|
9
12
|
const TASK_RECEIPT_EVENTS = new Set(['proof_ready', 'reviewed', 'completed']);
|
|
10
13
|
|
|
@@ -15,6 +18,12 @@ function formatLocalDate(date = new Date()) {
|
|
|
15
18
|
return `${year}-${month}-${day}`;
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
function formatLocalTimestamp(date = new Date()) {
|
|
22
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
23
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
24
|
+
return `${formatLocalDate(date)} at ${hours}:${minutes} local time`;
|
|
25
|
+
}
|
|
26
|
+
|
|
18
27
|
function todayIso() {
|
|
19
28
|
return formatLocalDate(new Date());
|
|
20
29
|
}
|
|
@@ -167,6 +176,20 @@ function taskReceiptProof(row) {
|
|
|
167
176
|
).trim();
|
|
168
177
|
}
|
|
169
178
|
|
|
179
|
+
function taskReceiptResult(row) {
|
|
180
|
+
return compactLine(
|
|
181
|
+
row?.state?.metadata?.result
|
|
182
|
+
|| row?.review_landing?.happened
|
|
183
|
+
|| row?.state?.metadata?.landing_happened
|
|
184
|
+
|| '',
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function taskReceiptCertified(row) {
|
|
189
|
+
return row?.state?.metadata?.agent_certified === true
|
|
190
|
+
|| /second-actor check/i.test(taskReceiptProof(row));
|
|
191
|
+
}
|
|
192
|
+
|
|
170
193
|
function taskReceiptKey(row, fallback) {
|
|
171
194
|
const episodeId = row?.episode_id || row?.source_episode_id;
|
|
172
195
|
if (episodeId) return `episode:${episodeId}`;
|
|
@@ -175,51 +198,205 @@ function taskReceiptKey(row, fallback) {
|
|
|
175
198
|
return `row:${fallback}`;
|
|
176
199
|
}
|
|
177
200
|
|
|
178
|
-
function
|
|
201
|
+
function storeTaskReceipt(byKey, row) {
|
|
202
|
+
const key = taskReceiptKey(row, byKey.size);
|
|
203
|
+
const previous = byKey.get(key);
|
|
204
|
+
const candidate = {
|
|
205
|
+
title: taskReceiptTitle(row),
|
|
206
|
+
result: taskReceiptResult(row),
|
|
207
|
+
certified: taskReceiptCertified(row),
|
|
208
|
+
};
|
|
209
|
+
byKey.set(key, {
|
|
210
|
+
title: candidate.title || previous?.title,
|
|
211
|
+
result: candidate.result || previous?.result || '',
|
|
212
|
+
certified: Boolean(candidate.certified || previous?.certified),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// One pass over today's receipt sources, deduped by key. Both the
|
|
217
|
+
// "Completed receipts today" count and the readable "While You Were Away"
|
|
218
|
+
// lines derive from this, so the number and the list can never disagree.
|
|
219
|
+
function collectTaskReceiptsToday(root = process.cwd(), date = new Date()) {
|
|
179
220
|
const targetDay = formatLocalDate(date);
|
|
180
221
|
const stateDir = path.join(root, '.atris', 'state');
|
|
181
|
-
const
|
|
222
|
+
const byKey = new Map();
|
|
182
223
|
|
|
183
224
|
for (const row of readJsonlRows(path.join(stateDir, 'task_episodes.jsonl'))) {
|
|
184
225
|
if (localDateKey(row?.created_at) !== targetDay) continue;
|
|
185
226
|
if (!rowMatchesWorkspace(row?.workspace_root, root)) continue;
|
|
186
|
-
|
|
227
|
+
const proof = taskReceiptProof(row);
|
|
228
|
+
if (!proof) continue;
|
|
187
229
|
const eventType = String(row?.action?.event_type || '').toLowerCase();
|
|
188
230
|
if (eventType && !TASK_RECEIPT_EVENTS.has(eventType)) continue;
|
|
189
|
-
|
|
231
|
+
storeTaskReceipt(byKey, row);
|
|
190
232
|
}
|
|
191
233
|
|
|
192
234
|
for (const row of readJsonlRows(path.join(stateDir, 'career_xp_receipts.jsonl'))) {
|
|
193
235
|
if (localDateKey(row?.accepted_at || row?.created_at || row?.ts) !== targetDay) continue;
|
|
194
236
|
if (!rowMatchesWorkspace(row?.workspace_root, root)) continue;
|
|
195
|
-
|
|
237
|
+
const proof = taskReceiptProof(row);
|
|
238
|
+
if (!proof) continue;
|
|
196
239
|
const source = String(row?.source_type || row?.receipt_id || row?.source || '').toLowerCase();
|
|
197
240
|
if (!source.includes('task')) continue;
|
|
198
|
-
|
|
241
|
+
storeTaskReceipt(byKey, row);
|
|
199
242
|
}
|
|
200
243
|
|
|
201
|
-
return
|
|
244
|
+
return Array.from(byKey.values());
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function countTaskReceiptsToday(root = process.cwd(), date = new Date()) {
|
|
248
|
+
return collectTaskReceiptsToday(root, date).length;
|
|
202
249
|
}
|
|
203
250
|
|
|
204
251
|
function compactLine(value) {
|
|
205
252
|
return String(value || '').replace(/\s+/g, ' ').trim();
|
|
206
253
|
}
|
|
207
254
|
|
|
255
|
+
function truncateLine(value, max) {
|
|
256
|
+
const s = compactLine(value);
|
|
257
|
+
if (s.length <= max) return s;
|
|
258
|
+
return `${s.slice(0, max - 1).trimEnd()}…`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function compactCommitSubject(value, max = 90) {
|
|
262
|
+
return historicalLandingText(compactLine(value), max);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function taskReceiptTitle(row) {
|
|
266
|
+
return compactLine(row?.state?.title || row?.title || row?.task_id || 'untitled work');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// The receipts behind "Completed receipts today", as lines a human can read:
|
|
270
|
+
// one per receipt, landed result + human proof state. Shares the collector
|
|
271
|
+
// with the count so the number and the visible list always match.
|
|
272
|
+
function todayTaskReceiptLines(root = process.cwd(), date = new Date(), limit = 6) {
|
|
273
|
+
return collectTaskReceiptsToday(root, date)
|
|
274
|
+
.slice(-limit)
|
|
275
|
+
.reverse()
|
|
276
|
+
.map((r) => {
|
|
277
|
+
const result = historicalLandingText(r.result || r.title, 180);
|
|
278
|
+
const proofState = r.certified ? 'independently checked' : 'proof on file';
|
|
279
|
+
return `- ✓ ${result} - ${proofState}`;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// What actually landed on this branch in the last day - the fleet's overnight
|
|
284
|
+
// merges are the strongest "the computer worked while you were away" evidence.
|
|
285
|
+
function landedCommitLines(root = process.cwd(), limit = 5) {
|
|
286
|
+
try {
|
|
287
|
+
const { execFileSync } = require('node:child_process');
|
|
288
|
+
const out = execFileSync(
|
|
289
|
+
'git',
|
|
290
|
+
['log', '--since=24 hours ago', '--no-merges', '--format=%s', '-n', '40'],
|
|
291
|
+
{ cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },
|
|
292
|
+
);
|
|
293
|
+
const seen = new Set();
|
|
294
|
+
const lines = [];
|
|
295
|
+
for (const subject of out.split('\n')) {
|
|
296
|
+
const s = compactLine(subject);
|
|
297
|
+
if (!s || seen.has(s)) continue;
|
|
298
|
+
seen.add(s);
|
|
299
|
+
lines.push(`- ↑ ${compactCommitSubject(s, 90)}`);
|
|
300
|
+
if (lines.length >= limit) break;
|
|
301
|
+
}
|
|
302
|
+
return lines;
|
|
303
|
+
} catch {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// The one thing only the owner can answer. Prefers an explicit owner action;
|
|
309
|
+
// falls back to a blocked loop's open question (needs_human). Loops ask here -
|
|
310
|
+
// they never invent the answer themselves.
|
|
311
|
+
function nextOwnerActionLine(root = process.cwd()) {
|
|
312
|
+
const statusPath = path.join(root, 'atris', 'status', 'master-loop.md');
|
|
313
|
+
if (!fs.existsSync(statusPath)) return null;
|
|
314
|
+
const lines = fs.readFileSync(statusPath, 'utf8').split(/\r?\n/);
|
|
315
|
+
for (const prefix of ['- next_owner_action:', '- needs_human:']) {
|
|
316
|
+
const line = lines.find((l) => l.startsWith(prefix));
|
|
317
|
+
if (line) {
|
|
318
|
+
const action = truncateLine(line.replace(prefix, ''), 220);
|
|
319
|
+
if (action) return action;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
|
|
208
325
|
function currentMissionMoveLine(root = process.cwd()) {
|
|
209
326
|
try {
|
|
210
|
-
const { selectCodexGoalMission, codexGoalNextCommand } = require('./mission');
|
|
327
|
+
const { selectCodexGoalMission, codexGoalNextCommand, missionBudgetContinuationText } = require('./mission');
|
|
211
328
|
const selected = selectCodexGoalMission(root);
|
|
212
329
|
const mission = selected?.mission || null;
|
|
213
330
|
if (!mission) return null;
|
|
214
|
-
const objective =
|
|
215
|
-
const
|
|
331
|
+
const objective = completeMissionObjective(mission.objective, 140);
|
|
332
|
+
const budgetContinuation = missionBudgetContinuationText(mission);
|
|
333
|
+
if (budgetContinuation) return `The move: ${objective} - next: ${budgetContinuation}`;
|
|
334
|
+
const compact = compactMissionCommand(codexGoalNextCommand(mission), mission);
|
|
335
|
+
const next = compact.length <= 160 ? compact : `atris mission status ${mission.n || mission.id}`;
|
|
216
336
|
if (!objective || !next) return null;
|
|
217
|
-
return `The move: ${objective}
|
|
337
|
+
return `The move: ${objective} - next: ${next}`;
|
|
218
338
|
} catch {
|
|
219
339
|
return null;
|
|
220
340
|
}
|
|
221
341
|
}
|
|
222
342
|
|
|
343
|
+
function completeMissionObjective(objective, max = 140) {
|
|
344
|
+
const clean = String(objective || '').replace(/\s+/g, ' ').trim();
|
|
345
|
+
const firstClause = clean.split(',', 1)[0].trim();
|
|
346
|
+
if (firstClause.length >= 40 && firstClause.length <= max) return firstClause;
|
|
347
|
+
return historicalLandingText(clean, max);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function compactMissionCommand(command, mission) {
|
|
351
|
+
const value = String(command || '').trim();
|
|
352
|
+
const id = String(mission?.id || '').trim();
|
|
353
|
+
const shortRef = String(mission?.n || '').trim();
|
|
354
|
+
return id && shortRef ? value.split(id).join(shortRef) : value;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function receiptSortKey(receipt) {
|
|
358
|
+
return String(receipt?.at || receipt?.result?.tick?.finished_at || receipt?.result?.tick?.started_at || '');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function collectMissionReceiptsToday(root = process.cwd(), date = new Date()) {
|
|
362
|
+
const targetDay = formatLocalDate(date);
|
|
363
|
+
const runsDir = path.join(root, MISSION_RUNS_PATH);
|
|
364
|
+
if (!fs.existsSync(runsDir)) return [];
|
|
365
|
+
let files = [];
|
|
366
|
+
try {
|
|
367
|
+
files = fs.readdirSync(runsDir)
|
|
368
|
+
.filter((file) => file.endsWith('.json'))
|
|
369
|
+
.map((file) => path.join(runsDir, file));
|
|
370
|
+
} catch {
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
const receipts = [];
|
|
374
|
+
for (const file of files) {
|
|
375
|
+
let receipt = null;
|
|
376
|
+
try {
|
|
377
|
+
receipt = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
378
|
+
} catch {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (receipt?.schema !== 'atris.mission_receipt.v1') continue;
|
|
382
|
+
if (localDateKey(receiptSortKey(receipt)) !== targetDay) continue;
|
|
383
|
+
receipts.push(receipt);
|
|
384
|
+
}
|
|
385
|
+
receipts.sort((a, b) => receiptSortKey(a).localeCompare(receiptSortKey(b)));
|
|
386
|
+
return receipts;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function countMissionReceiptsToday(root = process.cwd(), date = new Date()) {
|
|
390
|
+
return collectMissionReceiptsToday(root, date).length;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function todayMissionReceiptLines(root = process.cwd(), date = new Date(), limit = 6) {
|
|
394
|
+
return collectMissionReceiptsToday(root, date)
|
|
395
|
+
.slice(-limit)
|
|
396
|
+
.reverse()
|
|
397
|
+
.map((receipt) => renderMorningCardRow(receipt));
|
|
398
|
+
}
|
|
399
|
+
|
|
223
400
|
function currentJournalPath(root = process.cwd()) {
|
|
224
401
|
const now = new Date();
|
|
225
402
|
const year = String(now.getFullYear());
|
|
@@ -235,12 +412,26 @@ function renderDefaultNow(root = process.cwd()) {
|
|
|
235
412
|
const openTodoCount = countOpenWorkItems(root, todoPath);
|
|
236
413
|
const inboxCount = countMatches(journalPath, /^-\s+\*\*I\d+:/gm);
|
|
237
414
|
const taskReceiptCount = countTaskReceiptsToday(root);
|
|
238
|
-
const
|
|
239
|
-
const
|
|
415
|
+
const missionReceiptCount = countMissionReceiptsToday(root);
|
|
416
|
+
const completedCount = taskReceiptCount + missionReceiptCount || countJournalCompletedReceipts(journalPath);
|
|
417
|
+
const generated = formatLocalTimestamp();
|
|
240
418
|
const moveLine = currentMissionMoveLine(root);
|
|
241
419
|
const whatMattersNow = moveLine
|
|
242
|
-
? `${moveLine}\n\n-
|
|
420
|
+
? `${moveLine}\n\n- Run the named next action and leave proof before choosing another.`
|
|
243
421
|
: '- Decide the next useful move before opening more context.';
|
|
422
|
+
const receiptLines = todayTaskReceiptLines(root);
|
|
423
|
+
const missionReceiptLines = todayMissionReceiptLines(root);
|
|
424
|
+
const commitLines = landedCommitLines(root);
|
|
425
|
+
const hiddenReceiptCount = Math.max(0, completedCount - missionReceiptLines.length - receiptLines.length);
|
|
426
|
+
const hiddenReceiptLine = hiddenReceiptCount > 0
|
|
427
|
+
? [`- ${hiddenReceiptCount} more completed receipt${hiddenReceiptCount === 1 ? '' : 's'} omitted from this short recap; open task results with atris autoland digest and mission proof with atris mission status.`]
|
|
428
|
+
: [];
|
|
429
|
+
const awayLines = [...missionReceiptLines, ...receiptLines, ...hiddenReceiptLine, ...commitLines];
|
|
430
|
+
const whileAway = awayLines.length
|
|
431
|
+
? awayLines.join('\n')
|
|
432
|
+
: '- Nothing has landed yet today.';
|
|
433
|
+
const ownerAction = nextOwnerActionLine(root);
|
|
434
|
+
const needsYou = ownerAction ? `\n## Needs You\n\n- ${ownerAction}\n` : '';
|
|
244
435
|
|
|
245
436
|
return `# now
|
|
246
437
|
|
|
@@ -253,6 +444,10 @@ Last updated: ${generated}
|
|
|
253
444
|
|
|
254
445
|
${whatMattersNow}
|
|
255
446
|
|
|
447
|
+
## While You Were Away
|
|
448
|
+
|
|
449
|
+
${whileAway}
|
|
450
|
+
${needsYou}
|
|
256
451
|
## Current Priority
|
|
257
452
|
|
|
258
453
|
- Keep the workspace coherent and useful for the next human or agent.
|
|
@@ -264,16 +459,6 @@ ${whatMattersNow}
|
|
|
264
459
|
- Inbox items today: ${inboxCount}
|
|
265
460
|
- Completed receipts today: ${completedCount}
|
|
266
461
|
|
|
267
|
-
## Watchouts
|
|
268
|
-
|
|
269
|
-
- Do not treat old logs as current truth unless this file links to them.
|
|
270
|
-
- Do not create motion for its own sake.
|
|
271
|
-
- If facts conflict, surface the conflict and cite the receipts.
|
|
272
|
-
|
|
273
|
-
## Next Move
|
|
274
|
-
|
|
275
|
-
- Read \`atris/MAP.md\`, \`atris/TODO.md\`, and today's journal only as needed for the task in front of you.
|
|
276
|
-
|
|
277
462
|
## Receipts
|
|
278
463
|
|
|
279
464
|
- \`atris/MAP.md\`
|
|
@@ -288,7 +473,7 @@ function renderPortfolioNow(root = process.cwd()) {
|
|
|
288
473
|
throw new Error('atris/ folder not found. Run "atris init" first.');
|
|
289
474
|
}
|
|
290
475
|
|
|
291
|
-
const generated =
|
|
476
|
+
const generated = formatLocalTimestamp();
|
|
292
477
|
const lines = workspaces.map((workspace) => {
|
|
293
478
|
const heading = readFirstHeading(workspace.mapPath) || workspace.slug;
|
|
294
479
|
const todoCount = countOpenWorkItems(workspace.root, workspace.todoPath);
|
|
@@ -444,11 +629,21 @@ module.exports = {
|
|
|
444
629
|
CAREER_XP_RECEIPTS_PATH,
|
|
445
630
|
ensureNowFile,
|
|
446
631
|
formatLocalDate,
|
|
632
|
+
formatLocalTimestamp,
|
|
447
633
|
countJournalCompletedReceipts,
|
|
448
634
|
countOpenWorkItems,
|
|
449
635
|
countOpenTodoItems,
|
|
636
|
+
countMissionReceiptsToday,
|
|
450
637
|
countTaskReceiptsToday,
|
|
451
638
|
currentMissionMoveLine,
|
|
639
|
+
compactMissionCommand,
|
|
640
|
+
compactCommitSubject,
|
|
641
|
+
completeMissionObjective,
|
|
642
|
+
landedCommitLines,
|
|
643
|
+
nextOwnerActionLine,
|
|
644
|
+
todayMissionReceiptLines,
|
|
645
|
+
todayTaskReceiptLines,
|
|
646
|
+
truncateLine,
|
|
452
647
|
findChildWorkspaces,
|
|
453
648
|
isGeneratedNowFile,
|
|
454
649
|
nowAtris,
|