atris 3.34.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 +35 -0
- package/FOR_AGENTS.md +5 -3
- 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 +35 -8
- package/atris/skills/fable-method/SKILL.md +66 -0
- package/atris/skills/improve/SKILL.md +65 -45
- package/atris/skills/render-cli/SKILL.md +88 -0
- package/atris/skills/youtube/SKILL.md +10 -1
- package/atris.md +6 -2
- package/ax +617 -31
- package/bin/atris.js +719 -266
- package/commands/activate.js +194 -88
- package/commands/aeo.js +52 -0
- package/commands/agents.js +166 -0
- package/commands/autoland.js +718 -72
- 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/business.js +91 -8
- package/commands/clean.js +50 -24
- package/commands/close.js +1083 -0
- package/commands/cloud.js +245 -0
- package/commands/codex-goal.js +26 -2
- 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/drive.js +187 -0
- package/commands/engine.js +1061 -29
- package/commands/experiments.js +28 -0
- package/commands/feed.js +202 -0
- package/commands/feedback.js +34 -12
- package/commands/fleet-report.js +206 -0
- package/commands/github.js +38 -0
- package/commands/gm.js +285 -3
- package/commands/goal.js +247 -0
- package/commands/improve.js +642 -26
- package/commands/init.js +83 -43
- package/commands/integrations.js +39 -11
- package/commands/interview.js +209 -0
- package/commands/land.js +253 -52
- package/commands/lesson.js +112 -1
- package/commands/lifecycle.js +39 -3
- package/commands/linear.js +38 -0
- package/commands/log.js +84 -1
- package/commands/loops.js +220 -16
- package/commands/meet.js +220 -0
- package/commands/member.js +899 -66
- package/commands/mission.js +3512 -332
- package/commands/next.js +137 -0
- package/commands/now.js +240 -21
- 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/radar.js +259 -14
- 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/serve.js +54 -0
- package/commands/skill.js +47 -3
- package/commands/slop.js +50 -2
- package/commands/soul.js +1 -1
- package/commands/status.js +50 -5
- package/commands/stream.js +861 -0
- package/commands/stripe.js +38 -0
- package/commands/study.js +693 -0
- package/commands/supabase.js +39 -0
- package/commands/sync.js +67 -54
- package/commands/task.js +2275 -182
- package/commands/team.js +73 -0
- package/commands/truth.js +29 -3
- package/commands/unknowns.js +627 -0
- package/commands/update.js +44 -0
- package/commands/vercel.js +38 -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 +299 -20
- package/commands/write.js +399 -0
- package/commands/xp.js +29 -11
- package/lib/auto-accept-certified.js +391 -43
- package/lib/autoland.js +353 -52
- 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 +2431 -38
- 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/memory-view.js +14 -5
- package/lib/mission-room.js +1 -0
- package/lib/mission-root.js +52 -0
- package/lib/mission-runtime-loop.js +7 -0
- package/lib/next-moves.js +327 -10
- package/lib/official-cli-integration.js +174 -0
- package/lib/one-lap-validator.js +60 -0
- package/lib/orb-context.js +477 -0
- package/lib/orb-scorecard.js +224 -0
- package/lib/outbound-send-gate.js +165 -0
- package/lib/permission-grants.js +293 -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/review-integrity.js +147 -0
- package/lib/router-brain.js +352 -0
- package/lib/runner-command.js +33 -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 +319 -27
- package/lib/task-proof.js +43 -1
- package/lib/task-receipt.js +93 -0
- 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/utils/update-check.js +27 -6
- package/atris/learnings.jsonl +0 -1
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,30 +198,203 @@ 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);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return Array.from(byKey.values());
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function countTaskReceiptsToday(root = process.cwd(), date = new Date()) {
|
|
248
|
+
return collectTaskReceiptsToday(root, date).length;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function compactLine(value) {
|
|
252
|
+
return String(value || '').replace(/\s+/g, ' ').trim();
|
|
253
|
+
}
|
|
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
|
+
}
|
|
199
321
|
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function currentMissionMoveLine(root = process.cwd()) {
|
|
326
|
+
try {
|
|
327
|
+
const { selectCodexGoalMission, codexGoalNextCommand, missionBudgetContinuationText } = require('./mission');
|
|
328
|
+
const selected = selectCodexGoalMission(root);
|
|
329
|
+
const mission = selected?.mission || null;
|
|
330
|
+
if (!mission) return null;
|
|
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}`;
|
|
336
|
+
if (!objective || !next) return null;
|
|
337
|
+
return `The move: ${objective} - next: ${next}`;
|
|
338
|
+
} catch {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
200
342
|
|
|
201
|
-
|
|
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));
|
|
202
398
|
}
|
|
203
399
|
|
|
204
400
|
function currentJournalPath(root = process.cwd()) {
|
|
@@ -216,8 +412,26 @@ function renderDefaultNow(root = process.cwd()) {
|
|
|
216
412
|
const openTodoCount = countOpenWorkItems(root, todoPath);
|
|
217
413
|
const inboxCount = countMatches(journalPath, /^-\s+\*\*I\d+:/gm);
|
|
218
414
|
const taskReceiptCount = countTaskReceiptsToday(root);
|
|
219
|
-
const
|
|
220
|
-
const
|
|
415
|
+
const missionReceiptCount = countMissionReceiptsToday(root);
|
|
416
|
+
const completedCount = taskReceiptCount + missionReceiptCount || countJournalCompletedReceipts(journalPath);
|
|
417
|
+
const generated = formatLocalTimestamp();
|
|
418
|
+
const moveLine = currentMissionMoveLine(root);
|
|
419
|
+
const whatMattersNow = moveLine
|
|
420
|
+
? `${moveLine}\n\n- Run the named next action and leave proof before choosing another.`
|
|
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` : '';
|
|
221
435
|
|
|
222
436
|
return `# now
|
|
223
437
|
|
|
@@ -228,8 +442,12 @@ Last updated: ${generated}
|
|
|
228
442
|
|
|
229
443
|
## What Matters Now
|
|
230
444
|
|
|
231
|
-
|
|
445
|
+
${whatMattersNow}
|
|
446
|
+
|
|
447
|
+
## While You Were Away
|
|
232
448
|
|
|
449
|
+
${whileAway}
|
|
450
|
+
${needsYou}
|
|
233
451
|
## Current Priority
|
|
234
452
|
|
|
235
453
|
- Keep the workspace coherent and useful for the next human or agent.
|
|
@@ -241,16 +459,6 @@ Last updated: ${generated}
|
|
|
241
459
|
- Inbox items today: ${inboxCount}
|
|
242
460
|
- Completed receipts today: ${completedCount}
|
|
243
461
|
|
|
244
|
-
## Watchouts
|
|
245
|
-
|
|
246
|
-
- Do not treat old logs as current truth unless this file links to them.
|
|
247
|
-
- Do not create motion for its own sake.
|
|
248
|
-
- If facts conflict, surface the conflict and cite the receipts.
|
|
249
|
-
|
|
250
|
-
## Next Move
|
|
251
|
-
|
|
252
|
-
- Read \`atris/MAP.md\`, \`atris/TODO.md\`, and today's journal only as needed for the task in front of you.
|
|
253
|
-
|
|
254
462
|
## Receipts
|
|
255
463
|
|
|
256
464
|
- \`atris/MAP.md\`
|
|
@@ -265,7 +473,7 @@ function renderPortfolioNow(root = process.cwd()) {
|
|
|
265
473
|
throw new Error('atris/ folder not found. Run "atris init" first.');
|
|
266
474
|
}
|
|
267
475
|
|
|
268
|
-
const generated =
|
|
476
|
+
const generated = formatLocalTimestamp();
|
|
269
477
|
const lines = workspaces.map((workspace) => {
|
|
270
478
|
const heading = readFirstHeading(workspace.mapPath) || workspace.slug;
|
|
271
479
|
const todoCount = countOpenWorkItems(workspace.root, workspace.todoPath);
|
|
@@ -421,10 +629,21 @@ module.exports = {
|
|
|
421
629
|
CAREER_XP_RECEIPTS_PATH,
|
|
422
630
|
ensureNowFile,
|
|
423
631
|
formatLocalDate,
|
|
632
|
+
formatLocalTimestamp,
|
|
424
633
|
countJournalCompletedReceipts,
|
|
425
634
|
countOpenWorkItems,
|
|
426
635
|
countOpenTodoItems,
|
|
636
|
+
countMissionReceiptsToday,
|
|
427
637
|
countTaskReceiptsToday,
|
|
638
|
+
currentMissionMoveLine,
|
|
639
|
+
compactMissionCommand,
|
|
640
|
+
compactCommitSubject,
|
|
641
|
+
completeMissionObjective,
|
|
642
|
+
landedCommitLines,
|
|
643
|
+
nextOwnerActionLine,
|
|
644
|
+
todayMissionReceiptLines,
|
|
645
|
+
todayTaskReceiptLines,
|
|
646
|
+
truncateLine,
|
|
428
647
|
findChildWorkspaces,
|
|
429
648
|
isGeneratedNowFile,
|
|
430
649
|
nowAtris,
|