atris 3.79.0 → 3.80.1
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 +6 -0
- package/atris/atris.md +66 -167
- package/atris/skills/security-audit/SKILL.md +77 -0
- package/atris/team/brainstormer/MEMBER.md +2 -2
- package/atris.md +66 -167
- package/bin/atris.js +6 -0
- package/commands/auth.js +2 -2
- package/commands/business.js +44 -1984
- package/commands/computer.js +165 -2412
- package/commands/member.js +189 -966
- package/commands/mission.js +229 -1409
- package/commands/pack.js +112 -1476
- package/commands/security-review.js +129 -0
- package/commands/site-deploy.js +5 -1
- package/commands/task.js +137 -1359
- package/lib/business-core.js +2022 -0
- package/lib/computer-core.js +2447 -0
- package/lib/engine-ask.js +1 -0
- package/lib/handoff-wake.js +8 -6
- package/lib/known-commands.js +1 -1
- package/lib/member-autoland.js +21 -2
- package/lib/member-board.js +12 -10
- package/lib/member-core.js +1014 -0
- package/lib/member-up.js +46 -3
- package/lib/mission-core.js +1559 -0
- package/lib/pack-core.js +1588 -0
- package/lib/security-audit-classes.js +318 -0
- package/lib/security-audit.js +1549 -0
- package/lib/task-core.js +1412 -0
- package/lib/task-decision.js +66 -0
- package/lib/task-explanation.js +20 -0
- package/lib/yes-lock.js +1 -1
- package/package.json +9 -2
- package/utils/auth.js +18 -4
package/lib/task-decision.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
// marker is needs-human (CLI-879); decision is the same hold under a clearer
|
|
6
6
|
// name. Autonomous pickers must refuse these; list renderers must show them.
|
|
7
7
|
|
|
8
|
+
const { decisionChoiceText } = require('./task-explanation');
|
|
9
|
+
|
|
8
10
|
const DECISION_HOLD_TAGS = new Set([
|
|
9
11
|
'needs-human',
|
|
10
12
|
'needshuman',
|
|
@@ -41,10 +43,74 @@ function decisionMarkerFor(task) {
|
|
|
41
43
|
return isDecisionTask(task) ? DECISION_MARKER : '';
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
function decisionRefFor(task) {
|
|
47
|
+
if (!task || typeof task !== 'object') return 'TASK';
|
|
48
|
+
const ref = task.display_id || task.legacy_ref || task.id || '';
|
|
49
|
+
const text = String(ref || '').trim();
|
|
50
|
+
if (!text) return 'TASK';
|
|
51
|
+
if (task.display_id || task.legacy_ref) return text;
|
|
52
|
+
return text.replace(/[^a-zA-Z0-9]/g, '').toUpperCase().slice(0, 8) || 'TASK';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function decisionShowCommand(task) {
|
|
56
|
+
return `atris task show ${decisionRefFor(task)}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function summarizeDecisionTask(task) {
|
|
60
|
+
const ref = decisionRefFor(task);
|
|
61
|
+
const title = String((task && task.title) || '').replace(/\s+/g, ' ').trim();
|
|
62
|
+
const choice = decisionChoiceText(task);
|
|
63
|
+
const command = `atris task show ${ref}`;
|
|
64
|
+
return {
|
|
65
|
+
id: (task && task.id) || null,
|
|
66
|
+
task_id: (task && task.id) || null,
|
|
67
|
+
ref,
|
|
68
|
+
display_id: (task && task.display_id) || ref,
|
|
69
|
+
title,
|
|
70
|
+
choice,
|
|
71
|
+
command,
|
|
72
|
+
show_command: command,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function summarizeSkippedDecisions(tasks = []) {
|
|
77
|
+
const list = (Array.isArray(tasks) ? tasks : [])
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
.map(summarizeDecisionTask);
|
|
80
|
+
const first = list[0] || null;
|
|
81
|
+
return {
|
|
82
|
+
reason: DECISION_REFUSE_REASON,
|
|
83
|
+
skipped_decision_count: list.length,
|
|
84
|
+
skipped_decision_refs: list.map((item) => item.ref),
|
|
85
|
+
skipped_decisions: list,
|
|
86
|
+
decisions: list,
|
|
87
|
+
choice: first ? first.choice : null,
|
|
88
|
+
command: first ? first.command : null,
|
|
89
|
+
show_command: first ? first.command : null,
|
|
90
|
+
next_command: first ? first.command : null,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function formatDecisionRefusalLines(tasks = []) {
|
|
95
|
+
const summary = summarizeSkippedDecisions(tasks);
|
|
96
|
+
const lines = [DECISION_REFUSE_REASON];
|
|
97
|
+
for (const item of summary.skipped_decisions) {
|
|
98
|
+
lines.push(` ${item.ref}: ${item.title}`);
|
|
99
|
+
lines.push(` choice: ${item.choice}`);
|
|
100
|
+
lines.push(` show: ${item.command}`);
|
|
101
|
+
}
|
|
102
|
+
if (summary.command) {
|
|
103
|
+
lines.push(`next: ${summary.command}`);
|
|
104
|
+
}
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
|
|
44
108
|
module.exports = {
|
|
45
109
|
DECISION_REFUSE_REASON,
|
|
46
110
|
taskTagTokens,
|
|
47
111
|
isDecisionHoldTag,
|
|
48
112
|
isDecisionTask,
|
|
49
113
|
decisionMarkerFor,
|
|
114
|
+
summarizeSkippedDecisions,
|
|
115
|
+
formatDecisionRefusalLines,
|
|
50
116
|
};
|
package/lib/task-explanation.js
CHANGED
|
@@ -213,6 +213,25 @@ function taskApprovalControls({
|
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
function decisionChoiceText(task) {
|
|
217
|
+
const metadata = task && task.metadata && typeof task.metadata === 'object' ? task.metadata : {};
|
|
218
|
+
const explicitChoice = cleanText(
|
|
219
|
+
(task && task.choice)
|
|
220
|
+
|| metadata.choice
|
|
221
|
+
|| metadata.decision
|
|
222
|
+
|| metadata.question
|
|
223
|
+
);
|
|
224
|
+
if (explicitChoice) return endSentence(plainText(explicitChoice));
|
|
225
|
+
const explicit = explicitExplanationFields(metadata);
|
|
226
|
+
if (explicit.what_changes) return endSentence(plainText(explicit.what_changes));
|
|
227
|
+
if (explicit.why_it_matters) return endSentence(plainText(explicit.why_it_matters));
|
|
228
|
+
const goal = cleanText(explanationGoalText(task));
|
|
229
|
+
if (goal) return endSentence(plainText(goal));
|
|
230
|
+
const title = cleanText(task && task.title);
|
|
231
|
+
if (title) return endSentence(plainText(title));
|
|
232
|
+
return 'Decide whether to approve this work, revise it, or remove the decision hold.';
|
|
233
|
+
}
|
|
234
|
+
|
|
216
235
|
function approvalLines(approval, { indent = '' } = {}) {
|
|
217
236
|
const lines = [`${indent}${approval.question}`];
|
|
218
237
|
if (approval.approve.enabled) lines.push(`${indent}Approve: ${approval.approve.command}`);
|
|
@@ -228,6 +247,7 @@ module.exports = {
|
|
|
228
247
|
explicitDoneLooksLike,
|
|
229
248
|
plainText,
|
|
230
249
|
taskExplanation,
|
|
250
|
+
decisionChoiceText,
|
|
231
251
|
explanationFieldsFromInput,
|
|
232
252
|
explanationLines,
|
|
233
253
|
explanationMarkdownLines,
|
package/lib/yes-lock.js
CHANGED
|
@@ -593,7 +593,7 @@ const ATRIS_INTERNAL = new Set([
|
|
|
593
593
|
'version', 'help', 'next', 'atris', 'clean', 'close', 'harvest', 'verify', 'recover', 'search', 'scout', 'skill', 'member', 'codex-goal', 'learn', 'lesson', 'taste', 'teach',
|
|
594
594
|
'experiments', 'bench', 'router', 'tree', 'receipt', 'proof', 'openclaw', 'pull', 'watch', 'live', 'align', 'terminal', 'computer', 'diff', 'youtube', 'x-search',
|
|
595
595
|
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'campaign', 'agents', 'probe', 'worktree', 'caretaker', 'aeo', 'slop', 'voice', 'strings', 'write',
|
|
596
|
-
'security-review', 'secure', 'theme', 'improve', 'study', 'rainmaker', 'xp', 'play', 'gm', 'game', 'recap', 'report', 'clarity', 'interview', 'moves', 'unknowns', 'avail',
|
|
596
|
+
'security-review', 'secure', 'sentinel', 'theme', 'improve', 'study', 'rainmaker', 'xp', 'play', 'gm', 'game', 'recap', 'report', 'clarity', 'interview', 'moves', 'unknowns', 'avail',
|
|
597
597
|
'scoreboard', 'sync-checkout', 'zen', 'ci', 'balance', 'usage', 'agent-client', 'transactions', 'hires', 'design', 'mcp', 'integrations', 'setup', 'clean-workspace', 'cw',
|
|
598
598
|
'browse', 'sleep', 'wake', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'fleet-report', 'loops', 'self-improve', 'compile', 'spaceship', 'truth', 'engine',
|
|
599
599
|
'engines', 'link', 'playbook', 'brief', 'inbox', 'friends', 'rsi',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atris",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.80.1",
|
|
4
4
|
"description": "you say what you want in plain words. atris builds it, checks it, and shows you proof.",
|
|
5
5
|
"mcpName": "io.github.atrislabs/atris",
|
|
6
6
|
"main": "bin/atris.js",
|
|
@@ -91,7 +91,14 @@
|
|
|
91
91
|
"developer-tools",
|
|
92
92
|
"cli",
|
|
93
93
|
"codebase-navigation",
|
|
94
|
-
"ai-agents"
|
|
94
|
+
"ai-agents",
|
|
95
|
+
"agent-memory",
|
|
96
|
+
"ai-memory",
|
|
97
|
+
"llm-memory",
|
|
98
|
+
"project-memory",
|
|
99
|
+
"context-graph",
|
|
100
|
+
"knowledge-graph",
|
|
101
|
+
"memory"
|
|
95
102
|
],
|
|
96
103
|
"author": "Keshav Rao (atrislabs)",
|
|
97
104
|
"license": "MIT",
|
package/utils/auth.js
CHANGED
|
@@ -40,9 +40,11 @@ let inputIndex = 0;
|
|
|
40
40
|
/**
|
|
41
41
|
* Prompt the user for input, handling both TTY and piped input.
|
|
42
42
|
* @param {string} question - Prompt text to display
|
|
43
|
+
* @param {{secret?: boolean}} [opts] - secret: never print the answer back
|
|
43
44
|
* @returns {Promise<string>} User's input
|
|
44
45
|
*/
|
|
45
|
-
function promptUser(question) {
|
|
46
|
+
function promptUser(question, opts = {}) {
|
|
47
|
+
const shown = (answer) => (opts.secret ? '' : answer);
|
|
46
48
|
// If stdin is not a TTY (piped input), read all lines upfront
|
|
47
49
|
if (!process.stdin.isTTY && inputLines.length === 0 && !sharedRl) {
|
|
48
50
|
return new Promise((resolve) => {
|
|
@@ -57,7 +59,7 @@ function promptUser(question) {
|
|
|
57
59
|
inputLines = data.trim().split('\n');
|
|
58
60
|
process.stdout.write(question);
|
|
59
61
|
const answer = inputLines[inputIndex++] || '';
|
|
60
|
-
console.log(answer);
|
|
62
|
+
console.log(shown(answer));
|
|
61
63
|
resolve(answer.trim());
|
|
62
64
|
});
|
|
63
65
|
process.stdin.resume();
|
|
@@ -69,22 +71,34 @@ function promptUser(question) {
|
|
|
69
71
|
return new Promise((resolve) => {
|
|
70
72
|
process.stdout.write(question);
|
|
71
73
|
const answer = inputLines[inputIndex++] || '';
|
|
72
|
-
console.log(answer);
|
|
74
|
+
console.log(shown(answer));
|
|
73
75
|
resolve(answer.trim());
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
// Interactive TTY mode - create readline per prompt
|
|
80
|
+
// A secret typed at a terminal must stay hidden even when stdout is a file:
|
|
81
|
+
// terminal mode turns off the terminal's own echo, and the prompt goes to
|
|
82
|
+
// whichever stream is still the screen.
|
|
83
|
+
const secretOut = opts.secret && !process.stdout.isTTY && process.stderr.isTTY ? process.stderr : process.stdout;
|
|
78
84
|
const rl = readline.createInterface({
|
|
79
85
|
input: process.stdin,
|
|
80
|
-
output:
|
|
86
|
+
output: secretOut,
|
|
87
|
+
...(opts.secret ? { terminal: Boolean(process.stdin.isTTY) } : {}),
|
|
81
88
|
});
|
|
82
89
|
|
|
90
|
+
// Secret answers: let the prompt through, then swallow the typed echo.
|
|
91
|
+
let muted = false;
|
|
92
|
+
if (opts.secret) {
|
|
93
|
+
rl._writeToOutput = (text) => { if (!muted) rl.output.write(text); };
|
|
94
|
+
}
|
|
83
95
|
return new Promise((resolve) => {
|
|
84
96
|
rl.question(question, (answer) => {
|
|
97
|
+
if (muted) rl.output.write('\n');
|
|
85
98
|
rl.close();
|
|
86
99
|
resolve(answer.trim());
|
|
87
100
|
});
|
|
101
|
+
muted = Boolean(opts.secret);
|
|
88
102
|
});
|
|
89
103
|
}
|
|
90
104
|
|