atris 3.74.24 → 3.74.26
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 +16 -0
- package/bin/atris.js +5 -0
- package/commands/gm.js +7 -3
- package/commands/rating.js +166 -0
- package/commands/task.js +28 -7
- package/commands/worktree.js +167 -76
- package/lib/atris-rating-combine.json +77 -0
- package/lib/atris-rating.js +179 -0
- package/lib/fleet.js +42 -2
- package/lib/gm-bet.js +2 -2
- package/lib/gm-season.js +67 -18
- package/lib/known-commands.js +1 -1
- package/lib/task-db.js +117 -7
- package/lib/team-lineup.js +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -459,6 +459,22 @@ atris scorecard run --models haiku,opus # compare models; past Haiku needs AT
|
|
|
459
459
|
- The scorecard shows how many changes each model did, how long it took, what the same runs would cost on pay-per-use, and which changes no model could do from what was written.
|
|
460
460
|
- Tests that need their own command or settings go in `.atris/scorecard.json`.
|
|
461
461
|
|
|
462
|
+
## The Atris Rating
|
|
463
|
+
|
|
464
|
+
`atris rating` gives every AI teammate one number, 25 to 99, for how much real work it finishes.
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
atris rating # every engine the combine rated, and your members here
|
|
468
|
+
atris rating opus # one engine's card
|
|
469
|
+
atris rating <member> # one member's rating here, next to its engine's
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
- 99 means 99 of every 100 finished. Each halving of misses is worth about 6 points, so the top is the hardest climb: 3 in a row rates 76, and it takes about 60 in a row to rate 99.
|
|
473
|
+
- Engines are rated in the combine: Loop Bench tasks from the atris repos, each graded by the tests that shipped with it. No engine is a 99 yet.
|
|
474
|
+
- Each engine's card also rates its Python tasks, its JavaScript tasks, the tasks the Atris prompt was never tuned on, and how rarely a try broke another test, with its median time and pay-per-use price per finished task.
|
|
475
|
+
- Members are rated on the same scale from the jobs they landed in your workspace over the last 30 days. Landed means accepted or merged; drops and abandons count against them. `atris gm` shows the same numbers.
|
|
476
|
+
- The session boot shows the build engine's rating, for example `build opus 5.5 (86 ovr)`. The combine grades building only, so review and search engines show none.
|
|
477
|
+
|
|
462
478
|
## Benchmark Harness
|
|
463
479
|
|
|
464
480
|
Atris ships one public head-to-head benchmark harness for comparing a pinned
|
package/bin/atris.js
CHANGED
|
@@ -652,6 +652,7 @@ function showHelpAll() {
|
|
|
652
652
|
console.log(' avail - Booking availability (/book/{username} weekly windows)');
|
|
653
653
|
console.log(' scoreboard - Today\'s github contributions vs your best day, streak, repo commits (--watch, --json)');
|
|
654
654
|
console.log(' scorecard - Which AI can do your team\'s work: past changes graded by their own tests, run on your Claude plan (find, run, show)');
|
|
655
|
+
console.log(' rating - The Atris Rating, 25 to 99: how much real work each engine and member finishes (atris rating opus)');
|
|
655
656
|
console.log(' brain - Compile MAP/TODO/wiki/state into a loadable agent brain');
|
|
656
657
|
console.log(' lesson - atris lesson add <slug> <pass|fail> "<text>" (mine/sweep/resolve/revert/ledger; --detector validates the falsifier at write time)');
|
|
657
658
|
console.log(' taste - Record the operator\'s keep, kill, and more creative verdicts');
|
|
@@ -2239,6 +2240,10 @@ if (command === 'guide') {
|
|
|
2239
2240
|
Promise.resolve().then(() => require('../commands/scorecard').scorecardCommand(process.argv.slice(3)))
|
|
2240
2241
|
.then((code) => exitAfterStdoutDrain(typeof code === 'number' ? code : 0))
|
|
2241
2242
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2243
|
+
} else if (command === 'rating') {
|
|
2244
|
+
Promise.resolve().then(() => require('../commands/rating').ratingCommand(process.argv.slice(3)))
|
|
2245
|
+
.then((code) => exitAfterStdoutDrain(typeof code === 'number' ? code : 0))
|
|
2246
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2242
2247
|
} else if (command === 'meet') {
|
|
2243
2248
|
Promise.resolve().then(() => require('../commands/meet').meetCommand(process.argv.slice(3)))
|
|
2244
2249
|
.then((code) => exitAfterStdoutDrain(typeof code === 'number' ? code : 0))
|
package/commands/gm.js
CHANGED
|
@@ -41,7 +41,9 @@ function showHelp() {
|
|
|
41
41
|
console.log(' what is up next. Every job a member takes in the last 30 days ends');
|
|
42
42
|
console.log(' landed (accepted or merged), dropped (claim let go), sent back, or');
|
|
43
43
|
console.log(' abandoned (archived without landing). Jobs in review are pending.');
|
|
44
|
-
console.log(' ovr =
|
|
44
|
+
console.log(' ovr = the Atris Rating of landed over finished, 25 to 99: 99 means 99');
|
|
45
|
+
console.log(' of every 100 and each halving of misses is worth about 6 (atris rating).');
|
|
46
|
+
console.log(' Rookie under 3 finished.');
|
|
45
47
|
console.log(' Drops and abandons count, so this is stricter than the website rating.');
|
|
46
48
|
console.log(' "on a job" means the claimed task moved in the last 6 hours; a claim');
|
|
47
49
|
console.log(' that sat longer shows as stuck, with its age and task id.');
|
|
@@ -936,8 +938,8 @@ function renderBoardLines(board, { interactive = false, width = termWidth(), bor
|
|
|
936
938
|
}
|
|
937
939
|
lines.push('');
|
|
938
940
|
|
|
939
|
-
lines.push(`key: ovr
|
|
940
|
-
lines.push('
|
|
941
|
+
lines.push(`key: ovr = the Atris Rating of finished jobs landed, 25 to 99, ${boxed ? 'new' : 'rookie'} under 3 finished.`);
|
|
942
|
+
lines.push(' 99 means 99 of every 100. drops and abandons count (atris rating)');
|
|
941
943
|
if (boxed) lines.push(' ·· = nothing to show yet: no finished job, no role, or no pinned model');
|
|
942
944
|
else lines.push(' form: last 5, newest right: k landed, d dropped, x sent back, a abandoned');
|
|
943
945
|
lines.push(' hours: claim to result. on a job: moved in the last 6h. review: pending');
|
|
@@ -1893,6 +1895,8 @@ function wakeableMember(args) {
|
|
|
1893
1895
|
}
|
|
1894
1896
|
|
|
1895
1897
|
async function gmCommand(...args) {
|
|
1898
|
+
const leaseDb = require('../lib/task-db');
|
|
1899
|
+
try { leaseDb.sweepExpiredLeases(); } catch (_) { /* Existing views report unreadable databases. */ }
|
|
1896
1900
|
// the walk has its own help
|
|
1897
1901
|
if (positional(args)[0] === 'walk') {
|
|
1898
1902
|
const at = args.indexOf('walk');
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// atris rating: the Atris Rating, one number from 25 to 99 for how much real
|
|
4
|
+
// work a teammate finishes. Engines are rated in the combine (Loop Bench);
|
|
5
|
+
// members are rated on the jobs they land here, the same numbers atris gm
|
|
6
|
+
// shows. Read only: nothing runs and nothing is written.
|
|
7
|
+
|
|
8
|
+
const { hasFlag } = require('../lib/arg-parser');
|
|
9
|
+
const { modelLabel } = require('../lib/roster-models');
|
|
10
|
+
const rating = require('../lib/atris-rating');
|
|
11
|
+
|
|
12
|
+
const USAGE = [
|
|
13
|
+
'usage: atris rating [engine | member] [--json]',
|
|
14
|
+
' how much real work each AI teammate finishes, one number from 25 to 99.',
|
|
15
|
+
'',
|
|
16
|
+
' atris rating every engine the combine rated, and your members here',
|
|
17
|
+
' atris rating opus one engine\'s card (opus, sonnet, haiku, or a model id)',
|
|
18
|
+
' atris rating <member> one member\'s rating here, next to its engine\'s',
|
|
19
|
+
' --json print it as json',
|
|
20
|
+
].join('\n');
|
|
21
|
+
|
|
22
|
+
// "an 86", "a 76": eighty-something, eleven, and eighteen start with a vowel.
|
|
23
|
+
function rated(n) {
|
|
24
|
+
return `${/^(8|11$|18$)/.test(String(n)) ? 'an' : 'a'} ${n}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Members rated on the last 30 days of jobs here, best first, each with the
|
|
28
|
+
// job and model the roster gives it, plus the build line: what the build
|
|
29
|
+
// engine rates in the combine and what members doing build landed here.
|
|
30
|
+
// null when there is no task list or no finished job to rate.
|
|
31
|
+
function readHere(deps = {}) {
|
|
32
|
+
let root = deps.root;
|
|
33
|
+
let played = deps.season;
|
|
34
|
+
try {
|
|
35
|
+
if (!root) root = require('../lib/task-db').workspaceRoot(process.cwd());
|
|
36
|
+
if (!played) played = require('../lib/gm-season').loadSeason(root, { lastSeen: null });
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (!played || played.error || played.no_history) return null;
|
|
41
|
+
const { rosterRows } = require('../lib/gm-season');
|
|
42
|
+
const rows = rosterRows({ outcomes: played.outcomes || [], limit: Number.MAX_SAFE_INTEGER }).filter((row) => row.finished > 0);
|
|
43
|
+
if (!rows.length) return null;
|
|
44
|
+
let lineup = deps.lineup;
|
|
45
|
+
if (lineup === undefined) lineup = require('../lib/team-lineup').readLineupSafe(root);
|
|
46
|
+
const team = new Map(((lineup && lineup.ok && lineup.team) || []).map((row) => [String(row.member || '').toLowerCase(), row]));
|
|
47
|
+
const members = rows.map((row) => {
|
|
48
|
+
const seat = team.get(row.name.toLowerCase()) || {};
|
|
49
|
+
const reasons = new Map();
|
|
50
|
+
for (const play of played.outcomes || []) {
|
|
51
|
+
if (play.member === row.name && ['dropped', 'sent_back', 'abandoned'].includes(play.kind) && play.reason) {
|
|
52
|
+
reasons.set(play.reason, (reasons.get(play.reason) || 0) + 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const miss_reasons = [...reasons].map(([reason, count]) => ({ reason, count }))
|
|
56
|
+
.sort((a, b) => b.count - a.count || a.reason.localeCompare(b.reason)).slice(0, 3);
|
|
57
|
+
return { member: row.name, ovr: row.ovr, landed: row.landed, finished: row.finished, job: seat.job || null, model: seat.model || null, ...(miss_reasons.length ? { miss_reasons } : {}) };
|
|
58
|
+
});
|
|
59
|
+
const buildJob = ((lineup && lineup.ok && lineup.jobs) || []).find((row) => row.job === 'build' && !row.key);
|
|
60
|
+
const buildModel = buildJob && buildJob.now_runs ? buildJob.now_runs.model : null;
|
|
61
|
+
const card = buildModel ? rating.combineCards().find((c) => c.model === buildModel) : null;
|
|
62
|
+
const builders = members.filter((m) => m.job === 'build');
|
|
63
|
+
const landed = builders.reduce((sum, m) => sum + m.landed, 0);
|
|
64
|
+
const finished = builders.reduce((sum, m) => sum + m.finished, 0);
|
|
65
|
+
return {
|
|
66
|
+
workspace: played.workspace_name || null,
|
|
67
|
+
members,
|
|
68
|
+
build: card && finished ? { model: buildModel, combine_ovr: card.ovr, landed, finished, ovr: rating.atrisRating(landed, finished) } : null,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function renderHere(here) {
|
|
73
|
+
const ranked = here.members.filter((m) => m.ovr != null);
|
|
74
|
+
const fresh = here.members.filter((m) => m.ovr == null);
|
|
75
|
+
const nameW = Math.min(24, Math.max(6, ...ranked.map((m) => m.member.length))) + 2;
|
|
76
|
+
const lines = [`here${here.workspace ? `: ${here.workspace}` : ''}, last 30 days, the same ratings as atris gm`, ''];
|
|
77
|
+
if (ranked.length) {
|
|
78
|
+
lines.push(` ${'ovr'.padEnd(5)}${'member'.padEnd(nameW)}${'landed'.padEnd(11)}${'job'.padEnd(8)}model`);
|
|
79
|
+
for (const m of ranked) {
|
|
80
|
+
const name = m.member.length > nameW - 2 ? `${m.member.slice(0, nameW - 5)}...` : m.member;
|
|
81
|
+
lines.push(` ${String(m.ovr).padEnd(5)}${name.padEnd(nameW)}${`${m.landed} of ${m.finished}`.padEnd(11)}${(m.job || '').padEnd(8)}${m.model ? modelLabel(m.model) : ''}`.trimEnd());
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
lines.push(' no member has 3 finished jobs here yet');
|
|
85
|
+
}
|
|
86
|
+
if (fresh.length) {
|
|
87
|
+
const names = fresh.map((m) => m.member);
|
|
88
|
+
const head = `new, under 3 finished jobs (${names.length}): `;
|
|
89
|
+
const shown = [];
|
|
90
|
+
for (const name of names) {
|
|
91
|
+
if (head.length + [...shown, name].join(', ').length + ', and 99 more'.length > 80) break;
|
|
92
|
+
shown.push(name);
|
|
93
|
+
}
|
|
94
|
+
const rest = names.length - shown.length;
|
|
95
|
+
lines.push('', `${head}${shown.join(', ')}${rest ? `, and ${rest} more` : ''}`);
|
|
96
|
+
}
|
|
97
|
+
lines.push('landed: accepted or merged. drops and abandons count against a member.');
|
|
98
|
+
if (here.build) {
|
|
99
|
+
const b = here.build;
|
|
100
|
+
lines.push('', `build runs ${modelLabel(b.model)}, ${rated(b.combine_ovr)} in the combine.`,
|
|
101
|
+
`members doing build here landed ${b.landed} of ${b.finished} jobs, ${rated(b.ovr)}.`);
|
|
102
|
+
}
|
|
103
|
+
return lines.join('\n');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function renderMember(m, card) {
|
|
107
|
+
const job = m.job ? `, ${m.job}${m.model ? ` on ${modelLabel(m.model)}` : ''}` : '';
|
|
108
|
+
const head = `${m.member}${job}`;
|
|
109
|
+
const lines = [
|
|
110
|
+
`${head}${' '.repeat(Math.max(2, 44 - head.length))}${m.ovr == null ? 'new' : `${m.ovr} ovr`} here`,
|
|
111
|
+
'',
|
|
112
|
+
` landed ${m.landed} of ${m.finished} finished jobs in the last 30 days`,
|
|
113
|
+
];
|
|
114
|
+
if (m.ovr == null) lines.push(' rated once it has 3 finished jobs');
|
|
115
|
+
if (m.miss_reasons && m.miss_reasons.length) {
|
|
116
|
+
lines.push(' top miss reasons:');
|
|
117
|
+
for (const item of m.miss_reasons) lines.push(` ${item.count}: ${item.reason}`);
|
|
118
|
+
}
|
|
119
|
+
if (card && m.job === 'build') lines.push(` its engine, ${card.label}, is ${rated(card.ovr)} in the combine: atris rating ${card.label.split(' ')[0]}`);
|
|
120
|
+
lines.push(` every play: atris gm card ${m.member}`);
|
|
121
|
+
return lines.join('\n');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function ratingCommand(args = [], deps = {}) {
|
|
125
|
+
const taskDb = require('../lib/task-db');
|
|
126
|
+
taskDb.sweepExpiredLeases();
|
|
127
|
+
const write = deps.write || ((text) => process.stdout.write(text));
|
|
128
|
+
if (hasFlag(args, '--help') || hasFlag(args, '-h') || args[0] === 'help') {
|
|
129
|
+
write(`${USAGE}\n`);
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
const json = hasFlag(args, '--json');
|
|
133
|
+
const name = args.filter((arg) => !arg.startsWith('-')).join(' ').trim();
|
|
134
|
+
const cards = rating.combineCards();
|
|
135
|
+
if (name) {
|
|
136
|
+
const card = rating.combineCardFor(name);
|
|
137
|
+
if (card) {
|
|
138
|
+
write(json ? `${JSON.stringify({ schema: 'atris.rating.v1', engine: card }, null, 2)}\n` : `${rating.renderCard(card)}\n`);
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
const here = readHere(deps);
|
|
142
|
+
const member = here && here.members.find((m) => m.member.toLowerCase() === name.toLowerCase());
|
|
143
|
+
if (member) {
|
|
144
|
+
const own = member.model ? cards.find((c) => c.model === member.model) || null : null;
|
|
145
|
+
write(json ? `${JSON.stringify({ schema: 'atris.rating.v1', member, engine: member.job === 'build' ? own : null }, null, 2)}\n` : `${renderMember(member, own)}\n`);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
const err = deps.error || ((text) => process.stderr.write(text));
|
|
149
|
+
err(`no engine or member called "${name}" is rated. engines: ${cards.map((c) => c.label).join(', ')}. members show once they finish a job here.\n`);
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
const here = readHere(deps);
|
|
153
|
+
if (json) {
|
|
154
|
+
write(`${JSON.stringify({
|
|
155
|
+
schema: 'atris.rating.v1',
|
|
156
|
+
scale: { floor: 25, top: 99, means: rating.SCALE_LINES.join(' ') },
|
|
157
|
+
combine: { bench: rating.COMBINE.bench, month: rating.COMBINE.month, tasks: rating.COMBINE.tasks, unseen: rating.COMBINE.unseen, engines: cards },
|
|
158
|
+
here,
|
|
159
|
+
}, null, 2)}\n`);
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
write(`${rating.renderCombine(cards)}${here ? `\n\n${renderHere(here)}` : ''}\n`);
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = { ratingCommand, USAGE };
|
package/commands/task.js
CHANGED
|
@@ -208,6 +208,7 @@ atris task - durable local task state (SQLite, gitignored)
|
|
|
208
208
|
atris task auto-accept-certified --dry-run [--strict-verify] [--all] [--limit <n>]
|
|
209
209
|
Preview certified Review rows; live accept needs --confirm-human-accept --as <human>
|
|
210
210
|
atris task sweep --auto-accept [--json] Auto-accept verified Review rows; protected lanes wait for human
|
|
211
|
+
atris task sweep [--json] [--stale-days N] [--claimer NAME] [--dry-run] Release expired claims
|
|
211
212
|
atris task audit [--limit <n>] [--revise] re-run stored verifies for newest accepted tasks; report-only unless --revise
|
|
212
213
|
atris task revise <id> --note "..." Send reviewed work back to Do
|
|
213
214
|
|
|
@@ -6252,7 +6253,10 @@ function cmdClaim(args) {
|
|
|
6252
6253
|
const taskDb = getTaskDb();
|
|
6253
6254
|
const db = taskDb.open();
|
|
6254
6255
|
const taskId = requireTaskId(taskDb, db, id, 'atris task claim');
|
|
6255
|
-
const
|
|
6256
|
+
const leaseMinutes = flag(args, '--lease-minutes');
|
|
6257
|
+
const leasePid = flag(args, '--lease-pid');
|
|
6258
|
+
if (leaseMinutes != null && (!Number.isFinite(Number(leaseMinutes)) || Number(leaseMinutes) <= 0 || !Number.isInteger(Number(leasePid)) || Number(leasePid) <= 0)) throw new Error('invalid claim lease');
|
|
6259
|
+
const result = taskDb.claimTask(db, { id: taskId, claimedBy: String(owner), ...(leaseMinutes == null ? {} : { leaseMinutes: Number(leaseMinutes), leasePid: Number(leasePid) }) });
|
|
6256
6260
|
if (result.claimed) {
|
|
6257
6261
|
const { projection, outPath } = writeDefaultProjection(taskDb, db);
|
|
6258
6262
|
if (wantsJson(args)) {
|
|
@@ -10801,11 +10805,23 @@ function evaluateSweepAutoAccept(task, root, includeProtected = false) {
|
|
|
10801
10805
|
|
|
10802
10806
|
function cmdSweep(args) {
|
|
10803
10807
|
if (!hasFlag(args, '--auto-accept')) {
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
);
|
|
10808
|
+
const taskDb = getTaskDb();
|
|
10809
|
+
const staleRaw = flag(args, '--stale-days');
|
|
10810
|
+
if (staleRaw === true || (staleRaw != null && (!Number.isFinite(Number(staleRaw)) || Number(staleRaw) < 0))) throw new Error('stale days must be a nonnegative number');
|
|
10811
|
+
const claimer = flag(args, '--claimer');
|
|
10812
|
+
if (claimer === true) throw new Error('claimer requires a name');
|
|
10813
|
+
const dryRun = hasFlag(args, '--dry-run');
|
|
10814
|
+
const options = { staleDays: staleRaw == null ? undefined : Number(staleRaw), claimer };
|
|
10815
|
+
const tasks = dryRun ? taskDb.previewExpiredLeases(options) : taskDb.expireLeases(taskDb.open(), options);
|
|
10816
|
+
const groups = {};
|
|
10817
|
+
for (const task of tasks) (groups[task.claimed_by] ||= []).push(task);
|
|
10818
|
+
if (wantsJson(args)) printJson({ dry_run: dryRun, groups, tasks });
|
|
10819
|
+
else if (!tasks.length) console.log(dryRun ? 'no claims would be released' : 'no claims released');
|
|
10820
|
+
else for (const [name, entries] of Object.entries(groups)) {
|
|
10821
|
+
console.log(`${name}: ${entries.length} ${dryRun ? 'would be released' : 'released'}`);
|
|
10822
|
+
for (const entry of entries) console.log(` ${entry.title}: ${entry.reason}`);
|
|
10823
|
+
}
|
|
10824
|
+
return;
|
|
10809
10825
|
}
|
|
10810
10826
|
// Sweep has no dry-run implementation: every successful invocation can
|
|
10811
10827
|
// write accepts, even when an unrecognized --dry-run flag is supplied.
|
|
@@ -13076,6 +13092,11 @@ function cmdServe(args) {
|
|
|
13076
13092
|
|
|
13077
13093
|
async function runTaskCommand(args) {
|
|
13078
13094
|
const raw = args || [];
|
|
13095
|
+
// A dry run must not mutate even already-expired leases.
|
|
13096
|
+
if (!raw.includes('--dry-run') && !(raw[0] === 'sweep' && !raw.includes('--auto-accept'))) {
|
|
13097
|
+
const taskDb = getTaskDb();
|
|
13098
|
+
taskDb.sweepExpiredLeases();
|
|
13099
|
+
}
|
|
13079
13100
|
if (raw.includes('--help') || raw.includes('-h')) return help();
|
|
13080
13101
|
const first = raw[0];
|
|
13081
13102
|
if (!first) return cmdFirstMinute();
|
|
@@ -13273,7 +13294,7 @@ async function run(args) {
|
|
|
13273
13294
|
return;
|
|
13274
13295
|
}
|
|
13275
13296
|
const result = await runTaskCommand(raw);
|
|
13276
|
-
const skipsRender =
|
|
13297
|
+
const skipsRender = hasFlag(raw, '--dry-run');
|
|
13277
13298
|
if (MUTATING_TASK_COMMANDS.has(sub) && !skipsRender) autoRenderTodoFromDb();
|
|
13278
13299
|
return result;
|
|
13279
13300
|
}
|