atris 3.57.3 → 3.58.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/atris/skills/clawhub/member-runtime/SKILL.md +9 -9
- package/atris/skills/create-member/SKILL.md +16 -13
- package/atris/skills/design/SKILL.md +27 -4
- package/atris/skills/engines/SKILL.md +57 -13
- package/atris/skills/x-search/SKILL.md +13 -5
- package/atris/skills/youtube/SKILL.md +39 -8
- package/atris/team/brainstormer/MEMBER.md +2 -2
- package/atris/team/executor/MEMBER.md +3 -3
- package/atris/team/launcher/MEMBER.md +4 -4
- package/atris/team/navigator/MEMBER.md +3 -3
- package/atris/team/researcher/MEMBER.md +2 -2
- package/atris/team/validator/MEMBER.md +1 -1
- package/atris.md +14 -0
- package/ax +157 -24
- package/bin/atris.js +79 -31
- package/commands/aeo.js +4 -4
- package/commands/agents.js +1 -1
- package/commands/align.js +12 -12
- package/commands/analytics.js +3 -3
- package/commands/app.js +5 -5
- package/commands/ask.js +175 -0
- package/commands/auth.js +7 -7
- package/commands/autoland.js +29 -5
- package/commands/autopilot-front.js +6 -6
- package/commands/autopilot.js +90 -90
- package/commands/avail.js +5 -5
- package/commands/bench.js +63 -1
- package/commands/browse.js +2 -2
- package/commands/business.js +12 -12
- package/commands/card.js +2 -2
- package/commands/clean.js +13 -13
- package/commands/close.js +297 -15
- package/commands/compile.js +13 -13
- package/commands/computer.js +94 -27
- package/commands/console.js +5 -5
- package/commands/decide.js +1 -1
- package/commands/deck.js +9 -9
- package/commands/drive.js +4 -4
- package/commands/engine.js +173 -19
- package/commands/errors.js +3 -3
- package/commands/experiments.js +18 -1
- package/commands/feed.js +2 -2
- package/commands/feedback.js +4 -4
- package/commands/fleet.js +12 -12
- package/commands/game.js +1 -1
- package/commands/guide.js +49 -0
- package/commands/improve.js +19 -17
- package/commands/init.js +67 -19
- package/commands/interview.js +7 -7
- package/commands/land.js +40 -15
- package/commands/learn.js +12 -12
- package/commands/lesson.js +2 -2
- package/commands/log.js +1 -1
- package/commands/loops.js +4 -4
- package/commands/member.js +75 -50
- package/commands/mission.js +97 -98
- package/commands/one-lap.js +1 -1
- package/commands/pack.js +74 -8
- package/commands/plugin.js +6 -6
- package/commands/probe.js +9 -9
- package/commands/pull.js +35 -35
- package/commands/pulse.js +1 -1
- package/commands/push.js +21 -21
- package/commands/rainmaker.js +1 -1
- package/commands/recap.js +7 -7
- package/commands/reel.js +2 -2
- package/commands/release.js +3 -3
- package/commands/report.js +1 -1
- package/commands/review.js +5 -5
- package/commands/revisions.js +1 -1
- package/commands/run.js +1 -1
- package/commands/scout.js +3 -3
- package/commands/security-review.js +7 -7
- package/commands/serve.js +9 -9
- package/commands/setup.js +1 -1
- package/commands/sign.js +4 -4
- package/commands/signup.js +4 -4
- package/commands/site.js +8 -3
- package/commands/skill.js +6 -6
- package/commands/slop.js +18 -18
- package/commands/social.js +3 -3
- package/commands/soul.js +14 -14
- package/commands/spaceship.js +1 -1
- package/commands/status.js +2 -2
- package/commands/strings.js +13 -13
- package/commands/study.js +4 -4
- package/commands/sync.js +8 -8
- package/commands/task.js +50 -25
- package/commands/teach.js +2 -2
- package/commands/team.js +1 -1
- package/commands/theme.js +2 -2
- package/commands/tree.js +34 -0
- package/commands/truth.js +7 -7
- package/commands/verify.js +12 -12
- package/commands/visualize.js +2 -2
- package/commands/workflow.js +97 -40
- package/commands/worktree.js +57 -1
- package/commands/write.js +9 -9
- package/commands/x-search.js +304 -15
- package/commands/xp.js +6 -3
- package/commands/youtube.js +916 -65
- package/lib/accept-verify-gate.js +3 -3
- package/lib/activity-stream.js +1 -1
- package/lib/apply-gate.js +13 -0
- package/lib/auto-accept-certified.js +28 -12
- package/lib/autoland.js +6 -6
- package/lib/bench/engines.js +59 -8
- package/lib/bench/report.js +1 -1
- package/lib/bench/runner.js +204 -5
- package/lib/bench/tree-render.js +76 -0
- package/lib/card.js +1 -1
- package/lib/chat-log-scan.js +1 -1
- package/lib/claude-boot-block.js +2 -0
- package/lib/deck-compose.js +1 -1
- package/lib/deck-history.js +2 -2
- package/lib/deck-layout.js +1 -1
- package/lib/deck-review.js +5 -5
- package/lib/deck-schema.js +1 -1
- package/lib/default-verifier.js +1 -1
- package/lib/developer-api.js +3 -0
- package/lib/engine-ask.js +66 -9
- package/lib/engine-registry.js +15 -2
- package/lib/file-ops.js +1 -1
- package/lib/fleet.js +71 -35
- package/lib/html-render.js +1 -1
- package/lib/intents.js +172 -0
- package/lib/journal.js +1 -1
- package/lib/known-commands.js +2 -2
- package/lib/land-green.js +364 -0
- package/lib/lesson-contradiction.js +2 -2
- package/lib/lesson-preflight.js +1 -1
- package/lib/manifest.js +5 -5
- package/lib/member-alive.js +9 -5
- package/lib/memory-view.js +3 -3
- package/lib/mission-protected-lane.js +1 -1
- package/lib/mission-root.js +2 -2
- package/lib/orb-context.js +10 -10
- package/lib/pack-capabilities.js +861 -3
- package/lib/permission-grants.js +2 -2
- package/lib/policy-lessons.js +6 -6
- package/lib/pulse.js +8 -8
- package/lib/receipt-evidence.js +1 -1
- package/lib/reel.js +1 -1
- package/lib/review-integrity.js +1 -1
- package/lib/runner-command.js +35 -5
- package/lib/scorecard.js +4 -4
- package/lib/security-scan.js +5 -5
- package/lib/self-drive.js +1 -1
- package/lib/site-publish.js +372 -0
- package/lib/site.js +1 -1
- package/lib/slides-deck.js +2 -2
- package/lib/state-detection.js +2 -2
- package/lib/sync-telemetry.js +2 -2
- package/lib/task-db.js +17 -10
- package/lib/task-explanation.js +1 -1
- package/lib/task-proof.js +2 -2
- package/lib/task-receipt.js +3 -3
- package/lib/theme.js +12 -12
- package/lib/todo-fallback.js +3 -3
- package/lib/todo-sections.js +1 -1
- package/lib/tree-hash.js +79 -0
- package/lib/usage.js +1 -1
- package/lib/wish-delegate.js +1 -1
- package/lib/workspace-safety.js +4 -4
- package/lib/workspace-scaffold.js +3 -3
- package/package.json +1 -1
- package/scripts/det/concierge-bakeoff.sh +26 -0
- package/scripts/det/ytquote-repair.js +0 -1
- package/scripts/det/ytrail-race.js +0 -5
- package/scripts/member-operate.mjs +52 -14
- package/scripts/outbound-artifact-gate.js +0 -3
- package/utils/auth.js +0 -3
- package/utils/config.js +0 -1
- package/scripts/det/checklist-score.js +0 -191
package/commands/workflow.js
CHANGED
|
@@ -612,7 +612,7 @@ async function planAtris(userInput = null) {
|
|
|
612
612
|
|
|
613
613
|
if (showFactory) {
|
|
614
614
|
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
615
|
-
console.log('│ Atris Plan
|
|
615
|
+
console.log('│ Atris Plan - Navigator Agent Activated │');
|
|
616
616
|
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
617
617
|
console.log('');
|
|
618
618
|
|
|
@@ -641,7 +641,7 @@ async function planAtris(userInput = null) {
|
|
|
641
641
|
console.log(`- Navigator spec: ${navigatorPath || 'atris/team/navigator/MEMBER.md (missing)'}`);
|
|
642
642
|
console.log(`- Persona: ${personaFileRef || 'atris/PERSONA.md (missing)'}`);
|
|
643
643
|
const mapDisplay = mapFileRef
|
|
644
|
-
? `${mapFileRef}${mapIsPlaceholder ? ' (placeholder
|
|
644
|
+
? `${mapFileRef}${mapIsPlaceholder ? ' (placeholder, generate first)' : ''}`
|
|
645
645
|
: 'atris/MAP.md (missing)';
|
|
646
646
|
console.log(`- MAP: ${mapDisplay}`);
|
|
647
647
|
console.log(`- TODO: ${taskSourcePath || 'atris/TODO.md (missing)'}`);
|
|
@@ -710,11 +710,12 @@ async function planAtris(userInput = null) {
|
|
|
710
710
|
console.log('');
|
|
711
711
|
}
|
|
712
712
|
console.log('Workflow:');
|
|
713
|
-
console.log('1) ASCII visualize
|
|
713
|
+
console.log('1) ASCII visualize; use existing approval for this scope, otherwise wait for approval');
|
|
714
714
|
console.log('2) Run the Confidence Gate before writing tasks');
|
|
715
715
|
printConfidenceGate(' ');
|
|
716
|
-
console.log('3)
|
|
717
|
-
console.log('
|
|
716
|
+
console.log('3) Create each task in the live task plane: `atris task add "<title>" --tag <tag>`, then `atris task plan <id> --goal ... --exit ... --proof-needed ...`');
|
|
717
|
+
console.log(' Keep a delegated owner: `atris task delegate "<title>" --to <member>`; plan keeps that owner unless you pass --owner');
|
|
718
|
+
console.log(' atris/TODO.md is a generated view: never hand-edit it, regenerate with `atris task render --out atris/TODO.md`');
|
|
718
719
|
console.log('4) Log to atris/team/navigator/logs/YYYY-MM-DD.md');
|
|
719
720
|
console.log(' (Task, Delivered, User reaction, Pattern)');
|
|
720
721
|
if (atris2Mode) {
|
|
@@ -783,7 +784,7 @@ async function planAtris(userInput = null) {
|
|
|
783
784
|
userPrompt += `Your job (execute these steps):\n\n`;
|
|
784
785
|
userPrompt += `STEP 1: Generate ASCII visualizations for user approval\n`;
|
|
785
786
|
userPrompt += ` Create diagrams showing architecture, flows, schemas, UI/UX.\n`;
|
|
786
|
-
userPrompt += ` SHOW these diagrams
|
|
787
|
+
userPrompt += ` SHOW these diagrams; use existing approval for this scope, otherwise wait for approval before proceeding.\n\n`;
|
|
787
788
|
userPrompt += `STEP 2: Run the Confidence Gate before writing tasks\n`;
|
|
788
789
|
userPrompt += confidenceGatePrompt('plan') + `\n\n`;
|
|
789
790
|
userPrompt += `STEP 3: Break approved ideas into concrete tasks\n`;
|
|
@@ -799,7 +800,7 @@ async function planAtris(userInput = null) {
|
|
|
799
800
|
userPrompt += `STEP 5: Log to your journal\n`;
|
|
800
801
|
userPrompt += ` - Write to atris/team/navigator/logs/YYYY-MM-DD.md\n`;
|
|
801
802
|
userPrompt += ` - Include: Task, Delivered, User reaction, Pattern\n`;
|
|
802
|
-
userPrompt += ` - Your journal is how you learn
|
|
803
|
+
userPrompt += ` - Your journal is how you learn, so record what worked\n\n`;
|
|
803
804
|
userPrompt += `Start planning now. Read MAP.md for file references.`;
|
|
804
805
|
|
|
805
806
|
console.log('');
|
|
@@ -866,6 +867,73 @@ async function planAtris(userInput = null) {
|
|
|
866
867
|
// Prompt mode continues with existing output (already logged above)
|
|
867
868
|
}
|
|
868
869
|
|
|
870
|
+
// Both executor surfaces require the exact live record before any work.
|
|
871
|
+
// The rendered list omits raw instructions and cannot select the mission.
|
|
872
|
+
function executorDispatchForTask(task) {
|
|
873
|
+
const metadata = task && task.metadata || {};
|
|
874
|
+
return {
|
|
875
|
+
taskId: task && task.id || '',
|
|
876
|
+
owner: metadata.assigned_to || task && task.claimed_by || metadata.stage_owner || '',
|
|
877
|
+
goalId: metadata.goal_id || '',
|
|
878
|
+
missionId: metadata.mission_id || '',
|
|
879
|
+
objective: metadata.task_goal || metadata.goal_objective || metadata.stage_goal || '',
|
|
880
|
+
workspaceRoot: task && task.workspace_root || '',
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
function validateExecutorDispatch(expected = {}, task) {
|
|
885
|
+
if (!expected.taskId || !expected.owner || (!expected.goalId && !expected.missionId && !expected.objective)) {
|
|
886
|
+
return { ok: false, reason: 'missing task, owner, or mission in dispatch' };
|
|
887
|
+
}
|
|
888
|
+
const actual = executorDispatchForTask(task);
|
|
889
|
+
if (!task || ['taskId', 'owner', 'goalId', 'missionId', 'objective', 'workspaceRoot']
|
|
890
|
+
.some(key => (expected[key] || '') !== (actual[key] || ''))) {
|
|
891
|
+
return { ok: false, reason: 'task, owner, or mission changed since dispatch' };
|
|
892
|
+
}
|
|
893
|
+
if (!['open', 'claimed'].includes(task.status)
|
|
894
|
+
|| (task.status === 'claimed' && task.claimed_by !== expected.owner)) {
|
|
895
|
+
return { ok: false, reason: 'task is inactive or claimed by another owner' };
|
|
896
|
+
}
|
|
897
|
+
return { ok: true };
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
function executorTaskHandoff({ taskId = '', owner = '', goalId = '', missionId = '', objective = '' } = {}) {
|
|
901
|
+
const ref = taskId || '<task-id>';
|
|
902
|
+
const expected = JSON.stringify({ taskId: taskId || null, owner: owner || null, goalId: goalId || null, missionId: missionId || null, objective: objective || null });
|
|
903
|
+
return `Expected dispatch: ${expected}. Before claiming or editing, run \`atris task show ${ref} --json\` for the exact current dispatched task. If the expected task ID, owner, or mission is missing, stop; no edits are allowed. Do not select another displayed row. Check the ID, current mission, active status (open or claimed by the same owner), and functional owner against these expected values. Refuse a stale or mismatched task. Read the raw metadata, requirements, events, and verify command for exact paths, flags, and engine/model instructions; the explanation and rendered TODO are summaries only. Then claim that same task with \`atris task claim ${ref} --as <task-owner>\`, using its recorded functional owner and keeping the engine separate.`;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// The executor prompt sent to a backend agent in --execute mode. Kept as a
|
|
907
|
+
// pure function so the emitted instructions can be tested without a network:
|
|
908
|
+
// the agent claims and finishes work through the live task plane, and treats
|
|
909
|
+
// atris/TODO.md as a generated view it never hand-edits.
|
|
910
|
+
function executorAgentPrompt({ filteredTasks = '', taskSource = 'atris/TODO.md', context = 'UNKNOWN', taskId = '', owner = '', goalId = '', missionId = '', objective = '' } = {}) {
|
|
911
|
+
let userPrompt = `⚠️ CRITICAL: Execute tasks NOW. Use file tools to edit code, terminal to run commands.\n\n`;
|
|
912
|
+
userPrompt += `You are the Executor. Get it done, precisely, following instructions perfectly.\n\n`;
|
|
913
|
+
|
|
914
|
+
if (filteredTasks) {
|
|
915
|
+
userPrompt += `## REFERENCE TASK SUMMARIES (generated view from ${taskSource}; live truth is \`atris task list\`):\n${filteredTasks}\n\n`;
|
|
916
|
+
} else {
|
|
917
|
+
userPrompt += `## TASKS TO EXECUTE:\n(No tasks found - run \`atris task list\` for the live task plane)\n\n`;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
userPrompt += `Your process (EXECUTE these steps):\n`;
|
|
921
|
+
userPrompt += `1. ${executorTaskHandoff({ taskId, owner, goalId, missionId, objective })}\n`;
|
|
922
|
+
userPrompt += `2. For this task: Show ASCII visualization first (especially complex changes)\n`;
|
|
923
|
+
userPrompt += `3. Run the Confidence Gate before editing\n`;
|
|
924
|
+
userPrompt += confidenceGatePrompt('do') + `\n`;
|
|
925
|
+
userPrompt += `4. Execute task: Use file edit tools, terminal commands, etc.\n`;
|
|
926
|
+
userPrompt += `5. Before completion, rerun the gate against proof and residual risk\n`;
|
|
927
|
+
userPrompt += `6. Send it to review: \`atris task ready <id> --proof "<commands run>"\`; a human accepts. Never hand-edit TODO.md; \`atris task render --out atris/TODO.md\` regenerates it\n`;
|
|
928
|
+
userPrompt += `7. Log to atris/team/executor/logs/YYYY-MM-DD.md\n`;
|
|
929
|
+
userPrompt += ` (Task, Delivered, Errors hit, Learned)\n`;
|
|
930
|
+
userPrompt += `8. Use MAP.md to navigate codebase\n\n`;
|
|
931
|
+
userPrompt += `DO NOT just describe what you would do - actually edit files and execute commands!\n`;
|
|
932
|
+
userPrompt += `Context: ${context}\n`;
|
|
933
|
+
userPrompt += `Start only the dispatched task after the raw-record check.`;
|
|
934
|
+
return userPrompt;
|
|
935
|
+
}
|
|
936
|
+
|
|
869
937
|
async function doAtris() {
|
|
870
938
|
const { loadConfig } = require('../utils/config');
|
|
871
939
|
const { loadCredentials, ensureValidCredentials } = require('../utils/auth');
|
|
@@ -1044,7 +1112,7 @@ async function doAtris() {
|
|
|
1044
1112
|
console.log(`- Executor spec: ${executorPath || 'atris/team/executor/MEMBER.md (missing)'}`);
|
|
1045
1113
|
console.log(`- Persona: ${personaFileRef || 'atris/PERSONA.md (missing)'}`);
|
|
1046
1114
|
const mapDisplay = mapPath
|
|
1047
|
-
? `${mapPath}${mapIsPlaceholder ? ' (placeholder
|
|
1115
|
+
? `${mapPath}${mapIsPlaceholder ? ' (placeholder, generate first)' : ''}`
|
|
1048
1116
|
: 'atris/MAP.md (missing)';
|
|
1049
1117
|
console.log(`- MAP: ${mapDisplay}`);
|
|
1050
1118
|
console.log(`- TODO: ${taskSourcePath || 'atris/TODO.md (missing)'}`);
|
|
@@ -1097,17 +1165,17 @@ async function doAtris() {
|
|
|
1097
1165
|
console.log('');
|
|
1098
1166
|
}
|
|
1099
1167
|
console.log('Workflow:');
|
|
1100
|
-
console.log(
|
|
1101
|
-
console.log('
|
|
1168
|
+
console.log(`1) ${executorTaskHandoff(executorDispatchForTask(firstMinute && firstMinute.task))}`);
|
|
1169
|
+
console.log(' The live task plane is truth; never hand-edit TODO.md to claim or move work');
|
|
1102
1170
|
console.log('2) Run the Confidence Gate against the task before editing');
|
|
1103
1171
|
printConfidenceGate(' ');
|
|
1104
1172
|
console.log('3) Execute step-by-step. Run tests as you go.');
|
|
1105
1173
|
console.log('4) Before completion, rerun the gate against proof and residual risk');
|
|
1106
|
-
console.log('5) When done,
|
|
1174
|
+
console.log('5) When done, send it to review: `atris task ready <id> --proof "<commands run>"`; a human accepts, then `atris task render --out atris/TODO.md` refreshes the view');
|
|
1107
1175
|
console.log('6) Log to atris/team/executor/logs/YYYY-MM-DD.md');
|
|
1108
1176
|
console.log(' (Task, Delivered, Errors hit, Learned)');
|
|
1109
1177
|
console.log('');
|
|
1110
|
-
console.log('⛔ Do NOT plan
|
|
1178
|
+
console.log('⛔ Do NOT plan, just execute what\'s written.');
|
|
1111
1179
|
console.log('');
|
|
1112
1180
|
|
|
1113
1181
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
@@ -1146,6 +1214,10 @@ async function doAtris() {
|
|
|
1146
1214
|
|
|
1147
1215
|
// Check execution mode
|
|
1148
1216
|
if (executionMode === 'agent') {
|
|
1217
|
+
// Bind edit permission to the selected live task, not its rendered summary.
|
|
1218
|
+
const dispatch = executorDispatchForTask(firstMinute && firstMinute.task);
|
|
1219
|
+
const dispatchCheck = validateExecutorDispatch(dispatch, firstMinute && firstMinute.task);
|
|
1220
|
+
if (!dispatchCheck.ok) throw new Error(`executor dispatch refused: ${dispatchCheck.reason}`);
|
|
1149
1221
|
// Agent mode: execute via backend API
|
|
1150
1222
|
if (!config.agent_id) {
|
|
1151
1223
|
throw new Error('No agent selected. Run "atris agent" first.');
|
|
@@ -1175,29 +1247,11 @@ async function doAtris() {
|
|
|
1175
1247
|
}
|
|
1176
1248
|
|
|
1177
1249
|
// Build user prompt with context
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
if (
|
|
1182
|
-
|
|
1183
|
-
} else {
|
|
1184
|
-
userPrompt += `## TASKS TO EXECUTE:\n(No tasks found - check TODO.md)\n\n`;
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
userPrompt += `Your process (EXECUTE these steps):\n`;
|
|
1188
|
-
userPrompt += `1. Read tasks from TODO.md (shown above)\n`;
|
|
1189
|
-
userPrompt += `2. For each task: Show ASCII visualization first (especially complex changes)\n`;
|
|
1190
|
-
userPrompt += `3. Run the Confidence Gate before editing\n`;
|
|
1191
|
-
userPrompt += confidenceGatePrompt('do') + `\n`;
|
|
1192
|
-
userPrompt += `4. Execute task: Use file edit tools, terminal commands, etc.\n`;
|
|
1193
|
-
userPrompt += `5. Before completion, rerun the gate against proof and residual risk\n`;
|
|
1194
|
-
userPrompt += `6. Move task to ## Completed in TODO.md\n`;
|
|
1195
|
-
userPrompt += `7. Log to atris/team/executor/logs/YYYY-MM-DD.md\n`;
|
|
1196
|
-
userPrompt += ` (Task, Delivered, Errors hit, Learned)\n`;
|
|
1197
|
-
userPrompt += `8. Use MAP.md to navigate codebase\n\n`;
|
|
1198
|
-
userPrompt += `DO NOT just describe what you would do - actually edit files and execute commands!\n`;
|
|
1199
|
-
userPrompt += `Context: ${context}\n`;
|
|
1200
|
-
userPrompt += `Start executing tasks now.`;
|
|
1250
|
+
const taskDb = require('../lib/task-db');
|
|
1251
|
+
const liveTask = taskDb.getTask(taskDb.open(), dispatch.taskId);
|
|
1252
|
+
const currentDispatchCheck = validateExecutorDispatch(dispatch, liveTask);
|
|
1253
|
+
if (!currentDispatchCheck.ok) throw new Error(`executor dispatch refused: ${currentDispatchCheck.reason}`);
|
|
1254
|
+
const userPrompt = executorAgentPrompt({ filteredTasks, taskSource, context, ...dispatch });
|
|
1201
1255
|
|
|
1202
1256
|
console.log('');
|
|
1203
1257
|
console.log('🤖 AGENT MODE: Executing via backend API...');
|
|
@@ -1417,13 +1471,13 @@ async function reviewAtris() {
|
|
|
1417
1471
|
}
|
|
1418
1472
|
|
|
1419
1473
|
const mapDisplay = mapPath
|
|
1420
|
-
? `${mapPath}${mapIsPlaceholder ? ' (placeholder
|
|
1474
|
+
? `${mapPath}${mapIsPlaceholder ? ' (placeholder, generate first)' : ''}`
|
|
1421
1475
|
: 'atris/MAP.md (missing)';
|
|
1422
1476
|
|
|
1423
1477
|
if (showFull) {
|
|
1424
1478
|
console.log('');
|
|
1425
1479
|
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
1426
|
-
console.log('│ Atris Review
|
|
1480
|
+
console.log('│ Atris Review - Validator Agent Activated │');
|
|
1427
1481
|
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1428
1482
|
console.log('');
|
|
1429
1483
|
|
|
@@ -1594,7 +1648,7 @@ async function reviewAtris() {
|
|
|
1594
1648
|
userPrompt += ` • Verify everything works\n`;
|
|
1595
1649
|
userPrompt += ` • Find all plausible loopholes; patch them or name residual risk\n`;
|
|
1596
1650
|
userPrompt += ` • Test thoroughly (unless user says no)\n`;
|
|
1597
|
-
userPrompt += ` • Confirm active task state is clean
|
|
1651
|
+
userPrompt += ` • Confirm active task state is clean, with no unresolved Backlog/In Progress/Blocked rows for reviewed work.\n`;
|
|
1598
1652
|
userPrompt += ` If durable task state changed, regenerate the readable view with \`atris task render --out atris/TODO.md\`.\n`;
|
|
1599
1653
|
userPrompt += ` Do not hand-delete rendered completed history; if a task fails, move or mark it blocked with a note.\n`;
|
|
1600
1654
|
userPrompt += ` • Log to atris/team/validator/logs/YYYY-MM-DD.md\n`;
|
|
@@ -1718,7 +1772,7 @@ async function reviewAtris() {
|
|
|
1718
1772
|
if (fs.existsSync(logFile)) {
|
|
1719
1773
|
let journalContent = fs.readFileSync(logFile, 'utf8');
|
|
1720
1774
|
const timestamp = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });
|
|
1721
|
-
const learning = `- ${timestamp}
|
|
1775
|
+
const learning = `- ${timestamp} \u2014 ${answer.trim()}`;
|
|
1722
1776
|
|
|
1723
1777
|
// Find or create ## Notes section
|
|
1724
1778
|
if (journalContent.includes('## Notes')) {
|
|
@@ -1742,7 +1796,7 @@ async function reviewAtris() {
|
|
|
1742
1796
|
addLearning({ type, key, insight, confidence: 7, source: 'review', files: [] });
|
|
1743
1797
|
console.log(`✓ Saved to learnings: [7/10] ${type}/${key}`);
|
|
1744
1798
|
} catch {
|
|
1745
|
-
// learnings module not available
|
|
1799
|
+
// learnings module not available, so skip silently
|
|
1746
1800
|
}
|
|
1747
1801
|
}
|
|
1748
1802
|
|
|
@@ -1844,6 +1898,9 @@ module.exports = {
|
|
|
1844
1898
|
doAtris,
|
|
1845
1899
|
reviewAtris,
|
|
1846
1900
|
renderReviewMinute,
|
|
1901
|
+
executorAgentPrompt,
|
|
1902
|
+
executorDispatchForTask,
|
|
1903
|
+
validateExecutorDispatch,
|
|
1847
1904
|
executeAgentSDKFast,
|
|
1848
1905
|
makeCloudExecutor,
|
|
1849
1906
|
postToolResult
|
package/commands/worktree.js
CHANGED
|
@@ -6,11 +6,14 @@ const { spawnSync } = require('child_process');
|
|
|
6
6
|
const { hasFlag, readFlag } = require('../lib/arg-parser');
|
|
7
7
|
const { stampLatestOpenBriefForWorktree } = require('../lib/brief-ledger');
|
|
8
8
|
const { isConductorArtifact } = require('../lib/conductor-artifacts');
|
|
9
|
+
const close = require('./close');
|
|
9
10
|
|
|
10
11
|
const REGEN_ADAPTER_FILES = ['AGENTS.md', 'CLAUDE.md', 'GEMINI.md'];
|
|
11
12
|
const COMMAND_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
12
13
|
const GIT_OID_PATTERN = /^[0-9a-f]{40,64}$/;
|
|
13
14
|
const ONE_LAP_PROOF_REF_PATTERN = /^refs\/atris\/one-lap\/([0-9a-f]{40,64})$/;
|
|
15
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
16
|
+
const SHIP_HEALTH_SOURCE = 'ship-health:experiments-daily';
|
|
14
17
|
|
|
15
18
|
function runGit(args, { cwd = process.cwd(), check = true, timeout } = {}) {
|
|
16
19
|
const result = spawnSync('git', args, { cwd, encoding: 'utf8', timeout });
|
|
@@ -672,6 +675,56 @@ function findPrimaryRoot(root) {
|
|
|
672
675
|
return worktrees[0]?.path || root;
|
|
673
676
|
}
|
|
674
677
|
|
|
678
|
+
function shellQuote(value) {
|
|
679
|
+
const text = String(value || '');
|
|
680
|
+
if (/^[A-Za-z0-9_./:@+-]+$/.test(text)) return text;
|
|
681
|
+
return `'${text.replace(/'/g, `'"'"'`)}'`;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function experimentHealthProbe(statePath) {
|
|
685
|
+
const script = [
|
|
686
|
+
"const fs=require('fs')",
|
|
687
|
+
'const state=JSON.parse(fs.readFileSync(process.argv[1],\'utf8\'))',
|
|
688
|
+
'const last=Date.parse(state.last_run_date)',
|
|
689
|
+
`process.exit(Number.isFinite(last)&&Date.now()-last<=${DAY_MS}?0:1)`,
|
|
690
|
+
].join(';');
|
|
691
|
+
return `${shellQuote(process.execPath)} -e ${shellQuote(script)} ${shellQuote(statePath)}`;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function runShipHealthCheck(workspaceRoot, options = {}) {
|
|
695
|
+
try {
|
|
696
|
+
const now = options.now ? new Date(options.now) : new Date();
|
|
697
|
+
const statePath = path.join(workspaceRoot, '.atris', 'state', 'experiments-daily.json');
|
|
698
|
+
const state = fs.existsSync(statePath)
|
|
699
|
+
? JSON.parse(fs.readFileSync(statePath, 'utf8'))
|
|
700
|
+
: {};
|
|
701
|
+
const rawLastRunDate = state && state.last_run_date;
|
|
702
|
+
const lastRunMs = rawLastRunDate ? Date.parse(rawLastRunDate) : null;
|
|
703
|
+
if (rawLastRunDate && !Number.isFinite(lastRunMs)) {
|
|
704
|
+
throw new Error('experiment state date is unreadable');
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const ageMs = Number.isFinite(lastRunMs) ? now.getTime() - lastRunMs : null;
|
|
708
|
+
if (ageMs !== null && ageMs <= DAY_MS) return { healthy: true, filed: false };
|
|
709
|
+
|
|
710
|
+
const days = ageMs === null ? 1 : Math.max(1, Math.floor(ageMs / DAY_MS));
|
|
711
|
+
console.log(`health check failed: no verified experiment in ${days} days. shipping still works, the metabolism does not.`);
|
|
712
|
+
const filed = close.upsertSourceFlag({
|
|
713
|
+
what: 'no verified experiment has run in over a day',
|
|
714
|
+
owner: 'operator',
|
|
715
|
+
lane: 'code',
|
|
716
|
+
ttlDays: 1,
|
|
717
|
+
source: SHIP_HEALTH_SOURCE,
|
|
718
|
+
closeCondition: 'a verified experiment ran within 24 hours',
|
|
719
|
+
probe: experimentHealthProbe(statePath),
|
|
720
|
+
}, workspaceRoot, { now });
|
|
721
|
+
return { healthy: false, ...filed };
|
|
722
|
+
} catch (error) {
|
|
723
|
+
console.log(`health check skipped: ${String(error && error.message || error).toLowerCase()}. shipping still works.`);
|
|
724
|
+
return { healthy: null, filed: false, error };
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
675
728
|
function shipWorktree(args) {
|
|
676
729
|
if (hasFlag(args, '--help') || hasFlag(args, '-h') || args[0] === 'help') {
|
|
677
730
|
shipHelp();
|
|
@@ -825,6 +878,7 @@ function shipWorktree(args) {
|
|
|
825
878
|
}
|
|
826
879
|
}
|
|
827
880
|
console.log('pr: skipped (local mode)');
|
|
881
|
+
if (merge && !dryRun) runShipHealthCheck(primary || root);
|
|
828
882
|
console.log('done: worktree shipped');
|
|
829
883
|
return 0;
|
|
830
884
|
}
|
|
@@ -870,6 +924,7 @@ function shipWorktree(args) {
|
|
|
870
924
|
note: `worktree ship completed into ${targetRef}`,
|
|
871
925
|
}, { worktree: root });
|
|
872
926
|
} catch {}
|
|
927
|
+
if (merge && !dryRun) runShipHealthCheck(primary || root);
|
|
873
928
|
console.log('done: worktree shipped');
|
|
874
929
|
return 0;
|
|
875
930
|
}
|
|
@@ -884,7 +939,7 @@ function guard(args) {
|
|
|
884
939
|
return 2;
|
|
885
940
|
}
|
|
886
941
|
// Conductor plumbing (worktree metadata, the fleet prompt written for this very
|
|
887
|
-
// engine, runtime scratch, the brief ledger) must not count as dirt
|
|
942
|
+
// engine, runtime scratch, the brief ledger) must not count as dirt, otherwise the
|
|
888
943
|
// harness blocks the engine with the harness's own files.
|
|
889
944
|
const counts = statusCounts(root, { ignoreUntracked: isConductorArtifact });
|
|
890
945
|
if (counts && (counts.staged || counts.unstaged || counts.untracked) && !hasFlag(args, '--allow-dirty')) {
|
|
@@ -1219,5 +1274,6 @@ module.exports = {
|
|
|
1219
1274
|
taskTokens,
|
|
1220
1275
|
statusCounts,
|
|
1221
1276
|
swarloClaim,
|
|
1277
|
+
runShipHealthCheck,
|
|
1222
1278
|
worktreeCommand,
|
|
1223
1279
|
};
|
package/commands/write.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// atris write
|
|
1
|
+
// atris write: guided writing sessions (plan-do-review for prose).
|
|
2
2
|
//
|
|
3
3
|
// The contract: the human types every word of the draft. Atris structures the
|
|
4
4
|
// session (outline beats with states), tracks progress against the plan, and
|
|
5
5
|
// reviews against the taste gate (writing policy + slop detector). It NEVER
|
|
6
|
-
// writes or rewrites prose
|
|
6
|
+
// writes or rewrites prose. Review output is suggestions, not edits.
|
|
7
7
|
//
|
|
8
8
|
// Session = a folder of plain markdown, so the same files open in the web and
|
|
9
9
|
// desktop editors with no extra format:
|
|
10
10
|
// atris/writing/<slug>/plan.md outline beats: [ ] empty, [~] drafted, [x] passed
|
|
11
|
-
// atris/writing/<slug>/draft.md the piece
|
|
11
|
+
// atris/writing/<slug>/draft.md the piece, human-only territory
|
|
12
12
|
//
|
|
13
13
|
// Usage:
|
|
14
14
|
// atris write start "<topic>" [--dump "raw ideas"] [--beats "a | b | c"]
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// atris write pass <n> [slug] mark beat n passed (human calls it, not the AI)
|
|
18
18
|
// atris write list list sessions
|
|
19
19
|
//
|
|
20
|
-
// Zero external deps (Node built-ins only)
|
|
20
|
+
// Zero external deps (Node built-ins only). Repo contract.
|
|
21
21
|
|
|
22
22
|
const fs = require('fs');
|
|
23
23
|
const path = require('path');
|
|
@@ -212,7 +212,7 @@ function review(argv, root = process.cwd()) {
|
|
|
212
212
|
console.log(` ⚠ ${empty.length} beat${empty.length === 1 ? '' : 's'} still empty: ${empty.map((b) => b.title).join(', ')}`);
|
|
213
213
|
}
|
|
214
214
|
if (findings.length) {
|
|
215
|
-
console.log(`\n slop tells (fix them yourself
|
|
215
|
+
console.log(`\n slop tells (fix them yourself, atris never edits your draft):`);
|
|
216
216
|
for (const f of findings) console.log(` ✗ draft.md:${f.line} ${f.rule.padEnd(16)} ${f.why}`);
|
|
217
217
|
} else {
|
|
218
218
|
console.log(` ✓ slop scan clean`);
|
|
@@ -235,7 +235,7 @@ function pass(argv, root = process.cwd()) {
|
|
|
235
235
|
const beat = plan.beats.find((b) => b.n === n);
|
|
236
236
|
if (!beat) { console.error(` no beat ${n} in ${slug}`); return 2; }
|
|
237
237
|
const counts = draftWordCounts(slug, plan.beats, root);
|
|
238
|
-
if ((counts.get(n) || 0) === 0) { console.error(` beat ${n} "${beat.title}" has no words yet
|
|
238
|
+
if ((counts.get(n) || 0) === 0) { console.error(` beat ${n} "${beat.title}" has no words yet, write it first`); return 2; }
|
|
239
239
|
beat.state = 'x';
|
|
240
240
|
writePlanStates(slug, plan.beats, root);
|
|
241
241
|
console.log(` ● passed: ${n}. ${beat.title}`);
|
|
@@ -370,17 +370,17 @@ function coach(argv, root = process.cwd()) {
|
|
|
370
370
|
|
|
371
371
|
function help() {
|
|
372
372
|
console.log(`
|
|
373
|
-
atris write
|
|
373
|
+
atris write: guided writing sessions (you write every word; atris structures + reviews)
|
|
374
374
|
|
|
375
375
|
atris write the coach: knows where you are, gets you going
|
|
376
376
|
atris write start "<topic>" [--dump "..."] [--beats "a | b | c"]
|
|
377
377
|
atris write coach [slug] the coach: cheers your best line, asks the next question (--offline for no-LLM)
|
|
378
378
|
atris write status [slug] progress against the outline (beats landed)
|
|
379
379
|
atris write review [slug] taste gate: slop scan + writing-policy passes (read-only)
|
|
380
|
-
atris write pass <n> [slug] mark beat n passed
|
|
380
|
+
atris write pass <n> [slug] mark beat n passed, the human calls it
|
|
381
381
|
atris write list all sessions
|
|
382
382
|
|
|
383
|
-
sessions are plain markdown in atris/writing/<slug
|
|
383
|
+
sessions are plain markdown in atris/writing/<slug>/, the same files open
|
|
384
384
|
in the web and desktop editors. atris never writes or edits your draft.
|
|
385
385
|
`);
|
|
386
386
|
return 0;
|