atris 3.52.0 → 3.55.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/engines/SKILL.md +8 -7
- package/atris/skills/x-search/SKILL.md +24 -22
- package/atris/skills/youtube/SKILL.md +89 -40
- package/atris/team/_template/SOUL.md +40 -0
- package/atris/team/validator/MEMBER.md +1 -2
- package/ax +592 -91
- package/bin/atris +21 -0
- package/bin/atris.js +580 -378
- 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/computer.js +2 -2
- 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 +399 -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 +339 -74
- package/commands/now.js +25 -6
- 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 +96 -40
- 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 +418 -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 -33
- package/lib/account-bound.js +47 -0
- package/lib/auto-accept-certified.js +10 -2
- 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/engine-ask.js +11 -3
- package/lib/engine-registry.js +32 -7
- 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-ledger-compact.js +127 -0
- package/lib/mission-root.js +4 -2
- package/lib/mission-runtime-loop.js +30 -2
- package/lib/next-moves.js +34 -34
- package/lib/noninteractive.js +88 -0
- package/lib/permission-grants.js +10 -1
- package/lib/policy-lessons.js +4 -1
- package/lib/revision-metric.js +279 -0
- package/lib/runner-command.js +5 -4
- package/lib/scratch-root.js +48 -0
- package/lib/skill-eval-gate.js +249 -0
- package/lib/task-db.js +22 -2
- package/lib/task-proof.js +75 -9
- package/lib/task-receipt.js +5 -1
- 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 +4 -2
- package/scripts/det/checklist-score.js +191 -0
- package/scripts/det/ytsearch +31 -0
- package/scripts/outbound-artifact-gate.js +227 -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, 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,7 +6162,7 @@ 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) {
|
|
@@ -6446,6 +6474,15 @@ function cmdDay(args) {
|
|
|
6446
6474
|
console.log('add: atris task delegate "..." --to task-planner --tag tasks');
|
|
6447
6475
|
}
|
|
6448
6476
|
|
|
6477
|
+
function cmdFirstMinute() {
|
|
6478
|
+
const root = process.cwd();
|
|
6479
|
+
const screen = buildFirstMinute({
|
|
6480
|
+
root,
|
|
6481
|
+
fresh: !fs.existsSync(path.join(root, 'atris')),
|
|
6482
|
+
});
|
|
6483
|
+
console.log(screen.text);
|
|
6484
|
+
}
|
|
6485
|
+
|
|
6449
6486
|
function cmdHome(args) {
|
|
6450
6487
|
const all = hasFlag(args, '--all');
|
|
6451
6488
|
const everywhere = taskScopeEverywhere(args);
|
|
@@ -6771,7 +6808,108 @@ function createEndgameSeedTask(taskDb, db, seed, owner) {
|
|
|
6771
6808
|
};
|
|
6772
6809
|
}
|
|
6773
6810
|
|
|
6811
|
+
function nextActionFromCommand(command) {
|
|
6812
|
+
const match = String(command || '').trim().match(/^atris (?:task|mission) (\S+)/);
|
|
6813
|
+
const verb = match ? match[1] : '';
|
|
6814
|
+
if (!verb || verb === 'new') return 'none';
|
|
6815
|
+
return verb;
|
|
6816
|
+
}
|
|
6817
|
+
|
|
6818
|
+
function cmdNextTruth(args) {
|
|
6819
|
+
const owner = flag(args, '--as') || personName() || DEFAULT_OWNER;
|
|
6820
|
+
const scope = taskQueueScopeFromArgs(args);
|
|
6821
|
+
const taskDb = getTaskDb();
|
|
6822
|
+
const db = taskDb.open();
|
|
6823
|
+
const workspaceRoot = taskDb.workspaceRoot();
|
|
6824
|
+
const rows = taskDb.listTasks(db, { workspaceRoot, limit: 500 });
|
|
6825
|
+
const existingProj = readProjectionFile(workspaceRoot);
|
|
6826
|
+
let projection;
|
|
6827
|
+
let outPath;
|
|
6828
|
+
if (rows.length === 0 && existingProj && Array.isArray(existingProj.tasks) && existingProj.tasks.length > 0) {
|
|
6829
|
+
projection = existingProj;
|
|
6830
|
+
outPath = path.resolve(path.join(workspaceRoot || '.', '.atris', 'state', 'tasks.projection.json'));
|
|
6831
|
+
} else {
|
|
6832
|
+
const written = writeDefaultProjection(taskDb, db);
|
|
6833
|
+
projection = written.projection;
|
|
6834
|
+
outPath = written.outPath;
|
|
6835
|
+
}
|
|
6836
|
+
const scoped = filterTasksByScope(projection.tasks || [], scope);
|
|
6837
|
+
const openDecisions = scoped.filter((task) => task && isDecisionTask(task) && task.status === 'open');
|
|
6838
|
+
const actionable = scoped.filter((task) => task && !isDecisionTask(task));
|
|
6839
|
+
const picked = pickNext({ tasks: actionable, person: owner });
|
|
6840
|
+
const command = picked.task ? (picked.command || taskCommand(picked.task, owner)) : taskNextCommand(actionable, owner);
|
|
6841
|
+
const task = picked.task || null;
|
|
6842
|
+
|
|
6843
|
+
if (!task && openDecisions.length) {
|
|
6844
|
+
if (wantsJson(args)) {
|
|
6845
|
+
printJson({
|
|
6846
|
+
ok: false,
|
|
6847
|
+
action: 'refused',
|
|
6848
|
+
reason: DECISION_REFUSE_REASON,
|
|
6849
|
+
skipped_decision_count: openDecisions.length,
|
|
6850
|
+
owner: String(owner),
|
|
6851
|
+
scope: normalizeTaskQueueScope(scope),
|
|
6852
|
+
projection_path: outPath,
|
|
6853
|
+
});
|
|
6854
|
+
process.exit(1);
|
|
6855
|
+
}
|
|
6856
|
+
console.error(DECISION_REFUSE_REASON);
|
|
6857
|
+
process.exit(1);
|
|
6858
|
+
}
|
|
6859
|
+
|
|
6860
|
+
if (wantsJson(args)) {
|
|
6861
|
+
printJson({
|
|
6862
|
+
ok: true,
|
|
6863
|
+
action: nextActionFromCommand(command),
|
|
6864
|
+
command,
|
|
6865
|
+
task_id: task ? task.id : null,
|
|
6866
|
+
owner: String(owner),
|
|
6867
|
+
scope: normalizeTaskQueueScope(scope),
|
|
6868
|
+
projection_path: outPath,
|
|
6869
|
+
task: task ? compactTaskFromProjection(projection, task.id) : null,
|
|
6870
|
+
});
|
|
6871
|
+
return;
|
|
6872
|
+
}
|
|
6873
|
+
|
|
6874
|
+
if (!task) {
|
|
6875
|
+
console.log(noOpenTasksMessage(scope));
|
|
6876
|
+
console.log(`next: ${command}`);
|
|
6877
|
+
return;
|
|
6878
|
+
}
|
|
6879
|
+
console.log(`next: ${command}`);
|
|
6880
|
+
}
|
|
6881
|
+
|
|
6882
|
+
function isUninitializedTaskFolder(cwd = process.cwd()) {
|
|
6883
|
+
const workspace = getTaskDb().workspaceRoot(cwd);
|
|
6884
|
+
if (fs.existsSync(path.join(workspace, 'atris'))) return false;
|
|
6885
|
+
const existing = readProjectionFile(workspace);
|
|
6886
|
+
return !(existing && Array.isArray(existing.tasks) && existing.tasks.length > 0);
|
|
6887
|
+
}
|
|
6888
|
+
|
|
6774
6889
|
function cmdNext(args) {
|
|
6890
|
+
const root = process.cwd();
|
|
6891
|
+
// Empty folder talks like bare atris. Walk up like the task db so a
|
|
6892
|
+
// project subdir stays in the room; stop before inheriting /tmp.
|
|
6893
|
+
// A leftover projection with live tasks still names that work.
|
|
6894
|
+
if (isUninitializedTaskFolder(root)) {
|
|
6895
|
+
if (wantsJson(args)) {
|
|
6896
|
+
printJson({
|
|
6897
|
+
ok: true,
|
|
6898
|
+
action: 'init',
|
|
6899
|
+
command: 'atris init --minimal',
|
|
6900
|
+
task_id: null,
|
|
6901
|
+
owner: String(flag(args, '--as') || personName() || DEFAULT_OWNER),
|
|
6902
|
+
scope: normalizeTaskQueueScope(taskQueueScopeFromArgs(args)),
|
|
6903
|
+
projection_path: null,
|
|
6904
|
+
task: null,
|
|
6905
|
+
});
|
|
6906
|
+
return;
|
|
6907
|
+
}
|
|
6908
|
+
const screen = buildFirstMinute({ root, fresh: true });
|
|
6909
|
+
console.log(screen.text);
|
|
6910
|
+
return;
|
|
6911
|
+
}
|
|
6912
|
+
if (!hasFlag(args, '--create-next')) return cmdNextTruth(args);
|
|
6775
6913
|
const owner = flag(args, '--as') || DEFAULT_OWNER;
|
|
6776
6914
|
const scope = taskQueueScopeFromArgs(args);
|
|
6777
6915
|
const scoped = !taskQueueScopeIsEmpty(scope);
|
|
@@ -8637,7 +8775,7 @@ function taskStepError(reason, detail, { status = 409, exitCode = 1, page = null
|
|
|
8637
8775
|
}
|
|
8638
8776
|
|
|
8639
8777
|
function taskStepStatusForReason(reason) {
|
|
8640
|
-
if (['goal_required', 'exit_required', 'proof_needed_required', 'first_move_required', 'proof_required', 'weak_proof', 'invalid_reward'].includes(reason)) {
|
|
8778
|
+
if (['goal_required', 'exit_required', 'proof_needed_required', 'first_move_required', 'proof_required', 'weak_proof', 'proof_command_not_run', 'invalid_reward'].includes(reason)) {
|
|
8641
8779
|
return 400;
|
|
8642
8780
|
}
|
|
8643
8781
|
if (reason === 'not_found') return 404;
|
|
@@ -8848,7 +8986,11 @@ function runTaskStep(taskDb, db, taskId, options = {}) {
|
|
|
8848
8986
|
const proof = String(options.proof || '').trim();
|
|
8849
8987
|
const proofIssue = meaningfulTaskProofIssue(proof);
|
|
8850
8988
|
if (proofIssue) {
|
|
8851
|
-
throw taskStepError(proof ? 'weak_proof' : 'proof_required',
|
|
8989
|
+
throw taskStepError(proof ? 'weak_proof' : 'proof_required', weakProofDetail(proofIssue), { status: 400, exitCode: 2, page: actionPage });
|
|
8990
|
+
}
|
|
8991
|
+
const unrunIssue = unrunNamedProofCommandIssue(proof, '');
|
|
8992
|
+
if (unrunIssue) {
|
|
8993
|
+
throw taskStepError(unrunIssue.reason, unrunIssue.detail, { status: 400, exitCode: 2, page: actionPage });
|
|
8852
8994
|
}
|
|
8853
8995
|
const missionXpIssue = missionXpEndToEndProofIssue(task, proof, task.workspace_root || process.cwd());
|
|
8854
8996
|
if (missionXpIssue) {
|
|
@@ -8895,7 +9037,11 @@ function runTaskStep(taskDb, db, taskId, options = {}) {
|
|
|
8895
9037
|
const proof = String(options.proof || '').trim();
|
|
8896
9038
|
const proofIssue = meaningfulTaskProofIssue(proof);
|
|
8897
9039
|
if (proofIssue) {
|
|
8898
|
-
throw taskStepError(proof ? 'weak_proof' : 'proof_required',
|
|
9040
|
+
throw taskStepError(proof ? 'weak_proof' : 'proof_required', weakProofDetail(proofIssue), { status: 400, exitCode: 2, page: actionPage });
|
|
9041
|
+
}
|
|
9042
|
+
const unrunIssue = unrunNamedProofCommandIssue(proof, '');
|
|
9043
|
+
if (unrunIssue) {
|
|
9044
|
+
throw taskStepError(unrunIssue.reason, unrunIssue.detail, { status: 400, exitCode: 2, page: actionPage });
|
|
8899
9045
|
}
|
|
8900
9046
|
const parsedReward = parseStepReviewReward(options.reward);
|
|
8901
9047
|
if (!parsedReward.ok) {
|
|
@@ -9127,24 +9273,51 @@ function cmdCurrentStep(args) {
|
|
|
9127
9273
|
} catch (error) {
|
|
9128
9274
|
const errorCurrent = error.current || null;
|
|
9129
9275
|
if (wantsJson(args)) {
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9276
|
+
const selectedRef = errorCurrent ? errorCurrent.selected_ref : null;
|
|
9277
|
+
const nextCommand = error.page?.stage?.next_action?.command
|
|
9278
|
+
|| (errorCurrent && errorCurrent.next && errorCurrent.next.command)
|
|
9279
|
+
|| null;
|
|
9280
|
+
printCliJson(
|
|
9281
|
+
{
|
|
9282
|
+
ok: false,
|
|
9283
|
+
action: 'current_step',
|
|
9284
|
+
reason: error.reason || 'step_failed',
|
|
9285
|
+
detail: error.message,
|
|
9286
|
+
selected_task_id: errorCurrent ? errorCurrent.selected_task_id : null,
|
|
9287
|
+
selected_ref: selectedRef,
|
|
9288
|
+
selected_next_key: selectedNextKeyFromCurrent(errorCurrent),
|
|
9289
|
+
next_command: nextCommand,
|
|
9290
|
+
current: errorCurrent,
|
|
9291
|
+
page: error.page || null,
|
|
9292
|
+
},
|
|
9293
|
+
compactErrorPayload({
|
|
9294
|
+
reason: error.reason || 'step_failed',
|
|
9295
|
+
detail: error.message,
|
|
9296
|
+
selected_ref: selectedRef,
|
|
9297
|
+
next_command: nextCommand,
|
|
9298
|
+
}),
|
|
9299
|
+
args,
|
|
9300
|
+
);
|
|
9141
9301
|
} else {
|
|
9142
9302
|
console.error(error.message || 'atris task current-step failed');
|
|
9143
9303
|
}
|
|
9144
9304
|
process.exit(error.exitCode || 1);
|
|
9145
9305
|
}
|
|
9146
9306
|
if (wantsJson(args)) {
|
|
9147
|
-
|
|
9307
|
+
const nextCommand = result.page?.stage?.next_action?.command || null;
|
|
9308
|
+
printCliJson(
|
|
9309
|
+
result,
|
|
9310
|
+
compactSuccessPayload({
|
|
9311
|
+
action: 'current_step',
|
|
9312
|
+
ids: {
|
|
9313
|
+
selected_task_id: result.selected_task_id || null,
|
|
9314
|
+
selected_ref: result.selected_ref || null,
|
|
9315
|
+
step_action: result.step && result.step.step_action ? result.step.step_action : null,
|
|
9316
|
+
},
|
|
9317
|
+
next_command: nextCommand,
|
|
9318
|
+
}),
|
|
9319
|
+
args,
|
|
9320
|
+
);
|
|
9148
9321
|
return;
|
|
9149
9322
|
}
|
|
9150
9323
|
console.log(`current-step ${taskRef(result.task)} -> ${result.step.step_action}`);
|
|
@@ -9610,14 +9783,38 @@ function cmdReady(args) {
|
|
|
9610
9783
|
console.error('atris task ready: id required');
|
|
9611
9784
|
process.exit(2);
|
|
9612
9785
|
}
|
|
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
|
-
//
|
|
9786
|
+
// Two ways to prove: --proof "<note>" (claimed, pattern-checked) or
|
|
9787
|
+
// --verify "<command>" which actually RUNS the command and gates ready on exit 0.
|
|
9788
|
+
// If --proof names npm test, node --test, or git diff --check, this process
|
|
9789
|
+
// must have run that command. A sentence that names one of those is a lie.
|
|
9616
9790
|
const proofFlag = flag(args, '--proof');
|
|
9617
9791
|
const verifyFlag = flag(args, '--verify');
|
|
9618
|
-
const
|
|
9792
|
+
const proofUrl = textFlag(args, ['--proof-url']);
|
|
9793
|
+
const iFetched = hasFlag(args, '--i-fetched');
|
|
9794
|
+
if (proofUrl && !iFetched) {
|
|
9795
|
+
failTask(
|
|
9796
|
+
'atris task ready',
|
|
9797
|
+
'unfetched_proof_url',
|
|
9798
|
+
'CI run URLs only count after atris fetches them, or with --proof-url and --i-fetched',
|
|
9799
|
+
);
|
|
9800
|
+
}
|
|
9801
|
+
if (iFetched && !proofUrl && !(typeof proofFlag === 'string' && /https?:\/\/github[.]com\//i.test(proofFlag))) {
|
|
9802
|
+
failTask(
|
|
9803
|
+
'atris task ready',
|
|
9804
|
+
'proof_url_required',
|
|
9805
|
+
'--i-fetched requires --proof-url <actions-run-url> (or a URL inside --proof)',
|
|
9806
|
+
);
|
|
9807
|
+
}
|
|
9619
9808
|
const usedVerify = typeof verifyFlag === 'string' ? verifyFlag.trim() : '';
|
|
9809
|
+
const resultSentence = requireResultSentence('atris task ready', textFlag(args, ['--result']), {
|
|
9810
|
+
ready: true,
|
|
9811
|
+
allowCommandMention: Boolean(usedVerify),
|
|
9812
|
+
});
|
|
9620
9813
|
let proof = typeof proofFlag === 'string' ? proofFlag : '';
|
|
9814
|
+
if (proofUrl && iFetched) {
|
|
9815
|
+
const attested = `[i-fetched] ${proofUrl}`;
|
|
9816
|
+
proof = proof.trim() ? `${proof.trim()} ${attested}` : attested;
|
|
9817
|
+
}
|
|
9621
9818
|
const verifyAutoCertifyAllowed = !usedVerify || isAutoCertifyVerifyCommandAllowed(verifyFlag);
|
|
9622
9819
|
if (usedVerify) {
|
|
9623
9820
|
// Run the verifier once and write a receipt (pass or fail) so the review
|
|
@@ -9638,6 +9835,15 @@ function cmdReady(args) {
|
|
|
9638
9835
|
// this codebase fails there, and one that passes anywhere passes there too.
|
|
9639
9836
|
if (!hasFlag(args, '--no-falsify-check')) {
|
|
9640
9837
|
const { probeVerifierCanFail } = require('../lib/falsifier-probe');
|
|
9838
|
+
const { classifyVerifier } = require('../lib/verifier-quality');
|
|
9839
|
+
const quality = classifyVerifier(verifyFlag);
|
|
9840
|
+
if (!quality.ok) {
|
|
9841
|
+
console.error(`atris task ready: weak verifier — ${quality.reason}`);
|
|
9842
|
+
console.error(` command: ${verifyFlag}`);
|
|
9843
|
+
console.error(' allowlisted examples: node --test, npm test, git diff --check, node --check, rg <symbol>');
|
|
9844
|
+
console.error(' or pass --no-falsify-check to accept anyway.');
|
|
9845
|
+
process.exit(1);
|
|
9846
|
+
}
|
|
9641
9847
|
const probe = probeVerifierCanFail({ command: verifyFlag });
|
|
9642
9848
|
if (probe.probed && probe.canFail === false) {
|
|
9643
9849
|
console.error(`atris task ready: this check cannot fail — ${probe.reason}`);
|
|
@@ -9656,6 +9862,7 @@ function cmdReady(args) {
|
|
|
9656
9862
|
process.exit(2);
|
|
9657
9863
|
}
|
|
9658
9864
|
requireMeaningfulTaskProof('atris task ready', proof);
|
|
9865
|
+
requireRanNamedProofCommand('atris task ready', proof, usedVerify);
|
|
9659
9866
|
const lesson = flag(args, '--lesson') || '';
|
|
9660
9867
|
const nextTaskInput = normalizeReviewNextTaskInput(typeof flag(args, '--next') === 'string' ? flag(args, '--next') : '');
|
|
9661
9868
|
const landing = landingFlags(args);
|
|
@@ -9760,7 +9967,12 @@ function cmdReady(args) {
|
|
|
9760
9967
|
if (policyHints.length) handoff.policy_hints = policyHints;
|
|
9761
9968
|
if (readyPolicyGate.gate.advisories.length) handoff.policy_gate = readyPolicyGate.gate;
|
|
9762
9969
|
if (wantsJson(args)) {
|
|
9763
|
-
|
|
9970
|
+
const taskCard = compactTaskFromProjection(projection, taskId);
|
|
9971
|
+
const nextCommand = handoff.review_chat_command
|
|
9972
|
+
|| (agentCertified
|
|
9973
|
+
? `atris task accept ${taskRef(taskCard || result.row || taskId)}`
|
|
9974
|
+
: `atris task reviews`);
|
|
9975
|
+
const fullReady = {
|
|
9764
9976
|
ok: true,
|
|
9765
9977
|
action: 'ready',
|
|
9766
9978
|
task_id: taskId,
|
|
@@ -9773,8 +9985,23 @@ function cmdReady(args) {
|
|
|
9773
9985
|
landing_advisory: landingAdvisory,
|
|
9774
9986
|
...(nextTaskInput.ignored ? { review_next_task_ignored: nextTaskInput.ignored } : {}),
|
|
9775
9987
|
projection_path: outPath,
|
|
9776
|
-
task:
|
|
9777
|
-
|
|
9988
|
+
task: taskCard,
|
|
9989
|
+
next_command: nextCommand,
|
|
9990
|
+
};
|
|
9991
|
+
printCliJson(
|
|
9992
|
+
fullReady,
|
|
9993
|
+
compactSuccessPayload({
|
|
9994
|
+
action: 'ready',
|
|
9995
|
+
ids: {
|
|
9996
|
+
task_id: taskId,
|
|
9997
|
+
selected_ref: taskRef(taskCard || result.row || taskId),
|
|
9998
|
+
version: result.event.version,
|
|
9999
|
+
agent_certified: agentCertified,
|
|
10000
|
+
},
|
|
10001
|
+
next_command: nextCommand,
|
|
10002
|
+
}),
|
|
10003
|
+
args,
|
|
10004
|
+
);
|
|
9778
10005
|
return;
|
|
9779
10006
|
}
|
|
9780
10007
|
console.log(`ready for approval ${taskRef(compactTaskFromProjection(projection, taskId))} v${result.event.version}`);
|
|
@@ -11043,15 +11270,23 @@ function importTodoFile(taskDb, db, target) {
|
|
|
11043
11270
|
const parsed = parseTodoFile(filePath);
|
|
11044
11271
|
const ws = taskDb.workspaceRoot();
|
|
11045
11272
|
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' })),
|
|
11273
|
+
...parsed.backlog.map(t => ({ ...t, importStatus: 'open', sourceFile: filePath })),
|
|
11274
|
+
...parsed.inProgress.map(t => ({ ...t, importStatus: 'claimed', sourceFile: filePath })),
|
|
11275
|
+
...(parsed.review || []).map(t => ({ ...t, importStatus: 'review', sourceFile: filePath })),
|
|
11049
11276
|
];
|
|
11277
|
+
const knownTitles = new Set(
|
|
11278
|
+
taskDb.listTasks(db, { workspaceRoot: ws, limit: 500 }).map((row) => taskDb.normalizeTitle(row.title))
|
|
11279
|
+
);
|
|
11050
11280
|
let inserted = 0;
|
|
11051
11281
|
let skipped = 0;
|
|
11052
11282
|
for (const t of all) {
|
|
11053
11283
|
if (!t.title) continue;
|
|
11054
|
-
const
|
|
11284
|
+
const normalized = taskDb.normalizeTitle(t.title);
|
|
11285
|
+
if (knownTitles.has(normalized)) {
|
|
11286
|
+
skipped++;
|
|
11287
|
+
continue;
|
|
11288
|
+
}
|
|
11289
|
+
const sk = taskDb.sourceKey(t.sourceFile || filePath, t.title);
|
|
11055
11290
|
const result = taskDb.addTask(db, {
|
|
11056
11291
|
title: t.title,
|
|
11057
11292
|
tag: t.tag || null,
|
|
@@ -11061,11 +11296,72 @@ function importTodoFile(taskDb, db, target) {
|
|
|
11061
11296
|
claimedBy: t.claimed || null,
|
|
11062
11297
|
metadata: { todo_id: t.id, todo_tags: t.tags || [], claimed: t.claimed, stage: t.stage, verify: t.verify },
|
|
11063
11298
|
});
|
|
11064
|
-
if (result.inserted)
|
|
11299
|
+
if (result.inserted) {
|
|
11300
|
+
inserted++;
|
|
11301
|
+
knownTitles.add(normalized);
|
|
11302
|
+
} else {
|
|
11303
|
+
skipped++;
|
|
11304
|
+
}
|
|
11305
|
+
}
|
|
11306
|
+
return { ok: true, inserted, skipped, filePath, knownTitles };
|
|
11307
|
+
}
|
|
11308
|
+
|
|
11309
|
+
function importJournalFile(taskDb, db, journalPath, knownTitles = null) {
|
|
11310
|
+
const filePath = path.resolve(journalPath);
|
|
11311
|
+
if (!fs.existsSync(filePath)) {
|
|
11312
|
+
return { ok: false, reason: 'not_found', filePath, inserted: 0, skipped: 0 };
|
|
11313
|
+
}
|
|
11314
|
+
const { parseSection } = require('../lib/todo-fallback');
|
|
11315
|
+
const { parseInboxItems } = require('../lib/file-ops');
|
|
11316
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
11317
|
+
const ws = taskDb.workspaceRoot();
|
|
11318
|
+
const titles = knownTitles || new Set(
|
|
11319
|
+
taskDb.listTasks(db, { workspaceRoot: ws, limit: 500 }).map((row) => taskDb.normalizeTitle(row.title))
|
|
11320
|
+
);
|
|
11321
|
+
const all = [
|
|
11322
|
+
...parseSection(content, 'Backlog').map((t) => ({ ...t, importStatus: 'open' })),
|
|
11323
|
+
...parseSection(content, 'In Progress').map((t) => ({ ...t, importStatus: 'claimed' })),
|
|
11324
|
+
...parseInboxItems(content).map((item) => ({
|
|
11325
|
+
id: `I${item.id}`,
|
|
11326
|
+
title: item.text,
|
|
11327
|
+
tag: 'inbox',
|
|
11328
|
+
importStatus: 'open',
|
|
11329
|
+
})),
|
|
11330
|
+
];
|
|
11331
|
+
let inserted = 0;
|
|
11332
|
+
let skipped = 0;
|
|
11333
|
+
for (const t of all) {
|
|
11334
|
+
if (!t.title) continue;
|
|
11335
|
+
const normalized = taskDb.normalizeTitle(t.title);
|
|
11336
|
+
if (titles.has(normalized)) {
|
|
11337
|
+
skipped++;
|
|
11338
|
+
continue;
|
|
11339
|
+
}
|
|
11340
|
+
const sk = taskDb.sourceKey(filePath, t.title);
|
|
11341
|
+
const result = taskDb.addTask(db, {
|
|
11342
|
+
title: t.title,
|
|
11343
|
+
tag: t.tag || null,
|
|
11344
|
+
workspaceRoot: ws,
|
|
11345
|
+
sourceKey: sk,
|
|
11346
|
+
status: t.importStatus,
|
|
11347
|
+
claimedBy: t.claimed || null,
|
|
11348
|
+
metadata: { todo_id: t.id, source: 'journal_import' },
|
|
11349
|
+
});
|
|
11350
|
+
if (result.inserted) {
|
|
11351
|
+
inserted++;
|
|
11352
|
+
titles.add(normalized);
|
|
11353
|
+
} else {
|
|
11354
|
+
skipped++;
|
|
11355
|
+
}
|
|
11065
11356
|
}
|
|
11066
11357
|
return { ok: true, inserted, skipped, filePath };
|
|
11067
11358
|
}
|
|
11068
11359
|
|
|
11360
|
+
function todayJournalPath() {
|
|
11361
|
+
const { getLogPath } = require('../lib/file-ops');
|
|
11362
|
+
return getLogPath().logFile;
|
|
11363
|
+
}
|
|
11364
|
+
|
|
11069
11365
|
function cmdImport(args) {
|
|
11070
11366
|
const pos = positional(args);
|
|
11071
11367
|
const target = pos[0] || 'atris/TODO.md';
|
|
@@ -11076,7 +11372,9 @@ function cmdImport(args) {
|
|
|
11076
11372
|
console.error(`atris task import: file not found: ${result.filePath}`);
|
|
11077
11373
|
process.exit(2);
|
|
11078
11374
|
}
|
|
11079
|
-
const
|
|
11375
|
+
const journalResult = importJournalFile(taskDb, db, todayJournalPath(), result.knownTitles);
|
|
11376
|
+
const inserted = result.inserted + (journalResult.ok ? journalResult.inserted : 0);
|
|
11377
|
+
const skipped = result.skipped + (journalResult.ok ? journalResult.skipped : 0);
|
|
11080
11378
|
const { outPath } = writeDefaultProjection(taskDb, db);
|
|
11081
11379
|
if (wantsJson(args)) {
|
|
11082
11380
|
printJson({
|
|
@@ -11084,12 +11382,16 @@ function cmdImport(args) {
|
|
|
11084
11382
|
action: 'imported',
|
|
11085
11383
|
inserted,
|
|
11086
11384
|
skipped,
|
|
11087
|
-
source: filePath,
|
|
11385
|
+
source: result.filePath,
|
|
11386
|
+
journal: journalResult.ok ? journalResult.filePath : null,
|
|
11088
11387
|
projection_path: outPath,
|
|
11089
11388
|
});
|
|
11090
11389
|
return;
|
|
11091
11390
|
}
|
|
11092
|
-
console.log(`imported ${inserted} new, skipped ${skipped} (already imported), source=${filePath}`);
|
|
11391
|
+
console.log(`imported ${inserted} new, skipped ${skipped} (already imported), source=${result.filePath}`);
|
|
11392
|
+
if (journalResult.ok && journalResult.inserted > 0) {
|
|
11393
|
+
console.log(`journal imported ${journalResult.inserted} from ${journalResult.filePath}`);
|
|
11394
|
+
}
|
|
11093
11395
|
}
|
|
11094
11396
|
|
|
11095
11397
|
function cmdWhere(args) {
|
|
@@ -11275,12 +11577,22 @@ function cmdSetup(args) {
|
|
|
11275
11577
|
const db = taskDb.open();
|
|
11276
11578
|
const ws = taskDb.workspaceRoot();
|
|
11277
11579
|
let importResult = null;
|
|
11580
|
+
let journalResult = null;
|
|
11278
11581
|
if (hasFlag(args, '--import-todo')) {
|
|
11279
11582
|
importResult = importTodoFile(taskDb, db, flag(args, '--todo') || 'atris/TODO.md');
|
|
11280
11583
|
if (!importResult.ok && flag(args, '--todo')) {
|
|
11281
11584
|
console.error(`atris task setup: TODO file not found: ${importResult.filePath}`);
|
|
11282
11585
|
process.exit(2);
|
|
11283
11586
|
}
|
|
11587
|
+
if (importResult.ok) {
|
|
11588
|
+
journalResult = importJournalFile(taskDb, db, todayJournalPath(), importResult.knownTitles);
|
|
11589
|
+
importResult = {
|
|
11590
|
+
...importResult,
|
|
11591
|
+
inserted: importResult.inserted + (journalResult.ok ? journalResult.inserted : 0),
|
|
11592
|
+
skipped: importResult.skipped + (journalResult.ok ? journalResult.skipped : 0),
|
|
11593
|
+
journal: journalResult.ok ? journalResult.filePath : null,
|
|
11594
|
+
};
|
|
11595
|
+
}
|
|
11284
11596
|
}
|
|
11285
11597
|
const { projection, outPath } = writeDefaultProjection(taskDb, db);
|
|
11286
11598
|
if (wantsJson(args)) {
|
|
@@ -11293,6 +11605,7 @@ function cmdSetup(args) {
|
|
|
11293
11605
|
inserted: importResult.inserted,
|
|
11294
11606
|
skipped: importResult.skipped,
|
|
11295
11607
|
source: importResult.filePath,
|
|
11608
|
+
journal: importResult.journal || null,
|
|
11296
11609
|
} : null,
|
|
11297
11610
|
projection,
|
|
11298
11611
|
});
|
|
@@ -12572,6 +12885,14 @@ function postTaskApiReady({ res, taskDb, db, taskId, body }) {
|
|
|
12572
12885
|
const proof = String(body.proof || '').trim();
|
|
12573
12886
|
const proofIssue = meaningfulTaskProofIssue(proof);
|
|
12574
12887
|
if (proofIssue) return sendProofIssue(res, proof, proofIssue);
|
|
12888
|
+
const unrunIssue = unrunNamedProofCommandIssue(proof, '');
|
|
12889
|
+
if (unrunIssue) {
|
|
12890
|
+
return sendJson(res, 400, {
|
|
12891
|
+
ok: false,
|
|
12892
|
+
reason: unrunIssue.reason,
|
|
12893
|
+
detail: unrunIssue.detail,
|
|
12894
|
+
});
|
|
12895
|
+
}
|
|
12575
12896
|
const nextTaskInput = normalizeReviewNextTaskInput(body.next);
|
|
12576
12897
|
const actor = String(body.actor || DEFAULT_OWNER);
|
|
12577
12898
|
const resultText = String(body.result || '').replace(/\s+/g, ' ').trim();
|
|
@@ -12817,8 +13138,9 @@ async function runTaskCommand(args) {
|
|
|
12817
13138
|
const raw = args || [];
|
|
12818
13139
|
if (raw.includes('--help') || raw.includes('-h')) return help();
|
|
12819
13140
|
const first = raw[0];
|
|
12820
|
-
|
|
12821
|
-
const
|
|
13141
|
+
if (!first) return cmdFirstMinute();
|
|
13142
|
+
const sub = first.startsWith('--') ? 'desk' : first;
|
|
13143
|
+
const rest = first.startsWith('--') ? raw : raw.slice(1);
|
|
12822
13144
|
switch (sub) {
|
|
12823
13145
|
case 'desk': return cmdHome(rest);
|
|
12824
13146
|
case 'today': return cmdDay(rest);
|
|
@@ -12971,6 +13293,42 @@ const MUTATING_TASK_COMMANDS = new Set([
|
|
|
12971
13293
|
async function run(args) {
|
|
12972
13294
|
const raw = args || [];
|
|
12973
13295
|
const sub = !raw[0] || raw[0].startsWith('--') ? 'desk' : raw[0];
|
|
13296
|
+
// `task accept --help` is a help request, not a run. Accept mutates
|
|
13297
|
+
// review rows, so never list or accept just to show usage.
|
|
13298
|
+
if (sub === 'accept' && argsWantHelp(raw.slice(1))) {
|
|
13299
|
+
console.log('Usage: atris task accept <id> [--proof "..."] [--public]');
|
|
13300
|
+
return;
|
|
13301
|
+
}
|
|
13302
|
+
// `task claim --help` is a help request, not a run. Claim mutates
|
|
13303
|
+
// ownership, so never list or claim just to show usage.
|
|
13304
|
+
if (sub === 'claim' && argsWantHelp(raw.slice(1))) {
|
|
13305
|
+
console.log('Usage: atris task claim <id> --as <member>');
|
|
13306
|
+
return;
|
|
13307
|
+
}
|
|
13308
|
+
// `task ready --help` is a help request, not a run. Ready mutates
|
|
13309
|
+
// review state, so never list or ready just to show usage.
|
|
13310
|
+
if (sub === 'ready' && argsWantHelp(raw.slice(1))) {
|
|
13311
|
+
console.log('Usage: atris task ready <id> --proof "..." --result "<sentence>"');
|
|
13312
|
+
return;
|
|
13313
|
+
}
|
|
13314
|
+
// `task step --help` is a help request, not a run. Step mutates
|
|
13315
|
+
// Plan/Do/Review, so never list or step just to show usage.
|
|
13316
|
+
if (sub === 'step' && argsWantHelp(raw.slice(1))) {
|
|
13317
|
+
console.log('Usage: atris task step <id> [--json]');
|
|
13318
|
+
return;
|
|
13319
|
+
}
|
|
13320
|
+
// `task next --help` is a help request, not a run. Next can open
|
|
13321
|
+
// the task db or print the desk, so never list or claim just to show usage.
|
|
13322
|
+
if (sub === 'next' && argsWantHelp(raw.slice(1))) {
|
|
13323
|
+
console.log('Usage: atris task next [--tag <tag>] [--create-next]');
|
|
13324
|
+
return;
|
|
13325
|
+
}
|
|
13326
|
+
// `task show --help` is a help request, not a run. Show can dump
|
|
13327
|
+
// a task card or the encyclopedia, so never list or show just to show usage.
|
|
13328
|
+
if (sub === 'show' && argsWantHelp(raw.slice(1))) {
|
|
13329
|
+
console.log('Usage: atris task show <id> [--json]');
|
|
13330
|
+
return;
|
|
13331
|
+
}
|
|
12974
13332
|
const result = await runTaskCommand(raw);
|
|
12975
13333
|
const skipsRender = sub === 'clear-done' && hasFlag(raw, '--dry-run');
|
|
12976
13334
|
if (MUTATING_TASK_COMMANDS.has(sub) && !skipsRender) autoRenderTodoFromDb();
|