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/lib/functional-owner.js
CHANGED
|
@@ -179,11 +179,8 @@ function resolveFunctionalOwner({ requestedOwner, title, tag, note, goal, root,
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
module.exports = {
|
|
182
|
-
ENGINE_OWNER_IDS,
|
|
183
182
|
FUNCTIONAL_MEMBER_TOPICS,
|
|
184
183
|
normalizeOwnerSlug,
|
|
185
|
-
isEngineOwner,
|
|
186
184
|
listWorkspaceMemberSlugs,
|
|
187
|
-
proposedMemberSlugFromTask,
|
|
188
185
|
resolveFunctionalOwner,
|
|
189
186
|
};
|
package/lib/inspect-fields.js
CHANGED
package/lib/known-commands.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const knownCommands = ['init', 'log', 'logs', 'wish', 'drill', 'dream', 'now', 'goal', 'wtf', 'orb', 'radar', 'stream', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
|
|
4
4
|
'activate', '_activate', 'agent', 'team', 'chat', 'fast', 'ax', 'console', 'serve', 'login', 'logout', 'whoami', 'switch', 'use', 'accounts', '_resolve', '_profile-email', '_switch-session', 'shell-init', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
|
|
5
|
-
'clean', 'close', 'harvest', 'verify', 'search', 'scout', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'plugin', 'experiments', 'bench', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'watch', 'cloud', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
|
|
6
|
-
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'agents', 'probe', 'worktree', 'land', 'autoland', 'drive', 'aeo', 'slop', 'strings', 'write', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'study', 'rainmaker', 'xp', 'play', 'gm', 'x', 'recap', 'report', 'signup', 'clarity', 'interview', 'meet', 'moves', 'unknowns', 'avail',
|
|
5
|
+
'clean', 'close', 'harvest', 'verify', 'recover', 'search', 'scout', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'teach', 'plugin', 'experiments', 'bench', 'router', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'watch', 'cloud', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
|
|
6
|
+
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'agents', 'probe', 'worktree', 'land', 'autoland', 'drive', 'aeo', 'slop', 'strings', 'write', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'study', 'rainmaker', 'xp', 'play', 'gm', 'game', 'x', 'recap', 'report', 'signup', 'clarity', 'interview', 'meet', 'moves', 'unknowns', 'avail', 'sync-checkout',
|
|
7
7
|
'github', 'vercel', 'supabase', 'linear', 'stripe', 'gmail', 'calendar', 'twitter', 'slack', 'imessage', 'integrations', 'setup', 'clean-workspace', 'cw',
|
|
8
8
|
'fork', 'browse', 'publish', 'pack', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'fleet-report', 'loops', 'self-improve', 'compile', 'spaceship', 'truth', 'sign', 'engine', 'engines', 'feed', 'brief'];
|
|
9
9
|
|
package/lib/learnings.js
CHANGED
package/lib/loop-doctor.js
CHANGED
|
@@ -311,7 +311,7 @@ function missionLockPidAlive(pid) {
|
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
function
|
|
314
|
+
function missionLockRecords(root, pidAlive = missionLockPidAlive) {
|
|
315
315
|
const stateDir = path.join(root, '.atris', 'state');
|
|
316
316
|
let names = [];
|
|
317
317
|
try {
|
|
@@ -319,18 +319,21 @@ function staleMissionLockFinding(root, nowIso, pidAlive = missionLockPidAlive) {
|
|
|
319
319
|
} catch {
|
|
320
320
|
return [];
|
|
321
321
|
}
|
|
322
|
-
|
|
323
|
-
for (const name of names) {
|
|
322
|
+
return names.map((name) => {
|
|
324
323
|
const file = path.join(stateDir, name);
|
|
325
324
|
let lock = null;
|
|
326
325
|
try { lock = JSON.parse(fs.readFileSync(file, 'utf8')); } catch {}
|
|
327
326
|
const pid = Number(lock && lock.pid);
|
|
328
327
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
329
|
-
|
|
330
|
-
} else if (!pidAlive(pid)) {
|
|
331
|
-
stale.push({ lock: name, reason: 'dead-pid', pid });
|
|
328
|
+
return { lock: name, reason: 'unparseable', pid: null, stale: true };
|
|
332
329
|
}
|
|
333
|
-
|
|
330
|
+
const alive = pidAlive(pid);
|
|
331
|
+
return { lock: name, reason: alive ? 'live-pid' : 'dead-pid', pid, stale: !alive };
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function staleMissionLockFinding(root, nowIso, pidAlive = missionLockPidAlive) {
|
|
336
|
+
const stale = missionLockRecords(root, pidAlive).filter((lock) => lock.stale);
|
|
334
337
|
if (!stale.length) return [];
|
|
335
338
|
return [{
|
|
336
339
|
kind: 'stale_mission_lock',
|
|
@@ -400,17 +403,8 @@ function scanLoopReceipts({ root = process.cwd(), now = new Date(), freshnessMs
|
|
|
400
403
|
|
|
401
404
|
module.exports = {
|
|
402
405
|
scanLoopReceipts,
|
|
403
|
-
|
|
404
|
-
authFailureFindings,
|
|
405
|
-
rewardFlatlineFinding,
|
|
406
|
-
zeroDueCapableFinding,
|
|
407
|
-
staleMissionLockFinding,
|
|
408
|
-
isDueCapableMission,
|
|
406
|
+
missionLockRecords,
|
|
409
407
|
latestMissionRecords,
|
|
410
|
-
orderFindings,
|
|
411
408
|
nonPositiveRewardPressure,
|
|
412
|
-
applyRewardPressure,
|
|
413
409
|
FINDING_PRIORITY,
|
|
414
|
-
DEFAULT_RECEIPT_LIMIT,
|
|
415
|
-
DEFAULT_FINDING_FRESHNESS_MS,
|
|
416
410
|
};
|
package/lib/manifest.js
CHANGED
package/lib/member-alive.js
CHANGED
package/lib/member-switches.js
CHANGED
|
@@ -129,14 +129,9 @@ function memberArgFromArgv(argv = process.argv) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
module.exports = {
|
|
132
|
-
SWITCHES_REL,
|
|
133
|
-
switchesPath,
|
|
134
|
-
loadMemberSwitches,
|
|
135
|
-
saveMemberSwitches,
|
|
136
132
|
isLocalMember,
|
|
137
133
|
getMemberSwitch,
|
|
138
134
|
isMemberAwake,
|
|
139
|
-
isMemberLoopAwake,
|
|
140
135
|
setMemberAwake,
|
|
141
136
|
setMemberLoopAwake,
|
|
142
137
|
readLoopFlag,
|
package/lib/mission-artifact.js
CHANGED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
const { DENIED_TAGS } = require('./fleet');
|
|
8
|
+
|
|
9
|
+
const PATH_SURFACES = [
|
|
10
|
+
['middleware/proxy', /(?:^|[/_.-])(?:middleware|proxy)(?:[/_.-]|$)/i],
|
|
11
|
+
['csp', /(?:^|[/_.-])csp(?:[/_.-]|$)/i],
|
|
12
|
+
['auth', /(?:^|[/_.-])auth(?:entication|orization)?(?:[/_.-]|$)/i],
|
|
13
|
+
['session', /(?:^|[/_.-])sessions?(?:[/_.-]|$)/i],
|
|
14
|
+
['cookie', /(?:^|[/_.-])cookies?(?:[/_.-]|$)/i],
|
|
15
|
+
['cors', /(?:^|[/_.-])cors(?:[/_.-]|$)/i],
|
|
16
|
+
['sandbox', /(?:^|[/_.-])sandbox(?:[/_.-]|$)/i],
|
|
17
|
+
['permission', /(?:^|[/_.-])permissions?(?:[/_.-]|$)/i],
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const CONTENT_SURFACES = [
|
|
21
|
+
['csp', /\bContent-Security-Policy\b/i],
|
|
22
|
+
['csp nonce', /\bnonce\b/i],
|
|
23
|
+
['iframe sandbox', /\bsandbox\s*=/i],
|
|
24
|
+
['cookie', /\bSet-Cookie\b/i],
|
|
25
|
+
['cors', /\bAccess-Control-Allow-[A-Za-z-]+\b/i],
|
|
26
|
+
['public dynamic rendering', /\bforce-dynamic\b/i],
|
|
27
|
+
['auth header', /\b(?:Authorization\s*[:=].*\bBearer\b|headers?\b[^\n]*\bauthorization\b|\bauthorization\b[^\n]*headers?\b)/i],
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function normalizedTags(tags) {
|
|
31
|
+
const list = Array.isArray(tags) ? tags : [tags];
|
|
32
|
+
return list
|
|
33
|
+
.flatMap((tag) => String(tag || '').split(','))
|
|
34
|
+
.map((tag) => tag.trim().toLowerCase().replace(/_/g, '-'))
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function changedPathsFromDiff(diff) {
|
|
39
|
+
const paths = [];
|
|
40
|
+
for (const line of String(diff || '').split(/\r?\n/)) {
|
|
41
|
+
const header = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
42
|
+
if (header) {
|
|
43
|
+
paths.push(header[1], header[2]);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const file = line.match(/^(?:---|\+\+\+) (?:[ab]\/)?(.+)$/);
|
|
47
|
+
if (file && file[1] !== '/dev/null') paths.push(file[1]);
|
|
48
|
+
}
|
|
49
|
+
return Array.from(new Set(paths));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Prose is not a protected surface. Docs, judge cards, wikis, journals and run
|
|
53
|
+
// receipts routinely *describe* CSP or force-dynamic without changing any
|
|
54
|
+
// behaviour — replaying this guard over 60 real commits, 5 of 6 hits were
|
|
55
|
+
// markdown that merely mentioned the words. A guard that pauses on every judge
|
|
56
|
+
// card gets switched off, which is worse than no guard. Content signals
|
|
57
|
+
// therefore apply to code only; PATH signals still apply to every file.
|
|
58
|
+
const CODE_FILE = /\.(?:[cm]?[jt]sx?|py|rb|go|rs|java|kt|swift|php|sh|bash|zsh|sql|ya?ml|toml|env)$/i;
|
|
59
|
+
|
|
60
|
+
function isCodeFile(file) {
|
|
61
|
+
const f = String(file || '').trim();
|
|
62
|
+
if (!f || f === '/dev/null') return false;
|
|
63
|
+
if (/\.(?:md|mdx|markdown|txt|rst|adoc)$/i.test(f)) return false;
|
|
64
|
+
return CODE_FILE.test(f);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Walk the diff file-by-file so a changed line is attributed to the file it
|
|
68
|
+
// came from, then keep only lines from code files.
|
|
69
|
+
function changedCodeLinesFromDiff(diff) {
|
|
70
|
+
const lines = [];
|
|
71
|
+
let inCode = false;
|
|
72
|
+
for (const line of String(diff || '').split(/\r?\n/)) {
|
|
73
|
+
const header = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
74
|
+
if (header) {
|
|
75
|
+
inCode = isCodeFile(header[1]) || isCodeFile(header[2]);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (/^(?:---|\+\+\+) /.test(line)) continue;
|
|
79
|
+
if (!inCode) continue;
|
|
80
|
+
if (/^[+-]/.test(line)) lines.push(line.slice(1));
|
|
81
|
+
}
|
|
82
|
+
return lines;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function matchProtectedMissionDiff(diff, { tags = [] } = {}) {
|
|
86
|
+
const matches = [];
|
|
87
|
+
const add = (surface, signal, detail) => {
|
|
88
|
+
if (matches.some((match) => match.surface === surface && match.signal === signal && match.detail === detail)) return;
|
|
89
|
+
matches.push({ surface, signal, detail });
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
for (const tag of normalizedTags(tags)) {
|
|
93
|
+
if (DENIED_TAGS.includes(tag)) add(tag, 'tag', tag);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (const file of changedPathsFromDiff(diff)) {
|
|
97
|
+
for (const [surface, pattern] of PATH_SURFACES) {
|
|
98
|
+
if (pattern.test(file)) add(surface, 'path', file);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (const line of changedCodeLinesFromDiff(diff)) {
|
|
103
|
+
for (const [surface, pattern] of CONTENT_SURFACES) {
|
|
104
|
+
if (pattern.test(line)) add(surface, 'content', 'changed line');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
protected: matches.length > 0,
|
|
110
|
+
surfaces: Array.from(new Set(matches.map((match) => match.surface))),
|
|
111
|
+
matches,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function runGitDiff(git, args, root) {
|
|
116
|
+
const result = git(args, root);
|
|
117
|
+
if (!result || result.error || result.status !== 0) {
|
|
118
|
+
const detail = result?.error?.message
|
|
119
|
+
|| String(result?.stderr || result?.stdout || `git ${args.join(' ')} failed`).trim();
|
|
120
|
+
return { ok: false, detail: detail || 'git diff could not be read' };
|
|
121
|
+
}
|
|
122
|
+
return { ok: true, diff: String(result.stdout || '') };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function defaultGit(gitBin = 'git') {
|
|
126
|
+
return (args, root) => spawnSync(gitBin, args, {
|
|
127
|
+
cwd: root,
|
|
128
|
+
encoding: 'utf8',
|
|
129
|
+
timeout: 10000,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function readMissionDiff({
|
|
134
|
+
root = process.cwd(),
|
|
135
|
+
baseRef = '',
|
|
136
|
+
git = defaultGit(),
|
|
137
|
+
includeUnstaged = true,
|
|
138
|
+
} = {}) {
|
|
139
|
+
const parts = [];
|
|
140
|
+
const staged = runGitDiff(git, ['diff', '--cached', '--no-ext-diff', '--unified=0', '--no-color', '--'], root);
|
|
141
|
+
if (!staged.ok) return staged;
|
|
142
|
+
parts.push(staged.diff);
|
|
143
|
+
|
|
144
|
+
if (includeUnstaged) {
|
|
145
|
+
const unstaged = runGitDiff(git, ['diff', '--no-ext-diff', '--unified=0', '--no-color', '--'], root);
|
|
146
|
+
if (!unstaged.ok) return unstaged;
|
|
147
|
+
parts.push(unstaged.diff);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (baseRef) {
|
|
151
|
+
const committed = runGitDiff(git, ['diff', '--no-ext-diff', '--unified=0', '--no-color', baseRef, 'HEAD', '--'], root);
|
|
152
|
+
if (!committed.ok) return committed;
|
|
153
|
+
parts.push(committed.diff);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return { ok: true, diff: parts.filter(Boolean).join('\n') };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function protectedPause(reason, detail = {}) {
|
|
160
|
+
return {
|
|
161
|
+
ok: false,
|
|
162
|
+
allowed: false,
|
|
163
|
+
status: 'paused-for-review',
|
|
164
|
+
reason,
|
|
165
|
+
...detail,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function unreadableMissionGuard(error) {
|
|
170
|
+
return protectedPause('mission diff could not be read; human review is required', {
|
|
171
|
+
unreadable: true,
|
|
172
|
+
detail: error?.message || String(error || 'unknown diff read failure'),
|
|
173
|
+
surfaces: ['unreadable diff'],
|
|
174
|
+
matches: [],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function inspectMissionProtectedDiff({
|
|
179
|
+
root = process.cwd(),
|
|
180
|
+
baseRef = '',
|
|
181
|
+
tags = [],
|
|
182
|
+
readDiff = readMissionDiff,
|
|
183
|
+
git,
|
|
184
|
+
includeUnstaged = true,
|
|
185
|
+
} = {}) {
|
|
186
|
+
let read;
|
|
187
|
+
try {
|
|
188
|
+
read = readDiff({ root, baseRef, tags, git, includeUnstaged });
|
|
189
|
+
} catch (error) {
|
|
190
|
+
return unreadableMissionGuard(error);
|
|
191
|
+
}
|
|
192
|
+
if (!read || read.ok !== true) {
|
|
193
|
+
return unreadableMissionGuard(read?.detail);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const matched = matchProtectedMissionDiff(read.diff, { tags });
|
|
197
|
+
if (matched.protected) {
|
|
198
|
+
return protectedPause(`protected mission surface requires human review: ${matched.surfaces.join(', ')}`, {
|
|
199
|
+
unreadable: false,
|
|
200
|
+
surfaces: matched.surfaces,
|
|
201
|
+
matches: matched.matches,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
ok: true,
|
|
206
|
+
allowed: true,
|
|
207
|
+
status: 'clear',
|
|
208
|
+
reason: 'mission diff contains no protected surface',
|
|
209
|
+
unreadable: false,
|
|
210
|
+
surfaces: [],
|
|
211
|
+
matches: [],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function guardMissionLanding(options = {}) {
|
|
216
|
+
const inspection = inspectMissionProtectedDiff(options);
|
|
217
|
+
if (!inspection.allowed) return inspection;
|
|
218
|
+
const land = typeof options.land === 'function' ? options.land : () => ({ ok: true, landed: true });
|
|
219
|
+
return { ...land(), protected_lane_guard: inspection };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function gitSubcommand(args) {
|
|
223
|
+
const consumesValue = new Set(['-C', '-c', '--git-dir', '--work-tree', '--namespace', '--config-env']);
|
|
224
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
225
|
+
const arg = String(args[index] || '');
|
|
226
|
+
if (consumesValue.has(arg)) {
|
|
227
|
+
index += 1;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (arg.startsWith('-')) continue;
|
|
231
|
+
return arg;
|
|
232
|
+
}
|
|
233
|
+
return '';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function prepareMissionGitGuard({
|
|
237
|
+
root = process.cwd(),
|
|
238
|
+
tags = [],
|
|
239
|
+
pathValue = process.env.PATH || '',
|
|
240
|
+
} = {}) {
|
|
241
|
+
const resolved = spawnSync('sh', ['-c', 'command -v git'], {
|
|
242
|
+
cwd: root,
|
|
243
|
+
encoding: 'utf8',
|
|
244
|
+
timeout: 5000,
|
|
245
|
+
});
|
|
246
|
+
const gitBin = String(resolved.stdout || '').trim();
|
|
247
|
+
if (resolved.status !== 0 || !gitBin) {
|
|
248
|
+
throw new Error('mission git guard could not resolve git');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'atris-mission-git-'));
|
|
252
|
+
const wrapper = path.join(dir, 'git');
|
|
253
|
+
const modulePath = __filename;
|
|
254
|
+
const config = { root: path.resolve(root), tags: normalizedTags(tags), gitBin };
|
|
255
|
+
const source = [
|
|
256
|
+
'#!/usr/bin/env node',
|
|
257
|
+
"'use strict';",
|
|
258
|
+
`const { spawnSync } = require('child_process');`,
|
|
259
|
+
`const guard = require(${JSON.stringify(modulePath)});`,
|
|
260
|
+
`const config = ${JSON.stringify(config)};`,
|
|
261
|
+
gitSubcommand.toString(),
|
|
262
|
+
defaultGit.toString(),
|
|
263
|
+
`const args = process.argv.slice(2);`,
|
|
264
|
+
`if (gitSubcommand(args) === 'commit') {`,
|
|
265
|
+
` const result = guard.inspectMissionProtectedDiff({ root: config.root, tags: config.tags, includeUnstaged: false, git: defaultGit(config.gitBin) });`,
|
|
266
|
+
` if (!result.allowed) {`,
|
|
267
|
+
` process.stderr.write(result.reason + '\\n');`,
|
|
268
|
+
` process.exit(78);`,
|
|
269
|
+
` }`,
|
|
270
|
+
`}`,
|
|
271
|
+
`const child = spawnSync(config.gitBin, args, { cwd: process.cwd(), stdio: 'inherit' });`,
|
|
272
|
+
`if (child.error) { process.stderr.write(child.error.message + '\\n'); process.exit(1); }`,
|
|
273
|
+
`process.exit(child.status == null ? 1 : child.status);`,
|
|
274
|
+
'',
|
|
275
|
+
].join('\n');
|
|
276
|
+
fs.writeFileSync(wrapper, source, { encoding: 'utf8', mode: 0o755 });
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
env: { ...process.env, PATH: `${dir}${path.delimiter}${pathValue}` },
|
|
280
|
+
pathPrefix: dir,
|
|
281
|
+
cleanup() {
|
|
282
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch {}
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
module.exports = {
|
|
288
|
+
matchProtectedMissionDiff,
|
|
289
|
+
unreadableMissionGuard,
|
|
290
|
+
inspectMissionProtectedDiff,
|
|
291
|
+
guardMissionLanding,
|
|
292
|
+
prepareMissionGitGuard,
|
|
293
|
+
};
|
package/lib/mission-room.js
CHANGED
package/lib/next-moves.js
CHANGED
|
@@ -844,37 +844,19 @@ function nextMoves(root = process.cwd(), limit = 3) {
|
|
|
844
844
|
module.exports = {
|
|
845
845
|
moveId,
|
|
846
846
|
norm,
|
|
847
|
-
titleKey,
|
|
848
847
|
isGenericInboxPlaceholder,
|
|
849
|
-
WEIGHT,
|
|
850
848
|
SELF_IMPROVEMENT_SEED_TITLE,
|
|
851
|
-
cleanSuggestedTargetTitle,
|
|
852
|
-
suggestedTargetFromReportText,
|
|
853
849
|
latestSuggestedTarget,
|
|
854
|
-
parseInboxTitles,
|
|
855
|
-
cleanInboxMoveTitle,
|
|
856
850
|
readRoadmapOpenItems,
|
|
857
|
-
readWaitingWishCards,
|
|
858
|
-
readActionableMissionCards,
|
|
859
|
-
readActiveMissions,
|
|
860
|
-
readUnreviewedShippedWishCards,
|
|
861
|
-
readDreamCards,
|
|
862
851
|
markDreamCardConsumed,
|
|
863
|
-
dreamCardId,
|
|
864
852
|
readEndgameMove,
|
|
865
|
-
readActiveTasks,
|
|
866
|
-
isInternalNextMoveTask,
|
|
867
853
|
readHandledTaskTitles,
|
|
868
854
|
latestInboxItems,
|
|
869
855
|
todayInboxItems,
|
|
870
|
-
gatherCandidates,
|
|
871
856
|
pickNextMoves,
|
|
872
|
-
readNextParked,
|
|
873
857
|
parkNextCard,
|
|
874
858
|
nextCards,
|
|
875
|
-
addMissionOnlyFallback,
|
|
876
859
|
nextMoves,
|
|
877
|
-
readDecisions,
|
|
878
860
|
recordDecision,
|
|
879
861
|
seedInboxFromMove,
|
|
880
862
|
pickRoadmapSeed,
|
package/lib/orb-context.js
CHANGED
|
@@ -455,7 +455,8 @@ async function collectOrbContext(root, { threads = [], now = Date.now() } = {})
|
|
|
455
455
|
}
|
|
456
456
|
|
|
457
457
|
// The accumulate-context flywheel: each chosen option appends one visible line to the
|
|
458
|
-
// project's now.md. Append-only; creates
|
|
458
|
+
// project's operating truth at atris/now.md. Append-only; creates the file on first
|
|
459
|
+
// choice. (It used to write <root>/now.md, a stray file nothing reads.)
|
|
459
460
|
async function appendOrbChoice(root, label, when = new Date()) {
|
|
460
461
|
const safeRoot = typeof root === 'string' && root ? path.resolve(root) : null;
|
|
461
462
|
const cleanLabel = cleanTitle(label, 120);
|
|
@@ -463,7 +464,10 @@ async function appendOrbChoice(root, label, when = new Date()) {
|
|
|
463
464
|
const day = when.toISOString().slice(0, 10);
|
|
464
465
|
const line = `orb: ${cleanLabel} · ${day}\n`;
|
|
465
466
|
try {
|
|
466
|
-
|
|
467
|
+
const nowPath = fs.existsSync(path.join(safeRoot, 'atris'))
|
|
468
|
+
? path.join(safeRoot, 'atris', 'now.md')
|
|
469
|
+
: path.join(safeRoot, 'now.md'); // pre-init workspaces keep the old spot
|
|
470
|
+
await fs.promises.appendFile(nowPath, line, 'utf8');
|
|
467
471
|
return { ok: true, line: line.trim() };
|
|
468
472
|
} catch (error) {
|
|
469
473
|
return { ok: false, error: String((error && error.message) || error) };
|
|
@@ -471,7 +475,6 @@ async function appendOrbChoice(root, label, when = new Date()) {
|
|
|
471
475
|
}
|
|
472
476
|
|
|
473
477
|
module.exports = {
|
|
474
|
-
buildOrbContext,
|
|
475
478
|
collectOrbContext,
|
|
476
479
|
appendOrbChoice,
|
|
477
480
|
};
|
package/lib/orb-scorecard.js
CHANGED
|
@@ -153,13 +153,7 @@ function prepareOutboundSendTextOrExit(channel, args = [], options = {}) {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
module.exports = {
|
|
156
|
-
OutboundArtifactGateError,
|
|
157
|
-
assertOutboundSendAllowed,
|
|
158
156
|
assertOutboundSendAllowedOrExit,
|
|
159
|
-
defaultGateOptions,
|
|
160
157
|
extractOutboundGateOptions,
|
|
161
|
-
parseOutboundSendArgs,
|
|
162
158
|
prepareOutboundSendTextOrExit,
|
|
163
|
-
readOutboundBodyFile,
|
|
164
|
-
shouldRunOutboundGate,
|
|
165
159
|
};
|
package/lib/permission-grants.js
CHANGED
|
@@ -277,17 +277,11 @@ async function syncGrants({ apiRequestJson, token, file, endpoint = GRANTS_SYNC_
|
|
|
277
277
|
|
|
278
278
|
module.exports = {
|
|
279
279
|
GRANTS_SCHEMA,
|
|
280
|
-
GRANTS_SYNC_ENDPOINT,
|
|
281
|
-
grantsFilePath,
|
|
282
|
-
parseArgv,
|
|
283
|
-
commandIsGrantable,
|
|
284
280
|
loadGrants,
|
|
285
281
|
saveGrants,
|
|
286
282
|
addGrant,
|
|
287
283
|
revokeGrant,
|
|
288
284
|
matchGrant,
|
|
289
285
|
recordUse,
|
|
290
|
-
normalizeRemoteGrant,
|
|
291
|
-
mergeRemoteGrants,
|
|
292
286
|
syncGrants,
|
|
293
287
|
};
|
package/lib/policy-lessons.js
CHANGED
|
@@ -320,12 +320,10 @@ function syncLessonsMd(root, mined) {
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
module.exports = {
|
|
323
|
-
AGENT_ACTOR_PATTERN,
|
|
324
323
|
VERIFY_COMMAND_PATTERN,
|
|
325
324
|
loadHistory,
|
|
326
325
|
mineProofPolicy,
|
|
327
326
|
policyHintsForProof,
|
|
328
|
-
policyLessonsPath,
|
|
329
327
|
readPolicyLessons,
|
|
330
328
|
writePolicyLessons,
|
|
331
329
|
syncLessonsMd,
|