aiwcli 0.12.8 → 0.13.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.
Files changed (81) hide show
  1. package/dist/commands/clean.d.ts +7 -0
  2. package/dist/commands/clean.js +17 -8
  3. package/dist/commands/clear.d.ts +85 -0
  4. package/dist/commands/clear.js +455 -347
  5. package/dist/commands/init/index.d.ts +15 -0
  6. package/dist/commands/init/index.js +79 -38
  7. package/dist/lib/gitignore-manager.js +12 -13
  8. package/dist/lib/settings-hierarchy.d.ts +13 -1
  9. package/dist/lib/settings-hierarchy.js +1 -1
  10. package/dist/lib/template-linter.d.ts +4 -0
  11. package/dist/lib/template-linter.js +1 -1
  12. package/dist/lib/tty-detection.d.ts +1 -0
  13. package/dist/lib/tty-detection.js +1 -0
  14. package/dist/templates/CLAUDE.md +1 -1
  15. package/dist/templates/_shared/.claude/settings.json +7 -7
  16. package/dist/templates/_shared/.claude/skills/handoff/SKILL.md +1 -1
  17. package/dist/templates/_shared/.claude/skills/handoff-resume/SKILL.md +1 -1
  18. package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +43 -0
  19. package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
  20. package/dist/templates/_shared/.codex/workflows/meta-plan.md +347 -0
  21. package/dist/templates/_shared/.windsurf/workflows/handoff.md +1 -1
  22. package/dist/templates/_shared/.windsurf/workflows/meta-plan.md +347 -0
  23. package/dist/templates/_shared/hooks-ts/lint_after_edit.ts +59 -0
  24. package/dist/templates/_shared/hooks-ts/session_end.ts +11 -10
  25. package/dist/templates/_shared/hooks-ts/session_start.ts +15 -12
  26. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -12
  27. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +26 -7
  28. package/dist/templates/_shared/lib-ts/base/inference.ts +16 -16
  29. package/dist/templates/_shared/lib-ts/base/lint-dispatch.ts +287 -0
  30. package/dist/templates/_shared/lib-ts/base/state-io.ts +4 -3
  31. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +3 -3
  32. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +16 -15
  33. package/dist/templates/_shared/lib-ts/context/context-selector.ts +16 -16
  34. package/dist/templates/_shared/lib-ts/context/context-store.ts +15 -14
  35. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +2 -2
  36. package/dist/templates/_shared/scripts/resolve-run.ts +61 -0
  37. package/dist/templates/_shared/scripts/resolve_context.ts +1 -1
  38. package/dist/templates/_shared/scripts/status_line.ts +74 -65
  39. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/CLAUDE.md +10 -10
  40. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/document-generator.ts +5 -4
  41. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/handoff-reader.ts +2 -1
  42. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/resume_handoff.ts +6 -6
  43. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/save_handoff.ts +16 -17
  44. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff-resume.md +2 -2
  45. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff.md +3 -3
  46. package/dist/templates/_shared/skills/meta-plan/CLAUDE.md +44 -0
  47. package/dist/templates/_shared/skills/meta-plan/workflows/meta-plan.md +347 -0
  48. package/dist/templates/cc-native/.claude/settings.json +84 -56
  49. package/dist/templates/cc-native/_cc-native/artifacts/lib/format.ts +8 -6
  50. package/dist/templates/cc-native/_cc-native/artifacts/lib/index.ts +11 -11
  51. package/dist/templates/cc-native/_cc-native/artifacts/lib/tracker.ts +7 -6
  52. package/dist/templates/cc-native/_cc-native/artifacts/lib/write.ts +17 -16
  53. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +9 -7
  54. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +2 -2
  55. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +15 -16
  56. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +19 -19
  57. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +3 -3
  58. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +16 -12
  59. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +2 -3
  60. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
  61. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +7 -6
  62. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +9 -7
  63. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +17 -14
  64. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +41 -37
  65. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +43 -33
  66. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
  67. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +9 -8
  68. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +4 -3
  69. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +8 -9
  70. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +20 -19
  71. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +1 -1
  72. package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +2 -3
  73. package/dist/templates/cc-native/_cc-native/plan-review/lib/graduation.ts +1 -1
  74. package/dist/templates/cc-native/_cc-native/plan-review/lib/orchestrator.ts +1 -1
  75. package/dist/templates/cc-native/_cc-native/plan-review/lib/output-builder.ts +12 -21
  76. package/dist/templates/cc-native/_cc-native/plan-review/lib/plan-questions.ts +3 -4
  77. package/dist/templates/cc-native/_cc-native/plan-review/lib/review-pipeline.ts +35 -39
  78. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/agent.ts +2 -3
  79. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/codex-agent.ts +1 -1
  80. package/oclif.manifest.json +1 -1
  81. package/package.json +6 -5
