rodo-spec 2.2.1 → 2.4.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/LICENSE +21 -21
- package/README.md +287 -286
- package/dist/index.js +131 -73
- package/dist/kit/.agents/skills/rodo/SKILL.md +4 -1
- package/dist/kit/.agents/skills/rodo/clean.md +33 -0
- package/dist/kit/.agents/skills/rodo/coder.md +86 -82
- package/dist/kit/.agents/skills/rodo/review.md +30 -0
- package/dist/kit/.agents/skills/rodo/templates/card.rodo.md +2 -1
- package/dist/kit/.agents/skills/rodo/templates/en/card.rodo.md +33 -32
- package/dist/kit/KIT_VERSION +1 -1
- package/dist/kit/MIGRATION.md +6 -0
- package/dist/kit/agents-block.md +1 -1
- package/dist/kit/kit-manifest.json +23 -13
- package/dist/kit/project-template-en/RULES.md +1 -1
- package/package.json +11 -12
package/dist/index.js
CHANGED
|
@@ -11057,7 +11057,7 @@ function ensureBlock(path, block, kit20Hashes, importsAgents, dryRun = false) {
|
|
|
11057
11057
|
// package.json
|
|
11058
11058
|
var package_default = {
|
|
11059
11059
|
name: "rodo-spec",
|
|
11060
|
-
version: "2.
|
|
11060
|
+
version: "2.4.0",
|
|
11061
11061
|
description: "RODO method CLI \u2014 install the kit, manage cards, sync with the board",
|
|
11062
11062
|
license: "MIT",
|
|
11063
11063
|
type: "module",
|
|
@@ -11470,8 +11470,8 @@ function parseHours(v) {
|
|
|
11470
11470
|
function readFields(data, keyLine, order) {
|
|
11471
11471
|
const m = emptyModel();
|
|
11472
11472
|
const out = [];
|
|
11473
|
-
const
|
|
11474
|
-
const add = (code, k, args = {}) => out.push(finding(code,
|
|
11473
|
+
const L2 = (k) => keyLine[k] ?? null;
|
|
11474
|
+
const add = (code, k, args = {}) => out.push(finding(code, L2(k), args));
|
|
11475
11475
|
for (const k of order) {
|
|
11476
11476
|
if (KNOWN.has(k) || k.startsWith("x-"))
|
|
11477
11477
|
continue;
|
|
@@ -13088,6 +13088,129 @@ async function runDoctor(ctx) {
|
|
|
13088
13088
|
return 0;
|
|
13089
13089
|
}
|
|
13090
13090
|
|
|
13091
|
+
// src/core/i18n.ts
|
|
13092
|
+
var T = {
|
|
13093
|
+
"resume.none": { fa: "\u06A9\u0627\u0631\u062A \u0641\u0639\u0627\u0644\u06CC \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F", en: "no active card found" },
|
|
13094
|
+
"resume.several": { fa: "\u0686\u0646\u062F \u06A9\u0627\u0631\u062A \u0641\u0639\u0627\u0644 \u0647\u0633\u062A\u061B \u06CC\u06A9\u06CC \u0631\u0627 \u0645\u0634\u062E\u0635 \u06A9\u0646\u06CC\u062F", en: "several active cards; name one" },
|
|
13095
|
+
"resume.never": { fa: "\u0627\u06CC\u0646 \u067E\u0631\u0648\u0698\u0647 \u0647\u0646\u0648\u0632 \u0647\u06CC\u0686\u200C\u0648\u0642\u062A sync \u0646\u0634\u062F\u0647\u061B rodo sync \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F", en: "this project has never been synced; run rodo sync" },
|
|
13096
|
+
"resume.stale": { fa: "\u0622\u062E\u0631\u06CC\u0646 sync \u0628\u06CC\u0634 \u0627\u0632 \u06CC\u06A9 \u0633\u0627\u0639\u062A \u067E\u06CC\u0634 \u0628\u0648\u062F\u0647\u061B rodo sync \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F", en: "last sync is older than 1 hour; run rodo sync" },
|
|
13097
|
+
"status.waitingDecision": { fa: "\u0645\u0646\u062A\u0638\u0631 \u062A\u0635\u0645\u06CC\u0645 \u0634\u0645\u0627", en: "waiting for your decision" },
|
|
13098
|
+
"status.waitingApproval": { fa: "\u0645\u0646\u062A\u0638\u0631 \u062A\u0623\u06CC\u06CC\u062F \u0634\u0645\u0627", en: "waiting for approval" },
|
|
13099
|
+
"test.none": { fa: "\u0628\u0631\u0627\u06CC \u0627\u06CC\u0646 \u06A9\u0627\u0631\u062A \u062F\u0633\u062A\u0648\u0631 \u062A\u0633\u062A \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 (\u062A\u0633\u062A \u0627\u062E\u062A\u06CC\u0627\u0631\u06CC \u0627\u0633\u062A)", en: "no test command for this card (tests are optional)" },
|
|
13100
|
+
"offline.note": { fa: "\u062D\u0627\u0644\u062A \u0622\u0641\u0644\u0627\u06CC\u0646: \u0641\u0642\u0637 \u0628\u0631\u0631\u0633\u06CC \u06A9\u0627\u0631\u062A\u200C\u0647\u0627 \u0627\u0646\u062C\u0627\u0645 \u0634\u062F", en: "offline: cards were validated only" }
|
|
13101
|
+
};
|
|
13102
|
+
function pickLang(flag, projectLang) {
|
|
13103
|
+
return flag === "fa" || flag === "en" ? flag : projectLang === "en" ? "en" : "fa";
|
|
13104
|
+
}
|
|
13105
|
+
var t = (lang, key2) => T[key2]?.[lang] ?? key2;
|
|
13106
|
+
|
|
13107
|
+
// src/commands/shared.ts
|
|
13108
|
+
var LEGACY_MSG = "LEGACY_LAYOUT: run rodo init to move rodo/ into rodo/<project>/";
|
|
13109
|
+
function load(ctx, defaultToCwd) {
|
|
13110
|
+
const d = discover(ctx.cwd);
|
|
13111
|
+
const refs = selectProjects(d, ctx.opts.project ?? [], defaultToCwd);
|
|
13112
|
+
const broken = refs.find((r) => r.problem);
|
|
13113
|
+
if (broken) throw new CliError("PROJECT_INVALID", `rodo/${broken.slug}: ${broken.problem}`, 3);
|
|
13114
|
+
if (!refs.length) throw notRepo("no RODO project found: run rodo init --method-only");
|
|
13115
|
+
return { d, refs };
|
|
13116
|
+
}
|
|
13117
|
+
var fmt = (c, f, icon) => ` ${icon} ${c.path}${f.line ? `:${f.line}` : ""} ${f.message}`;
|
|
13118
|
+
function printFindings(ctx, cards) {
|
|
13119
|
+
for (const c of cards) {
|
|
13120
|
+
for (const f of c.errors) ctx.out.line(fmt(c, f, mark.err));
|
|
13121
|
+
for (const f of c.warnings) ctx.out.line(fmt(c, f, mark.warn));
|
|
13122
|
+
}
|
|
13123
|
+
}
|
|
13124
|
+
var sum = (cards) => ({
|
|
13125
|
+
files: cards.length,
|
|
13126
|
+
errors: cards.reduce((n, c) => n + c.errors.length, 0),
|
|
13127
|
+
warnings: cards.reduce((n, c) => n + c.warnings.length, 0)
|
|
13128
|
+
});
|
|
13129
|
+
var slim = (f) => ({ code: f.code, line: f.line, message: f.message });
|
|
13130
|
+
|
|
13131
|
+
// src/commands/select.ts
|
|
13132
|
+
function oneProject(ctx) {
|
|
13133
|
+
const { d, refs } = load(ctx, true);
|
|
13134
|
+
if (refs.length !== 1) throw usage(`several projects (${refs.map((r) => r.slug).join(", ")}): use --project <slug>`);
|
|
13135
|
+
return { d, ref: refs[0] };
|
|
13136
|
+
}
|
|
13137
|
+
function pickCard(cards, query) {
|
|
13138
|
+
if (query) {
|
|
13139
|
+
const c = findCard(cards, query);
|
|
13140
|
+
if (!c) throw usage(`no card matches "${query}"`);
|
|
13141
|
+
return c;
|
|
13142
|
+
}
|
|
13143
|
+
for (const status of ["in_progress", "blocked"]) {
|
|
13144
|
+
const list = cards.filter((c) => c.model?.status === status);
|
|
13145
|
+
if (list.length === 1) return list[0];
|
|
13146
|
+
if (list.length > 1) throw usage(`several ${status} cards, name one:
|
|
13147
|
+
${list.map((c) => ` ${c.number ?? c.key} ${c.model?.title}`).join("\n")}`);
|
|
13148
|
+
}
|
|
13149
|
+
throw new CliError("NO_ACTIVE_CARD", "no in_progress or blocked card; name one (rodo resume <card>)", 2);
|
|
13150
|
+
}
|
|
13151
|
+
function projectCards(ctx) {
|
|
13152
|
+
const { d, ref } = oneProject(ctx);
|
|
13153
|
+
return { d, ref, cards: scanCards(d.root, ref) };
|
|
13154
|
+
}
|
|
13155
|
+
|
|
13156
|
+
// src/commands/explain.ts
|
|
13157
|
+
var L = {
|
|
13158
|
+
status_todo: { fa: "\u0628\u0631\u0646\u0627\u0645\u0647\u200C\u0631\u06CC\u0632\u06CC \u0634\u062F\u0647\u060C \u0647\u0646\u0648\u0632 \u0634\u0631\u0648\u0639 \u0646\u0634\u062F\u0647", en: "planned, not started yet" },
|
|
13159
|
+
status_in_progress: { fa: "\u062F\u0631 \u062D\u0627\u0644 \u0627\u0646\u062C\u0627\u0645", en: "in progress" },
|
|
13160
|
+
status_blocked: { fa: "\u0645\u062A\u0648\u0642\u0641 \u0634\u062F\u0647", en: "stopped" },
|
|
13161
|
+
status_cancelled: { fa: "\u0644\u063A\u0648 \u0634\u062F\u0647", en: "cancelled" },
|
|
13162
|
+
status_done: { fa: "\u062A\u0645\u0627\u0645 \u0634\u062F\u0647", en: "finished" },
|
|
13163
|
+
what: { fa: "\u0686\u0647 \u0686\u06CC\u0632\u06CC \u0645\u06CC\u200C\u06AF\u06CC\u0631\u06CC\u062F", en: "What you get" },
|
|
13164
|
+
state: { fa: "\u0648\u0636\u0639\u06CC\u062A", en: "State" },
|
|
13165
|
+
steps: { fa: "\u0642\u062F\u0645\u200C\u0647\u0627", en: "Steps" },
|
|
13166
|
+
left: { fa: "\u0628\u0627\u0642\u06CC\u200C\u0645\u0627\u0646\u062F\u0647", en: "Still to do" },
|
|
13167
|
+
why: { fa: "\u062F\u0644\u06CC\u0644 \u062A\u0648\u0642\u0641", en: "Why it stopped" },
|
|
13168
|
+
noText: { fa: "\u0647\u0646\u0648\u0632 \u062A\u0648\u0636\u06CC\u062D \u0633\u0627\u062F\u0647\u200C\u0627\u06CC \u0628\u0631\u0627\u06CC \u0627\u06CC\u0646 \u06A9\u0627\u0631\u062A \u0646\u0648\u0634\u062A\u0647 \u0646\u0634\u062F\u0647", en: "no plain description has been written for this card yet" }
|
|
13169
|
+
};
|
|
13170
|
+
function intro(body) {
|
|
13171
|
+
const out = [];
|
|
13172
|
+
for (const raw of body.split(/\r?\n/)) {
|
|
13173
|
+
if (raw.startsWith("## ")) break;
|
|
13174
|
+
const l = raw.trim();
|
|
13175
|
+
if (l && !/\{\{.*\}\}/.test(l)) out.push(l);
|
|
13176
|
+
}
|
|
13177
|
+
return out;
|
|
13178
|
+
}
|
|
13179
|
+
async function runExplain(ctx, query) {
|
|
13180
|
+
const { ref, cards } = projectCards(ctx);
|
|
13181
|
+
const card = pickCard(cards, query);
|
|
13182
|
+
const m = card.model;
|
|
13183
|
+
if (!m) {
|
|
13184
|
+
ctx.out.line(`${card.path} is not a readable card:`);
|
|
13185
|
+
for (const e2 of card.errors) ctx.out.line(` ${e2.message}`);
|
|
13186
|
+
ctx.out.flush({ version: 1, card: card.key, errors: card.errors });
|
|
13187
|
+
return 2;
|
|
13188
|
+
}
|
|
13189
|
+
const lang = pickLang(ctx.opts.lang, ref.project?.language.simple);
|
|
13190
|
+
const tr = (k) => L[k][lang];
|
|
13191
|
+
const items = m.checklists.flatMap((c) => c.items);
|
|
13192
|
+
const done = items.filter((i) => i.isDone).length;
|
|
13193
|
+
const left = items.filter((i) => !i.isDone).map((i) => i.title).slice(0, 5);
|
|
13194
|
+
const text = intro(m.description);
|
|
13195
|
+
const title = card.number ? cardLabel(card.number, m.title, " \u2014 ") : m.title;
|
|
13196
|
+
ctx.out.line(title);
|
|
13197
|
+
ctx.out.line(`${tr("state")}: ${tr(`status_${m.status}`)}`);
|
|
13198
|
+
if (m.statusReason) ctx.out.line(`${tr("why")}: ${m.statusReason}`);
|
|
13199
|
+
ctx.out.line("");
|
|
13200
|
+
ctx.out.line(`${tr("what")}:`);
|
|
13201
|
+
(text.length ? text : [tr("noText")]).forEach((l) => ctx.out.line(` ${l}`));
|
|
13202
|
+
if (items.length) {
|
|
13203
|
+
ctx.out.line("");
|
|
13204
|
+
ctx.out.line(`${tr("steps")}: ${done}/${items.length}`);
|
|
13205
|
+
if (left.length) {
|
|
13206
|
+
ctx.out.line(`${tr("left")}:`);
|
|
13207
|
+
left.forEach((l) => ctx.out.line(` - ${l}`));
|
|
13208
|
+
}
|
|
13209
|
+
}
|
|
13210
|
+
ctx.out.flush({ version: 1, card: card.key, title: m.title, status: m.status, statusReason: m.statusReason ?? null, plain: text, steps: { done, total: items.length }, remaining: left });
|
|
13211
|
+
return 0;
|
|
13212
|
+
}
|
|
13213
|
+
|
|
13091
13214
|
// src/commands/init.ts
|
|
13092
13215
|
import { existsSync as existsSync14 } from "fs";
|
|
13093
13216
|
import { basename as basename2, join as join14 } from "path";
|
|
@@ -13259,13 +13382,13 @@ function withMarker(raw, marker) {
|
|
|
13259
13382
|
const next = bom + (marker ? marker + eol : "") + rest;
|
|
13260
13383
|
return next === raw ? null : next;
|
|
13261
13384
|
}
|
|
13262
|
-
var
|
|
13385
|
+
var slim2 = (f) => ({ code: f.code, line: f.line, message: f.message });
|
|
13263
13386
|
function buildReport(slug2, cards, startedAt, over = {}, extra = /* @__PURE__ */ new Map()) {
|
|
13264
13387
|
const merged = cards.map((c) => {
|
|
13265
13388
|
const x = extra.get(c.path);
|
|
13266
13389
|
return { c, errors: [...c.errors, ...x?.errors ?? []], warnings: [...c.warnings, ...x?.warnings ?? []] };
|
|
13267
13390
|
});
|
|
13268
|
-
const files = merged.filter((m) => m.errors.length || m.warnings.length).map((m) => ({ path: m.c.path, cardId: m.c.model?.id ?? null, errors: m.errors.map(
|
|
13391
|
+
const files = merged.filter((m) => m.errors.length || m.warnings.length).map((m) => ({ path: m.c.path, cardId: m.c.model?.id ?? null, errors: m.errors.map(slim2), warnings: m.warnings.map(slim2) }));
|
|
13269
13392
|
return {
|
|
13270
13393
|
version: 1,
|
|
13271
13394
|
project: slug2,
|
|
@@ -14069,32 +14192,6 @@ async function chooseLanguage(ctx, env = process.env) {
|
|
|
14069
14192
|
// src/commands/new.ts
|
|
14070
14193
|
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readdirSync as readdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync3 } from "fs";
|
|
14071
14194
|
import { join as join15, relative as relative5, sep as sep2 } from "path";
|
|
14072
|
-
|
|
14073
|
-
// src/commands/shared.ts
|
|
14074
|
-
var LEGACY_MSG = "LEGACY_LAYOUT: run rodo init to move rodo/ into rodo/<project>/";
|
|
14075
|
-
function load(ctx, defaultToCwd) {
|
|
14076
|
-
const d = discover(ctx.cwd);
|
|
14077
|
-
const refs = selectProjects(d, ctx.opts.project ?? [], defaultToCwd);
|
|
14078
|
-
const broken = refs.find((r) => r.problem);
|
|
14079
|
-
if (broken) throw new CliError("PROJECT_INVALID", `rodo/${broken.slug}: ${broken.problem}`, 3);
|
|
14080
|
-
if (!refs.length) throw notRepo("no RODO project found: run rodo init --method-only");
|
|
14081
|
-
return { d, refs };
|
|
14082
|
-
}
|
|
14083
|
-
var fmt = (c, f, icon) => ` ${icon} ${c.path}${f.line ? `:${f.line}` : ""} ${f.message}`;
|
|
14084
|
-
function printFindings(ctx, cards) {
|
|
14085
|
-
for (const c of cards) {
|
|
14086
|
-
for (const f of c.errors) ctx.out.line(fmt(c, f, mark.err));
|
|
14087
|
-
for (const f of c.warnings) ctx.out.line(fmt(c, f, mark.warn));
|
|
14088
|
-
}
|
|
14089
|
-
}
|
|
14090
|
-
var sum = (cards) => ({
|
|
14091
|
-
files: cards.length,
|
|
14092
|
-
errors: cards.reduce((n, c) => n + c.errors.length, 0),
|
|
14093
|
-
warnings: cards.reduce((n, c) => n + c.warnings.length, 0)
|
|
14094
|
-
});
|
|
14095
|
-
var slim2 = (f) => ({ code: f.code, line: f.line, message: f.message });
|
|
14096
|
-
|
|
14097
|
-
// src/commands/new.ts
|
|
14098
14195
|
function slugify2(title) {
|
|
14099
14196
|
return title.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").split("-").slice(0, 6).join("-");
|
|
14100
14197
|
}
|
|
@@ -14159,22 +14256,6 @@ async function runNew(ctx, title, o) {
|
|
|
14159
14256
|
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
|
|
14160
14257
|
import { dirname as dirname8, join as join17 } from "path";
|
|
14161
14258
|
|
|
14162
|
-
// src/core/i18n.ts
|
|
14163
|
-
var T = {
|
|
14164
|
-
"resume.none": { fa: "\u06A9\u0627\u0631\u062A \u0641\u0639\u0627\u0644\u06CC \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F", en: "no active card found" },
|
|
14165
|
-
"resume.several": { fa: "\u0686\u0646\u062F \u06A9\u0627\u0631\u062A \u0641\u0639\u0627\u0644 \u0647\u0633\u062A\u061B \u06CC\u06A9\u06CC \u0631\u0627 \u0645\u0634\u062E\u0635 \u06A9\u0646\u06CC\u062F", en: "several active cards; name one" },
|
|
14166
|
-
"resume.never": { fa: "\u0627\u06CC\u0646 \u067E\u0631\u0648\u0698\u0647 \u0647\u0646\u0648\u0632 \u0647\u06CC\u0686\u200C\u0648\u0642\u062A sync \u0646\u0634\u062F\u0647\u061B rodo sync \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F", en: "this project has never been synced; run rodo sync" },
|
|
14167
|
-
"resume.stale": { fa: "\u0622\u062E\u0631\u06CC\u0646 sync \u0628\u06CC\u0634 \u0627\u0632 \u06CC\u06A9 \u0633\u0627\u0639\u062A \u067E\u06CC\u0634 \u0628\u0648\u062F\u0647\u061B rodo sync \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F", en: "last sync is older than 1 hour; run rodo sync" },
|
|
14168
|
-
"status.waitingDecision": { fa: "\u0645\u0646\u062A\u0638\u0631 \u062A\u0635\u0645\u06CC\u0645 \u0634\u0645\u0627", en: "waiting for your decision" },
|
|
14169
|
-
"status.waitingApproval": { fa: "\u0645\u0646\u062A\u0638\u0631 \u062A\u0623\u06CC\u06CC\u062F \u0634\u0645\u0627", en: "waiting for approval" },
|
|
14170
|
-
"test.none": { fa: "\u0628\u0631\u0627\u06CC \u0627\u06CC\u0646 \u06A9\u0627\u0631\u062A \u062F\u0633\u062A\u0648\u0631 \u062A\u0633\u062A \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 (\u062A\u0633\u062A \u0627\u062E\u062A\u06CC\u0627\u0631\u06CC \u0627\u0633\u062A)", en: "no test command for this card (tests are optional)" },
|
|
14171
|
-
"offline.note": { fa: "\u062D\u0627\u0644\u062A \u0622\u0641\u0644\u0627\u06CC\u0646: \u0641\u0642\u0637 \u0628\u0631\u0631\u0633\u06CC \u06A9\u0627\u0631\u062A\u200C\u0647\u0627 \u0627\u0646\u062C\u0627\u0645 \u0634\u062F", en: "offline: cards were validated only" }
|
|
14172
|
-
};
|
|
14173
|
-
function pickLang(flag, projectLang) {
|
|
14174
|
-
return flag === "fa" || flag === "en" ? flag : projectLang === "en" ? "en" : "fa";
|
|
14175
|
-
}
|
|
14176
|
-
var t = (lang, key2) => T[key2]?.[lang] ?? key2;
|
|
14177
|
-
|
|
14178
14259
|
// src/core/time.ts
|
|
14179
14260
|
var fmtFor = (timeZone) => new Intl.DateTimeFormat("sv-SE", {
|
|
14180
14261
|
timeZone,
|
|
@@ -14431,31 +14512,6 @@ function streak(previous, sig) {
|
|
|
14431
14512
|
}
|
|
14432
14513
|
var STUCK_MESSAGE = (sig) => `RODO_STUCK: the same failure happened twice (${sig}). Per the RODO method: set status: blocked, blockerType: test or technical, write the reason in statusReason, and ask the user.`;
|
|
14433
14514
|
|
|
14434
|
-
// src/commands/select.ts
|
|
14435
|
-
function oneProject(ctx) {
|
|
14436
|
-
const { d, refs } = load(ctx, true);
|
|
14437
|
-
if (refs.length !== 1) throw usage(`several projects (${refs.map((r) => r.slug).join(", ")}): use --project <slug>`);
|
|
14438
|
-
return { d, ref: refs[0] };
|
|
14439
|
-
}
|
|
14440
|
-
function pickCard(cards, query) {
|
|
14441
|
-
if (query) {
|
|
14442
|
-
const c = findCard(cards, query);
|
|
14443
|
-
if (!c) throw usage(`no card matches "${query}"`);
|
|
14444
|
-
return c;
|
|
14445
|
-
}
|
|
14446
|
-
for (const status of ["in_progress", "blocked"]) {
|
|
14447
|
-
const list = cards.filter((c) => c.model?.status === status);
|
|
14448
|
-
if (list.length === 1) return list[0];
|
|
14449
|
-
if (list.length > 1) throw usage(`several ${status} cards, name one:
|
|
14450
|
-
${list.map((c) => ` ${c.number ?? c.key} ${c.model?.title}`).join("\n")}`);
|
|
14451
|
-
}
|
|
14452
|
-
throw new CliError("NO_ACTIVE_CARD", "no in_progress or blocked card; name one (rodo resume <card>)", 2);
|
|
14453
|
-
}
|
|
14454
|
-
function projectCards(ctx) {
|
|
14455
|
-
const { d, ref } = oneProject(ctx);
|
|
14456
|
-
return { d, ref, cards: scanCards(d.root, ref) };
|
|
14457
|
-
}
|
|
14458
|
-
|
|
14459
14515
|
// src/commands/resume.ts
|
|
14460
14516
|
var MAP_WHAT = /^##\s*(این پروژه چیست|What this project is)/i;
|
|
14461
14517
|
var MAP_WHERE = /^##\s*(الان کجاییم|Where we are)/i;
|
|
@@ -14784,7 +14840,7 @@ async function runValidate(ctx, paths, o = {}) {
|
|
|
14784
14840
|
if (ref.legacy) ctx.out.line(LEGACY_MSG);
|
|
14785
14841
|
ctx.out.line(`rodo/${ref.legacy ? "" : ref.slug} \u25B8 ${s.files} files \xB7 errors ${s.errors} \xB7 warnings ${s.warnings}`);
|
|
14786
14842
|
printFindings(ctx, cards);
|
|
14787
|
-
for (const c of cards) files.push({ project: ref.slug, path: c.path, errors: c.errors.map(
|
|
14843
|
+
for (const c of cards) files.push({ project: ref.slug, path: c.path, errors: c.errors.map(slim), warnings: c.warnings.map(slim) });
|
|
14788
14844
|
}
|
|
14789
14845
|
ctx.out.flush({ version: 2, files, summary: total });
|
|
14790
14846
|
return o.strict && total.errors > 0 ? 1 : 0;
|
|
@@ -14799,6 +14855,7 @@ Getting started:
|
|
|
14799
14855
|
rodo new "Delete a note" start the next cycle (card, simple.md, spec.md)
|
|
14800
14856
|
rodo validate --strict check the cards (exit 1 on errors)
|
|
14801
14857
|
rodo resume <card> context for an AI session
|
|
14858
|
+
rodo explain <card> the card in plain words, for you
|
|
14802
14859
|
rodo test <card> run the card test and catch repeated failures
|
|
14803
14860
|
rodo init --project <slug> --create-board later: connect a board, then rodo sync`);
|
|
14804
14861
|
program2.command("init").description("install or update the method kit and create a project folder").option("--name <name>", "display name").option("--server <url>", "board server (default: RODO_SERVER, else the built-in server)").option("--connect <code>", "one-time connect code from the board website (skips the device code)").option("--board <id>", "bind to an existing board").option("--create-board", "create a new board for this project").option("--method-only", "no server: install the kit and create the project folder only").option("--no-kit-update", "skip the kit step").option("--dry-run", "print the plan, write nothing").option("--yes-files", "answer yes to the .gitignore question").addHelpText("after", `
|
|
@@ -14815,6 +14872,7 @@ Examples:
|
|
|
14815
14872
|
program2.command("status").description("cards and their state").option("--local").action((o) => run((ctx) => runStatus(ctx, o)));
|
|
14816
14873
|
program2.command("doctor").description("read-only health checks").action(() => run((ctx) => runDoctor(ctx)));
|
|
14817
14874
|
program2.command("resume [card]").description("print the context of a card for an AI session").option("--full").action((card, o) => run((ctx) => runResume(ctx, card, o)));
|
|
14875
|
+
program2.command("explain [card]").description("describe a card in plain words for the user (read-only)").action((card) => run((ctx) => runExplain(ctx, card)));
|
|
14818
14876
|
program2.command("test [card]").description("run the card test command and track failure signatures").option("--adapter <adapter>", "web|api|cli|mobile|iot|other").action((card, o) => run((ctx) => runTest(ctx, card, o)));
|
|
14819
14877
|
program2.command("version").description("versions").action(() => run((ctx) => runVersion(ctx)));
|
|
14820
14878
|
return program2;
|
|
@@ -5,7 +5,7 @@ description: RODO project method. Use whenever the repo has a rodo/ folder or *.
|
|
|
5
5
|
|
|
6
6
|
> یادداشت فارسی: این مهارت برای AI است. نسخهٔ انسانی همین قواعد در `rodo/<project>/RULES.md` است. RODO فقط «روش کار» است: هیچ ابزاری جلوی commit، تست یا کار را نمیگیرد.
|
|
7
7
|
|
|
8
|
-
# RODO method (kit 2.
|
|
8
|
+
# RODO method (kit 2.4.0)
|
|
9
9
|
|
|
10
10
|
RODO is a way of working, not a gate. Nothing blocks a commit, a test or a status. You follow it because it keeps the project understandable for the user, for teammates and for the next AI session.
|
|
11
11
|
|
|
@@ -86,6 +86,8 @@ A card may have `scope: {allowed: [...], forbidden: [...]}`. Stay inside `allowe
|
|
|
86
86
|
| The repo has code but no `rodo/<project>/` yet | `onboarding.md` |
|
|
87
87
|
| Typo, style, refactor or a fix that does not change described behaviour | `small-change.md` |
|
|
88
88
|
| You write or fix tests (optional, recommended) | `testing.md` |
|
|
89
|
+
| Before closing any card: keep the code small and clean | `clean.md` |
|
|
90
|
+
| Review before closing a MAJOR card, or on request | `review.md` |
|
|
89
91
|
|
|
90
92
|
## Workflow levels
|
|
91
93
|
|
|
@@ -159,6 +161,7 @@ Card format details: the comments in `templates/card.rodo.md` and `rodo validate
|
|
|
159
161
|
| `rodo sync` | start and end of every session |
|
|
160
162
|
| `rodo resume [card] [--full]` | context for a new session |
|
|
161
163
|
| `rodo status` | board vs local, side by side |
|
|
164
|
+
| `rodo explain [card]` | the card in plain words, for the user |
|
|
162
165
|
| `rodo test [card]` | run the card's test command, record the failure signature |
|
|
163
166
|
| `rodo new "<title>"` | create the next cycle folder with `card.rodo.md`, `simple.md`, `spec.md` (`--major` adds `design.md` and `acceptance.feature`) |
|
|
164
167
|
| `rodo validate` | check card files (never blocks; `--strict` exits 1 on errors, for CI) |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Clean code formulas
|
|
2
|
+
|
|
3
|
+
Short rules for code you write or touch in a card. They keep the project small and easy to extend. Apply them to the files of this card only; never start a repo-wide cleanup without a card of its own.
|
|
4
|
+
|
|
5
|
+
## The formulas
|
|
6
|
+
|
|
7
|
+
| Rule | Limit |
|
|
8
|
+
|---|---|
|
|
9
|
+
| One function does one thing | about 30 lines |
|
|
10
|
+
| One file has one reason to change | about 300 lines; split by responsibility, not by size alone |
|
|
11
|
+
| Parameters | 3 or fewer; more → pass one object |
|
|
12
|
+
| Nesting | 3 levels or fewer; use early `return` |
|
|
13
|
+
| Repetition | the third copy becomes a shared function; two copies stay (do not guess early) |
|
|
14
|
+
| Names | say what, not how (`overdueInvoices`, not `list2`); no abbreviations the glossary does not know |
|
|
15
|
+
| Comments | only the *why*; delete comments that repeat the code |
|
|
16
|
+
| Dead code | delete it (git remembers); never comment code out |
|
|
17
|
+
| New dependency | only if it replaces more than ~50 lines you would write and keep; mention it in `spec.md` `## Decisions` |
|
|
18
|
+
| Extension | add a new file or a new entry in a list, not a new `if` inside a long function |
|
|
19
|
+
|
|
20
|
+
## Order of work (every card)
|
|
21
|
+
|
|
22
|
+
1. Make it work (R-rules pass).
|
|
23
|
+
2. Read your own diff once. Apply the formulas above to what you changed.
|
|
24
|
+
3. Remove what is now unused: imports, variables, files, docs that describe the removed behaviour.
|
|
25
|
+
4. Match the surrounding style (naming, comment density, error handling). Do not reformat code you did not change.
|
|
26
|
+
5. Re-run the checks. Cleaning must not change behaviour.
|
|
27
|
+
6. Tick the card's `Cleanup done` step and write `- Cleaned: <what you simplified, or "nothing needed">` in Progress notes.
|
|
28
|
+
|
|
29
|
+
## Boundaries
|
|
30
|
+
|
|
31
|
+
- A cleanup that touches files outside the card's `scope.allowed` is a new card (SKILL.md "Scope").
|
|
32
|
+
- If a formula forces a large rewrite, do not do it silently: write `- Out of scope: <refactor> → new card` and tell the user.
|
|
33
|
+
- Prefer deleting over adding. The best change is the one with fewer lines for the same behaviour.
|
|
@@ -1,82 +1,86 @@
|
|
|
1
|
-
> یادداشت فارسی: دستورالعمل کدنویس. از روی کارت کار کن، فقط ارجاعها را بخوان، قدمبهقدم جلو برو، سندها را درست نگه دار، و آخر هر جلسه «Progress notes» را بهروز کن. همهٔ مسیرها نسبت به `rodo/<project>/` هستند.
|
|
2
|
-
|
|
3
|
-
# Coder playbook
|
|
4
|
-
|
|
5
|
-
You implement one card. Any model may do this; the user chooses.
|
|
6
|
-
|
|
7
|
-
## Before you start (every session)
|
|
8
|
-
|
|
9
|
-
Follow "Session start" in SKILL.md (git check without pulling → rodo sync → rodo resume → refs only → approval check → answered decisions). Then set `status: in_progress`.
|
|
10
|
-
|
|
11
|
-
## Doing the steps
|
|
12
|
-
|
|
13
|
-
For each unticked step, in order:
|
|
14
|
-
1. Do only what the step says.
|
|
15
|
-
2. Check it (unit test, build, or the command the step names).
|
|
16
|
-
3. Tick it `- [x]`; add `[hours: H:MM]` only if you know the real time.
|
|
17
|
-
4. Commit with the card number in the message, e.g. `feat: discount code input [cycle 002]`, so people can find the work later.
|
|
18
|
-
|
|
19
|
-
If your change makes a project doc wrong (`project/*`, the card's `spec.md`), fix the doc in the same commit.
|
|
20
|
-
|
|
21
|
-
## Tests (if the card has scenarios)
|
|
22
|
-
|
|
23
|
-
- Step definitions go in the folder from `project.json` `stepsDirs`. They must really drive the app (browser, API or CLI) and really assert. See `testing.md`.
|
|
24
|
-
- Run the card's tests with `rodo test` (it uses the card's `test.command`, or `testCommand` from `project.json`). Tick `تست پذیرش پاس شد` only after a real passing run.
|
|
25
|
-
- **Never weaken a scenario or test to make code pass:** no deleting scenarios, loosening assertions, `@skip`/`.only`/`test.fixme`, or changing an expected value to match buggy output. If a scenario looks wrong, explain why to the user; change it only if they agree.
|
|
26
|
-
|
|
27
|
-
## Scope changes while coding
|
|
28
|
-
|
|
29
|
-
- Out of the card's `scope` or a new requirement: do not do it silently. Write `- Out of scope: <item> → new card` in Progress notes and tell the user.
|
|
30
|
-
- Small change in the same feature: update the scenario/spec/steps of this card, tell the user, continue (wait if there is an unticked approval item).
|
|
31
|
-
- Big new feature: do not add it. Write it under `- Remaining:` as "needs a new card" and tell the user.
|
|
32
|
-
|
|
33
|
-
## Stuck
|
|
34
|
-
|
|
35
|
-
Use the stuck rule in SKILL.md: same failure signature twice → `status: blocked`, `blockerType: test` or `technical`, a plain `statusReason:`, ask the user. Waiting for an answer, a key or another card → `status: blocked` with the matching `blockerType` (`decision`, `permission`, `external`). If only the user can choose, write a `## Decision:` section (SKILL.md). When solved: `status: in_progress`, remove `statusReason` and `blockerType`. Never set `cancelled` yourself; only with the user's OK.
|
|
36
|
-
|
|
37
|
-
## Verify and fix
|
|
38
|
-
|
|
39
|
-
**VERIFY** — pick the checks that fit this change and run them with the project's own tools (RODO runs nothing itself):
|
|
40
|
-
- build, typecheck, lint;
|
|
41
|
-
- unit, integration, e2e;
|
|
42
|
-
- architecture rules, security checks;
|
|
43
|
-
- acceptance (the card's `test` command via `rodo test`, or the acceptance criteria checked one by one);
|
|
44
|
-
- documentation consistency (below).
|
|
45
|
-
|
|
46
|
-
Write the result in Progress notes as `- Verified: <check> ✓/✗, …`.
|
|
47
|
-
|
|
48
|
-
**Documentation Consistency** (part of VERIFY):
|
|
49
|
-
- Check that every file listed under Documentation Impact was updated.
|
|
50
|
-
- Check that the CURRENT docs and the active cycle docs still describe the code.
|
|
51
|
-
- If something does not match: FIX, then VERIFY again.
|
|
52
|
-
- If a current doc contradicts a `MEMORY.md` decision, stop and ask the user (as small-change.md already says).
|
|
53
|
-
|
|
54
|
-
**REVIEW (optional; recommended for MAJOR)** — an independent AI session or model reads the change and checks:
|
|
55
|
-
- requirement coverage; acceptance criteria;
|
|
56
|
-
- regressions; architecture fit;
|
|
57
|
-
- missing tests; maintainability;
|
|
58
|
-
- unintended changes.
|
|
59
|
-
|
|
60
|
-
A review never replaces tests. Its findings go back to FIX.
|
|
61
|
-
|
|
62
|
-
**FIX loop** — FIX → VERIFY until everything passes (→ DONE) or the stuck rule applies: the **same failure twice** (same failure signature, or the same error at the same place) → `status: blocked` with `blockerType: test` or `technical` (SKILL.md "Stuck rule"). Different failures do not count.
|
|
63
|
-
|
|
64
|
-
##
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
##
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
1
|
+
> یادداشت فارسی: دستورالعمل کدنویس. از روی کارت کار کن، فقط ارجاعها را بخوان، قدمبهقدم جلو برو، سندها را درست نگه دار، و آخر هر جلسه «Progress notes» را بهروز کن. همهٔ مسیرها نسبت به `rodo/<project>/` هستند.
|
|
2
|
+
|
|
3
|
+
# Coder playbook
|
|
4
|
+
|
|
5
|
+
You implement one card. Any model may do this; the user chooses.
|
|
6
|
+
|
|
7
|
+
## Before you start (every session)
|
|
8
|
+
|
|
9
|
+
Follow "Session start" in SKILL.md (git check without pulling → rodo sync → rodo resume → refs only → approval check → answered decisions). Then set `status: in_progress`.
|
|
10
|
+
|
|
11
|
+
## Doing the steps
|
|
12
|
+
|
|
13
|
+
For each unticked step, in order:
|
|
14
|
+
1. Do only what the step says.
|
|
15
|
+
2. Check it (unit test, build, or the command the step names).
|
|
16
|
+
3. Tick it `- [x]`; add `[hours: H:MM]` only if you know the real time.
|
|
17
|
+
4. Commit with the card number in the message, e.g. `feat: discount code input [cycle 002]`, so people can find the work later.
|
|
18
|
+
|
|
19
|
+
If your change makes a project doc wrong (`project/*`, the card's `spec.md`), fix the doc in the same commit.
|
|
20
|
+
|
|
21
|
+
## Tests (if the card has scenarios)
|
|
22
|
+
|
|
23
|
+
- Step definitions go in the folder from `project.json` `stepsDirs`. They must really drive the app (browser, API or CLI) and really assert. See `testing.md`.
|
|
24
|
+
- Run the card's tests with `rodo test` (it uses the card's `test.command`, or `testCommand` from `project.json`). Tick `تست پذیرش پاس شد` only after a real passing run.
|
|
25
|
+
- **Never weaken a scenario or test to make code pass:** no deleting scenarios, loosening assertions, `@skip`/`.only`/`test.fixme`, or changing an expected value to match buggy output. If a scenario looks wrong, explain why to the user; change it only if they agree.
|
|
26
|
+
|
|
27
|
+
## Scope changes while coding
|
|
28
|
+
|
|
29
|
+
- Out of the card's `scope` or a new requirement: do not do it silently. Write `- Out of scope: <item> → new card` in Progress notes and tell the user.
|
|
30
|
+
- Small change in the same feature: update the scenario/spec/steps of this card, tell the user, continue (wait if there is an unticked approval item).
|
|
31
|
+
- Big new feature: do not add it. Write it under `- Remaining:` as "needs a new card" and tell the user.
|
|
32
|
+
|
|
33
|
+
## Stuck
|
|
34
|
+
|
|
35
|
+
Use the stuck rule in SKILL.md: same failure signature twice → `status: blocked`, `blockerType: test` or `technical`, a plain `statusReason:`, ask the user. Waiting for an answer, a key or another card → `status: blocked` with the matching `blockerType` (`decision`, `permission`, `external`). If only the user can choose, write a `## Decision:` section (SKILL.md). When solved: `status: in_progress`, remove `statusReason` and `blockerType`. Never set `cancelled` yourself; only with the user's OK.
|
|
36
|
+
|
|
37
|
+
## Verify and fix
|
|
38
|
+
|
|
39
|
+
**VERIFY** — pick the checks that fit this change and run them with the project's own tools (RODO runs nothing itself):
|
|
40
|
+
- build, typecheck, lint;
|
|
41
|
+
- unit, integration, e2e;
|
|
42
|
+
- architecture rules, security checks;
|
|
43
|
+
- acceptance (the card's `test` command via `rodo test`, or the acceptance criteria checked one by one);
|
|
44
|
+
- documentation consistency (below).
|
|
45
|
+
|
|
46
|
+
Write the result in Progress notes as `- Verified: <check> ✓/✗, …`.
|
|
47
|
+
|
|
48
|
+
**Documentation Consistency** (part of VERIFY):
|
|
49
|
+
- Check that every file listed under Documentation Impact was updated.
|
|
50
|
+
- Check that the CURRENT docs and the active cycle docs still describe the code.
|
|
51
|
+
- If something does not match: FIX, then VERIFY again.
|
|
52
|
+
- If a current doc contradicts a `MEMORY.md` decision, stop and ask the user (as small-change.md already says).
|
|
53
|
+
|
|
54
|
+
**REVIEW (optional; recommended for MAJOR)** — an independent AI session or model reads the change and checks:
|
|
55
|
+
- requirement coverage; acceptance criteria;
|
|
56
|
+
- regressions; architecture fit;
|
|
57
|
+
- missing tests; maintainability;
|
|
58
|
+
- unintended changes.
|
|
59
|
+
|
|
60
|
+
A review never replaces tests. Its findings go back to FIX.
|
|
61
|
+
|
|
62
|
+
**FIX loop** — FIX → VERIFY until everything passes (→ DONE) or the stuck rule applies: the **same failure twice** (same failure signature, or the same error at the same place) → `status: blocked` with `blockerType: test` or `technical` (SKILL.md "Stuck rule"). Different failures do not count.
|
|
63
|
+
|
|
64
|
+
## Clean before you close
|
|
65
|
+
|
|
66
|
+
When the steps are done and verified, follow `clean.md` (and `review.md` for MAJOR), then tick `Cleanup done`.
|
|
67
|
+
|
|
68
|
+
## End of every session
|
|
69
|
+
|
|
70
|
+
Follow "Session close" in SKILL.md. Always finish with `rodo sync`.
|
|
71
|
+
|
|
72
|
+
## Close (all steps ticked)
|
|
73
|
+
|
|
74
|
+
The folder does not move.
|
|
75
|
+
1. Card: `status: done`.
|
|
76
|
+
2. `MAP.md`: add the cycle under `## انجامشده` (one line, link to simple.md or the card folder) and update "الان کجاییم".
|
|
77
|
+
3. `MEMORY.md`: append each `## Decisions` line of spec.md as `- YYYY-MM-DD — <decision>. چون <reason>. (cycle NNN)`.
|
|
78
|
+
4. Commit the MAP and MEMORY change. Later changes to this behaviour need a new card; changes that do not touch behaviour go to `small-change.md`.
|
|
79
|
+
|
|
80
|
+
## Rules
|
|
81
|
+
|
|
82
|
+
- Never tick an approval item or change its text. Only a person can approve, in the web app. Never answer a `## Decision:` yourself.
|
|
83
|
+
- Never edit `id:` lines or `<!-- rodo:... -->` comments.
|
|
84
|
+
- Do not change `members`, `startAt`, `dueAt`, `priority` unless the user asks: the team owns them.
|
|
85
|
+
- Never delete files you did not create in this card without asking.
|
|
86
|
+
- Keep changes inside the steps. Unrelated fixes go to `small-change.md` or a new card.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Review checklists
|
|
2
|
+
|
|
3
|
+
Use before closing a MAJOR card (recommended) or whenever the user asks for a review. A review reads the diff; it never replaces tests. Report findings in plain words, most serious first, and fix them (FIX → VERIFY).
|
|
4
|
+
|
|
5
|
+
## 1. Simplify (always)
|
|
6
|
+
|
|
7
|
+
- Anything duplicated, over-built, or unused in the diff?
|
|
8
|
+
- Could a simpler existing function or library call replace new code?
|
|
9
|
+
- Follow `clean.md`.
|
|
10
|
+
|
|
11
|
+
## 2. Correctness
|
|
12
|
+
|
|
13
|
+
- Does each R-rule of `spec.md` have code and, if tests are used, a test?
|
|
14
|
+
- Edge cases: empty input, missing value, very large input, two things happening at once.
|
|
15
|
+
- Errors: are they handled or reported, never swallowed?
|
|
16
|
+
|
|
17
|
+
## 3. Security (quick pass)
|
|
18
|
+
|
|
19
|
+
- No secrets in code, config, logs, cards or commit messages.
|
|
20
|
+
- Input from outside (forms, URLs, files, env) is checked before use; no string-built SQL, shell commands or HTML.
|
|
21
|
+
- Access: every new route or action checks who is calling.
|
|
22
|
+
- New dependencies: known, maintained, and necessary.
|
|
23
|
+
|
|
24
|
+
## 4. Plain words
|
|
25
|
+
|
|
26
|
+
- Does the card's opening text (what the user gets) and `simple.md` still describe what the code now does? Run `rodo explain <card>` and read it as if you were not a developer.
|
|
27
|
+
|
|
28
|
+
## Optional external skills
|
|
29
|
+
|
|
30
|
+
If the project or the user's tools already provide them, you may use `simplify`, `code-review`, `security-review` or Graphify (code map). Never install them yourself; RODO works without them. Treat their output as advice and verify it before acting.
|
|
@@ -11,7 +11,7 @@ scope:
|
|
|
11
11
|
forbidden: []
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
{{دو تا پنج خط
|
|
14
|
+
{{دو تا پنج خط ساده و بدون اصطلاح فنی: کاربر چه چیزی میگیرد. دستور rodo explain همین را به کاربر نشان میدهد. جزئیات در spec.md است.}}
|
|
15
15
|
|
|
16
16
|
## Progress notes
|
|
17
17
|
|
|
@@ -30,4 +30,5 @@ scope:
|
|
|
30
30
|
<!-- - [ ] تأیید کاربر: simple.md و سناریوها [approval] — add only when the user asked for a human approval (D5) -->
|
|
31
31
|
- [ ] {{قدم ۱: کار مشخص + نشانهٔ انجام شدن}}
|
|
32
32
|
- [ ] {{قدم ۲}}
|
|
33
|
+
- [ ] تمیزکاری انجام شد (clean.md)
|
|
33
34
|
- [ ] تست پذیرش پاس شد
|
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
---
|
|
2
|
-
schemaVersion: 2
|
|
3
|
-
title: "{{short title}}"
|
|
4
|
-
status: todo
|
|
5
|
-
# statusReason: ... # only when status is blocked or cancelled: the reason in plain words
|
|
6
|
-
priority: medium
|
|
7
|
-
# workflow: standard # optional: quick | standard | major; local only, never sent to the board
|
|
8
|
-
members: []
|
|
9
|
-
scope:
|
|
10
|
-
allowed: []
|
|
11
|
-
forbidden: []
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
{{two to five plain lines: what the user gets. Details are in spec.md.}}
|
|
15
|
-
|
|
16
|
-
## Progress notes
|
|
17
|
-
|
|
18
|
-
- Updated: {{YYYY-MM-DD}}
|
|
19
|
-
- Done: not started yet
|
|
20
|
-
- Remaining: all steps
|
|
21
|
-
|
|
22
|
-
## Refs
|
|
23
|
-
|
|
24
|
-
- [Plain explanation](/rodo/{{project}}/cycles/{{NNN-slug}}/simple.md)
|
|
25
|
-
- [Technical spec](/rodo/{{project}}/cycles/{{NNN-slug}}/spec.md)
|
|
26
|
-
<!-- [Acceptance scenarios](/rodo/{{project}}/cycles/{{NNN-slug}}/acceptance.feature) — uncomment only after that file exists -->
|
|
27
|
-
|
|
28
|
-
## Checklist: Steps
|
|
29
|
-
|
|
30
|
-
<!-- - [ ] User approval: simple.md and scenarios [approval] — add only when the user asked for a human approval -->
|
|
31
|
-
- [ ] {{step 1: a concrete task + how you know it is done}}
|
|
32
|
-
- [ ] {{step 2}}
|
|
1
|
+
---
|
|
2
|
+
schemaVersion: 2
|
|
3
|
+
title: "{{short title}}"
|
|
4
|
+
status: todo
|
|
5
|
+
# statusReason: ... # only when status is blocked or cancelled: the reason in plain words
|
|
6
|
+
priority: medium
|
|
7
|
+
# workflow: standard # optional: quick | standard | major; local only, never sent to the board
|
|
8
|
+
members: []
|
|
9
|
+
scope:
|
|
10
|
+
allowed: []
|
|
11
|
+
forbidden: []
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
{{two to five plain lines: what the user gets, with no technical terms. `rodo explain` shows exactly this to the user. Details are in spec.md.}}
|
|
15
|
+
|
|
16
|
+
## Progress notes
|
|
17
|
+
|
|
18
|
+
- Updated: {{YYYY-MM-DD}}
|
|
19
|
+
- Done: not started yet
|
|
20
|
+
- Remaining: all steps
|
|
21
|
+
|
|
22
|
+
## Refs
|
|
23
|
+
|
|
24
|
+
- [Plain explanation](/rodo/{{project}}/cycles/{{NNN-slug}}/simple.md)
|
|
25
|
+
- [Technical spec](/rodo/{{project}}/cycles/{{NNN-slug}}/spec.md)
|
|
26
|
+
<!-- [Acceptance scenarios](/rodo/{{project}}/cycles/{{NNN-slug}}/acceptance.feature) — uncomment only after that file exists -->
|
|
27
|
+
|
|
28
|
+
## Checklist: Steps
|
|
29
|
+
|
|
30
|
+
<!-- - [ ] User approval: simple.md and scenarios [approval] — add only when the user asked for a human approval -->
|
|
31
|
+
- [ ] {{step 1: a concrete task + how you know it is done}}
|
|
32
|
+
- [ ] {{step 2}}
|
|
33
|
+
- [ ] Cleanup done (clean.md)
|
package/dist/kit/KIT_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.4.0
|