atris 3.58.6 → 3.58.8
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/GETTING_STARTED.md +2 -2
- package/PERSONA.md +11 -11
- package/README.md +9 -1
- package/atris/GEMINI.md +7 -6
- package/atris/PERSONA.md +4 -4
- package/atris/features/README.md +77 -6
- package/atris/policies/engineering-principles.md +129 -0
- package/atris/policies/genesis.md +112 -0
- package/atris/policies/product-design-principles.md +100 -0
- package/atris/skills/README.md +44 -15
- package/atris/skills/aeo/SKILL.md +10 -10
- package/atris/skills/atris/SKILL.md +1 -1
- package/atris/skills/design/SKILL.md +3 -1
- package/atris/skills/engines/SKILL.md +42 -50
- package/atris/skills/meta/SKILL.md +4 -4
- package/atris/skills/youtube/SKILL.md +11 -11
- package/bin/atris.js +60 -8
- package/commands/aeo.js +9 -12
- package/commands/analytics.js +8 -11
- package/commands/auth.js +8 -2
- package/commands/autopilot.js +4 -3
- package/commands/avail.js +1 -1
- package/commands/brain.js +4 -1
- package/commands/business.js +13 -8
- package/commands/close.js +2 -1
- package/commands/computer.js +15 -10
- package/commands/context-sync.js +3 -3
- package/commands/design.js +362 -0
- package/commands/doc-health.js +377 -0
- package/commands/drive.js +32 -0
- package/commands/experiments.js +13 -4
- package/commands/improve.js +68 -2
- package/commands/integrations.js +2 -5
- package/commands/land.js +144 -4
- package/commands/learn.js +7 -2
- package/commands/member.js +239 -58
- package/commands/mission.js +94 -18
- package/commands/pack.js +2 -2
- package/commands/probe.js +11 -5
- package/commands/pull.js +1 -1
- package/commands/pulse.js +38 -0
- package/commands/push.js +1 -1
- package/commands/rainmaker.js +3 -16
- package/commands/rsi.js +156 -0
- package/commands/spaceship.js +1 -1
- package/commands/stream.js +27 -2
- package/commands/study.js +15 -9
- package/commands/sync.js +1 -1
- package/commands/task.js +54 -3
- package/commands/workflow.js +17 -7
- package/commands/youtube.js +76 -8
- package/lib/apply-gate.js +22 -4
- package/lib/codex-flight.js +28 -5
- package/lib/daily-log.js +88 -0
- package/lib/design-api.js +130 -0
- package/lib/engine-ask.js +1 -1
- package/lib/first-minute.js +1 -6
- package/lib/fleet.js +4 -1
- package/lib/improve-vitals-html.js +3 -2
- package/lib/known-commands.js +3 -3
- package/lib/lesson-contradiction.js +2 -2
- package/lib/map-refs.js +183 -0
- package/lib/member-context.js +42 -0
- package/lib/mission-room.js +4 -4
- package/lib/noninteractive.js +15 -4
- package/lib/policy-lessons.js +1 -1
- package/lib/receipt-block.js +137 -28
- package/lib/rsi-record.js +335 -0
- package/lib/runner-command.js +1 -1
- package/lib/scorecard.js +4 -4
- package/lib/sleep-sync.js +11 -0
- package/lib/state-detection.js +36 -17
- package/lib/task-db.js +74 -53
- package/lib/task-list-keeper.js +192 -0
- package/lib/todo-fallback.js +10 -4
- package/lib/todo.js +22 -10
- package/lib/wish-delegate.js +19 -5
- package/mcp/atris-mcp/index.mjs +227 -0
- package/package.json +4 -2
- package/scripts/det/det.js +2 -2
- package/scripts/det/pr-description.js +2 -2
- package/scripts/det/test.js +2 -2
- package/scripts/det/ytnotes +43 -8
- package/utils/api.js +1 -1
- package/utils/auth.js +79 -14
- package/utils/backend-root.js +31 -0
- package/utils/config.js +5 -4
- package/utils/owner-identity.js +61 -0
- package/atris/policies/LESSONS.md +0 -13
- package/atris/skills/autopilot/atris-autopilot.md +0 -71
package/commands/member.js
CHANGED
|
@@ -4,12 +4,15 @@ const crypto = require('crypto');
|
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const { execFileSync, spawnSync } = require('child_process');
|
|
6
6
|
const { loadCredentials } = require('../utils/auth');
|
|
7
|
+
const { resolveBackendRoot } = require('../utils/backend-root');
|
|
7
8
|
const { apiRequestJson } = require('../utils/api');
|
|
8
9
|
const { runAliveTick } = require('../lib/member-alive');
|
|
9
10
|
const { defaultObjectiveRunner } = require('../lib/default-runner');
|
|
10
11
|
const { readJson, writeJson } = require('../lib/json-file');
|
|
12
|
+
const { sleepSync } = require('../lib/sleep-sync');
|
|
11
13
|
const { hasFlag, readFlag, readNumberFlag } = require('../lib/arg-parser');
|
|
12
14
|
const { ensureMemberBundle, memberBundlePresent } = require('../lib/member-scaffold');
|
|
15
|
+
const { memberProcessPrompt, MEMBER_PROCESS_PATH } = require('../lib/member-context');
|
|
13
16
|
|
|
14
17
|
function findWorkspaceBusinessId(startDir = process.cwd()) {
|
|
15
18
|
let dir = path.resolve(startDir);
|
|
@@ -462,6 +465,7 @@ function missionPurpose(paths) {
|
|
|
462
465
|
}
|
|
463
466
|
|
|
464
467
|
const MEMBER_RUN_RUNNABLE_STATUSES = new Set(['planning', 'running', 'ready']);
|
|
468
|
+
const MISSION_TERMINAL_STATUSES = new Set(['complete', 'stopped', 'failed']);
|
|
465
469
|
|
|
466
470
|
function memberRunMissionMap() {
|
|
467
471
|
try {
|
|
@@ -684,6 +688,15 @@ const MEMBER_RUN_START_VALUE_FLAGS = [
|
|
|
684
688
|
'--mission-id',
|
|
685
689
|
'--owner',
|
|
686
690
|
'--runner',
|
|
691
|
+
'--engine',
|
|
692
|
+
'--budget',
|
|
693
|
+
'--repo',
|
|
694
|
+
'--native-goal-status',
|
|
695
|
+
'--native-goal-objective',
|
|
696
|
+
'--visible-goal-status',
|
|
697
|
+
'--visible-goal-objective',
|
|
698
|
+
'--max-idle-ticks',
|
|
699
|
+
'--slots',
|
|
687
700
|
'--lane',
|
|
688
701
|
'--cadence',
|
|
689
702
|
'--verify',
|
|
@@ -715,10 +728,49 @@ const MEMBER_RUN_START_BOOLEAN_FLAGS = [
|
|
|
715
728
|
'--stop-when-done',
|
|
716
729
|
'--choose-work',
|
|
717
730
|
'--auto',
|
|
731
|
+
'--headless',
|
|
732
|
+
'--self-drive',
|
|
733
|
+
'--no-claude',
|
|
734
|
+
'--complete-on-pass',
|
|
735
|
+
'--no-drain',
|
|
736
|
+
'--create-next',
|
|
737
|
+
'--preflight',
|
|
738
|
+
'--no-preflight',
|
|
739
|
+
'--room-preflight',
|
|
740
|
+
'--no-room-preflight',
|
|
741
|
+
'--room-auto-run',
|
|
742
|
+
'--no-room-auto-run',
|
|
743
|
+
'--manual-ack',
|
|
744
|
+
'--allow-native-goal-supersede',
|
|
745
|
+
'--supersede-paused-native-goal',
|
|
746
|
+
'--take-goal-slot',
|
|
747
|
+
'--due',
|
|
748
|
+
'--detach',
|
|
749
|
+
'--fleet',
|
|
750
|
+
'--dry-run',
|
|
751
|
+
'--land',
|
|
752
|
+
'--cloud',
|
|
718
753
|
];
|
|
719
754
|
|
|
755
|
+
function memberRunMissionWordIndices(args = []) {
|
|
756
|
+
const values = new Set(MEMBER_RUN_START_VALUE_FLAGS);
|
|
757
|
+
const booleans = new Set(['--full', '--verbose', ...MEMBER_RUN_START_BOOLEAN_FLAGS]);
|
|
758
|
+
const indices = [];
|
|
759
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
760
|
+
const arg = String(args[i]);
|
|
761
|
+
const key = arg.includes('=') ? arg.slice(0, arg.indexOf('=')) : arg;
|
|
762
|
+
if (booleans.has(key)) continue;
|
|
763
|
+
if (values.has(key)) {
|
|
764
|
+
if (!arg.includes('=') && args[i + 1] && !String(args[i + 1]).startsWith('--')) i += 1;
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
indices.push(i);
|
|
768
|
+
}
|
|
769
|
+
return indices;
|
|
770
|
+
}
|
|
771
|
+
|
|
720
772
|
function memberRunMissionText(args = []) {
|
|
721
|
-
return
|
|
773
|
+
return memberRunMissionWordIndices(args).map((index) => args[index]).join(' ').trim();
|
|
722
774
|
}
|
|
723
775
|
|
|
724
776
|
function cleanMemberRunPhrase(value) {
|
|
@@ -832,10 +884,8 @@ function buildMemberRunStartArgs(owner, missionText, args = [], cwd = process.cw
|
|
|
832
884
|
pushFlagValue(startArgs, args, '--minutes');
|
|
833
885
|
pushFlagValue(startArgs, args, '--hours');
|
|
834
886
|
pushFlagValue(startArgs, args, '--base');
|
|
835
|
-
//
|
|
836
|
-
//
|
|
837
|
-
// wishes) would only kill autonomous legs like autopilot's "member chooses
|
|
838
|
-
// useful work". When the caller named no verifier, opt out explicitly.
|
|
887
|
+
// Member runs choose and drive work immediately, so an absent check must not
|
|
888
|
+
// leave autonomous callers with a mission that never ran.
|
|
839
889
|
if (hasFlag(args, '--no-verify') || !readFlag(args, '--verify', '')) {
|
|
840
890
|
startArgs.push('--no-verify');
|
|
841
891
|
}
|
|
@@ -851,7 +901,7 @@ function buildMemberRunStartArgs(owner, missionText, args = [], cwd = process.cw
|
|
|
851
901
|
if (!hasFlag(args, '--shared-checkout') && !hasFlag(args, '--no-worktree') && insideGitRepo(cwd)) {
|
|
852
902
|
startArgs.push('--worktree');
|
|
853
903
|
}
|
|
854
|
-
|
|
904
|
+
startArgs.push('--json');
|
|
855
905
|
return startArgs;
|
|
856
906
|
}
|
|
857
907
|
|
|
@@ -869,15 +919,52 @@ function startMemberRunMission(name, missionText, args = []) {
|
|
|
869
919
|
const paths = requireMemberDir(name);
|
|
870
920
|
const owner = paths.storageName || name;
|
|
871
921
|
const startArgs = buildMemberRunStartArgs(owner, missionText, args);
|
|
922
|
+
return memberRunCli(startArgs, process.cwd());
|
|
923
|
+
}
|
|
872
924
|
|
|
925
|
+
function memberRunCli(args, cwd, { live = false, missionId = '' } = {}) {
|
|
873
926
|
const cliPath = path.join(__dirname, '..', 'bin', 'atris.js');
|
|
927
|
+
const runsDir = path.join(cwd, 'atris', 'runs');
|
|
928
|
+
const previousReceipts = live && fs.existsSync(runsDir) ? new Set(fs.readdirSync(runsDir)) : new Set();
|
|
929
|
+
const result = spawnSync(process.execPath, [cliPath, ...args], {
|
|
930
|
+
cwd,
|
|
931
|
+
encoding: 'utf8',
|
|
932
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
933
|
+
stdio: live ? 'inherit' : ['ignore', 'pipe', 'pipe'],
|
|
934
|
+
});
|
|
935
|
+
if (result.error) throw result.error;
|
|
936
|
+
if (live) {
|
|
937
|
+
const receiptName = fs.existsSync(runsDir)
|
|
938
|
+
? fs.readdirSync(runsDir).filter((name) => !previousReceipts.has(name) && name.startsWith(`mission-${missionId}-`) && name.endsWith('.json')).sort().at(-1)
|
|
939
|
+
: null;
|
|
940
|
+
const receipt = receiptName ? readJson(path.join(runsDir, receiptName), null) : null;
|
|
941
|
+
return { status: result.status, payload: receipt?.result?.kind === 'mission_run_summary'
|
|
942
|
+
? { ran_ticks: receipt.result.ran_ticks } : null, stderr: '', errorReported: result.status !== 0 };
|
|
943
|
+
}
|
|
944
|
+
let payload = null;
|
|
874
945
|
try {
|
|
875
|
-
|
|
876
|
-
cwd: process.cwd(),
|
|
877
|
-
stdio: 'inherit',
|
|
878
|
-
});
|
|
946
|
+
payload = JSON.parse(result.stdout);
|
|
879
947
|
} catch (error) {
|
|
880
|
-
|
|
948
|
+
if (result.status === 0) throw new Error(`member run: mission command returned invalid json: ${error.message}`);
|
|
949
|
+
}
|
|
950
|
+
return { status: result.status, payload, stderr: String(result.stderr || '').trim() };
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
function memberRunConfiguredVerifier(paths) {
|
|
954
|
+
const frontmatter = parseFrontmatter(fs.readFileSync(paths.memberFile, 'utf8')) || {};
|
|
955
|
+
const check = frontmatter.verify || frontmatter.verifier;
|
|
956
|
+
return typeof check === 'string' ? check.trim() : '';
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function printMemberRunResult(result, asJson) {
|
|
960
|
+
if (asJson) {
|
|
961
|
+
console.log(JSON.stringify(result));
|
|
962
|
+
} else if (result.started) {
|
|
963
|
+
console.log(`started ${result.mission_id} (${result.state})`);
|
|
964
|
+
}
|
|
965
|
+
if (result.ok === false || (!result.started && result.ok !== true)) {
|
|
966
|
+
if (!result.errorReported) console.error(result.error);
|
|
967
|
+
process.exitCode = 1;
|
|
881
968
|
}
|
|
882
969
|
}
|
|
883
970
|
|
|
@@ -928,12 +1015,11 @@ function memberPing(name, ...args) {
|
|
|
928
1015
|
process.exit(2);
|
|
929
1016
|
}
|
|
930
1017
|
const missionMod = require('./mission');
|
|
931
|
-
const terminal = new Set(['complete', 'stopped', 'failed']);
|
|
932
1018
|
const candidates = [
|
|
933
1019
|
...missionMod.listMissions(process.cwd()),
|
|
934
1020
|
...missionMod.listWorktreeRollupMissions(process.cwd()),
|
|
935
1021
|
]
|
|
936
|
-
.filter((m) => m && m.owner === name && !
|
|
1022
|
+
.filter((m) => m && m.owner === name && !MISSION_TERMINAL_STATUSES.has(m.status))
|
|
937
1023
|
.sort((a, b) => String(b.updated_at || b.created_at || '').localeCompare(String(a.updated_at || a.created_at || '')));
|
|
938
1024
|
|
|
939
1025
|
const taskNote = pingClaimedTaskDialogue(name, text, from);
|
|
@@ -966,48 +1052,96 @@ function memberPing(name, ...args) {
|
|
|
966
1052
|
|
|
967
1053
|
function memberRun(name, ...args) {
|
|
968
1054
|
if (!name || name === '--help' || name === '-h' || hasFlag(args, '--help') || hasFlag(args, '-h')) {
|
|
969
|
-
console.log('
|
|
970
|
-
console.log('
|
|
971
|
-
console.log('
|
|
972
|
-
console.log('
|
|
973
|
-
console.log('
|
|
974
|
-
console.log('
|
|
975
|
-
console.log('
|
|
1055
|
+
console.log('usage: atris member run <name> ["mission text"] [--verify "<cmd>"] [--minutes N|--hours N] [--json]');
|
|
1056
|
+
console.log('new mission: atris member run growth "improve onboarding proof" --verify "npm test" --minutes 30 --json');
|
|
1057
|
+
console.log('choose work: atris member run growth --verify "npm test" --industry logistics --minutes 30 --json');
|
|
1058
|
+
console.log('existing mission: atris member run growth --mission <mission-id> --max-ticks 1 --json');
|
|
1059
|
+
console.log('meaning: if mission text is omitted, the member chooses one useful bounded task from atris state.');
|
|
1060
|
+
console.log('truth: useful work must improve revenue, reliability, speed, security, clarity, or trust, then show plain proof.');
|
|
1061
|
+
console.log('isolation: new missions use --worktree by default; add --shared-checkout to stay here.');
|
|
1062
|
+
console.log('check: --verify or a verify field in the member file adds a mission check.');
|
|
976
1063
|
return;
|
|
977
1064
|
}
|
|
978
1065
|
|
|
1066
|
+
const asJson = hasFlag(args, '--json');
|
|
1067
|
+
const paths = requireMemberDir(name);
|
|
1068
|
+
const requestedVerifier = readFlag(args, '--verify', '') || memberRunConfiguredVerifier(paths);
|
|
979
1069
|
const missionText = memberRunMissionText(args);
|
|
980
1070
|
const hasMissionOverride = Boolean(readFlag(args, '--mission', '') || readFlag(args, '--mission-id', ''));
|
|
1071
|
+
let mission = null;
|
|
1072
|
+
let startedNewMission = false;
|
|
1073
|
+
let nodeModulesLinked = false;
|
|
1074
|
+
let nodeModulesSource = null;
|
|
981
1075
|
if (missionText && !hasMissionOverride) {
|
|
982
|
-
startMemberRunMission(name, missionText, args);
|
|
983
|
-
|
|
1076
|
+
const start = startMemberRunMission(name, missionText, requestedVerifier ? [...args, '--verify', requestedVerifier] : args);
|
|
1077
|
+
if (start.status !== 0 || !start.payload?.mission) {
|
|
1078
|
+
printMemberRunResult({ started: false, state: null, mission_id: start.payload?.mission?.id || null,
|
|
1079
|
+
error: start.payload?.detail || start.payload?.error || start.stderr || 'mission creation failed' }, asJson);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
mission = start.payload.mission;
|
|
1083
|
+
startedNewMission = true;
|
|
1084
|
+
nodeModulesLinked = Boolean(start.payload.node_modules_linked);
|
|
1085
|
+
nodeModulesSource = start.payload.node_modules_source || null;
|
|
1086
|
+
} else {
|
|
1087
|
+
const missionId = resolveMemberRunMissionId(name, args);
|
|
1088
|
+
if (!missionId) {
|
|
1089
|
+
const start = startMemberRunMission(name, memberRunAutoMissionText(name, args), requestedVerifier ? [...args, '--verify', requestedVerifier] : args);
|
|
1090
|
+
if (start.status !== 0 || !start.payload?.mission) {
|
|
1091
|
+
printMemberRunResult({ started: false, state: null, mission_id: start.payload?.mission?.id || null,
|
|
1092
|
+
error: start.payload?.detail || start.payload?.error || start.stderr || 'mission creation failed' }, asJson);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
mission = start.payload.mission;
|
|
1096
|
+
startedNewMission = true;
|
|
1097
|
+
nodeModulesLinked = Boolean(start.payload.node_modules_linked);
|
|
1098
|
+
nodeModulesSource = start.payload.node_modules_source || null;
|
|
1099
|
+
} else {
|
|
1100
|
+
mission = require('./mission').resolveMission(missionId);
|
|
1101
|
+
if (!mission) {
|
|
1102
|
+
printMemberRunResult({ started: false, state: null, mission_id: missionId, error: `mission ${missionId} was not found` }, asJson);
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
984
1106
|
}
|
|
985
1107
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
return;
|
|
1108
|
+
if (startedNewMission && !asJson) {
|
|
1109
|
+
if (mission.worktree?.path) console.log(`worktree: ${mission.worktree.path}`);
|
|
1110
|
+
if (nodeModulesLinked) console.log(`linked node_modules from ${nodeModulesSource}`);
|
|
990
1111
|
}
|
|
991
1112
|
|
|
992
|
-
const
|
|
1113
|
+
const cwd = mission.worktree?.path || process.cwd();
|
|
1114
|
+
const verifier = readFlag(args, '--verify', '') || mission.verifier || requestedVerifier;
|
|
1115
|
+
if (verifier && verifier !== mission.verifier) {
|
|
1116
|
+
const changed = memberRunCli(['mission', 'set-verifier', mission.id, verifier, '--json'], cwd);
|
|
1117
|
+
if (changed.status !== 0) {
|
|
1118
|
+
printMemberRunResult({ started: false, state: mission.status, mission_id: mission.id, mission,
|
|
1119
|
+
error: changed.payload?.detail || changed.payload?.error || changed.stderr || 'could not set mission check' }, asJson);
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
mission.verifier = verifier;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
const missionWordIndices = missionText && !hasMissionOverride ? new Set(memberRunMissionWordIndices(args)) : new Set();
|
|
1126
|
+
const executionArgs = args.filter((_, index) => !missionWordIndices.has(index));
|
|
1127
|
+
const runArgs = stripKnownFlags(executionArgs,
|
|
1128
|
+
['--mission', '--mission-id', '--minutes', '--hours', '--industry', '--domain', '--value', '--outcome', '--truth', '--proof', '--base'],
|
|
1129
|
+
['--worktree', '--shared-checkout', '--no-worktree', '--choose-work', '--auto']);
|
|
993
1130
|
const budgetSeconds = memberRunBudgetSeconds(args);
|
|
994
|
-
// A timed run is a loop contract, not one tick: keep picking the next useful
|
|
995
|
-
// move until the wall clock (--max-wall) spends the budget. Only untimed runs
|
|
996
|
-
// default to a single tick.
|
|
997
1131
|
if (!readFlag(runArgs, '--max-ticks', '')) {
|
|
998
1132
|
runArgs.push('--max-ticks', budgetSeconds ? String(Math.max(4, Math.ceil(budgetSeconds / 300))) : '1');
|
|
999
1133
|
}
|
|
1000
1134
|
if (!readFlag(runArgs, '--max-wall', '')) runArgs.push('--max-wall', String(budgetSeconds || 900));
|
|
1001
|
-
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1135
|
+
const run = memberRunCli(['mission', 'run', mission.id, ...runArgs], cwd, { live: !asJson, missionId: mission.id });
|
|
1136
|
+
const payload = run.payload || {};
|
|
1137
|
+
const finalMission = payload.mission || require('./mission').resolveMission(mission.id, cwd) || mission;
|
|
1138
|
+
const started = run.status === 0 && payload.ok !== false && Number(payload.ran_ticks) > 0;
|
|
1139
|
+
const noWorkStepExpected = hasFlag(runArgs, '--detach') || hasFlag(runArgs, '--dry-run');
|
|
1140
|
+
const ok = run.status === 0 && payload.ok !== false && (started || noWorkStepExpected);
|
|
1141
|
+
printMemberRunResult({ ...payload, ok, started, state: finalMission.status, mission_id: mission.id,
|
|
1142
|
+
mission: finalMission, node_modules_linked: nodeModulesLinked, node_modules_source: nodeModulesSource,
|
|
1143
|
+
errorReported: run.errorReported,
|
|
1144
|
+
...(!ok ? { error: payload.detail || payload.error || payload.reason || run.stderr || 'mission did not run a work step' } : {}) }, asJson);
|
|
1011
1145
|
}
|
|
1012
1146
|
|
|
1013
1147
|
function loadTeamScoreEvidence(scoreJsonPath) {
|
|
@@ -1830,8 +1964,8 @@ function problemSignalSources(root = process.cwd()) {
|
|
|
1830
1964
|
sources.push(source);
|
|
1831
1965
|
}
|
|
1832
1966
|
for (const source of problemSignalFilesForStateDir(path.join(root, '.atris', 'state'))) push(source);
|
|
1833
|
-
const siblingBackend =
|
|
1834
|
-
if (
|
|
1967
|
+
const siblingBackend = resolveBackendRoot(root);
|
|
1968
|
+
if (siblingBackend) {
|
|
1835
1969
|
for (const source of problemSignalFilesForStateDir(path.join(siblingBackend, '.atris', 'state'), 'backend')) push(source);
|
|
1836
1970
|
}
|
|
1837
1971
|
for (const source of configuredProblemSignalSources(root)) push(source);
|
|
@@ -4216,6 +4350,7 @@ function memberActivate(name) {
|
|
|
4216
4350
|
|
|
4217
4351
|
const content = fs.readFileSync(activePath, 'utf8');
|
|
4218
4352
|
const fm = parseFrontmatter(content) || {};
|
|
4353
|
+
const sharedProcess = memberProcessPrompt(process.cwd());
|
|
4219
4354
|
|
|
4220
4355
|
console.log('');
|
|
4221
4356
|
console.log(`Activating: ${fm.name || name} (${fm.role || 'no role'})`);
|
|
@@ -4298,7 +4433,8 @@ function memberActivate(name) {
|
|
|
4298
4433
|
|
|
4299
4434
|
console.log('');
|
|
4300
4435
|
console.log(`Member "${fm.name || name}" activated.`);
|
|
4301
|
-
|
|
4436
|
+
const identityPath = path.relative(process.cwd(), activePath);
|
|
4437
|
+
console.log(`Tell your agent: "You are the ${fm.role || name}. Read ${sharedProcess ? `${MEMBER_PROCESS_PATH}, then ` : ''}${identityPath}. Stay inside this member's permissions."`);
|
|
4302
4438
|
}
|
|
4303
4439
|
|
|
4304
4440
|
// --- UPGRADE subcommand ---
|
|
@@ -4591,12 +4727,6 @@ function printJsonOrText(payload, lines, asJson) {
|
|
|
4591
4727
|
for (const line of lines) console.log(line);
|
|
4592
4728
|
}
|
|
4593
4729
|
|
|
4594
|
-
function sleepSync(ms) {
|
|
4595
|
-
const duration = Math.max(0, Number(ms) || 0);
|
|
4596
|
-
if (duration <= 0) return;
|
|
4597
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, duration);
|
|
4598
|
-
}
|
|
4599
|
-
|
|
4600
4730
|
function memberGoal(name, ...args) {
|
|
4601
4731
|
const paths = requireMemberDir(name);
|
|
4602
4732
|
const asJson = hasFlag(args, '--json');
|
|
@@ -4707,6 +4837,49 @@ function memberGoalFromMission(name, ...args) {
|
|
|
4707
4837
|
);
|
|
4708
4838
|
return;
|
|
4709
4839
|
}
|
|
4840
|
+
if (MISSION_TERMINAL_STATUSES.has(lowerCompact(runtime.status || ''))) {
|
|
4841
|
+
// A finished mission must not mint or re-point an active goal; that recreated the
|
|
4842
|
+
// stale-goal defect class (OBL-1961, OBL-2212, OBL-2232) after every retire. --force
|
|
4843
|
+
// cannot bypass this, it only widens the existing-goal match on a living mission.
|
|
4844
|
+
const staleGoals = state.goals.filter((goal) => (
|
|
4845
|
+
goal.source === 'mission' && goal.status === 'active'
|
|
4846
|
+
&& runtime.id && goal.mission_id === runtime.id
|
|
4847
|
+
));
|
|
4848
|
+
const staleList = staleGoals.map((goal) => goal.title || goal.id).join('; ');
|
|
4849
|
+
const ask = staleGoals.length
|
|
4850
|
+
? `Mission ${runtime.id || compactSentence(runtimeFocus, 88)} is ${runtime.status}, so its active goal is stale. Retire ${compactSentence(staleList, 140)} by setting its status in goals.json, or start a living mission and run: atris member goal-from-mission ${name} --force`
|
|
4851
|
+
: `Mission ${runtime.id || compactSentence(runtimeFocus, 88)} is ${runtime.status}. Start a living mission, then run: atris member goal-from-mission ${name} --force`;
|
|
4852
|
+
const logPath = appendMemberGoalLog(paths.memberDir, name, 'Member goal-from-mission blocked', {
|
|
4853
|
+
ask,
|
|
4854
|
+
mission_id: runtime.id || '',
|
|
4855
|
+
mission_status: runtime.status || '',
|
|
4856
|
+
stale_goals: staleGoals.map((goal) => goal.id),
|
|
4857
|
+
});
|
|
4858
|
+
printJsonOrText(
|
|
4859
|
+
{
|
|
4860
|
+
ok: true,
|
|
4861
|
+
action: 'needs_user',
|
|
4862
|
+
member: name,
|
|
4863
|
+
needs_user: true,
|
|
4864
|
+
ask,
|
|
4865
|
+
stale_goals: staleGoals,
|
|
4866
|
+
mission: {
|
|
4867
|
+
north_star: purpose.northStar,
|
|
4868
|
+
runtime_id: runtime.id || null,
|
|
4869
|
+
runtime_status: runtime.status || null,
|
|
4870
|
+
runtime_next: runtime.next || null,
|
|
4871
|
+
},
|
|
4872
|
+
mission_file: paths.missionFile,
|
|
4873
|
+
log_path: logPath,
|
|
4874
|
+
},
|
|
4875
|
+
[
|
|
4876
|
+
`Blocked for ${name}: mission ${runtime.id || 'in now.md'} is ${runtime.status}, a finished mission cannot drive an active goal.`,
|
|
4877
|
+
`Ask: ${ask}`,
|
|
4878
|
+
],
|
|
4879
|
+
asJson,
|
|
4880
|
+
);
|
|
4881
|
+
return;
|
|
4882
|
+
}
|
|
4710
4883
|
// The title IS the mission focus, no boilerplate prefix; the acceptance list already
|
|
4711
4884
|
// says "one bounded step" and the why carries the full sentence.
|
|
4712
4885
|
const title = compactSentence(runtimeFocus, 96);
|
|
@@ -4977,7 +5150,8 @@ function fallbackProposalForGoal(goal, context = {}) {
|
|
|
4977
5150
|
};
|
|
4978
5151
|
}
|
|
4979
5152
|
|
|
4980
|
-
function proposalPromptForGoal(goal, context = {}) {
|
|
5153
|
+
function proposalPromptForGoal(goal, context = {}, cwd = process.cwd()) {
|
|
5154
|
+
const sharedProcess = memberProcessPrompt(cwd);
|
|
4981
5155
|
const files = (context?.evidence?.goal_files?.files || [])
|
|
4982
5156
|
.filter((file) => file.exists && file.excerpt)
|
|
4983
5157
|
.slice(0, 4)
|
|
@@ -5005,6 +5179,7 @@ function proposalPromptForGoal(goal, context = {}) {
|
|
|
5005
5179
|
},
|
|
5006
5180
|
};
|
|
5007
5181
|
return [
|
|
5182
|
+
...(sharedProcess ? [sharedProcess, ''] : []),
|
|
5008
5183
|
'You generate the next bounded Atris member experiment.',
|
|
5009
5184
|
'Read the JSON context and return only JSON with keys: title, proof_target, next_step, verifier, stop_rule.',
|
|
5010
5185
|
'The next_step must be adaptive to the goal/evidence, concrete, receipt-backed, and safe for one bounded tick.',
|
|
@@ -5058,10 +5233,11 @@ async function callAtris2ProposalLlm(goal, context = {}) {
|
|
|
5058
5233
|
const injected = injectedLlmProposal();
|
|
5059
5234
|
if (injected) return injected;
|
|
5060
5235
|
if (process.env.ATRIS_MEMBER_PROPOSAL_LLM !== '1') return null;
|
|
5236
|
+
const prompt = proposalPromptForGoal(goal, context, process.cwd());
|
|
5061
5237
|
try {
|
|
5062
5238
|
const { postTurn } = require('../ax');
|
|
5063
5239
|
const output = { isTTY: false, write() { return true; } };
|
|
5064
|
-
const result = await postTurn(
|
|
5240
|
+
const result = await postTurn(prompt, {
|
|
5065
5241
|
mode: process.env.ATRIS_MEMBER_PROPOSAL_LLM_MODE || 'fast',
|
|
5066
5242
|
route: 'local',
|
|
5067
5243
|
cwd: process.cwd(),
|
|
@@ -5761,6 +5937,7 @@ function emptyObjectiveGeneratorProposal(extra = {}) {
|
|
|
5761
5937
|
updated_at: stampIso(),
|
|
5762
5938
|
status: extra.status || 'empty',
|
|
5763
5939
|
advisory_only: true,
|
|
5940
|
+
auto_task_eligible: extra.auto_task_eligible !== false,
|
|
5764
5941
|
world_model_used: false,
|
|
5765
5942
|
llm_source: extra.llm_source || null,
|
|
5766
5943
|
llm_error: extra.llm_error || null,
|
|
@@ -5893,8 +6070,8 @@ function fallbackObjectiveGeneratorProposal(graph, recommendations, transferPatt
|
|
|
5893
6070
|
),
|
|
5894
6071
|
suggested_member: member,
|
|
5895
6072
|
suggested_patterns: objectivePatternMatches(transferPatterns, proposedObjective),
|
|
5896
|
-
}, { status: 'ok', llm_error: 'llm_not_configured', world_model_used: true });
|
|
5897
|
-
return proposal || emptyObjectiveGeneratorProposal({ status: 'llm_not_configured', llm_error: 'llm_not_configured' });
|
|
6073
|
+
}, { status: 'ok', llm_error: 'llm_not_configured', world_model_used: true, auto_task_eligible: false });
|
|
6074
|
+
return proposal || emptyObjectiveGeneratorProposal({ status: 'llm_not_configured', llm_error: 'llm_not_configured', auto_task_eligible: false });
|
|
5898
6075
|
}
|
|
5899
6076
|
|
|
5900
6077
|
function objectiveGeneratorPrompt(graph, recommendations, transferPatterns = []) {
|
|
@@ -6056,7 +6233,7 @@ async function runObjectiveGeneratorWake(name, paths, { execute = false } = {})
|
|
|
6056
6233
|
proposal = emptyObjectiveGeneratorProposal({ status: llm.error === 'invalid_json' ? 'parse_error' : 'llm_error', llm_source: llm.source, llm_error: llm.error });
|
|
6057
6234
|
proposal.world_model_used = true;
|
|
6058
6235
|
} else {
|
|
6059
|
-
reason = 'heuristic_objective_proposal_written';
|
|
6236
|
+
reason = execute ? 'heuristic_objective_proposal_written' : 'heuristic_objective_proposal_dry_run';
|
|
6060
6237
|
proposal = fallbackObjectiveGeneratorProposal(graph, recommendations, transferPatterns);
|
|
6061
6238
|
}
|
|
6062
6239
|
}
|
|
@@ -6065,7 +6242,7 @@ async function runObjectiveGeneratorWake(name, paths, { execute = false } = {})
|
|
|
6065
6242
|
proposal.suggested_patterns = objectivePatternMatches(transferPatterns, proposal.proposed_objective);
|
|
6066
6243
|
}
|
|
6067
6244
|
|
|
6068
|
-
if (execute && proposal?.status === 'ok' && Number(proposal.overall_score) > 7) {
|
|
6245
|
+
if (execute && proposal?.status === 'ok' && proposal.auto_task_eligible !== false && Number(proposal.overall_score) > 7) {
|
|
6069
6246
|
createdTask = createAutoObjectiveTask(proposal);
|
|
6070
6247
|
proposal.created_task = createdTask.ok ? {
|
|
6071
6248
|
id: createdTask.task_id || null,
|
|
@@ -6081,7 +6258,8 @@ async function runObjectiveGeneratorWake(name, paths, { execute = false } = {})
|
|
|
6081
6258
|
}
|
|
6082
6259
|
|
|
6083
6260
|
const proposalsPath = objectiveGeneratorProposalsPath(root);
|
|
6084
|
-
|
|
6261
|
+
const proposalsWritten = Boolean(execute);
|
|
6262
|
+
if (proposalsWritten) {
|
|
6085
6263
|
fs.mkdirSync(path.dirname(proposalsPath), { recursive: true });
|
|
6086
6264
|
fs.writeFileSync(proposalsPath, JSON.stringify(proposal, null, 2) + '\n', 'utf8');
|
|
6087
6265
|
}
|
|
@@ -6111,6 +6289,7 @@ async function runObjectiveGeneratorWake(name, paths, { execute = false } = {})
|
|
|
6111
6289
|
llm_successful: Boolean(llm?.source && llm?.proposal && proposal.status === 'ok'),
|
|
6112
6290
|
llm_error: llm?.error || proposal.llm_error || null,
|
|
6113
6291
|
proposals_path: path.relative(root, proposalsPath),
|
|
6292
|
+
proposals_written: proposalsWritten,
|
|
6114
6293
|
task_creation_threshold: 7,
|
|
6115
6294
|
task_created: Boolean(createdTask?.ok),
|
|
6116
6295
|
created_task: proposal.created_task,
|
|
@@ -6128,7 +6307,7 @@ async function runObjectiveGeneratorWake(name, paths, { execute = false } = {})
|
|
|
6128
6307
|
score: proposal.overall_score || '',
|
|
6129
6308
|
task: proposal.created_task?.ref || '',
|
|
6130
6309
|
receipt: path.relative(root, receiptPath),
|
|
6131
|
-
output: path.relative(root, proposalsPath),
|
|
6310
|
+
output: proposalsWritten ? path.relative(root, proposalsPath) : '',
|
|
6132
6311
|
});
|
|
6133
6312
|
|
|
6134
6313
|
return {
|
|
@@ -7817,6 +7996,7 @@ const WAKE_REASON_TEXT = {
|
|
|
7817
7996
|
auto_improver_task_create_failed: 'it found an improvement but could not put the task on the board',
|
|
7818
7997
|
heuristic_cross_domain_proof_written: 'it wrote a cross-domain proof using its built-in heuristics',
|
|
7819
7998
|
heuristic_objective_proposal_written: 'it drafted an objective proposal using its built-in heuristics',
|
|
7999
|
+
heuristic_objective_proposal_dry_run: 'it previewed an objective proposal using its built-in heuristics, without writing it',
|
|
7820
8000
|
install_requires_clean_git: 'installing needs a clean git tree first',
|
|
7821
8001
|
insufficient_world_model_data: 'its world model is too thin to act on yet',
|
|
7822
8002
|
llm_json_parse_failed: 'the model reply did not parse, so it stopped rather than act on garbage',
|
|
@@ -9208,7 +9388,7 @@ async function memberCommand(subcommand, ...args) {
|
|
|
9208
9388
|
console.log(' atris member goal-from-mission growth --json');
|
|
9209
9389
|
console.log(' atris member goal-from-score growth --score-json team-score.json --json');
|
|
9210
9390
|
console.log(' atris member wake growth --json');
|
|
9211
|
-
console.log(' atris member run growth "
|
|
9391
|
+
console.log(' atris member run growth "improve onboarding proof" --verify "npm test" --minutes 30 --json');
|
|
9212
9392
|
console.log(' atris member run growth --mission <mission-id> --max-ticks 1 --json');
|
|
9213
9393
|
console.log(' atris member wake growth --execute --confirm-autonomy-policy');
|
|
9214
9394
|
console.log(' atris member supervisor recommendations --json');
|
|
@@ -9232,6 +9412,7 @@ async function memberCommand(subcommand, ...args) {
|
|
|
9232
9412
|
}
|
|
9233
9413
|
|
|
9234
9414
|
module.exports = {
|
|
9415
|
+
proposalPromptForGoal,
|
|
9235
9416
|
memberCommand,
|
|
9236
9417
|
findAllMembers,
|
|
9237
9418
|
findWorkspaceBusinessId,
|