atris 3.37.0 → 3.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/atris/PERSONA.md +3 -7
- package/atris.md +10 -2
- package/ax +158 -33
- package/bin/atris.js +49 -2
- package/commands/activate.js +16 -3
- package/commands/agent-spawn.js +0 -7
- package/commands/autoland.js +92 -14
- package/commands/autopilot-front.js +0 -4
- package/commands/autopilot.js +0 -12
- package/commands/brain.js +0 -7
- package/commands/brief.js +0 -2
- package/commands/business-sync.js +0 -1
- package/commands/business.js +107 -12
- package/commands/clean.js +31 -2
- package/commands/close.js +46 -11
- package/commands/cloud.js +0 -1
- package/commands/codex-goal.js +0 -2
- package/commands/computer.js +6 -5
- package/commands/console.js +46 -9
- package/commands/deck.js +29 -8
- package/commands/dream.js +0 -7
- package/commands/drill.js +0 -1
- package/commands/engine.js +10 -18
- package/commands/experiments.js +0 -4
- package/commands/fleet-report.js +12 -4
- package/commands/game.js +261 -0
- package/commands/gm.js +10 -2
- package/commands/goal.js +0 -6
- package/commands/harvest.js +0 -1
- package/commands/improve.js +29 -8
- package/commands/init.js +18 -34
- package/commands/integrations.js +0 -7
- package/commands/land.js +71 -8
- package/commands/launchpad.js +0 -2
- package/commands/lesson.js +17 -7
- package/commands/loop-front.js +0 -2
- package/commands/loops.js +6 -5
- package/commands/meet.js +0 -2
- package/commands/member.js +68 -3
- package/commands/mission.js +359 -102
- package/commands/next.js +0 -1
- package/commands/now.js +0 -12
- package/commands/one-lap.js +8 -8
- package/commands/orb.js +0 -4
- package/commands/pack-craft.js +0 -1
- package/commands/pack.js +670 -77
- package/commands/play.js +0 -2
- package/commands/probe.js +10 -4
- package/commands/pulse.js +73 -48
- package/commands/push.js +0 -4
- package/commands/radar.js +14 -11
- package/commands/recover.js +340 -0
- package/commands/report.js +0 -1
- package/commands/router.js +319 -0
- package/commands/run-front.js +0 -2
- package/commands/search.js +0 -3
- package/commands/skill.js +7 -2
- package/commands/slop.js +225 -7
- package/commands/status.js +6 -0
- package/commands/stream.js +0 -2
- package/commands/study.js +0 -3
- package/commands/sync-checkout.js +51 -0
- package/commands/sync.js +11 -40
- package/commands/task.js +125 -39
- package/commands/teach.js +86 -0
- package/commands/unknowns.js +0 -10
- package/commands/update.js +0 -1
- package/commands/visualize.js +0 -5
- package/commands/watch.js +0 -6
- package/commands/wiki.js +41 -11
- package/commands/wish.js +0 -1
- package/commands/worktree.js +87 -14
- package/commands/xp.js +1 -6
- package/commands/youtube.js +0 -2
- package/lib/accept-verify-gate.js +122 -0
- package/lib/activity-stream.js +0 -2
- package/lib/auto-accept-certified.js +145 -2
- package/lib/autoland.js +0 -3
- package/lib/ax-auto-lane.js +94 -10
- package/lib/bench/context.js +0 -2
- package/lib/bench/report.js +0 -1
- package/lib/bench/runner.js +0 -11
- package/lib/brief-ledger.js +0 -6
- package/lib/business-simulate.js +382 -0
- package/lib/chat-log-scan.js +0 -5
- package/lib/checkout-sync.js +52 -0
- package/lib/claude-boot-block.js +48 -0
- package/lib/cloud-mission.js +0 -6
- package/lib/codex-flight.js +0 -1
- package/lib/conductor-artifacts.js +25 -0
- package/lib/context-gatherer.js +0 -1
- package/lib/deck-compose.js +0 -1
- package/lib/deck-history.js +0 -1
- package/lib/deck-layout.js +0 -5
- package/lib/deck-review.js +0 -7
- package/lib/deck-schema.js +0 -1
- package/lib/default-verifier.js +0 -2
- package/lib/engine-registry.js +16 -8
- package/lib/experiments/daily.js +0 -6
- package/lib/fleet.js +210 -27
- package/lib/functional-owner.js +0 -3
- package/lib/inspect-fields.js +0 -1
- package/lib/known-commands.js +2 -2
- package/lib/learnings.js +0 -2
- package/lib/loop-doctor.js +11 -17
- package/lib/manifest.js +0 -2
- package/lib/member-alive.js +0 -1
- package/lib/member-switches.js +0 -5
- package/lib/mission-artifact.js +0 -1
- package/lib/mission-protected-lane.js +293 -0
- package/lib/mission-room.js +0 -2
- package/lib/mission-runtime-loop.js +0 -1
- package/lib/next-moves.js +0 -18
- package/lib/official-cli-integration.js +0 -4
- package/lib/orb-context.js +6 -3
- package/lib/orb-scorecard.js +0 -1
- package/lib/outbound-send-gate.js +0 -6
- package/lib/permission-grants.js +0 -6
- package/lib/policy-lessons.js +0 -2
- package/lib/pulse.js +68 -15
- package/lib/review-integrity.js +0 -2
- package/lib/router-brain.js +0 -2
- package/lib/runner-command.js +0 -4
- package/lib/runtime-bootstrap.js +0 -1
- package/lib/scorecard.js +0 -1
- package/lib/self-drive.js +1 -1
- package/lib/state-detection.js +0 -6
- package/lib/task-db.js +0 -4
- package/lib/team-presence.js +0 -1
- package/lib/voice-gate.js +63 -2
- package/lib/wiki.js +152 -9
- package/lib/wish-audit.js +20 -6
- package/lib/wish-delegate.js +26 -20
- package/lib/wish-stats.js +0 -5
- package/lib/wish-store.js +0 -1
- package/lib/workspace-safety.js +0 -2
- package/lib/zip.js +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -226,6 +226,8 @@ atris business record atris/reports/2026-04-12-operator-recap.md --outcome mixed
|
|
|
226
226
|
| `atris experiments` | Run small experiments and compare results |
|
|
227
227
|
| `atris computer card` | Show or write the local owner/computer card |
|
|
228
228
|
| `atris release` | Draft or publish a version bump, tag, GitHub release, and launch post |
|
|
229
|
+
| `atris slop` | Deterministic slop detector: frontend/prose tells, plus `slop dead --exports` for dead code |
|
|
230
|
+
| `atris clean` | Housekeeping: heal MAP refs, archive journals, report stale pages and dead code |
|
|
229
231
|
|
|
230
232
|
## Built-In Systems
|
|
231
233
|
|
package/atris/PERSONA.md
CHANGED
|
@@ -30,19 +30,15 @@ This defines how Atris agents communicate, decide, and work.
|
|
|
30
30
|
|
|
31
31
|
**Read before you act.** Before planning or building, read the relevant files. Understand the current state. Your first action in any new area is always reconnaissance — not execution.
|
|
32
32
|
|
|
33
|
-
**
|
|
33
|
+
**Ask for intent when it's fuzzy or the blast radius is real.** A vague brief gets 2-3 named interpretations with a recommendation, not open questions. Small, reversible, clearly-scoped work: act, then report. Standing autonomy (autoland, push-asap) means asking permission for routine work is a failure smell, not politeness.
|
|
34
34
|
|
|
35
|
-
**Use ASCII visualization to confirm understanding:**
|
|
35
|
+
**Use ASCII visualization to confirm understanding when a plan is worth confirming:**
|
|
36
36
|
- **UI elements:** Show design using ASCII
|
|
37
37
|
- **Backend:** Use arrows, diagrams, logic gates
|
|
38
38
|
- **Databases:** Tables and graphs showing relationships
|
|
39
39
|
- **Other cases:** Use best judgment
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Then go 3-4 sentences one by one through each task.
|
|
44
|
-
|
|
45
|
-
Once every task is confirmed, create a plan.
|
|
41
|
+
A one-file fix needs no diagram; a new surface or cross-system change does.
|
|
46
42
|
|
|
47
43
|
**If a task is too big, break it down.** One job per task. If you can't describe "done" in one sentence, decompose it. Small precise tasks compound into big results.
|
|
48
44
|
|
package/atris.md
CHANGED
|
@@ -7,7 +7,9 @@ leave a trail another agent or human can trust.
|
|
|
7
7
|
|
|
8
8
|
## activate
|
|
9
9
|
|
|
10
|
-
On session start, before responding
|
|
10
|
+
On session start, before responding (if the harness already booted for you, via a
|
|
11
|
+
SessionStart hook or an `atris` status block in context, do not repeat it; go
|
|
12
|
+
straight to the work):
|
|
11
13
|
|
|
12
14
|
1. Read:
|
|
13
15
|
- `atris/logs/YYYY/YYYY-MM-DD.md`: today's journal
|
|
@@ -39,13 +41,17 @@ If a task was already given, show the box and proceed with that task.
|
|
|
39
41
|
|
|
40
42
|
You can move fast. You do not get to move blindly.
|
|
41
43
|
|
|
42
|
-
Before
|
|
44
|
+
Scale ceremony to blast radius. Before a nontrivial change (new surface,
|
|
45
|
+
multi-file, migrations, anything hard to roll back), state:
|
|
43
46
|
- the goal
|
|
44
47
|
- the files or systems in scope
|
|
45
48
|
- what "done" means
|
|
46
49
|
- how it will be checked
|
|
47
50
|
- what happens if it fails
|
|
48
51
|
|
|
52
|
+
For a small bounded fix, the task's Exit and Verify fields carry this; do not
|
|
53
|
+
restate them as ritual.
|
|
54
|
+
|
|
49
55
|
Then:
|
|
50
56
|
- when you begin work in a repo that has no `atris/` folder, run `npx -y atris init` before anything else, then read `atris/atris.md`
|
|
51
57
|
- do not execute if another agent owns the same task or files
|
|
@@ -90,6 +96,8 @@ The same discipline for words. Output stays sharp no matter how bloated the cont
|
|
|
90
96
|
- "Missions survive everything: one engine starts the work, another picks it up cold, a third lands it. Work is no longer tied to a chat window, a session, or a vendor."
|
|
91
97
|
- "The system reports in plain English: one daily message with what landed, what waits on you, and who should own what's next. One person can supervise many projects."
|
|
92
98
|
- **Fit the screen.** An operator-facing report shows three results, air between them, and holds the rest on ask. No scrolling: reading it is one glance, and the reader asks for more if they want more.
|
|
99
|
+
- **Pace with whitespace.** Words for the operator arrive as complete sentences, one or two per paragraph, blank line between. The whitespace does the pacing, never fragments: fast to scan, still flowing.
|
|
100
|
+
- **Assume attention is scarce and ambition is not.** The reader is at the end of a long day and still moving something big forward. Nothing may require held state (remembering step 2 while reading step 5), every surface ends in one obvious next action that starts in under a minute, and each glance should leave the reader one step closer. Engineers and non-engineers get the same plain sentence; precision stays one ask away, never in the way.
|
|
93
101
|
- **Human surfaces are gated.** Anything rendered for the operator (brief, digest, boot) goes through the operator-voice translator and a deterministic jargon gate; raw ids, commands, paths, and test tallies never reach a page. A gate violation is a build error, not a style note.
|
|
94
102
|
- **Interview the fuzz.** When the operator hands off a fuzzy build ("make me the best X", "yeah ok this is my thought, go make it"), do not ask open questions and do not dispatch as-is. Offer 2-3 named interpretations with a recommendation ("best could mean capture, resurfacing, or closure: I'd bet resurfacing, right?") so the operator confirms or corrects in five words. Repeat until the brief fits one screen (goal, why now, done-looks-like, open risks), show the brief, then dispatch. The interview lends the operator a structure to think in; the sharpened brief is what makes every downstream lap cheap.
|
|
95
103
|
|
package/ax
CHANGED
|
@@ -12,7 +12,7 @@ const permissionGrants = require(path.join(__dirname, 'lib', 'permission-grants.
|
|
|
12
12
|
const { loadCredentials } = require('./utils/auth');
|
|
13
13
|
const { apiRequestJson, getApiBaseUrl } = require('./utils/api');
|
|
14
14
|
const missionRuntime = require('./lib/mission-runtime-loop');
|
|
15
|
-
const { pickLane } = require('./lib/ax-auto-lane');
|
|
15
|
+
const { loadOverrides, pickLane } = require('./lib/ax-auto-lane');
|
|
16
16
|
|
|
17
17
|
const EXIT_WORDS = new Set(['exit', 'quit', ':q']);
|
|
18
18
|
const BACKEND = {
|
|
@@ -957,16 +957,92 @@ function normalizeMode(mode) {
|
|
|
957
957
|
return mode === 'fast' ? 'fast' : 'pro';
|
|
958
958
|
}
|
|
959
959
|
|
|
960
|
+
function autoPickLogPath(options = {}) {
|
|
961
|
+
return options.pickLogPath
|
|
962
|
+
|| process.env.ATRIS_ROUTER_PICKS_PATH
|
|
963
|
+
|| path.join(os.homedir(), '.atris', 'ax-auto-picks.jsonl');
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function autoMessageWords(message) {
|
|
967
|
+
return new Set(String(message || '').toLowerCase().match(/[a-z0-9]+/g) || []);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function autoMessageOverlap(left, right) {
|
|
971
|
+
const leftWords = autoMessageWords(left);
|
|
972
|
+
const rightWords = autoMessageWords(right);
|
|
973
|
+
const union = new Set([...leftWords, ...rightWords]);
|
|
974
|
+
if (!union.size) return 0;
|
|
975
|
+
let shared = 0;
|
|
976
|
+
for (const word of leftWords) {
|
|
977
|
+
if (rightWords.has(word)) shared += 1;
|
|
978
|
+
}
|
|
979
|
+
return shared / union.size;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function appendRephrasedOutcome(message, logPath) {
|
|
983
|
+
try {
|
|
984
|
+
const rows = fs.readFileSync(logPath, 'utf8').split(/\r?\n/).filter((line) => line.trim());
|
|
985
|
+
let previous = null;
|
|
986
|
+
for (let index = rows.length - 1; index >= 0; index -= 1) {
|
|
987
|
+
try {
|
|
988
|
+
const row = JSON.parse(rows[index]);
|
|
989
|
+
if (row && row.pick_id && row.lane && row.message) {
|
|
990
|
+
previous = row;
|
|
991
|
+
break;
|
|
992
|
+
}
|
|
993
|
+
} catch (_) {
|
|
994
|
+
// Ignore malformed historical lines.
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
if (!previous) return;
|
|
998
|
+
const ageMs = Date.now() - Date.parse(previous.at);
|
|
999
|
+
if (ageMs < 0 || ageMs >= 10 * 60 * 1000) return;
|
|
1000
|
+
if (autoMessageOverlap(previous.message, message) < 0.5) return;
|
|
1001
|
+
fs.appendFileSync(logPath, `${JSON.stringify({
|
|
1002
|
+
event: 'outcome',
|
|
1003
|
+
pick_id: previous.pick_id,
|
|
1004
|
+
outcome: 'rephrased',
|
|
1005
|
+
})}\n`);
|
|
1006
|
+
} catch (_) {
|
|
1007
|
+
// Rephrase detection is best-effort and must never block a turn.
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
960
1011
|
function appendAutoPick(message, picked, options = {}) {
|
|
1012
|
+
const pick = { ...picked, pick_id: crypto.randomUUID() };
|
|
1013
|
+
const logPath = autoPickLogPath(options);
|
|
1014
|
+
Object.defineProperty(pick, '_logPath', { value: logPath, enumerable: false });
|
|
961
1015
|
try {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
fs.appendFileSync(
|
|
1016
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
1017
|
+
appendRephrasedOutcome(message, logPath);
|
|
1018
|
+
fs.appendFileSync(logPath, `${JSON.stringify({
|
|
965
1019
|
at: new Date().toISOString(),
|
|
966
|
-
|
|
967
|
-
|
|
1020
|
+
pick_id: pick.pick_id,
|
|
1021
|
+
lane: pick.lane,
|
|
1022
|
+
reason: pick.reason,
|
|
1023
|
+
message: String(message || ''),
|
|
968
1024
|
message_chars: String(message || '').length,
|
|
969
1025
|
print: Boolean(options.print),
|
|
1026
|
+
...(pick.override_id ? { override_id: pick.override_id } : {}),
|
|
1027
|
+
})}\n`);
|
|
1028
|
+
} catch (_) {
|
|
1029
|
+
// Lane telemetry is best-effort and must never block a turn.
|
|
1030
|
+
}
|
|
1031
|
+
return pick;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function appendAutoOutcome(picked, result, options = {}) {
|
|
1035
|
+
if (!picked || !picked.pick_id) return;
|
|
1036
|
+
try {
|
|
1037
|
+
const logPath = autoPickLogPath({ pickLogPath: options.pickLogPath || picked._logPath });
|
|
1038
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
1039
|
+
fs.appendFileSync(logPath, `${JSON.stringify({
|
|
1040
|
+
event: 'outcome',
|
|
1041
|
+
pick_id: picked.pick_id,
|
|
1042
|
+
ok: Boolean(result && result.ok),
|
|
1043
|
+
model: String((result && result.model) || modelForMode(picked.lane)),
|
|
1044
|
+
duration_ms: Number((result && (result.duration_ms || result.durationMs)) || 0),
|
|
1045
|
+
error: result && result.error ? String(result.error) : null,
|
|
970
1046
|
})}\n`);
|
|
971
1047
|
} catch (_) {
|
|
972
1048
|
// Lane telemetry is best-effort and must never block a turn.
|
|
@@ -974,8 +1050,10 @@ function appendAutoPick(message, picked, options = {}) {
|
|
|
974
1050
|
}
|
|
975
1051
|
|
|
976
1052
|
function autoLaneForMessage(message, options = {}) {
|
|
977
|
-
const
|
|
978
|
-
|
|
1053
|
+
const overrides = Array.isArray(options.overrides)
|
|
1054
|
+
? options.overrides
|
|
1055
|
+
: loadOverrides(options.overridesPath);
|
|
1056
|
+
const picked = appendAutoPick(message, pickLane(message, { overrides }), options);
|
|
979
1057
|
const errorOutput = options.errorOutput || process.stderr;
|
|
980
1058
|
errorOutput.write(`${picked.reason}\n`);
|
|
981
1059
|
return picked;
|
|
@@ -3016,8 +3094,11 @@ async function runHeadlessTurn(message, options = {}) {
|
|
|
3016
3094
|
const startedAt = Date.now();
|
|
3017
3095
|
const sink = options.output || bufferedOutput();
|
|
3018
3096
|
const turnFunction = options.turnFunction || turnFunctionForMode(mode);
|
|
3019
|
-
const
|
|
3020
|
-
|
|
3097
|
+
const autoPick = options.autoPick || null;
|
|
3098
|
+
const autoFields = autoPick
|
|
3099
|
+
? { auto_lane: normalizeMode(autoPick.lane), auto_reason: String(autoPick.reason) }
|
|
3100
|
+
: options.autoLane && options.autoReason
|
|
3101
|
+
? { auto_lane: normalizeMode(options.autoLane), auto_reason: String(options.autoReason) }
|
|
3021
3102
|
: {};
|
|
3022
3103
|
|
|
3023
3104
|
try {
|
|
@@ -3030,15 +3111,17 @@ async function runHeadlessTurn(message, options = {}) {
|
|
|
3030
3111
|
output: sink,
|
|
3031
3112
|
showProgress: false,
|
|
3032
3113
|
});
|
|
3033
|
-
|
|
3114
|
+
const payload = {
|
|
3034
3115
|
ok: true,
|
|
3035
3116
|
model: modelForMode(mode),
|
|
3036
3117
|
output: String((result && result.output) || '').trim(),
|
|
3037
3118
|
durationMs: Number((result && result.durationMs) || 0) || (Date.now() - startedAt),
|
|
3038
3119
|
...autoFields,
|
|
3039
3120
|
};
|
|
3121
|
+
appendAutoOutcome(autoPick, payload);
|
|
3122
|
+
return payload;
|
|
3040
3123
|
} catch (error) {
|
|
3041
|
-
|
|
3124
|
+
const payload = {
|
|
3042
3125
|
ok: false,
|
|
3043
3126
|
model: modelForMode(mode),
|
|
3044
3127
|
output: '',
|
|
@@ -3046,6 +3129,8 @@ async function runHeadlessTurn(message, options = {}) {
|
|
|
3046
3129
|
error: String((error && error.message) || error || 'headless turn failed'),
|
|
3047
3130
|
...autoFields,
|
|
3048
3131
|
};
|
|
3132
|
+
appendAutoOutcome(autoPick, payload);
|
|
3133
|
+
return payload;
|
|
3049
3134
|
}
|
|
3050
3135
|
}
|
|
3051
3136
|
|
|
@@ -3125,11 +3210,16 @@ async function chat(options = {}) {
|
|
|
3125
3210
|
return false;
|
|
3126
3211
|
}
|
|
3127
3212
|
|
|
3213
|
+
let autoPick = null;
|
|
3128
3214
|
if (options.auto) {
|
|
3129
|
-
|
|
3215
|
+
autoPick = autoLaneForMessage(trimmed, {
|
|
3130
3216
|
errorOutput: options.errorOutput,
|
|
3131
3217
|
print: false,
|
|
3132
|
-
|
|
3218
|
+
overrides: options.overrides,
|
|
3219
|
+
overridesPath: options.overridesPath,
|
|
3220
|
+
pickLogPath: options.pickLogPath,
|
|
3221
|
+
});
|
|
3222
|
+
mode = autoPick.lane;
|
|
3133
3223
|
}
|
|
3134
3224
|
|
|
3135
3225
|
if (logger) logger.write(`${formatPrompt(mode)}${trimmed}\n`);
|
|
@@ -3230,22 +3320,38 @@ async function chat(options = {}) {
|
|
|
3230
3320
|
lastCompactionNotice = compactedTurns;
|
|
3231
3321
|
output.write(`${paint(`· context: ${compactedTurns} earlier turn${compactedTurns === 1 ? '' : 's'} compacted into a digest`, [ANSI.muted], output)}\n`);
|
|
3232
3322
|
}
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3323
|
+
let result;
|
|
3324
|
+
try {
|
|
3325
|
+
result = await turnFunction(trimmed, {
|
|
3326
|
+
mode,
|
|
3327
|
+
cwd,
|
|
3328
|
+
history,
|
|
3329
|
+
input,
|
|
3330
|
+
output,
|
|
3331
|
+
route,
|
|
3332
|
+
business: options.business,
|
|
3333
|
+
verify: options.verify,
|
|
3334
|
+
conversationId,
|
|
3335
|
+
turnId,
|
|
3336
|
+
approveBackendApi: options.approveBackendApi,
|
|
3337
|
+
apiRequestJson: options.apiRequestJson,
|
|
3338
|
+
loadCredentials: options.loadCredentials,
|
|
3339
|
+
getApiBaseUrl: options.getApiBaseUrl,
|
|
3340
|
+
});
|
|
3341
|
+
appendAutoOutcome(autoPick, {
|
|
3342
|
+
ok: true,
|
|
3343
|
+
model: modelForMode(mode),
|
|
3344
|
+
durationMs: Number(result && result.durationMs) || (Date.now() - turnStartedAt),
|
|
3345
|
+
});
|
|
3346
|
+
} catch (error) {
|
|
3347
|
+
appendAutoOutcome(autoPick, {
|
|
3348
|
+
ok: false,
|
|
3349
|
+
model: modelForMode(mode),
|
|
3350
|
+
durationMs: Date.now() - turnStartedAt,
|
|
3351
|
+
error: String((error && error.message) || error),
|
|
3352
|
+
});
|
|
3353
|
+
throw error;
|
|
3354
|
+
}
|
|
3249
3355
|
if (result.output && !result.output.endsWith('\n')) output.write('\n');
|
|
3250
3356
|
const approvalExecution = normalizeMode(mode) === 'code-fast'
|
|
3251
3357
|
? null
|
|
@@ -4288,8 +4394,7 @@ async function main() {
|
|
|
4288
4394
|
route: route === 'auto' ? undefined : route,
|
|
4289
4395
|
business,
|
|
4290
4396
|
verify,
|
|
4291
|
-
|
|
4292
|
-
autoReason: autoPick && autoPick.reason,
|
|
4397
|
+
autoPick,
|
|
4293
4398
|
})
|
|
4294
4399
|
: { ok: false, model: modelForMode(mode), output: '', durationMs: 0, error: 'missing prompt' };
|
|
4295
4400
|
console.log(JSON.stringify(payload));
|
|
@@ -4305,7 +4410,23 @@ async function main() {
|
|
|
4305
4410
|
console.log('');
|
|
4306
4411
|
maybeWriteAtrisGoalBanner(process.stdout, process.cwd());
|
|
4307
4412
|
const turnStartedAt = Date.now();
|
|
4308
|
-
|
|
4413
|
+
let result;
|
|
4414
|
+
try {
|
|
4415
|
+
result = await turnFunctionForMode(mode)(prompt, { mode, cwd: process.cwd(), route: route === 'auto' ? undefined : route, business, verify });
|
|
4416
|
+
appendAutoOutcome(autoPick, {
|
|
4417
|
+
ok: true,
|
|
4418
|
+
model: modelForMode(mode),
|
|
4419
|
+
durationMs: Number(result && result.durationMs) || (Date.now() - turnStartedAt),
|
|
4420
|
+
});
|
|
4421
|
+
} catch (error) {
|
|
4422
|
+
appendAutoOutcome(autoPick, {
|
|
4423
|
+
ok: false,
|
|
4424
|
+
model: modelForMode(mode),
|
|
4425
|
+
durationMs: Date.now() - turnStartedAt,
|
|
4426
|
+
error: String((error && error.message) || error),
|
|
4427
|
+
});
|
|
4428
|
+
throw error;
|
|
4429
|
+
}
|
|
4309
4430
|
const receipt = receiptFromState(result);
|
|
4310
4431
|
const approvalRequest = normalizeMode(mode) === 'code-fast' ? null : approvalRequestFromReceipt(receipt);
|
|
4311
4432
|
const approvalRecord = approvalRequest
|
|
@@ -4338,6 +4459,10 @@ if (require.main === module) {
|
|
|
4338
4459
|
}
|
|
4339
4460
|
|
|
4340
4461
|
module.exports = {
|
|
4462
|
+
appendAutoOutcome,
|
|
4463
|
+
appendAutoPick,
|
|
4464
|
+
autoLaneForMessage,
|
|
4465
|
+
autoMessageOverlap,
|
|
4341
4466
|
authToken,
|
|
4342
4467
|
authUserId,
|
|
4343
4468
|
approvalExecutionRequestFromReceipt,
|
package/bin/atris.js
CHANGED
|
@@ -519,6 +519,8 @@ function showHelp() {
|
|
|
519
519
|
console.log(' close - track open loops with deadlines and daily escalation');
|
|
520
520
|
console.log(' harvest - Find bugs and next actions from receipts, run logs, and thinking');
|
|
521
521
|
console.log(' verify - Validate work is done (tests, MAP.md, changes)');
|
|
522
|
+
console.log(' slop - Deterministic slop detector: frontend/prose tells, dead code (slop dead --exports)');
|
|
523
|
+
console.log(' recover - Explain stopped missions; --apply performs safe recovery only');
|
|
522
524
|
console.log(' task - Local agent task plane (atomic claims, TODO import)');
|
|
523
525
|
console.log(' golden path (zero human turns):');
|
|
524
526
|
console.log(' atris task delegate "fix the login bug" --to <member>');
|
|
@@ -535,10 +537,11 @@ function showHelp() {
|
|
|
535
537
|
console.log(' avail - Booking availability (/book/{username} weekly windows)');
|
|
536
538
|
console.log(' brain - Compile MAP/TODO/wiki/state into a loadable agent brain');
|
|
537
539
|
console.log(' lesson - Append a one-line lesson to atris/lessons.md (mine: distill receipts/episodes/scorecards into policy lessons)');
|
|
540
|
+
console.log(' teach - Turn a bad turn into a failing benchmark, then a permanent guard (red gate: no promotion without a proven failure)');
|
|
538
541
|
console.log(' ingest - Local-first wiki ingest into atris/wiki/');
|
|
539
542
|
console.log(' query - Local-first wiki query against atris/wiki/');
|
|
540
543
|
console.log(' lint - Local-first wiki lint for atris/wiki/');
|
|
541
|
-
console.log(' loop -
|
|
544
|
+
console.log(' loop - Recurring loops front door (wiki upkeep lives under: loop wiki)');
|
|
542
545
|
console.log(' write - Guided writing sessions: you write every word, atris structures + reviews');
|
|
543
546
|
console.log('');
|
|
544
547
|
console.log('Optional helpers:');
|
|
@@ -550,6 +553,7 @@ function showHelp() {
|
|
|
550
553
|
console.log(' drive - One self-driving tick: mission doctor -> auto-fix -> count disengagements');
|
|
551
554
|
console.log(' autoland - Approve the policy once; certified work lands itself, you keep irreversible calls');
|
|
552
555
|
console.log(' engine - Engine registry: list/resolve roles, health flips, default engine, `engine test`, and dispatch flights');
|
|
556
|
+
console.log(' router - inspect ax lane outcomes and promote gated reflex overrides');
|
|
553
557
|
console.log(' sign - Co-author trailer on every commit in an atris workspace (on/off/status)');
|
|
554
558
|
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
555
559
|
console.log(' youtube - Process YouTube videos with timestamped transcript-first analysis');
|
|
@@ -575,6 +579,7 @@ function showHelp() {
|
|
|
575
579
|
console.log('Sync:');
|
|
576
580
|
console.log(' pull - Pull journals + member data from cloud');
|
|
577
581
|
console.log(' push - Push workspace files to cloud');
|
|
582
|
+
console.log(' sync-checkout - fetch and fast-forward a clean current branch');
|
|
578
583
|
console.log(' cloud - Delete cloud files not present locally (cloud clean --dry-run|--yes)');
|
|
579
584
|
console.log(' live - Keep a business brain fresh (doctor, pull, watch, push)');
|
|
580
585
|
console.log(' clean-workspace <slug> - Analyze & remove junk files from a workspace (alias: cw)');
|
|
@@ -1617,6 +1622,11 @@ function showWelcomeVisualization() {
|
|
|
1617
1622
|
console.log(` learned \"${latestBriefTitle}\" overnight -> atris/wiki/briefs/${latestBriefName}`);
|
|
1618
1623
|
}
|
|
1619
1624
|
|
|
1625
|
+
const checkoutWarning = require('../lib/checkout-sync').checkoutBehindMessage(cwd);
|
|
1626
|
+
if (checkoutWarning) {
|
|
1627
|
+
console.log(` ${checkoutWarning}`);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1620
1630
|
// Show the work itself, not counts. A newcomer in any domain (code, docs,
|
|
1621
1631
|
// a travel plan) should read actual task names and know what's happening.
|
|
1622
1632
|
// Waiting-on-you comes first: the one thing only a human can do.
|
|
@@ -1694,6 +1704,16 @@ function showWelcomeVisualization() {
|
|
|
1694
1704
|
console.log(row('tidy', tidyBits.join(', ')));
|
|
1695
1705
|
}
|
|
1696
1706
|
|
|
1707
|
+
let wikiNudge = '';
|
|
1708
|
+
try {
|
|
1709
|
+
wikiNudge = require('../lib/wiki').wikiMetabolismNudge(cwd);
|
|
1710
|
+
} catch {
|
|
1711
|
+
wikiNudge = '';
|
|
1712
|
+
}
|
|
1713
|
+
if (wikiNudge) {
|
|
1714
|
+
console.log(` ${wikiNudge}`);
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1697
1717
|
console.log(row('logs', journalEntries > 0
|
|
1698
1718
|
? `${journalEntries} note${journalEntries === 1 ? '' : 's'} today`
|
|
1699
1719
|
: 'nothing yet today'));
|
|
@@ -1792,6 +1812,9 @@ if (command === 'init') {
|
|
|
1792
1812
|
Promise.resolve(require('../commands/bench').benchCommand(process.argv.slice(3)))
|
|
1793
1813
|
.then((code) => process.exit(code || 0))
|
|
1794
1814
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(2); });
|
|
1815
|
+
} else if (command === 'router') {
|
|
1816
|
+
const code = require('../commands/router').routerCommand(process.argv.slice(3));
|
|
1817
|
+
if (Number.isInteger(code) && code !== 0) process.exit(code);
|
|
1795
1818
|
} else if (command === 'mission') {
|
|
1796
1819
|
// process.exit() can outrun a piped stdout: writes beyond the 64KB pipe
|
|
1797
1820
|
// buffer are async, so large --json payloads truncate at 64KB multiples.
|
|
@@ -1804,6 +1827,10 @@ if (command === 'init') {
|
|
|
1804
1827
|
Promise.resolve(require('../commands/mission').missionCommand(process.argv.slice(3)))
|
|
1805
1828
|
.then(() => exitAfterStdoutDrain(process.exitCode || 0))
|
|
1806
1829
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); exitAfterStdoutDrain(1); });
|
|
1830
|
+
} else if (command === 'recover') {
|
|
1831
|
+
Promise.resolve(require('../commands/recover').recoverCommand(process.argv.slice(3)))
|
|
1832
|
+
.then((code) => process.exit(code || 0))
|
|
1833
|
+
.catch((err) => { console.error(`\nerror: ${err.message || err}`); process.exit(1); });
|
|
1807
1834
|
} else if (command === 'agents') {
|
|
1808
1835
|
// Glanceable view of every member's state: stuck, waiting on you, working, resting.
|
|
1809
1836
|
const code = require('../commands/agents').agentsCommand(process.argv.slice(3));
|
|
@@ -1931,8 +1958,17 @@ if (command === 'init') {
|
|
|
1931
1958
|
logCmd();
|
|
1932
1959
|
}
|
|
1933
1960
|
} else if (command === 'logs') {
|
|
1961
|
+
const logsArgs = process.argv.slice(3);
|
|
1962
|
+
if (logsArgs.includes('--help') || logsArgs.includes('-h') || logsArgs[0] === 'help') {
|
|
1963
|
+
console.log('Usage: atris logs [--date YYYY-MM-DD] [--json]');
|
|
1964
|
+
console.log('');
|
|
1965
|
+
console.log(' atris logs Show today\'s workspace + team journal digest');
|
|
1966
|
+
console.log(' atris logs --date <day> Show the digest for a specific day');
|
|
1967
|
+
console.log(' atris logs --json Emit the digest as JSON');
|
|
1968
|
+
process.exit(0);
|
|
1969
|
+
}
|
|
1934
1970
|
try {
|
|
1935
|
-
require('../commands/log').logsDigest(
|
|
1971
|
+
require('../commands/log').logsDigest(logsArgs);
|
|
1936
1972
|
process.exit(0);
|
|
1937
1973
|
} catch (error) {
|
|
1938
1974
|
console.error(error.message || String(error));
|
|
@@ -1956,6 +1992,9 @@ if (command === 'init') {
|
|
|
1956
1992
|
activateCmd();
|
|
1957
1993
|
} else if (command === 'watch') {
|
|
1958
1994
|
require('../commands/watch').watchAtris();
|
|
1995
|
+
} else if (command === 'sync-checkout') {
|
|
1996
|
+
const code = require('../commands/sync-checkout').syncCheckoutCommand(process.argv.slice(3));
|
|
1997
|
+
process.exit(code);
|
|
1959
1998
|
} else if (command === 'update' || command === 'sync') {
|
|
1960
1999
|
const args = process.argv.slice(3);
|
|
1961
2000
|
const firstSyncArg = process.argv[3];
|
|
@@ -2514,6 +2553,10 @@ if (command === 'init') {
|
|
|
2514
2553
|
require('../commands/gm').gmCommand(...process.argv.slice(3))
|
|
2515
2554
|
.then(() => process.exit(0))
|
|
2516
2555
|
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2556
|
+
} else if (command === 'game') {
|
|
2557
|
+
require('../commands/game').gameCommand(process.argv.slice(3))
|
|
2558
|
+
.then((status) => process.exit(status === 1 ? 1 : 0))
|
|
2559
|
+
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2517
2560
|
} else if (command === 'github') {
|
|
2518
2561
|
const status = require('../commands/github').githubCommand(process.argv.slice(3));
|
|
2519
2562
|
process.exit(status);
|
|
@@ -2590,6 +2633,10 @@ if (command === 'init') {
|
|
|
2590
2633
|
const subcommand = process.argv[3];
|
|
2591
2634
|
const args = process.argv.slice(4);
|
|
2592
2635
|
require('../commands/lesson')(subcommand, ...args);
|
|
2636
|
+
} else if (command === 'teach') {
|
|
2637
|
+
const subcommand = process.argv[3];
|
|
2638
|
+
const args = process.argv.slice(4);
|
|
2639
|
+
require('../commands/teach')(subcommand, ...args);
|
|
2593
2640
|
} else if (command === 'skill') {
|
|
2594
2641
|
const subcommand = process.argv[3];
|
|
2595
2642
|
const args = process.argv.slice(4);
|
package/commands/activate.js
CHANGED
|
@@ -110,6 +110,15 @@ function completionSentence(completions) {
|
|
|
110
110
|
return humanSentence(`since last time: ${landed}; the biggest: ${biggest}.`);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// STATUS.md bullets can carry paths and counts the gate would reject, so the
|
|
114
|
+
// narration only says that attention is needed, never quotes the bullet.
|
|
115
|
+
function wikiHealthSentence(wikiStatus) {
|
|
116
|
+
if (!wikiStatus || !Array.isArray(wikiStatus.bullets)) return null;
|
|
117
|
+
const needsAttention = wikiStatus.bullets.some((b) => /stale|orphan/i.test(b));
|
|
118
|
+
if (!needsAttention) return null;
|
|
119
|
+
return humanSentence('the wiki has pages going stale; refresh them: atris loop wiki');
|
|
120
|
+
}
|
|
121
|
+
|
|
113
122
|
function activeWorkSentence(state, context) {
|
|
114
123
|
const tasks = Array.isArray(context?.inProgressTasks) ? context.inProgressTasks : [];
|
|
115
124
|
if (tasks.length) {
|
|
@@ -237,13 +246,14 @@ function activateAtris() {
|
|
|
237
246
|
} catch {}
|
|
238
247
|
|
|
239
248
|
let moves = [];
|
|
249
|
+
let clarityLine = null;
|
|
240
250
|
try {
|
|
241
251
|
const { nextMoves } = require('../lib/next-moves');
|
|
242
252
|
const { profilePaths } = require('../lib/clarity');
|
|
243
253
|
const root = process.cwd();
|
|
244
254
|
moves = nextMoves(root, 3);
|
|
245
255
|
const { profile, mdPath } = readActivationClarityProfile(root, profilePaths);
|
|
246
|
-
formatClarityLine(profile, rel(mdPath));
|
|
256
|
+
clarityLine = formatClarityLine(profile, rel(mdPath));
|
|
247
257
|
} catch { /* alive onboarding is best-effort; never block activate */ }
|
|
248
258
|
|
|
249
259
|
let briefData = null;
|
|
@@ -258,7 +268,6 @@ function activateAtris() {
|
|
|
258
268
|
|
|
259
269
|
void dateFormatted;
|
|
260
270
|
void learningCount;
|
|
261
|
-
void wikiStatus;
|
|
262
271
|
fs.existsSync(personaFile);
|
|
263
272
|
fs.existsSync(mapFile);
|
|
264
273
|
void taskFilePath;
|
|
@@ -269,6 +278,7 @@ function activateAtris() {
|
|
|
269
278
|
handoffSentence(handoffContent),
|
|
270
279
|
completionSentence(recentCompletions),
|
|
271
280
|
activeWorkSentence(state, context),
|
|
281
|
+
wikiHealthSentence(wikiStatus),
|
|
272
282
|
].filter(Boolean);
|
|
273
283
|
if (Array.isArray(briefData?.waiting)) {
|
|
274
284
|
const approvalCount = briefData.waiting.length;
|
|
@@ -284,6 +294,9 @@ function activateAtris() {
|
|
|
284
294
|
statusLines.forEach((line) => console.log(line));
|
|
285
295
|
}
|
|
286
296
|
|
|
297
|
+
console.log('');
|
|
298
|
+
console.log(clarityLine || 'Tip: run atris clarity once so agents learn how you work.');
|
|
299
|
+
|
|
287
300
|
const nextMove = moves[0] || briefData?.moves?.[0];
|
|
288
301
|
const nextMoveTitle = focusFragment(nextMove?.title, 100);
|
|
289
302
|
if (nextMoveTitle) {
|
|
@@ -292,4 +305,4 @@ function activateAtris() {
|
|
|
292
305
|
}
|
|
293
306
|
}
|
|
294
307
|
|
|
295
|
-
module.exports = { activateAtris };
|
|
308
|
+
module.exports = { activateAtris, wikiHealthSentence };
|
package/commands/agent-spawn.js
CHANGED
|
@@ -463,18 +463,11 @@ function agentSpawnStatusCommand(args = [], deps = {}) {
|
|
|
463
463
|
}
|
|
464
464
|
|
|
465
465
|
module.exports = {
|
|
466
|
-
SPAWN_SCHEMA,
|
|
467
|
-
SPAWN_STATE_REL,
|
|
468
466
|
parseSpawnArgs,
|
|
469
|
-
buildDelegatePrompt,
|
|
470
467
|
commandForEngine,
|
|
471
468
|
createSpawnRequest,
|
|
472
469
|
agentDogfoodCommand,
|
|
473
|
-
parseDogfoodArgs,
|
|
474
|
-
runDogfoodEngine,
|
|
475
|
-
loadSpawnRequests,
|
|
476
470
|
agentSpawnCommand,
|
|
477
471
|
agentSpawnListCommand,
|
|
478
472
|
agentSpawnStatusCommand,
|
|
479
|
-
showSpawnHelp,
|
|
480
473
|
};
|