atris 3.57.3 → 3.58.5
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/README.md +12 -1
- package/atris/skills/clawhub/member-runtime/SKILL.md +9 -9
- package/atris/skills/create-member/SKILL.md +16 -13
- package/atris/skills/design/SKILL.md +27 -4
- package/atris/skills/engines/SKILL.md +57 -13
- package/atris/skills/x-search/SKILL.md +13 -5
- package/atris/skills/youtube/SKILL.md +39 -8
- package/atris/team/brainstormer/MEMBER.md +2 -2
- package/atris/team/executor/MEMBER.md +3 -3
- package/atris/team/launcher/MEMBER.md +4 -4
- package/atris/team/navigator/MEMBER.md +3 -3
- package/atris/team/researcher/MEMBER.md +2 -2
- package/atris/team/validator/MEMBER.md +1 -1
- package/atris.md +14 -0
- package/ax +157 -24
- package/bin/atris.js +79 -31
- package/commands/aeo.js +4 -4
- package/commands/agents.js +1 -1
- package/commands/align.js +12 -12
- package/commands/analytics.js +3 -3
- package/commands/app.js +5 -5
- package/commands/ask.js +175 -0
- package/commands/auth.js +7 -7
- package/commands/autoland.js +29 -5
- package/commands/autopilot-front.js +6 -6
- package/commands/autopilot.js +90 -90
- package/commands/avail.js +5 -5
- package/commands/bench.js +63 -1
- package/commands/browse.js +2 -2
- package/commands/business.js +12 -12
- package/commands/card.js +2 -2
- package/commands/clean.js +13 -13
- package/commands/close.js +297 -15
- package/commands/compile.js +13 -13
- package/commands/computer.js +94 -27
- package/commands/console.js +5 -5
- package/commands/decide.js +1 -1
- package/commands/deck.js +9 -9
- package/commands/drive.js +4 -4
- package/commands/engine.js +173 -19
- package/commands/errors.js +3 -3
- package/commands/experiments.js +18 -1
- package/commands/feed.js +2 -2
- package/commands/feedback.js +4 -4
- package/commands/fleet.js +12 -12
- package/commands/game.js +1 -1
- package/commands/guide.js +49 -0
- package/commands/improve.js +19 -17
- package/commands/init.js +67 -19
- package/commands/interview.js +7 -7
- package/commands/land.js +40 -15
- package/commands/learn.js +12 -12
- package/commands/lesson.js +2 -2
- package/commands/log.js +1 -1
- package/commands/loops.js +4 -4
- package/commands/member.js +75 -50
- package/commands/mission.js +97 -98
- package/commands/one-lap.js +1 -1
- package/commands/pack.js +74 -8
- package/commands/plugin.js +6 -6
- package/commands/probe.js +9 -9
- package/commands/pull.js +35 -35
- package/commands/pulse.js +1 -1
- package/commands/push.js +21 -21
- package/commands/rainmaker.js +1 -1
- package/commands/recap.js +7 -7
- package/commands/reel.js +2 -2
- package/commands/release.js +3 -3
- package/commands/report.js +1 -1
- package/commands/review.js +5 -5
- package/commands/revisions.js +1 -1
- package/commands/run.js +1 -1
- package/commands/scout.js +3 -3
- package/commands/security-review.js +7 -7
- package/commands/serve.js +9 -9
- package/commands/setup.js +1 -1
- package/commands/sign.js +4 -4
- package/commands/signup.js +4 -4
- package/commands/site.js +8 -3
- package/commands/skill.js +6 -6
- package/commands/slop.js +18 -18
- package/commands/social.js +3 -3
- package/commands/soul.js +14 -14
- package/commands/spaceship.js +1 -1
- package/commands/status.js +2 -2
- package/commands/strings.js +13 -13
- package/commands/study.js +4 -4
- package/commands/sync.js +8 -8
- package/commands/task.js +50 -25
- package/commands/teach.js +2 -2
- package/commands/team.js +1 -1
- package/commands/theme.js +2 -2
- package/commands/tree.js +34 -0
- package/commands/truth.js +7 -7
- package/commands/verify.js +12 -12
- package/commands/visualize.js +2 -2
- package/commands/workflow.js +97 -40
- package/commands/worktree.js +57 -1
- package/commands/write.js +9 -9
- package/commands/x-search.js +304 -15
- package/commands/xp.js +6 -3
- package/commands/youtube.js +916 -65
- package/lib/accept-verify-gate.js +3 -3
- package/lib/activity-stream.js +1 -1
- package/lib/apply-gate.js +13 -0
- package/lib/auto-accept-certified.js +28 -12
- package/lib/autoland.js +6 -6
- package/lib/bench/engines.js +59 -8
- package/lib/bench/report.js +1 -1
- package/lib/bench/runner.js +204 -5
- package/lib/bench/tree-render.js +76 -0
- package/lib/card.js +1 -1
- package/lib/chat-log-scan.js +1 -1
- package/lib/claude-boot-block.js +2 -0
- package/lib/deck-compose.js +1 -1
- package/lib/deck-history.js +2 -2
- package/lib/deck-layout.js +1 -1
- package/lib/deck-review.js +5 -5
- package/lib/deck-schema.js +1 -1
- package/lib/default-verifier.js +1 -1
- package/lib/developer-api.js +3 -0
- package/lib/engine-ask.js +66 -9
- package/lib/engine-registry.js +15 -2
- package/lib/file-ops.js +1 -1
- package/lib/fleet.js +71 -35
- package/lib/html-render.js +1 -1
- package/lib/intents.js +172 -0
- package/lib/journal.js +1 -1
- package/lib/known-commands.js +2 -2
- package/lib/land-green.js +364 -0
- package/lib/lesson-contradiction.js +2 -2
- package/lib/lesson-preflight.js +1 -1
- package/lib/manifest.js +5 -5
- package/lib/member-alive.js +9 -5
- package/lib/memory-view.js +3 -3
- package/lib/mission-protected-lane.js +1 -1
- package/lib/mission-root.js +2 -2
- package/lib/orb-context.js +10 -10
- package/lib/pack-capabilities.js +861 -3
- package/lib/permission-grants.js +2 -2
- package/lib/policy-lessons.js +6 -6
- package/lib/pulse.js +8 -8
- package/lib/receipt-evidence.js +1 -1
- package/lib/reel.js +1 -1
- package/lib/review-integrity.js +1 -1
- package/lib/runner-command.js +35 -5
- package/lib/scorecard.js +4 -4
- package/lib/security-scan.js +5 -5
- package/lib/self-drive.js +1 -1
- package/lib/site-publish.js +372 -0
- package/lib/site.js +1 -1
- package/lib/slides-deck.js +2 -2
- package/lib/state-detection.js +2 -2
- package/lib/sync-telemetry.js +2 -2
- package/lib/task-db.js +17 -10
- package/lib/task-explanation.js +1 -1
- package/lib/task-proof.js +2 -2
- package/lib/task-receipt.js +3 -3
- package/lib/theme.js +12 -12
- package/lib/todo-fallback.js +3 -3
- package/lib/todo-sections.js +1 -1
- package/lib/tree-hash.js +79 -0
- package/lib/usage.js +1 -1
- package/lib/wish-delegate.js +1 -1
- package/lib/workspace-safety.js +4 -4
- package/lib/workspace-scaffold.js +3 -3
- package/package.json +1 -1
- package/scripts/det/concierge-bakeoff.sh +26 -0
- package/scripts/det/ytquote-repair.js +0 -1
- package/scripts/det/ytrail-race.js +0 -5
- package/scripts/member-operate.mjs +52 -14
- package/scripts/outbound-artifact-gate.js +0 -3
- package/utils/auth.js +0 -3
- package/utils/config.js +0 -1
- package/scripts/det/checklist-score.js +0 -191
package/lib/theme.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Brand themes
|
|
1
|
+
// Brand themes: a project defines its own theme in .atris/theme.json and every
|
|
2
2
|
// renderer (deck, HTML, site, memory view) uses it. Compounds like slop rules:
|
|
3
3
|
// describe your brand once, every deck and page is on-brand.
|
|
4
4
|
//
|
|
@@ -72,7 +72,7 @@ function writeStarterTheme(root = process.cwd()) {
|
|
|
72
72
|
return { file, already: false };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
// ---------- color math (WCAG contrast
|
|
75
|
+
// ---------- color math (WCAG contrast, the tasteful guardrail) ----------
|
|
76
76
|
function hexToRgb(hex) {
|
|
77
77
|
const h = String(hex == null ? '' : hex).trim().replace(/^#/, '');
|
|
78
78
|
const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h;
|
|
@@ -128,7 +128,7 @@ const FONT_PERSONALITIES = {
|
|
|
128
128
|
// the user picks a feeling; we keep the surface tasteful and let their accent lead.
|
|
129
129
|
const MOODS = {
|
|
130
130
|
editorial: {
|
|
131
|
-
blurb: 'warm, literary, considered
|
|
131
|
+
blurb: 'warm, literary, considered: Fraunces headlines on calm paper',
|
|
132
132
|
defaultMode: 'dark', fonts: 'editorial-serif',
|
|
133
133
|
swatches: ['#B5572E', '#D98E5C', '#9E3B2E', '#C08552'],
|
|
134
134
|
modes: {
|
|
@@ -137,7 +137,7 @@ const MOODS = {
|
|
|
137
137
|
},
|
|
138
138
|
},
|
|
139
139
|
technical: {
|
|
140
|
-
blurb: 'cool, precise, engineered
|
|
140
|
+
blurb: 'cool, precise, engineered: Space Grotesk on slate, mono accents',
|
|
141
141
|
defaultMode: 'dark', fonts: 'clean-sans',
|
|
142
142
|
swatches: ['#3B82F6', '#06B6D4', '#6366F1', '#14B8A6'],
|
|
143
143
|
modes: {
|
|
@@ -146,7 +146,7 @@ const MOODS = {
|
|
|
146
146
|
},
|
|
147
147
|
},
|
|
148
148
|
noir: {
|
|
149
|
-
blurb: 'high-contrast, near-black, one electric accent
|
|
149
|
+
blurb: 'high-contrast, near-black, one electric accent: confident and stark',
|
|
150
150
|
defaultMode: 'dark', forceMode: 'dark', fonts: 'clean-sans',
|
|
151
151
|
swatches: ['#C8FF00', '#FF2D78', '#FFB000', '#7DD3FC'],
|
|
152
152
|
modes: {
|
|
@@ -154,7 +154,7 @@ const MOODS = {
|
|
|
154
154
|
},
|
|
155
155
|
},
|
|
156
156
|
paper: {
|
|
157
|
-
blurb: 'calm, light, low-key
|
|
157
|
+
blurb: 'calm, light, low-key: ink on cream, nothing shouting',
|
|
158
158
|
defaultMode: 'light', forceMode: 'light', fonts: 'editorial-serif',
|
|
159
159
|
swatches: ['#2F4858', '#5B7553', '#B5572E', '#6B4E71'],
|
|
160
160
|
modes: {
|
|
@@ -162,7 +162,7 @@ const MOODS = {
|
|
|
162
162
|
},
|
|
163
163
|
},
|
|
164
164
|
vivid: {
|
|
165
|
-
blurb: 'saturated, playful, energetic
|
|
165
|
+
blurb: 'saturated, playful, energetic: a bold accent that carries the page',
|
|
166
166
|
defaultMode: 'dark', fonts: 'clean-sans',
|
|
167
167
|
swatches: ['#FF5C5C', '#8B5CF6', '#10B981', '#F59E0B'],
|
|
168
168
|
modes: {
|
|
@@ -207,16 +207,16 @@ function buildTheme(answers = {}) {
|
|
|
207
207
|
});
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
// readability guardrail
|
|
210
|
+
// readability guardrail: human messages for low-contrast choices (empty array = clean)
|
|
211
211
|
function themeWarnings(theme) {
|
|
212
212
|
const c = normalizeTheme(theme).color;
|
|
213
213
|
const warn = [];
|
|
214
214
|
const body = contrastRatio(c.ink, c.bg);
|
|
215
|
-
if (body < 4.5) warn.push(`body text (ink on bg) is ${body.toFixed(1)}:1
|
|
215
|
+
if (body < 4.5) warn.push(`body text (ink on bg) is ${body.toFixed(1)}:1, below the 4.5:1 readable floor`);
|
|
216
216
|
const onAcc = contrastRatio(c.onAccent, c.accent);
|
|
217
|
-
if (onAcc < 4.5) warn.push(`text on the accent is ${onAcc.toFixed(1)}:1
|
|
217
|
+
if (onAcc < 4.5) warn.push(`text on the accent is ${onAcc.toFixed(1)}:1, below 4.5:1`);
|
|
218
218
|
const accentBg = contrastRatio(c.accent, c.bg);
|
|
219
|
-
if (accentBg < 2.0) warn.push(`the accent barely separates from the background (${accentBg.toFixed(1)}:1)
|
|
219
|
+
if (accentBg < 2.0) warn.push(`the accent barely separates from the background (${accentBg.toFixed(1)}:1), pick a bolder color`);
|
|
220
220
|
return warn;
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -230,7 +230,7 @@ function upsertProjectTheme(name, theme, root = process.cwd(), recipe = null) {
|
|
|
230
230
|
if (fs.existsSync(file)) {
|
|
231
231
|
let raw;
|
|
232
232
|
try { raw = JSON.parse(fs.readFileSync(file, 'utf8')); }
|
|
233
|
-
catch { const e = new Error(`${PROJECT_THEME_FILE} is not valid JSON
|
|
233
|
+
catch { const e = new Error(`${PROJECT_THEME_FILE} is not valid JSON, fix or remove it before saving`); e.code = 'EBADTHEME'; throw e; }
|
|
234
234
|
if (raw && raw.themes && typeof raw.themes === 'object') themes = { ...raw.themes };
|
|
235
235
|
else if (isValidThemeShape(raw)) themes[raw.name || 'brand'] = { name: raw.name, color: raw.color, fonts: raw.fonts };
|
|
236
236
|
}
|
package/lib/todo-fallback.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// the shim in lib/todo.js can fall back to it when the SQLite store is empty
|
|
3
3
|
// (or when ATRIS_TASK_DB is not enabled).
|
|
4
4
|
//
|
|
5
|
-
// Do not add new callers. Use lib/todo.js (the shim)
|
|
5
|
+
// Do not add new callers. Use lib/todo.js (the shim), it merges DB + markdown.
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
@@ -32,9 +32,9 @@ function tagsFromText(text) {
|
|
|
32
32
|
function cleanTaskTitle(text) {
|
|
33
33
|
const raw = String(text || '').trim();
|
|
34
34
|
const withoutTags = raw.replace(/\s*\[[\w-]+\]/g, '').trim();
|
|
35
|
-
const bold = withoutTags.match(/^\*\*(.+?)\*\*\s*(?:[
|
|
35
|
+
const bold = withoutTags.match(/^\*\*(.+?)\*\*\s*(?:[\u2014-]\s*)?(.*)$/);
|
|
36
36
|
if (!bold) return withoutTags;
|
|
37
|
-
return [bold[1], bold[2]].filter(Boolean).join('
|
|
37
|
+
return [bold[1], bold[2]].filter(Boolean).join(' \u2014 ').trim();
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function parseSection(content, sectionName) {
|
package/lib/todo-sections.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// commands/brain.js (CLI-288); centralizing it here so a third copy can't drift.
|
|
6
6
|
//
|
|
7
7
|
// Headings may carry trailing decoration ("## In Progress 🔄", "## Completed ✅"),
|
|
8
|
-
// so detection uses \b (not \s*$) and section names match by prefix
|
|
8
|
+
// so detection uses \b (not \s*$) and section names match by prefix: "In Progress 🔄"
|
|
9
9
|
// counts as "In Progress", while "Backlogged Notes" does NOT count as "Backlog".
|
|
10
10
|
|
|
11
11
|
const RENDERED_SECTION_RE = /^##\s+(Backlog|In Progress|Blocked|Completed)\b/m;
|
package/lib/tree-hash.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const TREE_HASH_SCHEMA = 'atris.tree_hash.v1';
|
|
8
|
+
const FIXED_FILES = [
|
|
9
|
+
'atris.md',
|
|
10
|
+
'atris/CLAUDE.md',
|
|
11
|
+
'atris/atris.md',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function optionalChildren(root, parent, filename) {
|
|
15
|
+
const directory = path.join(root, ...parent.split('/'));
|
|
16
|
+
let entries;
|
|
17
|
+
try {
|
|
18
|
+
entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (error && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) return [];
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
return entries.map((entry) => `${parent}/${entry.name}/${filename}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function optionalBytes(root, relativePath) {
|
|
27
|
+
try {
|
|
28
|
+
return fs.readFileSync(path.join(root, ...relativePath.split('/')));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) return null;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function computeTreeHash(root = process.cwd()) {
|
|
36
|
+
const workspaceRoot = path.resolve(root);
|
|
37
|
+
const stat = fs.statSync(workspaceRoot);
|
|
38
|
+
if (!stat.isDirectory()) throw new Error(`tree hash root is not a directory: ${workspaceRoot}`);
|
|
39
|
+
fs.accessSync(workspaceRoot, fs.constants.R_OK);
|
|
40
|
+
|
|
41
|
+
const paths = [
|
|
42
|
+
...FIXED_FILES,
|
|
43
|
+
...optionalChildren(workspaceRoot, 'atris/skills', 'SKILL.md'),
|
|
44
|
+
...optionalChildren(workspaceRoot, 'atris/team', 'MEMBER.md'),
|
|
45
|
+
].sort();
|
|
46
|
+
const manifest = [];
|
|
47
|
+
for (const relativePath of paths) {
|
|
48
|
+
const bytes = optionalBytes(workspaceRoot, relativePath);
|
|
49
|
+
if (bytes === null) continue;
|
|
50
|
+
manifest.push({
|
|
51
|
+
path: relativePath,
|
|
52
|
+
sha256: crypto.createHash('sha256').update(bytes).digest('hex'),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const hash = crypto.createHash('sha256')
|
|
56
|
+
.update(manifest.map((file) => `${file.path}\0${file.sha256}\n`).join(''))
|
|
57
|
+
.digest('hex');
|
|
58
|
+
return {
|
|
59
|
+
schema: TREE_HASH_SCHEMA,
|
|
60
|
+
hash,
|
|
61
|
+
short: hash.slice(0, 12),
|
|
62
|
+
files: manifest.length,
|
|
63
|
+
manifest,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function treeHashFor(root) {
|
|
68
|
+
try {
|
|
69
|
+
return computeTreeHash(root).hash;
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
TREE_HASH_SCHEMA,
|
|
77
|
+
computeTreeHash,
|
|
78
|
+
treeHashFor,
|
|
79
|
+
};
|
package/lib/usage.js
CHANGED
|
@@ -10,7 +10,7 @@ const USAGE_MAX_BYTES = 5 * 1024 * 1024;
|
|
|
10
10
|
|
|
11
11
|
// Usage telemetry used to write to `<cwd>/.atris/state/usage.jsonl`, so a
|
|
12
12
|
// command run from a subdirectory that already had a nested .atris (e.g.
|
|
13
|
-
// backend/) split its usage away from the workspace root's store
|
|
13
|
+
// backend/) split its usage away from the workspace root's store, the same
|
|
14
14
|
// footgun the mission and task stores hit. Resolve to the shared workspace
|
|
15
15
|
// root (spine-first -> git toplevel -> cwd) so usage lands with the rest of the
|
|
16
16
|
// state, whichever subdir the caller stood in. Falls back to the raw cwd if the
|
package/lib/wish-delegate.js
CHANGED
|
@@ -1749,7 +1749,7 @@ function explicitAnswerRef(value) {
|
|
|
1749
1749
|
return /^#\d+$/.test(text) || looksLikeWishId(text);
|
|
1750
1750
|
}
|
|
1751
1751
|
|
|
1752
|
-
// atris wish answer "your words"
|
|
1752
|
+
// atris wish answer "your words", answers the pending question of the wish
|
|
1753
1753
|
// that is waiting on you, no list numbers involved.
|
|
1754
1754
|
function answerWish(positionals, root = process.cwd(), options = {}) {
|
|
1755
1755
|
const parts = positionals.slice(1).map(String).filter((value) => value.trim());
|
package/lib/workspace-safety.js
CHANGED
|
@@ -27,7 +27,7 @@ function dangerousWorkspaceReason(dir) {
|
|
|
27
27
|
if (abs === p) return `the system path ${p}`;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// Reserved top-level folders inside the user's home
|
|
30
|
+
// Reserved top-level folders inside the user's home: never workspaces.
|
|
31
31
|
const homeReservedNames = new Set([
|
|
32
32
|
'Library', 'Applications', 'Documents', 'Downloads', 'Desktop',
|
|
33
33
|
'Pictures', 'Music', 'Movies', 'Public', 'Sites', 'Dropbox',
|
|
@@ -51,20 +51,20 @@ function safeFallbackDir(slug, cwd) {
|
|
|
51
51
|
|
|
52
52
|
// Resolve an outputDir, auto-relocating to a safe fallback if the originally
|
|
53
53
|
// chosen path is dangerous. Non-technical users don't need to know about
|
|
54
|
-
// mkdir/cd
|
|
54
|
+
// mkdir/cd: atris picks a safe folder and tells them where it landed.
|
|
55
55
|
function resolveSafeOutputDir(requested, { slug, cwd = process.cwd(), op = 'use' } = {}) {
|
|
56
56
|
const reason = dangerousWorkspaceReason(requested);
|
|
57
57
|
if (!reason) return { dir: path.resolve(requested), relocated: false };
|
|
58
58
|
|
|
59
59
|
const fallback = safeFallbackDir(slug, cwd);
|
|
60
60
|
console.log('');
|
|
61
|
-
console.log(` ${requested} is ${reason}
|
|
61
|
+
console.log(` ${requested} is ${reason}, not safe to ${op}.`);
|
|
62
62
|
console.log(` Using ${fallback} instead.`);
|
|
63
63
|
console.log('');
|
|
64
64
|
return { dir: fallback, relocated: true, originalReason: reason };
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// Hard-refuse variant
|
|
67
|
+
// Hard-refuse variant, used by push where we can't auto-relocate (the
|
|
68
68
|
// source has to be where the user actually has their files).
|
|
69
69
|
function assertSafeWorkspaceRoot(dir, { slug, op } = {}) {
|
|
70
70
|
const reason = dangerousWorkspaceReason(dir);
|
|
@@ -18,7 +18,7 @@ function todoPlaceholder() {
|
|
|
18
18
|
|
|
19
19
|
## Backlog
|
|
20
20
|
|
|
21
|
-
- **T1:** Generate MAP.md
|
|
21
|
+
- **T1:** Generate MAP.md, scan codebase, create navigation index with file:line refs
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -37,7 +37,7 @@ function todoPlaceholder() {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
function firstJournalMarkdown(today) {
|
|
40
|
-
return `# Log
|
|
40
|
+
return `# Log: ${today}
|
|
41
41
|
|
|
42
42
|
## Completed ✅
|
|
43
43
|
|
|
@@ -49,7 +49,7 @@ function firstJournalMarkdown(today) {
|
|
|
49
49
|
|
|
50
50
|
## Backlog
|
|
51
51
|
|
|
52
|
-
- **T1:** Generate MAP.md
|
|
52
|
+
- **T1:** Generate MAP.md, scan codebase, create navigation index with file:line refs
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# concierge bakeoff: does a fresh-install agent translate plain english into
|
|
3
|
+
# atris moves on its own? usage: concierge-bakeoff.sh <engine> <project-dir>
|
|
4
|
+
# engine: opencode | devin. logs land in <project-dir>/bakeoff/<n>.log
|
|
5
|
+
set -u
|
|
6
|
+
engine="$1"; dir="$2"; logdir=/tmp/bakeoff-logs/$engine; mkdir -p "$logdir"
|
|
7
|
+
export PATH=/tmp/atris-shim:$PATH
|
|
8
|
+
i=0
|
|
9
|
+
while IFS= read -r prompt; do
|
|
10
|
+
i=$((i+1)); log="$logdir/$i.log"
|
|
11
|
+
echo "prompt: $prompt" > "$log"
|
|
12
|
+
start=$(date +%s)
|
|
13
|
+
case "$engine" in
|
|
14
|
+
opencode) (cd "$dir" && perl -e 'alarm shift; exec @ARGV' 420 opencode run --model opencode/muse-spark-1.3-contributor-free "$prompt" </dev/null >>"$log" 2>&1); code=$? ;;
|
|
15
|
+
devin) (cd "$dir" && perl -e 'alarm shift; exec @ARGV' 420 devin -p --model swe-1-7 -- "$prompt" </dev/null >>"$log" 2>&1); code=$? ;;
|
|
16
|
+
*) echo "unknown engine" >&2; exit 2 ;;
|
|
17
|
+
esac
|
|
18
|
+
echo "exit=$code seconds=$(( $(date +%s) - start ))" >> "$log"
|
|
19
|
+
hits=$(grep -o 'atris \(guide\|next\|engine\|spaceship\|plan\|moves\|improve\|task\|atris\.md\)[^ "]*' "$log" | sort | uniq -c | tr '\n' ';')
|
|
20
|
+
told=$(grep -c '^`atris [a-z]' "$log")
|
|
21
|
+
echo "$engine #$i exit=$code atris-calls=[$hits] told-user-to-run=$told"
|
|
22
|
+
done <<'PROMPTS'
|
|
23
|
+
what should I do next on this project?
|
|
24
|
+
use a free model so we don't burn credits
|
|
25
|
+
keep going on this while I'm away tonight
|
|
26
|
+
PROMPTS
|
|
@@ -179,14 +179,9 @@ if (require.main === module) {
|
|
|
179
179
|
|
|
180
180
|
module.exports = {
|
|
181
181
|
DEFAULT_URL,
|
|
182
|
-
DEFAULT_ENGINES,
|
|
183
182
|
DEFAULT_TIMEOUT_MS,
|
|
184
183
|
parseArgs,
|
|
185
184
|
parseEvalLine,
|
|
186
|
-
createDefaultRunner,
|
|
187
|
-
pickWinner,
|
|
188
|
-
formatTable,
|
|
189
|
-
formatVerdict,
|
|
190
185
|
runRace,
|
|
191
186
|
main,
|
|
192
187
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Contract (lib/member-alive.js runMemberOperateScript):
|
|
5
5
|
// node scripts/member-operate.mjs <member> --json --max-wall <60..1800>
|
|
6
|
-
// --execute --confirm-autonomy-policy [--agent claude] [--model X] [--
|
|
6
|
+
// --execute --confirm-autonomy-policy [--agent claude] [--model X] [--shared-checkout]
|
|
7
7
|
// stdout: final JSON only (last line wins). stderr: live progress, prefixed
|
|
8
8
|
// with ATRIS_MEMBER_OPERATE_PROGRESS\t so the alive loop can stream phases.
|
|
9
9
|
//
|
|
@@ -39,12 +39,40 @@ function finish(result) {
|
|
|
39
39
|
function collectJsonSignals(text) {
|
|
40
40
|
// member run / mission run print JSON payloads along the way; harvest the
|
|
41
41
|
// fields the alive loop cares about without depending on exact shapes.
|
|
42
|
-
const signals = { receipt_path: null, needs_user: false, summary: null };
|
|
42
|
+
const signals = { receipt_path: null, needs_user: false, summary: null, failed: false, reason: null, detail: null, mission_started: false, execution_result: false };
|
|
43
|
+
let buffer = '';
|
|
44
|
+
let depth = 0;
|
|
45
|
+
let quoted = false;
|
|
46
|
+
let escaped = false;
|
|
43
47
|
for (const line of String(text || '').split(/\r?\n/)) {
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
if (!buffer && !line.trimStart().startsWith('{')) continue;
|
|
49
|
+
buffer += line + '\n';
|
|
50
|
+
for (const character of line) {
|
|
51
|
+
if (quoted) {
|
|
52
|
+
if (escaped) escaped = false;
|
|
53
|
+
else if (character === '\\') escaped = true;
|
|
54
|
+
else if (character === '"') quoted = false;
|
|
55
|
+
} else if (character === '"') quoted = true;
|
|
56
|
+
else if (character === '{') depth++;
|
|
57
|
+
else if (character === '}') depth--;
|
|
58
|
+
}
|
|
59
|
+
if (depth > 0) continue;
|
|
46
60
|
try {
|
|
47
|
-
const parsed = JSON.parse(
|
|
61
|
+
const parsed = JSON.parse(buffer);
|
|
62
|
+
const failedTick = parsed.action === 'mission_run' && Array.isArray(parsed.ticks)
|
|
63
|
+
? parsed.ticks.find((tick) => ['errored', 'failed'].includes(tick.status)
|
|
64
|
+
|| tick.claude?.ok === false || tick.atris2?.ok === false)
|
|
65
|
+
: null;
|
|
66
|
+
const missionErrored = parsed.action === 'mission_run'
|
|
67
|
+
&& ['errored', 'failed'].includes(parsed.mission?.last_tick_status);
|
|
68
|
+
if (parsed.ok === false || failedTick || missionErrored) {
|
|
69
|
+
signals.failed = true;
|
|
70
|
+
signals.reason ||= parsed.reason || parsed.error || failedTick?.reason || 'operate_failed';
|
|
71
|
+
signals.detail ||= parsed.detail || failedTick?.claude?.summary || failedTick?.atris2?.error || null;
|
|
72
|
+
}
|
|
73
|
+
if (parsed.action === 'mission_started') signals.mission_started = true;
|
|
74
|
+
else if (parsed.action === 'mission_run') signals.execution_result ||= Number(parsed.ran_ticks) > 0;
|
|
75
|
+
else if (parsed.executed === true || parsed.result || parsed.receipt_path) signals.execution_result = true;
|
|
48
76
|
if (parsed.receipt_path) signals.receipt_path = parsed.receipt_path;
|
|
49
77
|
if (parsed.mission?.receipt_path) signals.receipt_path = parsed.mission.receipt_path;
|
|
50
78
|
if (parsed.needs_user === true) signals.needs_user = true;
|
|
@@ -52,8 +80,12 @@ function collectJsonSignals(text) {
|
|
|
52
80
|
if (landing?.changed) signals.summary = landing.changed;
|
|
53
81
|
else if (parsed.summary) signals.summary = parsed.summary;
|
|
54
82
|
} catch {
|
|
55
|
-
//
|
|
83
|
+
// A log line that resembles JSON is not a result.
|
|
56
84
|
}
|
|
85
|
+
buffer = '';
|
|
86
|
+
depth = 0;
|
|
87
|
+
quoted = false;
|
|
88
|
+
escaped = false;
|
|
57
89
|
}
|
|
58
90
|
return signals;
|
|
59
91
|
}
|
|
@@ -103,6 +135,7 @@ if (!atrisBin) {
|
|
|
103
135
|
const runArgs = [atrisBin, 'member', 'run', member, '--json', '--max-wall', String(maxWall)];
|
|
104
136
|
if (agent === 'claude') runArgs.push('--runner', 'claude');
|
|
105
137
|
if (model) runArgs.push('--model', model);
|
|
138
|
+
if (args.includes('--shared-checkout')) runArgs.push('--shared-checkout');
|
|
106
139
|
|
|
107
140
|
progress({ kind: 'phase', text: `Dispatching one bounded ${member} slice (wall cap ${maxWall}s).` });
|
|
108
141
|
|
|
@@ -113,14 +146,16 @@ const child = spawn(process.execPath, runArgs, {
|
|
|
113
146
|
});
|
|
114
147
|
|
|
115
148
|
let output = '';
|
|
116
|
-
|
|
149
|
+
let errors = '';
|
|
150
|
+
const forward = (chunk, isError = false) => {
|
|
117
151
|
const text = chunk.toString();
|
|
118
|
-
|
|
152
|
+
if (isError) errors += text;
|
|
153
|
+
else output += text;
|
|
119
154
|
// Keep stdout clean for the final JSON; the human-visible stream is stderr.
|
|
120
155
|
process.stderr.write(text);
|
|
121
156
|
};
|
|
122
157
|
child.stdout.on('data', forward);
|
|
123
|
-
child.stderr.on('data', forward);
|
|
158
|
+
child.stderr.on('data', (chunk) => forward(chunk, true));
|
|
124
159
|
|
|
125
160
|
const wallTimer = setTimeout(() => {
|
|
126
161
|
progress({ kind: 'phase', text: `Wall cap ${maxWall}s reached; stopping the slice.` });
|
|
@@ -130,17 +165,20 @@ const wallTimer = setTimeout(() => {
|
|
|
130
165
|
|
|
131
166
|
child.on('close', (code) => {
|
|
132
167
|
clearTimeout(wallTimer);
|
|
133
|
-
const signals = collectJsonSignals(output);
|
|
134
|
-
const ok = code === 0;
|
|
168
|
+
const signals = collectJsonSignals(output + '\n' + errors);
|
|
169
|
+
const ok = code === 0 && !signals.failed;
|
|
170
|
+
const planned = ok && !signals.execution_result;
|
|
135
171
|
finish({
|
|
136
172
|
ok,
|
|
137
|
-
reason: ok ? 'operate_complete' : 'operate_failed',
|
|
173
|
+
reason: planned ? signals.mission_started ? 'mission_started' : 'no_execution_evidence' : ok ? 'operate_complete' : signals.reason || 'operate_failed',
|
|
174
|
+
...(planned ? { status: 'planned' } : {}),
|
|
175
|
+
...(signals.detail ? { detail: signals.detail } : {}),
|
|
138
176
|
member,
|
|
139
|
-
executed:
|
|
177
|
+
executed: !planned,
|
|
140
178
|
exit_code: code,
|
|
141
179
|
max_wall_seconds: maxWall,
|
|
142
180
|
needs_user: signals.needs_user,
|
|
143
|
-
receipt_path: signals.receipt_path,
|
|
181
|
+
receipt_path: planned ? null : signals.receipt_path,
|
|
144
182
|
summary: signals.summary,
|
|
145
183
|
});
|
|
146
184
|
});
|
package/utils/auth.js
CHANGED
|
@@ -760,11 +760,9 @@ module.exports = {
|
|
|
760
760
|
promptUser,
|
|
761
761
|
validateAccessToken,
|
|
762
762
|
refreshAccessToken,
|
|
763
|
-
refreshProviderHint,
|
|
764
763
|
performTokenRefresh,
|
|
765
764
|
ensureValidCredentials,
|
|
766
765
|
isAuthFailure,
|
|
767
|
-
printAuthRequired,
|
|
768
766
|
abortOnAuthFailure,
|
|
769
767
|
fetchMyAgents,
|
|
770
768
|
displayAccountSummary,
|
|
@@ -774,7 +772,6 @@ module.exports = {
|
|
|
774
772
|
listProfiles,
|
|
775
773
|
deleteProfile,
|
|
776
774
|
profileNameFromEmail,
|
|
777
|
-
autoSaveProfile,
|
|
778
775
|
// Per-terminal sessions
|
|
779
776
|
getTerminalSessionId,
|
|
780
777
|
getSessionsDir,
|