atris 3.57.4 → 3.58.6
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 +66 -21
- 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 +59 -31
- 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 +216 -50
- 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 +101 -48
- package/commands/worktree.js +1 -1
- package/commands/write.js +9 -9
- package/commands/x-search.js +93 -22
- package/commands/xp.js +6 -3
- package/commands/youtube.js +1019 -123
- 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/ytnotes +82 -5
- 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 +47 -9
- package/utils/config.js +0 -1
- package/scripts/det/checklist-score.js +0 -191
package/utils/auth.js
CHANGED
|
@@ -352,9 +352,13 @@ function autoSaveProfile(credentials) {
|
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
function saveCredentials(token, refreshToken, email, userId, provider) {
|
|
355
|
+
function saveCredentials(token, refreshToken, email, userId, provider, extras = {}) {
|
|
356
|
+
if (decodeJwtClaims(token)?.type === 'agent_access') {
|
|
357
|
+
throw new Error('Refusing to save a scoped agent token as the login token; keep it under agent_token');
|
|
358
|
+
}
|
|
356
359
|
const credentialsPath = getCredentialsPath();
|
|
357
360
|
const credentials = {
|
|
361
|
+
...extras,
|
|
358
362
|
token,
|
|
359
363
|
refresh_token: refreshToken || null,
|
|
360
364
|
email: email || null,
|
|
@@ -374,7 +378,43 @@ function saveCredentials(token, refreshToken, email, userId, provider) {
|
|
|
374
378
|
autoSaveProfile(credentials);
|
|
375
379
|
}
|
|
376
380
|
|
|
377
|
-
|
|
381
|
+
// Supplying the auth client enables asynchronous repair. Local-only readers stay synchronous.
|
|
382
|
+
function loadCredentials(apiRequestJson) {
|
|
383
|
+
const credentials = readCredentials();
|
|
384
|
+
if (!credentials || credentials.source || decodeJwtClaims(credentials.token)?.type !== 'agent_access') {
|
|
385
|
+
return credentials;
|
|
386
|
+
}
|
|
387
|
+
if (!credentials.refresh_token) {
|
|
388
|
+
console.error('atris login');
|
|
389
|
+
return credentials;
|
|
390
|
+
}
|
|
391
|
+
if (!apiRequestJson) return credentials;
|
|
392
|
+
return repairLoginCredentials(credentials, apiRequestJson);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
async function repairLoginCredentials(credentials, apiRequestJson) {
|
|
396
|
+
const refreshed = await refreshAccessToken(credentials.refresh_token, null, apiRequestJson);
|
|
397
|
+
const token = refreshed.data?.access_token;
|
|
398
|
+
if (!refreshed.ok || !token || decodeJwtClaims(token)?.type === 'agent_access') {
|
|
399
|
+
throw new Error('Could not repair login file. Run atris login');
|
|
400
|
+
}
|
|
401
|
+
const claims = decodeJwtClaims(credentials.token);
|
|
402
|
+
const { source_profile, ...rest } = credentials;
|
|
403
|
+
const next = {
|
|
404
|
+
...rest,
|
|
405
|
+
token,
|
|
406
|
+
refresh_token: refreshed.data.refresh_token || credentials.refresh_token,
|
|
407
|
+
agent_token: credentials.token,
|
|
408
|
+
agent_token_scopes: claims.scopes || [],
|
|
409
|
+
agent_token_expires_at: typeof claims.exp === 'number' ? new Date(claims.exp * 1000).toISOString() : null,
|
|
410
|
+
};
|
|
411
|
+
if (source_profile) saveProfile(source_profile, next);
|
|
412
|
+
else saveCredentials(token, next.refresh_token, next.email, next.user_id, next.provider, next);
|
|
413
|
+
console.error('Repaired login file: moved a scoped agent token aside.');
|
|
414
|
+
return { ...next, ...(source_profile ? { source_profile } : {}) };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function readCredentials() {
|
|
378
418
|
// Priority: ATRIS_TOKEN env var → placed agent token → ATRIS_PROFILE env var
|
|
379
419
|
// → per-terminal session file → global credentials.json. A fresh placed token
|
|
380
420
|
// overrides a different env token because cloud images can carry a stale one.
|
|
@@ -552,7 +592,7 @@ async function performTokenRefresh(credentials, apiRequestJson) {
|
|
|
552
592
|
saved_at: new Date().toISOString(),
|
|
553
593
|
});
|
|
554
594
|
} else {
|
|
555
|
-
saveCredentials(accessToken, newRefreshToken, email, userId, provider);
|
|
595
|
+
saveCredentials(accessToken, newRefreshToken, email, userId, provider, credentials);
|
|
556
596
|
}
|
|
557
597
|
};
|
|
558
598
|
|
|
@@ -586,7 +626,7 @@ async function performTokenRefresh(credentials, apiRequestJson) {
|
|
|
586
626
|
saved_at: new Date().toISOString(),
|
|
587
627
|
});
|
|
588
628
|
} else {
|
|
589
|
-
saveCredentials(accessToken, newRefreshToken, updatedEmail, updatedUserId, updatedProvider);
|
|
629
|
+
saveCredentials(accessToken, newRefreshToken, updatedEmail, updatedUserId, updatedProvider, credentials);
|
|
590
630
|
}
|
|
591
631
|
latestCreds = loadCredentials();
|
|
592
632
|
}
|
|
@@ -603,7 +643,7 @@ async function performTokenRefresh(credentials, apiRequestJson) {
|
|
|
603
643
|
}
|
|
604
644
|
|
|
605
645
|
async function ensureValidCredentials(apiRequestJson, options = {}) {
|
|
606
|
-
let credentials = loadCredentials();
|
|
646
|
+
let credentials = await loadCredentials(apiRequestJson);
|
|
607
647
|
if (!credentials || !credentials.token) {
|
|
608
648
|
return { error: 'not_logged_in' };
|
|
609
649
|
}
|
|
@@ -659,7 +699,8 @@ async function ensureValidCredentials(apiRequestJson, options = {}) {
|
|
|
659
699
|
credentials.refresh_token,
|
|
660
700
|
updatedEmail,
|
|
661
701
|
updatedUserId,
|
|
662
|
-
updatedProvider
|
|
702
|
+
updatedProvider,
|
|
703
|
+
credentials
|
|
663
704
|
);
|
|
664
705
|
}
|
|
665
706
|
}
|
|
@@ -760,11 +801,9 @@ module.exports = {
|
|
|
760
801
|
promptUser,
|
|
761
802
|
validateAccessToken,
|
|
762
803
|
refreshAccessToken,
|
|
763
|
-
refreshProviderHint,
|
|
764
804
|
performTokenRefresh,
|
|
765
805
|
ensureValidCredentials,
|
|
766
806
|
isAuthFailure,
|
|
767
|
-
printAuthRequired,
|
|
768
807
|
abortOnAuthFailure,
|
|
769
808
|
fetchMyAgents,
|
|
770
809
|
displayAccountSummary,
|
|
@@ -774,7 +813,6 @@ module.exports = {
|
|
|
774
813
|
listProfiles,
|
|
775
814
|
deleteProfile,
|
|
776
815
|
profileNameFromEmail,
|
|
777
|
-
autoSaveProfile,
|
|
778
816
|
// Per-terminal sessions
|
|
779
817
|
getTerminalSessionId,
|
|
780
818
|
getSessionsDir,
|
package/utils/config.js
CHANGED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
// Pareto-3 checklist quality score.
|
|
5
|
-
//
|
|
6
|
-
// Measures the three front doors a brand-new person actually hits, the way
|
|
7
|
-
// they would hit them: from an empty folder, with no context, reading only
|
|
8
|
-
// what the tool prints. Every point is earned by a live probe, never opinion.
|
|
9
|
-
//
|
|
10
|
-
// 1. onboard - `atris init --yes` in a fresh folder
|
|
11
|
-
// 2. chat - one real answered message through `ax`
|
|
12
|
-
// 3. mission - the end-to-end loop drill in its own sandbox
|
|
13
|
-
//
|
|
14
|
-
// Rubric per feature (100 points):
|
|
15
|
-
// cold start works, zero setup ......... 40
|
|
16
|
-
// speed to first value ................. 20 (full marks at target, 0 at 4x)
|
|
17
|
-
// plain language on the first screen ... 20 (fraction of clean lines)
|
|
18
|
-
// graceful failure on wrong input ...... 20 (honest exit + plain reason,
|
|
19
|
-
// no stack trace)
|
|
20
|
-
//
|
|
21
|
-
// Usage: node scripts/det/checklist-score.js [--json]
|
|
22
|
-
|
|
23
|
-
const { spawnSync } = require('node:child_process');
|
|
24
|
-
const fs = require('node:fs');
|
|
25
|
-
const os = require('node:os');
|
|
26
|
-
const path = require('node:path');
|
|
27
|
-
|
|
28
|
-
const repoRoot = path.resolve(__dirname, '..', '..');
|
|
29
|
-
const cliPath = path.join(repoRoot, 'bin', 'atris.js');
|
|
30
|
-
const axPath = path.join(repoRoot, 'ax');
|
|
31
|
-
const { scanText } = require(path.join(repoRoot, 'lib', 'voice-gate'));
|
|
32
|
-
|
|
33
|
-
// System nouns a person with no idea should never have to decode on a first
|
|
34
|
-
// screen. Backticked command examples are exempt (they are copy targets).
|
|
35
|
-
const SYSTEM_NOUNS = /\b(?:verifier|worktree|subagent|jsonl|projection|runner[- ]profile|heartbeat|orchestrat\w+|frontmatter|monorepo)\b/i;
|
|
36
|
-
const STACK_FRAME = /^\s+at .+:\d+:\d+\)?$/;
|
|
37
|
-
|
|
38
|
-
function run(cmd, args, options = {}) {
|
|
39
|
-
const started = Date.now();
|
|
40
|
-
const result = spawnSync(cmd, args, {
|
|
41
|
-
cwd: options.cwd,
|
|
42
|
-
encoding: 'utf8',
|
|
43
|
-
timeout: options.timeoutMs || 180000,
|
|
44
|
-
env: { ...process.env, ATRIS_SKIP_UPDATE_CHECK: '1', ...(options.env || {}) },
|
|
45
|
-
});
|
|
46
|
-
return {
|
|
47
|
-
status: result.status,
|
|
48
|
-
error: result.error || null,
|
|
49
|
-
stdout: result.stdout || '',
|
|
50
|
-
stderr: result.stderr || '',
|
|
51
|
-
ms: Date.now() - started,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function speedPoints(ms, targetMs) {
|
|
56
|
-
if (ms <= targetMs) return 20;
|
|
57
|
-
const over = (ms - targetMs) / (targetMs * 3);
|
|
58
|
-
return Math.max(0, Math.round(20 * (1 - over)));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function plainPoints(text) {
|
|
62
|
-
const lines = String(text || '')
|
|
63
|
-
.split(/\r?\n/)
|
|
64
|
-
.map((line) => line.trim())
|
|
65
|
-
.filter(Boolean)
|
|
66
|
-
.slice(0, 30);
|
|
67
|
-
if (!lines.length) return { points: 0, dirty: ['(no output at all)'] };
|
|
68
|
-
const dirty = [];
|
|
69
|
-
for (const line of lines) {
|
|
70
|
-
// Command examples are copy targets, not prose; the reader with no idea
|
|
71
|
-
// reads the description column, so scan only the human words.
|
|
72
|
-
if (/^`.*`$/.test(line) || /^\$\s/.test(line) || /^(?:ax|atris|npx)\s/.test(line)) continue;
|
|
73
|
-
const bare = line
|
|
74
|
-
.replace(/`[^`]*`/g, '')
|
|
75
|
-
.replace(/--[\w-]+/g, '')
|
|
76
|
-
.replace(/\[[^\]]*\]/g, '')
|
|
77
|
-
.replace(/<[^>]*>/g, '');
|
|
78
|
-
if (STACK_FRAME.test(line) || /\u2014/.test(bare) || SYSTEM_NOUNS.test(bare) || scanText(bare).length) {
|
|
79
|
-
dirty.push(line.slice(0, 80));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const clean = lines.length - dirty.length;
|
|
83
|
-
return { points: Math.round((20 * clean) / lines.length), dirty };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function failurePoints(result) {
|
|
87
|
-
const text = `${result.stdout}\n${result.stderr}`;
|
|
88
|
-
const honest = result.status !== 0 && !result.error;
|
|
89
|
-
const noStack = !text.split(/\r?\n/).some((line) => STACK_FRAME.test(line))
|
|
90
|
-
&& !/\b(?:TypeError|ReferenceError|SyntaxError)\b/.test(text);
|
|
91
|
-
const saysWhy = /\b(?:unknown|not found|no such|missing|usage|help|try|error)\b/i.test(text);
|
|
92
|
-
let points = 0;
|
|
93
|
-
if (honest) points += 8;
|
|
94
|
-
if (noStack) points += 6;
|
|
95
|
-
if (saysWhy) points += 6;
|
|
96
|
-
return points;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function scoreOnboard(base) {
|
|
100
|
-
const dir = fs.mkdtempSync(path.join(base, 'onboard-'));
|
|
101
|
-
const cold = run(process.execPath, [cliPath, 'init', '--yes'], { cwd: dir });
|
|
102
|
-
const artifact = fs.existsSync(path.join(dir, 'atris'));
|
|
103
|
-
const coldPoints = cold.status === 0 && artifact ? 40 : 0;
|
|
104
|
-
const plain = plainPoints(cold.stdout);
|
|
105
|
-
const bad = run(process.execPath, [cliPath, 'definitely-not-a-command'], { cwd: dir });
|
|
106
|
-
return {
|
|
107
|
-
feature: 'onboard: atris init in an empty folder',
|
|
108
|
-
dir,
|
|
109
|
-
cold: coldPoints,
|
|
110
|
-
speed: speedPoints(cold.ms, 10000),
|
|
111
|
-
plain: plain.points,
|
|
112
|
-
failure: failurePoints(bad),
|
|
113
|
-
ms: cold.ms,
|
|
114
|
-
dirty_lines: plain.dirty,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function scoreChat(base, workspaceDir) {
|
|
119
|
-
const cold = run(process.execPath, [axPath, '--fast', '--print', 'Reply with exactly: checklist-ok'], {
|
|
120
|
-
cwd: workspaceDir,
|
|
121
|
-
timeoutMs: 120000,
|
|
122
|
-
});
|
|
123
|
-
let answered = false;
|
|
124
|
-
try {
|
|
125
|
-
const payload = JSON.parse(cold.stdout.slice(cold.stdout.indexOf('{')));
|
|
126
|
-
answered = payload.ok === true && /checklist-ok/.test(String(payload.output || ''));
|
|
127
|
-
} catch {}
|
|
128
|
-
const helpScreen = run(process.execPath, [axPath, '--help'], { cwd: workspaceDir, timeoutMs: 30000 });
|
|
129
|
-
const plain = plainPoints(helpScreen.stdout);
|
|
130
|
-
const bad = run(process.execPath, [axPath, '--fast', '--print'], { cwd: workspaceDir, timeoutMs: 30000 });
|
|
131
|
-
return {
|
|
132
|
-
feature: 'chat: one real answered message through ax',
|
|
133
|
-
cold: cold.status !== null && answered ? 40 : 0,
|
|
134
|
-
speed: speedPoints(cold.ms, 15000),
|
|
135
|
-
plain: plain.points,
|
|
136
|
-
failure: failurePoints(bad),
|
|
137
|
-
ms: cold.ms,
|
|
138
|
-
dirty_lines: plain.dirty,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function scoreMission(base, workspaceDir) {
|
|
143
|
-
const cold = run(process.execPath, [cliPath, 'drill', '--json'], { cwd: workspaceDir, timeoutMs: 300000 });
|
|
144
|
-
let passed = false;
|
|
145
|
-
let stages = 0;
|
|
146
|
-
try {
|
|
147
|
-
const payload = JSON.parse(cold.stdout.slice(cold.stdout.indexOf('{')));
|
|
148
|
-
passed = payload.pass === true;
|
|
149
|
-
stages = Array.isArray(payload.stages) ? payload.stages.length : 0;
|
|
150
|
-
} catch {}
|
|
151
|
-
const status = run(process.execPath, [cliPath, 'mission'], { cwd: workspaceDir, timeoutMs: 60000 });
|
|
152
|
-
const plain = plainPoints(status.stdout);
|
|
153
|
-
const bad = run(process.execPath, [cliPath, 'mission', 'run', '9999'], { cwd: workspaceDir, timeoutMs: 60000 });
|
|
154
|
-
return {
|
|
155
|
-
feature: `mission: full loop drill (${stages} stages) plus status screen`,
|
|
156
|
-
cold: passed ? 40 : 0,
|
|
157
|
-
speed: speedPoints(cold.ms, 90000),
|
|
158
|
-
plain: plain.points,
|
|
159
|
-
failure: failurePoints(bad),
|
|
160
|
-
ms: cold.ms,
|
|
161
|
-
dirty_lines: plain.dirty,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function main() {
|
|
166
|
-
const asJson = process.argv.includes('--json');
|
|
167
|
-
const base = fs.mkdtempSync(path.join(os.tmpdir(), 'atris-checklist-'));
|
|
168
|
-
const onboard = scoreOnboard(base);
|
|
169
|
-
const chat = scoreChat(base, onboard.dir);
|
|
170
|
-
const mission = scoreMission(base, onboard.dir);
|
|
171
|
-
const features = [onboard, chat, mission].map((f) => ({
|
|
172
|
-
...f,
|
|
173
|
-
total: f.cold + f.speed + f.plain + f.failure,
|
|
174
|
-
}));
|
|
175
|
-
const overall = Math.round(features.reduce((sum, f) => sum + f.total, 0) / features.length);
|
|
176
|
-
const report = { schema: 'atris.checklist_score.v1', overall, features };
|
|
177
|
-
fs.rmSync(base, { recursive: true, force: true });
|
|
178
|
-
if (asJson) {
|
|
179
|
-
console.log(JSON.stringify(report, null, 2));
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
console.log('Pareto-3 checklist quality score\n');
|
|
183
|
-
for (const f of features) {
|
|
184
|
-
console.log(` ${f.feature}`);
|
|
185
|
-
console.log(` cold start ${f.cold}/40 · speed ${f.speed}/20 (${(f.ms / 1000).toFixed(1)}s) · plain words ${f.plain}/20 · graceful failure ${f.failure}/20 => ${f.total}/100`);
|
|
186
|
-
if (f.dirty_lines.length) console.log(` lines that need plain words: ${f.dirty_lines.length}`);
|
|
187
|
-
}
|
|
188
|
-
console.log(`\n overall: ${overall}/100`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
main();
|