atris 3.57.4 → 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 +55 -12
- package/atris/skills/x-search/SKILL.md +8 -6
- package/atris/skills/youtube/SKILL.md +37 -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 +153 -23
- package/bin/atris.js +78 -30
- 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 +3 -3
- 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 +90 -82
- 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 +1 -1
- package/commands/write.js +9 -9
- package/commands/x-search.js +89 -17
- package/commands/xp.js +6 -3
- package/commands/youtube.js +601 -48
- package/lib/accept-verify-gate.js +3 -3
- package/lib/activity-stream.js +1 -1
- 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 +45 -7
- 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/commands/avail.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Booking availability
|
|
4
|
+
* Booking availability: read/update the windows that power /book/{username}.
|
|
5
5
|
*
|
|
6
6
|
* atris avail # show current settings
|
|
7
7
|
* atris avail set --wake 2:30pm --sleep 9pm --where Ibiza --days all --apply
|
|
@@ -172,13 +172,13 @@ function summarizeHours(availableHours) {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// The booking link is the funnel: an operator shares /book/{username} so a
|
|
175
|
-
// stranger can pick a slot. With no claimed handle there is no link
|
|
175
|
+
// stranger can pick a slot. With no claimed handle there is no link, say so and
|
|
176
176
|
// name the fix instead of silently dropping the line.
|
|
177
177
|
function formatBookingLink(username, appBase) {
|
|
178
178
|
const handle = String(username || '').trim();
|
|
179
179
|
const base = String(appBase || '').replace(/\/+$/, '');
|
|
180
180
|
if (!handle) {
|
|
181
|
-
return ' link: none yet
|
|
181
|
+
return ' link: none yet, claim a handle with `atris signup` to get your /book link';
|
|
182
182
|
}
|
|
183
183
|
return ` link: ${base}/book/${handle}`;
|
|
184
184
|
}
|
|
@@ -263,7 +263,7 @@ async function setAvail(argv) {
|
|
|
263
263
|
console.log(summarizeHours(payload.available_hours));
|
|
264
264
|
|
|
265
265
|
if (!opts.apply) {
|
|
266
|
-
console.log('\n Dry run
|
|
266
|
+
console.log('\n Dry run, add --apply to push to your profile.');
|
|
267
267
|
return 0;
|
|
268
268
|
}
|
|
269
269
|
|
|
@@ -308,7 +308,7 @@ async function slotsAvail(argv) {
|
|
|
308
308
|
if (!username) {
|
|
309
309
|
const identity = await apiRequestJson('/identity/me', { method: 'GET', token });
|
|
310
310
|
if (!identity.ok || !identity.data?.username) {
|
|
311
|
-
console.error('Could not resolve username
|
|
311
|
+
console.error('Could not resolve username, pass --user keshav');
|
|
312
312
|
return 1;
|
|
313
313
|
}
|
|
314
314
|
username = identity.data.username;
|
package/commands/bench.js
CHANGED
|
@@ -8,9 +8,11 @@ const {
|
|
|
8
8
|
packMetadata,
|
|
9
9
|
readResultRecords,
|
|
10
10
|
runBench,
|
|
11
|
+
runBenchPair,
|
|
11
12
|
taskMetadata,
|
|
12
13
|
} = require('../lib/bench/runner');
|
|
13
14
|
const { buildBenchReport, renderBenchReportText } = require('../lib/bench/report');
|
|
15
|
+
const { materializeCandidate } = require('../lib/bench/tree-render');
|
|
14
16
|
const { hasFlag } = require('../lib/arg-parser');
|
|
15
17
|
|
|
16
18
|
function isAtrisCliRepo(cwd = process.cwd()) {
|
|
@@ -51,16 +53,32 @@ function readRepeatedFlag(args, name) {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
function printHelp() {
|
|
54
|
-
console.log('Usage: atris bench run [--pack <id>] [--engine <name>] [--task <id> ...] [--label baseline|candidate] [--experiment <id>] [--update-baseline] [--json]');
|
|
56
|
+
console.log('Usage: atris bench run [--pack <id>] [--engine <name>] [--model <id>] [--task <id> ...] [--label baseline|candidate] [--experiment <id>] [--update-baseline] [--json]');
|
|
57
|
+
console.log('Usage: atris bench pair --candidate <dir|git-ref> [--pack <id>] [--engine <name>] [--model <id>] [--task <id> ...] [--min-win-margin <n>] [--repeats <n>] [--current <dir>] [--json]');
|
|
55
58
|
console.log('Usage: atris bench results [--last N] [--json]');
|
|
56
59
|
console.log('Usage: atris bench tasks [--pack <id>] [--json]');
|
|
57
60
|
console.log('Usage: atris bench packs [--json]');
|
|
58
61
|
console.log('Usage: atris bench report [--pack agents-v1] [--json]');
|
|
62
|
+
console.log('packs: core-v1, agents-v1, harness-v1');
|
|
59
63
|
console.log('');
|
|
60
64
|
console.log('Bench runs product gates and only belongs in the atris CLI repo.');
|
|
61
65
|
console.log('Pass --here to allow running outside that repo.');
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
function pairScoreText(score) {
|
|
69
|
+
if (score === null) return 'could-not-run';
|
|
70
|
+
return score === 1 ? 'pass' : 'fail';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function printPairText(record) {
|
|
74
|
+
const width = Math.max(0, ...record.tasks.map((task) => task.id.length)) + 3;
|
|
75
|
+
for (const task of record.tasks) {
|
|
76
|
+
console.log(`${task.id.padEnd(width)}current ${pairScoreText(task.current)} candidate ${pairScoreText(task.candidate)} ${task.outcome}`);
|
|
77
|
+
}
|
|
78
|
+
console.log(`wins ${record.wins} losses ${record.losses} ties ${record.ties}`);
|
|
79
|
+
console.log(`verdict: ${record.verdict}, ${record.reason}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
64
82
|
function printRunText(record) {
|
|
65
83
|
console.log(record.summary);
|
|
66
84
|
for (const task of record.tasks) {
|
|
@@ -76,6 +94,7 @@ async function runCommand(args) {
|
|
|
76
94
|
const result = await runBench({
|
|
77
95
|
pack: readInlineFirstFlag(args, '--pack') || undefined,
|
|
78
96
|
engine: readInlineFirstFlag(args, '--engine') || undefined,
|
|
97
|
+
model: readInlineFirstFlag(args, '--model') || undefined,
|
|
79
98
|
taskIds: readRepeatedFlag(args, '--task'),
|
|
80
99
|
label: readInlineFirstFlag(args, '--label'),
|
|
81
100
|
experiment: readInlineFirstFlag(args, '--experiment'),
|
|
@@ -102,6 +121,48 @@ async function runCommand(args) {
|
|
|
102
121
|
}
|
|
103
122
|
}
|
|
104
123
|
|
|
124
|
+
async function pairCommand(args) {
|
|
125
|
+
const asJson = hasFlag(args, '--json');
|
|
126
|
+
const candidateSource = readInlineFirstFlag(args, '--candidate');
|
|
127
|
+
let candidateRoot = null;
|
|
128
|
+
let removeCandidate = false;
|
|
129
|
+
try {
|
|
130
|
+
if (!candidateSource) throw new BenchInfraError('candidate is required');
|
|
131
|
+
try {
|
|
132
|
+
removeCandidate = !fs.statSync(path.resolve(candidateSource)).isDirectory();
|
|
133
|
+
} catch {
|
|
134
|
+
removeCandidate = true;
|
|
135
|
+
}
|
|
136
|
+
candidateRoot = materializeCandidate(candidateSource, process.cwd());
|
|
137
|
+
const result = await runBenchPair({
|
|
138
|
+
pack: readInlineFirstFlag(args, '--pack') || undefined,
|
|
139
|
+
engine: readInlineFirstFlag(args, '--engine') || undefined,
|
|
140
|
+
model: readInlineFirstFlag(args, '--model') || undefined,
|
|
141
|
+
taskIds: readRepeatedFlag(args, '--task'),
|
|
142
|
+
minWinMargin: readInlineFirstFlag(args, '--min-win-margin') || undefined,
|
|
143
|
+
repeats: readInlineFirstFlag(args, '--repeats') || undefined,
|
|
144
|
+
currentRoot: readInlineFirstFlag(args, '--current') || undefined,
|
|
145
|
+
candidateRoot,
|
|
146
|
+
stateRoot: process.cwd(),
|
|
147
|
+
});
|
|
148
|
+
if (asJson) console.log(JSON.stringify(result.record));
|
|
149
|
+
else printPairText(result.record);
|
|
150
|
+
return result.exitCode;
|
|
151
|
+
} catch (err) {
|
|
152
|
+
const message = err && err.message ? err.message : String(err);
|
|
153
|
+
if (asJson) {
|
|
154
|
+
console.log(JSON.stringify({ schema: 'atris.bench.error.v1', error: message }));
|
|
155
|
+
} else {
|
|
156
|
+
console.error(`atris bench: ${message}`);
|
|
157
|
+
}
|
|
158
|
+
return 2;
|
|
159
|
+
} finally {
|
|
160
|
+
if (removeCandidate && candidateRoot) {
|
|
161
|
+
fs.rmSync(candidateRoot, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
105
166
|
function tasksCommand(args) {
|
|
106
167
|
const pack = readInlineFirstFlag(args, '--pack') || undefined;
|
|
107
168
|
const tasks = taskMetadata({ pack });
|
|
@@ -200,6 +261,7 @@ async function benchCommand(args = []) {
|
|
|
200
261
|
return 2;
|
|
201
262
|
}
|
|
202
263
|
if (subcommand === 'run') return runCommand(rest);
|
|
264
|
+
if (subcommand === 'pair') return pairCommand(rest);
|
|
203
265
|
if (subcommand === 'tasks') return tasksCommand(rest);
|
|
204
266
|
if (subcommand === 'packs') return packsCommand(rest);
|
|
205
267
|
if (subcommand === 'results') return resultsCommand(rest);
|
package/commands/browse.js
CHANGED
|
@@ -32,7 +32,7 @@ async function browseAtris() {
|
|
|
32
32
|
const result = await apiRequestJson(endpoint, { method: 'GET', token: creds.token });
|
|
33
33
|
|
|
34
34
|
if (!result.ok) {
|
|
35
|
-
// API failed
|
|
35
|
+
// API failed, try local templates
|
|
36
36
|
console.log(' API unavailable, checking local templates...');
|
|
37
37
|
const localDir = path.join(os.homedir(), '.atris', 'templates');
|
|
38
38
|
if (!fs.existsSync(localDir)) {
|
|
@@ -61,7 +61,7 @@ async function browseAtris() {
|
|
|
61
61
|
desc = meta.description || '';
|
|
62
62
|
} catch {}
|
|
63
63
|
}
|
|
64
|
-
console.log(` ${name}${desc ? '
|
|
64
|
+
console.log(` ${name}${desc ? ': ' + desc : ''}`);
|
|
65
65
|
}
|
|
66
66
|
console.log('');
|
|
67
67
|
return;
|
package/commands/business.js
CHANGED
|
@@ -58,14 +58,14 @@ function validateBusinessCreateName(name) {
|
|
|
58
58
|
return {
|
|
59
59
|
ok: false,
|
|
60
60
|
usage: BUSINESS_CREATE_USAGE,
|
|
61
|
-
detail: `Refusing to create a business named "${name}"
|
|
61
|
+
detail: `Refusing to create a business named "${name}", looks like a flag, not a name.`,
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
if (isAccidentalHelpBusiness(name)) {
|
|
65
65
|
return {
|
|
66
66
|
ok: false,
|
|
67
67
|
usage: BUSINESS_CREATE_USAGE,
|
|
68
|
-
detail: `Refusing to create a business named "${name}"
|
|
68
|
+
detail: `Refusing to create a business named "${name}", looks like accidental help output, not a real business.`,
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
return { ok: true };
|
|
@@ -883,7 +883,7 @@ function collectBusinessOperatingState(cwd = process.cwd(), nowMs = Date.now())
|
|
|
883
883
|
}
|
|
884
884
|
|
|
885
885
|
function seedBusinessStarterTask(cwd, todoPath, starterAction) {
|
|
886
|
-
const title = `${starterAction.title}
|
|
886
|
+
const title = `${starterAction.title}: ${starterAction.action}`;
|
|
887
887
|
try {
|
|
888
888
|
const taskDb = require('../lib/task-db');
|
|
889
889
|
const db = taskDb.open();
|
|
@@ -1626,12 +1626,12 @@ ${stagedSources.length > 0 ? `- Local evidence files: ${stagedSources.length}` :
|
|
|
1626
1626
|
'- Before sharing the workspace, run `atris business share --write` and send the handoff.',
|
|
1627
1627
|
].filter(Boolean).join('\n') + '\n';
|
|
1628
1628
|
fs.writeFileSync(cheatSheetPath, operatorSummary, 'utf8');
|
|
1629
|
-
fs.writeFileSync(onePagerPath, operatorSummary.replace('# ', '# One Pager
|
|
1629
|
+
fs.writeFileSync(onePagerPath, operatorSummary.replace('# ', '# One Pager: '), 'utf8');
|
|
1630
1630
|
|
|
1631
1631
|
const todoPath = path.join(cwd, 'atris', 'TODO.md');
|
|
1632
1632
|
if (fs.existsSync(todoPath)) {
|
|
1633
1633
|
let todoContent = fs.readFileSync(todoPath, 'utf8');
|
|
1634
|
-
const taskLine = `- **Onboard:** ${starterAction.title}
|
|
1634
|
+
const taskLine = `- **Onboard:** ${starterAction.title}: ${starterAction.action} [execute]\n`;
|
|
1635
1635
|
const backlogMatch = todoContent.match(/^## Backlog\s*$/m);
|
|
1636
1636
|
if (backlogMatch) {
|
|
1637
1637
|
const insertAt = backlogMatch.index + backlogMatch[0].length;
|
|
@@ -1761,7 +1761,7 @@ function detectBusinessSlug(explicitSlug) {
|
|
|
1761
1761
|
async function findExistingBusinessBySlug(slug, token) {
|
|
1762
1762
|
if (!slug) return null;
|
|
1763
1763
|
|
|
1764
|
-
// Local cache first
|
|
1764
|
+
// Local cache first, no network round-trip needed.
|
|
1765
1765
|
const local = loadBusinesses();
|
|
1766
1766
|
if (local[slug]) {
|
|
1767
1767
|
return { id: local[slug].business_id, name: local[slug].name, slug, source: 'local' };
|
|
@@ -1774,7 +1774,7 @@ async function findExistingBusinessBySlug(slug, token) {
|
|
|
1774
1774
|
|
|
1775
1775
|
if (!token) return null;
|
|
1776
1776
|
|
|
1777
|
-
// Cloud lookup
|
|
1777
|
+
// Cloud lookup, covers businesses the user is a member of but hasn't added.
|
|
1778
1778
|
const direct = await apiRequestJson(`/business/by-slug/${encodeURIComponent(slug)}`, {
|
|
1779
1779
|
method: 'GET',
|
|
1780
1780
|
token,
|
|
@@ -1878,7 +1878,7 @@ async function listBusinesses(opts = {}) {
|
|
|
1878
1878
|
|
|
1879
1879
|
/**
|
|
1880
1880
|
* Walk ~/arena/atris-business/ and print a fleet status table for every
|
|
1881
|
-
* customer workspace. Pure local
|
|
1881
|
+
* customer workspace. Pure local, no API calls, no rate-limit risk.
|
|
1882
1882
|
*
|
|
1883
1883
|
* Classifies each dir as: ready, flat, unbound, nested, bare, or superseded.
|
|
1884
1884
|
*
|
|
@@ -1986,7 +1986,7 @@ function listBusinessesLocal(opts = {}) {
|
|
|
1986
1986
|
}
|
|
1987
1987
|
|
|
1988
1988
|
console.log('');
|
|
1989
|
-
console.log(`Atris Fleet
|
|
1989
|
+
console.log(`Atris Fleet: ${rootDir}`);
|
|
1990
1990
|
console.log('═'.repeat(86));
|
|
1991
1991
|
console.log(' CUSTOMER STATE FILES BIZ.JSON ATRIS/ ACTION');
|
|
1992
1992
|
console.log(' ' + '─'.repeat(83));
|
|
@@ -2016,7 +2016,7 @@ function listBusinessesLocal(opts = {}) {
|
|
|
2016
2016
|
const counts = {};
|
|
2017
2017
|
for (const c of customers) counts[c.state] = (counts[c.state] || 0) + 1;
|
|
2018
2018
|
const summary = order.filter((s) => counts[s]).map((s) => `${counts[s]} ${s}`).join(', ');
|
|
2019
|
-
console.log(` ${customers.length} customers
|
|
2019
|
+
console.log(` ${customers.length} customers: ${summary}`);
|
|
2020
2020
|
console.log('');
|
|
2021
2021
|
|
|
2022
2022
|
const needsWork = customers.filter((c) => ['flat', 'unbound', 'flat-unbound', 'nested'].includes(c.state));
|
|
@@ -3086,7 +3086,7 @@ async function connectService(connector, ...flags) {
|
|
|
3086
3086
|
for (const s of integrations) {
|
|
3087
3087
|
console.log(` ${s}`);
|
|
3088
3088
|
}
|
|
3089
|
-
if (integrations.length === 0) console.log(' (none found
|
|
3089
|
+
if (integrations.length === 0) console.log(' (none found, install skills first)');
|
|
3090
3090
|
return;
|
|
3091
3091
|
}
|
|
3092
3092
|
|
|
@@ -3540,7 +3540,7 @@ function printBusinessHelp() {
|
|
|
3540
3540
|
}
|
|
3541
3541
|
|
|
3542
3542
|
async function businessCommand(subcommand, ...args) {
|
|
3543
|
-
// Help intercept
|
|
3543
|
+
// Help intercept, without this, `atris business init --help` would treat
|
|
3544
3544
|
// `--help` as a business name and create one. Same for any subcommand that
|
|
3545
3545
|
// takes a positional name/slug.
|
|
3546
3546
|
if (!subcommand || isHelpToken(subcommand)) {
|
package/commands/card.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// atris card
|
|
1
|
+
// atris card, one line of text -> a beautiful, on-brand image (your theme).
|
|
2
2
|
//
|
|
3
3
|
// atris card "Ship faster" --kind statement --theme brand --size og
|
|
4
4
|
// atris card "It just works" --kind quote --by "a happy user"
|
|
@@ -64,7 +64,7 @@ function run(argv) {
|
|
|
64
64
|
const { flags, pos } = parseFlags(argv);
|
|
65
65
|
|
|
66
66
|
if (pos[0] === 'help' || flags.help) {
|
|
67
|
-
console.log(`\n atris card
|
|
67
|
+
console.log(`\n atris card, one line of text into an on-brand image\n
|
|
68
68
|
atris card "Your headline" [--kind statement|quote|stat] [--theme <name>] [--size og|wide|square|story]
|
|
69
69
|
flags: --sub --kicker --by --number --label --brand --version --out <file.png> --html-only\n
|
|
70
70
|
examples:
|
package/commands/clean.js
CHANGED
|
@@ -122,7 +122,7 @@ function cleanAtris(options = {}) {
|
|
|
122
122
|
if (unhealable.length > 0) {
|
|
123
123
|
console.log(`⚠ ${unhealable.length} MAP.md ${unhealable.length === 1 ? 'ref' : 'refs'} couldn't be healed:`);
|
|
124
124
|
unhealable.slice(0, 3).forEach(ref => {
|
|
125
|
-
console.log(` • ${ref.file}:${ref.line}
|
|
125
|
+
console.log(` • ${ref.file}:${ref.line}: ${ref.reason}`);
|
|
126
126
|
});
|
|
127
127
|
if (unhealable.length > 3) {
|
|
128
128
|
console.log(` ... and ${unhealable.length - 3} more`);
|
|
@@ -156,7 +156,7 @@ function cleanAtris(options = {}) {
|
|
|
156
156
|
if (stalePages.length > 0) {
|
|
157
157
|
console.log(`⚠ ${stalePages.length} stale ${stalePages.length === 1 ? 'page' : 'pages'} (source changed since last compiled):`);
|
|
158
158
|
stalePages.forEach(sp => {
|
|
159
|
-
console.log(` • ${path.relative(cwd, sp.page)}
|
|
159
|
+
console.log(` • ${path.relative(cwd, sp.page)}: stale source: ${sp.staleSource}`);
|
|
160
160
|
});
|
|
161
161
|
console.log('');
|
|
162
162
|
} else {
|
|
@@ -165,7 +165,7 @@ function cleanAtris(options = {}) {
|
|
|
165
165
|
|
|
166
166
|
// Dead code
|
|
167
167
|
if ((results.deadFiles || []).length > 0) {
|
|
168
|
-
console.log(`⚠ ${results.deadFiles.length} dead ${results.deadFiles.length === 1 ? 'file' : 'files'} (unreachable and unreferenced
|
|
168
|
+
console.log(`⚠ ${results.deadFiles.length} dead ${results.deadFiles.length === 1 ? 'file' : 'files'} (unreachable and unreferenced, atris slop dead for detail):`);
|
|
169
169
|
results.deadFiles.slice(0, 5).forEach((f) => console.log(` • ${f}`));
|
|
170
170
|
if (results.deadFiles.length > 5) console.log(` ... and ${results.deadFiles.length - 5} more`);
|
|
171
171
|
console.log('');
|
|
@@ -252,8 +252,8 @@ function firstLine(text) {
|
|
|
252
252
|
function mapScriptLine(step) {
|
|
253
253
|
const script = MAP_SCRIPTS.find(s => step.script.endsWith(s.file));
|
|
254
254
|
if (step.status === 'would_run') return `✓ ${script.dryLabel} (${step.script})`;
|
|
255
|
-
if (step.status === 'skipped') return `○ Skipped ${step.script}
|
|
256
|
-
if (step.status === 'failed') return `✗ ${script.failLabel}
|
|
255
|
+
if (step.status === 'skipped') return `○ Skipped ${step.script}: ${step.detail}`;
|
|
256
|
+
if (step.status === 'failed') return `✗ ${script.failLabel}: ${step.detail}`;
|
|
257
257
|
return `✓ ${script.ranLabel}`;
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -368,8 +368,8 @@ function healBrokenMapRefs(cwd, atrisDir, dryRun = false, homeDir = os.homedir()
|
|
|
368
368
|
|
|
369
369
|
// Match both `file.js:123` and `file.js:123-456` with surrounding context
|
|
370
370
|
// [^\S\n] = horizontal whitespace only (no newlines)
|
|
371
|
-
// Required delimiter
|
|
372
|
-
const refPattern = /(`?)([a-zA-Z0-9_~\-./\\]+\.(js|ts|py|go|rs|rb|java|c|cpp|h|hpp|md|json|yaml|yml)):(\d+)(?:-(\d+))?(`?)([^\S\n]*[\(\[
|
|
371
|
+
// Required delimiter set, including the u2014 escape, prevents bleeding into adjacent refs on same line
|
|
372
|
+
const refPattern = /(`?)([a-zA-Z0-9_~\-./\\]+\.(js|ts|py|go|rs|rb|java|c|cpp|h|hpp|md|json|yaml|yml)):(\d+)(?:-(\d+))?(`?)([^\S\n]*[\(\[\u2014\-][^\S\n]*([^)\]\n]+))?/g;
|
|
373
373
|
|
|
374
374
|
// Function Inventory form: `symbolName()` → `file:line[-line]`
|
|
375
375
|
// Pre-scan to build a (file:line) → symbol map so refs with the symbol BEFORE them still verify.
|
|
@@ -518,7 +518,7 @@ function findFunctionEnd(lines, startLine) {
|
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
/**
|
|
521
|
-
* Extract a symbol name from context like "(interactiveEntry function)" or "
|
|
521
|
+
* Extract a symbol name from context like "(interactiveEntry function)" or "Main entry" after punctuation
|
|
522
522
|
*/
|
|
523
523
|
function extractSymbol(context) {
|
|
524
524
|
if (!context) return null;
|
|
@@ -529,7 +529,7 @@ function extractSymbol(context) {
|
|
|
529
529
|
const unquoted = context.trim().replace(/`/g, '');
|
|
530
530
|
const wrapper = unquoted.match(/^([\(\[])/)?.[1];
|
|
531
531
|
let cleaned = unquoted
|
|
532
|
-
.replace(/^[\(\[
|
|
532
|
+
.replace(/^[\(\[\u2014\-:]+\s*/, '')
|
|
533
533
|
.trim();
|
|
534
534
|
if (wrapper === '(') cleaned = cleaned.replace(/\)$/, '').trim();
|
|
535
535
|
if (wrapper === '[') cleaned = cleaned.replace(/\]$/, '').trim();
|
|
@@ -553,13 +553,13 @@ function extractSymbol(context) {
|
|
|
553
553
|
|
|
554
554
|
/**
|
|
555
555
|
* Find the line number where a symbol is defined (strict patterns only)
|
|
556
|
-
* Returns null if only loose matches found
|
|
556
|
+
* Returns null if only loose matches found, prevents healing to wrong locations
|
|
557
557
|
*/
|
|
558
558
|
function findSymbolLine(fileContent, symbol) {
|
|
559
559
|
const lines = fileContent.split('\n');
|
|
560
560
|
const esc = escapeRegExp(symbol);
|
|
561
561
|
|
|
562
|
-
// Strict definition patterns only
|
|
562
|
+
// Strict definition patterns only, no loose fallback
|
|
563
563
|
const patterns = [
|
|
564
564
|
new RegExp(`^\\s*(async\\s+)?function\\s+${esc}\\s*\\(`), // function name(
|
|
565
565
|
new RegExp(`^\\s*(const|let|var)\\s+${esc}\\s*=`), // const/let/var name =
|
|
@@ -652,7 +652,7 @@ function checkPageStaleness(cwd, filePath) {
|
|
|
652
652
|
|
|
653
653
|
// Check each source's mtime against last_compiled.
|
|
654
654
|
// Source entries can include a line range and/or a parenthesized annotation,
|
|
655
|
-
// e.g. "bin/atris.js:199-340 (showHelp function)"
|
|
655
|
+
// e.g. "bin/atris.js:199-340 (showHelp function)". Strip both before stat.
|
|
656
656
|
for (const source of sources) {
|
|
657
657
|
const filePart = source
|
|
658
658
|
.replace(/\s*\([^)]*\)\s*$/, '') // drop trailing "(annotation)"
|
|
@@ -670,7 +670,7 @@ function checkPageStaleness(cwd, filePath) {
|
|
|
670
670
|
};
|
|
671
671
|
}
|
|
672
672
|
} catch {
|
|
673
|
-
// Source file doesn't exist
|
|
673
|
+
// Source file doesn't exist, that's also a staleness signal
|
|
674
674
|
return {
|
|
675
675
|
page: filePath,
|
|
676
676
|
staleSource: source + ' (missing)',
|
package/commands/close.js
CHANGED
|
@@ -472,7 +472,7 @@ function commandAdd(args, context = {}) {
|
|
|
472
472
|
return 0;
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
// atris close check [id]
|
|
475
|
+
// atris close check [id]: run the live probes on open incidents. This is the
|
|
476
476
|
// first move for any session entering an area: if a probe still fails, the
|
|
477
477
|
// recorded theory is still live; do not diagnose fresh. After
|
|
478
478
|
// PROBE_STOP_AFTER_FAILED_CHECKS failing re-checks the verdict is automatic:
|
|
@@ -893,7 +893,7 @@ function pulseLivenessState(cwd, now) {
|
|
|
893
893
|
// decommissioned or intermittent loop leaves stale receipts frozen; without a
|
|
894
894
|
// guard the last N finished ticks stay net-negative forever and the flag can
|
|
895
895
|
// never clear (no fresh positive receipt arrives). It also must not treat a
|
|
896
|
-
// scattered set
|
|
896
|
+
// scattered set, e.g. one tick today plus five from days ago, as a "run":
|
|
897
897
|
// summing rewards across a multi-day gap is meaningless. So we only consider
|
|
898
898
|
// finished ticks from the last few days and require a full window of them; a
|
|
899
899
|
// silent or sparse loop is the pulse-liveness sensor's concern, and here it
|
|
@@ -1524,7 +1524,7 @@ function run(args = [], context = {}) {
|
|
|
1524
1524
|
printHelp();
|
|
1525
1525
|
return 0;
|
|
1526
1526
|
}
|
|
1527
|
-
// `close <sub> --help` is a help request, not a run
|
|
1527
|
+
// `close <sub> --help` is a help request, not a run, sweep and scan mutate
|
|
1528
1528
|
// the ledger (escalations, auto-closes), so never execute a subcommand just
|
|
1529
1529
|
// to show usage.
|
|
1530
1530
|
if (rest.includes('--help') || rest.includes('-h')) {
|
package/commands/compile.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Atris Compile
|
|
2
|
+
* Atris Compile: learn like AI, run like code.
|
|
3
3
|
*
|
|
4
4
|
* The compile loop: execution records → compile-to-deterministic-code →
|
|
5
5
|
* statistical backtest → gated promote. The LLM is only in the build path;
|
|
@@ -328,7 +328,7 @@ function deepEqual(a, b) {
|
|
|
328
328
|
function loadRunner(root, name) {
|
|
329
329
|
const p = runnerPath(root, name);
|
|
330
330
|
if (!fs.existsSync(p)) {
|
|
331
|
-
throw new Error(`no compiled artifact at ${path.relative(root, p)}
|
|
331
|
+
throw new Error(`no compiled artifact at ${path.relative(root, p)}, run "atris compile build ${name}" first`);
|
|
332
332
|
}
|
|
333
333
|
const resolved = require.resolve(p);
|
|
334
334
|
delete require.cache[resolved]; // always load the latest compiled version
|
|
@@ -344,7 +344,7 @@ function loadRunner(root, name) {
|
|
|
344
344
|
async function runBacktest(root, name, options = {}) {
|
|
345
345
|
const records = readRecords(root, name);
|
|
346
346
|
if (records.length === 0) {
|
|
347
|
-
throw new Error(`no execution records for "${name}"
|
|
347
|
+
throw new Error(`no execution records for "${name}", add some with "atris compile record ${name} --input ... --output ..."`);
|
|
348
348
|
}
|
|
349
349
|
const runner = loadRunner(root, name);
|
|
350
350
|
const manifest = readManifest(root, name) || defaultManifest(name);
|
|
@@ -395,7 +395,7 @@ async function runBacktest(root, name, options = {}) {
|
|
|
395
395
|
function promoteProcess(root, name, options = {}) {
|
|
396
396
|
const manifest = readManifest(root, name);
|
|
397
397
|
if (!manifest) {
|
|
398
|
-
throw new Error(`no manifest for "${name}"
|
|
398
|
+
throw new Error(`no manifest for "${name}", compile and backtest it first`);
|
|
399
399
|
}
|
|
400
400
|
if (options.threshold !== undefined) {
|
|
401
401
|
// the only way to change the standing gate: deliberate, at promote time
|
|
@@ -403,13 +403,13 @@ function promoteProcess(root, name, options = {}) {
|
|
|
403
403
|
}
|
|
404
404
|
const bt = manifest.backtest;
|
|
405
405
|
if (!bt) {
|
|
406
|
-
throw new Error(`"${name}" has no backtest
|
|
406
|
+
throw new Error(`"${name}" has no backtest, run "atris compile backtest ${name}" first`);
|
|
407
407
|
}
|
|
408
408
|
if (bt.version !== manifest.version) {
|
|
409
|
-
throw new Error(`backtest is for version ${bt.version} but current version is ${manifest.version}
|
|
409
|
+
throw new Error(`backtest is for version ${bt.version} but current version is ${manifest.version}, re-run the backtest`);
|
|
410
410
|
}
|
|
411
411
|
if (bt.accuracy < manifest.threshold) {
|
|
412
|
-
throw new Error(`backtest accuracy ${(bt.accuracy * 100).toFixed(2)}% is below the ${(manifest.threshold * 100).toFixed(2)}% gate (${bt.passed}/${bt.total})
|
|
412
|
+
throw new Error(`backtest accuracy ${(bt.accuracy * 100).toFixed(2)}% is below the ${(manifest.threshold * 100).toFixed(2)}% gate (${bt.passed}/${bt.total}), not promoting`);
|
|
413
413
|
}
|
|
414
414
|
manifest.status = 'active';
|
|
415
415
|
manifest.promotedAt = new Date().toISOString();
|
|
@@ -436,10 +436,10 @@ Write the compiled artifact to ${runRel} with this exact contract:
|
|
|
436
436
|
- CommonJS module exporting { run }: \`module.exports = { run };\`
|
|
437
437
|
- \`run(input)\` takes one input value and returns the output (sync return or promise both fine)
|
|
438
438
|
- deterministic: no network calls, no Date.now()/new Date() in outputs, no randomness, no environment reads
|
|
439
|
-
- Node.js built-ins only
|
|
439
|
+
- Node.js built-ins only, zero npm dependencies
|
|
440
440
|
- handle malformed input by throwing a clear Error, never by guessing
|
|
441
441
|
|
|
442
|
-
The artifact will be verified by replaying every execution record through run() and requiring near-perfect accuracy, so generalize the rules
|
|
442
|
+
The artifact will be verified by replaying every execution record through run() and requiring near-perfect accuracy, so generalize the rules, do not hardcode a lookup table of the sample records.
|
|
443
443
|
|
|
444
444
|
Reply [COMPILE_COMPLETE] when ${runRel} is written.`;
|
|
445
445
|
}
|
|
@@ -448,7 +448,7 @@ function executeBuild(root, name, options = {}) {
|
|
|
448
448
|
const { verbose = false, timeout = 600000, notes = '', cmdOverride } = options;
|
|
449
449
|
const records = readRecords(root, name);
|
|
450
450
|
if (records.length === 0) {
|
|
451
|
-
throw new Error(`no execution records for "${name}"
|
|
451
|
+
throw new Error(`no execution records for "${name}", record real runs first, then compile`);
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
if (!cmdOverride) {
|
|
@@ -526,7 +526,7 @@ function formatAccuracy(accuracy) {
|
|
|
526
526
|
function printBacktest(name, result, failureCount, manifest) {
|
|
527
527
|
console.log(`backtest ${name} v${result.version}: ${result.passed}/${result.total} passed (${formatAccuracy(result.accuracy)}), gate ${formatAccuracy(result.threshold)}`);
|
|
528
528
|
if (result.total < LOW_RECORD_WARNING) {
|
|
529
|
-
console.log(`note: only ${result.total} record${result.total === 1 ? '' : 's'}
|
|
529
|
+
console.log(`note: only ${result.total} record${result.total === 1 ? '' : 's'}, accuracy means more with ${LOW_RECORD_WARNING}+`);
|
|
530
530
|
}
|
|
531
531
|
if (failureCount > 0) {
|
|
532
532
|
console.log(`${failureCount} mismatch${failureCount === 1 ? '' : 'es'}. first ${Math.min(failureCount, 3)}:`);
|
|
@@ -675,7 +675,7 @@ function showCompileHelp() {
|
|
|
675
675
|
console.log('Server commands require --agent <id> and Atris auth from atris login or ATRIS_TOKEN.');
|
|
676
676
|
console.log('Loop: record real runs -> build -> backtest -> promote -> exec --record');
|
|
677
677
|
console.log('When backtest accuracy drops below the gate, the process is marked drifted');
|
|
678
|
-
console.log('and a recompile is suggested
|
|
678
|
+
console.log('and a recompile is suggested, self-healing against process drift.');
|
|
679
679
|
console.log('');
|
|
680
680
|
}
|
|
681
681
|
|
|
@@ -830,7 +830,7 @@ async function compileCommand(subcommand, ...rawArgs) {
|
|
|
830
830
|
}
|
|
831
831
|
const manifest = readManifest(root, name);
|
|
832
832
|
if (manifest && manifest.status === 'drifted') {
|
|
833
|
-
console.error(`warning: ${name} is marked drifted
|
|
833
|
+
console.error(`warning: ${name} is marked drifted, outputs may be stale. recompile with "atris compile build ${name}"`);
|
|
834
834
|
}
|
|
835
835
|
const runner = loadRunner(root, name);
|
|
836
836
|
const output = await runner.run(input);
|