@titan-design/active-work 0.6.0 → 0.7.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/dist/cli.js CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  NotFoundError,
14
14
  NoteFrontmatterSchema,
15
15
  NoteKindSchema,
16
+ SCHEMA_VERSION,
16
17
  SessionFrontmatterSchema,
17
18
  SessionIdSchema,
18
19
  SessionResolveSchema,
@@ -21,11 +22,13 @@ import {
21
22
  TaskSeqSchema,
22
23
  UsageError,
23
24
  ValidationError,
25
+ WORKSPACE_SPAN_SOURCE_BASE,
24
26
  WorktreeEntrySchema,
25
27
  assembleBootstrap,
26
28
  atomicWrite,
27
29
  coerceDates,
28
30
  color,
31
+ defaultGraphPath,
29
32
  defineCommand,
30
33
  deriveOpenLoops,
31
34
  deriveOpenLoopsFrom,
@@ -48,6 +51,8 @@ import {
48
51
  loadNotesFromDir,
49
52
  loadSessionsFromDir,
50
53
  nowIso,
54
+ openGraph,
55
+ openGraphReadOnly,
51
56
  open_default,
52
57
  probeHealth,
53
58
  readArtifactHashes,
@@ -76,7 +81,7 @@ import {
76
81
  writeFrontmatter,
77
82
  writeNoteFile,
78
83
  writeYaml
79
- } from "./chunk-RLSQSE7I.js";
84
+ } from "./chunk-KAR6NOS2.js";
80
85
 
81
86
  // src/cli.ts
82
87
  import { Command, CommanderError } from "commander";
@@ -1517,8 +1522,8 @@ var NO_UPSTREAM = { ahead: null, behind: null };
1517
1522
  function shortBranch(ref) {
1518
1523
  return ref.replace(/^refs\/heads\//, "");
1519
1524
  }
1520
- function emptyWorktree(path68) {
1521
- return { path: path68, head: null, branch: null, detached: false, bare: false };
1525
+ function emptyWorktree(path67) {
1526
+ return { path: path67, head: null, branch: null, detached: false, bare: false };
1522
1527
  }
1523
1528
  function parseWorktreePorcelain(stdout) {
1524
1529
  const out = [];
@@ -3855,144 +3860,6 @@ import { z as z33 } from "zod";
3855
3860
  // src/search/index.ts
3856
3861
  import { createRetrievalEngine, ftsRetriever } from "@titan-design/retrieval";
3857
3862
 
3858
- // src/session-index/graph.ts
3859
- import Database from "better-sqlite3";
3860
- import { openSessionGraph } from "@titan-design/session-graph";
3861
- import { runMigrations, WatermarkTable } from "@titan-design/store-sqlite";
3862
- import path34 from "path";
3863
-
3864
- // src/workspace-index/schema.ts
3865
- import { kitDdl } from "@titan-design/store-sqlite";
3866
- import { MIGRATIONS as SESSION_GRAPH_MIGRATIONS } from "@titan-design/session-graph";
3867
- var WORKSPACE_KIT = {
3868
- watermark: "workspace_file",
3869
- edge: "edge",
3870
- spanFts: "search"
3871
- };
3872
- var WORKSPACE_SPAN_SOURCE_BASE = 1e9;
3873
- var DOMAIN_DDL = `
3874
- CREATE TABLE IF NOT EXISTS initiative (
3875
- path TEXT PRIMARY KEY,
3876
- initiative_ref TEXT NOT NULL UNIQUE,
3877
- slug TEXT NOT NULL,
3878
- title TEXT,
3879
- state TEXT,
3880
- rank INTEGER,
3881
- ship_target TEXT,
3882
- owner TEXT,
3883
- task_prefix TEXT,
3884
- updated TEXT
3885
- );
3886
-
3887
- CREATE TABLE IF NOT EXISTS note (
3888
- path TEXT PRIMARY KEY,
3889
- note_ref TEXT NOT NULL UNIQUE,
3890
- initiative TEXT NOT NULL,
3891
- filename TEXT NOT NULL,
3892
- kind TEXT NOT NULL,
3893
- title TEXT NOT NULL,
3894
- created TEXT,
3895
- tags TEXT,
3896
- hits INTEGER NOT NULL DEFAULT 0,
3897
- promoted_at TEXT
3898
- );
3899
- CREATE INDEX IF NOT EXISTS idx_note_initiative ON note(initiative);
3900
-
3901
- CREATE TABLE IF NOT EXISTS workspace_task (
3902
- path TEXT PRIMARY KEY,
3903
- task_ref TEXT NOT NULL,
3904
- initiative TEXT NOT NULL,
3905
- task_id TEXT NOT NULL,
3906
- title TEXT NOT NULL,
3907
- status TEXT NOT NULL,
3908
- priority INTEGER,
3909
- severity TEXT,
3910
- estimate REAL,
3911
- tags TEXT,
3912
- created TEXT,
3913
- updated TEXT,
3914
- done_at TEXT
3915
- );
3916
- CREATE INDEX IF NOT EXISTS idx_workspace_task_ref ON workspace_task(task_ref);
3917
-
3918
- CREATE TABLE IF NOT EXISTS session_record (
3919
- path TEXT PRIMARY KEY,
3920
- session_ref TEXT NOT NULL,
3921
- initiative TEXT NOT NULL,
3922
- session_id TEXT NOT NULL,
3923
- started TEXT,
3924
- ended TEXT,
3925
- track TEXT,
3926
- parent_session_id TEXT
3927
- );
3928
- CREATE INDEX IF NOT EXISTS idx_session_record_ref ON session_record(session_ref);
3929
-
3930
- CREATE TABLE IF NOT EXISTS source (
3931
- path TEXT PRIMARY KEY,
3932
- source_ref TEXT NOT NULL UNIQUE,
3933
- initiative TEXT NOT NULL,
3934
- title TEXT,
3935
- kind TEXT,
3936
- added TEXT
3937
- );
3938
- `;
3939
- function nextVersion(chain) {
3940
- return (chain[chain.length - 1]?.version ?? 0) + 1;
3941
- }
3942
- var SPAN_SOURCE_INDEX = `
3943
- CREATE INDEX IF NOT EXISTS idx_search_span_source ON search_span(source_id);
3944
- `;
3945
- var WORKSPACE_MIGRATIONS = [
3946
- {
3947
- version: nextVersion(SESSION_GRAPH_MIGRATIONS),
3948
- name: "workspace index tables",
3949
- up: (db) => {
3950
- db.exec(kitDdl({ watermark: WORKSPACE_KIT.watermark }));
3951
- db.exec(DOMAIN_DDL);
3952
- db.exec(SPAN_SOURCE_INDEX);
3953
- }
3954
- }
3955
- ];
3956
- var PRESERVE_DDL = `
3957
- CREATE TABLE IF NOT EXISTS preserved_row (
3958
- table_name TEXT NOT NULL,
3959
- identity TEXT NOT NULL,
3960
- row_key TEXT NOT NULL,
3961
- payload TEXT NOT NULL,
3962
- origin TEXT NOT NULL,
3963
- mode TEXT NOT NULL DEFAULT 'insert',
3964
- preserved_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
3965
- PRIMARY KEY (table_name, row_key)
3966
- );
3967
- `;
3968
- var PRESERVE_MIGRATION = {
3969
- version: nextVersion([...SESSION_GRAPH_MIGRATIONS, ...WORKSPACE_MIGRATIONS]),
3970
- name: "preserved rows",
3971
- up: (db) => db.exec(PRESERVE_DDL)
3972
- };
3973
- var MIGRATIONS = [
3974
- ...SESSION_GRAPH_MIGRATIONS,
3975
- ...WORKSPACE_MIGRATIONS,
3976
- PRESERVE_MIGRATION
3977
- ];
3978
-
3979
- // src/session-index/graph.ts
3980
- var SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
3981
- function defaultGraphPath() {
3982
- return path34.join(getMinerRoot(), "graph.sqlite3");
3983
- }
3984
- function openGraph(dbPath = defaultGraphPath()) {
3985
- const graph = openSessionGraph(dbPath);
3986
- runMigrations(graph.db, MIGRATIONS);
3987
- return {
3988
- ...graph,
3989
- workspaceFiles: new WatermarkTable(graph.db, { name: WORKSPACE_KIT.watermark })
3990
- };
3991
- }
3992
- function openGraphReadOnly(dbPath = defaultGraphPath()) {
3993
- return new Database(dbPath, { readonly: true });
3994
- }
3995
-
3996
3863
  // src/search/classes.ts
3997
3864
  var TRANSCRIPT_FIELDS = ["prompt", "assistant_response", "tool_input", "tool_result"];
3998
3865
  var SEARCH_CLASSES = [
@@ -4028,11 +3895,11 @@ function classOf(ref, field) {
4028
3895
  }
4029
3896
 
4030
3897
  // src/search/resolve.ts
4031
- import path36 from "path";
3898
+ import path35 from "path";
4032
3899
  import { readLocatorText } from "@titan-design/locator";
4033
3900
 
4034
3901
  // src/workspace-index/refs.ts
4035
- import path35 from "path";
3902
+ import path34 from "path";
4036
3903
  import { refKind } from "@titan-design/store-sqlite";
4037
3904
  var initiativeRef = refKind("initiative");
4038
3905
  var noteRef = refKind("note");
@@ -4040,10 +3907,10 @@ var taskRef = refKind("task");
4040
3907
  var sessionRef = refKind("session");
4041
3908
  var sourceRef = refKind("source");
4042
3909
  function toRelative(activeRoot, absolutePath) {
4043
- return path35.relative(activeRoot, absolutePath).split(path35.sep).join("/");
3910
+ return path34.relative(activeRoot, absolutePath).split(path34.sep).join("/");
4044
3911
  }
4045
3912
  function toAbsolute(activeRoot, relativePath) {
4046
- return path35.join(activeRoot, ...relativePath.split("/"));
3913
+ return path34.join(activeRoot, ...relativePath.split("/"));
4047
3914
  }
4048
3915
 
4049
3916
  // src/search/resolve.ts
@@ -4071,7 +3938,7 @@ function fileForSource(graph, sourceId, activeRoot) {
4071
3938
  }
4072
3939
  const row = graph.db.prepare("SELECT source_key FROM transcript WHERE source_id = ?").get(sourceId);
4073
3940
  if (!row) return null;
4074
- return row.source_key.startsWith("~") ? path36.join(process.env.HOME ?? "", row.source_key.slice(1)) : row.source_key;
3941
+ return row.source_key.startsWith("~") ? path35.join(process.env.HOME ?? "", row.source_key.slice(1)) : row.source_key;
4075
3942
  }
4076
3943
  function oneLine(text, width) {
4077
3944
  const flat = text.replace(/\s+/g, " ").trim();
@@ -4304,7 +4171,7 @@ var list_default = defineCommand({
4304
4171
  });
4305
4172
 
4306
4173
  // src/commands/worktree-set.ts
4307
- import path37 from "path";
4174
+ import path36 from "path";
4308
4175
  import { z as z35 } from "zod";
4309
4176
  var argsSchema3 = z35.object({
4310
4177
  slug: z35.string().min(1),
@@ -4321,7 +4188,7 @@ var resultSchema3 = z35.object({
4321
4188
  promoted: z35.boolean()
4322
4189
  });
4323
4190
  var DEFAULT_LABEL = "main";
4324
- var samePath = (a, b) => path37.resolve(expandTilde(a)) === path37.resolve(expandTilde(b));
4191
+ var samePath = (a, b) => path36.resolve(expandTilde(a)) === path36.resolve(expandTilde(b));
4325
4192
  var worktree_set_default = defineCommand({
4326
4193
  name: "worktree.set",
4327
4194
  description: "Add or update a registered worktree on an existing initiative. A lone worktree is made default automatically; use --default to promote an added one. Registered worktrees live in artifacts.yml alongside the ones wrap sweeps, and are what `aw` resolves a cwd against.",
@@ -4343,8 +4210,8 @@ var worktree_set_default = defineCommand({
4343
4210
  },
4344
4211
  async run(args) {
4345
4212
  const label = args.label ?? DEFAULT_LABEL;
4346
- const initiativeDir = path37.join(getActiveRoot(), args.slug);
4347
- const briefPath = path37.join(initiativeDir, "brief.md");
4213
+ const initiativeDir = path36.join(getActiveRoot(), args.slug);
4214
+ const briefPath = path36.join(initiativeDir, "brief.md");
4348
4215
  return withFileLock(getLockPath(args.slug), async () => {
4349
4216
  let frontmatter2;
4350
4217
  let body;
@@ -4398,7 +4265,7 @@ var worktree_set_default = defineCommand({
4398
4265
  });
4399
4266
 
4400
4267
  // src/commands/worktree-set-default.ts
4401
- import path38 from "path";
4268
+ import path37 from "path";
4402
4269
  import { z as z36 } from "zod";
4403
4270
  var argsSchema4 = z36.object({
4404
4271
  slug: z36.string().min(1),
@@ -4417,8 +4284,8 @@ var worktree_set_default_default = defineCommand({
4417
4284
  positional: ["slug", "label"]
4418
4285
  },
4419
4286
  async run({ slug, label }) {
4420
- const initiativeDir = path38.join(getActiveRoot(), slug);
4421
- const briefPath = path38.join(initiativeDir, "brief.md");
4287
+ const initiativeDir = path37.join(getActiveRoot(), slug);
4288
+ const briefPath = path37.join(initiativeDir, "brief.md");
4422
4289
  return withFileLock(getLockPath(slug), async () => {
4423
4290
  let frontmatter2;
4424
4291
  let body;
@@ -4453,7 +4320,7 @@ import { z as z37 } from "zod";
4453
4320
 
4454
4321
  // src/discover/index.ts
4455
4322
  import { promises as fs29 } from "fs";
4456
- import path42 from "path";
4323
+ import path41 from "path";
4457
4324
 
4458
4325
  // src/discover/run-command.ts
4459
4326
  import { spawn } from "child_process";
@@ -4550,13 +4417,13 @@ async function discoverGitHub(repos, run = runCommand) {
4550
4417
  }
4551
4418
 
4552
4419
  // src/discover/git.ts
4553
- import path39 from "path";
4420
+ import path38 from "path";
4554
4421
  var BRANCH_LIMIT = 20;
4555
4422
  async function discoverGit(repoPaths, run = runCommand) {
4556
4423
  const hits = [];
4557
4424
  const errors = [];
4558
4425
  for (const repoPath of repoPaths) {
4559
- const repoName = path39.basename(repoPath);
4426
+ const repoName = path38.basename(repoPath);
4560
4427
  await collectBranches(repoPath, repoName, hits, errors, run);
4561
4428
  await collectWorktrees(repoPath, repoName, hits, errors, run);
4562
4429
  await collectStashes(repoPath, repoName, hits, errors, run);
@@ -4671,14 +4538,14 @@ function errStr(err) {
4671
4538
 
4672
4539
  // src/discover/projects.ts
4673
4540
  import { promises as fs27 } from "fs";
4674
- import path40 from "path";
4541
+ import path39 from "path";
4675
4542
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
4676
4543
  var RECENT_THRESHOLD_DAYS = 30;
4677
4544
  async function discoverProjects(projectsRoot) {
4678
4545
  const hits = [];
4679
4546
  const errors = [];
4680
4547
  if (!projectsRoot) return { hits, errors };
4681
- const resolved = path40.resolve(expandTilde(projectsRoot));
4548
+ const resolved = path39.resolve(expandTilde(projectsRoot));
4682
4549
  let entries;
4683
4550
  try {
4684
4551
  entries = await fs27.readdir(resolved, { withFileTypes: true });
@@ -4694,7 +4561,7 @@ async function discoverProjects(projectsRoot) {
4694
4561
  if (!entry.isDirectory()) continue;
4695
4562
  if (entry.name.startsWith(".")) continue;
4696
4563
  if (entry.name === "active") continue;
4697
- const fullPath = path40.join(resolved, entry.name);
4564
+ const fullPath = path39.join(resolved, entry.name);
4698
4565
  let mtimeMs = 0;
4699
4566
  try {
4700
4567
  const stat = await fs27.stat(fullPath);
@@ -4727,11 +4594,11 @@ async function discoverProjects(projectsRoot) {
4727
4594
  // src/discover/claude.ts
4728
4595
  import { promises as fs28 } from "fs";
4729
4596
  import os2 from "os";
4730
- import path41 from "path";
4597
+ import path40 from "path";
4731
4598
  var MAX_SCAN_LINES = 200;
4732
4599
  var COMPACTION_SUBJECT_PREFIX = "[compaction] ";
4733
4600
  async function discoverClaudeSessions() {
4734
- const root = process.env.CLAUDE_PROJECTS_ROOT ?? path41.join(os2.homedir(), ".claude", "projects");
4601
+ const root = process.env.CLAUDE_PROJECTS_ROOT ?? path40.join(os2.homedir(), ".claude", "projects");
4735
4602
  const hits = [];
4736
4603
  const errors = [];
4737
4604
  let projectDirs;
@@ -4746,7 +4613,7 @@ async function discoverClaudeSessions() {
4746
4613
  const byCwd = /* @__PURE__ */ new Map();
4747
4614
  for (const dir of projectDirs) {
4748
4615
  if (!dir.isDirectory()) continue;
4749
- const dirPath = path41.join(root, dir.name);
4616
+ const dirPath = path40.join(root, dir.name);
4750
4617
  let files;
4751
4618
  try {
4752
4619
  files = await fs28.readdir(dirPath, { withFileTypes: true });
@@ -4759,7 +4626,7 @@ async function discoverClaudeSessions() {
4759
4626
  }
4760
4627
  for (const file of files) {
4761
4628
  if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
4762
- const filePath = path41.join(dirPath, file.name);
4629
+ const filePath = path40.join(dirPath, file.name);
4763
4630
  try {
4764
4631
  await aggregateSession(filePath, byCwd);
4765
4632
  } catch (err) {
@@ -4815,7 +4682,7 @@ async function aggregateSession(filePath, byCwd) {
4815
4682
  }
4816
4683
  if (!cwd) return;
4817
4684
  const subject = lastCompactionSummary ? `${COMPACTION_SUBJECT_PREFIX}${truncate2(lastCompactionSummary, 120)}` : firstUserMessage ? truncate2(firstUserMessage, 120) : "";
4818
- const sessionId = path41.basename(filePath, ".jsonl");
4685
+ const sessionId = path40.basename(filePath, ".jsonl");
4819
4686
  const existing = byCwd.get(cwd);
4820
4687
  if (!existing) {
4821
4688
  byCwd.set(cwd, {
@@ -4915,7 +4782,7 @@ async function loadSlugs(activeRoot) {
4915
4782
  }
4916
4783
  }
4917
4784
  async function loadTriagedRefs(activeRoot) {
4918
- const logPath = path42.join(activeRoot, ".triaged.log");
4785
+ const logPath = path41.join(activeRoot, ".triaged.log");
4919
4786
  const refs = /* @__PURE__ */ new Set();
4920
4787
  try {
4921
4788
  const raw = await fs29.readFile(logPath, "utf8");
@@ -4993,11 +4860,11 @@ import { z as z38 } from "zod";
4993
4860
 
4994
4861
  // src/discover/triaged-log.ts
4995
4862
  import { promises as fs30 } from "fs";
4996
- import path43 from "path";
4863
+ import path42 from "path";
4997
4864
  async function appendTriagedLog(action, ref, extra) {
4998
4865
  const root = getActiveRoot();
4999
4866
  await fs30.mkdir(root, { recursive: true });
5000
- const logPath = path43.join(root, ".triaged.log");
4867
+ const logPath = path42.join(root, ".triaged.log");
5001
4868
  let existing = "";
5002
4869
  try {
5003
4870
  existing = await fs30.readFile(logPath, "utf8");
@@ -5039,7 +4906,7 @@ var drop_default = defineCommand({
5039
4906
 
5040
4907
  // src/commands/fold.ts
5041
4908
  import { promises as fs31 } from "fs";
5042
- import path44 from "path";
4909
+ import path43 from "path";
5043
4910
  import { z as z39 } from "zod";
5044
4911
  var ArgsSchema35 = z39.object({
5045
4912
  ref: z39.string().min(1),
@@ -5081,7 +4948,7 @@ var fold_default = defineCommand({
5081
4948
  if (err instanceof NotFoundError) throw err;
5082
4949
  throw new NotFoundError(`Initiative not found: ${args.into}`);
5083
4950
  }
5084
- const sessionsDir = path44.join(initiativeDir, "sessions");
4951
+ const sessionsDir = path43.join(initiativeDir, "sessions");
5085
4952
  await fs31.mkdir(sessionsDir, { recursive: true });
5086
4953
  const startedIso = nowIso();
5087
4954
  const stem = buildSessionStem(startedIso, `folded-${sanitizeRef(args.ref)}`);
@@ -5114,7 +4981,7 @@ function sanitizeRef(ref) {
5114
4981
 
5115
4982
  // src/commands/track.ts
5116
4983
  import { promises as fs32 } from "fs";
5117
- import path45 from "path";
4984
+ import path44 from "path";
5118
4985
  import { z as z40 } from "zod";
5119
4986
  import { stringify as yamlStringify } from "yaml";
5120
4987
  var ArgsSchema36 = z40.object({
@@ -5161,13 +5028,13 @@ var track_default = defineCommand({
5161
5028
  if (await dirExists5(dir)) {
5162
5029
  throw new UsageError(`Initiative already exists: ${args.slug}`);
5163
5030
  }
5164
- await fs32.mkdir(path45.join(dir, "tasks"), { recursive: true });
5165
- await fs32.mkdir(path45.join(dir, "sessions"), { recursive: true });
5166
- await fs32.mkdir(path45.join(dir, "sources"), { recursive: true });
5031
+ await fs32.mkdir(path44.join(dir, "tasks"), { recursive: true });
5032
+ await fs32.mkdir(path44.join(dir, "sessions"), { recursive: true });
5033
+ await fs32.mkdir(path44.join(dir, "sources"), { recursive: true });
5167
5034
  const title = args.title ?? deriveTitle(args.slug);
5168
5035
  const briefBody = buildBriefBody(title, args.ref);
5169
5036
  await writeFrontmatter(
5170
- path45.join(dir, "brief.md"),
5037
+ path44.join(dir, "brief.md"),
5171
5038
  {
5172
5039
  schema_version: 1,
5173
5040
  title,
@@ -5183,8 +5050,8 @@ var track_default = defineCommand({
5183
5050
  const artifacts = ArtifactsSchema.parse({
5184
5051
  worktrees: args.worktree ? [{ path: args.worktree, repo: args.worktree, name: "main", default: true }] : []
5185
5052
  });
5186
- await atomicWrite(path45.join(dir, "artifacts.yml"), yamlStringify(artifacts));
5187
- await atomicWrite(path45.join(dir, "sources", ".gitkeep"), "");
5053
+ await atomicWrite(path44.join(dir, "artifacts.yml"), yamlStringify(artifacts));
5054
+ await atomicWrite(path44.join(dir, "sources", ".gitkeep"), "");
5188
5055
  await appendTriagedLog("track", args.ref, `slug:${args.slug}`);
5189
5056
  return { slug: args.slug, dir, ref: args.ref };
5190
5057
  }
@@ -5224,6 +5091,8 @@ var ArgsSchema37 = z41.object({
5224
5091
  // Frame the prompt as ad-hoc work on the workstream rather than a
5225
5092
  // continuation of its handoff / top task.
5226
5093
  adhoc: z41.boolean().optional(),
5094
+ // Rank the notes against this instead of the top task and brief titles.
5095
+ about: z41.string().min(1).optional(),
5227
5096
  // Skip the check for another session already live on this initiative.
5228
5097
  no_sibling_check: z41.boolean().optional()
5229
5098
  });
@@ -5247,12 +5116,16 @@ var promptCommand = defineCommand({
5247
5116
  long: "--adhoc",
5248
5117
  description: "Frame the prompt as ad-hoc work on the workstream, awaiting the user\u2019s task, not a continuation of the handoff / top task."
5249
5118
  },
5119
+ about: {
5120
+ long: "--about",
5121
+ description: "What this session is about, ranking the notes against it instead of the top task and brief titles."
5122
+ },
5250
5123
  no_sibling_check: {
5251
5124
  long: "--no-sibling-check",
5252
5125
  description: "Skip the check for another session already live on this initiative."
5253
5126
  }
5254
5127
  },
5255
- usage: "active-work prompt [slug] [--offline] [--cwd <dir>] [--adhoc] [--no-sibling-check]"
5128
+ usage: "active-work prompt [slug] [--offline] [--cwd <dir>] [--adhoc] [--about <text>] [--no-sibling-check]"
5256
5129
  },
5257
5130
  async run(args, ctx) {
5258
5131
  const activeRoot = ctx.activeRoot ?? getActiveRoot();
@@ -5274,6 +5147,7 @@ var promptCommand = defineCommand({
5274
5147
  slug,
5275
5148
  includeLiveStatus: !args.offline,
5276
5149
  adhoc: args.adhoc,
5150
+ ...args.about !== void 0 ? { about: args.about } : {},
5277
5151
  detectSiblings: !args.no_sibling_check && !args.offline,
5278
5152
  ...process.env.AW_LEASE_ID ? { ownLeaseId: process.env.AW_LEASE_ID } : {}
5279
5153
  });
@@ -5284,7 +5158,7 @@ var prompt_default = promptCommand;
5284
5158
 
5285
5159
  // src/commands/edit.ts
5286
5160
  import { promises as fs33 } from "fs";
5287
- import path46 from "path";
5161
+ import path45 from "path";
5288
5162
  import { spawn as spawn2 } from "child_process";
5289
5163
  import { z as z42 } from "zod";
5290
5164
  var ArgsSchema38 = z42.object({
@@ -5335,7 +5209,7 @@ var defaultDeps = {
5335
5209
  spawner: defaultSpawner
5336
5210
  };
5337
5211
  function targetFile(slug) {
5338
- return path46.join(getInitiativeDir(slug), "brief.md");
5212
+ return path45.join(getInitiativeDir(slug), "brief.md");
5339
5213
  }
5340
5214
  async function fileExists2(p) {
5341
5215
  try {
@@ -5414,7 +5288,7 @@ import {
5414
5288
  } from "@titan-design/registry";
5415
5289
 
5416
5290
  // src/version.ts
5417
- var BUILD_VERSION = "0.6.0";
5291
+ var BUILD_VERSION = "0.7.0";
5418
5292
 
5419
5293
  // src/server/mcp.ts
5420
5294
  var TOOL_NAME_PREFIX = "active__";
@@ -5437,7 +5311,7 @@ import { DaemonAlreadyRunningError, startDaemon } from "@titan-design/daemon";
5437
5311
 
5438
5312
  // src/server/dashboard-routes.ts
5439
5313
  import { promises as fs34 } from "fs";
5440
- import path47 from "path";
5314
+ import path46 from "path";
5441
5315
  import { fileURLToPath } from "url";
5442
5316
  var PLACEHOLDER_HTML = `<!doctype html>
5443
5317
  <html lang="en">
@@ -5469,17 +5343,17 @@ var CONTENT_TYPES = {
5469
5343
  ".woff2": "font/woff2"
5470
5344
  };
5471
5345
  function contentTypeFor(filename) {
5472
- const ext = path47.extname(filename).toLowerCase();
5346
+ const ext = path46.extname(filename).toLowerCase();
5473
5347
  return CONTENT_TYPES[ext] ?? "application/octet-stream";
5474
5348
  }
5475
5349
  function dashboardDirCandidates() {
5476
- const here = path47.dirname(fileURLToPath(import.meta.url));
5350
+ const here = path46.dirname(fileURLToPath(import.meta.url));
5477
5351
  return [
5478
- path47.resolve(here, "dashboard"),
5352
+ path46.resolve(here, "dashboard"),
5479
5353
  // bundled: dist/cli.js -> dist/dashboard
5480
- path47.resolve(here, "..", "dashboard"),
5354
+ path46.resolve(here, "..", "dashboard"),
5481
5355
  // legacy: dist/server -> dist/dashboard
5482
- path47.resolve(here, "..", "..", "dist", "dashboard")
5356
+ path46.resolve(here, "..", "..", "dist", "dashboard")
5483
5357
  // dev: src/server -> dist/dashboard
5484
5358
  ];
5485
5359
  }
@@ -5505,13 +5379,13 @@ async function handleDashboard(c) {
5505
5379
  const url = new URL(c.req.url);
5506
5380
  const subpath = url.pathname.replace(/^\/ui\/?/, "");
5507
5381
  const relative = subpath === "" ? "index.html" : subpath;
5508
- const target = path47.resolve(root, relative);
5509
- if (!target.startsWith(root + path47.sep) && target !== root) {
5382
+ const target = path46.resolve(root, relative);
5383
+ if (!target.startsWith(root + path46.sep) && target !== root) {
5510
5384
  return c.text("forbidden", 403);
5511
5385
  }
5512
5386
  const stat = await safeStat(target);
5513
5387
  if (!stat.exists || !stat.isFile) {
5514
- const indexPath = path47.join(root, "index.html");
5388
+ const indexPath = path46.join(root, "index.html");
5515
5389
  const indexStat = await safeStat(indexPath);
5516
5390
  if (!indexStat.exists) {
5517
5391
  return c.html(PLACEHOLDER_HTML, 200);
@@ -5529,13 +5403,13 @@ async function handleDashboard(c) {
5529
5403
 
5530
5404
  // src/server/logger.ts
5531
5405
  import { mkdirSync, createWriteStream } from "fs";
5532
- import path48 from "path";
5406
+ import path47 from "path";
5533
5407
  import pino, { multistream } from "pino";
5534
5408
  var cachedLogger;
5535
5409
  function buildLogger() {
5536
5410
  const stateRoot = getStateRoot();
5537
5411
  mkdirSync(stateRoot, { recursive: true });
5538
- const logPath = path48.join(stateRoot, "daemon.log");
5412
+ const logPath = path47.join(stateRoot, "daemon.log");
5539
5413
  const fileStream = createWriteStream(logPath, { flags: "a" });
5540
5414
  const stderrIsTTY = process.stderr.isTTY === true;
5541
5415
  const stderrStream = stderrIsTTY ? pino.transport({
@@ -5556,7 +5430,7 @@ import { transcriptsRoot as transcriptsRoot2 } from "@titan-design/session-read"
5556
5430
  import { watchTree } from "@titan-design/daemon";
5557
5431
 
5558
5432
  // src/session-index/refresh.ts
5559
- import path57 from "path";
5433
+ import path56 from "path";
5560
5434
  import { promises as fs44 } from "fs";
5561
5435
  import lockfile from "proper-lockfile";
5562
5436
  import { discoverTranscripts, transcriptsRoot } from "@titan-design/session-read";
@@ -5564,7 +5438,7 @@ import { refreshCorpus, resetIndex } from "@titan-design/session-graph";
5564
5438
 
5565
5439
  // src/session-index/tasks.ts
5566
5440
  import { promises as fs35 } from "fs";
5567
- import path49 from "path";
5441
+ import path48 from "path";
5568
5442
  var AMBIGUOUS = null;
5569
5443
  async function initiativeSlugs(root) {
5570
5444
  try {
@@ -5576,7 +5450,7 @@ async function initiativeSlugs(root) {
5576
5450
  }
5577
5451
  }
5578
5452
  async function readInitiative(root, slug) {
5579
- const dir = path49.join(root, slug, "tasks");
5453
+ const dir = path48.join(root, slug, "tasks");
5580
5454
  let files;
5581
5455
  try {
5582
5456
  files = await fs35.readdir(dir);
@@ -5588,7 +5462,7 @@ async function readInitiative(root, slug) {
5588
5462
  for (const file of files) {
5589
5463
  if (!file.endsWith(".yml")) continue;
5590
5464
  try {
5591
- const task = await readYaml(path49.join(dir, file), TaskSchema);
5465
+ const task = await readYaml(path48.join(dir, file), TaskSchema);
5592
5466
  found.push([task.id, { initiative: slug, title: task.title, status: task.status }]);
5593
5467
  } catch {
5594
5468
  continue;
@@ -5642,8 +5516,8 @@ function extractMentions(body, initiative, index) {
5642
5516
  for (const id of matches(body, NOTE_REF)) {
5643
5517
  if (index.noteRefs.has(noteRef(id))) found.add(noteRef(id));
5644
5518
  }
5645
- for (const path68 of matches(body, SOURCE_PATH)) {
5646
- const scoped = `${initiative}/${path68}`;
5519
+ for (const path67 of matches(body, SOURCE_PATH)) {
5520
+ const scoped = `${initiative}/${path67}`;
5647
5521
  if (index.sourcePaths.has(scoped)) found.add(sourceRef(scoped));
5648
5522
  }
5649
5523
  return [...found].sort();
@@ -5980,26 +5854,26 @@ function compact(spans) {
5980
5854
 
5981
5855
  // src/workspace-index/scan.ts
5982
5856
  import { promises as fs42 } from "fs";
5983
- import path56 from "path";
5857
+ import path55 from "path";
5984
5858
 
5985
5859
  // src/lint/index.ts
5986
5860
  import { promises as fs41 } from "fs";
5987
- import path55 from "path";
5861
+ import path54 from "path";
5988
5862
 
5989
5863
  // src/lint/brief.ts
5990
5864
  import { promises as fs37 } from "fs";
5991
- import path50 from "path";
5865
+ import path49 from "path";
5992
5866
 
5993
5867
  // src/lint/hashes.ts
5994
5868
  import { promises as fs38 } from "fs";
5995
- import path51 from "path";
5869
+ import path50 from "path";
5996
5870
  async function lintHashes(slug, initiativeDir) {
5997
5871
  const manifest = await readArtifactHashes(initiativeDir);
5998
5872
  const findings = [];
5999
5873
  for (const [relPath, storedHash] of Object.entries(manifest)) {
6000
5874
  let content;
6001
5875
  try {
6002
- content = await fs38.readFile(path51.join(initiativeDir, relPath), "utf8");
5876
+ content = await fs38.readFile(path50.join(initiativeDir, relPath), "utf8");
6003
5877
  } catch (err) {
6004
5878
  const code = err.code;
6005
5879
  if (code === "ENOENT") continue;
@@ -6017,16 +5891,16 @@ async function lintHashes(slug, initiativeDir) {
6017
5891
  }
6018
5892
 
6019
5893
  // src/lint/open-loops.ts
6020
- import path52 from "path";
5894
+ import path51 from "path";
6021
5895
 
6022
5896
  // src/lint/task.ts
6023
5897
  import { promises as fs39 } from "fs";
6024
- import path53 from "path";
5898
+ import path52 from "path";
6025
5899
  import YAML2 from "yaml";
6026
5900
 
6027
5901
  // src/lint/zero-loops.ts
6028
5902
  import { promises as fs40 } from "fs";
6029
- import path54 from "path";
5903
+ import path53 from "path";
6030
5904
  import YAML3 from "yaml";
6031
5905
 
6032
5906
  // src/lint/index.ts
@@ -6055,21 +5929,21 @@ function isVisible(entry, extensions) {
6055
5929
  }
6056
5930
  async function filesIn(dir, extensions) {
6057
5931
  const entries = await readDirents(dir);
6058
- return entries.filter((entry) => isVisible(entry, extensions)).map((entry) => path56.join(dir, entry.name)).sort();
5932
+ return entries.filter((entry) => isVisible(entry, extensions)).map((entry) => path55.join(dir, entry.name)).sort();
6059
5933
  }
6060
5934
  async function taskFiles(tasksDir) {
6061
5935
  const own = await filesIn(tasksDir, [".yml", ".yaml"]);
6062
- const archive = await filesIn(path56.join(tasksDir, "archive"), [".yml", ".yaml"]);
5936
+ const archive = await filesIn(path55.join(tasksDir, "archive"), [".yml", ".yaml"]);
6063
5937
  return [...own, ...archive];
6064
5938
  }
6065
5939
  async function collectSlug(activeRoot, slug) {
6066
- const dir = path56.join(activeRoot, slug);
6067
- const brief = path56.join(dir, "brief.md");
5940
+ const dir = path55.join(activeRoot, slug);
5941
+ const brief = path55.join(dir, "brief.md");
6068
5942
  const [notes, tasks, sessions2, sources] = await Promise.all([
6069
- filesIn(path56.join(dir, "sources", "notes"), [".md"]),
6070
- taskFiles(path56.join(dir, "tasks")),
6071
- filesIn(path56.join(dir, "sessions"), [".md"]),
6072
- filesIn(path56.join(dir, "sources"), [".md"])
5943
+ filesIn(path55.join(dir, "sources", "notes"), [".md"]),
5944
+ taskFiles(path55.join(dir, "tasks")),
5945
+ filesIn(path55.join(dir, "sessions"), [".md"]),
5946
+ filesIn(path55.join(dir, "sources"), [".md"])
6073
5947
  ]);
6074
5948
  return [
6075
5949
  ...notes.map((p) => ["note", p]),
@@ -6479,7 +6353,7 @@ function refreshLockPath() {
6479
6353
  }
6480
6354
  async function withRefreshLock(fn) {
6481
6355
  const target = refreshLockPath();
6482
- await fs44.mkdir(path57.dirname(target), { recursive: true });
6356
+ await fs44.mkdir(path56.dirname(target), { recursive: true });
6483
6357
  await fs44.writeFile(target, "", { flag: "a" });
6484
6358
  const release = await lockfile.lock(target, {
6485
6359
  realpath: false,
@@ -7011,7 +6885,7 @@ var mcp_status_default = defineCommand({
7011
6885
 
7012
6886
  // src/commands/mcp-logs.ts
7013
6887
  import { promises as fs45 } from "fs";
7014
- import path58 from "path";
6888
+ import path57 from "path";
7015
6889
  import { z as z48 } from "zod";
7016
6890
  var ArgsSchema43 = z48.object({
7017
6891
  lines: z48.number().int().positive().optional()
@@ -7035,7 +6909,7 @@ var mcp_logs_default = defineCommand({
7035
6909
  },
7036
6910
  async run(args) {
7037
6911
  const n = args.lines ?? DEFAULT_LINES;
7038
- const logPath = path58.join(getStateRoot(), "daemon.log");
6912
+ const logPath = path57.join(getStateRoot(), "daemon.log");
7039
6913
  let content;
7040
6914
  try {
7041
6915
  content = await fs45.readFile(logPath, "utf8");
@@ -7065,7 +6939,7 @@ import { Clusterer } from "@titan-design/cluster";
7065
6939
 
7066
6940
  // src/drain/store.ts
7067
6941
  import { promises as fs46 } from "fs";
7068
- import path59 from "path";
6942
+ import path58 from "path";
7069
6943
 
7070
6944
  // src/schemas/template.ts
7071
6945
  import { z as z49 } from "zod";
@@ -7095,10 +6969,10 @@ var TemplatesFileSchema = z49.object({
7095
6969
 
7096
6970
  // src/drain/store.ts
7097
6971
  function templatesPath(root) {
7098
- return path59.join(root, "templates.yml");
6972
+ return path58.join(root, "templates.yml");
7099
6973
  }
7100
6974
  function occurrencesPath(root) {
7101
- return path59.join(root, "occurrences.jsonl");
6975
+ return path58.join(root, "occurrences.jsonl");
7102
6976
  }
7103
6977
  async function loadTemplates(root = getMinerRoot()) {
7104
6978
  try {
@@ -7136,7 +7010,7 @@ async function appendOccurrences(occurrences, root = getMinerRoot()) {
7136
7010
 
7137
7011
  // src/drain/tree-store.ts
7138
7012
  import { promises as fs47 } from "fs";
7139
- import path60 from "path";
7013
+ import path59 from "path";
7140
7014
  import { z as z50 } from "zod";
7141
7015
  var PartitionSchema = z50.object({
7142
7016
  partition: z50.string().min(1),
@@ -7160,7 +7034,7 @@ var LegacySnapshotFileSchema = z50.object({
7160
7034
  trees: z50.array(PartitionSchema.omit({ partition: true }).extend({ toolType: z50.string().min(1) }))
7161
7035
  });
7162
7036
  function snapshotPath(root) {
7163
- return path60.join(root, "drain-trees.json");
7037
+ return path59.join(root, "drain-trees.json");
7164
7038
  }
7165
7039
  function empty() {
7166
7040
  return { version: 1, partitions: [] };
@@ -7339,7 +7213,7 @@ function extractBlobs(line, toolNames) {
7339
7213
 
7340
7214
  // src/drain/reader-state.ts
7341
7215
  import { promises as fs48 } from "fs";
7342
- import path61 from "path";
7216
+ import path60 from "path";
7343
7217
  import { z as z51 } from "zod";
7344
7218
  var TranscriptStateSchema = z51.object({
7345
7219
  /** `~`-relative path, matching `session-index/discover.ts`'s display form. */
@@ -7360,7 +7234,7 @@ var ReaderStateSchema = z51.object({
7360
7234
  });
7361
7235
  var MAX_PENDING_TOOL_NAMES = 256;
7362
7236
  function readerStatePath(root = getMinerRoot()) {
7363
- return path61.join(root, "reader-state.json");
7237
+ return path60.join(root, "reader-state.json");
7364
7238
  }
7365
7239
  async function loadReaderState(root = getMinerRoot()) {
7366
7240
  try {
@@ -8011,7 +7885,7 @@ async function readStdinJson(stream = process.stdin) {
8011
7885
 
8012
7886
  // src/utils/agent-chat-hook-state.ts
8013
7887
  import { promises as fs49 } from "fs";
8014
- import path62 from "path";
7888
+ import path61 from "path";
8015
7889
  import { z as z56 } from "zod";
8016
7890
  var SpawnContextSchema = z56.object({
8017
7891
  slug: z56.string().min(1),
@@ -8031,10 +7905,10 @@ var SpawnContextSchema = z56.object({
8031
7905
  briefing: z56.string().nullable().default(null)
8032
7906
  });
8033
7907
  function stateDir() {
8034
- return path62.join(getStateRoot(), "agent-chat-hooks");
7908
+ return path61.join(getStateRoot(), "agent-chat-hooks");
8035
7909
  }
8036
7910
  function stateFile(agentId) {
8037
- return path62.join(stateDir(), `${agentId}.json`);
7911
+ return path61.join(stateDir(), `${agentId}.json`);
8038
7912
  }
8039
7913
  async function stashSpawnContext(agentId, context) {
8040
7914
  await fs49.mkdir(stateDir(), { recursive: true });
@@ -8204,7 +8078,7 @@ import { join } from "path";
8204
8078
 
8205
8079
  // src/migrations/v1-to-v2-artifacts.ts
8206
8080
  import { promises as fs50 } from "fs";
8207
- import path63 from "path";
8081
+ import path62 from "path";
8208
8082
  import YAML4 from "yaml";
8209
8083
  function asArray(value) {
8210
8084
  return Array.isArray(value) ? value : [];
@@ -8264,7 +8138,7 @@ async function walkArtifactsFiles(activeRoot) {
8264
8138
  for (const entry of entries) {
8265
8139
  if (!entry.isDirectory()) continue;
8266
8140
  if (entry.name.startsWith(".")) continue;
8267
- const candidate = path63.join(activeRoot, entry.name, "artifacts.yml");
8141
+ const candidate = path62.join(activeRoot, entry.name, "artifacts.yml");
8268
8142
  try {
8269
8143
  await fs50.access(candidate);
8270
8144
  out.push(candidate);
@@ -8273,14 +8147,14 @@ async function walkArtifactsFiles(activeRoot) {
8273
8147
  }
8274
8148
  } catch {
8275
8149
  }
8276
- const archiveRoot = path63.resolve(activeRoot, "..");
8150
+ const archiveRoot = path62.resolve(activeRoot, "..");
8277
8151
  try {
8278
8152
  const domains = await fs50.readdir(archiveRoot, { withFileTypes: true });
8279
8153
  for (const domain of domains) {
8280
8154
  if (!domain.isDirectory()) continue;
8281
8155
  if (domain.name.startsWith(".")) continue;
8282
- if (path63.join(archiveRoot, domain.name) === path63.resolve(activeRoot)) continue;
8283
- const archiveDir = path63.join(archiveRoot, domain.name, "archive");
8156
+ if (path62.join(archiveRoot, domain.name) === path62.resolve(activeRoot)) continue;
8157
+ const archiveDir = path62.join(archiveRoot, domain.name, "archive");
8284
8158
  let archived;
8285
8159
  try {
8286
8160
  archived = await fs50.readdir(archiveDir, { withFileTypes: true });
@@ -8289,7 +8163,7 @@ async function walkArtifactsFiles(activeRoot) {
8289
8163
  }
8290
8164
  for (const entry of archived) {
8291
8165
  if (!entry.isDirectory()) continue;
8292
- const candidate = path63.join(archiveDir, entry.name, "artifacts.yml");
8166
+ const candidate = path62.join(archiveDir, entry.name, "artifacts.yml");
8293
8167
  try {
8294
8168
  await fs50.access(candidate);
8295
8169
  out.push(candidate);
@@ -8303,7 +8177,7 @@ async function walkArtifactsFiles(activeRoot) {
8303
8177
  }
8304
8178
  async function appendMigrationLog(activeRoot, lines) {
8305
8179
  if (lines.length === 0) return;
8306
- const logPath = path63.join(activeRoot, ".migrations.log");
8180
+ const logPath = path62.join(activeRoot, ".migrations.log");
8307
8181
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
8308
8182
  const body = lines.map((l) => `${stamp} v1->v2 ${l}
8309
8183
  `).join("");
@@ -8335,7 +8209,7 @@ var v1ToV2Artifacts = {
8335
8209
 
8336
8210
  // src/migrations/v2-to-v3-open-loops.ts
8337
8211
  import { promises as fs53 } from "fs";
8338
- import path65 from "path";
8212
+ import path64 from "path";
8339
8213
 
8340
8214
  // src/migrations/v3-proposal.ts
8341
8215
  import { promises as fs51 } from "fs";
@@ -9235,17 +9109,17 @@ async function loadProposal() {
9235
9109
 
9236
9110
  // src/migrations/v3-repairs.ts
9237
9111
  import { promises as fs52 } from "fs";
9238
- import path64 from "path";
9112
+ import path63 from "path";
9239
9113
  var KNOWN_REPAIRS = [
9240
9114
  {
9241
- file: path64.join("audiobook", "sessions", "2026-07-23-0549-2026-07-26-book1-m4b-packaging.md"),
9115
+ file: path63.join("audiobook", "sessions", "2026-07-23-0549-2026-07-26-book1-m4b-packaging.md"),
9242
9116
  kind: "retrack",
9243
9117
  why: "track is a branch name ('feat/tts-quality'), not one of canonical|sidecar|adhoc"
9244
9118
  },
9245
9119
  {
9246
- file: path64.join("voltras-workspace", "sessions", "ARCHIVED-handoff-through-2026-07-15.md"),
9120
+ file: path63.join("voltras-workspace", "sessions", "ARCHIVED-handoff-through-2026-07-15.md"),
9247
9121
  kind: "relocate",
9248
- target: path64.join("voltras-workspace", "sources", "ARCHIVED-handoff-through-2026-07-15.md"),
9122
+ target: path63.join("voltras-workspace", "sources", "ARCHIVED-handoff-through-2026-07-15.md"),
9249
9123
  why: "not a session file \u2014 a hand-archived handoff parked in sessions/"
9250
9124
  }
9251
9125
  ];
@@ -9304,7 +9178,7 @@ async function exists3(p) {
9304
9178
  async function planRepairs(activeRoot) {
9305
9179
  const plans = [];
9306
9180
  for (const repair of KNOWN_REPAIRS) {
9307
- const fullPath = path64.join(activeRoot, repair.file);
9181
+ const fullPath = path63.join(activeRoot, repair.file);
9308
9182
  if (!await exists3(fullPath)) {
9309
9183
  plans.push({ action: "skip", file: repair.file, detail: "already absent" });
9310
9184
  continue;
@@ -9314,7 +9188,7 @@ async function planRepairs(activeRoot) {
9314
9188
  continue;
9315
9189
  }
9316
9190
  const target = repair.target;
9317
- if (await exists3(path64.join(activeRoot, target))) {
9191
+ if (await exists3(path63.join(activeRoot, target))) {
9318
9192
  plans.push({
9319
9193
  action: "skip",
9320
9194
  file: repair.file,
@@ -9328,7 +9202,7 @@ async function planRepairs(activeRoot) {
9328
9202
  return plans;
9329
9203
  }
9330
9204
  async function applyRepair(activeRoot, plan) {
9331
- const fullPath = path64.join(activeRoot, plan.file);
9205
+ const fullPath = path63.join(activeRoot, plan.file);
9332
9206
  if (plan.action === "retrack" && plan.repaired !== void 0) {
9333
9207
  await writeFrontmatter(
9334
9208
  fullPath,
@@ -9339,15 +9213,15 @@ async function applyRepair(activeRoot, plan) {
9339
9213
  return;
9340
9214
  }
9341
9215
  if (plan.action === "relocate") {
9342
- const target = path64.join(activeRoot, plan.target);
9343
- await fs52.mkdir(path64.dirname(target), { recursive: true });
9216
+ const target = path63.join(activeRoot, plan.target);
9217
+ await fs52.mkdir(path63.dirname(target), { recursive: true });
9344
9218
  await fs52.rename(fullPath, target);
9345
9219
  }
9346
9220
  }
9347
9221
 
9348
9222
  // src/migrations/v2-to-v3-open-loops.ts
9349
9223
  var HANDOFF_FILE = "handoff.md";
9350
- var HANDOFF_ARCHIVE = path65.join("sources", "handoff-archive.md");
9224
+ var HANDOFF_ARCHIVE = path64.join("sources", "handoff-archive.md");
9351
9225
  async function pathExists(p) {
9352
9226
  try {
9353
9227
  await fs53.access(p);
@@ -9366,7 +9240,7 @@ async function listInitiativeSlugs3(activeRoot) {
9366
9240
  const slugs = [];
9367
9241
  for (const entry of entries) {
9368
9242
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
9369
- if (await pathExists(path65.join(activeRoot, entry.name, "brief.md"))) {
9243
+ if (await pathExists(path64.join(activeRoot, entry.name, "brief.md"))) {
9370
9244
  slugs.push(entry.name);
9371
9245
  }
9372
9246
  }
@@ -9374,9 +9248,9 @@ async function listInitiativeSlugs3(activeRoot) {
9374
9248
  }
9375
9249
  async function maxOnDiskTaskNumber2(initiativeDir, prefix) {
9376
9250
  const re = new RegExp(`^${prefix}-(\\d+)\\.yml$`);
9377
- const tasksDir = path65.join(initiativeDir, "tasks");
9251
+ const tasksDir = path64.join(initiativeDir, "tasks");
9378
9252
  let max = 0;
9379
- for (const dir of [tasksDir, path65.join(tasksDir, "archive")]) {
9253
+ for (const dir of [tasksDir, path64.join(tasksDir, "archive")]) {
9380
9254
  let names;
9381
9255
  try {
9382
9256
  names = await fs53.readdir(dir);
@@ -9398,7 +9272,7 @@ async function nextTaskSeq(initiativeDir, frontmatter2) {
9398
9272
  return max > 0 ? max : null;
9399
9273
  }
9400
9274
  async function planBrief(initiativeDir, slug) {
9401
- const raw = await readRawFrontmatter(path65.join(initiativeDir, "brief.md"));
9275
+ const raw = await readRawFrontmatter(path64.join(initiativeDir, "brief.md"));
9402
9276
  const repaired = repairBriefFrontmatter(slug, raw.frontmatter);
9403
9277
  const taskSeq = await nextTaskSeq(initiativeDir, repaired.frontmatter);
9404
9278
  if (taskSeq === null && repaired.applied.length === 0) return { write: null };
@@ -9415,8 +9289,8 @@ async function planBrief(initiativeDir, slug) {
9415
9289
  };
9416
9290
  }
9417
9291
  async function planHandoff(initiativeDir) {
9418
- if (!await pathExists(path65.join(initiativeDir, HANDOFF_FILE))) return "absent";
9419
- if (await pathExists(path65.join(initiativeDir, HANDOFF_ARCHIVE))) return "archive-exists";
9292
+ if (!await pathExists(path64.join(initiativeDir, HANDOFF_FILE))) return "absent";
9293
+ if (await pathExists(path64.join(initiativeDir, HANDOFF_ARCHIVE))) return "archive-exists";
9420
9294
  return "archive-and-remove";
9421
9295
  }
9422
9296
  function buildOpenSession(entry) {
@@ -9506,7 +9380,7 @@ function draftSessions(entry, abandonedAt) {
9506
9380
  return [open, buildAbandonSession(entry, open.stem, abandonedAt)];
9507
9381
  }
9508
9382
  async function planInitiative(activeRoot, slug, entry, abandonedAt) {
9509
- const initiativeDir = path65.join(activeRoot, slug);
9383
+ const initiativeDir = path64.join(activeRoot, slug);
9510
9384
  const brief = await planBrief(initiativeDir, slug);
9511
9385
  const base = {
9512
9386
  slug,
@@ -9545,9 +9419,9 @@ async function planV2ToV3(activeRoot) {
9545
9419
  return { proposalOrigin: origin, initiatives, repairs: await planRepairs(activeRoot) };
9546
9420
  }
9547
9421
  async function archiveHandoff(initiativeDir) {
9548
- const source = path65.join(initiativeDir, HANDOFF_FILE);
9549
- const target = path65.join(initiativeDir, HANDOFF_ARCHIVE);
9550
- await fs53.mkdir(path65.dirname(target), { recursive: true });
9422
+ const source = path64.join(initiativeDir, HANDOFF_FILE);
9423
+ const target = path64.join(initiativeDir, HANDOFF_ARCHIVE);
9424
+ await fs53.mkdir(path64.dirname(target), { recursive: true });
9551
9425
  await fs53.copyFile(source, target);
9552
9426
  await fs53.rm(source);
9553
9427
  }
@@ -9566,15 +9440,15 @@ async function writePlannedSession(activeRoot, slug, session) {
9566
9440
  });
9567
9441
  }
9568
9442
  async function applyInitiative(activeRoot, plan) {
9569
- const initiativeDir = path65.join(activeRoot, plan.slug);
9570
- await withFileLock(path65.join(initiativeDir, ".lock"), async () => {
9443
+ const initiativeDir = path64.join(activeRoot, plan.slug);
9444
+ await withFileLock(path64.join(initiativeDir, ".lock"), async () => {
9571
9445
  for (const session of plan.sessions) {
9572
9446
  if (session.exists) continue;
9573
9447
  await writePlannedSession(activeRoot, plan.slug, session);
9574
9448
  }
9575
9449
  if (plan.brief !== null) {
9576
9450
  await writeFrontmatter(
9577
- path65.join(initiativeDir, "brief.md"),
9451
+ path64.join(initiativeDir, "brief.md"),
9578
9452
  plan.brief.frontmatter,
9579
9453
  plan.brief.body,
9580
9454
  BriefFrontmatterSchema
@@ -9605,12 +9479,12 @@ var v2ToV3OpenLoops = {
9605
9479
 
9606
9480
  // src/migrations/v3-to-v4-worktrees.ts
9607
9481
  import { promises as fs54 } from "fs";
9608
- import path66 from "path";
9482
+ import path65 from "path";
9609
9483
  import matter5 from "gray-matter";
9610
9484
  import YAML5 from "yaml";
9611
9485
  function normalize(value) {
9612
- const expanded = value.startsWith("~") ? path66.join(process.env.HOME ?? "", value.slice(1)) : value;
9613
- return path66.resolve(expanded);
9486
+ const expanded = value.startsWith("~") ? path65.join(process.env.HOME ?? "", value.slice(1)) : value;
9487
+ return path65.resolve(expanded);
9614
9488
  }
9615
9489
  function toEntries(raw) {
9616
9490
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
@@ -9657,7 +9531,7 @@ async function readArtifacts2(file) {
9657
9531
  }
9658
9532
  }
9659
9533
  async function migrateOne2(initiativeDir) {
9660
- const briefPath = path66.join(initiativeDir, "brief.md");
9534
+ const briefPath = path65.join(initiativeDir, "brief.md");
9661
9535
  let raw;
9662
9536
  try {
9663
9537
  raw = await fs54.readFile(briefPath, "utf8");
@@ -9670,7 +9544,7 @@ async function migrateOne2(initiativeDir) {
9670
9544
  const incoming = toEntries(data.worktrees);
9671
9545
  delete data.worktrees;
9672
9546
  if (incoming.length > 0) {
9673
- const artifactsPath2 = path66.join(initiativeDir, "artifacts.yml");
9547
+ const artifactsPath2 = path65.join(initiativeDir, "artifacts.yml");
9674
9548
  const current = await readArtifacts2(artifactsPath2);
9675
9549
  await writeYaml(
9676
9550
  artifactsPath2,
@@ -9695,9 +9569,9 @@ async function initiativeDirs(activeRoot) {
9695
9569
  }
9696
9570
  for (const entry of entries) {
9697
9571
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
9698
- const dir = path66.join(activeRoot, entry.name);
9572
+ const dir = path65.join(activeRoot, entry.name);
9699
9573
  try {
9700
- await fs54.access(path66.join(dir, "brief.md"));
9574
+ await fs54.access(path65.join(dir, "brief.md"));
9701
9575
  out.push(dir);
9702
9576
  } catch {
9703
9577
  }
@@ -9712,12 +9586,12 @@ var v3ToV4Worktrees = {
9712
9586
  const moved = [];
9713
9587
  for (const dir of await initiativeDirs(activeRoot)) {
9714
9588
  const count = await migrateOne2(dir);
9715
- if (count > 0) moved.push(`${path66.basename(dir)} ${count} worktree(s)`);
9589
+ if (count > 0) moved.push(`${path65.basename(dir)} ${count} worktree(s)`);
9716
9590
  }
9717
9591
  if (moved.length === 0) return;
9718
9592
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
9719
9593
  await fs54.appendFile(
9720
- path66.join(activeRoot, ".migrations.log"),
9594
+ path65.join(activeRoot, ".migrations.log"),
9721
9595
  moved.map((line) => `${stamp} v3->v4 ${line}
9722
9596
  `).join(""),
9723
9597
  "utf8"
@@ -9727,12 +9601,12 @@ var v3ToV4Worktrees = {
9727
9601
 
9728
9602
  // src/migrations/index.ts
9729
9603
  var BASE_VERSION = 1;
9730
- var MIGRATIONS2 = [v1ToV2Artifacts, v2ToV3OpenLoops, v3ToV4Worktrees];
9731
- var CURRENT_VERSION = targetVersion(MIGRATIONS2);
9604
+ var MIGRATIONS = [v1ToV2Artifacts, v2ToV3OpenLoops, v3ToV4Worktrees];
9605
+ var CURRENT_VERSION = targetVersion(MIGRATIONS);
9732
9606
  function targetVersion(migrations) {
9733
9607
  return migrations.reduce((highest, m) => Math.max(highest, m.to), BASE_VERSION);
9734
9608
  }
9735
- async function runMigrations2(activeRoot, fromVersion, migrations = MIGRATIONS2) {
9609
+ async function runMigrations(activeRoot, fromVersion, migrations = MIGRATIONS) {
9736
9610
  if (fromVersion === CURRENT_VERSION) {
9737
9611
  return { ran: [] };
9738
9612
  }
@@ -9770,10 +9644,10 @@ var SCHEMA_VERSION_FILENAME = ".schema-version";
9770
9644
  var schemaVersionPath = (activeRoot) => join(activeRoot, SCHEMA_VERSION_FILENAME);
9771
9645
  var isNodeErrnoException = (err) => typeof err === "object" && err !== null && "code" in err;
9772
9646
  async function readSchemaVersion(activeRoot) {
9773
- const path68 = schemaVersionPath(activeRoot);
9647
+ const path67 = schemaVersionPath(activeRoot);
9774
9648
  let raw;
9775
9649
  try {
9776
- raw = await readFile(path68, "utf8");
9650
+ raw = await readFile(path67, "utf8");
9777
9651
  } catch (err) {
9778
9652
  if (isNodeErrnoException(err) && err.code === "ENOENT") {
9779
9653
  return 0;
@@ -9783,13 +9657,13 @@ async function readSchemaVersion(activeRoot) {
9783
9657
  const trimmed = raw.trim();
9784
9658
  if (trimmed === "" || !/^\d+$/.test(trimmed)) {
9785
9659
  throw new Error(
9786
- `Invalid schema version in ${path68}: expected a positive integer, got ${JSON.stringify(raw)}`
9660
+ `Invalid schema version in ${path67}: expected a positive integer, got ${JSON.stringify(raw)}`
9787
9661
  );
9788
9662
  }
9789
9663
  const parsed = Number(trimmed);
9790
9664
  if (!Number.isInteger(parsed) || parsed <= 0) {
9791
9665
  throw new Error(
9792
- `Invalid schema version in ${path68}: expected a positive integer, got ${JSON.stringify(raw)}`
9666
+ `Invalid schema version in ${path67}: expected a positive integer, got ${JSON.stringify(raw)}`
9793
9667
  );
9794
9668
  }
9795
9669
  return parsed;
@@ -9802,10 +9676,10 @@ async function writeSchemaVersion(activeRoot, version) {
9802
9676
  `, "utf8");
9803
9677
  }
9804
9678
  async function readRawSchemaVersion(activeRoot) {
9805
- const path68 = schemaVersionPath(activeRoot);
9679
+ const path67 = schemaVersionPath(activeRoot);
9806
9680
  let raw;
9807
9681
  try {
9808
- raw = await readFile(path68, "utf8");
9682
+ raw = await readFile(path67, "utf8");
9809
9683
  } catch (err) {
9810
9684
  if (isNodeErrnoException(err) && err.code === "ENOENT") {
9811
9685
  return { present: false };
@@ -9815,13 +9689,13 @@ async function readRawSchemaVersion(activeRoot) {
9815
9689
  const trimmed = raw.trim();
9816
9690
  if (trimmed === "" || !/^\d+$/.test(trimmed)) {
9817
9691
  throw new Error(
9818
- `Invalid schema version in ${path68}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9692
+ `Invalid schema version in ${path67}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9819
9693
  );
9820
9694
  }
9821
9695
  const parsed = Number(trimmed);
9822
9696
  if (!Number.isInteger(parsed) || parsed < 0) {
9823
9697
  throw new Error(
9824
- `Invalid schema version in ${path68}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9698
+ `Invalid schema version in ${path67}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9825
9699
  );
9826
9700
  }
9827
9701
  return { present: true, version: parsed };
@@ -9841,7 +9715,7 @@ async function ensureSchemaVersion(activeRoot) {
9841
9715
  if (before === CURRENT_VERSION) {
9842
9716
  return { before, after: before, migrated: false, ran: [] };
9843
9717
  }
9844
- const { ran } = await runMigrations2(activeRoot, before);
9718
+ const { ran } = await runMigrations(activeRoot, before);
9845
9719
  await writeSchemaVersion(activeRoot, CURRENT_VERSION);
9846
9720
  return {
9847
9721
  before,
@@ -12040,14 +11914,14 @@ import { readCommanderOption } from "@titan-design/registry";
12040
11914
 
12041
11915
  // src/utils/usage-log.ts
12042
11916
  import { promises as fs56 } from "fs";
12043
- import path67 from "path";
11917
+ import path66 from "path";
12044
11918
  function usageLogPath() {
12045
- return path67.join(getStateRoot(), "usage.jsonl");
11919
+ return path66.join(getStateRoot(), "usage.jsonl");
12046
11920
  }
12047
11921
  async function appendUsage(rec) {
12048
11922
  try {
12049
11923
  const file = usageLogPath();
12050
- await fs56.mkdir(path67.dirname(file), { recursive: true });
11924
+ await fs56.mkdir(path66.dirname(file), { recursive: true });
12051
11925
  await fs56.appendFile(file, JSON.stringify(rec) + "\n", "utf8");
12052
11926
  } catch {
12053
11927
  }