atris 3.38.0 → 3.41.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 +25 -6
- package/atris/PERSONA.md +8 -4
- package/atris.md +7 -0
- package/ax +2 -1
- package/bin/atris.js +31 -6
- package/commands/agent-spawn.js +13 -11
- package/commands/autoland.js +28 -77
- package/commands/bench.js +10 -12
- package/commands/business.js +345 -0
- package/commands/chat-scan.js +5 -7
- package/commands/codex-goal.js +8 -10
- package/commands/computer.js +20 -0
- package/commands/console.js +19 -3
- package/commands/decide.js +166 -0
- package/commands/deck.js +1 -4
- package/commands/drill.js +14 -24
- package/commands/engine.js +196 -8
- package/commands/gm.js +8 -6
- package/commands/harvest.js +1 -4
- package/commands/init.js +23 -3
- package/commands/land.js +8 -14
- package/commands/launchpad.js +1 -14
- package/commands/lifecycle.js +5 -5
- package/commands/log.js +55 -5
- package/commands/member.js +558 -574
- package/commands/mission.js +456 -237
- package/commands/pack.js +2746 -164
- package/commands/play.js +6 -4
- package/commands/probe.js +2 -2
- package/commands/pulse.js +15 -16
- package/commands/release.js +10 -9
- package/commands/router.js +5 -4
- package/commands/site-deploy.js +885 -0
- package/commands/site.js +11 -2
- package/commands/slop.js +14 -2
- package/commands/stream.js +4 -18
- package/commands/task.js +880 -558
- package/commands/taste.js +101 -0
- package/commands/team.js +176 -3
- package/commands/vercel.js +4 -2
- package/commands/voice.js +195 -0
- package/commands/watch.js +1 -22
- package/commands/wiki.js +1 -4
- package/commands/workflow.js +2 -2
- package/commands/worktree.js +1 -14
- package/commands/xp.js +27 -24
- package/lib/accept-verify-gate.js +5 -1
- package/lib/arg-parser.js +41 -0
- package/lib/auto-accept-certified.js +116 -1
- package/lib/autoland.js +66 -0
- package/lib/bench/runner.js +19 -1
- package/lib/context-gatherer.js +7 -1
- package/lib/engine-registry.js +141 -20
- package/lib/falsifier-probe.js +84 -0
- package/lib/fleet.js +65 -15
- package/lib/git-spawn.js +15 -0
- package/lib/json-file.js +37 -0
- package/lib/known-commands.js +2 -2
- package/lib/lesson-preflight.js +146 -0
- package/lib/loop-doctor.js +0 -2
- package/lib/mission-human-asks.js +28 -0
- package/lib/mission-protected-lane.js +4 -1
- package/lib/official-cli-integration.js +47 -2
- package/lib/orb-context.js +8 -1
- package/lib/pack-capabilities.js +685 -0
- package/lib/router-brain.js +51 -1
- package/lib/runner-command.js +0 -6
- package/lib/self-drive.js +44 -13
- package/lib/task-db.js +137 -3
- package/lib/task-decision.js +50 -0
- package/lib/taste-lessons.js +153 -0
- package/lib/tool-result-encode.js +17 -1
- package/lib/voice-gate.js +66 -0
- package/lib/wish-audit.js +1 -1
- package/lib/wish-delegate.js +1 -1
- package/lib/zip.js +95 -7
- package/package.json +2 -1
- package/templates/business-starter/persona.md +9 -0
package/commands/init.js
CHANGED
|
@@ -282,6 +282,7 @@ function initAtris() {
|
|
|
282
282
|
const printReadyCounts = () => {
|
|
283
283
|
console.log(`workspace files ready (${ready.workspace.size})`);
|
|
284
284
|
console.log(`team members ready (${ready.team.size})`);
|
|
285
|
+
console.log('more members are available with atris member create <name>');
|
|
285
286
|
console.log(`agent adapters ready (${ready.adapters.size})`);
|
|
286
287
|
console.log(`skills installed (${ready.skills.size})`);
|
|
287
288
|
};
|
|
@@ -601,8 +602,8 @@ function initAtris() {
|
|
|
601
602
|
|
|
602
603
|
|
|
603
604
|
// Copy team members (MEMBER.md format — directory per member with skills/tools/context)
|
|
604
|
-
const
|
|
605
|
-
|
|
605
|
+
const starterMembers = ['navigator', 'executor', 'validator', 'mission-lead', 'improver'];
|
|
606
|
+
starterMembers.forEach(name => {
|
|
606
607
|
const sourceFile = path.join(__dirname, '..', 'atris', 'team', name, 'MEMBER.md');
|
|
607
608
|
const targetMemberDir = path.join(teamDir, name);
|
|
608
609
|
const targetFile = path.join(targetMemberDir, 'MEMBER.md');
|
|
@@ -644,7 +645,7 @@ tools: []
|
|
|
644
645
|
# Insert persona, workflow, and rules below
|
|
645
646
|
`;
|
|
646
647
|
fs.writeFileSync(path.join(templateTargetDir, 'MEMBER.md'), templateContent);
|
|
647
|
-
markReady('
|
|
648
|
+
markReady('workspace', 'team/_template/MEMBER.md', '✓ Created team/_template/MEMBER.md');
|
|
648
649
|
}
|
|
649
650
|
|
|
650
651
|
// Detect project context and generate profile
|
|
@@ -676,6 +677,25 @@ atris atris.md
|
|
|
676
677
|
|
|
677
678
|
This is the Atris boot sequence. Show the output to the user, then respond naturally.
|
|
678
679
|
|
|
680
|
+
## The way of talking (every reply, no exceptions)
|
|
681
|
+
|
|
682
|
+
Talk like a person. This governs every message you send the operator: boot, status, summaries, everything.
|
|
683
|
+
|
|
684
|
+
- Plain words. Say what happened and what it means for the reader, cause and effect. Not the machinery.
|
|
685
|
+
- No task codes, branch names, commit hashes, PR numbers, or system nouns (worktree, verifier, projection, tick) in the message body. If the reader needs a command, put ONE copyable line at the end.
|
|
686
|
+
- No insider terms without defining them in the same breath. A sharp non-engineer must follow it on first read.
|
|
687
|
+
- Lead with the outcome. Complete sentences, one or two per paragraph, blank line between. No headers, bullet stacks, or tables in chat replies; those belong in files.
|
|
688
|
+
- Detail lives in files and receipts. Offer "want the detail?" instead of dumping it.
|
|
689
|
+
- No em dashes anywhere; use a comma, colon, or period.
|
|
690
|
+
- The test before sending: read it fried at 2am. If decoding takes work, rewrite it.
|
|
691
|
+
|
|
692
|
+
copy these shapes:
|
|
693
|
+
- **Status:** "The reply check is built. I am running the final checks now, so the result is not ready yet."
|
|
694
|
+
- **Landing:** "Replies now get a plain-language check before they reach you. The checks passed, and the change is ready."
|
|
695
|
+
- **Failure:** "The plain-language check could not run because its model was unavailable. Your reply still went through, so no work was blocked."
|
|
696
|
+
|
|
697
|
+
Canonical source: \`atris/atris.md\` \`## voice\`. This block is a copy for tools that only read \`AGENTS.md\`; if they differ, atris.md wins.
|
|
698
|
+
|
|
679
699
|
## Core Files
|
|
680
700
|
|
|
681
701
|
Atris is the source of truth. This file is only an adapter for tools that read
|
package/commands/land.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const {
|
|
4
|
-
|
|
3
|
+
const { runGit } = require('../lib/git-spawn');
|
|
5
4
|
const { listWorktrees, statusCounts } = require('./worktree');
|
|
6
5
|
|
|
7
6
|
const DEFAULT_TTL_DAYS = 7;
|
|
@@ -14,14 +13,6 @@ function countLabel(n, word) {
|
|
|
14
13
|
return `${n} ${word}${n === 1 ? '' : 's'}`;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
function runGit(args, { cwd = process.cwd(), check = true, maxBuffer } = {}) {
|
|
18
|
-
const result = spawnSync('git', args, { cwd, encoding: 'utf8', ...(maxBuffer ? { maxBuffer } : {}) });
|
|
19
|
-
if (check && result.status !== 0) {
|
|
20
|
-
throw new Error(`git ${args.join(' ')} failed: ${(result.stderr || result.stdout || '').trim()}`);
|
|
21
|
-
}
|
|
22
|
-
return result;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
16
|
function repoRoot(cwd = process.cwd()) {
|
|
26
17
|
const result = runGit(['rev-parse', '--show-toplevel'], { cwd, check: false });
|
|
27
18
|
if (result.status !== 0) return '';
|
|
@@ -614,7 +605,9 @@ function printReceipt(receipt) {
|
|
|
614
605
|
// fresh-grace keeps are healthy active work, not a call to action —
|
|
615
606
|
// "needs a human" on those trained readers to ignore the real ones.
|
|
616
607
|
for (const k of receipt.keptWorktrees || []) {
|
|
608
|
+
// The receipt keeps the raw codes; the human line speaks in sentences.
|
|
617
609
|
if (String(k).includes('(fresh_worktree_grace)')) console.log(` in use, left alone: ${k.replace(' (fresh_worktree_grace)', '')}`);
|
|
610
|
+
else if (String(k).includes('(current_checkout)')) console.log(` you are standing in it, left alone: ${k.replace(' (current_checkout)', '')}`);
|
|
618
611
|
else console.log(` ✋ kept, needs a human: ${k}`);
|
|
619
612
|
}
|
|
620
613
|
for (const m of receipt.keptMovedBranches || []) console.log(` moved since scan, left alone: ${m}`);
|
|
@@ -624,7 +617,8 @@ function printReceipt(receipt) {
|
|
|
624
617
|
console.log('');
|
|
625
618
|
}
|
|
626
619
|
|
|
627
|
-
|
|
620
|
+
// Preserve split-only parsing and its fallback for missing or falsey values.
|
|
621
|
+
function readFollowingFlag(args, name, fallback = '') {
|
|
628
622
|
const idx = args.indexOf(name);
|
|
629
623
|
if (idx === -1) return fallback;
|
|
630
624
|
return args[idx + 1] || fallback;
|
|
@@ -665,10 +659,10 @@ function landCommand(args = []) {
|
|
|
665
659
|
console.error('not a git repository');
|
|
666
660
|
return 1;
|
|
667
661
|
}
|
|
668
|
-
const ttlRaw =
|
|
662
|
+
const ttlRaw = readFollowingFlag(args, '--ttl', '');
|
|
669
663
|
const ttlParsed = Number(ttlRaw);
|
|
670
664
|
const ttlDays = ttlRaw !== '' && Number.isFinite(ttlParsed) && ttlParsed >= 0 ? ttlParsed : DEFAULT_TTL_DAYS;
|
|
671
|
-
const base =
|
|
665
|
+
const base = readFollowingFlag(args, '--base', '');
|
|
672
666
|
const json = args.includes('--json');
|
|
673
667
|
|
|
674
668
|
if (args.includes('--reap')) {
|
|
@@ -679,7 +673,7 @@ function landCommand(args = []) {
|
|
|
679
673
|
}
|
|
680
674
|
|
|
681
675
|
const lookupArgs = args[0] === 'status' ? args.slice(1) : args;
|
|
682
|
-
const name = lookupArgs.find((a) => !a.startsWith('-') && a !==
|
|
676
|
+
const name = lookupArgs.find((a) => !a.startsWith('-') && a !== readFollowingFlag(lookupArgs, '--ttl') && a !== readFollowingFlag(lookupArgs, '--base'));
|
|
683
677
|
if (name) {
|
|
684
678
|
const story = collectStory(root, name, { base });
|
|
685
679
|
if (!story) {
|
package/commands/launchpad.js
CHANGED
|
@@ -2,23 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const { hasFlag, readFlag } = require('../lib/arg-parser');
|
|
5
6
|
|
|
6
7
|
const ACTIVE_MISSION_STATUSES = new Set(['planning', 'running', 'ready']);
|
|
7
8
|
|
|
8
|
-
function hasFlag(args, name) {
|
|
9
|
-
return args.includes(name);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function readFlag(args, name, fallback = '') {
|
|
13
|
-
const prefix = `${name}=`;
|
|
14
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
15
|
-
const arg = String(args[i]);
|
|
16
|
-
if (arg === name && args[i + 1] && !String(args[i + 1]).startsWith('--')) return String(args[i + 1]);
|
|
17
|
-
if (arg.startsWith(prefix)) return arg.slice(prefix.length);
|
|
18
|
-
}
|
|
19
|
-
return fallback;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
9
|
function readJson(file) {
|
|
23
10
|
try {
|
|
24
11
|
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
package/commands/lifecycle.js
CHANGED
|
@@ -168,7 +168,7 @@ async function sleepAtris() {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
|
-
* Wake a sleeping workspace
|
|
171
|
+
* Wake a sleeping workspace: remote wake request, or local wake flag.
|
|
172
172
|
* @returns {Promise<void>}
|
|
173
173
|
*/
|
|
174
174
|
async function wakeAtris() {
|
|
@@ -179,7 +179,7 @@ async function wakeAtris() {
|
|
|
179
179
|
if (!slug || slug === '--help' || slug === '-h' || slug === 'help') {
|
|
180
180
|
console.log('Usage: atris wake [business|member] [--loop <loop-id>]');
|
|
181
181
|
console.log('');
|
|
182
|
-
console.log(' Wake a sleeping workspace.
|
|
182
|
+
console.log(' Wake a sleeping workspace. Wake signal sent; loops pick it up on their next pass.');
|
|
183
183
|
console.log(' Or flip a local member / member-loop switch awake.');
|
|
184
184
|
process.exit(0);
|
|
185
185
|
}
|
|
@@ -207,13 +207,13 @@ async function wakeAtris() {
|
|
|
207
207
|
console.log(`Waking business computer '${business.name || slug}'...`);
|
|
208
208
|
|
|
209
209
|
if (result.data && result.data.status === 'running' && result.data.endpoint) {
|
|
210
|
-
console.log(`Business computer '${business.name || slug}' is alive.
|
|
210
|
+
console.log(`Business computer '${business.name || slug}' is alive. Wake signal sent; loops pick it up on their next pass.`);
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
const running = await waitForBusinessComputer(creds.token, business);
|
|
215
215
|
if (running) {
|
|
216
|
-
console.log(`Business computer '${business.name || slug}' is alive.
|
|
216
|
+
console.log(`Business computer '${business.name || slug}' is alive. Wake signal sent; loops pick it up on their next pass.`);
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
219
219
|
|
|
@@ -246,7 +246,7 @@ async function wakeAtris() {
|
|
|
246
246
|
});
|
|
247
247
|
|
|
248
248
|
if (status.ok && status.data && status.data.status === 'running') {
|
|
249
|
-
console.log(`Workspace '${slug}' is alive.
|
|
249
|
+
console.log(`Workspace '${slug}' is alive. Wake signal sent; loops pick it up on their next pass.`);
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
252
|
}
|
package/commands/log.js
CHANGED
|
@@ -97,6 +97,56 @@ function readDigestSection(root, title, relativePath, maxLines = null) {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
// Splits a journal body into its ## groups so the digest can show
|
|
101
|
+
// completed / inbox / notes as short labeled blocks instead of a raw dump.
|
|
102
|
+
function journalGroups(lines) {
|
|
103
|
+
const groups = [];
|
|
104
|
+
let current = null;
|
|
105
|
+
for (const line of lines) {
|
|
106
|
+
const heading = line.match(/^##\s+(.+?)\s*$/);
|
|
107
|
+
if (heading) {
|
|
108
|
+
current = { heading: heading[1], lines: [] };
|
|
109
|
+
groups.push(current);
|
|
110
|
+
} else if (current) {
|
|
111
|
+
current.lines.push(line);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return groups;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function bulletCount(group) {
|
|
118
|
+
return group.lines.filter((line) => /^\s*-\s+/.test(line)).length;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function digestSummaryLine(date, sections) {
|
|
122
|
+
let completed = 0;
|
|
123
|
+
let inbox = 0;
|
|
124
|
+
for (const section of sections) {
|
|
125
|
+
for (const group of journalGroups(section.lines)) {
|
|
126
|
+
if (/^completed/i.test(group.heading)) completed += bulletCount(group);
|
|
127
|
+
else if (/^inbox/i.test(group.heading)) inbox += bulletCount(group);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const parts = [`${sections.length} log${sections.length === 1 ? '' : 's'}`];
|
|
131
|
+
if (completed) parts.push(`${completed} completed`);
|
|
132
|
+
if (inbox) parts.push(`${inbox} inbox`);
|
|
133
|
+
return `${date}: ${parts.join(', ')}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function renderDigestSection(section) {
|
|
137
|
+
const groups = journalGroups(section.lines);
|
|
138
|
+
if (!groups.length) {
|
|
139
|
+
return [`=== ${section.title} ===`, section.path, ...section.lines].join('\n');
|
|
140
|
+
}
|
|
141
|
+
const out = [`=== ${section.title} ===`, section.path];
|
|
142
|
+
for (const group of groups) {
|
|
143
|
+
const body = group.lines.filter((line) => line.trim() && line.trim() !== '---');
|
|
144
|
+
if (!body.length) continue;
|
|
145
|
+
out.push('', `${group.heading.toLowerCase()} (${bulletCount(group)})`, ...body);
|
|
146
|
+
}
|
|
147
|
+
return out.join('\n');
|
|
148
|
+
}
|
|
149
|
+
|
|
100
150
|
function logsDigest(args = [], options = {}) {
|
|
101
151
|
const root = options.cwd || process.cwd();
|
|
102
152
|
const date = digestDate(args);
|
|
@@ -125,11 +175,11 @@ function logsDigest(args = [], options = {}) {
|
|
|
125
175
|
} else if (sections.length === 0) {
|
|
126
176
|
console.log(`No logs for ${date} yet.`);
|
|
127
177
|
} else {
|
|
128
|
-
console.log(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
...
|
|
132
|
-
].join('\n'))
|
|
178
|
+
console.log([
|
|
179
|
+
digestSummaryLine(date, sections),
|
|
180
|
+
'',
|
|
181
|
+
...sections.map(renderDigestSection),
|
|
182
|
+
].join('\n'));
|
|
133
183
|
}
|
|
134
184
|
|
|
135
185
|
return payload;
|