@@ -9,7 +9,7 @@
9
9
 
10
10
  import * as fs from "node:fs";
11
11
  import * as path from "node:path";
12
- import { readStateJson, writeStateJson, toDict, dictToState } from "../base/state-io.js";
12
+
13
13
  import { atomicWrite } from "../base/atomic-write.js";
14
14
  import {
15
15
  getContextDir,
@@ -20,7 +20,8 @@ import {
20
20
  getArchiveIndexPath,
21
21
  validateContextId,
22
22
  } from "../base/constants.js";
23
- import { logDebug, logInfo, logWarn, logError, setContextPath } from "../base/logger.js";
23
+ import { logInfo, logWarn, logError, setContextPath } from "../base/logger.js";
24
+ import { readStateJson, writeStateJson } from "../base/state-io.js";
24
25
  import { nowIso, generateContextId } from "../base/utils.js";
25
26
  import type { ContextState, IndexFile, IndexEntry, Mode } from "../types.js";
26
27
 
@@ -77,8 +78,8 @@ function loadIndex(projectRoot?: string): IndexFile {
77
78
  try {
78
79
  const raw = fs.readFileSync(indexPath, "utf-8");
79
80
  return JSON.parse(raw) as IndexFile;
80
- } catch (e: any) {
81
- logWarn("context_store", `Failed to read index, recreating: ${e}`);
81
+ } catch (error: any) {
82
+ logWarn("context_store", `Failed to read index, recreating: ${error}`);
82
83
  }
83
84
  }
84
85
  return { version: INDEX_VERSION, updated_at: nowIso(), sessions: {}, contexts: {} };
@@ -145,8 +146,8 @@ function migrateContextJson(contextId: string, projectRoot?: string): ContextSta
145
146
  last_session: null,
146
147
  tasks: [],
147
148
  };
148
- } catch (e: any) {
149
- logWarn("context_store", `Failed to migrate context.json for '${contextId}': ${e}`);
149
+ } catch (error: any) {
150
+ logWarn("context_store", `Failed to migrate context.json for '${contextId}': ${error}`);
150
151
  return null;
151
152
  }
152
153
  }
@@ -556,8 +557,8 @@ export function archiveContext(contextId: string, projectRoot?: string): Context
556
557
 
557
558
  try {
558
559
  fs.renameSync(sourceDir, archiveDest);
559
- } catch (e: any) {
560
- logError("context_store", `Failed to move context to archive: ${e}`);
560
+ } catch (error: any) {
561
+ logError("context_store", `Failed to move context to archive: ${error}`);
561
562
  return null;
562
563
  }
563
564
 
@@ -647,8 +648,8 @@ function updateArchiveIndex(state: ContextState, projectRoot?: string): boolean
647
648
  if (fs.existsSync(archiveIndexPath)) {
648
649
  try {
649
650
  archiveIndex = JSON.parse(fs.readFileSync(archiveIndexPath, "utf-8"));
650
- } catch (e: any) {
651
- logWarn("context_store", `Failed to read archive index, recreating: ${e}`);
651
+ } catch (error_: any) {
652
+ logWarn("context_store", `Failed to read archive index, recreating: ${error_}`);
652
653
  }
653
654
  }
654
655
 
@@ -675,8 +676,8 @@ function restoreFromArchive(contextId: string, projectRoot?: string): ContextSta
675
676
 
676
677
  try {
677
678
  fs.renameSync(archiveDir, activeDir);
678
- } catch (e: any) {
679
- logError("context_store", `Failed to restore context from archive: ${e}`);
679
+ } catch (error: any) {
680
+ logError("context_store", `Failed to restore context from archive: ${error}`);
680
681
  return null;
681
682
  }
682
683
 
@@ -705,8 +706,8 @@ function removeFromArchiveIndex(contextId: string, projectRoot?: string): boolea
705
706
  }
706
707
  }
707
708
  return true;
708
- } catch (e: any) {
709
- logWarn("context_store", `Failed to read archive index: ${e}`);
709
+ } catch (error: any) {
710
+ logWarn("context_store", `Failed to read archive index: ${error}`);
710
711
  return false;
711
712
  }
712
713
  }
@@ -13,10 +13,9 @@ import * as fs from "node:fs";
13
13
  import * as path from "node:path";
14
14
 
15
15
  import { atomicWrite } from "../base/atomic-write.js";
16
- import { getContextDir, getContextPlansDir, sanitizeTitle } from "../base/constants.js";
16
+ import { getContextPlansDir, sanitizeTitle } from "../base/constants.js";
17
17
  import { logDebug, logInfo, logWarn, logError } from "../base/logger.js";
