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/lib/permission-grants.js
CHANGED
|
@@ -123,7 +123,7 @@ function revokeGrant(grantId, file) {
|
|
|
123
123
|
let grant = store.grants.find(g => g.grant_id === ref);
|
|
124
124
|
if (!grant && ref) {
|
|
125
125
|
// Prefix refs are a convenience, but an ambiguous prefix must never
|
|
126
|
-
// revoke an arbitrary grant
|
|
126
|
+
// revoke an arbitrary grant, require exactly one match.
|
|
127
127
|
const matches = store.grants.filter(g => String(g.grant_id).startsWith(ref));
|
|
128
128
|
if (matches.length > 1) return { ok: false, reason: `"${ref}" matches ${matches.length} grants; use more characters` };
|
|
129
129
|
grant = matches[0];
|
|
@@ -258,7 +258,7 @@ function mergeRemoteGrants(store, remoteGrants = [], now = new Date()) {
|
|
|
258
258
|
// Push the local grants to the backend and merge back the authoritative set.
|
|
259
259
|
// apiRequestJson is injected (utils/api) so this stays offline-testable. The
|
|
260
260
|
// call is best-effort: on any transport/HTTP failure the local store is left
|
|
261
|
-
// untouched and { ok: false, reason } is returned
|
|
261
|
+
// untouched and { ok: false, reason } is returned, grants keep working locally.
|
|
262
262
|
async function syncGrants({ apiRequestJson, token, file, endpoint = GRANTS_SYNC_ENDPOINT, now = new Date() } = {}) {
|
|
263
263
|
if (typeof apiRequestJson !== 'function') {
|
|
264
264
|
return { ok: false, reason: 'no api client' };
|
package/lib/policy-lessons.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// The workspace already records its own history: career XP receipts (human
|
|
4
4
|
// accepts), task episodes (every review turn with an RL label), and
|
|
5
5
|
// scorecards (improve/brain ticks). This module mines that history into a
|
|
6
|
-
// small set of deterministic policy lessons
|
|
7
|
-
// counts it was computed from
|
|
6
|
+
// small set of deterministic policy lessons, each one carries the evidence
|
|
7
|
+
// counts it was computed from, and surfaces them at the moment an agent
|
|
8
8
|
// submits proof (`atris task ready`), so the next submission behaves
|
|
9
9
|
// differently than the last. No LLM calls; re-mining refreshes the numbers.
|
|
10
10
|
const fs = require('fs');
|
|
@@ -23,7 +23,7 @@ const DAY_MS = 24 * 60 * 60 * 1000;
|
|
|
23
23
|
// Review actors that are agents, not the human gate. Mining must split the
|
|
24
24
|
// two: agent self-review churn and human accept/bounce are different signals.
|
|
25
25
|
const AGENT_ACTOR_PATTERN = /review|validator|certifier|auto|codex|claude|devin|droid|improver|second-pass|agent|bot/i;
|
|
26
|
-
// "Names a runnable verify command"
|
|
26
|
+
// "Names a runnable verify command": the check a reviewer could replay.
|
|
27
27
|
const VERIFY_COMMAND_PATTERN = /\b(npm (run )?test|node --test|node --check|node bin\/|pytest|cargo test|go test|make test|atris verify|grep\s+-[A-Za-z]*q[A-Za-z]*|rg\s+(?:-\S+\s+)*(?:"[^"]+"|'[^']+'|\S+)\s+(?:\.{0,2}\/|~\/|\/|[\w.-]+\/|[\w.-]+\.[A-Za-z0-9]|\b(?:atris|bin|commands|lib|scripts|src|test)\b)|git diff --(?:check|exit-code|quiet)|diff (?:-u|--brief)|cmp -s|test -[fs])\b|--verify\b|\bverify:\s/;
|
|
28
28
|
const COMMIT_REF_PATTERN = /\bcommit\s+[0-9a-f]{7,40}\b/i;
|
|
29
29
|
|
|
@@ -87,7 +87,7 @@ function acceptRate(withCount, againstCount) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// True when proofs carrying the feature get accepted at a higher rate than
|
|
90
|
-
// proofs without it
|
|
90
|
+
// proofs without it, the bar for emitting a feature lesson at all.
|
|
91
91
|
function featureHelps(counts) {
|
|
92
92
|
const withRate = acceptRate(counts.accepted_with, counts.revised_with);
|
|
93
93
|
const withoutRate = acceptRate(counts.accepted_without, counts.revised_without);
|
|
@@ -366,7 +366,7 @@ function syncLessonsMd(root, mined) {
|
|
|
366
366
|
const today = (mined.mined_at || new Date().toISOString()).split('T')[0];
|
|
367
367
|
const lines = (mined.lessons || []).map((lesson) => ({
|
|
368
368
|
id: lesson.id,
|
|
369
|
-
line: `- **[${today}] policy-${lesson.id}**
|
|
369
|
+
line: `- **[${today}] policy-${lesson.id}** \u2014 ${lesson.status || 'pass'} \u2014 ${lesson.lesson} (mined from ${mined.sources.career_xp_receipts} receipts / ${mined.sources.task_episodes} episodes / ${mined.sources.scorecards} scorecards)`,
|
|
370
370
|
}));
|
|
371
371
|
if (!lines.length) return { path: lessonsPath, written: [] };
|
|
372
372
|
|
|
@@ -374,7 +374,7 @@ function syncLessonsMd(root, mined) {
|
|
|
374
374
|
try {
|
|
375
375
|
content = fs.readFileSync(lessonsPath, 'utf8');
|
|
376
376
|
} catch {
|
|
377
|
-
content = '# lessons.md
|
|
377
|
+
content = '# lessons.md: What We Learned\n\n> Append-only. One line per lesson.\n\n---\n';
|
|
378
378
|
}
|
|
379
379
|
const written = [];
|
|
380
380
|
for (const { id, line } of lines) {
|
package/lib/pulse.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
//
|
|
5
5
|
// The /loop skill schedules a heartbeat via Claude Code's CronCreate, but that
|
|
6
6
|
// only fires while Claude Code is open and idle and dies with the session. The
|
|
7
|
-
// proven overnight pattern is an OS cron (see the commander tick.sh template)
|
|
7
|
+
// proven overnight pattern is an OS cron (see the commander tick.sh template),
|
|
8
8
|
// it fires regardless of whether Claude Code is running. `atris pulse` brings
|
|
9
9
|
// that pattern home: one OS-cron tick that runs the existing mission engine,
|
|
10
10
|
// verifies, and writes BOTH a pulse receipt (revives the Pulse AGI loop-health
|
|
@@ -32,7 +32,7 @@ const DEFAULT_CADENCE_CRON = '23 * * * *';
|
|
|
32
32
|
const STALE_TICK_MS = 30 * 60 * 1000;
|
|
33
33
|
// Liveness timeout: how long since the last finished tick before the loop reads
|
|
34
34
|
// as "stale" (stopped firing). Must exceed the cadence or it flaps stale between
|
|
35
|
-
// every tick
|
|
35
|
+
// every tick, default cadence is hourly, so allow ~2 missed ticks before alarm.
|
|
36
36
|
const LIVENESS_STALE_MS = 150 * 60 * 1000;
|
|
37
37
|
|
|
38
38
|
function stateDir(root) {
|
|
@@ -273,7 +273,7 @@ function buildInterruptedPulseReceipt(input = {}) {
|
|
|
273
273
|
|
|
274
274
|
// The heartbeat's full composition (mirrors the /loop skill): run the due
|
|
275
275
|
// mission to continue an existing goal; if none is due, fall back to an
|
|
276
|
-
// autopilot tick
|
|
276
|
+
// autopilot tick, that path is where proposeCandidateHorizons AUTHORS a new
|
|
277
277
|
// goal at an endgame boundary. The fallback needs a worker, so skip it under
|
|
278
278
|
// --no-claude (goal-authoring can't happen without the model in the loop).
|
|
279
279
|
function shouldFallbackToAutopilot({ missionReason, autopilotFallback = true, noClaude = false } = {}) {
|
|
@@ -285,12 +285,12 @@ function shouldFallbackToAutopilot({ missionReason, autopilotFallback = true, no
|
|
|
285
285
|
// Reward gating mirrors the improve.js tick-5 lesson: only verified,
|
|
286
286
|
// work-producing ticks earn positive reward; verify failure is punished;
|
|
287
287
|
// a tick that produced no work scores 0. `producedWork` MUST be the tick's
|
|
288
|
-
// actual delta (new commit or newly-dirtied files), never the whole dirty tree
|
|
288
|
+
// actual delta (new commit or newly-dirtied files), never the whole dirty tree.
|
|
289
289
|
// crediting pre-existing dirt re-rewards the same change every tick (the reward
|
|
290
290
|
// inflation bug). The caller computes producedWork from a before/after snapshot.
|
|
291
291
|
//
|
|
292
292
|
// A crashed engine must also score -1. Before this, a hard `mission error` tick
|
|
293
|
-
// produced no work and ran no verifier, so it scored 0
|
|
293
|
+
// produced no work and ran no verifier, so it scored 0, indistinguishable from
|
|
294
294
|
// a healthy idle tick. The 2026-07-16 heartbeat death proved the cost: 25
|
|
295
295
|
// consecutive error ticks left reward_sum flat, nothing escalated, and the loop
|
|
296
296
|
// stopped with a ledger that still read green. `actorReason: 'error'` is a
|
|
@@ -312,7 +312,7 @@ function shouldWriteScorecard({ reward } = {}) {
|
|
|
312
312
|
//
|
|
313
313
|
// A workspace without .git made producedWork permanently false (git snapshots
|
|
314
314
|
// return an empty delta), so every tick scored 0 regardless of what the engine
|
|
315
|
-
// wrote
|
|
315
|
+
// wrote, the loop was blind, not idle. When git is absent, pulse falls back to
|
|
316
316
|
// a filesystem snapshot: path → mtime+size, excluding churn dirs.
|
|
317
317
|
|
|
318
318
|
const FS_SNAPSHOT_SKIP = new Set(['.git', 'node_modules', '.atris']);
|
|
@@ -346,7 +346,7 @@ function fsSnapshot(root) {
|
|
|
346
346
|
return entries;
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
// New or modified files between two fsSnapshots. Deletions are ignored
|
|
349
|
+
// New or modified files between two fsSnapshots. Deletions are ignored, the
|
|
350
350
|
// signal we need is "did the tick author anything", not a full diff.
|
|
351
351
|
function diffFsSnapshots(before, after) {
|
|
352
352
|
const changed = [];
|
|
@@ -373,7 +373,7 @@ function defaultVerifyCmd(root) {
|
|
|
373
373
|
// --- ghost / stale detection (pure) ---
|
|
374
374
|
|
|
375
375
|
// Pair started+finished by tick_index; any 'started' with no 'finished' partner
|
|
376
|
-
// is a tick that crashed mid-run
|
|
376
|
+
// is a tick that crashed mid-run, exactly the silent-runner-death failure mode.
|
|
377
377
|
function findOrphanStarts(receipts) {
|
|
378
378
|
if (!Array.isArray(receipts)) return [];
|
|
379
379
|
const finished = new Set();
|
package/lib/receipt-evidence.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// atris/runs/. Validating those paths on disk turns "trust the prose" into
|
|
5
5
|
// "read the verifier state": the queue and accept surfaces show whether the
|
|
6
6
|
// receipts named in a proof exist and whether their verifiers passed. This
|
|
7
|
-
// informs the human gate
|
|
7
|
+
// informs the human gate, it never blocks it.
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
10
|
|
package/lib/reel.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// atris reel
|
|
1
|
+
// atris reel, a card, animated. A reel is the card from lib/card.js rendered at
|
|
2
2
|
// progress t in [0,1]: each element fades and rises in on a staggered schedule.
|
|
3
3
|
// Pure: (spec, t) -> HTML for that single frame. commands/reel.js screenshots the
|
|
4
4
|
// frames (same Chrome as card) and ffmpeg-encodes them. No new dependency.
|
package/lib/review-integrity.js
CHANGED
|
@@ -67,7 +67,7 @@ function independentReviewActors(task) {
|
|
|
67
67
|
|
|
68
68
|
// True when at least one review pass came from someone other than the
|
|
69
69
|
// builder. When the builder cannot be resolved at all, fall back to
|
|
70
|
-
// requiring two distinct actors
|
|
70
|
+
// requiring two distinct actors. Independence cannot be proven from one.
|
|
71
71
|
function hasIndependentReview(task) {
|
|
72
72
|
const builder = taskBuilder(task);
|
|
73
73
|
if (!builder) return reviewEventActors(task).size >= 2;
|
package/lib/runner-command.js
CHANGED
|
@@ -24,7 +24,7 @@ const RUNNER_PROFILE_DEFS = Object.freeze({
|
|
|
24
24
|
commandTemplate: '{bin} --fast {prompt}',
|
|
25
25
|
}),
|
|
26
26
|
// Guest engines: any installed headless coding CLI is a swappable worker.
|
|
27
|
-
// No commandTemplate on claude
|
|
27
|
+
// No commandTemplate on claude, the default spawn shape is already
|
|
28
28
|
// claude-compatible (bin -p prompt --model X --allowedTools ...).
|
|
29
29
|
claude: Object.freeze({
|
|
30
30
|
bin: 'claude',
|
|
@@ -70,8 +70,26 @@ const RUNNER_PROFILE_DEFS = Object.freeze({
|
|
|
70
70
|
}),
|
|
71
71
|
agy: Object.freeze({
|
|
72
72
|
bin: 'agy',
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
// gemini 3.8 flash is the 2026-09-04 bake-off pick beside opencode muse.
|
|
74
|
+
// --add-dir or agy edits its own scratch folder; the headless note or
|
|
75
|
+
// gemini stops to ask "may I edit?" and exits 0 having changed nothing.
|
|
76
|
+
model: 'gemini-3.8-flash-high',
|
|
77
|
+
commandTemplate: '{bin} --mode accept-edits --dangerously-skip-permissions --add-dir "$PWD" {modelFlag} -p "You are running headless with edit permission already granted. Apply changes directly and never ask for confirmation. "{prompt}',
|
|
78
|
+
}),
|
|
79
|
+
opencode: Object.freeze({
|
|
80
|
+
bin: 'opencode',
|
|
81
|
+
model: '',
|
|
82
|
+
commandTemplate: '{bin} run {prompt}',
|
|
83
|
+
}),
|
|
84
|
+
// Private engine: fully functional (routable, selectable, probeable) but
|
|
85
|
+
// kept out of every operator-facing list. For engines an operator wants to
|
|
86
|
+
// use without advertising them on the roster. No pinned model: headless
|
|
87
|
+
// print mode rides whatever this machine's Command Code default is.
|
|
88
|
+
commandcode: Object.freeze({
|
|
89
|
+
bin: 'cmd',
|
|
90
|
+
model: '',
|
|
91
|
+
commandTemplate: '{bin} -p {prompt}',
|
|
92
|
+
hidden: true,
|
|
75
93
|
}),
|
|
76
94
|
});
|
|
77
95
|
|
|
@@ -94,8 +112,19 @@ const RUNNER_PROFILES = Object.freeze(
|
|
|
94
112
|
])
|
|
95
113
|
);
|
|
96
114
|
|
|
97
|
-
// Operator-facing list: canonical profile names only (no alias noise)
|
|
98
|
-
|
|
115
|
+
// Operator-facing list: canonical profile names only (no alias noise), and no
|
|
116
|
+
// hidden profiles. Hidden profiles stay resolvable through RUNNER_PROFILES and
|
|
117
|
+
// canonicalEngineName; they just never appear in help text, error hints, or
|
|
118
|
+
// rosters.
|
|
119
|
+
const HIDDEN_PROFILE_NAMES = Object.freeze(
|
|
120
|
+
Object.entries(RUNNER_PROFILE_DEFS)
|
|
121
|
+
.filter(([, def]) => def.hidden === true)
|
|
122
|
+
.map(([name]) => name)
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const RUNNER_PROFILE_NAMES = Object.freeze(
|
|
126
|
+
Object.keys(RUNNER_PROFILE_DEFS).filter((name) => !HIDDEN_PROFILE_NAMES.includes(name))
|
|
127
|
+
);
|
|
99
128
|
|
|
100
129
|
function shellWord(value) {
|
|
101
130
|
const s = String(value || '');
|
|
@@ -227,6 +256,7 @@ module.exports = {
|
|
|
227
256
|
RUNNER_PROFILE_DEFS,
|
|
228
257
|
RUNNER_PROFILE_ALIASES,
|
|
229
258
|
RUNNER_PROFILE_NAMES,
|
|
259
|
+
HIDDEN_PROFILE_NAMES,
|
|
230
260
|
resolveRunnerProfile,
|
|
231
261
|
resolveClaudeRunnerModel,
|
|
232
262
|
resolveClaudeRunnerBin,
|
package/lib/scorecard.js
CHANGED
|
@@ -245,14 +245,14 @@ function writeScorecard(atrisDir, data) {
|
|
|
245
245
|
|
|
246
246
|
// Ensure scorecards.md exists
|
|
247
247
|
if (!fs.existsSync(scorecardsPath)) {
|
|
248
|
-
const template = `# scorecards.md
|
|
248
|
+
const template = `# scorecards.md \u2014 Endgame Results\n\n> Append-only. One line per closed endgame. Records outcome metrics from the horizon.\n\n---\n\n`;
|
|
249
249
|
fs.writeFileSync(scorecardsPath, template, 'utf8');
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
// Format: - **[date] slug
|
|
252
|
+
// Format: - **[date] slug**, shipped: X/Y, wall-clock: Nh, halt: Z%, reward: total, lessons: N
|
|
253
253
|
const haltPercent = Math.round(haltRatio * 100);
|
|
254
254
|
const wallClockStr = wallClockHours < 1 ? `${Math.round(wallClockHours * 60)}m` : `${wallClockHours.toFixed(1)}h`;
|
|
255
|
-
const line = `- **[${endDate}] ${slug}**
|
|
255
|
+
const line = `- **[${endDate}] ${slug}** \u2014 shipped: ${tasksShipped}/${tasksAttempted} \u2014 wall-clock: ${wallClockStr} \u2014 halt: ${haltPercent}% \u2014 reward: ${totalReward} \u2014 lessons: ${lessonsGenerated}\n`;
|
|
256
256
|
|
|
257
257
|
// Append to file
|
|
258
258
|
fs.appendFileSync(scorecardsPath, line, 'utf8');
|
|
@@ -302,7 +302,7 @@ function readScorecards(atrisDir) {
|
|
|
302
302
|
const scorecards = [];
|
|
303
303
|
|
|
304
304
|
for (const line of content.split('\n')) {
|
|
305
|
-
const match = line.match(/^- \*\*\[(.+?)\]\s+(.+?)\*\*\s
|
|
305
|
+
const match = line.match(/^- \*\*\[(.+?)\]\s+(.+?)\*\*\s*\u2014\s*shipped:\s*(\d+)\/(\d+)\s*\u2014\s*wall-clock:\s*(.+?)\s*\u2014\s*halt:\s*(\d+)%\s*\u2014\s*reward:\s*(-?\d+)\s*\u2014\s*lessons:\s*(\d+)$/);
|
|
306
306
|
if (!match) continue;
|
|
307
307
|
|
|
308
308
|
const [, endDate, slug, shipped, attempted, wallClockStr, haltPercent, reward, lessons] = match;
|
package/lib/security-scan.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// atris security scan
|
|
3
|
+
// atris security scan: deterministic secrets / PII / privacy detectors (no LLM).
|
|
4
4
|
//
|
|
5
5
|
// A finding is a fact (file:line + rule + severity), so it drops straight into a
|
|
6
6
|
// loop / mission / CI gate and doubles as a SOC 2 evidence artifact (machine
|
|
7
7
|
// JSON). Precision over recall: a noisy gate gets muted, and a muted gate is dead.
|
|
8
8
|
// Suppress a single line with a trailing `atris-allow-secret` comment.
|
|
9
9
|
//
|
|
10
|
-
// Zero external deps (Node built-ins only)
|
|
10
|
+
// Zero external deps (Node built-ins only). Repo contract.
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
@@ -77,7 +77,7 @@ const PII_RULES = [
|
|
|
77
77
|
// Code-execution risks. For an AI CLI that runs autonomous loops and shells out,
|
|
78
78
|
// these are the "are we actually safe" checks beyond data exposure. eval/Function
|
|
79
79
|
// are almost never legitimate (HIGH); shelling out with interpolated input is the
|
|
80
|
-
// command-injection class (MEDIUM
|
|
80
|
+
// command-injection class (MEDIUM, common and sometimes safe, so it asks for a
|
|
81
81
|
// human look rather than hard-failing the gate).
|
|
82
82
|
const CODE_RULES = [
|
|
83
83
|
{ id: 'eval-call', sev: 'medium', cat: 'code', re: /(?<![.\w])eval\((?!\s*\))/, why: 'eval() can run untrusted code' },
|
|
@@ -271,7 +271,7 @@ function scanText(text, rules = RULES) {
|
|
|
271
271
|
return out;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
// Code-execution rules only make sense in actual code files
|
|
274
|
+
// Code-execution rules only make sense in actual code files, `eval(` written in
|
|
275
275
|
// a markdown doc is prose, not a vuln.
|
|
276
276
|
const CODE_EXTS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.jsx', '.py', '.rb', '.go', '.java', '.php', '.sh', '.bash', '.zsh']);
|
|
277
277
|
const DOC_EXTS = new Set(['.md', '.mdx', '.txt', '.patch']);
|
|
@@ -359,7 +359,7 @@ function resolveTargets({ root = process.cwd(), paths = [], staged = false } = {
|
|
|
359
359
|
|
|
360
360
|
// Full scan: line-level findings across files + repo hygiene findings.
|
|
361
361
|
// The scanner's own pattern database and its fixtures necessarily contain the
|
|
362
|
-
// very strings it detects
|
|
362
|
+
// very strings it detects. Never scan them (a tool that flags itself is noise).
|
|
363
363
|
const SELF_FILES = new Set(['lib/security-scan.js', 'commands/security-review.js', 'test/security-scan.test.js']);
|
|
364
364
|
|
|
365
365
|
function runScan({ root = process.cwd(), paths = [], staged = false } = {}) {
|
package/lib/self-drive.js
CHANGED
|
@@ -66,7 +66,7 @@ function postBlockerToFleet({ task, blockerClass, stopReason, mission }, injecte
|
|
|
66
66
|
const apiKey = loadKey();
|
|
67
67
|
if (!apiKey) return { posted: false, channel };
|
|
68
68
|
const ref = taskRef(task);
|
|
69
|
-
const content = `Mission blocker filed with no local engine ready: ${ref}
|
|
69
|
+
const content = `Mission blocker filed with no local engine ready: ${ref}: ${String(stopReason || blockerClass).trim()}. Mission: ${String(mission?.objective || mission?.id || '').trim()}.`;
|
|
70
70
|
const response = httpPost(`${SWARLO_HUB}/api/${SWARLO_HUB_ID}/channels/${channel}/posts`, {
|
|
71
71
|
headers: {
|
|
72
72
|
'Content-Type': 'application/json',
|