@goodandready/dsh-kanban 0.2.21 → 0.2.23

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/lib/worktree.js CHANGED
@@ -30,10 +30,11 @@ export async function defaultGitRunner(args, cwd) {
30
30
  maxBuffer: 10 * 1024 * 1024,
31
31
  env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
32
32
  })
33
- return { stdout: stdout.trim(), stderr: stderr.trim(), code: 0 }
33
+ return { stdout: stdout.trim(), stderr: stderr.trim(), code: 0, exitCode: 0 }
34
34
  } catch (err) {
35
35
  const error = new Error(`git ${args.join(' ')} failed: ${err.stderr || err.message}`)
36
36
  error.code = err.code || 1
37
+ error.exitCode = err.code || 1
37
38
  error.stdout = err.stdout ? String(err.stdout).trim() : ''
38
39
  error.stderr = err.stderr ? String(err.stderr).trim() : ''
39
40
  throw error
@@ -264,7 +265,7 @@ export async function checkWorktreeDirty({ worktreePath, gitRunner = defaultGitR
264
265
  .filter((line) => !isSubmoduleDrift(worktreePath, line))
265
266
  return { dirty: files.length > 0, files }
266
267
  } catch (error) {
267
- return { dirty: false, files: [], error: String(error?.message ?? error) }
268
+ return { dirty: true, files: [], error: String(error?.message ?? error) }
268
269
  }
269
270
  }
270
271
 
@@ -289,6 +290,13 @@ export async function removeTaskWorktree({
289
290
  }
290
291
 
291
292
  const dirtyCheck = await checkWorktreeDirty({ worktreePath, gitRunner })
293
+ if (dirtyCheck.error) {
294
+ return {
295
+ removed: false,
296
+ error: 'worktree-status-error',
297
+ detail: dirtyCheck.error,
298
+ }
299
+ }
292
300
  if (dirtyCheck.dirty && !force) {
293
301
  return {
294
302
  removed: false,
@@ -431,21 +439,21 @@ export async function getTaskDiff({ worktreePath, baseRef, gitRunner = defaultGi
431
439
  let diffOut = ''
432
440
  if (base) {
433
441
  const res = await gitRunner(['diff', `${base}...HEAD`], worktreePath)
434
- if (res.exitCode === 0) {
442
+ if ((res?.exitCode ?? res?.code ?? 0) === 0) {
435
443
  diffOut = res.stdout
436
444
  }
437
445
  }
438
446
 
439
447
  // Include uncommitted changes (unstaged + staged)
440
448
  const unstaged = await gitRunner(['diff', 'HEAD'], worktreePath)
441
- if (unstaged.exitCode === 0 && unstaged.stdout.trim() !== '') {
449
+ if ((unstaged?.exitCode ?? unstaged?.code ?? 0) === 0 && unstaged.stdout.trim() !== '') {
442
450
  diffOut = diffOut ? `${diffOut}\n\n# Uncommitted Changes:\n${unstaged.stdout}` : unstaged.stdout
443
451
  }
444
452
 
445
453
  // Fallback to plain git diff if base...HEAD produced no output
446
454
  if (!diffOut.trim()) {
447
455
  const fallback = await gitRunner(['diff'], worktreePath)
448
- if (fallback.exitCode === 0) diffOut = fallback.stdout
456
+ if ((fallback?.exitCode ?? fallback?.code ?? 0) === 0) diffOut = fallback.stdout
449
457
  }
450
458
 
451
459
  // Count affected files
@@ -481,10 +489,10 @@ export async function getTaskCommits({ worktreePath, baseRef, gitRunner = defaul
481
489
 
482
490
  const range = base ? `${base}..HEAD` : '-n 20'
483
491
  const logRes = await gitRunner(['log', range, '--pretty=format:%h%x09%an%x09%ad%x09%s', '--date=short'], worktreePath)
484
- if (logRes.exitCode !== 0 || !logRes.stdout.trim()) {
492
+ if ((logRes?.exitCode ?? logRes?.code ?? 0) !== 0 || !logRes.stdout.trim()) {
485
493
  // Fallback to last 10 commits
486
494
  const fallback = await gitRunner(['log', '-n', '10', '--pretty=format:%h%x09%an%x09%ad%x09%s', '--date=short'], worktreePath)
487
- if (fallback.exitCode !== 0 || !fallback.stdout.trim()) return []
495
+ if ((fallback?.exitCode ?? fallback?.code ?? 0) !== 0 || !fallback.stdout.trim()) return []
488
496
  return fallback.stdout.trim().split('\n').map(parseCommitLine).filter(Boolean)
489
497
  }
490
498
 
@@ -521,6 +529,9 @@ export async function mergeTaskWorktree({
521
529
 
522
530
  // 1. Verify worktree cleanliness
523
531
  const dirtyCheck = await checkWorktreeDirty({ worktreePath: task.worktree, gitRunner })
532
+ if (dirtyCheck.error) {
533
+ return { success: false, merged: false, error: 'worktree-status-error', detail: dirtyCheck.error }
534
+ }
524
535
  if (dirtyCheck.dirty) {
525
536
  return { success: false, merged: false, error: 'worktree-dirty', files: dirtyCheck.files }
526
537
  }
@@ -528,7 +539,7 @@ export async function mergeTaskWorktree({
528
539
  // 2. Locate main repository root
529
540
  let mainRepoDir = ''
530
541
  const revParse = await gitRunner(['rev-parse', '--git-common-dir'], task.worktree)
531
- if (revParse.exitCode === 0 && revParse.stdout.trim()) {
542
+ if ((revParse?.exitCode ?? revParse?.code ?? 0) === 0 && revParse.stdout.trim()) {
532
543
  const commonDir = revParse.stdout.trim()
533
544
  mainRepoDir = commonDir.endsWith('/.git') ? commonDir.slice(0, -5) : commonDir
534
545
  }
@@ -551,7 +562,7 @@ export async function mergeTaskWorktree({
551
562
  const currentBranch = await gitRunner(['branch', '--show-current'], mainRepoDir)
552
563
  if (currentBranch.stdout.trim() !== target) {
553
564
  const checkoutRes = await gitRunner(['checkout', '--', target], mainRepoDir)
554
- if (checkoutRes.exitCode !== 0) {
565
+ if ((checkoutRes?.exitCode ?? checkoutRes?.code ?? 0) !== 0) {
555
566
  return { success: false, merged: false, error: 'checkout-target-failed', detail: checkoutRes.stderr }
556
567
  }
557
568
  }
@@ -559,7 +570,7 @@ export async function mergeTaskWorktree({
559
570
  // 5. Execute git merge --no-ff
560
571
  const mergeMsg = `Merge branch '${task.branch}' for task ${task.id}`
561
572
  const mergeRes = await gitRunner(['merge', '--no-ff', task.branch, '-m', mergeMsg], mainRepoDir)
562
- if (mergeRes.exitCode !== 0) {
573
+ if ((mergeRes?.exitCode ?? mergeRes?.code ?? 0) !== 0) {
563
574
  // Roll back merge on conflict
564
575
  await gitRunner(['merge', '--abort'], mainRepoDir)
565
576
  return { success: false, merged: false, error: 'merge-conflict', detail: mergeRes.stderr || mergeRes.stdout }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-kanban",
3
- "version": "0.2.21",
3
+ "version": "0.2.23",
4
4
  "description": "Visual Kanban board for DeepSeek Harness: Gitea and GitHub-backed tasks, workflow columns, and a dedicated agent session per task.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",