18
18
  import { generateSlug } from "../base/utils.js";
19
- import type { ContextState } from "../types.js";
20
19
 
21
20
  // ---------------------------------------------------------------------------
22
21
  // Plan archival
@@ -144,6 +143,7 @@ export function findLatestPlan(
144
143
  // 1. Check state.json plan_path first
145
144
  try {
146
145
  // Dynamic import to avoid circular dependency at module level
146
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, no-undef -- dynamic require to avoid circular dependency
147
147
  const stateIo = require("../base/state-io.js");
148
148
  const state = stateIo.readStateJson(contextId, projectRoot);
149
149
  if (state?.plan_path && fs.existsSync(state.plan_path)) {
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Cross-platform project root resolver for hook and status line commands.
4
+ *
5
+ * Finds the project root (via git or .aiwcli/ anchor walk-up), then spawns
6
+ * the target script with cwd set to the root. stdin/stdout/stderr pass through.
7
+ *
8
+ * Install: ~/.aiwcli/bin/resolve-run.ts (global, always findable via ~)
9
+ * Usage: bun ~/.aiwcli/bin/resolve-run.ts .aiwcli/_shared/scripts/status_line.ts
10
+ *
11
+ * Works on: bash, zsh, PowerShell, cmd (anywhere bun + ~ expansion works)
12
+ */
13
+ import { execSync } from "node:child_process";
14
+ import * as fs from "node:fs";
15
+ import * as path from "node:path";
16
+
17
+ function findProjectRoot(): string {
18
+ // 1. git (works from any subdirectory of a repo)
19
+ try {
20
+ const root = execSync("git rev-parse --show-toplevel", {
21
+ encoding: "utf-8",
22
+ stdio: ["pipe", "pipe", "pipe"],
23
+ timeout: 2000,
24
+ }).trim();
25
+ if (root && fs.existsSync(path.join(root, ".aiwcli"))) return root;
26
+ } catch { /* not a git repo or git not available */ }
27
+
28
+ // 2. Walk up from cwd to find .aiwcli/ anchor
29
+ let dir = process.cwd();
30
+ while (true) {
31
+ if (fs.existsSync(path.join(dir, ".aiwcli"))) return dir;
32
+ const parent = path.dirname(dir);
33
+ if (parent === dir) break;
34
+ dir = parent;
35
+ }
36
+
37
+ return process.cwd(); // last resort
38
+ }
39
+
40
+ const target = process.argv[2];
41
+ if (!target) {
42
+ process.stderr.write("resolve-run: missing script path argument\n");
43
+ process.exit(1);
44
+ }
45
+
46
+ const root = findProjectRoot();
47
+ const fullPath = path.resolve(root, target);
48
+
49
+ if (!fs.existsSync(fullPath)) {
50
+ process.stderr.write(`resolve-run: script not found: ${fullPath}\n`);
51
+ process.exit(1);
52
+ }
53
+
54
+ const result = Bun.spawnSync(["bun", fullPath], {
55
+ stdin: "inherit",
56
+ stdout: "inherit",
57
+ stderr: "inherit",
58
+ cwd: root,
59
+ });
60
+
61
+ process.exit(result.exitCode);
@@ -11,9 +11,9 @@
11
11
  *
12
12
  * Requires CLAUDE_SESSION_ID environment variable (set by Claude Code).
13
13
  */
14
- import { getContextBySessionId } from "../lib-ts/context/context-store.js";
15
14
  import { getProjectRoot } from "../lib-ts/base/constants.js";
16
15
  import { eprint } from "../lib-ts/base/utils.js";
16
+ import { getContextBySessionId } from "../lib-ts/context/context-store.js";
17
17
 
18
18
  const projectRoot = getProjectRoot(process.cwd());
19
19
  const sessionId = process.env.CLAUDE_SESSION_ID;
@@ -22,7 +22,10 @@ import { findLatestPlan } from "../lib-ts/context/plan-manager.js";
22
22
  // Path setup
23
23
  // ---------------------------------------------------------------------------
24
24
  const SCRIPT_DIR = path.dirname(new URL(import.meta.url).pathname);
25
- const OUTPUT_DIR = path.join(".", "_output");
25
+ // Resolve project root from script location (.aiwcli/_shared/scripts/) so paths
26
+ // work even when cwd has drifted via `cd` in a Bash tool call.
27
+ const PROJECT_ROOT = path.resolve(SCRIPT_DIR, "..", "..", "..");
28
+ const OUTPUT_DIR = path.join(PROJECT_ROOT, "_output");
26
29
  const CACHE_DIR = path.join(OUTPUT_DIR, "cache");
27
30
  const STATUSLINE_CACHE = path.join(CACHE_DIR, ".statusline-cache.json");
28
31
 
@@ -342,89 +345,97 @@ function getGitStatus(cwd: string): GitStatus | null {
342
345
  return status;
343
346
  }
344
347
 
345
- function renderGit(mode: string, git: GitStatus, dirName: string): void {
346
- const totalChanged = git.modified + git.staged;
347
- const statusIcon = (totalChanged > 0 || git.untracked > 0) ? "*" : "\u2713";
348
+ function renderGit(mode: string, git: GitStatus | null, dirName: string): void {
349
+ const totalChanged = git ? git.modified + git.staged : 0;
350
+ const statusIcon = git && (totalChanged > 0 || git.untracked > 0) ? "*" : "\u2713";
348
351
 
349
352
  switch (mode) {
350
353
  case "micro": {
351
- let line = `${GIT_PRIMARY}\u25C8${RESET} ${GIT_DIR}${dirName}${RESET} ${GIT_VALUE}${git.branch}${RESET}`;
352
- if (git.age_display) {
353
- line += ` ${git.age_color}${git.age_display}${RESET}`;
354
- }
355
- line += " ";
356
- if (statusIcon === "\u2713") {
357
- line += `${GIT_CLEAN}${statusIcon}${RESET}`;
358
- } else {
359
- line += `${GIT_MODIFIED}${statusIcon}${totalChanged}${RESET}`;
354
+ let line = `${GIT_PRIMARY}\u25C8${RESET} ${GIT_DIR}${dirName}${RESET}`;
355
+ if (git) {
356
+ line += ` ${GIT_VALUE}${git.branch}${RESET}`;
357
+ if (git.age_display) {
358
+ line += ` ${git.age_color}${git.age_display}${RESET}`;
359
+ }
360
+ line += " ";
361
+ if (statusIcon === "\u2713") {
362
+ line += `${GIT_CLEAN}${statusIcon}${RESET}`;
363
+ } else {
364
+ line += `${GIT_MODIFIED}${statusIcon}${totalChanged}${RESET}`;
365
+ }
360
366
  }
361
367
  console.log(line);
362
-
368
+
363
369
  break;
364
370
  }
365
371
  case "mini": {
366
- let line =
367
- `${GIT_PRIMARY}\u25C8${RESET} ${GIT_DIR}${dirName}${RESET} ` +
368
- `${SLATE_600}\u2502${RESET} ${GIT_VALUE}${git.branch}${RESET}`;
369
- if (git.age_display) {
370
- line += ` ${SLATE_600}\u2502${RESET} ${git.age_color}${git.age_display}${RESET}`;
371
- }
372
- line += ` ${SLATE_600}\u2502${RESET} `;
373
- if (statusIcon === "\u2713") {
374
- line += `${GIT_CLEAN}${statusIcon}${RESET}`;
375
- } else {
376
- line += `${GIT_MODIFIED}${statusIcon}${totalChanged}${RESET}`;
377
- if (git.untracked > 0) {
378
- line += ` ${GIT_ADDED}+${git.untracked}${RESET}`;
372
+ let line = `${GIT_PRIMARY}\u25C8${RESET} ${GIT_DIR}${dirName}${RESET}`;
373
+ if (git) {
374
+ line += ` ${SLATE_600}\u2502${RESET} ${GIT_VALUE}${git.branch}${RESET}`;
375
+ if (git.age_display) {
376
+ line += ` ${SLATE_600}\u2502${RESET} ${git.age_color}${git.age_display}${RESET}`;
377
+ }
378
+ line += ` ${SLATE_600}\u2502${RESET} `;
379
+ if (statusIcon === "\u2713") {
380
+ line += `${GIT_CLEAN}${statusIcon}${RESET}`;
381
+ } else {
382
+ line += `${GIT_MODIFIED}${statusIcon}${totalChanged}${RESET}`;
383
+ if (git.untracked > 0) {
384
+ line += ` ${GIT_ADDED}+${git.untracked}${RESET}`;
385
+ }
379
386
  }
380
387
  }
381
388
  console.log(line);
382
-
389
+
383
390
  break;
384
391
  }
385
392
  case "nano": {
386
- let line = `${GIT_PRIMARY}\u25C8${RESET} ${GIT_DIR}${dirName}${RESET} ${GIT_VALUE}${git.branch}${RESET} `;
387
- if (statusIcon === "\u2713") {
388
- line += `${GIT_CLEAN}\u2713${RESET}`;
389
- } else {
390
- line += `${GIT_MODIFIED}*${totalChanged}${RESET}`;
393
+ let line = `${GIT_PRIMARY}\u25C8${RESET} ${GIT_DIR}${dirName}${RESET}`;
394
+ if (git) {
395
+ line += ` ${GIT_VALUE}${git.branch}${RESET} `;
396
+ if (statusIcon === "\u2713") {
397
+ line += `${GIT_CLEAN}\u2713${RESET}`;
398
+ } else {
399
+ line += `${GIT_MODIFIED}*${totalChanged}${RESET}`;
400
+ }
391
401
  }
392
402
  console.log(line);
393
-
403
+
394
404
  break;
395
405
  }
396
406
  default: {
397
- let line =
398
- `${GIT_PRIMARY}\u25C8${RESET} ${GIT_PRIMARY}PWD:${RESET} ${GIT_DIR}${dirName}${RESET} ` +
399
- `${SLATE_600}\u2502${RESET} ` +
400
- `${GIT_PRIMARY}Branch:${RESET} ${GIT_VALUE}${git.branch}${RESET}`;
401
- if (git.age_display) {
402
- line += ` ${SLATE_600}\u2502${RESET} ${GIT_PRIMARY}Age:${RESET} ${git.age_color}${git.age_display}${RESET}`;
403
- }
404
- if (git.stash_count > 0) {
405
- line += ` ${SLATE_600}\u2502${RESET} ${GIT_PRIMARY}Stash:${RESET} ${GIT_STASH}${git.stash_count}${RESET}`;
406
- }
407
-
408
- if (totalChanged > 0 || git.untracked > 0) {
409
- line += ` ${SLATE_600}\u2502${RESET} `;
410
- if (totalChanged > 0) {
411
- line += `${GIT_PRIMARY}Mod:${RESET} ${GIT_MODIFIED}${totalChanged}${RESET}`;
407
+ let line = `${GIT_PRIMARY}\u25C8${RESET} ${GIT_PRIMARY}PWD:${RESET} ${GIT_DIR}${dirName}${RESET}`;
408
+ if (git) {
409
+ line += ` ${SLATE_600}\u2502${RESET} ` +
410
+ `${GIT_PRIMARY}Branch:${RESET} ${GIT_VALUE}${git.branch}${RESET}`;
411
+ if (git.age_display) {
412
+ line += ` ${SLATE_600}\u2502${RESET} ${GIT_PRIMARY}Age:${RESET} ${git.age_color}${git.age_display}${RESET}`;
412
413
  }
413
- if (git.untracked > 0) {
414
- if (totalChanged > 0) line += " ";
415
- line += `${GIT_PRIMARY}New:${RESET} ${GIT_ADDED}${git.untracked}${RESET}`;
414
+ if (git.stash_count > 0) {
415
+ line += ` ${SLATE_600}\u2502${RESET} ${GIT_PRIMARY}Stash:${RESET} ${GIT_STASH}${git.stash_count}${RESET}`;
416
416
  }
417
- } else {
418
- line += ` ${SLATE_600}\u2502${RESET} ${GIT_CLEAN}\u2713 clean${RESET}`;
419
- }
420
417
 
421
- if (git.ahead > 0 || git.behind > 0) {
422
- line += ` ${SLATE_600}\u2502${RESET} ${GIT_PRIMARY}Sync:${RESET} `;
423
- if (git.ahead > 0) {
424
- line += `${GIT_CLEAN}\u2191${git.ahead}${RESET}`;
418
+ if (totalChanged > 0 || git.untracked > 0) {
419
+ line += ` ${SLATE_600}\u2502${RESET} `;
420
+ if (totalChanged > 0) {
421
+ line += `${GIT_PRIMARY}Mod:${RESET} ${GIT_MODIFIED}${totalChanged}${RESET}`;
422
+ }
423
+ if (git.untracked > 0) {
424
+ if (totalChanged > 0) line += " ";
425
+ line += `${GIT_PRIMARY}New:${RESET} ${GIT_ADDED}${git.untracked}${RESET}`;
426
+ }
427
+ } else {
428
+ line += ` ${SLATE_600}\u2502${RESET} ${GIT_CLEAN}\u2713 clean${RESET}`;
425
429
  }
426
- if (git.behind > 0) {
427
- line += `${GIT_STASH}\u2193${git.behind}${RESET}`;
430
+
431
+ if (git.ahead > 0 || git.behind > 0) {
432
+ line += ` ${SLATE_600}\u2502${RESET} ${GIT_PRIMARY}Sync:${RESET} `;
433
+ if (git.ahead > 0) {
434
+ line += `${GIT_CLEAN}\u2191${git.ahead}${RESET}`;
435
+ }
436
+ if (git.behind > 0) {
437
+ line += `${GIT_STASH}\u2193${git.behind}${RESET}`;
438
+ }
428
439
  }
429
440
  }
430
441
  console.log(line);
@@ -684,11 +695,9 @@ function main(): void {
684
695
  // Render context section
685
696
  renderContext(mode, contextPct, contextK, maxK, timeDisplay, modelName);
686
697
 
687
- // Render git section
698
+ // Render PWD + git section (PWD always shown, git stats only when in a repo)
688
699
  const git = getGitStatus(currentDir);
689
- if (git) {
690
- renderGit(mode, git, dirName);
691
- }
700
+ renderGit(mode, git, dirName);
692
701
 
693
702
  // Render context manager line (line 3) with separator
694
703
  console.log(SEPARATOR);
@@ -173,7 +173,7 @@ If `plan_hash` differs from `plan_hash_consumed`, new plan detected:
173
173
 
174
174
  **Usage:**
175
175
  ```bash
176
- bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts [--context-id ID] [--session-id SID] < handoff.md
176
+ bun .aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts [--context-id ID] [--session-id SID] < handoff.md
177
177
  ```
178
178
 
179
179
  **Stdin format:**
@@ -209,13 +209,13 @@ If timestamp folder exists, appends `-2`, `-3`, etc.
209
209
  **Usage:**
210
210
  ```bash
211
211
  # Auto-discover from current session
212
- bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts
212
+ bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts
213
213
 
214
214
  # Explicit handoff path
215
- bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts path/to/handoff/index.md
215
+ bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts path/to/handoff/index.md
216
216
 
217
217
  # Explicit context
218
- bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts --context context-id
218
+ bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts --context context-id
219
219
  ```
220
220
 
221
221
  **Output format (to stdout):**
@@ -257,7 +257,7 @@ Uses `CLAUDE_SESSION_ID` env var → lookup context → find latest handoff in `
257
257
 
258
258
  ### handoff-reader.ts
259
259
 
260
- **Location:** `_shared/handoff-system/lib/handoff-reader.ts`
260
+ **Location:** `_shared/skills/handoff-system/lib/handoff-reader.ts`
261
261
 
262
262
  **Exports:**
263
263
 
@@ -292,7 +292,7 @@ const SECTION_FILES = {
292
292
 
293
293
  ### document-generator.ts
294
294
 
295
- **Location:** `_shared/handoff-system/lib/document-generator.ts`
295
+ **Location:** `_shared/skills/handoff-system/lib/document-generator.ts`
296
296
 
297
297
  **Exports:**
298
298
 
@@ -316,7 +316,7 @@ function buildDeadEndsSection(deadEnds: DeadEnd[]): string
316
316
  **Thin pointer pattern:**
317
317
 
318
318
  `.claude/skills/handoff/SKILL.md` (user-facing, discoverable via `/`, `user-invocable: true`)
319
- → References `.aiwcli/_shared/handoff-system/workflows/handoff.md` (detailed procedural steps)
319
+ → References `.aiwcli/_shared/skills/handoff-system/workflows/handoff.md` (detailed procedural steps)
320
320
 
321
321
  **Benefits:**
322
322
  - Skill files stay concise (easy to scan in `/` menu)
@@ -325,7 +325,7 @@ function buildDeadEndsSection(deadEnds: DeadEnd[]): string
325
325
 
326
326
  **Example reference format:**
327
327
  ```markdown
328
- See `.aiwcli/_shared/handoff-system/workflows/handoff.md` for complete process documentation.
328
+ See `.aiwcli/_shared/skills/handoff-system/workflows/handoff.md` for complete process documentation.
329
329
  ```
330
330
 
331
331
  ## Testing
@@ -406,7 +406,7 @@ Expected: No import errors, clean execution.
406
406
  ## Gotchas
407
407
 
408
408
  **Template sync is mandatory:**
409
- Both `.aiwcli/_shared/handoff-system/` (working copy) and `packages/cli/src/templates/_shared/handoff-system/` (template source) must stay in sync per CLAUDE.md template sync rules.
409
+ Both `.aiwcli/_shared/skills/handoff-system/` (working copy) and `packages/cli/src/templates/_shared/skills/handoff-system/` (template source) must stay in sync per CLAUDE.md template sync rules.
410
410
 
411
411
  **Import paths after move:**
412
412
  - From `scripts/resume_handoff.ts` → `lib/handoff-reader.ts`: `../lib/handoff-reader.js`
@@ -418,7 +418,7 @@ Both `.aiwcli/_shared/handoff-system/` (working copy) and `packages/cli/src/temp
418
418
  - No direct handoff-reader dependency in hooks
419
419
 
420
420
  **Command file script paths are absolute:**
421
- - Reference from project root: `.aiwcli/_shared/handoff-system/scripts/save_handoff.ts`
421
+ - Reference from project root: `.aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts`
422
422
  - NOT relative to command file location
423
423
 
424
424
  **Section markers must be HTML comments:**
@@ -6,17 +6,18 @@
6
6
  * work to a new session (typically due to context window limits).
7
7
  */
8
8
 
9
+ import * as crypto from "node:crypto";
9
10
  import * as fs from "node:fs";
10
11
  import * as path from "node:path";
11
- import * as crypto from "node:crypto";
12
- import { getContextHandoffsDir, getContextDir } from "../base/constants.js";
12
+
13
13
  import { atomicWrite } from "../base/atomic-write.js";
14
+ import { getContextHandoffsDir, getContextDir } from "../base/constants.js";
14
15
  import { logInfo, logError } from "../base/logger.js";
15
16
  import { nowIso } from "../base/utils.js";
16
- import { getContext, saveState } from "../context/context-store.js";
17
+ import { getContext } from "../context/context-store.js";
17
18
  import { getTasks } from "../context/task-tracker.js";
18
19
  import { renderTaskList, formatContinuationHeader, formatReason } from "../templates/formatters.js";
19
- import type { HandoffDocument, Task } from "../types.js";
20
+ import type { HandoffDocument } from "../types.js";
20
21
 
21
22
  /**
22
23
  * Generate and save a handoff document for a context.
@@ -8,6 +8,7 @@
8
8
 
9
9
  import * as fs from "node:fs";
10
10
  import * as path from "node:path";
11
+
11
12
  import { getContextHandoffsDir } from "../../lib-ts/base/constants.js";
12
13
  import { getContext } from "../../lib-ts/context/context-store.js";
13
14
  import type { HandoffSections } from "../../lib-ts/types.js";
@@ -29,7 +30,7 @@ export function findLatestHandoff(contextId: string, projectRoot?: string): stri
29
30
  .sort();
30
31
 
31
32
  if (entries.length === 0) return null;
32
- return path.join(handoffsDir, entries[entries.length - 1]!);
33
+ return path.join(handoffsDir, entries.at(-1)!);
33
34
  } catch {
34
35
  return null;
35
36
  }
@@ -4,8 +4,8 @@
4
4
  * a structured briefing to stdout.
5
5
  *
6
6
  * Usage:
7
- * bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts <handoff_folder_or_index>
8
- * bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts --context <context_id>
7
+ * bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts <handoff_folder_or_index>
8
+ * bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts --context <context_id>
9
9
  *
10
10
  * If no args, auto-discovers the active context and finds the latest handoff.
11
11
  *
@@ -15,16 +15,16 @@
15
15
  import * as fs from "node:fs";
16
16
  import * as path from "node:path";
17
17
 
18
+ import { getProjectRoot } from "../../lib-ts/base/constants.js";
19
+ import { getGitStatusShort } from "../../lib-ts/base/git-state.js";
20
+ import { eprint } from "../../lib-ts/base/utils.js";
21
+ import { getContextBySessionId } from "../../lib-ts/context/context-store.js";
18
22
  import {
19
23
  findLatestHandoff,
20
24
  readHandoffSections,
21
25
  getHandoffTimestamp,
22
26
  getHandoffPlanReference,
23
27
  } from "../lib/handoff-reader.js";
24
- import { getProjectRoot } from "../../lib-ts/base/constants.js";
25
- import { getContextBySessionId } from "../../lib-ts/context/context-store.js";
26
- import { getGitStatusShort } from "../../lib-ts/base/git-state.js";
27
- import { eprint } from "../../lib-ts/base/utils.js";
28
28
 
29
29
  // ---------------------------------------------------------------------------
30
30
  // Helpers
@@ -3,12 +3,12 @@
3
3
  * Save a handoff document with folder-based sharding.
4
4
  *
5
5
  * Usage:
6
- * bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts <<'EOF'
6
+ * bun .aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts <<'EOF'
7
7
  * # Your handoff markdown content here (with <!-- SECTION: name --> markers)
8
8
  * EOF
9
9
  *
10
10
  * Or with a file:
11
- * bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts < handoff.md
11
+ * bun .aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts < handoff.md
12
12
  *
13
13
  * This script:
14
14
  * 1. Auto-resolves the active context ID
@@ -23,12 +23,12 @@
23
23
  import * as fs from "node:fs";
24
24
  import * as path from "node:path";
25
25
 
26
- import { getContext, saveState, getContextBySessionId, getAllContexts } from "../../lib-ts/context/context-store.js";
27
- import { getHandoffFolderPath, getProjectRoot } from "../../lib-ts/base/constants.js";
28
26
  import { atomicWrite } from "../../lib-ts/base/atomic-write.js";
29
- import { logInfo, logWarn, logError } from "../../lib-ts/base/logger.js";
27
+ import { getHandoffFolderPath, getProjectRoot } from "../../lib-ts/base/constants.js";
30
28
  import { getGitStatusShort } from "../../lib-ts/base/git-state.js";
29
+ import { logInfo, logWarn, logError } from "../../lib-ts/base/logger.js";
31
30
  import { eprint } from "../../lib-ts/base/utils.js";
31
+ import { getContext, saveState, getContextBySessionId, getAllContexts } from "../../lib-ts/context/context-store.js";
32
32
 
33
33
  // ---------------------------------------------------------------------------
34
34
  // Parsing helpers
@@ -333,8 +333,8 @@ function main(): void {
333
333
  } else {
334
334
  logWarn("save_handoff", `Failed to copy plan to handoff: ${error}`);
335
335
  }
336
- } catch (e) {
337
- logWarn("save_handoff", `Plan update failed (non-critical): ${e}`);
336
+ } catch (error) {
337
+ logWarn("save_handoff", `Plan update failed (non-critical): ${error}`);
338
338
  }
339
339
  } else if (planPath) {
340
340
  // Fallback: copy unchanged plan if Claude didn't provide an update
@@ -346,8 +346,8 @@ function main(): void {
346
346
  } else {
347
347
  logWarn("save_handoff", `Failed to copy plan: ${error}`);
348
348
  }
349
- } catch (e) {
350
- logWarn("save_handoff", `Failed to read plan: ${e}`);
349
+ } catch (error) {
350
+ logWarn("save_handoff", `Failed to read plan: ${error}`);
351
351
  }
352
352
  }
353
353
 
@@ -384,13 +384,12 @@ function main(): void {
384
384
  // Append mode
385
385
  if (!fileContents[filename]) fileContents[filename] = [];
386
386
  fileContents[filename]!.push(sectionContent);
387
+ } else if (!fileContents[filename]) {
388
+ // Write mode with title — new file
389
+ fileContents[filename] = [`# ${title}`, "", sectionContent];
387
390
  } else {
388
- // Write mode with title
389
- if (!fileContents[filename]) {
390
- fileContents[filename] = [`# ${title}`, "", sectionContent];
391
- } else {
392
- fileContents[filename] = [`# ${title}`, "", ...fileContents[filename]!, "", sectionContent];
393
- }
391
+ // Write mode with title — prepend to existing
392
+ fileContents[filename] = [`# ${title}`, "", ...fileContents[filename]!, "", sectionContent];
394
393
  }
395
394
  }
396
395
 
@@ -449,8 +448,8 @@ function main(): void {
449
448
  } else {
450
449
  logWarn("save_handoff", `Could not load context state for ${contextId}`);
451
450
  }
452
- } catch (e) {
453
- logWarn("save_handoff", `Handoff saved but auto-resume won't work: ${e}`);
451
+ } catch (error) {
452
+ logWarn("save_handoff", `Handoff saved but auto-resume won't work: ${error}`);
454
453
  }
455
454
 
456
455
  // Output success message
@@ -16,13 +16,13 @@ Run the resume script to collect and format all handoff sections:
16
16
 
17
17
  **If `$ARGUMENTS` is provided:**
18
18
  ```bash
19
- bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts "$ARGUMENTS"
19
+ bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts "$ARGUMENTS"
20
20
  ```
21
21
 
22
22
  **If `$ARGUMENTS` is empty:**
23
23
  The script auto-discovers the active context ID programmatically — no manual lookup needed:
24
24
  ```bash
25
- bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts
25
+ bun .aiwcli/_shared/skills/handoff-system/scripts/resume_handoff.ts
26
26
  ```
27
27
 
28
28
  Present the script's output to the conversation. The output is already structured in priority order (dead ends first, then pending items, decisions, git delta, completed work, context notes).
@@ -153,7 +153,7 @@ The closing `EOF` delimiter **MUST** be at column 0 (no leading spaces or tabs).
153
153
 
154
154
  **Correct Example:**
155
155
  ```bash
156
- bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts <<'EOF'
156
+ bun .aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts <<'EOF'
157
157
  content here
158
158
  EOF
159
159
  ```
@@ -161,7 +161,7 @@ EOF
161
161
 
162
162
  **Wrong Example (will fail):**
163
163
  ```bash
164
- bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts <<'EOF'
164
+ bun .aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts <<'EOF'
165
165
  content here
166
166
  EOF
167
167
  ```
@@ -172,7 +172,7 @@ content here
172
172
  Instead of writing the file directly, pipe your handoff content to the save script:
173
173
 
174
174
  ```bash
175
- bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts <<'EOF'
175
+ bun .aiwcli/_shared/skills/handoff-system/scripts/save_handoff.ts <<'EOF'
176
176
  {Your complete handoff markdown content from Step 3}
177
177
  EOF
178
178
  ```