atris 3.30.8 → 3.31.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 +16 -3
- package/FOR_AGENTS.md +81 -0
- package/README.md +4 -2
- package/atris/atris.md +51 -19
- package/atris/skills/README.md +1 -0
- package/atris/skills/blocks/SKILL.md +134 -0
- package/atris/skills/clawhub/philosophy-of-work/SKILL.md +56 -0
- package/atris/skills/youtube/SKILL.md +31 -11
- package/atris.md +7 -0
- package/ax +367 -93
- package/bin/atris.js +317 -155
- package/commands/autoland.js +319 -0
- package/commands/autopilot.js +94 -4
- package/commands/business.js +1 -1
- package/commands/clean.js +72 -9
- package/commands/codex-goal.js +72 -22
- package/commands/computer.js +48 -3
- package/commands/gm.js +1 -1
- package/commands/harvest.js +179 -0
- package/commands/init.js +1 -1
- package/commands/land.js +442 -0
- package/commands/loop-front.js +122 -4
- package/commands/member.js +519 -19
- package/commands/mission.js +3659 -282
- package/commands/play.js +1 -1
- package/commands/pulse.js +65 -7
- package/commands/run.js +3 -3
- package/commands/strings.js +301 -0
- package/commands/task.js +575 -102
- package/commands/truth.js +170 -0
- package/commands/xp.js +32 -8
- package/commands/youtube.js +72 -5
- package/decks/README.md +6 -12
- package/lib/auto-accept-certified.js +10 -0
- package/lib/autoland.js +283 -0
- package/lib/context-gatherer.js +0 -8
- package/lib/mission-artifact.js +504 -0
- package/lib/mission-room.js +846 -0
- package/lib/mission-runtime-loop.js +320 -0
- package/lib/next-moves.js +212 -6
- package/lib/pulse.js +74 -1
- package/lib/runner-command.js +20 -8
- package/lib/runs-prune.js +242 -0
- package/lib/task-proof.js +1 -1
- package/package.json +3 -3
- package/decks/atris-seed-pitch-v3.json +0 -118
- package/decks/atris-seed-pitch-v4-skeleton.json +0 -106
- package/decks/atris-seed-pitch-v5.json +0 -109
- package/decks/atris-seed-pitch-v6.json +0 -137
- package/decks/atris-seed-pitch-v7.json +0 -133
- package/decks/mark-pincus-narrative.json +0 -102
- package/decks/mark-pincus-sourcery.json +0 -94
- package/decks/yash-applied-compute-detailed.json +0 -150
- package/decks/yash-applied-compute-generalist.json +0 -82
- package/decks/yash-applied-compute-narrative.json +0 -54
- package/lib/ax-chat-input.js +0 -164
- package/lib/ax-goal.js +0 -307
- package/lib/ax-prefs.js +0 -63
- package/lib/ax-shimmer.js +0 -63
package/bin/atris.js
CHANGED
|
@@ -65,6 +65,7 @@ const {
|
|
|
65
65
|
apiRequestJson, streamProChat, spawnClaudeCodeSession,
|
|
66
66
|
DEFAULT_CLIENT_ID, DEFAULT_USER_AGENT,
|
|
67
67
|
} = require('../utils/api');
|
|
68
|
+
const missionRuntime = require('../lib/mission-runtime-loop');
|
|
68
69
|
|
|
69
70
|
// Bind DI wrappers (utils/auth uses dependency injection for apiRequestJson)
|
|
70
71
|
const validateAccessToken = (token) => _validateAccessToken(token, apiRequestJson);
|
|
@@ -200,10 +201,14 @@ function loadActiveMissions(workspaceDir) {
|
|
|
200
201
|
owner: m.owner || '?',
|
|
201
202
|
objective: m.objective || '',
|
|
202
203
|
status,
|
|
204
|
+
created_at: m.created_at || null,
|
|
205
|
+
updated_at: m.updated_at || null,
|
|
206
|
+
completed_at: m.completed_at || null,
|
|
203
207
|
verifier: m.verifier || null,
|
|
204
208
|
verifier_passed: (m.verifier_result && m.verifier_result.passed) === true,
|
|
205
209
|
next_action: m.next_action || '',
|
|
206
210
|
lane: m.lane || null,
|
|
211
|
+
runner: m.runner || null,
|
|
207
212
|
});
|
|
208
213
|
}
|
|
209
214
|
// Most recently started first (rough — relies on insertion order from reversed walk)
|
|
@@ -213,6 +218,93 @@ function loadActiveMissions(workspaceDir) {
|
|
|
213
218
|
}
|
|
214
219
|
}
|
|
215
220
|
|
|
221
|
+
function readAtrisGoalState(workspaceDir) {
|
|
222
|
+
try {
|
|
223
|
+
const file = path.join(workspaceDir, '.atris', 'state', 'atris_goal.json');
|
|
224
|
+
if (!fs.existsSync(file)) return null;
|
|
225
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
226
|
+
return parsed?.goal || null;
|
|
227
|
+
} catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function currentAtrisGoal(workspaceDir) {
|
|
233
|
+
const activeMissions = loadActiveMissions(workspaceDir);
|
|
234
|
+
const stored = readAtrisGoalState(workspaceDir);
|
|
235
|
+
if (stored && stored.objective) {
|
|
236
|
+
const mission = activeMissions.find((item) => item.id === stored.mission_id) || null;
|
|
237
|
+
return {
|
|
238
|
+
...stored,
|
|
239
|
+
mission_status: mission?.status || stored.mission_status,
|
|
240
|
+
created_at: stored.created_at || mission?.created_at || null,
|
|
241
|
+
updated_at: stored.updated_at || mission?.updated_at || null,
|
|
242
|
+
completed_at: stored.completed_at || mission?.completed_at || null,
|
|
243
|
+
next_command: stored.next_command || mission?.next_action || null,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const mission = activeMissions[0] || null;
|
|
247
|
+
if (!mission) return null;
|
|
248
|
+
return {
|
|
249
|
+
objective: mission.objective,
|
|
250
|
+
mission_id: mission.id,
|
|
251
|
+
mission_status: mission.status,
|
|
252
|
+
owner: mission.owner,
|
|
253
|
+
runner: mission.runner || 'mission',
|
|
254
|
+
created_at: mission.created_at,
|
|
255
|
+
updated_at: mission.updated_at,
|
|
256
|
+
completed_at: mission.completed_at,
|
|
257
|
+
next_command: mission.next_action || `atris mission tick ${mission.id} --summary "<what changed>"`,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function goalElapsedSeconds(goal) {
|
|
262
|
+
const started = Date.parse(goal?.created_at || '');
|
|
263
|
+
if (!Number.isFinite(started)) return null;
|
|
264
|
+
const ended = Date.parse(goal?.completed_at || '') || Date.now();
|
|
265
|
+
return Math.max(0, Math.floor((ended - started) / 1000));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function formatGoalDuration(seconds) {
|
|
269
|
+
if (!Number.isFinite(seconds)) return null;
|
|
270
|
+
const total = Math.max(0, Math.floor(seconds));
|
|
271
|
+
const hours = Math.floor(total / 3600);
|
|
272
|
+
const minutes = Math.floor((total % 3600) / 60);
|
|
273
|
+
const secs = total % 60;
|
|
274
|
+
if (hours > 0) return `${hours}h ${minutes}m`;
|
|
275
|
+
if (minutes > 0) return `${minutes}m ${secs}s`;
|
|
276
|
+
return `${secs}s`;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function goalAchieved(goal) {
|
|
280
|
+
return ['complete', 'completed', 'achieved'].includes(String(goal?.mission_status || goal?.status || '').toLowerCase());
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function printAtrisGoalBanner(workspaceDir = process.cwd(), label = 'Atris goal') {
|
|
284
|
+
if (process.env.ATRIS_SHOW_GOAL_BANNER !== '1' && process.env.AX_SHOW_GOAL_BANNER !== '1') return null;
|
|
285
|
+
const goal = currentAtrisGoal(workspaceDir);
|
|
286
|
+
if (!goal) return null;
|
|
287
|
+
if (String(goal.runner || '').trim().toLowerCase() === 'codex_goal') return null;
|
|
288
|
+
const objective = String(goal.objective || '').length > 92
|
|
289
|
+
? `${String(goal.objective).slice(0, 89)}...`
|
|
290
|
+
: String(goal.objective || '');
|
|
291
|
+
console.log(`${label}: ${objective}`);
|
|
292
|
+
if (goal.mission_id || goal.mission_status || goal.runner) {
|
|
293
|
+
const elapsed = formatGoalDuration(goalElapsedSeconds(goal));
|
|
294
|
+
const parts = [
|
|
295
|
+
goal.mission_id || '?',
|
|
296
|
+
goal.mission_status || '?',
|
|
297
|
+
goal.runner || 'mission',
|
|
298
|
+
];
|
|
299
|
+
if (elapsed) parts.push(`elapsed ${elapsed}`);
|
|
300
|
+
parts.push(`achieved ${goalAchieved(goal) ? 'yes' : 'no'}`);
|
|
301
|
+
console.log(`Mission: ${parts.join(' · ')}`);
|
|
302
|
+
}
|
|
303
|
+
if (goal.next_command) console.log(`Next: ${goal.next_command}`);
|
|
304
|
+
console.log('');
|
|
305
|
+
return goal;
|
|
306
|
+
}
|
|
307
|
+
|
|
216
308
|
function showSearchHelp() {
|
|
217
309
|
console.log('Usage: atris search <keyword>');
|
|
218
310
|
console.log('Example: atris search auth');
|
|
@@ -376,6 +468,7 @@ function showHelp() {
|
|
|
376
468
|
console.log(' analytics - Show recent productivity from journals');
|
|
377
469
|
console.log(' search - Search journal history (atris search <keyword>)');
|
|
378
470
|
console.log(' clean - Housekeeping (stale tasks, archive journals, broken refs)');
|
|
471
|
+
console.log(' harvest - Find bugs and next actions from receipts, run logs, and thinking');
|
|
379
472
|
console.log(' verify - Validate work is done (tests, MAP.md, changes)');
|
|
380
473
|
console.log(' task - Local agent task plane (atomic claims, TODO import)');
|
|
381
474
|
console.log(' mission - Goal + loop + member owner + verifier + receipt');
|
|
@@ -393,8 +486,10 @@ function showHelp() {
|
|
|
393
486
|
console.log(' autopilot - Guided loop that can clarify TODOs and run plan → do → review');
|
|
394
487
|
console.log(' improve - Run one paid RL tick (POST /api/improve, deducts credits)');
|
|
395
488
|
console.log(' worktree - Isolated Git worktrees plus guarded ship/merge for parallel agents');
|
|
489
|
+
console.log(' land - The landing: what is actually done vs still in the air; --reap backs up + clears overdue');
|
|
490
|
+
console.log(' autoland - Approve the policy once; certified work lands itself, you keep irreversible calls');
|
|
396
491
|
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
397
|
-
console.log(' youtube - Process YouTube videos with
|
|
492
|
+
console.log(' youtube - Process YouTube videos with timestamped transcript-first analysis');
|
|
398
493
|
console.log('');
|
|
399
494
|
console.log('Experiments:');
|
|
400
495
|
console.log(' experiments init [slug] - Prepare atris/experiments/ or scaffold a pack');
|
|
@@ -739,22 +834,27 @@ function showServeHelp() {
|
|
|
739
834
|
|
|
740
835
|
function showLoopHelp() {
|
|
741
836
|
console.log('');
|
|
742
|
-
console.log('Usage: atris loop [
|
|
837
|
+
console.log('Usage: atris loop [add|start|status|report|stop|wiki] [options]');
|
|
743
838
|
console.log('');
|
|
744
839
|
console.log('Description:');
|
|
745
|
-
console.log('
|
|
746
|
-
console.log('');
|
|
747
|
-
console.log('
|
|
748
|
-
console.log('
|
|
749
|
-
console.log('
|
|
750
|
-
console.log(' --
|
|
751
|
-
console.log(' --
|
|
840
|
+
console.log(' One front door for the self-improvement loop. It reads ROADMAP.md,');
|
|
841
|
+
console.log(' runs bounded proof-backed work, and keeps wiki upkeep under loop wiki.');
|
|
842
|
+
console.log('');
|
|
843
|
+
console.log('Commands:');
|
|
844
|
+
console.log(' atris loop add "<task>" Put a bounded task into the loop queue.');
|
|
845
|
+
console.log(' atris loop start [--once] Run the local loop.');
|
|
846
|
+
console.log(' atris loop start --overnight Install the durable heartbeat.');
|
|
847
|
+
console.log(' atris loop status [--json] Show heartbeat, local runs, and next moves.');
|
|
848
|
+
console.log(' atris loop report [--json] Show proof of handled and queued loop work.');
|
|
849
|
+
console.log(' atris loop stop Remove the durable heartbeat.');
|
|
850
|
+
console.log(' atris loop wiki Run the wiki upkeep loop.');
|
|
851
|
+
console.log(' --help, -h Show this help.');
|
|
752
852
|
console.log('');
|
|
753
853
|
}
|
|
754
854
|
|
|
755
855
|
function showCleanHelp() {
|
|
756
856
|
console.log('');
|
|
757
|
-
console.log('Usage: atris clean [--dry-run]');
|
|
857
|
+
console.log('Usage: atris clean [--dry-run] [--json]');
|
|
758
858
|
console.log('');
|
|
759
859
|
console.log('Description:');
|
|
760
860
|
console.log(' Check workspace housekeeping: stale tasks, MAP.md refs, old journals,');
|
|
@@ -762,6 +862,7 @@ function showCleanHelp() {
|
|
|
762
862
|
console.log('');
|
|
763
863
|
console.log('Options:');
|
|
764
864
|
console.log(' --dry-run, -n Preview cleanup without changing files.');
|
|
865
|
+
console.log(' --json Print machine-readable cleanup results.');
|
|
765
866
|
console.log(' --help, -h Show this help.');
|
|
766
867
|
console.log('');
|
|
767
868
|
}
|
|
@@ -821,12 +922,12 @@ if (command === '2' && ['fast', 'pro'].includes(String(firstCommandArg || '').to
|
|
|
821
922
|
}
|
|
822
923
|
|
|
823
924
|
// Check if this is a known command or natural language input
|
|
824
|
-
const knownCommands = ['init', 'log', 'now', 'radar', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', 'plan', 'do', 'review', 'release',
|
|
925
|
+
const knownCommands = ['init', 'log', 'now', 'radar', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
|
|
825
926
|
'activate', '_activate', 'agent', 'chat', 'fast', 'ax', 'console', 'serve', 'login', 'logout', 'whoami', 'switch', 'use', 'accounts', '_resolve', '_profile-email', '_switch-session', 'shell-init', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
|
|
826
|
-
'clean', 'verify', 'search', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'plugin', 'experiments', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
|
|
827
|
-
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'probe', 'worktree', 'aeo', 'slop', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'xp', 'play', 'gm', 'x', 'recap', 'signup', 'clarity', 'moves',
|
|
927
|
+
'clean', 'harvest', 'verify', 'search', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'plugin', 'experiments', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
|
|
928
|
+
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'probe', 'worktree', 'land', 'autoland', 'aeo', 'slop', 'strings', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'xp', 'play', 'gm', 'x', 'recap', 'signup', 'clarity', 'moves',
|
|
828
929
|
'gmail', 'calendar', 'twitter', 'slack', 'imessage', 'integrations', 'setup', 'clean-workspace', 'cw',
|
|
829
|
-
'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'compile', 'spaceship'];
|
|
930
|
+
'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'compile', 'spaceship', 'truth'];
|
|
830
931
|
|
|
831
932
|
// Check if command is an atris.md spec file - triggers welcome visualization
|
|
832
933
|
function isSpecFile(cmd) {
|
|
@@ -848,7 +949,15 @@ if (command === '--version' || command === '-v' || process.argv.includes('--vers
|
|
|
848
949
|
// If no command OR command is not recognized, treat as natural language
|
|
849
950
|
// Voice-friendly aliases — natural language → command mapping
|
|
850
951
|
// Solves speech-to-text issues (inspired by gstack v0.14.6 voice-triggers)
|
|
952
|
+
const START_MISSION_OBJECTIVE = 'self improve goal after goal: pick one useful bounded mission from current Atris state, run proof, and continue only with real next work';
|
|
953
|
+
|
|
851
954
|
const voiceTriggers = {
|
|
955
|
+
'start': '_start',
|
|
956
|
+
'start now': '_start',
|
|
957
|
+
'go': '_start',
|
|
958
|
+
'keep going': '_start',
|
|
959
|
+
'keepgoing': '_start',
|
|
960
|
+
'keep-going': '_start',
|
|
852
961
|
'review my code': 'code-review',
|
|
853
962
|
'check my code': 'code-review',
|
|
854
963
|
'run a review': 'code-review',
|
|
@@ -873,7 +982,12 @@ const voiceTriggers = {
|
|
|
873
982
|
if (!command || !knownCommands.includes(command)) {
|
|
874
983
|
// Check voice triggers before falling through to natural language
|
|
875
984
|
const fullInput = process.argv.slice(2).join(' ').toLowerCase().trim();
|
|
876
|
-
const
|
|
985
|
+
const fullInputWithoutFlags = process.argv.slice(2)
|
|
986
|
+
.filter((arg, index, args) => !String(arg).startsWith('-') && !isOptionValue(args, index, RUNNER_FLAG_NAMES))
|
|
987
|
+
.join(' ')
|
|
988
|
+
.toLowerCase()
|
|
989
|
+
.trim();
|
|
990
|
+
const triggered = voiceTriggers[fullInput] || voiceTriggers[fullInputWithoutFlags];
|
|
877
991
|
if (triggered) {
|
|
878
992
|
command = triggered;
|
|
879
993
|
// Re-check — if it's now a known command, fall through to dispatch
|
|
@@ -1263,6 +1377,12 @@ function showWelcomeVisualization() {
|
|
|
1263
1377
|
: `${tasksInReview} waiting`;
|
|
1264
1378
|
console.log(` │ ⏳ Review: ${reviewText.padEnd(26)}│`);
|
|
1265
1379
|
}
|
|
1380
|
+
let landInfo = null;
|
|
1381
|
+
try { landInfo = require('../commands/land').landSummary(process.cwd()); } catch (err) { landInfo = null; }
|
|
1382
|
+
if (landInfo && landInfo.branches > 0) {
|
|
1383
|
+
const landText = `${landInfo.branches} in the air, ${landInfo.due} overdue`;
|
|
1384
|
+
console.log(` │ 🛬 Land: ${landText.padEnd(26)}│`);
|
|
1385
|
+
}
|
|
1266
1386
|
console.log(` │ 📝 Journal: ${(journalEntries + ' entries today').padEnd(26)}│`);
|
|
1267
1387
|
if (endgameState.slug !== 'unset' && endgameState.horizon) {
|
|
1268
1388
|
const endgameLine = endgameState.slug + ' — ' + endgameState.horizon;
|
|
@@ -1285,7 +1405,13 @@ function showWelcomeVisualization() {
|
|
|
1285
1405
|
if (tasksCertified > 0) {
|
|
1286
1406
|
console.log(` Ready. ${tasksCertified} certified await accept — run 'atris task reviews'.`);
|
|
1287
1407
|
} else {
|
|
1288
|
-
|
|
1408
|
+
let landHint = null;
|
|
1409
|
+
try { landHint = require('../commands/land').landSummary(process.cwd()); } catch (err) { landHint = null; }
|
|
1410
|
+
if (landHint && landHint.due > 0) {
|
|
1411
|
+
console.log(` Ready. ${landHint.due} overdue in the landing — run 'atris land --reap'.`);
|
|
1412
|
+
} else {
|
|
1413
|
+
console.log(` Ready. Run 'atris plan' to start.`);
|
|
1414
|
+
}
|
|
1289
1415
|
}
|
|
1290
1416
|
console.log('');
|
|
1291
1417
|
}
|
|
@@ -1306,6 +1432,40 @@ if (command === 'init') {
|
|
|
1306
1432
|
console.error(`✗ Error: ${error.message || error}`);
|
|
1307
1433
|
process.exit(1);
|
|
1308
1434
|
});
|
|
1435
|
+
} else if (command === '_start') {
|
|
1436
|
+
const args = process.argv.slice(3);
|
|
1437
|
+
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
1438
|
+
console.log('');
|
|
1439
|
+
console.log('Usage: atris start [options]');
|
|
1440
|
+
console.log('');
|
|
1441
|
+
console.log('Starts the durable mission loop for one useful self-improvement mission.');
|
|
1442
|
+
console.log('');
|
|
1443
|
+
console.log('Options:');
|
|
1444
|
+
console.log(' --json Print the mission route without starting it.');
|
|
1445
|
+
console.log(' --owner X Override mission owner.');
|
|
1446
|
+
console.log(' --cadence X Override mission cadence.');
|
|
1447
|
+
console.log('');
|
|
1448
|
+
process.exit(0);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
if (args.includes('--json')) {
|
|
1452
|
+
console.log(JSON.stringify({
|
|
1453
|
+
ok: true,
|
|
1454
|
+
action: 'start_mission_run',
|
|
1455
|
+
route: `atris mission run "${START_MISSION_OBJECTIVE}"`,
|
|
1456
|
+
reason: 'casual_launch',
|
|
1457
|
+
objective: START_MISSION_OBJECTIVE,
|
|
1458
|
+
expected_loop: 'mission_run',
|
|
1459
|
+
}, null, 2));
|
|
1460
|
+
process.exit(0);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
Promise.resolve(require('../commands/mission').missionCommand(['run', START_MISSION_OBJECTIVE, ...args]))
|
|
1464
|
+
.then(() => process.exit(process.exitCode || 0))
|
|
1465
|
+
.catch((error) => {
|
|
1466
|
+
console.error(`✗ Start failed: ${error.message || error}`);
|
|
1467
|
+
process.exit(1);
|
|
1468
|
+
});
|
|
1309
1469
|
} else if (command === 'task') {
|
|
1310
1470
|
// SQLite-backed task plane. ~/.atris/tasks.db, gitignored, per-workspace.
|
|
1311
1471
|
Promise.resolve(require('../commands/task').run(process.argv.slice(3)))
|
|
@@ -1313,7 +1473,7 @@ if (command === 'init') {
|
|
|
1313
1473
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1314
1474
|
} else if (command === 'mission') {
|
|
1315
1475
|
Promise.resolve(require('../commands/mission').missionCommand(process.argv.slice(3)))
|
|
1316
|
-
.then(() => process.exit(0))
|
|
1476
|
+
.then(() => process.exit(process.exitCode || 0))
|
|
1317
1477
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1318
1478
|
} else if (command === 'pulse') {
|
|
1319
1479
|
// Pulse: durable overnight self-improvement heartbeat (OS cron) for atris-cli.
|
|
@@ -1329,11 +1489,24 @@ if (command === 'init') {
|
|
|
1329
1489
|
Promise.resolve(require('../commands/worktree').worktreeCommand(process.argv.slice(3)))
|
|
1330
1490
|
.then((code) => process.exit(code || 0))
|
|
1331
1491
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1492
|
+
} else if (command === 'autoland') {
|
|
1493
|
+
Promise.resolve(require('../commands/autoland').autolandCommand(process.argv.slice(3)))
|
|
1494
|
+
.then((code) => process.exit(code || 0))
|
|
1495
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1496
|
+
} else if (command === 'land') {
|
|
1497
|
+
Promise.resolve(require('../commands/land').landCommand(process.argv.slice(3)))
|
|
1498
|
+
.then((code) => process.exit(code || 0))
|
|
1499
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1332
1500
|
} else if (command === 'radar' || command === 'ctop') {
|
|
1333
1501
|
const radarArgs = command === 'ctop' ? ['--agents', ...process.argv.slice(3)] : process.argv.slice(3);
|
|
1334
1502
|
Promise.resolve(require('../commands/radar').radarCommand(radarArgs))
|
|
1335
1503
|
.then((code) => process.exit(code || 0))
|
|
1336
1504
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1505
|
+
} else if (command === 'truth') {
|
|
1506
|
+
// Truth: one table rolling up mission state, tasks, feature proof receipts, and loop heartbeats.
|
|
1507
|
+
Promise.resolve(require('../commands/truth').truthCommand(process.argv.slice(3)))
|
|
1508
|
+
.then((code) => process.exit(code || 0))
|
|
1509
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1337
1510
|
} else if (command === 'codex-goal') {
|
|
1338
1511
|
Promise.resolve(require('../commands/codex-goal').codexGoalCommand(process.argv.slice(3)))
|
|
1339
1512
|
.then(() => process.exit(process.exitCode || 0))
|
|
@@ -1830,7 +2003,14 @@ if (command === 'init') {
|
|
|
1830
2003
|
process.exit(0);
|
|
1831
2004
|
}
|
|
1832
2005
|
const dryRun = process.argv.includes('--dry-run') || process.argv.includes('-n');
|
|
1833
|
-
|
|
2006
|
+
const json = process.argv.includes('--json');
|
|
2007
|
+
require('../commands/clean').cleanAtris({ dryRun, json });
|
|
2008
|
+
} else if (command === 'harvest') {
|
|
2009
|
+
Promise.resolve(require('../commands/harvest').harvestCommand(process.argv.slice(3)))
|
|
2010
|
+
.catch((err) => {
|
|
2011
|
+
console.error(err.message || err);
|
|
2012
|
+
process.exit(1);
|
|
2013
|
+
});
|
|
1834
2014
|
} else if (command === 'verify') {
|
|
1835
2015
|
const args = process.argv.slice(3);
|
|
1836
2016
|
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
@@ -2038,8 +2218,8 @@ if (command === 'init') {
|
|
|
2038
2218
|
showLoopHelp();
|
|
2039
2219
|
process.exit(0);
|
|
2040
2220
|
}
|
|
2041
|
-
require('../commands/loop').
|
|
2042
|
-
.then(() => process.exit(0))
|
|
2221
|
+
Promise.resolve(require('../commands/loop-front').loopFront(args))
|
|
2222
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2043
2223
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2044
2224
|
} else if (command === 'clean-workspace' || command === 'cw') {
|
|
2045
2225
|
const { cleanWorkspace } = require('../commands/workspace-clean');
|
|
@@ -2065,6 +2245,12 @@ if (command === 'init') {
|
|
|
2065
2245
|
Promise.resolve(require('../commands/slop').slopCommand(process.argv.slice(3)))
|
|
2066
2246
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2067
2247
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2248
|
+
} else if (command === 'strings') {
|
|
2249
|
+
// Strings: content design system from live code (no LLM). Extracts UI strings, flags variants,
|
|
2250
|
+
// enforces preferred terms at the gate. Exit 1 = variants/banned terms found, for CI + the gate.
|
|
2251
|
+
Promise.resolve(require('../commands/strings').stringsCommand(process.argv.slice(3)))
|
|
2252
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2253
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2068
2254
|
} else if (command === 'security-review' || command === 'secure') {
|
|
2069
2255
|
// Security review: deterministic secrets/PII/code-risk scan (no LLM). Exit 1 = HIGH finding,
|
|
2070
2256
|
// for the autopilot/mission/CI gate + a SOC 2 evidence artifact via --json.
|
|
@@ -2318,13 +2504,12 @@ async function agentAtris() {
|
|
|
2318
2504
|
// Respect -h / --help / help before any auth/state work
|
|
2319
2505
|
const firstArg = process.argv[3];
|
|
2320
2506
|
if (firstArg === '-h' || firstArg === '--help' || firstArg === 'help') {
|
|
2321
|
-
console.log('Usage: atris agent [doctor|
|
|
2507
|
+
console.log('Usage: atris agent [doctor|spawn|spawns|spawn-status]');
|
|
2322
2508
|
console.log('');
|
|
2323
2509
|
console.log(' Pick which cloud agent to chat with from this workspace.');
|
|
2324
2510
|
console.log(' Run `atris agent spawn <role> --task "..."` to create a worker request.');
|
|
2325
2511
|
console.log(' Run `atris agent spawns` to list worker requests.');
|
|
2326
2512
|
console.log(' Run `atris agent doctor` to verify local AI CLIs can see Atris context.');
|
|
2327
|
-
console.log(' Run `atris agent dogfood --live` to smoke-test Devin/Droid with GLM 5.2.');
|
|
2328
2513
|
console.log(' Requires `atris login` first.');
|
|
2329
2514
|
console.log('');
|
|
2330
2515
|
console.log(' After selecting, use: atris chat ["message"]');
|
|
@@ -2335,7 +2520,19 @@ async function agentAtris() {
|
|
|
2335
2520
|
agentDoctor();
|
|
2336
2521
|
}
|
|
2337
2522
|
if (firstArg === 'dogfood') {
|
|
2338
|
-
|
|
2523
|
+
// Internal diagnostic, gated off the public CLI. Operators use `atris agent doctor`.
|
|
2524
|
+
if (!process.env.ATRIS_INTERNAL_AGENT_DOGFOOD) {
|
|
2525
|
+
console.error('atris agent dogfood is an internal diagnostic and is not part of the public CLI.');
|
|
2526
|
+
console.error('Run `atris agent doctor` to verify local AI CLIs can see Atris context.');
|
|
2527
|
+
process.exit(1);
|
|
2528
|
+
}
|
|
2529
|
+
const dogfoodArgs = process.argv.slice(4);
|
|
2530
|
+
if (dogfoodArgs.includes('--help') || dogfoodArgs.includes('-h') || dogfoodArgs[0] === 'help') {
|
|
2531
|
+
console.log('Internal usage: atris agent dogfood [--live]');
|
|
2532
|
+
console.log(' Smoke-test Devin/Droid with GLM 5.2. Gated behind ATRIS_INTERNAL_AGENT_DOGFOOD.');
|
|
2533
|
+
process.exit(0);
|
|
2534
|
+
}
|
|
2535
|
+
const result = require('../commands/agent-spawn').agentDogfoodCommand(dogfoodArgs);
|
|
2339
2536
|
process.exit(result.ok ? 0 : 1);
|
|
2340
2537
|
}
|
|
2341
2538
|
if (firstArg === 'spawn') {
|
|
@@ -2359,6 +2556,8 @@ async function agentAtris() {
|
|
|
2359
2556
|
process.exit(1);
|
|
2360
2557
|
}
|
|
2361
2558
|
|
|
2559
|
+
printAtrisGoalBanner(process.cwd());
|
|
2560
|
+
|
|
2362
2561
|
// Check if logged in (with token refresh)
|
|
2363
2562
|
const ensured = await ensureValidCredentials();
|
|
2364
2563
|
if (ensured.error === 'not_logged_in' || !ensured.credentials?.token) {
|
|
@@ -2461,6 +2660,13 @@ async function chatAtris() {
|
|
|
2461
2660
|
process.exit(1);
|
|
2462
2661
|
}
|
|
2463
2662
|
|
|
2663
|
+
const missionIntent = missionRunIntentFromFastMessage(message);
|
|
2664
|
+
if (missionIntent) {
|
|
2665
|
+
process.exit(await runLocalFastMission(missionIntent));
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
printAtrisGoalBanner(process.cwd());
|
|
2669
|
+
|
|
2464
2670
|
// Check agent selected
|
|
2465
2671
|
const config = loadConfig();
|
|
2466
2672
|
if (!config.agent_id) {
|
|
@@ -2550,6 +2756,15 @@ async function chatInteractive(config, credentials) {
|
|
|
2550
2756
|
return;
|
|
2551
2757
|
}
|
|
2552
2758
|
|
|
2759
|
+
const missionIntent = missionRunIntentFromFastMessage(input);
|
|
2760
|
+
if (missionIntent) {
|
|
2761
|
+
console.log('');
|
|
2762
|
+
await runLocalFastMission(missionIntent);
|
|
2763
|
+
console.log('');
|
|
2764
|
+
rl.prompt();
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2553
2768
|
// Send to pro-chat
|
|
2554
2769
|
console.log('');
|
|
2555
2770
|
const apiUrl = getApiBaseUrl().replace(/\/api$/, '');
|
|
@@ -2598,6 +2813,78 @@ function atrisFastMessageFromArgs() {
|
|
|
2598
2813
|
return process.argv.slice(offset).join(' ').trim();
|
|
2599
2814
|
}
|
|
2600
2815
|
|
|
2816
|
+
function stripFastMissionQuotes(value) {
|
|
2817
|
+
const text = String(value || '').trim();
|
|
2818
|
+
if (text.length >= 2) {
|
|
2819
|
+
const first = text[0];
|
|
2820
|
+
const last = text[text.length - 1];
|
|
2821
|
+
if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
|
|
2822
|
+
return text.slice(1, -1).trim();
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
return text;
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
function extractFastMissionFlag(text, flagName) {
|
|
2829
|
+
const source = String(text || '');
|
|
2830
|
+
const inline = new RegExp(`(^|\\s)${flagName}=([^\\s]+)(?=\\s|$)`).exec(source);
|
|
2831
|
+
if (inline) {
|
|
2832
|
+
return {
|
|
2833
|
+
value: inline[2],
|
|
2834
|
+
text: `${source.slice(0, inline.index)}${inline[1] || ''}${source.slice(inline.index + inline[0].length)}`.replace(/\s+/g, ' ').trim(),
|
|
2835
|
+
};
|
|
2836
|
+
}
|
|
2837
|
+
const split = new RegExp(`(^|\\s)${flagName}\\s+([^\\s]+)(?=\\s|$)`).exec(source);
|
|
2838
|
+
if (split) {
|
|
2839
|
+
return {
|
|
2840
|
+
value: split[2],
|
|
2841
|
+
text: `${source.slice(0, split.index)}${split[1] || ''}${source.slice(split.index + split[0].length)}`.replace(/\s+/g, ' ').trim(),
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
return { value: null, text: source.trim() };
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
function missionRunIntentFromFastMessage(message) {
|
|
2848
|
+
return missionRuntime.missionRunIntentFromMessage(message);
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
function printFastMissionStartReceipt(payload) {
|
|
2852
|
+
const mission = payload?.mission || {};
|
|
2853
|
+
const goal = payload?.atris_goal_state?.goal || {};
|
|
2854
|
+
const receiptGoal = {
|
|
2855
|
+
...goal,
|
|
2856
|
+
objective: goal.objective || mission.objective,
|
|
2857
|
+
mission_id: goal.mission_id || mission.id,
|
|
2858
|
+
mission_status: goal.mission_status || mission.status,
|
|
2859
|
+
runner: goal.runner || mission.runner,
|
|
2860
|
+
created_at: goal.created_at || mission.created_at,
|
|
2861
|
+
updated_at: goal.updated_at || mission.updated_at,
|
|
2862
|
+
completed_at: goal.completed_at || mission.completed_at,
|
|
2863
|
+
next_command: goal.next_command || payload?.next_command || mission.next_action,
|
|
2864
|
+
};
|
|
2865
|
+
const elapsed = formatGoalDuration(goalElapsedSeconds(receiptGoal)) || '0s';
|
|
2866
|
+
|
|
2867
|
+
console.log('Atris mission started');
|
|
2868
|
+
console.log(`Goal: ${receiptGoal.objective || '?'}`);
|
|
2869
|
+
console.log(`Mission: ${receiptGoal.mission_id || '?'} · ${receiptGoal.mission_status || '?'} · ${receiptGoal.runner || 'atris2'}`);
|
|
2870
|
+
console.log(`Elapsed: ${elapsed}`);
|
|
2871
|
+
console.log(`Achieved: ${goalAchieved(receiptGoal) ? 'yes' : 'no'}`);
|
|
2872
|
+
if (receiptGoal.next_command) console.log(`Next: ${receiptGoal.next_command}`);
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2875
|
+
async function runLocalFastMission(intent) {
|
|
2876
|
+
const result = await missionRuntime.runRuntimeMissionLoop(intent, {
|
|
2877
|
+
cwd: process.cwd(),
|
|
2878
|
+
cliPath: __filename,
|
|
2879
|
+
onProgress: (line) => {
|
|
2880
|
+
if (/^pursuing /.test(line)) console.log('Pursuing goal...');
|
|
2881
|
+
else if (/^\[tick /.test(line)) console.log(line);
|
|
2882
|
+
},
|
|
2883
|
+
});
|
|
2884
|
+
console.log(result.text || 'Mission command failed.');
|
|
2885
|
+
return result.ok ? 0 : (result.status || 1);
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2601
2888
|
async function atrisFastChat() {
|
|
2602
2889
|
if (command === 'ax' && process.argv[3] !== 'fast') {
|
|
2603
2890
|
console.error('Usage: atris ax fast "message"');
|
|
@@ -2622,6 +2909,13 @@ async function atrisFastChat() {
|
|
|
2622
2909
|
process.exit(1);
|
|
2623
2910
|
}
|
|
2624
2911
|
|
|
2912
|
+
const missionIntent = missionRunIntentFromFastMessage(message);
|
|
2913
|
+
if (missionIntent) {
|
|
2914
|
+
process.exit(await runLocalFastMission(missionIntent));
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
printAtrisGoalBanner(process.cwd());
|
|
2918
|
+
|
|
2625
2919
|
const ensured = await ensureValidCredentials();
|
|
2626
2920
|
if (ensured.error === 'not_logged_in' || !ensured.credentials?.token) {
|
|
2627
2921
|
console.error('✗ Error: Not logged in. Run "atris login" first.');
|
|
@@ -2651,135 +2945,3 @@ async function atrisFastOnce(credentials, message) {
|
|
|
2651
2945
|
await streamProChat(endpoint, credentials.token, body);
|
|
2652
2946
|
console.log('\n\n✓ Complete\n');
|
|
2653
2947
|
}
|
|
2654
|
-
|
|
2655
|
-
async function atrisDevEntry(userInput = null) {
|
|
2656
|
-
// Load workspace context and present planning-ready state
|
|
2657
|
-
// userInput: optional task description for hot start
|
|
2658
|
-
const targetDir = path.join(process.cwd(), 'atris');
|
|
2659
|
-
|
|
2660
|
-
// Check if Atris is initialized
|
|
2661
|
-
if (!fs.existsSync(targetDir)) {
|
|
2662
|
-
console.log('');
|
|
2663
|
-
console.log('🚀 Welcome to Atris\n');
|
|
2664
|
-
console.log('Not initialized yet. Let\'s get started:\n');
|
|
2665
|
-
console.log(' → atris init Set up your workspace');
|
|
2666
|
-
console.log(' → atris help See all commands\n');
|
|
2667
|
-
return;
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
|
-
ensureLogDirectory();
|
|
2671
|
-
const { logFile, dateFormatted } = getLogPath();
|
|
2672
|
-
if (!fs.existsSync(logFile)) {
|
|
2673
|
-
createLogFile(logFile, dateFormatted);
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
|
-
// Load context
|
|
2677
|
-
const workspaceDir = process.cwd();
|
|
2678
|
-
const state = detectWorkspaceState(workspaceDir);
|
|
2679
|
-
const context = loadContext(workspaceDir);
|
|
2680
|
-
|
|
2681
|
-
// Detect existing features
|
|
2682
|
-
const featuresDir = path.join(targetDir, 'features');
|
|
2683
|
-
let existingFeatures = [];
|
|
2684
|
-
if (fs.existsSync(featuresDir)) {
|
|
2685
|
-
existingFeatures = fs.readdirSync(featuresDir)
|
|
2686
|
-
.filter(name => {
|
|
2687
|
-
const featurePath = path.join(featuresDir, name);
|
|
2688
|
-
return fs.statSync(featurePath).isDirectory() && !name.startsWith('_');
|
|
2689
|
-
});
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
console.log('');
|
|
2693
|
-
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
2694
|
-
console.log('│ Atris Mode │');
|
|
2695
|
-
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
2696
|
-
console.log('');
|
|
2697
|
-
console.log(`📅 ${dateFormatted}`);
|
|
2698
|
-
console.log('');
|
|
2699
|
-
|
|
2700
|
-
// Show existing features
|
|
2701
|
-
if (existingFeatures.length > 0) {
|
|
2702
|
-
console.log('📦 Features: ' + existingFeatures.join(', '));
|
|
2703
|
-
console.log('');
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
// Show active work
|
|
2707
|
-
if (context.inProgressFeatures.length > 0) {
|
|
2708
|
-
console.log('⚡ Active: ' + context.inProgressFeatures.join(', '));
|
|
2709
|
-
console.log('');
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
// Show inbox
|
|
2713
|
-
if (context.hasInbox && context.inboxItems.length > 0) {
|
|
2714
|
-
console.log(`📥 Inbox (${context.inboxItems.length}):`);
|
|
2715
|
-
context.inboxItems.slice(0, 3).forEach((item, i) => {
|
|
2716
|
-
const preview = item.length > 50 ? item.substring(0, 47) + '...' : item;
|
|
2717
|
-
console.log(` ${i + 1}. ${preview}`);
|
|
2718
|
-
});
|
|
2719
|
-
if (context.inboxItems.length > 3) {
|
|
2720
|
-
console.log(` ... and ${context.inboxItems.length - 3} more`);
|
|
2721
|
-
}
|
|
2722
|
-
console.log('');
|
|
2723
|
-
}
|
|
2724
|
-
|
|
2725
|
-
// Show recent completions
|
|
2726
|
-
const logContent = fs.existsSync(logFile) ? fs.readFileSync(logFile, 'utf8') : '';
|
|
2727
|
-
const completedMatch = logContent.match(/## Completed ✅\n([\s\S]*?)(?=\n##|$)/);
|
|
2728
|
-
if (completedMatch && completedMatch[1].trim()) {
|
|
2729
|
-
const completedItems = completedMatch[1].trim().split('\n')
|
|
2730
|
-
.filter(line => line.match(/^- \*\*C\d+:/))
|
|
2731
|
-
.slice(-2);
|
|
2732
|
-
if (completedItems.length > 0) {
|
|
2733
|
-
console.log('✅ Recent:');
|
|
2734
|
-
completedItems.forEach(item => {
|
|
2735
|
-
const match = item.match(/^- \*\*C\d+:\s*(.+)\*\*/);
|
|
2736
|
-
if (match) {
|
|
2737
|
-
const text = match[1].length > 50 ? match[1].substring(0, 47) + '...' : match[1];
|
|
2738
|
-
console.log(` • ${text}`);
|
|
2739
|
-
}
|
|
2740
|
-
});
|
|
2741
|
-
console.log('');
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
2746
|
-
console.log('atris — navigator agent');
|
|
2747
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
2748
|
-
console.log('');
|
|
2749
|
-
|
|
2750
|
-
if (userInput) {
|
|
2751
|
-
// Hot start - user provided task
|
|
2752
|
-
console.log('User wants:');
|
|
2753
|
-
console.log(`"${userInput}"`);
|
|
2754
|
-
console.log('');
|
|
2755
|
-
} else {
|
|
2756
|
-
// Cold start - no specific task
|
|
2757
|
-
console.log('Wait for user to describe what they want.');
|
|
2758
|
-
console.log('');
|
|
2759
|
-
}
|
|
2760
|
-
|
|
2761
|
-
console.log('⚠️ APPROVAL REQUIRED — Follow this workflow:');
|
|
2762
|
-
console.log('');
|
|
2763
|
-
console.log('STEP 1: Show ASCII visualization');
|
|
2764
|
-
console.log(' Create diagrams showing architecture/flow/UI');
|
|
2765
|
-
console.log(' SHOW diagrams to user and WAIT for approval.');
|
|
2766
|
-
console.log('');
|
|
2767
|
-
console.log('STEP 2: After approval, determine scope');
|
|
2768
|
-
if (existingFeatures.length > 0) {
|
|
2769
|
-
console.log(' Existing: ' + existingFeatures.join(', '));
|
|
2770
|
-
}
|
|
2771
|
-
console.log(' NEW feature → atris/features/[name]/idea.md + build.md + validate.md');
|
|
2772
|
-
console.log(' EXISTING → Update that feature\'s docs');
|
|
2773
|
-
console.log(' SIMPLE → TODO.md only');
|
|
2774
|
-
console.log('');
|
|
2775
|
-
console.log('STEP 3: Create/update docs');
|
|
2776
|
-
console.log(' idea.md = intent (any format)');
|
|
2777
|
-
console.log(' build.md = technical spec');
|
|
2778
|
-
console.log(' validate.md = proof it works (from _templates/validate.md.template)');
|
|
2779
|
-
console.log(' lessons.md = read past lessons before planning, write new ones after validating');
|
|
2780
|
-
console.log('');
|
|
2781
|
-
console.log('⛔ DO NOT execute — that\'s for "atris do"');
|
|
2782
|
-
console.log('');
|
|
2783
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
2784
|
-
console.log('');
|
|
2785
|
-
}
|