kandown 0.27.0 → 0.28.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/CHANGELOG.md +14 -0
- package/bin/kandown.js +49 -7
- package/dist/index.html +254 -142
- package/package.json +2 -1
- package/templates/AGENT_KANDOWN.md +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.28.0 — 2026-07-20 — "Agent Instruction Modes & CLI Reference"
|
|
4
|
+
|
|
5
|
+
- **Added**: **3 Base Agent Rule Modes (Verbose, Optimized, Caveman)** — redesigned the Agent instructions settings into 3 distinct rule density modes. Users can choose between **Verbose** (full reference guide), **Optimized** (concise, high-density structured rules tailored for LLMs), and **Caveman** (ultra-compact minimal token rules).
|
|
6
|
+
- **Added**: **Quick CLI Commands Reference in Agent Rules** — added a concise CLI cheatsheet table (`kandown work`, `kandown list`, `kandown show`, `kandown create`, `kandown move`, `kandown assign`, `kandown commit`) right at the top of base rules across all modes so AI agents immediately know the native CLI commands available to interact with the board.
|
|
7
|
+
- **Added**: **3-Step Numbered Layout for Agent Settings** — reorganized the Agent Instructions settings page into 3 clear numbered step cards: Step 1 (Base Rules mode & density), Step 2 (Project Guidelines stored in `.kandown/instructions.md`), and Step 3 (Live Board State data filters).
|
|
8
|
+
- **Added**: **Quick Preset Instruction Chips** — added 1-click template insertion chips (`📦 pnpm`, `🧪 Test rule`, `🌳 Git rule`, `⚡ Task log`) below the project instructions editor for adding repository rules instantly.
|
|
9
|
+
- **Added**: **Terminal-Style Sticky Live Preview Panel** — added an independent sticky preview panel on the right with window dot indicators, token estimation badge, layer legend badges (🟢 Step 1, 🟡 Step 2, 🔵 Step 3), 1-click Copy button, and real-time interactive color highlighting when hovering over options.
|
|
10
|
+
|
|
11
|
+
## 0.27.1 — 2026-07-20 — "Auto-Updater & Daemon Process Upgrade"
|
|
12
|
+
|
|
13
|
+
- **Fixed**: **Environment inheritance during background auto-update** — cleaned inherited `npm_config_*` and `npm_*` environment variables when spawning `npm install -g kandown` in `checkForUpdate()`. Previously, if Kandown was run via `npx` or `npm run`, inherited local prefix overrides could cause global background updates to fail or target a temporary cache.
|
|
14
|
+
- **Fixed**: **Binary path resolution for system PATH and `~/.local/bin`** — updated `resolveKandownBin()` to check `which kandown`, `command -v kandown`, and `~/.local/bin/kandown` before checking package manager prefixes, ensuring custom global PATH installations are detected accurately.
|
|
15
|
+
- **Fixed**: **Live daemon process upgrade on CLI update** — updated `refreshRunningProjectHtml()` so that background project daemon processes in RAM running older code are automatically stopped and relaunched with the newly updated CLI binary.
|
|
16
|
+
|
|
3
17
|
## 0.27.0 — 2026-07-20 — "Unified Views"
|
|
4
18
|
|
|
5
19
|
- **Added**: **Full Component Parity between Board and List Views** — unified the List view (`ListView.tsx`) and Board view (`Column.tsx`) so that List view sections and task items share the exact same components, column background color tints, icons, and action options as Board columns.
|
package/bin/kandown.js
CHANGED
|
@@ -130,17 +130,27 @@ function getCurrentVersion() {
|
|
|
130
130
|
* @returns {string|null} Absolute path to the kandown binary, or null.
|
|
131
131
|
*/
|
|
132
132
|
function resolveKandownBin() {
|
|
133
|
+
try {
|
|
134
|
+
const whichBin = String(execSync('which kandown 2>/dev/null || command -v kandown 2>/dev/null', {
|
|
135
|
+
timeout: 3000, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
136
|
+
})).trim();
|
|
137
|
+
if (whichBin && existsSync(whichBin)) return whichBin;
|
|
138
|
+
} catch { /* ignore */ }
|
|
139
|
+
const localBin = join(homedir(), '.local', 'bin', 'kandown');
|
|
140
|
+
if (existsSync(localBin)) return localBin;
|
|
133
141
|
try {
|
|
134
142
|
const npmBin = String(execSync('npm config get prefix 2>/dev/null', {
|
|
135
143
|
timeout: 3000, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
136
144
|
})).trim();
|
|
137
145
|
if (existsSync(join(npmBin, 'bin', 'kandown'))) return join(npmBin, 'bin', 'kandown');
|
|
146
|
+
if (existsSync(join(npmBin, 'kandown'))) return join(npmBin, 'kandown');
|
|
138
147
|
} catch { /* npm not available */ }
|
|
139
148
|
try {
|
|
140
149
|
const pnpmBin = String(execSync('pnpm config get prefix 2>/dev/null', {
|
|
141
150
|
timeout: 3000, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
142
151
|
})).trim();
|
|
143
152
|
if (existsSync(join(pnpmBin, 'bin', 'kandown'))) return join(pnpmBin, 'bin', 'kandown');
|
|
153
|
+
if (existsSync(join(pnpmBin, 'kandown'))) return join(pnpmBin, 'kandown');
|
|
144
154
|
} catch { /* pnpm not available */ }
|
|
145
155
|
return null;
|
|
146
156
|
}
|
|
@@ -307,10 +317,16 @@ async function checkForUpdate(argv = process.argv) {
|
|
|
307
317
|
const updateOk = await new Promise((resolve) => {
|
|
308
318
|
const tryInstall = (cmd) => {
|
|
309
319
|
return new Promise((res) => {
|
|
320
|
+
const cleanEnv = { ...process.env };
|
|
321
|
+
for (const k of Object.keys(cleanEnv)) {
|
|
322
|
+
if (k.startsWith('npm_config_') || k.startsWith('npm_') || k === 'INIT_CWD') {
|
|
323
|
+
delete cleanEnv[k];
|
|
324
|
+
}
|
|
325
|
+
}
|
|
310
326
|
const child = spawn(cmd, ['install', '-g', 'kandown'], {
|
|
311
|
-
timeout:
|
|
327
|
+
timeout: 60000,
|
|
312
328
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
313
|
-
env:
|
|
329
|
+
env: cleanEnv,
|
|
314
330
|
detached: false,
|
|
315
331
|
});
|
|
316
332
|
child.stderr.on('data', () => {}); // silence npm noise
|
|
@@ -1559,18 +1575,32 @@ function priorityRank(p) {
|
|
|
1559
1575
|
}
|
|
1560
1576
|
|
|
1561
1577
|
const WORK_OUTPUT_SECTION_IDS = ['baseRules', 'projectInstructions', 'boardDigest'];
|
|
1562
|
-
const
|
|
1578
|
+
const OPTIMIZED_AGENT_RULES = `# Kandown agent rules
|
|
1579
|
+
|
|
1580
|
+
## CLI Commands
|
|
1581
|
+
- \`kandown list\` (list tasks) · \`kandown show <id>\` (view task)
|
|
1582
|
+
- \`kandown create "<title>"\` (create task) · \`kandown move <id> <status>\` (move task column)
|
|
1583
|
+
- \`kandown assign <id> <user>\` · \`kandown commit\` (commit board to git)
|
|
1563
1584
|
|
|
1585
|
+
## Rules
|
|
1564
1586
|
- Task state lives in project-root \`tasks/*.md\`; do not maintain a separate board index.
|
|
1565
1587
|
- Before work, read the relevant task file and keep it updated while you progress.
|
|
1566
1588
|
- Move tasks by editing frontmatter \`status:\`; complete work by setting \`status: Done\` and adding a markdown \`report:\` summary.
|
|
1567
1589
|
- Update subtasks in-place: \`- [ ]\` → \`- [x]\`, with a short \`report:\` line for meaningful progress.
|
|
1568
1590
|
- Board columns live in \`.kandown/kandown.json\` under \`board.columns\`; project instructions live in \`.kandown/instructions.md\`.
|
|
1569
1591
|
- Never put Kandown task data inside \`.kandown/\`; tasks belong in \`./tasks/\`.`;
|
|
1592
|
+
|
|
1593
|
+
const CAVEMAN_AGENT_RULES = `# Kandown agent rules
|
|
1594
|
+
|
|
1595
|
+
CLI: kandown list | kandown show <id> | kandown create "<title>" | kandown move <id> <status> | kandown assign <id> <user> | kandown commit
|
|
1596
|
+
RULES: TASKS IN ./tasks/*.md. READ TASK BEFORE WORK. UPDATE SUBTASKS - [ ] -> - [x] + REPORT. MOVE: EDIT status:. DONE: status: Done + report:.`;
|
|
1597
|
+
|
|
1598
|
+
const CONCISE_AGENT_RULES = OPTIMIZED_AGENT_RULES;
|
|
1599
|
+
|
|
1570
1600
|
const DEFAULT_WORK_OUTPUT = {
|
|
1571
1601
|
mode: 'blocks',
|
|
1572
1602
|
includeBaseRules: true,
|
|
1573
|
-
baseRulesMode: '
|
|
1603
|
+
baseRulesMode: 'verbose',
|
|
1574
1604
|
includeProjectInstructions: true,
|
|
1575
1605
|
includeBoardDigest: true,
|
|
1576
1606
|
sectionOrder: WORK_OUTPUT_SECTION_IDS,
|
|
@@ -1596,11 +1626,13 @@ function normalizeWorkOutputConfig(config) {
|
|
|
1596
1626
|
? raw.sectionOrder.filter(id => WORK_OUTPUT_SECTION_IDS.includes(id))
|
|
1597
1627
|
: DEFAULT_WORK_OUTPUT.sectionOrder;
|
|
1598
1628
|
const order = sectionOrder.length > 0 ? sectionOrder : DEFAULT_WORK_OUTPUT.sectionOrder;
|
|
1629
|
+
const validBaseModes = ['verbose', 'optimized', 'caveman', 'full', 'concise'];
|
|
1630
|
+
const baseMode = validBaseModes.includes(raw.baseRulesMode) ? raw.baseRulesMode : DEFAULT_WORK_OUTPUT.baseRulesMode;
|
|
1599
1631
|
return {
|
|
1600
1632
|
...DEFAULT_WORK_OUTPUT,
|
|
1601
1633
|
...raw,
|
|
1602
1634
|
mode: raw.mode === 'raw' ? 'raw' : 'blocks',
|
|
1603
|
-
baseRulesMode:
|
|
1635
|
+
baseRulesMode: baseMode,
|
|
1604
1636
|
sectionOrder: order,
|
|
1605
1637
|
rawTemplate: typeof raw.rawTemplate === 'string' && raw.rawTemplate.trim()
|
|
1606
1638
|
? raw.rawTemplate
|
|
@@ -1609,8 +1641,9 @@ function normalizeWorkOutputConfig(config) {
|
|
|
1609
1641
|
};
|
|
1610
1642
|
}
|
|
1611
1643
|
|
|
1612
|
-
function readBaseAgentRules(mode = '
|
|
1613
|
-
if (mode === '
|
|
1644
|
+
function readBaseAgentRules(mode = 'verbose') {
|
|
1645
|
+
if (mode === 'caveman') return CAVEMAN_AGENT_RULES;
|
|
1646
|
+
if (mode === 'optimized' || mode === 'concise') return OPTIMIZED_AGENT_RULES;
|
|
1614
1647
|
try {
|
|
1615
1648
|
return readFileSync(join(PKG_ROOT, 'templates', 'AGENT_KANDOWN.md'), 'utf8').trim();
|
|
1616
1649
|
} catch (e) {
|
|
@@ -1926,10 +1959,19 @@ async function refreshRunningProjectHtml() {
|
|
|
1926
1959
|
.filter(dir => typeof dir === 'string' && dir.length > 0)
|
|
1927
1960
|
);
|
|
1928
1961
|
|
|
1962
|
+
const currentVersion = getCurrentVersion();
|
|
1929
1963
|
let refreshed = 0;
|
|
1930
1964
|
for (const kandownDir of kandownDirs) {
|
|
1931
1965
|
try {
|
|
1932
1966
|
if (refreshKandownHtml(kandownDir)) refreshed++;
|
|
1967
|
+
const current = await getDaemonStatus(kandownDir);
|
|
1968
|
+
if (current.running) {
|
|
1969
|
+
const daemonVersion = current.metadata?.version || null;
|
|
1970
|
+
if (!daemonVersion || (currentVersion && semverGt(currentVersion, daemonVersion) > 0)) {
|
|
1971
|
+
await stopDaemon(kandownDir);
|
|
1972
|
+
await startDaemon(kandownDir, current.metadata?.port || null);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1933
1975
|
} catch { /* best-effort: one locked project must not block restart */ }
|
|
1934
1976
|
}
|
|
1935
1977
|
return refreshed;
|