atris 3.53.0 → 3.56.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/FOR_AGENTS.md +7 -0
- package/README.md +1 -1
- package/atris/policies/ANTISLOP.md +2 -1
- package/atris/skills/copy-editor/SKILL.md +2 -1
- package/atris/skills/design/SKILL.md +1 -1
- package/atris/skills/x-search/SKILL.md +24 -22
- package/atris/skills/youtube/SKILL.md +82 -33
- package/atris/team/_template/SOUL.md +40 -0
- package/atris/team/validator/MEMBER.md +1 -2
- package/bin/atris +21 -0
- package/bin/atris.js +563 -373
- package/commands/api-key.js +170 -0
- package/commands/auth.js +453 -43
- package/commands/autoland.js +3 -1
- package/commands/autopilot-front.js +58 -11
- package/commands/avail.js +5 -4
- package/commands/balance.js +55 -0
- package/commands/bench.js +29 -1
- package/commands/brain.js +63 -12
- package/commands/brainstorm.js +18 -0
- package/commands/business.js +149 -1
- package/commands/chat-scan.js +17 -4
- package/commands/close.js +5 -1
- package/commands/doctor.js +174 -0
- package/commands/dream.js +7 -0
- package/commands/drill.js +34 -2
- package/commands/engine.js +47 -35
- package/commands/errors.js +58 -8
- package/commands/experiments.js +14 -0
- package/commands/feedback.js +61 -2
- package/commands/fleet-report.js +27 -7
- package/commands/fleet.js +98 -11
- package/commands/founder.js +60 -21
- package/commands/human-missions.js +79 -4
- package/commands/improve.js +54 -4
- package/commands/init.js +68 -92
- package/commands/install.js +40 -0
- package/commands/integrations.js +565 -30
- package/commands/interview.js +8 -0
- package/commands/land.js +48 -17
- package/commands/learn.js +29 -4
- package/commands/log.js +51 -0
- package/commands/member.js +68 -10
- package/commands/mission.js +287 -50
- package/commands/now.js +15 -3
- package/commands/orb.js +97 -2
- package/commands/pack.js +83 -9
- package/commands/playbook.js +381 -0
- package/commands/plugin.js +16 -0
- package/commands/radar.js +31 -7
- package/commands/recap.js +128 -21
- package/commands/release.js +102 -2
- package/commands/review.js +5 -10
- package/commands/revisions.js +55 -0
- package/commands/run-front.js +12 -4
- package/commands/scout.js +12 -1
- package/commands/search.js +123 -28
- package/commands/sign.js +2 -2
- package/commands/signup.js +12 -3
- package/commands/site-deploy.js +17 -4
- package/commands/site.js +2 -2
- package/commands/skill-eval.js +289 -0
- package/commands/skill.js +56 -6
- package/commands/social.js +603 -0
- package/commands/spaceship.js +69 -6
- package/commands/stream.js +8 -1
- package/commands/study.js +32 -19
- package/commands/sync.js +28 -22
- package/commands/task.js +435 -60
- package/commands/teach.js +72 -63
- package/commands/terminal.js +25 -9
- package/commands/topup.js +88 -0
- package/commands/truth.js +52 -6
- package/commands/usage.js +91 -0
- package/commands/verify.js +3 -2
- package/commands/version.js +3 -1
- package/commands/voice.js +5 -1
- package/commands/who.js +69 -11
- package/commands/wiki.js +7 -4
- package/commands/wish.js +76 -5
- package/commands/workflow.js +327 -145
- package/commands/worktree.js +1 -0
- package/commands/write.js +5 -0
- package/commands/x-search.js +340 -0
- package/commands/xp.js +5 -1
- package/commands/youtube.js +551 -25
- package/lib/account-bound.js +47 -0
- package/lib/auto-accept-certified.js +8 -1
- package/lib/auto-lessons.js +186 -0
- package/lib/autoland.js +4 -2
- package/lib/chat-log-scan.js +7 -4
- package/lib/cli-json.js +77 -0
- package/lib/cli-scope.js +26 -0
- package/lib/codex-flight.js +1 -0
- package/lib/conductor-artifacts.js +1 -1
- package/lib/context-gatherer.js +11 -0
- package/lib/developer-api.js +116 -0
- package/lib/feedback-triage.js +274 -0
- package/lib/first-minute.js +398 -0
- package/lib/fleet.js +115 -34
- package/lib/functional-owner.js +22 -0
- package/lib/known-commands.js +31 -5
- package/lib/member-scaffold.js +197 -0
- package/lib/mission-root.js +4 -2
- package/lib/noninteractive.js +88 -0
- package/lib/policy-lessons.js +4 -1
- package/lib/revision-metric.js +279 -0
- package/lib/scratch-root.js +48 -0
- package/lib/skill-eval-gate.js +249 -0
- package/lib/task-db.js +4 -0
- package/lib/task-proof.js +69 -8
- package/lib/verifier-quality.js +69 -0
- package/lib/wish-audit.js +2 -2
- package/lib/wish-delegate.js +10 -1
- package/lib/workspace-scaffold.js +270 -0
- package/package.json +3 -2
- package/scripts/det/checklist-score.js +191 -0
- package/scripts/det/ytsearch +31 -0
- package/utils/update-check.js +15 -0
package/commands/task.js
CHANGED
|
@@ -9,7 +9,17 @@ const { execSync } = require('node:child_process');
|
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const os = require('os');
|
|
11
11
|
const { hasFlag } = require('../lib/arg-parser');
|
|
12
|
-
const {
|
|
12
|
+
const { argsWantHelp } = require('../lib/noninteractive');
|
|
13
|
+
const {
|
|
14
|
+
compactErrorPayload,
|
|
15
|
+
compactSuccessPayload,
|
|
16
|
+
printCliJson,
|
|
17
|
+
} = require('../lib/cli-json');
|
|
18
|
+
const {
|
|
19
|
+
taskProofState,
|
|
20
|
+
LOCAL_SUCCESS_PROOF_EXAMPLE,
|
|
21
|
+
unrunNamedProofCommandIssue,
|
|
22
|
+
} = require('../lib/task-proof');
|
|
13
23
|
const {
|
|
14
24
|
candidatePolicyGate,
|
|
15
25
|
evaluateAutoAccept,
|
|
@@ -50,6 +60,7 @@ const {
|
|
|
50
60
|
decisionMarkerFor,
|
|
51
61
|
DECISION_REFUSE_REASON,
|
|
52
62
|
} = require('../lib/task-decision');
|
|
63
|
+
const { buildFirstMinute, deskNextCommand, personName, pickNext, speakFirstMinute, taskCommand, taskNextCommand } = require('../lib/first-minute');
|
|
53
64
|
|
|
54
65
|
const DEFAULT_OWNER = process.env.ATRIS_AGENT_ID
|
|
55
66
|
|| process.env.USER
|
|
@@ -151,11 +162,12 @@ atris task - durable local task state (SQLite, gitignored)
|
|
|
151
162
|
atris task ready <id> --verify
|
|
152
163
|
atris autoland tick # second check runs, task lands
|
|
153
164
|
|
|
154
|
-
atris task
|
|
165
|
+
atris task Same two-line next as bare atris
|
|
166
|
+
atris task desk [--all] Show the full task desk
|
|
155
167
|
atris task new "<title>" [--what-changes "..."] [--why-it-matters "..."] [--done-looks-like "..."] [--verify <cmd>]
|
|
156
168
|
Create a task with a plain explanation; omitted fields get honest defaults
|
|
157
169
|
atris task next [--tag <tag>] [--create-next]
|
|
158
|
-
|
|
170
|
+
Same next command as bare atris and the task desk; --create-next still seeds Endgame fallback
|
|
159
171
|
atris task continue-work <id> Create/reuse a certified Review follow-up task
|
|
160
172
|
atris task say <id> "<message>" Add context to a task
|
|
161
173
|
atris task chat <id> "<message>" [--goal "..."] Refine a task chat + working goal
|
|
@@ -163,7 +175,8 @@ atris task - durable local task state (SQLite, gitignored)
|
|
|
163
175
|
Agent proof ready; native goal can complete
|
|
164
176
|
atris task ready <id> --verify "<cmd>" --result "<sentence>"
|
|
165
177
|
Run <cmd>; only ready if it exits 0 (executed proof)
|
|
166
|
-
Writes atris/runs/ receipt (pass or fail)
|
|
178
|
+
Writes atris/runs/ receipt (pass or fail); that local pass is enough proof
|
|
179
|
+
Optional CI URL only with --proof-url and --i-fetched
|
|
167
180
|
atris task receipt <id> --verify "<cmd>" Run <cmd> and write an atris/runs/ receipt without going to ready
|
|
168
181
|
atris task plan-preview "<purpose>" [--tag <tag>] [--owner <member>] [--task <id>]
|
|
169
182
|
Show the plain Plan before work starts
|
|
@@ -440,12 +453,18 @@ function jsonModeActive() {
|
|
|
440
453
|
|
|
441
454
|
function failTask(label, reason, detail, exitCode = 2) {
|
|
442
455
|
if (jsonModeActive()) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
456
|
+
printCliJson(
|
|
457
|
+
{
|
|
458
|
+
ok: false,
|
|
459
|
+
command: label,
|
|
460
|
+
reason,
|
|
461
|
+
detail: detail || null,
|
|
462
|
+
selected_ref: null,
|
|
463
|
+
next_command: null,
|
|
464
|
+
},
|
|
465
|
+
compactErrorPayload({ reason, detail: detail || null }),
|
|
466
|
+
process.argv.slice(2),
|
|
467
|
+
);
|
|
449
468
|
} else {
|
|
450
469
|
console.error(detail || `${label}: ${reason}`);
|
|
451
470
|
}
|
|
@@ -472,8 +491,8 @@ function proofFlagValue(args) {
|
|
|
472
491
|
return typeof proof === 'string' ? proof.trim() : '';
|
|
473
492
|
}
|
|
474
493
|
|
|
475
|
-
function resultSentenceIssue(value) {
|
|
476
|
-
const check = explainResult(value);
|
|
494
|
+
function resultSentenceIssue(value, { allowCommandMention = false } = {}) {
|
|
495
|
+
const check = explainResult(value, { allowCommandMention });
|
|
477
496
|
return check.ok ? null : check.reason;
|
|
478
497
|
}
|
|
479
498
|
|
|
@@ -481,13 +500,35 @@ function readyResultDetail(reason) {
|
|
|
481
500
|
return reason ? `${READY_RESULT_TEACHING}\n${reason}` : READY_RESULT_TEACHING;
|
|
482
501
|
}
|
|
483
502
|
|
|
484
|
-
function requireResultSentence(label, value, { ready = false } = {}) {
|
|
485
|
-
const issue = resultSentenceIssue(value);
|
|
503
|
+
function requireResultSentence(label, value, { ready = false, allowCommandMention = false } = {}) {
|
|
504
|
+
const issue = resultSentenceIssue(value, { allowCommandMention });
|
|
486
505
|
if (!issue) return String(value || '').replace(/\s+/g, ' ').trim();
|
|
487
506
|
const detail = ready ? readyResultDetail(issue) : issue;
|
|
488
507
|
failTask(label, 'weak_result', detail);
|
|
489
508
|
}
|
|
490
509
|
|
|
510
|
+
function weakProofDetail(issue) {
|
|
511
|
+
return `meaningful proof required: ${issue}\n${LOCAL_SUCCESS_PROOF_EXAMPLE}`;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function requireMeaningfulTaskProof(label, proof, { required = true } = {}) {
|
|
515
|
+
const issue = meaningfulTaskProofIssue(proof, { required });
|
|
516
|
+
if (issue) failTask(label, 'weak_proof', weakProofDetail(issue));
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function requireRanNamedProofCommand(label, proof, ranCommand = '') {
|
|
520
|
+
const issue = unrunNamedProofCommandIssue(proof, ranCommand);
|
|
521
|
+
if (issue) failTask(label, issue.reason, issue.detail);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function sendProofIssue(res, proof, issue) {
|
|
525
|
+
return sendJson(res, 400, {
|
|
526
|
+
ok: false,
|
|
527
|
+
reason: String(proof || '').trim() ? 'weak_proof' : 'proof_required',
|
|
528
|
+
detail: weakProofDetail(issue),
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
491
532
|
function textFlag(args, names) {
|
|
492
533
|
for (const name of names) {
|
|
493
534
|
const value = flag(args, name);
|
|
@@ -658,19 +699,6 @@ function missionXpProofBoundaryEvaluation(task, proofOverride = null) {
|
|
|
658
699
|
};
|
|
659
700
|
}
|
|
660
701
|
|
|
661
|
-
function requireMeaningfulTaskProof(label, proof, { required = true } = {}) {
|
|
662
|
-
const issue = meaningfulTaskProofIssue(proof, { required });
|
|
663
|
-
if (issue) failTask(label, 'weak_proof', `meaningful proof required: ${issue}`);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
function sendProofIssue(res, proof, issue) {
|
|
667
|
-
return sendJson(res, 400, {
|
|
668
|
-
ok: false,
|
|
669
|
-
reason: String(proof || '').trim() ? 'weak_proof' : 'proof_required',
|
|
670
|
-
detail: `meaningful proof required: ${issue}`,
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
|
|
674
702
|
function positional(args) {
|
|
675
703
|
return args.filter((a, i) => {
|
|
676
704
|
if (a.startsWith('--')) return false;
|
|
@@ -6134,10 +6162,27 @@ function renderTaskDesk(rows, refRows = rows) {
|
|
|
6134
6162
|
if (active.length === 0) console.log('clear no active tasks');
|
|
6135
6163
|
console.log('');
|
|
6136
6164
|
console.log(`active ${active.length} / done ${done.length}`);
|
|
6137
|
-
console.log(
|
|
6165
|
+
console.log(`next: ${deskNextCommand(displayRows, personName())}`);
|
|
6138
6166
|
}
|
|
6139
6167
|
|
|
6140
6168
|
function cmdAdd(args) {
|
|
6169
|
+
const root = process.cwd();
|
|
6170
|
+
// Empty folder talks like bare atris. A leftover title is not a
|
|
6171
|
+
// task desk. After init, a title still files.
|
|
6172
|
+
if (isUninitializedTaskFolder(root)) {
|
|
6173
|
+
if (wantsJson(args)) {
|
|
6174
|
+
printJson({
|
|
6175
|
+
ok: true,
|
|
6176
|
+
action: 'init',
|
|
6177
|
+
command: 'atris init --minimal',
|
|
6178
|
+
task_id: null,
|
|
6179
|
+
projection_path: null,
|
|
6180
|
+
task: null,
|
|
6181
|
+
});
|
|
6182
|
+
return;
|
|
6183
|
+
}
|
|
6184
|
+
return speakFirstMinute({ root, fresh: true });
|
|
6185
|
+
}
|
|
6141
6186
|
const pos = positional(args);
|
|
6142
6187
|
const title = pos.join(' ').trim();
|
|
6143
6188
|
if (!title) {
|
|
@@ -6446,6 +6491,15 @@ function cmdDay(args) {
|
|
|
6446
6491
|
console.log('add: atris task delegate "..." --to task-planner --tag tasks');
|
|
6447
6492
|
}
|
|
6448
6493
|
|
|
6494
|
+
function cmdFirstMinute() {
|
|
6495
|
+
const root = process.cwd();
|
|
6496
|
+
const screen = buildFirstMinute({
|
|
6497
|
+
root,
|
|
6498
|
+
fresh: !fs.existsSync(path.join(root, 'atris')),
|
|
6499
|
+
});
|
|
6500
|
+
console.log(screen.text);
|
|
6501
|
+
}
|
|
6502
|
+
|
|
6449
6503
|
function cmdHome(args) {
|
|
6450
6504
|
const all = hasFlag(args, '--all');
|
|
6451
6505
|
const everywhere = taskScopeEverywhere(args);
|
|
@@ -6771,7 +6825,108 @@ function createEndgameSeedTask(taskDb, db, seed, owner) {
|
|
|
6771
6825
|
};
|
|
6772
6826
|
}
|
|
6773
6827
|
|
|
6828
|
+
function nextActionFromCommand(command) {
|
|
6829
|
+
const match = String(command || '').trim().match(/^atris (?:task|mission) (\S+)/);
|
|
6830
|
+
const verb = match ? match[1] : '';
|
|
6831
|
+
if (!verb || verb === 'new') return 'none';
|
|
6832
|
+
return verb;
|
|
6833
|
+
}
|
|
6834
|
+
|
|
6835
|
+
function cmdNextTruth(args) {
|
|
6836
|
+
const owner = flag(args, '--as') || personName() || DEFAULT_OWNER;
|
|
6837
|
+
const scope = taskQueueScopeFromArgs(args);
|
|
6838
|
+
const taskDb = getTaskDb();
|
|
6839
|
+
const db = taskDb.open();
|
|
6840
|
+
const workspaceRoot = taskDb.workspaceRoot();
|
|
6841
|
+
const rows = taskDb.listTasks(db, { workspaceRoot, limit: 500 });
|
|
6842
|
+
const existingProj = readProjectionFile(workspaceRoot);
|
|
6843
|
+
let projection;
|
|
6844
|
+
let outPath;
|
|
6845
|
+
if (rows.length === 0 && existingProj && Array.isArray(existingProj.tasks) && existingProj.tasks.length > 0) {
|
|
6846
|
+
projection = existingProj;
|
|
6847
|
+
outPath = path.resolve(path.join(workspaceRoot || '.', '.atris', 'state', 'tasks.projection.json'));
|
|
6848
|
+
} else {
|
|
6849
|
+
const written = writeDefaultProjection(taskDb, db);
|
|
6850
|
+
projection = written.projection;
|
|
6851
|
+
outPath = written.outPath;
|
|
6852
|
+
}
|
|
6853
|
+
const scoped = filterTasksByScope(projection.tasks || [], scope);
|
|
6854
|
+
const openDecisions = scoped.filter((task) => task && isDecisionTask(task) && task.status === 'open');
|
|
6855
|
+
const actionable = scoped.filter((task) => task && !isDecisionTask(task));
|
|
6856
|
+
const picked = pickNext({ tasks: actionable, person: owner });
|
|
6857
|
+
const command = picked.task ? (picked.command || taskCommand(picked.task, owner)) : taskNextCommand(actionable, owner);
|
|
6858
|
+
const task = picked.task || null;
|
|
6859
|
+
|
|
6860
|
+
if (!task && openDecisions.length) {
|
|
6861
|
+
if (wantsJson(args)) {
|
|
6862
|
+
printJson({
|
|
6863
|
+
ok: false,
|
|
6864
|
+
action: 'refused',
|
|
6865
|
+
reason: DECISION_REFUSE_REASON,
|
|
6866
|
+
skipped_decision_count: openDecisions.length,
|
|
6867
|
+
owner: String(owner),
|
|
6868
|
+
scope: normalizeTaskQueueScope(scope),
|
|
6869
|
+
projection_path: outPath,
|
|
6870
|
+
});
|
|
6871
|
+
process.exit(1);
|
|
6872
|
+
}
|
|
6873
|
+
console.error(DECISION_REFUSE_REASON);
|
|
6874
|
+
process.exit(1);
|
|
6875
|
+
}
|
|
6876
|
+
|
|
6877
|
+
if (wantsJson(args)) {
|
|
6878
|
+
printJson({
|
|
6879
|
+
ok: true,
|
|
6880
|
+
action: nextActionFromCommand(command),
|
|
6881
|
+
command,
|
|
6882
|
+
task_id: task ? task.id : null,
|
|
6883
|
+
owner: String(owner),
|
|
6884
|
+
scope: normalizeTaskQueueScope(scope),
|
|
6885
|
+
projection_path: outPath,
|
|
6886
|
+
task: task ? compactTaskFromProjection(projection, task.id) : null,
|
|
6887
|
+
});
|
|
6888
|
+
return;
|
|
6889
|
+
}
|
|
6890
|
+
|
|
6891
|
+
if (!task) {
|
|
6892
|
+
console.log(noOpenTasksMessage(scope));
|
|
6893
|
+
console.log(`next: ${command}`);
|
|
6894
|
+
return;
|
|
6895
|
+
}
|
|
6896
|
+
console.log(`next: ${command}`);
|
|
6897
|
+
}
|
|
6898
|
+
|
|
6899
|
+
function isUninitializedTaskFolder(cwd = process.cwd()) {
|
|
6900
|
+
const workspace = getTaskDb().workspaceRoot(cwd);
|
|
6901
|
+
if (fs.existsSync(path.join(workspace, 'atris'))) return false;
|
|
6902
|
+
const existing = readProjectionFile(workspace);
|
|
6903
|
+
return !(existing && Array.isArray(existing.tasks) && existing.tasks.length > 0);
|
|
6904
|
+
}
|
|
6905
|
+
|
|
6774
6906
|
function cmdNext(args) {
|
|
6907
|
+
const root = process.cwd();
|
|
6908
|
+
// Empty folder talks like bare atris. Walk up like the task db so a
|
|
6909
|
+
// project subdir stays in the room; stop before inheriting /tmp.
|
|
6910
|
+
// A leftover projection with live tasks still names that work.
|
|
6911
|
+
if (isUninitializedTaskFolder(root)) {
|
|
6912
|
+
if (wantsJson(args)) {
|
|
6913
|
+
printJson({
|
|
6914
|
+
ok: true,
|
|
6915
|
+
action: 'init',
|
|
6916
|
+
command: 'atris init --minimal',
|
|
6917
|
+
task_id: null,
|
|
6918
|
+
owner: String(flag(args, '--as') || personName() || DEFAULT_OWNER),
|
|
6919
|
+
scope: normalizeTaskQueueScope(taskQueueScopeFromArgs(args)),
|
|
6920
|
+
projection_path: null,
|
|
6921
|
+
task: null,
|
|
6922
|
+
});
|
|
6923
|
+
return;
|
|
6924
|
+
}
|
|
6925
|
+
const screen = buildFirstMinute({ root, fresh: true });
|
|
6926
|
+
console.log(screen.text);
|
|
6927
|
+
return;
|
|
6928
|
+
}
|
|
6929
|
+
if (!hasFlag(args, '--create-next')) return cmdNextTruth(args);
|
|
6775
6930
|
const owner = flag(args, '--as') || DEFAULT_OWNER;
|
|
6776
6931
|
const scope = taskQueueScopeFromArgs(args);
|
|
6777
6932
|
const scoped = !taskQueueScopeIsEmpty(scope);
|
|
@@ -8637,7 +8792,7 @@ function taskStepError(reason, detail, { status = 409, exitCode = 1, page = null
|
|
|
8637
8792
|
}
|
|
8638
8793
|
|
|
8639
8794
|
function taskStepStatusForReason(reason) {
|
|
8640
|
-
if (['goal_required', 'exit_required', 'proof_needed_required', 'first_move_required', 'proof_required', 'weak_proof', 'invalid_reward'].includes(reason)) {
|
|
8795
|
+
if (['goal_required', 'exit_required', 'proof_needed_required', 'first_move_required', 'proof_required', 'weak_proof', 'proof_command_not_run', 'invalid_reward'].includes(reason)) {
|
|
8641
8796
|
return 400;
|
|
8642
8797
|
}
|
|
8643
8798
|
if (reason === 'not_found') return 404;
|
|
@@ -8848,7 +9003,11 @@ function runTaskStep(taskDb, db, taskId, options = {}) {
|
|
|
8848
9003
|
const proof = String(options.proof || '').trim();
|
|
8849
9004
|
const proofIssue = meaningfulTaskProofIssue(proof);
|
|
8850
9005
|
if (proofIssue) {
|
|
8851
|
-
throw taskStepError(proof ? 'weak_proof' : 'proof_required',
|
|
9006
|
+
throw taskStepError(proof ? 'weak_proof' : 'proof_required', weakProofDetail(proofIssue), { status: 400, exitCode: 2, page: actionPage });
|
|
9007
|
+
}
|
|
9008
|
+
const unrunIssue = unrunNamedProofCommandIssue(proof, '');
|
|
9009
|
+
if (unrunIssue) {
|
|
9010
|
+
throw taskStepError(unrunIssue.reason, unrunIssue.detail, { status: 400, exitCode: 2, page: actionPage });
|
|
8852
9011
|
}
|
|
8853
9012
|
const missionXpIssue = missionXpEndToEndProofIssue(task, proof, task.workspace_root || process.cwd());
|
|
8854
9013
|
if (missionXpIssue) {
|
|
@@ -8895,7 +9054,11 @@ function runTaskStep(taskDb, db, taskId, options = {}) {
|
|
|
8895
9054
|
const proof = String(options.proof || '').trim();
|
|
8896
9055
|
const proofIssue = meaningfulTaskProofIssue(proof);
|
|
8897
9056
|
if (proofIssue) {
|
|
8898
|
-
throw taskStepError(proof ? 'weak_proof' : 'proof_required',
|
|
9057
|
+
throw taskStepError(proof ? 'weak_proof' : 'proof_required', weakProofDetail(proofIssue), { status: 400, exitCode: 2, page: actionPage });
|
|
9058
|
+
}
|
|
9059
|
+
const unrunIssue = unrunNamedProofCommandIssue(proof, '');
|
|
9060
|
+
if (unrunIssue) {
|
|
9061
|
+
throw taskStepError(unrunIssue.reason, unrunIssue.detail, { status: 400, exitCode: 2, page: actionPage });
|
|
8899
9062
|
}
|
|
8900
9063
|
const parsedReward = parseStepReviewReward(options.reward);
|
|
8901
9064
|
if (!parsedReward.ok) {
|
|
@@ -9127,24 +9290,51 @@ function cmdCurrentStep(args) {
|
|
|
9127
9290
|
} catch (error) {
|
|
9128
9291
|
const errorCurrent = error.current || null;
|
|
9129
9292
|
if (wantsJson(args)) {
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9293
|
+
const selectedRef = errorCurrent ? errorCurrent.selected_ref : null;
|
|
9294
|
+
const nextCommand = error.page?.stage?.next_action?.command
|
|
9295
|
+
|| (errorCurrent && errorCurrent.next && errorCurrent.next.command)
|
|
9296
|
+
|| null;
|
|
9297
|
+
printCliJson(
|
|
9298
|
+
{
|
|
9299
|
+
ok: false,
|
|
9300
|
+
action: 'current_step',
|
|
9301
|
+
reason: error.reason || 'step_failed',
|
|
9302
|
+
detail: error.message,
|
|
9303
|
+
selected_task_id: errorCurrent ? errorCurrent.selected_task_id : null,
|
|
9304
|
+
selected_ref: selectedRef,
|
|
9305
|
+
selected_next_key: selectedNextKeyFromCurrent(errorCurrent),
|
|
9306
|
+
next_command: nextCommand,
|
|
9307
|
+
current: errorCurrent,
|
|
9308
|
+
page: error.page || null,
|
|
9309
|
+
},
|
|
9310
|
+
compactErrorPayload({
|
|
9311
|
+
reason: error.reason || 'step_failed',
|
|
9312
|
+
detail: error.message,
|
|
9313
|
+
selected_ref: selectedRef,
|
|
9314
|
+
next_command: nextCommand,
|
|
9315
|
+
}),
|
|
9316
|
+
args,
|
|
9317
|
+
);
|
|
9141
9318
|
} else {
|
|
9142
9319
|
console.error(error.message || 'atris task current-step failed');
|
|
9143
9320
|
}
|
|
9144
9321
|
process.exit(error.exitCode || 1);
|
|
9145
9322
|
}
|
|
9146
9323
|
if (wantsJson(args)) {
|
|
9147
|
-
|
|
9324
|
+
const nextCommand = result.page?.stage?.next_action?.command || null;
|
|
9325
|
+
printCliJson(
|
|
9326
|
+
result,
|
|
9327
|
+
compactSuccessPayload({
|
|
9328
|
+
action: 'current_step',
|
|
9329
|
+
ids: {
|
|
9330
|
+
selected_task_id: result.selected_task_id || null,
|
|
9331
|
+
selected_ref: result.selected_ref || null,
|
|
9332
|
+
step_action: result.step && result.step.step_action ? result.step.step_action : null,
|
|
9333
|
+
},
|
|
9334
|
+
next_command: nextCommand,
|
|
9335
|
+
}),
|
|
9336
|
+
args,
|
|
9337
|
+
);
|
|
9148
9338
|
return;
|
|
9149
9339
|
}
|
|
9150
9340
|
console.log(`current-step ${taskRef(result.task)} -> ${result.step.step_action}`);
|
|
@@ -9610,14 +9800,38 @@ function cmdReady(args) {
|
|
|
9610
9800
|
console.error('atris task ready: id required');
|
|
9611
9801
|
process.exit(2);
|
|
9612
9802
|
}
|
|
9613
|
-
// Two ways to prove: --proof "<note>" (claimed, pattern-checked
|
|
9614
|
-
// --verify "<command>" which actually RUNS the command and gates ready on exit 0
|
|
9615
|
-
//
|
|
9803
|
+
// Two ways to prove: --proof "<note>" (claimed, pattern-checked) or
|
|
9804
|
+
// --verify "<command>" which actually RUNS the command and gates ready on exit 0.
|
|
9805
|
+
// If --proof names npm test, node --test, or git diff --check, this process
|
|
9806
|
+
// must have run that command. A sentence that names one of those is a lie.
|
|
9616
9807
|
const proofFlag = flag(args, '--proof');
|
|
9617
9808
|
const verifyFlag = flag(args, '--verify');
|
|
9618
|
-
const
|
|
9809
|
+
const proofUrl = textFlag(args, ['--proof-url']);
|
|
9810
|
+
const iFetched = hasFlag(args, '--i-fetched');
|
|
9811
|
+
if (proofUrl && !iFetched) {
|
|
9812
|
+
failTask(
|
|
9813
|
+
'atris task ready',
|
|
9814
|
+
'unfetched_proof_url',
|
|
9815
|
+
'CI run URLs only count after atris fetches them, or with --proof-url and --i-fetched',
|
|
9816
|
+
);
|
|
9817
|
+
}
|
|
9818
|
+
if (iFetched && !proofUrl && !(typeof proofFlag === 'string' && /https?:\/\/github[.]com\//i.test(proofFlag))) {
|
|
9819
|
+
failTask(
|
|
9820
|
+
'atris task ready',
|
|
9821
|
+
'proof_url_required',
|
|
9822
|
+
'--i-fetched requires --proof-url <actions-run-url> (or a URL inside --proof)',
|
|
9823
|
+
);
|
|
9824
|
+
}
|
|
9619
9825
|
const usedVerify = typeof verifyFlag === 'string' ? verifyFlag.trim() : '';
|
|
9826
|
+
const resultSentence = requireResultSentence('atris task ready', textFlag(args, ['--result']), {
|
|
9827
|
+
ready: true,
|
|
9828
|
+
allowCommandMention: Boolean(usedVerify),
|
|
9829
|
+
});
|
|
9620
9830
|
let proof = typeof proofFlag === 'string' ? proofFlag : '';
|
|
9831
|
+
if (proofUrl && iFetched) {
|
|
9832
|
+
const attested = `[i-fetched] ${proofUrl}`;
|
|
9833
|
+
proof = proof.trim() ? `${proof.trim()} ${attested}` : attested;
|
|
9834
|
+
}
|
|
9621
9835
|
const verifyAutoCertifyAllowed = !usedVerify || isAutoCertifyVerifyCommandAllowed(verifyFlag);
|
|
9622
9836
|
if (usedVerify) {
|
|
9623
9837
|
// Run the verifier once and write a receipt (pass or fail) so the review
|
|
@@ -9638,6 +9852,15 @@ function cmdReady(args) {
|
|
|
9638
9852
|
// this codebase fails there, and one that passes anywhere passes there too.
|
|
9639
9853
|
if (!hasFlag(args, '--no-falsify-check')) {
|
|
9640
9854
|
const { probeVerifierCanFail } = require('../lib/falsifier-probe');
|
|
9855
|
+
const { classifyVerifier } = require('../lib/verifier-quality');
|
|
9856
|
+
const quality = classifyVerifier(verifyFlag);
|
|
9857
|
+
if (!quality.ok) {
|
|
9858
|
+
console.error(`atris task ready: weak verifier — ${quality.reason}`);
|
|
9859
|
+
console.error(` command: ${verifyFlag}`);
|
|
9860
|
+
console.error(' allowlisted examples: node --test, npm test, git diff --check, node --check, rg <symbol>');
|
|
9861
|
+
console.error(' or pass --no-falsify-check to accept anyway.');
|
|
9862
|
+
process.exit(1);
|
|
9863
|
+
}
|
|
9641
9864
|
const probe = probeVerifierCanFail({ command: verifyFlag });
|
|
9642
9865
|
if (probe.probed && probe.canFail === false) {
|
|
9643
9866
|
console.error(`atris task ready: this check cannot fail — ${probe.reason}`);
|
|
@@ -9656,6 +9879,7 @@ function cmdReady(args) {
|
|
|
9656
9879
|
process.exit(2);
|
|
9657
9880
|
}
|
|
9658
9881
|
requireMeaningfulTaskProof('atris task ready', proof);
|
|
9882
|
+
requireRanNamedProofCommand('atris task ready', proof, usedVerify);
|
|
9659
9883
|
const lesson = flag(args, '--lesson') || '';
|
|
9660
9884
|
const nextTaskInput = normalizeReviewNextTaskInput(typeof flag(args, '--next') === 'string' ? flag(args, '--next') : '');
|
|
9661
9885
|
const landing = landingFlags(args);
|
|
@@ -9760,7 +9984,12 @@ function cmdReady(args) {
|
|
|
9760
9984
|
if (policyHints.length) handoff.policy_hints = policyHints;
|
|
9761
9985
|
if (readyPolicyGate.gate.advisories.length) handoff.policy_gate = readyPolicyGate.gate;
|
|
9762
9986
|
if (wantsJson(args)) {
|
|
9763
|
-
|
|
9987
|
+
const taskCard = compactTaskFromProjection(projection, taskId);
|
|
9988
|
+
const nextCommand = handoff.review_chat_command
|
|
9989
|
+
|| (agentCertified
|
|
9990
|
+
? `atris task accept ${taskRef(taskCard || result.row || taskId)}`
|
|
9991
|
+
: `atris task reviews`);
|
|
9992
|
+
const fullReady = {
|
|
9764
9993
|
ok: true,
|
|
9765
9994
|
action: 'ready',
|
|
9766
9995
|
task_id: taskId,
|
|
@@ -9773,8 +10002,23 @@ function cmdReady(args) {
|
|
|
9773
10002
|
landing_advisory: landingAdvisory,
|
|
9774
10003
|
...(nextTaskInput.ignored ? { review_next_task_ignored: nextTaskInput.ignored } : {}),
|
|
9775
10004
|
projection_path: outPath,
|
|
9776
|
-
task:
|
|
9777
|
-
|
|
10005
|
+
task: taskCard,
|
|
10006
|
+
next_command: nextCommand,
|
|
10007
|
+
};
|
|
10008
|
+
printCliJson(
|
|
10009
|
+
fullReady,
|
|
10010
|
+
compactSuccessPayload({
|
|
10011
|
+
action: 'ready',
|
|
10012
|
+
ids: {
|
|
10013
|
+
task_id: taskId,
|
|
10014
|
+
selected_ref: taskRef(taskCard || result.row || taskId),
|
|
10015
|
+
version: result.event.version,
|
|
10016
|
+
agent_certified: agentCertified,
|
|
10017
|
+
},
|
|
10018
|
+
next_command: nextCommand,
|
|
10019
|
+
}),
|
|
10020
|
+
args,
|
|
10021
|
+
);
|
|
9778
10022
|
return;
|
|
9779
10023
|
}
|
|
9780
10024
|
console.log(`ready for approval ${taskRef(compactTaskFromProjection(projection, taskId))} v${result.event.version}`);
|
|
@@ -11043,15 +11287,23 @@ function importTodoFile(taskDb, db, target) {
|
|
|
11043
11287
|
const parsed = parseTodoFile(filePath);
|
|
11044
11288
|
const ws = taskDb.workspaceRoot();
|
|
11045
11289
|
const all = [
|
|
11046
|
-
...parsed.backlog.map(t => ({ ...t, importStatus: 'open' })),
|
|
11047
|
-
...parsed.inProgress.map(t => ({ ...t, importStatus: 'claimed' })),
|
|
11048
|
-
...(parsed.review || []).map(t => ({ ...t, importStatus: 'review' })),
|
|
11290
|
+
...parsed.backlog.map(t => ({ ...t, importStatus: 'open', sourceFile: filePath })),
|
|
11291
|
+
...parsed.inProgress.map(t => ({ ...t, importStatus: 'claimed', sourceFile: filePath })),
|
|
11292
|
+
...(parsed.review || []).map(t => ({ ...t, importStatus: 'review', sourceFile: filePath })),
|
|
11049
11293
|
];
|
|
11294
|
+
const knownTitles = new Set(
|
|
11295
|
+
taskDb.listTasks(db, { workspaceRoot: ws, limit: 500 }).map((row) => taskDb.normalizeTitle(row.title))
|
|
11296
|
+
);
|
|
11050
11297
|
let inserted = 0;
|
|
11051
11298
|
let skipped = 0;
|
|
11052
11299
|
for (const t of all) {
|
|
11053
11300
|
if (!t.title) continue;
|
|
11054
|
-
const
|
|
11301
|
+
const normalized = taskDb.normalizeTitle(t.title);
|
|
11302
|
+
if (knownTitles.has(normalized)) {
|
|
11303
|
+
skipped++;
|
|
11304
|
+
continue;
|
|
11305
|
+
}
|
|
11306
|
+
const sk = taskDb.sourceKey(t.sourceFile || filePath, t.title);
|
|
11055
11307
|
const result = taskDb.addTask(db, {
|
|
11056
11308
|
title: t.title,
|
|
11057
11309
|
tag: t.tag || null,
|
|
@@ -11061,11 +11313,72 @@ function importTodoFile(taskDb, db, target) {
|
|
|
11061
11313
|
claimedBy: t.claimed || null,
|
|
11062
11314
|
metadata: { todo_id: t.id, todo_tags: t.tags || [], claimed: t.claimed, stage: t.stage, verify: t.verify },
|
|
11063
11315
|
});
|
|
11064
|
-
if (result.inserted)
|
|
11316
|
+
if (result.inserted) {
|
|
11317
|
+
inserted++;
|
|
11318
|
+
knownTitles.add(normalized);
|
|
11319
|
+
} else {
|
|
11320
|
+
skipped++;
|
|
11321
|
+
}
|
|
11322
|
+
}
|
|
11323
|
+
return { ok: true, inserted, skipped, filePath, knownTitles };
|
|
11324
|
+
}
|
|
11325
|
+
|
|
11326
|
+
function importJournalFile(taskDb, db, journalPath, knownTitles = null) {
|
|
11327
|
+
const filePath = path.resolve(journalPath);
|
|
11328
|
+
if (!fs.existsSync(filePath)) {
|
|
11329
|
+
return { ok: false, reason: 'not_found', filePath, inserted: 0, skipped: 0 };
|
|
11330
|
+
}
|
|
11331
|
+
const { parseSection } = require('../lib/todo-fallback');
|
|
11332
|
+
const { parseInboxItems } = require('../lib/file-ops');
|
|
11333
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
11334
|
+
const ws = taskDb.workspaceRoot();
|
|
11335
|
+
const titles = knownTitles || new Set(
|
|
11336
|
+
taskDb.listTasks(db, { workspaceRoot: ws, limit: 500 }).map((row) => taskDb.normalizeTitle(row.title))
|
|
11337
|
+
);
|
|
11338
|
+
const all = [
|
|
11339
|
+
...parseSection(content, 'Backlog').map((t) => ({ ...t, importStatus: 'open' })),
|
|
11340
|
+
...parseSection(content, 'In Progress').map((t) => ({ ...t, importStatus: 'claimed' })),
|
|
11341
|
+
...parseInboxItems(content).map((item) => ({
|
|
11342
|
+
id: `I${item.id}`,
|
|
11343
|
+
title: item.text,
|
|
11344
|
+
tag: 'inbox',
|
|
11345
|
+
importStatus: 'open',
|
|
11346
|
+
})),
|
|
11347
|
+
];
|
|
11348
|
+
let inserted = 0;
|
|
11349
|
+
let skipped = 0;
|
|
11350
|
+
for (const t of all) {
|
|
11351
|
+
if (!t.title) continue;
|
|
11352
|
+
const normalized = taskDb.normalizeTitle(t.title);
|
|
11353
|
+
if (titles.has(normalized)) {
|
|
11354
|
+
skipped++;
|
|
11355
|
+
continue;
|
|
11356
|
+
}
|
|
11357
|
+
const sk = taskDb.sourceKey(filePath, t.title);
|
|
11358
|
+
const result = taskDb.addTask(db, {
|
|
11359
|
+
title: t.title,
|
|
11360
|
+
tag: t.tag || null,
|
|
11361
|
+
workspaceRoot: ws,
|
|
11362
|
+
sourceKey: sk,
|
|
11363
|
+
status: t.importStatus,
|
|
11364
|
+
claimedBy: t.claimed || null,
|
|
11365
|
+
metadata: { todo_id: t.id, source: 'journal_import' },
|
|
11366
|
+
});
|
|
11367
|
+
if (result.inserted) {
|
|
11368
|
+
inserted++;
|
|
11369
|
+
titles.add(normalized);
|
|
11370
|
+
} else {
|
|
11371
|
+
skipped++;
|
|
11372
|
+
}
|
|
11065
11373
|
}
|
|
11066
11374
|
return { ok: true, inserted, skipped, filePath };
|
|
11067
11375
|
}
|
|
11068
11376
|
|
|
11377
|
+
function todayJournalPath() {
|
|
11378
|
+
const { getLogPath } = require('../lib/file-ops');
|
|
11379
|
+
return getLogPath().logFile;
|
|
11380
|
+
}
|
|
11381
|
+
|
|
11069
11382
|
function cmdImport(args) {
|
|
11070
11383
|
const pos = positional(args);
|
|
11071
11384
|
const target = pos[0] || 'atris/TODO.md';
|
|
@@ -11076,7 +11389,9 @@ function cmdImport(args) {
|
|
|
11076
11389
|
console.error(`atris task import: file not found: ${result.filePath}`);
|
|
11077
11390
|
process.exit(2);
|
|
11078
11391
|
}
|
|
11079
|
-
const
|
|
11392
|
+
const journalResult = importJournalFile(taskDb, db, todayJournalPath(), result.knownTitles);
|
|
11393
|
+
const inserted = result.inserted + (journalResult.ok ? journalResult.inserted : 0);
|
|
11394
|
+
const skipped = result.skipped + (journalResult.ok ? journalResult.skipped : 0);
|
|
11080
11395
|
const { outPath } = writeDefaultProjection(taskDb, db);
|
|
11081
11396
|
if (wantsJson(args)) {
|
|
11082
11397
|
printJson({
|
|
@@ -11084,12 +11399,16 @@ function cmdImport(args) {
|
|
|
11084
11399
|
action: 'imported',
|
|
11085
11400
|
inserted,
|
|
11086
11401
|
skipped,
|
|
11087
|
-
source: filePath,
|
|
11402
|
+
source: result.filePath,
|
|
11403
|
+
journal: journalResult.ok ? journalResult.filePath : null,
|
|
11088
11404
|
projection_path: outPath,
|
|
11089
11405
|
});
|
|
11090
11406
|
return;
|
|
11091
11407
|
}
|
|
11092
|
-
console.log(`imported ${inserted} new, skipped ${skipped} (already imported), source=${filePath}`);
|
|
11408
|
+
console.log(`imported ${inserted} new, skipped ${skipped} (already imported), source=${result.filePath}`);
|
|
11409
|
+
if (journalResult.ok && journalResult.inserted > 0) {
|
|
11410
|
+
console.log(`journal imported ${journalResult.inserted} from ${journalResult.filePath}`);
|
|
11411
|
+
}
|
|
11093
11412
|
}
|
|
11094
11413
|
|
|
11095
11414
|
function cmdWhere(args) {
|
|
@@ -11275,12 +11594,22 @@ function cmdSetup(args) {
|
|
|
11275
11594
|
const db = taskDb.open();
|
|
11276
11595
|
const ws = taskDb.workspaceRoot();
|
|
11277
11596
|
let importResult = null;
|
|
11597
|
+
let journalResult = null;
|
|
11278
11598
|
if (hasFlag(args, '--import-todo')) {
|
|
11279
11599
|
importResult = importTodoFile(taskDb, db, flag(args, '--todo') || 'atris/TODO.md');
|
|
11280
11600
|
if (!importResult.ok && flag(args, '--todo')) {
|
|
11281
11601
|
console.error(`atris task setup: TODO file not found: ${importResult.filePath}`);
|
|
11282
11602
|
process.exit(2);
|
|
11283
11603
|
}
|
|
11604
|
+
if (importResult.ok) {
|
|
11605
|
+
journalResult = importJournalFile(taskDb, db, todayJournalPath(), importResult.knownTitles);
|
|
11606
|
+
importResult = {
|
|
11607
|
+
...importResult,
|
|
11608
|
+
inserted: importResult.inserted + (journalResult.ok ? journalResult.inserted : 0),
|
|
11609
|
+
skipped: importResult.skipped + (journalResult.ok ? journalResult.skipped : 0),
|
|
11610
|
+
journal: journalResult.ok ? journalResult.filePath : null,
|
|
11611
|
+
};
|
|
11612
|
+
}
|
|
11284
11613
|
}
|
|
11285
11614
|
const { projection, outPath } = writeDefaultProjection(taskDb, db);
|
|
11286
11615
|
if (wantsJson(args)) {
|
|
@@ -11293,6 +11622,7 @@ function cmdSetup(args) {
|
|
|
11293
11622
|
inserted: importResult.inserted,
|
|
11294
11623
|
skipped: importResult.skipped,
|
|
11295
11624
|
source: importResult.filePath,
|
|
11625
|
+
journal: importResult.journal || null,
|
|
11296
11626
|
} : null,
|
|
11297
11627
|
projection,
|
|
11298
11628
|
});
|
|
@@ -12572,6 +12902,14 @@ function postTaskApiReady({ res, taskDb, db, taskId, body }) {
|
|
|
12572
12902
|
const proof = String(body.proof || '').trim();
|
|
12573
12903
|
const proofIssue = meaningfulTaskProofIssue(proof);
|
|
12574
12904
|
if (proofIssue) return sendProofIssue(res, proof, proofIssue);
|
|
12905
|
+
const unrunIssue = unrunNamedProofCommandIssue(proof, '');
|
|
12906
|
+
if (unrunIssue) {
|
|
12907
|
+
return sendJson(res, 400, {
|
|
12908
|
+
ok: false,
|
|
12909
|
+
reason: unrunIssue.reason,
|
|
12910
|
+
detail: unrunIssue.detail,
|
|
12911
|
+
});
|
|
12912
|
+
}
|
|
12575
12913
|
const nextTaskInput = normalizeReviewNextTaskInput(body.next);
|
|
12576
12914
|
const actor = String(body.actor || DEFAULT_OWNER);
|
|
12577
12915
|
const resultText = String(body.result || '').replace(/\s+/g, ' ').trim();
|
|
@@ -12817,8 +13155,9 @@ async function runTaskCommand(args) {
|
|
|
12817
13155
|
const raw = args || [];
|
|
12818
13156
|
if (raw.includes('--help') || raw.includes('-h')) return help();
|
|
12819
13157
|
const first = raw[0];
|
|
12820
|
-
|
|
12821
|
-
const
|
|
13158
|
+
if (!first) return cmdFirstMinute();
|
|
13159
|
+
const sub = first.startsWith('--') ? 'desk' : first;
|
|
13160
|
+
const rest = first.startsWith('--') ? raw : raw.slice(1);
|
|
12822
13161
|
switch (sub) {
|
|
12823
13162
|
case 'desk': return cmdHome(rest);
|
|
12824
13163
|
case 'today': return cmdDay(rest);
|
|
@@ -12971,6 +13310,42 @@ const MUTATING_TASK_COMMANDS = new Set([
|
|
|
12971
13310
|
async function run(args) {
|
|
12972
13311
|
const raw = args || [];
|
|
12973
13312
|
const sub = !raw[0] || raw[0].startsWith('--') ? 'desk' : raw[0];
|
|
13313
|
+
// `task accept --help` is a help request, not a run. Accept mutates
|
|
13314
|
+
// review rows, so never list or accept just to show usage.
|
|
13315
|
+
if (sub === 'accept' && argsWantHelp(raw.slice(1))) {
|
|
13316
|
+
console.log('Usage: atris task accept <id> [--proof "..."] [--public]');
|
|
13317
|
+
return;
|
|
13318
|
+
}
|
|
13319
|
+
// `task claim --help` is a help request, not a run. Claim mutates
|
|
13320
|
+
// ownership, so never list or claim just to show usage.
|
|
13321
|
+
if (sub === 'claim' && argsWantHelp(raw.slice(1))) {
|
|
13322
|
+
console.log('Usage: atris task claim <id> --as <member>');
|
|
13323
|
+
return;
|
|
13324
|
+
}
|
|
13325
|
+
// `task ready --help` is a help request, not a run. Ready mutates
|
|
13326
|
+
// review state, so never list or ready just to show usage.
|
|
13327
|
+
if (sub === 'ready' && argsWantHelp(raw.slice(1))) {
|
|
13328
|
+
console.log('Usage: atris task ready <id> --proof "..." --result "<sentence>"');
|
|
13329
|
+
return;
|
|
13330
|
+
}
|
|
13331
|
+
// `task step --help` is a help request, not a run. Step mutates
|
|
13332
|
+
// Plan/Do/Review, so never list or step just to show usage.
|
|
13333
|
+
if (sub === 'step' && argsWantHelp(raw.slice(1))) {
|
|
13334
|
+
console.log('Usage: atris task step <id> [--json]');
|
|
13335
|
+
return;
|
|
13336
|
+
}
|
|
13337
|
+
// `task next --help` is a help request, not a run. Next can open
|
|
13338
|
+
// the task db or print the desk, so never list or claim just to show usage.
|
|
13339
|
+
if (sub === 'next' && argsWantHelp(raw.slice(1))) {
|
|
13340
|
+
console.log('Usage: atris task next [--tag <tag>] [--create-next]');
|
|
13341
|
+
return;
|
|
13342
|
+
}
|
|
13343
|
+
// `task show --help` is a help request, not a run. Show can dump
|
|
13344
|
+
// a task card or the encyclopedia, so never list or show just to show usage.
|
|
13345
|
+
if (sub === 'show' && argsWantHelp(raw.slice(1))) {
|
|
13346
|
+
console.log('Usage: atris task show <id> [--json]');
|
|
13347
|
+
return;
|
|
13348
|
+
}
|
|
12974
13349
|
const result = await runTaskCommand(raw);
|
|
12975
13350
|
const skipsRender = sub === 'clear-done' && hasFlag(raw, '--dry-run');
|
|
12976
13351
|
if (MUTATING_TASK_COMMANDS.has(sub) && !skipsRender) autoRenderTodoFromDb();
|