@titan-design/active-work 0.5.0 → 0.6.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
@@ -1517,8 +1517,8 @@ var NO_UPSTREAM = { ahead: null, behind: null };
1517
1517
  function shortBranch(ref) {
1518
1518
  return ref.replace(/^refs\/heads\//, "");
1519
1519
  }
1520
- function emptyWorktree(path67) {
1521
- return { path: path67, head: null, branch: null, detached: false, bare: false };
1520
+ function emptyWorktree(path68) {
1521
+ return { path: path68, head: null, branch: null, detached: false, bare: false };
1522
1522
  }
1523
1523
  function parseWorktreePorcelain(stdout) {
1524
1524
  const out = [];
@@ -3849,29 +3849,387 @@ var context_graph_default = defineCommand({
3849
3849
  }
3850
3850
  });
3851
3851
 
3852
- // src/commands/list.ts
3852
+ // src/commands/search.ts
3853
3853
  import { z as z33 } from "zod";
3854
- var argsSchema2 = z33.object({}).strict();
3855
- var itemSchema = z33.object({
3856
- slug: z33.string(),
3857
- title: z33.string(),
3858
- state: z33.enum(["focused", "backburner", "paused", "done"]),
3859
- rank: z33.number().int().positive().optional(),
3860
- ship_target: z33.string().optional(),
3861
- paused_since: z33.string().optional(),
3862
- updated: z33.string()
3863
- });
3864
- var sectionSchema = z33.object({
3865
- heading: z33.string(),
3866
- items: z33.array(itemSchema)
3867
- });
3868
- var parseErrorSchema2 = z33.object({
3869
- slug: z33.string(),
3870
- error: z33.string()
3871
- });
3872
- var resultSchema2 = z33.object({
3873
- sections: z33.array(sectionSchema),
3874
- parse_errors: z33.array(parseErrorSchema2)
3854
+
3855
+ // src/search/index.ts
3856
+ import { createRetrievalEngine, ftsRetriever } from "@titan-design/retrieval";
3857
+
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
+ // src/search/classes.ts
3997
+ var TRANSCRIPT_FIELDS = ["prompt", "assistant_response", "tool_input", "tool_result"];
3998
+ var SEARCH_CLASSES = [
3999
+ { name: "notes", scope: { ownerPrefix: "note:" }, weight: 1.3, share: 0.5 },
4000
+ // Briefs are the most distilled statement of what an initiative is, and there
4001
+ // are only 56 spans of them. The design's table predates the indexer and
4002
+ // omits the class; including it costs nothing and makes `brief.md` findable.
4003
+ { name: "initiatives", scope: { ownerPrefix: "initiative:" }, weight: 1.15, share: 0.2 },
4004
+ { name: "sources", scope: { ownerPrefix: "source:" }, weight: 1.1, share: 0.3 },
4005
+ { name: "tasks", scope: { ownerPrefix: "task:" }, weight: 1, share: 0.3 },
4006
+ // Narrative restatements of the notes, written by the session that wrote
4007
+ // them: the workspace's own duplicate content, so low on both counts.
4008
+ {
4009
+ name: "sessions",
4010
+ scope: { ownerPrefix: "session:", fields: ["body"] },
4011
+ weight: 0.6,
4012
+ share: 0.2
4013
+ },
4014
+ {
4015
+ name: "transcripts",
4016
+ scope: { ownerPrefix: "session:", fields: TRANSCRIPT_FIELDS },
4017
+ weight: 0.45,
4018
+ share: 0.2
4019
+ }
4020
+ ];
4021
+ function capFor(cls, limit) {
4022
+ return Math.max(1, Math.ceil(limit * cls.share));
4023
+ }
4024
+ function classOf(ref, field) {
4025
+ const prefix = ref.slice(0, ref.indexOf(":"));
4026
+ if (prefix !== "session") return `${prefix}s`;
4027
+ return field !== void 0 && TRANSCRIPT_FIELDS.includes(field) ? "transcripts" : "sessions";
4028
+ }
4029
+
4030
+ // src/search/resolve.ts
4031
+ import path36 from "path";
4032
+ import { readLocatorText } from "@titan-design/locator";
4033
+
4034
+ // src/workspace-index/refs.ts
4035
+ import path35 from "path";
4036
+ import { refKind } from "@titan-design/store-sqlite";
4037
+ var initiativeRef = refKind("initiative");
4038
+ var noteRef = refKind("note");
4039
+ var taskRef = refKind("task");
4040
+ var sessionRef = refKind("session");
4041
+ var sourceRef = refKind("source");
4042
+ function toRelative(activeRoot, absolutePath) {
4043
+ return path35.relative(activeRoot, absolutePath).split(path35.sep).join("/");
4044
+ }
4045
+ function toAbsolute(activeRoot, relativePath) {
4046
+ return path35.join(activeRoot, ...relativePath.split("/"));
4047
+ }
4048
+
4049
+ // src/search/resolve.ts
4050
+ var ROW_SOURCES = [
4051
+ { table: "note", refColumn: "note_ref", title: "title" },
4052
+ { table: "workspace_task", refColumn: "task_ref", title: "title" },
4053
+ { table: "source", refColumn: "source_ref", title: "title" },
4054
+ { table: "initiative", refColumn: "initiative_ref", title: "title" },
4055
+ { table: "session_record", refColumn: "session_ref", title: "session_id" }
4056
+ ];
4057
+ function rowFor(graph, ref) {
4058
+ for (const { table, refColumn, title } of ROW_SOURCES) {
4059
+ const row = graph.db.prepare(
4060
+ `SELECT path, "${title}" AS title, ${table === "initiative" ? "slug" : "initiative"} AS initiative
4061
+ FROM "${table}" WHERE "${refColumn}" = ? LIMIT 1`
4062
+ ).get(ref);
4063
+ if (row) return row;
4064
+ }
4065
+ return null;
4066
+ }
4067
+ function fileForSource(graph, sourceId, activeRoot) {
4068
+ if (sourceId >= WORKSPACE_SPAN_SOURCE_BASE) {
4069
+ const row2 = graph.db.prepare("SELECT source_key FROM workspace_file WHERE source_id = ?").get(sourceId - WORKSPACE_SPAN_SOURCE_BASE);
4070
+ return row2 ? toAbsolute(activeRoot, row2.source_key) : null;
4071
+ }
4072
+ const row = graph.db.prepare("SELECT source_key FROM transcript WHERE source_id = ?").get(sourceId);
4073
+ if (!row) return null;
4074
+ return row.source_key.startsWith("~") ? path36.join(process.env.HOME ?? "", row.source_key.slice(1)) : row.source_key;
4075
+ }
4076
+ function oneLine(text, width) {
4077
+ const flat = text.replace(/\s+/g, " ").trim();
4078
+ return flat.length <= width ? flat : `${flat.slice(0, width - 1)}\u2026`;
4079
+ }
4080
+ async function excerptFor(graph, payload, activeRoot, width) {
4081
+ if (!payload) return null;
4082
+ const file = fileForSource(graph, payload.sourceId, activeRoot);
4083
+ if (file === null) return null;
4084
+ try {
4085
+ const locator = [0, payload.byteOffset, payload.byteLength];
4086
+ return oneLine(await readLocatorText(file, locator), width);
4087
+ } catch {
4088
+ return null;
4089
+ }
4090
+ }
4091
+ function spanPayload(result) {
4092
+ const first = Object.values(result.payloads)[0];
4093
+ return first;
4094
+ }
4095
+ async function resolveHits(graph, results, activeRoot, excerptWidth) {
4096
+ return Promise.all(
4097
+ results.map(async (result) => {
4098
+ const payload = spanPayload(result);
4099
+ const row = rowFor(graph, result.id);
4100
+ return {
4101
+ ref: result.id,
4102
+ class: classOf(result.id, payload?.field),
4103
+ initiative: row?.initiative ?? null,
4104
+ title: row?.title ?? null,
4105
+ path: row?.path ?? null,
4106
+ excerpt: await excerptFor(graph, payload, activeRoot, excerptWidth),
4107
+ score: result.score,
4108
+ sources: result.sources
4109
+ };
4110
+ })
4111
+ );
4112
+ }
4113
+
4114
+ // src/search/index.ts
4115
+ var AFFINITY_BOOST = 7e-3;
4116
+ async function searchWorkspace(query, options = {}) {
4117
+ const activeRoot = options.activeRoot ?? getActiveRoot();
4118
+ const graph = options.graph ?? openGraph(options.dbPath ?? defaultGraphPath());
4119
+ const owned = options.graph === void 0;
4120
+ const limit = options.limit ?? 10;
4121
+ try {
4122
+ const engine = createRetrievalEngine({
4123
+ retrievers: SEARCH_CLASSES.map(
4124
+ (cls) => ftsRetriever(graph.spans, {
4125
+ name: cls.name,
4126
+ scope: cls.scope,
4127
+ cap: capFor(cls, limit)
4128
+ })
4129
+ ),
4130
+ fusion: {
4131
+ weights: Object.fromEntries(SEARCH_CLASSES.map((cls) => [cls.name, cls.weight]))
4132
+ }
4133
+ });
4134
+ const response = await engine.search(query, { limit });
4135
+ const resolved = await resolveHits(
4136
+ graph,
4137
+ response.results,
4138
+ activeRoot,
4139
+ options.excerptWidth ?? 160
4140
+ );
4141
+ const boosted = options.initiative ? resolved.map(
4142
+ (hit) => hit.initiative === options.initiative ? { ...hit, score: hit.score + AFFINITY_BOOST } : hit
4143
+ ).sort((a, b) => b.score - a.score) : resolved;
4144
+ return {
4145
+ hits: boosted.slice(0, limit),
4146
+ degraded: response.degraded,
4147
+ timingsMs: response.timingsMs
4148
+ };
4149
+ } finally {
4150
+ if (owned) graph.db.close();
4151
+ }
4152
+ }
4153
+
4154
+ // src/commands/search.ts
4155
+ var ArgsSchema32 = z33.object({
4156
+ query: z33.string().min(1),
4157
+ limit: z33.number().int().positive().max(100).optional(),
4158
+ initiative: z33.string().min(1).optional()
4159
+ });
4160
+ var HitSchema = z33.object({
4161
+ ref: z33.string(),
4162
+ class: z33.string(),
4163
+ initiative: z33.string().nullable(),
4164
+ title: z33.string().nullable(),
4165
+ path: z33.string().nullable(),
4166
+ excerpt: z33.string().nullable(),
4167
+ score: z33.number(),
4168
+ sources: z33.array(z33.string())
4169
+ });
4170
+ var ResultSchema29 = z33.object({
4171
+ query: z33.string(),
4172
+ hits: z33.array(HitSchema),
4173
+ // A retriever that failed contributed nothing and is named here. The search
4174
+ // still answers, with less; an index is allowed to be partly broken.
4175
+ degraded: z33.array(z33.object({ retriever: z33.string(), reason: z33.string(), message: z33.string() }))
4176
+ });
4177
+ var search_default = defineCommand({
4178
+ name: "search",
4179
+ description: "Search every initiative at once: notes, briefs, sources, tasks, session records and mined transcripts.",
4180
+ args: ArgsSchema32,
4181
+ result: ResultSchema29,
4182
+ cli: {
4183
+ positional: ["query"],
4184
+ options: {
4185
+ limit: { long: "--limit", description: "How many results to return (default 10)" },
4186
+ initiative: {
4187
+ long: "--initiative",
4188
+ description: "Bias towards this initiative. A boost, never a filter \u2014 foreign hits still rank."
4189
+ }
4190
+ },
4191
+ usage: "active-work search <query> [--limit 10] [--initiative <slug>]"
4192
+ },
4193
+ async run(args) {
4194
+ const { hits, degraded } = await searchWorkspace(args.query, {
4195
+ limit: args.limit,
4196
+ initiative: args.initiative
4197
+ });
4198
+ return {
4199
+ query: args.query,
4200
+ hits,
4201
+ degraded: degraded.map((entry) => ({
4202
+ retriever: entry.retriever,
4203
+ reason: entry.reason,
4204
+ message: entry.message
4205
+ }))
4206
+ };
4207
+ }
4208
+ });
4209
+
4210
+ // src/commands/list.ts
4211
+ import { z as z34 } from "zod";
4212
+ var argsSchema2 = z34.object({}).strict();
4213
+ var itemSchema = z34.object({
4214
+ slug: z34.string(),
4215
+ title: z34.string(),
4216
+ state: z34.enum(["focused", "backburner", "paused", "done"]),
4217
+ rank: z34.number().int().positive().optional(),
4218
+ ship_target: z34.string().optional(),
4219
+ paused_since: z34.string().optional(),
4220
+ updated: z34.string()
4221
+ });
4222
+ var sectionSchema = z34.object({
4223
+ heading: z34.string(),
4224
+ items: z34.array(itemSchema)
4225
+ });
4226
+ var parseErrorSchema2 = z34.object({
4227
+ slug: z34.string(),
4228
+ error: z34.string()
4229
+ });
4230
+ var resultSchema2 = z34.object({
4231
+ sections: z34.array(sectionSchema),
4232
+ parse_errors: z34.array(parseErrorSchema2)
3875
4233
  });
3876
4234
  function toItem(slug, fm) {
3877
4235
  return {
@@ -3946,24 +4304,24 @@ var list_default = defineCommand({
3946
4304
  });
3947
4305
 
3948
4306
  // src/commands/worktree-set.ts
3949
- import path34 from "path";
3950
- import { z as z34 } from "zod";
3951
- var argsSchema3 = z34.object({
3952
- slug: z34.string().min(1),
3953
- path: z34.string().min(1),
3954
- label: z34.string().min(1).optional(),
3955
- default: z34.boolean().optional()
4307
+ import path37 from "path";
4308
+ import { z as z35 } from "zod";
4309
+ var argsSchema3 = z35.object({
4310
+ slug: z35.string().min(1),
4311
+ path: z35.string().min(1),
4312
+ label: z35.string().min(1).optional(),
4313
+ default: z35.boolean().optional()
3956
4314
  });
3957
- var resultSchema3 = z34.object({
3958
- slug: z34.string(),
3959
- label: z34.string(),
3960
- path: z34.string(),
3961
- default: z34.boolean(),
4315
+ var resultSchema3 = z35.object({
4316
+ slug: z35.string(),
4317
+ label: z35.string(),
4318
+ path: z35.string(),
4319
+ default: z35.boolean(),
3962
4320
  /** True when this promoted a worktree `wrap` had already swept (AW-67). */
3963
- promoted: z34.boolean()
4321
+ promoted: z35.boolean()
3964
4322
  });
3965
4323
  var DEFAULT_LABEL = "main";
3966
- var samePath = (a, b) => path34.resolve(expandTilde(a)) === path34.resolve(expandTilde(b));
4324
+ var samePath = (a, b) => path37.resolve(expandTilde(a)) === path37.resolve(expandTilde(b));
3967
4325
  var worktree_set_default = defineCommand({
3968
4326
  name: "worktree.set",
3969
4327
  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.",
@@ -3985,8 +4343,8 @@ var worktree_set_default = defineCommand({
3985
4343
  },
3986
4344
  async run(args) {
3987
4345
  const label = args.label ?? DEFAULT_LABEL;
3988
- const initiativeDir = path34.join(getActiveRoot(), args.slug);
3989
- const briefPath = path34.join(initiativeDir, "brief.md");
4346
+ const initiativeDir = path37.join(getActiveRoot(), args.slug);
4347
+ const briefPath = path37.join(initiativeDir, "brief.md");
3990
4348
  return withFileLock(getLockPath(args.slug), async () => {
3991
4349
  let frontmatter2;
3992
4350
  let body;
@@ -4040,15 +4398,15 @@ var worktree_set_default = defineCommand({
4040
4398
  });
4041
4399
 
4042
4400
  // src/commands/worktree-set-default.ts
4043
- import path35 from "path";
4044
- import { z as z35 } from "zod";
4045
- var argsSchema4 = z35.object({
4046
- slug: z35.string().min(1),
4047
- label: z35.string().min(1)
4401
+ import path38 from "path";
4402
+ import { z as z36 } from "zod";
4403
+ var argsSchema4 = z36.object({
4404
+ slug: z36.string().min(1),
4405
+ label: z36.string().min(1)
4048
4406
  });
4049
- var resultSchema4 = z35.object({
4050
- slug: z35.string(),
4051
- default_label: z35.string()
4407
+ var resultSchema4 = z36.object({
4408
+ slug: z36.string(),
4409
+ default_label: z36.string()
4052
4410
  });
4053
4411
  var worktree_set_default_default = defineCommand({
4054
4412
  name: "worktree.set-default",
@@ -4059,8 +4417,8 @@ var worktree_set_default_default = defineCommand({
4059
4417
  positional: ["slug", "label"]
4060
4418
  },
4061
4419
  async run({ slug, label }) {
4062
- const initiativeDir = path35.join(getActiveRoot(), slug);
4063
- const briefPath = path35.join(initiativeDir, "brief.md");
4420
+ const initiativeDir = path38.join(getActiveRoot(), slug);
4421
+ const briefPath = path38.join(initiativeDir, "brief.md");
4064
4422
  return withFileLock(getLockPath(slug), async () => {
4065
4423
  let frontmatter2;
4066
4424
  let body;
@@ -4091,11 +4449,11 @@ var worktree_set_default_default = defineCommand({
4091
4449
  });
4092
4450
 
4093
4451
  // src/commands/discover.ts
4094
- import { z as z36 } from "zod";
4452
+ import { z as z37 } from "zod";
4095
4453
 
4096
4454
  // src/discover/index.ts
4097
4455
  import { promises as fs29 } from "fs";
4098
- import path39 from "path";
4456
+ import path42 from "path";
4099
4457
 
4100
4458
  // src/discover/run-command.ts
4101
4459
  import { spawn } from "child_process";
@@ -4192,13 +4550,13 @@ async function discoverGitHub(repos, run = runCommand) {
4192
4550
  }
4193
4551
 
4194
4552
  // src/discover/git.ts
4195
- import path36 from "path";
4553
+ import path39 from "path";
4196
4554
  var BRANCH_LIMIT = 20;
4197
4555
  async function discoverGit(repoPaths, run = runCommand) {
4198
4556
  const hits = [];
4199
4557
  const errors = [];
4200
4558
  for (const repoPath of repoPaths) {
4201
- const repoName = path36.basename(repoPath);
4559
+ const repoName = path39.basename(repoPath);
4202
4560
  await collectBranches(repoPath, repoName, hits, errors, run);
4203
4561
  await collectWorktrees(repoPath, repoName, hits, errors, run);
4204
4562
  await collectStashes(repoPath, repoName, hits, errors, run);
@@ -4313,14 +4671,14 @@ function errStr(err) {
4313
4671
 
4314
4672
  // src/discover/projects.ts
4315
4673
  import { promises as fs27 } from "fs";
4316
- import path37 from "path";
4674
+ import path40 from "path";
4317
4675
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
4318
4676
  var RECENT_THRESHOLD_DAYS = 30;
4319
4677
  async function discoverProjects(projectsRoot) {
4320
4678
  const hits = [];
4321
4679
  const errors = [];
4322
4680
  if (!projectsRoot) return { hits, errors };
4323
- const resolved = path37.resolve(expandTilde(projectsRoot));
4681
+ const resolved = path40.resolve(expandTilde(projectsRoot));
4324
4682
  let entries;
4325
4683
  try {
4326
4684
  entries = await fs27.readdir(resolved, { withFileTypes: true });
@@ -4336,7 +4694,7 @@ async function discoverProjects(projectsRoot) {
4336
4694
  if (!entry.isDirectory()) continue;
4337
4695
  if (entry.name.startsWith(".")) continue;
4338
4696
  if (entry.name === "active") continue;
4339
- const fullPath = path37.join(resolved, entry.name);
4697
+ const fullPath = path40.join(resolved, entry.name);
4340
4698
  let mtimeMs = 0;
4341
4699
  try {
4342
4700
  const stat = await fs27.stat(fullPath);
@@ -4369,11 +4727,11 @@ async function discoverProjects(projectsRoot) {
4369
4727
  // src/discover/claude.ts
4370
4728
  import { promises as fs28 } from "fs";
4371
4729
  import os2 from "os";
4372
- import path38 from "path";
4730
+ import path41 from "path";
4373
4731
  var MAX_SCAN_LINES = 200;
4374
4732
  var COMPACTION_SUBJECT_PREFIX = "[compaction] ";
4375
4733
  async function discoverClaudeSessions() {
4376
- const root = process.env.CLAUDE_PROJECTS_ROOT ?? path38.join(os2.homedir(), ".claude", "projects");
4734
+ const root = process.env.CLAUDE_PROJECTS_ROOT ?? path41.join(os2.homedir(), ".claude", "projects");
4377
4735
  const hits = [];
4378
4736
  const errors = [];
4379
4737
  let projectDirs;
@@ -4388,7 +4746,7 @@ async function discoverClaudeSessions() {
4388
4746
  const byCwd = /* @__PURE__ */ new Map();
4389
4747
  for (const dir of projectDirs) {
4390
4748
  if (!dir.isDirectory()) continue;
4391
- const dirPath = path38.join(root, dir.name);
4749
+ const dirPath = path41.join(root, dir.name);
4392
4750
  let files;
4393
4751
  try {
4394
4752
  files = await fs28.readdir(dirPath, { withFileTypes: true });
@@ -4401,7 +4759,7 @@ async function discoverClaudeSessions() {
4401
4759
  }
4402
4760
  for (const file of files) {
4403
4761
  if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
4404
- const filePath = path38.join(dirPath, file.name);
4762
+ const filePath = path41.join(dirPath, file.name);
4405
4763
  try {
4406
4764
  await aggregateSession(filePath, byCwd);
4407
4765
  } catch (err) {
@@ -4457,7 +4815,7 @@ async function aggregateSession(filePath, byCwd) {
4457
4815
  }
4458
4816
  if (!cwd) return;
4459
4817
  const subject = lastCompactionSummary ? `${COMPACTION_SUBJECT_PREFIX}${truncate2(lastCompactionSummary, 120)}` : firstUserMessage ? truncate2(firstUserMessage, 120) : "";
4460
- const sessionId = path38.basename(filePath, ".jsonl");
4818
+ const sessionId = path41.basename(filePath, ".jsonl");
4461
4819
  const existing = byCwd.get(cwd);
4462
4820
  if (!existing) {
4463
4821
  byCwd.set(cwd, {
@@ -4557,7 +4915,7 @@ async function loadSlugs(activeRoot) {
4557
4915
  }
4558
4916
  }
4559
4917
  async function loadTriagedRefs(activeRoot) {
4560
- const logPath = path39.join(activeRoot, ".triaged.log");
4918
+ const logPath = path42.join(activeRoot, ".triaged.log");
4561
4919
  const refs = /* @__PURE__ */ new Set();
4562
4920
  try {
4563
4921
  const raw = await fs29.readFile(logPath, "utf8");
@@ -4583,28 +4941,28 @@ function matchSlug(hit, slugs) {
4583
4941
  }
4584
4942
 
4585
4943
  // src/commands/discover.ts
4586
- var ArgsSchema32 = z36.object({
4587
- github_repos: z36.array(z36.string().min(1)).optional(),
4588
- local_repos: z36.array(z36.string().min(1)).optional(),
4589
- projects_root: z36.string().optional()
4590
- });
4591
- var HitSchema = z36.object({
4592
- source: z36.string(),
4593
- ref: z36.string(),
4594
- detail: z36.string(),
4595
- metadata: z36.record(z36.string(), z36.unknown()).optional(),
4596
- slug_match: z36.string().optional(),
4597
- untracked: z36.boolean().optional()
4598
- });
4599
- var ResultSchema29 = z36.object({
4600
- hits: z36.array(HitSchema),
4601
- errors: z36.array(z36.object({ source: z36.string(), error: z36.string() }))
4944
+ var ArgsSchema33 = z37.object({
4945
+ github_repos: z37.array(z37.string().min(1)).optional(),
4946
+ local_repos: z37.array(z37.string().min(1)).optional(),
4947
+ projects_root: z37.string().optional()
4948
+ });
4949
+ var HitSchema2 = z37.object({
4950
+ source: z37.string(),
4951
+ ref: z37.string(),
4952
+ detail: z37.string(),
4953
+ metadata: z37.record(z37.string(), z37.unknown()).optional(),
4954
+ slug_match: z37.string().optional(),
4955
+ untracked: z37.boolean().optional()
4956
+ });
4957
+ var ResultSchema30 = z37.object({
4958
+ hits: z37.array(HitSchema2),
4959
+ errors: z37.array(z37.object({ source: z37.string(), error: z37.string() }))
4602
4960
  });
4603
4961
  var discover_default = defineCommand({
4604
4962
  name: "discover",
4605
4963
  description: "Scan configured sources (gh PRs, local git, projects root, Claude sessions) and emit unfiltered discovery hits.",
4606
- args: ArgsSchema32,
4607
- result: ResultSchema29,
4964
+ args: ArgsSchema33,
4965
+ result: ResultSchema30,
4608
4966
  cli: {
4609
4967
  options: {
4610
4968
  github_repos: {
@@ -4631,15 +4989,15 @@ var discover_default = defineCommand({
4631
4989
  });
4632
4990
 
4633
4991
  // src/commands/drop.ts
4634
- import { z as z37 } from "zod";
4992
+ import { z as z38 } from "zod";
4635
4993
 
4636
4994
  // src/discover/triaged-log.ts
4637
4995
  import { promises as fs30 } from "fs";
4638
- import path40 from "path";
4996
+ import path43 from "path";
4639
4997
  async function appendTriagedLog(action, ref, extra) {
4640
4998
  const root = getActiveRoot();
4641
4999
  await fs30.mkdir(root, { recursive: true });
4642
- const logPath = path40.join(root, ".triaged.log");
5000
+ const logPath = path43.join(root, ".triaged.log");
4643
5001
  let existing = "";
4644
5002
  try {
4645
5003
  existing = await fs30.readFile(logPath, "utf8");
@@ -4652,18 +5010,18 @@ async function appendTriagedLog(action, ref, extra) {
4652
5010
  }
4653
5011
 
4654
5012
  // src/commands/drop.ts
4655
- var ArgsSchema33 = z37.object({
4656
- ref: z37.string().min(1),
4657
- reason: z37.string().optional()
5013
+ var ArgsSchema34 = z38.object({
5014
+ ref: z38.string().min(1),
5015
+ reason: z38.string().optional()
4658
5016
  });
4659
- var ResultSchema30 = z37.object({
4660
- ref: z37.string()
5017
+ var ResultSchema31 = z38.object({
5018
+ ref: z38.string()
4661
5019
  });
4662
5020
  var drop_default = defineCommand({
4663
5021
  name: "drop",
4664
5022
  description: "Mark a discover hit as dropped so future discovers suppress it.",
4665
- args: ArgsSchema33,
4666
- result: ResultSchema30,
5023
+ args: ArgsSchema34,
5024
+ result: ResultSchema31,
4667
5025
  cli: {
4668
5026
  positional: ["ref"],
4669
5027
  options: {
@@ -4681,23 +5039,23 @@ var drop_default = defineCommand({
4681
5039
 
4682
5040
  // src/commands/fold.ts
4683
5041
  import { promises as fs31 } from "fs";
4684
- import path41 from "path";
4685
- import { z as z38 } from "zod";
4686
- var ArgsSchema34 = z38.object({
4687
- ref: z38.string().min(1),
4688
- into: z38.string().min(1),
4689
- note: z38.string().optional()
5042
+ import path44 from "path";
5043
+ import { z as z39 } from "zod";
5044
+ var ArgsSchema35 = z39.object({
5045
+ ref: z39.string().min(1),
5046
+ into: z39.string().min(1),
5047
+ note: z39.string().optional()
4690
5048
  });
4691
- var ResultSchema31 = z38.object({
4692
- ref: z38.string(),
4693
- into: z38.string(),
4694
- session_file: z38.string()
5049
+ var ResultSchema32 = z39.object({
5050
+ ref: z39.string(),
5051
+ into: z39.string(),
5052
+ session_file: z39.string()
4695
5053
  });
4696
5054
  var fold_default = defineCommand({
4697
5055
  name: "fold",
4698
5056
  description: "Mark a discover hit as folded into an existing initiative.",
4699
- args: ArgsSchema34,
4700
- result: ResultSchema31,
5057
+ args: ArgsSchema35,
5058
+ result: ResultSchema32,
4701
5059
  cli: {
4702
5060
  positional: ["ref"],
4703
5061
  options: {
@@ -4723,7 +5081,7 @@ var fold_default = defineCommand({
4723
5081
  if (err instanceof NotFoundError) throw err;
4724
5082
  throw new NotFoundError(`Initiative not found: ${args.into}`);
4725
5083
  }
4726
- const sessionsDir = path41.join(initiativeDir, "sessions");
5084
+ const sessionsDir = path44.join(initiativeDir, "sessions");
4727
5085
  await fs31.mkdir(sessionsDir, { recursive: true });
4728
5086
  const startedIso = nowIso();
4729
5087
  const stem = buildSessionStem(startedIso, `folded-${sanitizeRef(args.ref)}`);
@@ -4756,27 +5114,27 @@ function sanitizeRef(ref) {
4756
5114
 
4757
5115
  // src/commands/track.ts
4758
5116
  import { promises as fs32 } from "fs";
4759
- import path42 from "path";
4760
- import { z as z39 } from "zod";
5117
+ import path45 from "path";
5118
+ import { z as z40 } from "zod";
4761
5119
  import { stringify as yamlStringify } from "yaml";
4762
- var ArgsSchema35 = z39.object({
4763
- ref: z39.string().min(1),
4764
- slug: z39.string().min(1),
4765
- title: z39.string().optional(),
4766
- ship_target: z39.string().optional(),
4767
- owner: z39.string().optional(),
4768
- worktree: z39.string().optional()
4769
- });
4770
- var ResultSchema32 = z39.object({
4771
- slug: z39.string(),
4772
- dir: z39.string(),
4773
- ref: z39.string()
5120
+ var ArgsSchema36 = z40.object({
5121
+ ref: z40.string().min(1),
5122
+ slug: z40.string().min(1),
5123
+ title: z40.string().optional(),
5124
+ ship_target: z40.string().optional(),
5125
+ owner: z40.string().optional(),
5126
+ worktree: z40.string().optional()
5127
+ });
5128
+ var ResultSchema33 = z40.object({
5129
+ slug: z40.string(),
5130
+ dir: z40.string(),
5131
+ ref: z40.string()
4774
5132
  });
4775
5133
  var track_default = defineCommand({
4776
5134
  name: "track",
4777
5135
  description: "Scaffold a new initiative from a discover hit.",
4778
- args: ArgsSchema35,
4779
- result: ResultSchema32,
5136
+ args: ArgsSchema36,
5137
+ result: ResultSchema33,
4780
5138
  cli: {
4781
5139
  positional: ["ref"],
4782
5140
  options: {
@@ -4803,13 +5161,13 @@ var track_default = defineCommand({
4803
5161
  if (await dirExists5(dir)) {
4804
5162
  throw new UsageError(`Initiative already exists: ${args.slug}`);
4805
5163
  }
4806
- await fs32.mkdir(path42.join(dir, "tasks"), { recursive: true });
4807
- await fs32.mkdir(path42.join(dir, "sessions"), { recursive: true });
4808
- await fs32.mkdir(path42.join(dir, "sources"), { recursive: true });
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 });
4809
5167
  const title = args.title ?? deriveTitle(args.slug);
4810
5168
  const briefBody = buildBriefBody(title, args.ref);
4811
5169
  await writeFrontmatter(
4812
- path42.join(dir, "brief.md"),
5170
+ path45.join(dir, "brief.md"),
4813
5171
  {
4814
5172
  schema_version: 1,
4815
5173
  title,
@@ -4825,8 +5183,8 @@ var track_default = defineCommand({
4825
5183
  const artifacts = ArtifactsSchema.parse({
4826
5184
  worktrees: args.worktree ? [{ path: args.worktree, repo: args.worktree, name: "main", default: true }] : []
4827
5185
  });
4828
- await atomicWrite(path42.join(dir, "artifacts.yml"), yamlStringify(artifacts));
4829
- await atomicWrite(path42.join(dir, "sources", ".gitkeep"), "");
5186
+ await atomicWrite(path45.join(dir, "artifacts.yml"), yamlStringify(artifacts));
5187
+ await atomicWrite(path45.join(dir, "sources", ".gitkeep"), "");
4830
5188
  await appendTriagedLog("track", args.ref, `slug:${args.slug}`);
4831
5189
  return { slug: args.slug, dir, ref: args.ref };
4832
5190
  }
@@ -4856,24 +5214,24 @@ function buildBriefBody(title, ref) {
4856
5214
  }
4857
5215
 
4858
5216
  // src/commands/prompt.ts
4859
- import { z as z40 } from "zod";
4860
- var ArgsSchema36 = z40.object({
4861
- slug: z40.string().min(1).optional(),
4862
- offline: z40.boolean().optional(),
5217
+ import { z as z41 } from "zod";
5218
+ var ArgsSchema37 = z41.object({
5219
+ slug: z41.string().min(1).optional(),
5220
+ offline: z41.boolean().optional(),
4863
5221
  // Directory to resolve the initiative from when no slug is given. Falls back
4864
5222
  // to the interactive-surface context cwd; unset for daemon/MCP callers.
4865
- cwd: z40.string().min(1).optional(),
5223
+ cwd: z41.string().min(1).optional(),
4866
5224
  // Frame the prompt as ad-hoc work on the workstream rather than a
4867
5225
  // continuation of its handoff / top task.
4868
- adhoc: z40.boolean().optional(),
5226
+ adhoc: z41.boolean().optional(),
4869
5227
  // Skip the check for another session already live on this initiative.
4870
- no_sibling_check: z40.boolean().optional()
5228
+ no_sibling_check: z41.boolean().optional()
4871
5229
  });
4872
5230
  var promptCommand = defineCommand({
4873
5231
  name: "prompt",
4874
5232
  description: "Print the bootstrap prompt for an initiative \u2014 the same text `aw` feeds Claude at launch \u2014 without any side effects. Resolves the initiative from a slug or the caller's cwd. Use it to re-seed context in a running session.",
4875
- args: ArgsSchema36,
4876
- result: z40.string(),
5233
+ args: ArgsSchema37,
5234
+ result: z41.string(),
4877
5235
  cli: {
4878
5236
  positional: ["slug"],
4879
5237
  options: {
@@ -4926,19 +5284,19 @@ var prompt_default = promptCommand;
4926
5284
 
4927
5285
  // src/commands/edit.ts
4928
5286
  import { promises as fs33 } from "fs";
4929
- import path43 from "path";
5287
+ import path46 from "path";
4930
5288
  import { spawn as spawn2 } from "child_process";
4931
- import { z as z41 } from "zod";
4932
- var ArgsSchema37 = z41.object({
4933
- slug: z41.string().min(1),
4934
- target: z41.enum(["brief"]).default("brief")
5289
+ import { z as z42 } from "zod";
5290
+ var ArgsSchema38 = z42.object({
5291
+ slug: z42.string().min(1),
5292
+ target: z42.enum(["brief"]).default("brief")
4935
5293
  });
4936
- var ResultSchema33 = z41.object({
4937
- slug: z41.string(),
4938
- target: z41.enum(["brief"]),
4939
- file: z41.string(),
4940
- validated: z41.boolean(),
4941
- aborted: z41.boolean().optional()
5294
+ var ResultSchema34 = z42.object({
5295
+ slug: z42.string(),
5296
+ target: z42.enum(["brief"]),
5297
+ file: z42.string(),
5298
+ validated: z42.boolean(),
5299
+ aborted: z42.boolean().optional()
4942
5300
  });
4943
5301
  async function resolveEditor(filePath) {
4944
5302
  const editorEnv = process.env.EDITOR;
@@ -4977,7 +5335,7 @@ var defaultDeps = {
4977
5335
  spawner: defaultSpawner
4978
5336
  };
4979
5337
  function targetFile(slug) {
4980
- return path43.join(getInitiativeDir(slug), "brief.md");
5338
+ return path46.join(getInitiativeDir(slug), "brief.md");
4981
5339
  }
4982
5340
  async function fileExists2(p) {
4983
5341
  try {
@@ -5025,8 +5383,8 @@ ${message}`,
5025
5383
  var edit = defineCommand({
5026
5384
  name: "edit",
5027
5385
  description: "Open the operator's editor on brief.md.",
5028
- args: ArgsSchema37,
5029
- result: ResultSchema33,
5386
+ args: ArgsSchema38,
5387
+ result: ResultSchema34,
5030
5388
  cli: {
5031
5389
  positional: ["slug", "target"],
5032
5390
  usage: "active-work edit <slug> [brief]"
@@ -5039,7 +5397,7 @@ var edit_default = edit;
5039
5397
 
5040
5398
  // src/commands/mcp-serve.ts
5041
5399
  import { spawn as spawn3 } from "child_process";
5042
- import { z as z43 } from "zod";
5400
+ import { z as z44 } from "zod";
5043
5401
 
5044
5402
  // src/server/mcp.ts
5045
5403
  import {
@@ -5056,7 +5414,7 @@ import {
5056
5414
  } from "@titan-design/registry";
5057
5415
 
5058
5416
  // src/version.ts
5059
- var BUILD_VERSION = "0.5.0";
5417
+ var BUILD_VERSION = "0.6.0";
5060
5418
 
5061
5419
  // src/server/mcp.ts
5062
5420
  var TOOL_NAME_PREFIX = "active__";
@@ -5079,7 +5437,7 @@ import { DaemonAlreadyRunningError, startDaemon } from "@titan-design/daemon";
5079
5437
 
5080
5438
  // src/server/dashboard-routes.ts
5081
5439
  import { promises as fs34 } from "fs";
5082
- import path44 from "path";
5440
+ import path47 from "path";
5083
5441
  import { fileURLToPath } from "url";
5084
5442
  var PLACEHOLDER_HTML = `<!doctype html>
5085
5443
  <html lang="en">
@@ -5111,17 +5469,17 @@ var CONTENT_TYPES = {
5111
5469
  ".woff2": "font/woff2"
5112
5470
  };
5113
5471
  function contentTypeFor(filename) {
5114
- const ext = path44.extname(filename).toLowerCase();
5472
+ const ext = path47.extname(filename).toLowerCase();
5115
5473
  return CONTENT_TYPES[ext] ?? "application/octet-stream";
5116
5474
  }
5117
5475
  function dashboardDirCandidates() {
5118
- const here = path44.dirname(fileURLToPath(import.meta.url));
5476
+ const here = path47.dirname(fileURLToPath(import.meta.url));
5119
5477
  return [
5120
- path44.resolve(here, "dashboard"),
5478
+ path47.resolve(here, "dashboard"),
5121
5479
  // bundled: dist/cli.js -> dist/dashboard
5122
- path44.resolve(here, "..", "dashboard"),
5480
+ path47.resolve(here, "..", "dashboard"),
5123
5481
  // legacy: dist/server -> dist/dashboard
5124
- path44.resolve(here, "..", "..", "dist", "dashboard")
5482
+ path47.resolve(here, "..", "..", "dist", "dashboard")
5125
5483
  // dev: src/server -> dist/dashboard
5126
5484
  ];
5127
5485
  }
@@ -5147,13 +5505,13 @@ async function handleDashboard(c) {
5147
5505
  const url = new URL(c.req.url);
5148
5506
  const subpath = url.pathname.replace(/^\/ui\/?/, "");
5149
5507
  const relative = subpath === "" ? "index.html" : subpath;
5150
- const target = path44.resolve(root, relative);
5151
- if (!target.startsWith(root + path44.sep) && target !== root) {
5508
+ const target = path47.resolve(root, relative);
5509
+ if (!target.startsWith(root + path47.sep) && target !== root) {
5152
5510
  return c.text("forbidden", 403);
5153
5511
  }
5154
5512
  const stat = await safeStat(target);
5155
5513
  if (!stat.exists || !stat.isFile) {
5156
- const indexPath = path44.join(root, "index.html");
5514
+ const indexPath = path47.join(root, "index.html");
5157
5515
  const indexStat = await safeStat(indexPath);
5158
5516
  if (!indexStat.exists) {
5159
5517
  return c.html(PLACEHOLDER_HTML, 200);
@@ -5166,177 +5524,39 @@ async function handleDashboard(c) {
5166
5524
  const body = await fs34.readFile(target);
5167
5525
  return c.body(new Uint8Array(body), 200, {
5168
5526
  "content-type": contentTypeFor(target)
5169
- });
5170
- }
5171
-
5172
- // src/server/logger.ts
5173
- import { mkdirSync, createWriteStream } from "fs";
5174
- import path45 from "path";
5175
- import pino, { multistream } from "pino";
5176
- var cachedLogger;
5177
- function buildLogger() {
5178
- const stateRoot = getStateRoot();
5179
- mkdirSync(stateRoot, { recursive: true });
5180
- const logPath = path45.join(stateRoot, "daemon.log");
5181
- const fileStream = createWriteStream(logPath, { flags: "a" });
5182
- const stderrIsTTY = process.stderr.isTTY === true;
5183
- const stderrStream = stderrIsTTY ? pino.transport({
5184
- target: "pino-pretty",
5185
- options: { destination: 2, colorize: true }
5186
- }) : process.stderr;
5187
- const streams = [{ stream: stderrStream }, { stream: fileStream }];
5188
- return pino({ level: process.env.AW_LOG_LEVEL ?? "info" }, multistream(streams));
5189
- }
5190
- function getLogger() {
5191
- cachedLogger ??= buildLogger();
5192
- return cachedLogger;
5193
- }
5194
-
5195
- // src/server/session-index-watch.ts
5196
- import { existsSync } from "fs";
5197
- import { transcriptsRoot as transcriptsRoot2 } from "@titan-design/session-read";
5198
- import { watchTree } from "@titan-design/daemon";
5199
-
5200
- // src/session-index/graph.ts
5201
- import Database from "better-sqlite3";
5202
- import { openSessionGraph } from "@titan-design/session-graph";
5203
- import { runMigrations, WatermarkTable } from "@titan-design/store-sqlite";
5204
- import path46 from "path";
5205
-
5206
- // src/workspace-index/schema.ts
5207
- import { kitDdl } from "@titan-design/store-sqlite";
5208
- import { MIGRATIONS as SESSION_GRAPH_MIGRATIONS } from "@titan-design/session-graph";
5209
- var WORKSPACE_KIT = {
5210
- watermark: "workspace_file",
5211
- edge: "edge",
5212
- spanFts: "search"
5213
- };
5214
- var WORKSPACE_SPAN_SOURCE_BASE = 1e9;
5215
- var DOMAIN_DDL = `
5216
- CREATE TABLE IF NOT EXISTS initiative (
5217
- path TEXT PRIMARY KEY,
5218
- initiative_ref TEXT NOT NULL UNIQUE,
5219
- slug TEXT NOT NULL,
5220
- title TEXT,
5221
- state TEXT,
5222
- rank INTEGER,
5223
- ship_target TEXT,
5224
- owner TEXT,
5225
- task_prefix TEXT,
5226
- updated TEXT
5227
- );
5228
-
5229
- CREATE TABLE IF NOT EXISTS note (
5230
- path TEXT PRIMARY KEY,
5231
- note_ref TEXT NOT NULL UNIQUE,
5232
- initiative TEXT NOT NULL,
5233
- filename TEXT NOT NULL,
5234
- kind TEXT NOT NULL,
5235
- title TEXT NOT NULL,
5236
- created TEXT,
5237
- tags TEXT,
5238
- hits INTEGER NOT NULL DEFAULT 0,
5239
- promoted_at TEXT
5240
- );
5241
- CREATE INDEX IF NOT EXISTS idx_note_initiative ON note(initiative);
5242
-
5243
- CREATE TABLE IF NOT EXISTS workspace_task (
5244
- path TEXT PRIMARY KEY,
5245
- task_ref TEXT NOT NULL,
5246
- initiative TEXT NOT NULL,
5247
- task_id TEXT NOT NULL,
5248
- title TEXT NOT NULL,
5249
- status TEXT NOT NULL,
5250
- priority INTEGER,
5251
- severity TEXT,
5252
- estimate REAL,
5253
- tags TEXT,
5254
- created TEXT,
5255
- updated TEXT,
5256
- done_at TEXT
5257
- );
5258
- CREATE INDEX IF NOT EXISTS idx_workspace_task_ref ON workspace_task(task_ref);
5259
-
5260
- CREATE TABLE IF NOT EXISTS session_record (
5261
- path TEXT PRIMARY KEY,
5262
- session_ref TEXT NOT NULL,
5263
- initiative TEXT NOT NULL,
5264
- session_id TEXT NOT NULL,
5265
- started TEXT,
5266
- ended TEXT,
5267
- track TEXT,
5268
- parent_session_id TEXT
5269
- );
5270
- CREATE INDEX IF NOT EXISTS idx_session_record_ref ON session_record(session_ref);
5271
-
5272
- CREATE TABLE IF NOT EXISTS source (
5273
- path TEXT PRIMARY KEY,
5274
- source_ref TEXT NOT NULL UNIQUE,
5275
- initiative TEXT NOT NULL,
5276
- title TEXT,
5277
- kind TEXT,
5278
- added TEXT
5279
- );
5280
- `;
5281
- function nextVersion(chain) {
5282
- return (chain[chain.length - 1]?.version ?? 0) + 1;
5283
- }
5284
- var SPAN_SOURCE_INDEX = `
5285
- CREATE INDEX IF NOT EXISTS idx_search_span_source ON search_span(source_id);
5286
- `;
5287
- var WORKSPACE_MIGRATIONS = [
5288
- {
5289
- version: nextVersion(SESSION_GRAPH_MIGRATIONS),
5290
- name: "workspace index tables",
5291
- up: (db) => {
5292
- db.exec(kitDdl({ watermark: WORKSPACE_KIT.watermark }));
5293
- db.exec(DOMAIN_DDL);
5294
- db.exec(SPAN_SOURCE_INDEX);
5295
- }
5296
- }
5297
- ];
5298
- var PRESERVE_DDL = `
5299
- CREATE TABLE IF NOT EXISTS preserved_row (
5300
- table_name TEXT NOT NULL,
5301
- identity TEXT NOT NULL,
5302
- row_key TEXT NOT NULL,
5303
- payload TEXT NOT NULL,
5304
- origin TEXT NOT NULL,
5305
- mode TEXT NOT NULL DEFAULT 'insert',
5306
- preserved_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
5307
- PRIMARY KEY (table_name, row_key)
5308
- );
5309
- `;
5310
- var PRESERVE_MIGRATION = {
5311
- version: nextVersion([...SESSION_GRAPH_MIGRATIONS, ...WORKSPACE_MIGRATIONS]),
5312
- name: "preserved rows",
5313
- up: (db) => db.exec(PRESERVE_DDL)
5314
- };
5315
- var MIGRATIONS = [
5316
- ...SESSION_GRAPH_MIGRATIONS,
5317
- ...WORKSPACE_MIGRATIONS,
5318
- PRESERVE_MIGRATION
5319
- ];
5320
-
5321
- // src/session-index/graph.ts
5322
- var SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
5323
- function defaultGraphPath() {
5324
- return path46.join(getMinerRoot(), "graph.sqlite3");
5527
+ });
5325
5528
  }
5326
- function openGraph(dbPath = defaultGraphPath()) {
5327
- const graph = openSessionGraph(dbPath);
5328
- runMigrations(graph.db, MIGRATIONS);
5329
- return {
5330
- ...graph,
5331
- workspaceFiles: new WatermarkTable(graph.db, { name: WORKSPACE_KIT.watermark })
5332
- };
5529
+
5530
+ // src/server/logger.ts
5531
+ import { mkdirSync, createWriteStream } from "fs";
5532
+ import path48 from "path";
5533
+ import pino, { multistream } from "pino";
5534
+ var cachedLogger;
5535
+ function buildLogger() {
5536
+ const stateRoot = getStateRoot();
5537
+ mkdirSync(stateRoot, { recursive: true });
5538
+ const logPath = path48.join(stateRoot, "daemon.log");
5539
+ const fileStream = createWriteStream(logPath, { flags: "a" });
5540
+ const stderrIsTTY = process.stderr.isTTY === true;
5541
+ const stderrStream = stderrIsTTY ? pino.transport({
5542
+ target: "pino-pretty",
5543
+ options: { destination: 2, colorize: true }
5544
+ }) : process.stderr;
5545
+ const streams = [{ stream: stderrStream }, { stream: fileStream }];
5546
+ return pino({ level: process.env.AW_LOG_LEVEL ?? "info" }, multistream(streams));
5333
5547
  }
5334
- function openGraphReadOnly(dbPath = defaultGraphPath()) {
5335
- return new Database(dbPath, { readonly: true });
5548
+ function getLogger() {
5549
+ cachedLogger ??= buildLogger();
5550
+ return cachedLogger;
5336
5551
  }
5337
5552
 
5553
+ // src/server/session-index-watch.ts
5554
+ import { existsSync } from "fs";
5555
+ import { transcriptsRoot as transcriptsRoot2 } from "@titan-design/session-read";
5556
+ import { watchTree } from "@titan-design/daemon";
5557
+
5338
5558
  // src/session-index/refresh.ts
5339
- import path56 from "path";
5559
+ import path57 from "path";
5340
5560
  import { promises as fs44 } from "fs";
5341
5561
  import lockfile from "proper-lockfile";
5342
5562
  import { discoverTranscripts, transcriptsRoot } from "@titan-design/session-read";
@@ -5344,7 +5564,7 @@ import { refreshCorpus, resetIndex } from "@titan-design/session-graph";
5344
5564
 
5345
5565
  // src/session-index/tasks.ts
5346
5566
  import { promises as fs35 } from "fs";
5347
- import path47 from "path";
5567
+ import path49 from "path";
5348
5568
  var AMBIGUOUS = null;
5349
5569
  async function initiativeSlugs(root) {
5350
5570
  try {
@@ -5356,7 +5576,7 @@ async function initiativeSlugs(root) {
5356
5576
  }
5357
5577
  }
5358
5578
  async function readInitiative(root, slug) {
5359
- const dir = path47.join(root, slug, "tasks");
5579
+ const dir = path49.join(root, slug, "tasks");
5360
5580
  let files;
5361
5581
  try {
5362
5582
  files = await fs35.readdir(dir);
@@ -5368,7 +5588,7 @@ async function readInitiative(root, slug) {
5368
5588
  for (const file of files) {
5369
5589
  if (!file.endsWith(".yml")) continue;
5370
5590
  try {
5371
- const task = await readYaml(path47.join(dir, file), TaskSchema);
5591
+ const task = await readYaml(path49.join(dir, file), TaskSchema);
5372
5592
  found.push([task.id, { initiative: slug, title: task.title, status: task.status }]);
5373
5593
  } catch {
5374
5594
  continue;
@@ -5401,22 +5621,7 @@ function taskResolver(root) {
5401
5621
  // src/workspace-index/refresh.ts
5402
5622
  import { promises as fs43 } from "fs";
5403
5623
  import matter4 from "gray-matter";
5404
- import { z as z42 } from "zod";
5405
-
5406
- // src/workspace-index/refs.ts
5407
- import path48 from "path";
5408
- import { refKind } from "@titan-design/store-sqlite";
5409
- var initiativeRef = refKind("initiative");
5410
- var noteRef = refKind("note");
5411
- var taskRef = refKind("task");
5412
- var sessionRef = refKind("session");
5413
- var sourceRef = refKind("source");
5414
- function toRelative(activeRoot, absolutePath) {
5415
- return path48.relative(activeRoot, absolutePath).split(path48.sep).join("/");
5416
- }
5417
- function toAbsolute(activeRoot, relativePath) {
5418
- return path48.join(activeRoot, ...relativePath.split("/"));
5419
- }
5624
+ import { z as z43 } from "zod";
5420
5625
 
5421
5626
  // src/workspace-index/mentions.ts
5422
5627
  var TASK_ID = /(?<![A-Za-z0-9])([A-Za-z][A-Za-z0-9]*-\d+)(?![A-Za-z0-9])/g;
@@ -5437,8 +5642,8 @@ function extractMentions(body, initiative, index) {
5437
5642
  for (const id of matches(body, NOTE_REF)) {
5438
5643
  if (index.noteRefs.has(noteRef(id))) found.add(noteRef(id));
5439
5644
  }
5440
- for (const path67 of matches(body, SOURCE_PATH)) {
5441
- const scoped = `${initiative}/${path67}`;
5645
+ for (const path68 of matches(body, SOURCE_PATH)) {
5646
+ const scoped = `${initiative}/${path68}`;
5442
5647
  if (index.sourcePaths.has(scoped)) found.add(sourceRef(scoped));
5443
5648
  }
5444
5649
  return [...found].sort();
@@ -5775,26 +5980,26 @@ function compact(spans) {
5775
5980
 
5776
5981
  // src/workspace-index/scan.ts
5777
5982
  import { promises as fs42 } from "fs";
5778
- import path55 from "path";
5983
+ import path56 from "path";
5779
5984
 
5780
5985
  // src/lint/index.ts
5781
5986
  import { promises as fs41 } from "fs";
5782
- import path54 from "path";
5987
+ import path55 from "path";
5783
5988
 
5784
5989
  // src/lint/brief.ts
5785
5990
  import { promises as fs37 } from "fs";
5786
- import path49 from "path";
5991
+ import path50 from "path";
5787
5992
 
5788
5993
  // src/lint/hashes.ts
5789
5994
  import { promises as fs38 } from "fs";
5790
- import path50 from "path";
5995
+ import path51 from "path";
5791
5996
  async function lintHashes(slug, initiativeDir) {
5792
5997
  const manifest = await readArtifactHashes(initiativeDir);
5793
5998
  const findings = [];
5794
5999
  for (const [relPath, storedHash] of Object.entries(manifest)) {
5795
6000
  let content;
5796
6001
  try {
5797
- content = await fs38.readFile(path50.join(initiativeDir, relPath), "utf8");
6002
+ content = await fs38.readFile(path51.join(initiativeDir, relPath), "utf8");
5798
6003
  } catch (err) {
5799
6004
  const code = err.code;
5800
6005
  if (code === "ENOENT") continue;
@@ -5812,16 +6017,16 @@ async function lintHashes(slug, initiativeDir) {
5812
6017
  }
5813
6018
 
5814
6019
  // src/lint/open-loops.ts
5815
- import path51 from "path";
6020
+ import path52 from "path";
5816
6021
 
5817
6022
  // src/lint/task.ts
5818
6023
  import { promises as fs39 } from "fs";
5819
- import path52 from "path";
6024
+ import path53 from "path";
5820
6025
  import YAML2 from "yaml";
5821
6026
 
5822
6027
  // src/lint/zero-loops.ts
5823
6028
  import { promises as fs40 } from "fs";
5824
- import path53 from "path";
6029
+ import path54 from "path";
5825
6030
  import YAML3 from "yaml";
5826
6031
 
5827
6032
  // src/lint/index.ts
@@ -5850,21 +6055,21 @@ function isVisible(entry, extensions) {
5850
6055
  }
5851
6056
  async function filesIn(dir, extensions) {
5852
6057
  const entries = await readDirents(dir);
5853
- return entries.filter((entry) => isVisible(entry, extensions)).map((entry) => path55.join(dir, entry.name)).sort();
6058
+ return entries.filter((entry) => isVisible(entry, extensions)).map((entry) => path56.join(dir, entry.name)).sort();
5854
6059
  }
5855
6060
  async function taskFiles(tasksDir) {
5856
6061
  const own = await filesIn(tasksDir, [".yml", ".yaml"]);
5857
- const archive = await filesIn(path55.join(tasksDir, "archive"), [".yml", ".yaml"]);
6062
+ const archive = await filesIn(path56.join(tasksDir, "archive"), [".yml", ".yaml"]);
5858
6063
  return [...own, ...archive];
5859
6064
  }
5860
6065
  async function collectSlug(activeRoot, slug) {
5861
- const dir = path55.join(activeRoot, slug);
5862
- const brief = path55.join(dir, "brief.md");
6066
+ const dir = path56.join(activeRoot, slug);
6067
+ const brief = path56.join(dir, "brief.md");
5863
6068
  const [notes, tasks, sessions2, sources] = await Promise.all([
5864
- filesIn(path55.join(dir, "sources", "notes"), [".md"]),
5865
- taskFiles(path55.join(dir, "tasks")),
5866
- filesIn(path55.join(dir, "sessions"), [".md"]),
5867
- filesIn(path55.join(dir, "sources"), [".md"])
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"])
5868
6073
  ]);
5869
6074
  return [
5870
6075
  ...notes.map((p) => ["note", p]),
@@ -6032,7 +6237,7 @@ function isUnchanged(row, file) {
6032
6237
  }
6033
6238
  var BATCH = 200;
6034
6239
  function describeFailure(err) {
6035
- if (err instanceof z42.ZodError) {
6240
+ if (err instanceof z43.ZodError) {
6036
6241
  return err.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
6037
6242
  }
6038
6243
  return err instanceof Error ? err.message : String(err);
@@ -6274,7 +6479,7 @@ function refreshLockPath() {
6274
6479
  }
6275
6480
  async function withRefreshLock(fn) {
6276
6481
  const target = refreshLockPath();
6277
- await fs44.mkdir(path56.dirname(target), { recursive: true });
6482
+ await fs44.mkdir(path57.dirname(target), { recursive: true });
6278
6483
  await fs44.writeFile(target, "", { flag: "a" });
6279
6484
  const release = await lockfile.lock(target, {
6280
6485
  realpath: false,
@@ -6538,15 +6743,15 @@ async function runDaemon(options = {}) {
6538
6743
  }
6539
6744
 
6540
6745
  // src/commands/mcp-serve.ts
6541
- var ArgsSchema38 = z43.object({
6542
- stdio: z43.boolean().optional(),
6543
- detach: z43.boolean().optional(),
6544
- port: z43.number().int().positive().optional()
6746
+ var ArgsSchema39 = z44.object({
6747
+ stdio: z44.boolean().optional(),
6748
+ detach: z44.boolean().optional(),
6749
+ port: z44.number().int().positive().optional()
6545
6750
  });
6546
- var ResultSchema34 = z43.object({
6547
- mode: z43.enum(["stdio", "http", "detached"]),
6548
- pid: z43.number().optional(),
6549
- port: z43.number().optional()
6751
+ var ResultSchema35 = z44.object({
6752
+ mode: z44.enum(["stdio", "http", "detached"]),
6753
+ pid: z44.number().optional(),
6754
+ port: z44.number().optional()
6550
6755
  });
6551
6756
  function detachedSpawn(port) {
6552
6757
  const entry = process.argv[1];
@@ -6568,8 +6773,8 @@ function detachedSpawn(port) {
6568
6773
  var mcp_serve_default = defineCommand({
6569
6774
  name: "mcp.serve",
6570
6775
  description: "Start the MCP server. --stdio for stdio mode; --detach to fork the HTTP daemon; otherwise runs the HTTP daemon in the foreground.",
6571
- args: ArgsSchema38,
6572
- result: ResultSchema34,
6776
+ args: ArgsSchema39,
6777
+ result: ResultSchema35,
6573
6778
  cli: {
6574
6779
  options: {
6575
6780
  stdio: {
@@ -6601,11 +6806,11 @@ var mcp_serve_default = defineCommand({
6601
6806
  });
6602
6807
 
6603
6808
  // src/commands/mcp-stop.ts
6604
- import { z as z44 } from "zod";
6605
- var ArgsSchema39 = z44.object({});
6606
- var ResultSchema35 = z44.union([
6607
- z44.object({ stopped: z44.literal(true), pid: z44.number() }),
6608
- z44.object({ stopped: z44.literal(false), reason: z44.string() })
6809
+ import { z as z45 } from "zod";
6810
+ var ArgsSchema40 = z45.object({});
6811
+ var ResultSchema36 = z45.union([
6812
+ z45.object({ stopped: z45.literal(true), pid: z45.number() }),
6813
+ z45.object({ stopped: z45.literal(false), reason: z45.string() })
6609
6814
  ]);
6610
6815
  var SHUTDOWN_TIMEOUT_MS = 3e3;
6611
6816
  var POLL_INTERVAL_MS = 100;
@@ -6620,8 +6825,8 @@ async function waitForExit(pid, timeoutMs) {
6620
6825
  var mcp_stop_default = defineCommand({
6621
6826
  name: "mcp.stop",
6622
6827
  description: "Stop the running MCP HTTP daemon (sends SIGTERM, waits for exit).",
6623
- args: ArgsSchema39,
6624
- result: ResultSchema35,
6828
+ args: ArgsSchema40,
6829
+ result: ResultSchema36,
6625
6830
  async run() {
6626
6831
  const pidEntry = await readPidFile();
6627
6832
  if (!pidEntry) {
@@ -6650,13 +6855,13 @@ var mcp_stop_default = defineCommand({
6650
6855
 
6651
6856
  // src/commands/mcp-restart.ts
6652
6857
  import { spawn as spawn4 } from "child_process";
6653
- import { z as z45 } from "zod";
6654
- var ArgsSchema40 = z45.object({
6655
- port: z45.number().int().positive().optional()
6858
+ import { z as z46 } from "zod";
6859
+ var ArgsSchema41 = z46.object({
6860
+ port: z46.number().int().positive().optional()
6656
6861
  });
6657
- var ResultSchema36 = z45.object({
6658
- pid: z45.number(),
6659
- port: z45.number()
6862
+ var ResultSchema37 = z46.object({
6863
+ pid: z46.number(),
6864
+ port: z46.number()
6660
6865
  });
6661
6866
  var SHUTDOWN_TIMEOUT_MS2 = 15e3;
6662
6867
  var KILL_TIMEOUT_MS = 3e3;
@@ -6724,8 +6929,8 @@ async function confirmStarted(pid, port) {
6724
6929
  var mcp_restart_default = defineCommand({
6725
6930
  name: "mcp.restart",
6726
6931
  description: "Restart the MCP HTTP daemon (stop, then spawn a fresh detached instance).",
6727
- args: ArgsSchema40,
6728
- result: ResultSchema36,
6932
+ args: ArgsSchema41,
6933
+ result: ResultSchema37,
6729
6934
  cli: {
6730
6935
  options: {
6731
6936
  port: {
@@ -6744,17 +6949,17 @@ var mcp_restart_default = defineCommand({
6744
6949
  });
6745
6950
 
6746
6951
  // src/commands/mcp-status.ts
6747
- import { z as z46 } from "zod";
6748
- var ArgsSchema41 = z46.object({});
6749
- var ResultSchema37 = z46.object({
6750
- running: z46.boolean(),
6751
- pid: z46.number().optional(),
6752
- port: z46.number().optional(),
6753
- version: z46.string().optional(),
6754
- uptime_ms: z46.number().optional(),
6755
- healthy: z46.boolean().optional(),
6952
+ import { z as z47 } from "zod";
6953
+ var ArgsSchema42 = z47.object({});
6954
+ var ResultSchema38 = z47.object({
6955
+ running: z47.boolean(),
6956
+ pid: z47.number().optional(),
6957
+ port: z47.number().optional(),
6958
+ version: z47.string().optional(),
6959
+ uptime_ms: z47.number().optional(),
6960
+ healthy: z47.boolean().optional(),
6756
6961
  /** Answering `/health` with no PID file naming it — see `removePidFile`. */
6757
- orphaned: z46.boolean().optional()
6962
+ orphaned: z47.boolean().optional()
6758
6963
  });
6759
6964
  async function statusByPort(port) {
6760
6965
  const health = await probeHealth(port);
@@ -6772,8 +6977,8 @@ async function statusByPort(port) {
6772
6977
  var mcp_status_default = defineCommand({
6773
6978
  name: "mcp.status",
6774
6979
  description: "Report the MCP HTTP daemon status (pid, port, version, uptime).",
6775
- args: ArgsSchema41,
6776
- result: ResultSchema37,
6980
+ args: ArgsSchema42,
6981
+ result: ResultSchema38,
6777
6982
  async run() {
6778
6983
  const entry = await readPidFile();
6779
6984
  if (!entry) {
@@ -6806,20 +7011,20 @@ var mcp_status_default = defineCommand({
6806
7011
 
6807
7012
  // src/commands/mcp-logs.ts
6808
7013
  import { promises as fs45 } from "fs";
6809
- import path57 from "path";
6810
- import { z as z47 } from "zod";
6811
- var ArgsSchema42 = z47.object({
6812
- lines: z47.number().int().positive().optional()
7014
+ import path58 from "path";
7015
+ import { z as z48 } from "zod";
7016
+ var ArgsSchema43 = z48.object({
7017
+ lines: z48.number().int().positive().optional()
6813
7018
  });
6814
- var ResultSchema38 = z47.object({
6815
- lines: z47.array(z47.string())
7019
+ var ResultSchema39 = z48.object({
7020
+ lines: z48.array(z48.string())
6816
7021
  });
6817
7022
  var DEFAULT_LINES = 50;
6818
7023
  var mcp_logs_default = defineCommand({
6819
7024
  name: "mcp.logs",
6820
7025
  description: "Return the last N lines of the daemon log (default 50).",
6821
- args: ArgsSchema42,
6822
- result: ResultSchema38,
7026
+ args: ArgsSchema43,
7027
+ result: ResultSchema39,
6823
7028
  cli: {
6824
7029
  options: {
6825
7030
  lines: {
@@ -6830,7 +7035,7 @@ var mcp_logs_default = defineCommand({
6830
7035
  },
6831
7036
  async run(args) {
6832
7037
  const n = args.lines ?? DEFAULT_LINES;
6833
- const logPath = path57.join(getStateRoot(), "daemon.log");
7038
+ const logPath = path58.join(getStateRoot(), "daemon.log");
6834
7039
  let content;
6835
7040
  try {
6836
7041
  content = await fs45.readFile(logPath, "utf8");
@@ -6849,7 +7054,7 @@ var mcp_logs_default = defineCommand({
6849
7054
  });
6850
7055
 
6851
7056
  // src/commands/miner-drain-ingest.ts
6852
- import { z as z51 } from "zod";
7057
+ import { z as z52 } from "zod";
6853
7058
 
6854
7059
  // src/drain/transcript-reader.ts
6855
7060
  import { nextOffset, prefixHash, readJsonLines, resumePoint } from "@titan-design/locator";
@@ -6860,40 +7065,40 @@ import { Clusterer } from "@titan-design/cluster";
6860
7065
 
6861
7066
  // src/drain/store.ts
6862
7067
  import { promises as fs46 } from "fs";
6863
- import path58 from "path";
7068
+ import path59 from "path";
6864
7069
 
6865
7070
  // src/schemas/template.ts
6866
- import { z as z48 } from "zod";
6867
- var LocatorSchema = z48.tuple([
6868
- z48.number().int().nonnegative(),
6869
- z48.number().int().nonnegative(),
6870
- z48.number().int().positive()
7071
+ import { z as z49 } from "zod";
7072
+ var LocatorSchema = z49.tuple([
7073
+ z49.number().int().nonnegative(),
7074
+ z49.number().int().nonnegative(),
7075
+ z49.number().int().positive()
6871
7076
  ]);
6872
- var TemplateSchema = z48.object({
6873
- templateId: z48.string().min(1),
6874
- toolType: z48.string().min(1),
6875
- maskedSignature: z48.string().min(1),
6876
- createdAt: z48.string().min(1),
6877
- occurrenceCount: z48.number().int().nonnegative(),
7077
+ var TemplateSchema = z49.object({
7078
+ templateId: z49.string().min(1),
7079
+ toolType: z49.string().min(1),
7080
+ maskedSignature: z49.string().min(1),
7081
+ createdAt: z49.string().min(1),
7082
+ occurrenceCount: z49.number().int().nonnegative(),
6878
7083
  exemplarLocator: LocatorSchema
6879
7084
  });
6880
- var OccurrenceSchema = z48.object({
6881
- templateId: z48.string().min(1),
7085
+ var OccurrenceSchema = z49.object({
7086
+ templateId: z49.string().min(1),
6882
7087
  locator: LocatorSchema,
6883
- sessionId: z48.string().min(1),
6884
- timestamp: z48.string().min(1),
6885
- extractedParams: z48.record(z48.string(), z48.string()).optional()
7088
+ sessionId: z49.string().min(1),
7089
+ timestamp: z49.string().min(1),
7090
+ extractedParams: z49.record(z49.string(), z49.string()).optional()
6886
7091
  });
6887
- var TemplatesFileSchema = z48.object({
6888
- templates: z48.array(TemplateSchema).default([])
7092
+ var TemplatesFileSchema = z49.object({
7093
+ templates: z49.array(TemplateSchema).default([])
6889
7094
  });
6890
7095
 
6891
7096
  // src/drain/store.ts
6892
7097
  function templatesPath(root) {
6893
- return path58.join(root, "templates.yml");
7098
+ return path59.join(root, "templates.yml");
6894
7099
  }
6895
7100
  function occurrencesPath(root) {
6896
- return path58.join(root, "occurrences.jsonl");
7101
+ return path59.join(root, "occurrences.jsonl");
6897
7102
  }
6898
7103
  async function loadTemplates(root = getMinerRoot()) {
6899
7104
  try {
@@ -6931,31 +7136,31 @@ async function appendOccurrences(occurrences, root = getMinerRoot()) {
6931
7136
 
6932
7137
  // src/drain/tree-store.ts
6933
7138
  import { promises as fs47 } from "fs";
6934
- import path59 from "path";
6935
- import { z as z49 } from "zod";
6936
- var PartitionSchema = z49.object({
6937
- partition: z49.string().min(1),
6938
- nextClusterId: z49.number().int().positive(),
6939
- clusters: z49.array(
6940
- z49.object({
6941
- clusterId: z49.number().int().positive(),
6942
- tokens: z49.array(z49.string()),
6943
- size: z49.number().int().nonnegative()
7139
+ import path60 from "path";
7140
+ import { z as z50 } from "zod";
7141
+ var PartitionSchema = z50.object({
7142
+ partition: z50.string().min(1),
7143
+ nextClusterId: z50.number().int().positive(),
7144
+ clusters: z50.array(
7145
+ z50.object({
7146
+ clusterId: z50.number().int().positive(),
7147
+ tokens: z50.array(z50.string()),
7148
+ size: z50.number().int().nonnegative()
6944
7149
  })
6945
7150
  ),
6946
7151
  /** `clusterId -> templateId`, as pairs so the file has a stable order. */
6947
- templateIds: z49.array(z49.tuple([z49.number().int().positive(), z49.string().min(1)]))
7152
+ templateIds: z50.array(z50.tuple([z50.number().int().positive(), z50.string().min(1)]))
6948
7153
  });
6949
- var TreeSnapshotFileSchema = z49.object({
6950
- version: z49.literal(1).default(1),
6951
- partitions: z49.array(PartitionSchema).default([])
7154
+ var TreeSnapshotFileSchema = z50.object({
7155
+ version: z50.literal(1).default(1),
7156
+ partitions: z50.array(PartitionSchema).default([])
6952
7157
  });
6953
- var LegacySnapshotFileSchema = z49.object({
6954
- version: z49.literal(1),
6955
- trees: z49.array(PartitionSchema.omit({ partition: true }).extend({ toolType: z49.string().min(1) }))
7158
+ var LegacySnapshotFileSchema = z50.object({
7159
+ version: z50.literal(1),
7160
+ trees: z50.array(PartitionSchema.omit({ partition: true }).extend({ toolType: z50.string().min(1) }))
6956
7161
  });
6957
7162
  function snapshotPath(root) {
6958
- return path59.join(root, "drain-trees.json");
7163
+ return path60.join(root, "drain-trees.json");
6959
7164
  }
6960
7165
  function empty() {
6961
7166
  return { version: 1, partitions: [] };
@@ -7134,28 +7339,28 @@ function extractBlobs(line, toolNames) {
7134
7339
 
7135
7340
  // src/drain/reader-state.ts
7136
7341
  import { promises as fs48 } from "fs";
7137
- import path60 from "path";
7138
- import { z as z50 } from "zod";
7139
- var TranscriptStateSchema = z50.object({
7342
+ import path61 from "path";
7343
+ import { z as z51 } from "zod";
7344
+ var TranscriptStateSchema = z51.object({
7140
7345
  /** `~`-relative path, matching `session-index/discover.ts`'s display form. */
7141
- path: z50.string().min(1),
7142
- lastByteOffset: z50.number().int().nonnegative().default(0),
7346
+ path: z51.string().min(1),
7347
+ lastByteOffset: z51.number().int().nonnegative().default(0),
7143
7348
  /** sha256 of bytes `[0, lastByteOffset)`; detects rewrite vs. append. */
7144
- prefixHash: z50.string().nullable().default(null),
7349
+ prefixHash: z51.string().nullable().default(null),
7145
7350
  /**
7146
7351
  * `tool_use_id -> tool name` pairs seen but not yet consumed by a result.
7147
7352
  * Persisted because a chunk boundary routinely falls between an assistant's
7148
7353
  * `tool_use` and the user line carrying its result.
7149
7354
  */
7150
- pendingToolNames: z50.record(z50.string(), z50.string()).default({})
7355
+ pendingToolNames: z51.record(z51.string(), z51.string()).default({})
7151
7356
  });
7152
- var ReaderStateSchema = z50.object({
7153
- version: z50.literal(1).default(1),
7154
- transcripts: z50.array(TranscriptStateSchema).default([])
7357
+ var ReaderStateSchema = z51.object({
7358
+ version: z51.literal(1).default(1),
7359
+ transcripts: z51.array(TranscriptStateSchema).default([])
7155
7360
  });
7156
7361
  var MAX_PENDING_TOOL_NAMES = 256;
7157
7362
  function readerStatePath(root = getMinerRoot()) {
7158
- return path60.join(root, "reader-state.json");
7363
+ return path61.join(root, "reader-state.json");
7159
7364
  }
7160
7365
  async function loadReaderState(root = getMinerRoot()) {
7161
7366
  try {
@@ -7322,33 +7527,33 @@ async function runDrainIngest(options = {}) {
7322
7527
  }
7323
7528
 
7324
7529
  // src/commands/miner-drain-ingest.ts
7325
- var ArgsSchema43 = z51.object({
7326
- full: z51.boolean().optional(),
7327
- limit: z51.coerce.number().int().positive().optional(),
7328
- verify_hashes: z51.boolean().optional()
7329
- });
7330
- var ResultSchema39 = z51.object({
7331
- startedAt: z51.string(),
7332
- durationMs: z51.number(),
7333
- transcripts: z51.number(),
7334
- scanned: z51.number(),
7335
- unchanged: z51.number(),
7336
- rewound: z51.number(),
7337
- linesRead: z51.number(),
7338
- malformedLines: z51.number(),
7339
- blobs: z51.number(),
7340
- ingested: z51.number(),
7341
- newTemplates: z51.number(),
7342
- templates: z51.number(),
7343
- evicting: z51.boolean(),
7344
- curve: z51.array(z51.object({ blobs: z51.number(), templates: z51.number(), evicting: z51.boolean() })),
7345
- errors: z51.array(z51.string())
7530
+ var ArgsSchema44 = z52.object({
7531
+ full: z52.boolean().optional(),
7532
+ limit: z52.coerce.number().int().positive().optional(),
7533
+ verify_hashes: z52.boolean().optional()
7534
+ });
7535
+ var ResultSchema40 = z52.object({
7536
+ startedAt: z52.string(),
7537
+ durationMs: z52.number(),
7538
+ transcripts: z52.number(),
7539
+ scanned: z52.number(),
7540
+ unchanged: z52.number(),
7541
+ rewound: z52.number(),
7542
+ linesRead: z52.number(),
7543
+ malformedLines: z52.number(),
7544
+ blobs: z52.number(),
7545
+ ingested: z52.number(),
7546
+ newTemplates: z52.number(),
7547
+ templates: z52.number(),
7548
+ evicting: z52.boolean(),
7549
+ curve: z52.array(z52.object({ blobs: z52.number(), templates: z52.number(), evicting: z52.boolean() })),
7550
+ errors: z52.array(z52.string())
7346
7551
  });
7347
7552
  var miner_drain_ingest_default = defineCommand({
7348
7553
  name: "miner.drain-ingest",
7349
7554
  description: "Cluster new tool-result/error blobs from Claude transcripts into the template store.",
7350
- args: ArgsSchema43,
7351
- result: ResultSchema39,
7555
+ args: ArgsSchema44,
7556
+ result: ResultSchema40,
7352
7557
  cli: {
7353
7558
  options: {
7354
7559
  full: {
@@ -7375,52 +7580,52 @@ var miner_drain_ingest_default = defineCommand({
7375
7580
  });
7376
7581
 
7377
7582
  // src/commands/miner-refresh.ts
7378
- import { z as z52 } from "zod";
7379
- var ArgsSchema44 = z52.object({
7380
- full: z52.boolean().optional(),
7381
- limit: z52.coerce.number().int().positive().optional(),
7382
- verify_hashes: z52.boolean().optional()
7383
- });
7384
- var WorkspaceSchema = z52.object({
7385
- files: z52.number(),
7386
- indexed: z52.number(),
7387
- unchanged: z52.number(),
7388
- removed: z52.number(),
7389
- malformed: z52.array(z52.object({ path: z52.string(), reason: z52.string() })),
7390
- rows: z52.object({
7391
- initiative: z52.number(),
7392
- note: z52.number(),
7393
- task: z52.number(),
7394
- session: z52.number(),
7395
- source: z52.number()
7583
+ import { z as z53 } from "zod";
7584
+ var ArgsSchema45 = z53.object({
7585
+ full: z53.boolean().optional(),
7586
+ limit: z53.coerce.number().int().positive().optional(),
7587
+ verify_hashes: z53.boolean().optional()
7588
+ });
7589
+ var WorkspaceSchema = z53.object({
7590
+ files: z53.number(),
7591
+ indexed: z53.number(),
7592
+ unchanged: z53.number(),
7593
+ removed: z53.number(),
7594
+ malformed: z53.array(z53.object({ path: z53.string(), reason: z53.string() })),
7595
+ rows: z53.object({
7596
+ initiative: z53.number(),
7597
+ note: z53.number(),
7598
+ task: z53.number(),
7599
+ session: z53.number(),
7600
+ source: z53.number()
7396
7601
  }),
7397
- edges: z52.object({ holds: z52.number(), mentions: z52.number(), sharesTag: z52.number() }),
7398
- orphanRatio: z52.number()
7602
+ edges: z53.object({ holds: z53.number(), mentions: z53.number(), sharesTag: z53.number() }),
7603
+ orphanRatio: z53.number()
7399
7604
  });
7400
- var ResultSchema40 = z52.object({
7401
- startedAt: z52.string(),
7402
- durationMs: z52.number(),
7403
- transcripts: z52.number(),
7404
- scanned: z52.number(),
7405
- indexed: z52.number(),
7406
- rewound: z52.number(),
7407
- unchanged: z52.number(),
7408
- quarantined: z52.number(),
7409
- missing: z52.number(),
7410
- reconciledMissing: z52.number(),
7411
- factsAdded: z52.number(),
7412
- turnsRolledUp: z52.number(),
7413
- tasksRequested: z52.number(),
7414
- tasksApplied: z52.number(),
7605
+ var ResultSchema41 = z53.object({
7606
+ startedAt: z53.string(),
7607
+ durationMs: z53.number(),
7608
+ transcripts: z53.number(),
7609
+ scanned: z53.number(),
7610
+ indexed: z53.number(),
7611
+ rewound: z53.number(),
7612
+ unchanged: z53.number(),
7613
+ quarantined: z53.number(),
7614
+ missing: z53.number(),
7615
+ reconciledMissing: z53.number(),
7616
+ factsAdded: z53.number(),
7617
+ turnsRolledUp: z53.number(),
7618
+ tasksRequested: z53.number(),
7619
+ tasksApplied: z53.number(),
7415
7620
  workspace: WorkspaceSchema.nullable(),
7416
- preserved: z52.object({ restored: z52.number(), merged: z52.number(), skipped: z52.number() }),
7417
- errors: z52.array(z52.string())
7621
+ preserved: z53.object({ restored: z53.number(), merged: z53.number(), skipped: z53.number() }),
7622
+ errors: z53.array(z53.string())
7418
7623
  });
7419
7624
  var miner_refresh_default = defineCommand({
7420
7625
  name: "miner.refresh",
7421
7626
  description: "Index new Claude session transcripts into the session-signal index.",
7422
- args: ArgsSchema44,
7423
- result: ResultSchema40,
7627
+ args: ArgsSchema45,
7628
+ result: ResultSchema41,
7424
7629
  cli: {
7425
7630
  options: {
7426
7631
  full: {
@@ -7446,7 +7651,7 @@ var miner_refresh_default = defineCommand({
7446
7651
 
7447
7652
  // src/commands/miner-liveness.ts
7448
7653
  import { existsSync as existsSync3 } from "fs";
7449
- import { z as z53 } from "zod";
7654
+ import { z as z54 } from "zod";
7450
7655
 
7451
7656
  // src/session-index/liveness.ts
7452
7657
  import { existsSync as existsSync2 } from "fs";
@@ -7563,22 +7768,22 @@ function runLiveness(db) {
7563
7768
  }
7564
7769
 
7565
7770
  // src/commands/miner-liveness.ts
7566
- var ArgsSchema45 = z53.object({});
7567
- var ResultSchema41 = z53.object({
7568
- emptyColumns: z53.array(
7569
- z53.object({ table: z53.string(), column: z53.string(), rows: z53.number(), nonNull: z53.number() })
7771
+ var ArgsSchema46 = z54.object({});
7772
+ var ResultSchema42 = z54.object({
7773
+ emptyColumns: z54.array(
7774
+ z54.object({ table: z54.string(), column: z54.string(), rows: z54.number(), nonNull: z54.number() })
7570
7775
  ),
7571
- unusedRelations: z53.array(z53.string()),
7572
- undeclaredRelations: z53.array(z53.string()),
7573
- danglingNamespaces: z53.array(
7574
- z53.object({ namespace: z53.string(), edges: z53.number(), dangling: z53.number() })
7776
+ unusedRelations: z54.array(z54.string()),
7777
+ undeclaredRelations: z54.array(z54.string()),
7778
+ danglingNamespaces: z54.array(
7779
+ z54.object({ namespace: z54.string(), edges: z54.number(), dangling: z54.number() })
7575
7780
  ),
7576
- unmappedNamespaces: z53.array(z53.string()),
7577
- expectedEmptyColumns: z53.array(
7578
- z53.object({ table: z53.string(), column: z53.string(), reason: z53.string() })
7781
+ unmappedNamespaces: z54.array(z54.string()),
7782
+ expectedEmptyColumns: z54.array(
7783
+ z54.object({ table: z54.string(), column: z54.string(), reason: z54.string() })
7579
7784
  ),
7580
- staleTranscripts: z53.number(),
7581
- transcripts: z53.number()
7785
+ staleTranscripts: z54.number(),
7786
+ transcripts: z54.number()
7582
7787
  });
7583
7788
  function report(result) {
7584
7789
  const lines = [color.bold("active-work miner liveness")];
@@ -7630,8 +7835,8 @@ function report(result) {
7630
7835
  var miner_liveness_default = defineCommand({
7631
7836
  name: "miner.liveness",
7632
7837
  description: "Report which declared index structures nothing ever populates: empty columns, unused edge relations, dangling refs, stale transcripts.",
7633
- args: ArgsSchema45,
7634
- result: ResultSchema41,
7838
+ args: ArgsSchema46,
7839
+ result: ResultSchema42,
7635
7840
  cli: { usage: "active-work miner liveness" },
7636
7841
  async run(_args, ctx) {
7637
7842
  const dbPath = defaultGraphPath();
@@ -7669,40 +7874,40 @@ var miner_liveness_default = defineCommand({
7669
7874
 
7670
7875
  // src/commands/miner-status.ts
7671
7876
  import { existsSync as existsSync4, statSync } from "fs";
7672
- import { z as z54 } from "zod";
7673
- var ArgsSchema46 = z54.object({});
7674
- var ResultSchema42 = z54.object({
7675
- dbPath: z54.string(),
7676
- schemaVersion: z54.number(),
7677
- sizeBytes: z54.number(),
7678
- counts: z54.object({
7679
- transcripts: z54.number(),
7680
- sessions: z54.number(),
7681
- facts: z54.number(),
7682
- turns: z54.number(),
7683
- edges: z54.number(),
7684
- spans: z54.number()
7877
+ import { z as z55 } from "zod";
7878
+ var ArgsSchema47 = z55.object({});
7879
+ var ResultSchema43 = z55.object({
7880
+ dbPath: z55.string(),
7881
+ schemaVersion: z55.number(),
7882
+ sizeBytes: z55.number(),
7883
+ counts: z55.object({
7884
+ transcripts: z55.number(),
7885
+ sessions: z55.number(),
7886
+ facts: z55.number(),
7887
+ turns: z55.number(),
7888
+ edges: z55.number(),
7889
+ spans: z55.number()
7685
7890
  }),
7686
- transcripts: z54.object({
7687
- ok: z54.number(),
7688
- quarantined: z54.number(),
7689
- missing: z54.number()
7891
+ transcripts: z55.object({
7892
+ ok: z55.number(),
7893
+ quarantined: z55.number(),
7894
+ missing: z55.number()
7690
7895
  }),
7691
- watermark: z54.object({
7692
- lastIndexedAt: z54.string().nullable(),
7693
- behindBytes: z54.number()
7896
+ watermark: z55.object({
7897
+ lastIndexedAt: z55.string().nullable(),
7898
+ behindBytes: z55.number()
7694
7899
  }),
7695
- fts: z54.object({
7696
- rows: z54.number(),
7697
- orphanRows: z54.number(),
7698
- needsFullRebuild: z54.boolean()
7900
+ fts: z55.object({
7901
+ rows: z55.number(),
7902
+ orphanRows: z55.number(),
7903
+ needsFullRebuild: z55.boolean()
7699
7904
  }),
7700
- daemon: z54.object({
7701
- indexing: z54.boolean(),
7702
- pending: z54.boolean(),
7703
- lastRunAt: z54.string().nullable(),
7704
- lastDurationMs: z54.number().nullable(),
7705
- consecutiveErrors: z54.number()
7905
+ daemon: z55.object({
7906
+ indexing: z55.boolean(),
7907
+ pending: z55.boolean(),
7908
+ lastRunAt: z55.string().nullable(),
7909
+ lastDurationMs: z55.number().nullable(),
7910
+ consecutiveErrors: z55.number()
7706
7911
  }).nullable()
7707
7912
  });
7708
7913
  var ORPHAN_WARN_RATIO = 0.2;
@@ -7743,8 +7948,8 @@ async function emptyStatus(dbPath) {
7743
7948
  var miner_status_default = defineCommand({
7744
7949
  name: "miner.status",
7745
7950
  description: "Report session-signal index size, freshness, and daemon indexing state.",
7746
- args: ArgsSchema46,
7747
- result: ResultSchema42,
7951
+ args: ArgsSchema47,
7952
+ result: ResultSchema43,
7748
7953
  async run() {
7749
7954
  const dbPath = defaultGraphPath();
7750
7955
  if (!existsSync4(dbPath)) return emptyStatus(dbPath);
@@ -7786,7 +7991,7 @@ var miner_status_default = defineCommand({
7786
7991
  });
7787
7992
 
7788
7993
  // src/commands/hooks-agent-chat-spawn.ts
7789
- import { z as z56 } from "zod";
7994
+ import { z as z57 } from "zod";
7790
7995
 
7791
7996
  // src/utils/read-stdin-json.ts
7792
7997
  async function readStdinJson(stream = process.stdin) {
@@ -7806,13 +8011,13 @@ async function readStdinJson(stream = process.stdin) {
7806
8011
 
7807
8012
  // src/utils/agent-chat-hook-state.ts
7808
8013
  import { promises as fs49 } from "fs";
7809
- import path61 from "path";
7810
- import { z as z55 } from "zod";
7811
- var SpawnContextSchema = z55.object({
7812
- slug: z55.string().min(1),
7813
- sessionId: z55.string().min(1),
7814
- name: z55.string(),
7815
- started: z55.string(),
8014
+ import path62 from "path";
8015
+ import { z as z56 } from "zod";
8016
+ var SpawnContextSchema = z56.object({
8017
+ slug: z56.string().min(1),
8018
+ sessionId: z56.string().min(1),
8019
+ name: z56.string(),
8020
+ started: z56.string(),
7816
8021
  /**
7817
8022
  * The spawning session, already resolved from the payload's `parent`
7818
8023
  * agentId to a session id. Resolved at spawn time on purpose: `parent` names
@@ -7820,16 +8025,16 @@ var SpawnContextSchema = z55.object({
7820
8025
  * another live entry in this same directory — which is gone by the time
7821
8026
  * on_complete runs, because reading one deletes it.
7822
8027
  */
7823
- parentSessionId: z55.string().min(1).nullable().default(null),
8028
+ parentSessionId: z56.string().min(1).nullable().default(null),
7824
8029
  /** agent-chat profile and briefing slug, for the recorded session's prose. */
7825
- profile: z55.string().nullable().default(null),
7826
- briefing: z55.string().nullable().default(null)
8030
+ profile: z56.string().nullable().default(null),
8031
+ briefing: z56.string().nullable().default(null)
7827
8032
  });
7828
8033
  function stateDir() {
7829
- return path61.join(getStateRoot(), "agent-chat-hooks");
8034
+ return path62.join(getStateRoot(), "agent-chat-hooks");
7830
8035
  }
7831
8036
  function stateFile(agentId) {
7832
- return path61.join(stateDir(), `${agentId}.json`);
8037
+ return path62.join(stateDir(), `${agentId}.json`);
7833
8038
  }
7834
8039
  async function stashSpawnContext(agentId, context) {
7835
8040
  await fs49.mkdir(stateDir(), { recursive: true });
@@ -7855,10 +8060,10 @@ async function peekSpawnContext(agentId) {
7855
8060
  }
7856
8061
 
7857
8062
  // src/commands/hooks-agent-chat-spawn.ts
7858
- var ArgsSchema47 = z56.object({});
7859
- var ResultSchema43 = z56.object({
7860
- matched: z56.boolean(),
7861
- slug: z56.string().nullable()
8063
+ var ArgsSchema48 = z57.object({});
8064
+ var ResultSchema44 = z57.object({
8065
+ matched: z57.boolean(),
8066
+ slug: z57.string().nullable()
7862
8067
  });
7863
8068
  function str2(source, key) {
7864
8069
  const value = source?.[key];
@@ -7887,8 +8092,8 @@ async function handleOnSpawn(payload, activeRoot) {
7887
8092
  var hooks_agent_chat_spawn_default = defineCommand({
7888
8093
  name: "hooks.agent-chat-spawn",
7889
8094
  description: "agent-chat on_spawn hook consumer (AW-99): stash a spawned peer's context, keyed by agentId, for the matching on_complete call.",
7890
- args: ArgsSchema47,
7891
- result: ResultSchema43,
8095
+ args: ArgsSchema48,
8096
+ result: ResultSchema44,
7892
8097
  cli: {
7893
8098
  usage: "active-work hooks agent-chat-spawn (reads the on_spawn JSON payload from stdin)"
7894
8099
  },
@@ -7900,11 +8105,11 @@ var hooks_agent_chat_spawn_default = defineCommand({
7900
8105
 
7901
8106
  // src/commands/hooks-agent-chat-complete.ts
7902
8107
  import { spawn as spawn5 } from "child_process";
7903
- import { z as z57 } from "zod";
7904
- var ArgsSchema48 = z57.object({});
7905
- var ResultSchema44 = z57.object({
7906
- recorded: z57.boolean(),
7907
- slug: z57.string().nullable()
8108
+ import { z as z58 } from "zod";
8109
+ var ArgsSchema49 = z58.object({});
8110
+ var ResultSchema45 = z58.object({
8111
+ recorded: z58.boolean(),
8112
+ slug: z58.string().nullable()
7908
8113
  });
7909
8114
  function str3(source, key) {
7910
8115
  const value = source?.[key];
@@ -7971,8 +8176,8 @@ async function handleOnComplete(payload) {
7971
8176
  var hooks_agent_chat_complete_default = defineCommand({
7972
8177
  name: "hooks.agent-chat-complete",
7973
8178
  description: "agent-chat on_complete hook consumer (AW-99): record a spawned peer's run as a track:adhoc session via wrap.",
7974
- args: ArgsSchema48,
7975
- result: ResultSchema44,
8179
+ args: ArgsSchema49,
8180
+ result: ResultSchema45,
7976
8181
  cli: {
7977
8182
  usage: "active-work hooks agent-chat-complete (reads the on_complete JSON payload from stdin)"
7978
8183
  },
@@ -7983,7 +8188,7 @@ var hooks_agent_chat_complete_default = defineCommand({
7983
8188
  });
7984
8189
 
7985
8190
  // src/commands/setup.ts
7986
- import { z as z59 } from "zod";
8191
+ import { z as z60 } from "zod";
7987
8192
 
7988
8193
  // src/setup/steps.ts
7989
8194
  import { promises as fsp3, existsSync as existsSync5 } from "fs";
@@ -7999,7 +8204,7 @@ import { join } from "path";
7999
8204
 
8000
8205
  // src/migrations/v1-to-v2-artifacts.ts
8001
8206
  import { promises as fs50 } from "fs";
8002
- import path62 from "path";
8207
+ import path63 from "path";
8003
8208
  import YAML4 from "yaml";
8004
8209
  function asArray(value) {
8005
8210
  return Array.isArray(value) ? value : [];
@@ -8059,7 +8264,7 @@ async function walkArtifactsFiles(activeRoot) {
8059
8264
  for (const entry of entries) {
8060
8265
  if (!entry.isDirectory()) continue;
8061
8266
  if (entry.name.startsWith(".")) continue;
8062
- const candidate = path62.join(activeRoot, entry.name, "artifacts.yml");
8267
+ const candidate = path63.join(activeRoot, entry.name, "artifacts.yml");
8063
8268
  try {
8064
8269
  await fs50.access(candidate);
8065
8270
  out.push(candidate);
@@ -8068,14 +8273,14 @@ async function walkArtifactsFiles(activeRoot) {
8068
8273
  }
8069
8274
  } catch {
8070
8275
  }
8071
- const archiveRoot = path62.resolve(activeRoot, "..");
8276
+ const archiveRoot = path63.resolve(activeRoot, "..");
8072
8277
  try {
8073
8278
  const domains = await fs50.readdir(archiveRoot, { withFileTypes: true });
8074
8279
  for (const domain of domains) {
8075
8280
  if (!domain.isDirectory()) continue;
8076
8281
  if (domain.name.startsWith(".")) continue;
8077
- if (path62.join(archiveRoot, domain.name) === path62.resolve(activeRoot)) continue;
8078
- const archiveDir = path62.join(archiveRoot, domain.name, "archive");
8282
+ if (path63.join(archiveRoot, domain.name) === path63.resolve(activeRoot)) continue;
8283
+ const archiveDir = path63.join(archiveRoot, domain.name, "archive");
8079
8284
  let archived;
8080
8285
  try {
8081
8286
  archived = await fs50.readdir(archiveDir, { withFileTypes: true });
@@ -8084,7 +8289,7 @@ async function walkArtifactsFiles(activeRoot) {
8084
8289
  }
8085
8290
  for (const entry of archived) {
8086
8291
  if (!entry.isDirectory()) continue;
8087
- const candidate = path62.join(archiveDir, entry.name, "artifacts.yml");
8292
+ const candidate = path63.join(archiveDir, entry.name, "artifacts.yml");
8088
8293
  try {
8089
8294
  await fs50.access(candidate);
8090
8295
  out.push(candidate);
@@ -8098,7 +8303,7 @@ async function walkArtifactsFiles(activeRoot) {
8098
8303
  }
8099
8304
  async function appendMigrationLog(activeRoot, lines) {
8100
8305
  if (lines.length === 0) return;
8101
- const logPath = path62.join(activeRoot, ".migrations.log");
8306
+ const logPath = path63.join(activeRoot, ".migrations.log");
8102
8307
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
8103
8308
  const body = lines.map((l) => `${stamp} v1->v2 ${l}
8104
8309
  `).join("");
@@ -8130,11 +8335,11 @@ var v1ToV2Artifacts = {
8130
8335
 
8131
8336
  // src/migrations/v2-to-v3-open-loops.ts
8132
8337
  import { promises as fs53 } from "fs";
8133
- import path64 from "path";
8338
+ import path65 from "path";
8134
8339
 
8135
8340
  // src/migrations/v3-proposal.ts
8136
8341
  import { promises as fs51 } from "fs";
8137
- import { z as z58 } from "zod";
8342
+ import { z as z59 } from "zod";
8138
8343
 
8139
8344
  // src/migrations/data/v3-open-loops-proposal.ts
8140
8345
  var V3_OPEN_LOOPS_PROPOSAL = {
@@ -8930,36 +9135,36 @@ var KEBAB_SESSION_ID = SessionIdSchema.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
8930
9135
  message: "session_id must be kebab-case ([a-z0-9-], no leading/trailing dash)"
8931
9136
  });
8932
9137
  var ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
8933
- var AbandonedSchema = z58.object({ note: z58.string().min(1) });
9138
+ var AbandonedSchema = z59.object({ note: z59.string().min(1) });
8934
9139
  var ProposalNextStepSchema = NextStepSchema.extend({
8935
9140
  abandoned: AbandonedSchema.optional()
8936
9141
  });
8937
- var ProposalInitiativeSchema = z58.object({
8938
- slug: z58.string().min(1),
9142
+ var ProposalInitiativeSchema = z59.object({
9143
+ slug: z59.string().min(1),
8939
9144
  /**
8940
9145
  * Real last-touch of the initiative, hand-supplied. Never `Date.now()` and
8941
9146
  * never file mtime — several initiatives have mtimes months adrift from
8942
9147
  * their true last-touch, and the whole point of back-dating is to preserve
8943
9148
  * the staleness signal.
8944
9149
  */
8945
- ended: z58.string().regex(ISO_INSTANT, {
9150
+ ended: z59.string().regex(ISO_INSTANT, {
8946
9151
  message: "ended must be an ISO 8601 instant with timezone"
8947
9152
  }),
8948
9153
  session_id: KEBAB_SESSION_ID,
8949
- body: z58.string().min(1),
8950
- next_steps: z58.array(ProposalNextStepSchema).default([])
9154
+ body: z59.string().min(1),
9155
+ next_steps: z59.array(ProposalNextStepSchema).default([])
8951
9156
  });
8952
- var ProposalSchema = z58.object({
9157
+ var ProposalSchema = z59.object({
8953
9158
  /**
8954
9159
  * When the abandonment decision was made. Hand-supplied rather than read
8955
9160
  * from the clock: the second session's filename derives from it, and the
8956
9161
  * migration keys idempotence on exact paths, so `Date.now()` would mint a
8957
9162
  * fresh path — and a duplicate abandonment session — on every re-run.
8958
9163
  */
8959
- abandoned_at: z58.string().regex(ISO_INSTANT, {
9164
+ abandoned_at: z59.string().regex(ISO_INSTANT, {
8960
9165
  message: "abandoned_at must be an ISO 8601 instant with timezone"
8961
9166
  }).optional(),
8962
- initiatives: z58.array(ProposalInitiativeSchema)
9167
+ initiatives: z59.array(ProposalInitiativeSchema)
8963
9168
  }).superRefine((value, ctx) => {
8964
9169
  const withAbandoned = value.initiatives.filter(
8965
9170
  (i) => i.next_steps.some((n) => n.abandoned !== void 0)
@@ -9030,17 +9235,17 @@ async function loadProposal() {
9030
9235
 
9031
9236
  // src/migrations/v3-repairs.ts
9032
9237
  import { promises as fs52 } from "fs";
9033
- import path63 from "path";
9238
+ import path64 from "path";
9034
9239
  var KNOWN_REPAIRS = [
9035
9240
  {
9036
- file: path63.join("audiobook", "sessions", "2026-07-23-0549-2026-07-26-book1-m4b-packaging.md"),
9241
+ file: path64.join("audiobook", "sessions", "2026-07-23-0549-2026-07-26-book1-m4b-packaging.md"),
9037
9242
  kind: "retrack",
9038
9243
  why: "track is a branch name ('feat/tts-quality'), not one of canonical|sidecar|adhoc"
9039
9244
  },
9040
9245
  {
9041
- file: path63.join("voltras-workspace", "sessions", "ARCHIVED-handoff-through-2026-07-15.md"),
9246
+ file: path64.join("voltras-workspace", "sessions", "ARCHIVED-handoff-through-2026-07-15.md"),
9042
9247
  kind: "relocate",
9043
- target: path63.join("voltras-workspace", "sources", "ARCHIVED-handoff-through-2026-07-15.md"),
9248
+ target: path64.join("voltras-workspace", "sources", "ARCHIVED-handoff-through-2026-07-15.md"),
9044
9249
  why: "not a session file \u2014 a hand-archived handoff parked in sessions/"
9045
9250
  }
9046
9251
  ];
@@ -9099,7 +9304,7 @@ async function exists3(p) {
9099
9304
  async function planRepairs(activeRoot) {
9100
9305
  const plans = [];
9101
9306
  for (const repair of KNOWN_REPAIRS) {
9102
- const fullPath = path63.join(activeRoot, repair.file);
9307
+ const fullPath = path64.join(activeRoot, repair.file);
9103
9308
  if (!await exists3(fullPath)) {
9104
9309
  plans.push({ action: "skip", file: repair.file, detail: "already absent" });
9105
9310
  continue;
@@ -9109,7 +9314,7 @@ async function planRepairs(activeRoot) {
9109
9314
  continue;
9110
9315
  }
9111
9316
  const target = repair.target;
9112
- if (await exists3(path63.join(activeRoot, target))) {
9317
+ if (await exists3(path64.join(activeRoot, target))) {
9113
9318
  plans.push({
9114
9319
  action: "skip",
9115
9320
  file: repair.file,
@@ -9123,7 +9328,7 @@ async function planRepairs(activeRoot) {
9123
9328
  return plans;
9124
9329
  }
9125
9330
  async function applyRepair(activeRoot, plan) {
9126
- const fullPath = path63.join(activeRoot, plan.file);
9331
+ const fullPath = path64.join(activeRoot, plan.file);
9127
9332
  if (plan.action === "retrack" && plan.repaired !== void 0) {
9128
9333
  await writeFrontmatter(
9129
9334
  fullPath,
@@ -9134,15 +9339,15 @@ async function applyRepair(activeRoot, plan) {
9134
9339
  return;
9135
9340
  }
9136
9341
  if (plan.action === "relocate") {
9137
- const target = path63.join(activeRoot, plan.target);
9138
- await fs52.mkdir(path63.dirname(target), { recursive: true });
9342
+ const target = path64.join(activeRoot, plan.target);
9343
+ await fs52.mkdir(path64.dirname(target), { recursive: true });
9139
9344
  await fs52.rename(fullPath, target);
9140
9345
  }
9141
9346
  }
9142
9347
 
9143
9348
  // src/migrations/v2-to-v3-open-loops.ts
9144
9349
  var HANDOFF_FILE = "handoff.md";
9145
- var HANDOFF_ARCHIVE = path64.join("sources", "handoff-archive.md");
9350
+ var HANDOFF_ARCHIVE = path65.join("sources", "handoff-archive.md");
9146
9351
  async function pathExists(p) {
9147
9352
  try {
9148
9353
  await fs53.access(p);
@@ -9161,7 +9366,7 @@ async function listInitiativeSlugs3(activeRoot) {
9161
9366
  const slugs = [];
9162
9367
  for (const entry of entries) {
9163
9368
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
9164
- if (await pathExists(path64.join(activeRoot, entry.name, "brief.md"))) {
9369
+ if (await pathExists(path65.join(activeRoot, entry.name, "brief.md"))) {
9165
9370
  slugs.push(entry.name);
9166
9371
  }
9167
9372
  }
@@ -9169,9 +9374,9 @@ async function listInitiativeSlugs3(activeRoot) {
9169
9374
  }
9170
9375
  async function maxOnDiskTaskNumber2(initiativeDir, prefix) {
9171
9376
  const re = new RegExp(`^${prefix}-(\\d+)\\.yml$`);
9172
- const tasksDir = path64.join(initiativeDir, "tasks");
9377
+ const tasksDir = path65.join(initiativeDir, "tasks");
9173
9378
  let max = 0;
9174
- for (const dir of [tasksDir, path64.join(tasksDir, "archive")]) {
9379
+ for (const dir of [tasksDir, path65.join(tasksDir, "archive")]) {
9175
9380
  let names;
9176
9381
  try {
9177
9382
  names = await fs53.readdir(dir);
@@ -9193,7 +9398,7 @@ async function nextTaskSeq(initiativeDir, frontmatter2) {
9193
9398
  return max > 0 ? max : null;
9194
9399
  }
9195
9400
  async function planBrief(initiativeDir, slug) {
9196
- const raw = await readRawFrontmatter(path64.join(initiativeDir, "brief.md"));
9401
+ const raw = await readRawFrontmatter(path65.join(initiativeDir, "brief.md"));
9197
9402
  const repaired = repairBriefFrontmatter(slug, raw.frontmatter);
9198
9403
  const taskSeq = await nextTaskSeq(initiativeDir, repaired.frontmatter);
9199
9404
  if (taskSeq === null && repaired.applied.length === 0) return { write: null };
@@ -9210,8 +9415,8 @@ async function planBrief(initiativeDir, slug) {
9210
9415
  };
9211
9416
  }
9212
9417
  async function planHandoff(initiativeDir) {
9213
- if (!await pathExists(path64.join(initiativeDir, HANDOFF_FILE))) return "absent";
9214
- if (await pathExists(path64.join(initiativeDir, HANDOFF_ARCHIVE))) return "archive-exists";
9418
+ if (!await pathExists(path65.join(initiativeDir, HANDOFF_FILE))) return "absent";
9419
+ if (await pathExists(path65.join(initiativeDir, HANDOFF_ARCHIVE))) return "archive-exists";
9215
9420
  return "archive-and-remove";
9216
9421
  }
9217
9422
  function buildOpenSession(entry) {
@@ -9301,7 +9506,7 @@ function draftSessions(entry, abandonedAt) {
9301
9506
  return [open, buildAbandonSession(entry, open.stem, abandonedAt)];
9302
9507
  }
9303
9508
  async function planInitiative(activeRoot, slug, entry, abandonedAt) {
9304
- const initiativeDir = path64.join(activeRoot, slug);
9509
+ const initiativeDir = path65.join(activeRoot, slug);
9305
9510
  const brief = await planBrief(initiativeDir, slug);
9306
9511
  const base = {
9307
9512
  slug,
@@ -9340,9 +9545,9 @@ async function planV2ToV3(activeRoot) {
9340
9545
  return { proposalOrigin: origin, initiatives, repairs: await planRepairs(activeRoot) };
9341
9546
  }
9342
9547
  async function archiveHandoff(initiativeDir) {
9343
- const source = path64.join(initiativeDir, HANDOFF_FILE);
9344
- const target = path64.join(initiativeDir, HANDOFF_ARCHIVE);
9345
- await fs53.mkdir(path64.dirname(target), { recursive: true });
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 });
9346
9551
  await fs53.copyFile(source, target);
9347
9552
  await fs53.rm(source);
9348
9553
  }
@@ -9361,15 +9566,15 @@ async function writePlannedSession(activeRoot, slug, session) {
9361
9566
  });
9362
9567
  }
9363
9568
  async function applyInitiative(activeRoot, plan) {
9364
- const initiativeDir = path64.join(activeRoot, plan.slug);
9365
- await withFileLock(path64.join(initiativeDir, ".lock"), async () => {
9569
+ const initiativeDir = path65.join(activeRoot, plan.slug);
9570
+ await withFileLock(path65.join(initiativeDir, ".lock"), async () => {
9366
9571
  for (const session of plan.sessions) {
9367
9572
  if (session.exists) continue;
9368
9573
  await writePlannedSession(activeRoot, plan.slug, session);
9369
9574
  }
9370
9575
  if (plan.brief !== null) {
9371
9576
  await writeFrontmatter(
9372
- path64.join(initiativeDir, "brief.md"),
9577
+ path65.join(initiativeDir, "brief.md"),
9373
9578
  plan.brief.frontmatter,
9374
9579
  plan.brief.body,
9375
9580
  BriefFrontmatterSchema
@@ -9400,12 +9605,12 @@ var v2ToV3OpenLoops = {
9400
9605
 
9401
9606
  // src/migrations/v3-to-v4-worktrees.ts
9402
9607
  import { promises as fs54 } from "fs";
9403
- import path65 from "path";
9608
+ import path66 from "path";
9404
9609
  import matter5 from "gray-matter";
9405
9610
  import YAML5 from "yaml";
9406
9611
  function normalize(value) {
9407
- const expanded = value.startsWith("~") ? path65.join(process.env.HOME ?? "", value.slice(1)) : value;
9408
- return path65.resolve(expanded);
9612
+ const expanded = value.startsWith("~") ? path66.join(process.env.HOME ?? "", value.slice(1)) : value;
9613
+ return path66.resolve(expanded);
9409
9614
  }
9410
9615
  function toEntries(raw) {
9411
9616
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
@@ -9452,7 +9657,7 @@ async function readArtifacts2(file) {
9452
9657
  }
9453
9658
  }
9454
9659
  async function migrateOne2(initiativeDir) {
9455
- const briefPath = path65.join(initiativeDir, "brief.md");
9660
+ const briefPath = path66.join(initiativeDir, "brief.md");
9456
9661
  let raw;
9457
9662
  try {
9458
9663
  raw = await fs54.readFile(briefPath, "utf8");
@@ -9465,7 +9670,7 @@ async function migrateOne2(initiativeDir) {
9465
9670
  const incoming = toEntries(data.worktrees);
9466
9671
  delete data.worktrees;
9467
9672
  if (incoming.length > 0) {
9468
- const artifactsPath2 = path65.join(initiativeDir, "artifacts.yml");
9673
+ const artifactsPath2 = path66.join(initiativeDir, "artifacts.yml");
9469
9674
  const current = await readArtifacts2(artifactsPath2);
9470
9675
  await writeYaml(
9471
9676
  artifactsPath2,
@@ -9490,9 +9695,9 @@ async function initiativeDirs(activeRoot) {
9490
9695
  }
9491
9696
  for (const entry of entries) {
9492
9697
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
9493
- const dir = path65.join(activeRoot, entry.name);
9698
+ const dir = path66.join(activeRoot, entry.name);
9494
9699
  try {
9495
- await fs54.access(path65.join(dir, "brief.md"));
9700
+ await fs54.access(path66.join(dir, "brief.md"));
9496
9701
  out.push(dir);
9497
9702
  } catch {
9498
9703
  }
@@ -9507,12 +9712,12 @@ var v3ToV4Worktrees = {
9507
9712
  const moved = [];
9508
9713
  for (const dir of await initiativeDirs(activeRoot)) {
9509
9714
  const count = await migrateOne2(dir);
9510
- if (count > 0) moved.push(`${path65.basename(dir)} ${count} worktree(s)`);
9715
+ if (count > 0) moved.push(`${path66.basename(dir)} ${count} worktree(s)`);
9511
9716
  }
9512
9717
  if (moved.length === 0) return;
9513
9718
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
9514
9719
  await fs54.appendFile(
9515
- path65.join(activeRoot, ".migrations.log"),
9720
+ path66.join(activeRoot, ".migrations.log"),
9516
9721
  moved.map((line) => `${stamp} v3->v4 ${line}
9517
9722
  `).join(""),
9518
9723
  "utf8"
@@ -9565,10 +9770,10 @@ var SCHEMA_VERSION_FILENAME = ".schema-version";
9565
9770
  var schemaVersionPath = (activeRoot) => join(activeRoot, SCHEMA_VERSION_FILENAME);
9566
9771
  var isNodeErrnoException = (err) => typeof err === "object" && err !== null && "code" in err;
9567
9772
  async function readSchemaVersion(activeRoot) {
9568
- const path67 = schemaVersionPath(activeRoot);
9773
+ const path68 = schemaVersionPath(activeRoot);
9569
9774
  let raw;
9570
9775
  try {
9571
- raw = await readFile(path67, "utf8");
9776
+ raw = await readFile(path68, "utf8");
9572
9777
  } catch (err) {
9573
9778
  if (isNodeErrnoException(err) && err.code === "ENOENT") {
9574
9779
  return 0;
@@ -9578,13 +9783,13 @@ async function readSchemaVersion(activeRoot) {
9578
9783
  const trimmed = raw.trim();
9579
9784
  if (trimmed === "" || !/^\d+$/.test(trimmed)) {
9580
9785
  throw new Error(
9581
- `Invalid schema version in ${path67}: expected a positive integer, got ${JSON.stringify(raw)}`
9786
+ `Invalid schema version in ${path68}: expected a positive integer, got ${JSON.stringify(raw)}`
9582
9787
  );
9583
9788
  }
9584
9789
  const parsed = Number(trimmed);
9585
9790
  if (!Number.isInteger(parsed) || parsed <= 0) {
9586
9791
  throw new Error(
9587
- `Invalid schema version in ${path67}: expected a positive integer, got ${JSON.stringify(raw)}`
9792
+ `Invalid schema version in ${path68}: expected a positive integer, got ${JSON.stringify(raw)}`
9588
9793
  );
9589
9794
  }
9590
9795
  return parsed;
@@ -9597,10 +9802,10 @@ async function writeSchemaVersion(activeRoot, version) {
9597
9802
  `, "utf8");
9598
9803
  }
9599
9804
  async function readRawSchemaVersion(activeRoot) {
9600
- const path67 = schemaVersionPath(activeRoot);
9805
+ const path68 = schemaVersionPath(activeRoot);
9601
9806
  let raw;
9602
9807
  try {
9603
- raw = await readFile(path67, "utf8");
9808
+ raw = await readFile(path68, "utf8");
9604
9809
  } catch (err) {
9605
9810
  if (isNodeErrnoException(err) && err.code === "ENOENT") {
9606
9811
  return { present: false };
@@ -9610,13 +9815,13 @@ async function readRawSchemaVersion(activeRoot) {
9610
9815
  const trimmed = raw.trim();
9611
9816
  if (trimmed === "" || !/^\d+$/.test(trimmed)) {
9612
9817
  throw new Error(
9613
- `Invalid schema version in ${path67}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9818
+ `Invalid schema version in ${path68}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9614
9819
  );
9615
9820
  }
9616
9821
  const parsed = Number(trimmed);
9617
9822
  if (!Number.isInteger(parsed) || parsed < 0) {
9618
9823
  throw new Error(
9619
- `Invalid schema version in ${path67}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9824
+ `Invalid schema version in ${path68}: expected a non-negative integer, got ${JSON.stringify(raw)}`
9620
9825
  );
9621
9826
  }
9622
9827
  return { present: true, version: parsed };
@@ -10889,20 +11094,20 @@ async function runUninstall(deps = {}) {
10889
11094
  }
10890
11095
 
10891
11096
  // src/commands/setup.ts
10892
- var ArgsSchema49 = z59.object({
10893
- update: z59.boolean().optional(),
10894
- yes: z59.boolean().optional()
11097
+ var ArgsSchema50 = z60.object({
11098
+ update: z60.boolean().optional(),
11099
+ yes: z60.boolean().optional()
10895
11100
  });
10896
- var StepSchema = z59.object({
10897
- name: z59.string(),
10898
- ok: z59.boolean(),
10899
- done: z59.boolean().optional(),
10900
- message: z59.string().optional(),
10901
- error: z59.string().optional()
11101
+ var StepSchema = z60.object({
11102
+ name: z60.string(),
11103
+ ok: z60.boolean(),
11104
+ done: z60.boolean().optional(),
11105
+ message: z60.string().optional(),
11106
+ error: z60.string().optional()
10902
11107
  });
10903
- var ResultSchema45 = z59.object({
10904
- banner: z59.string(),
10905
- steps: z59.array(StepSchema)
11108
+ var ResultSchema46 = z60.object({
11109
+ banner: z60.string(),
11110
+ steps: z60.array(StepSchema)
10906
11111
  });
10907
11112
  function printStep(step) {
10908
11113
  if (step.ok) {
@@ -10919,8 +11124,8 @@ function printStep(step) {
10919
11124
  var setup_default = defineCommand({
10920
11125
  name: "setup",
10921
11126
  description: "Interactive wizard: verifies Node, scaffolds directories, registers the MCP server, and optionally starts the daemon and walks through ingestion.",
10922
- args: ArgsSchema49,
10923
- result: ResultSchema45,
11127
+ args: ArgsSchema50,
11128
+ result: ResultSchema46,
10924
11129
  cli: {
10925
11130
  options: {
10926
11131
  update: {
@@ -10955,25 +11160,25 @@ var setup_default = defineCommand({
10955
11160
  });
10956
11161
 
10957
11162
  // src/commands/uninstall.ts
10958
- import { z as z60 } from "zod";
10959
- var ArgsSchema50 = z60.object({
10960
- yes: z60.boolean().optional()
11163
+ import { z as z61 } from "zod";
11164
+ var ArgsSchema51 = z61.object({
11165
+ yes: z61.boolean().optional()
10961
11166
  });
10962
- var StepSchema2 = z60.object({
10963
- name: z60.string(),
10964
- done: z60.boolean(),
10965
- message: z60.string().optional(),
10966
- error: z60.string().optional()
11167
+ var StepSchema2 = z61.object({
11168
+ name: z61.string(),
11169
+ done: z61.boolean(),
11170
+ message: z61.string().optional(),
11171
+ error: z61.string().optional()
10967
11172
  });
10968
- var ResultSchema46 = z60.object({
10969
- steps: z60.array(StepSchema2),
10970
- activeRootPreservedAt: z60.string()
11173
+ var ResultSchema47 = z61.object({
11174
+ steps: z61.array(StepSchema2),
11175
+ activeRootPreservedAt: z61.string()
10971
11176
  });
10972
11177
  var uninstall_default = defineCommand({
10973
11178
  name: "uninstall",
10974
11179
  description: "Reverse what setup did: remove the skill, stop the daemon, unregister MCP. Preserves the active root.",
10975
- args: ArgsSchema50,
10976
- result: ResultSchema46,
11180
+ args: ArgsSchema51,
11181
+ result: ResultSchema47,
10977
11182
  cli: {
10978
11183
  options: {
10979
11184
  yes: {
@@ -11003,7 +11208,7 @@ var uninstall_default = defineCommand({
11003
11208
  });
11004
11209
 
11005
11210
  // src/commands/doctor.ts
11006
- import { z as z61 } from "zod";
11211
+ import { z as z62 } from "zod";
11007
11212
 
11008
11213
  // src/doctor.ts
11009
11214
  import { promises as fsp4 } from "fs";
@@ -11411,15 +11616,15 @@ async function runDoctor(deps = {}) {
11411
11616
  }
11412
11617
 
11413
11618
  // src/commands/doctor.ts
11414
- var ArgsSchema51 = z61.object({});
11415
- var CheckSchema = z61.object({
11416
- name: z61.string(),
11417
- status: z61.enum(["ok", "warn", "fail"]),
11418
- detail: z61.string()
11619
+ var ArgsSchema52 = z62.object({});
11620
+ var CheckSchema = z62.object({
11621
+ name: z62.string(),
11622
+ status: z62.enum(["ok", "warn", "fail"]),
11623
+ detail: z62.string()
11419
11624
  });
11420
- var ResultSchema47 = z61.object({
11421
- ok: z61.boolean(),
11422
- checks: z61.array(CheckSchema)
11625
+ var ResultSchema48 = z62.object({
11626
+ ok: z62.boolean(),
11627
+ checks: z62.array(CheckSchema)
11423
11628
  });
11424
11629
  function badge(status) {
11425
11630
  if (status === "ok") return color.green("OK ");
@@ -11429,8 +11634,8 @@ function badge(status) {
11429
11634
  var doctor_default = defineCommand({
11430
11635
  name: "doctor",
11431
11636
  description: "Health-check the install: Node, active root, daemon, MCP registration, skill, and supervision.",
11432
- args: ArgsSchema51,
11433
- result: ResultSchema47,
11637
+ args: ArgsSchema52,
11638
+ result: ResultSchema48,
11434
11639
  async run(_args, ctx) {
11435
11640
  const report2 = await runDoctor();
11436
11641
  if (ctx.format !== "json") {
@@ -11447,34 +11652,34 @@ var doctor_default = defineCommand({
11447
11652
  });
11448
11653
 
11449
11654
  // src/commands/migrate.ts
11450
- import { z as z62 } from "zod";
11451
- var ArgsSchema52 = z62.object({
11452
- dry_run: z62.boolean().optional(),
11453
- apply: z62.boolean().optional()
11454
- });
11455
- var SessionSchema = z62.object({
11456
- kind: z62.enum(["open", "abandon"]),
11457
- action: z62.enum(["write", "exists"]),
11458
- file: z62.string(),
11459
- ended: z62.string(),
11460
- loops: z62.number().int().nonnegative(),
11461
- resolves: z62.number().int().nonnegative()
11462
- });
11463
- var InitiativeSchema = z62.object({
11464
- slug: z62.string(),
11465
- sessions: z62.array(SessionSchema),
11466
- task_seq_backfill: z62.number().int().positive().nullable(),
11467
- brief_repairs: z62.array(z62.string()),
11468
- brief_blocked: z62.string().optional(),
11469
- handoff: z62.enum(["archive-and-remove", "archive-exists", "absent"]),
11470
- note: z62.string().optional()
11655
+ import { z as z63 } from "zod";
11656
+ var ArgsSchema53 = z63.object({
11657
+ dry_run: z63.boolean().optional(),
11658
+ apply: z63.boolean().optional()
11659
+ });
11660
+ var SessionSchema = z63.object({
11661
+ kind: z63.enum(["open", "abandon"]),
11662
+ action: z63.enum(["write", "exists"]),
11663
+ file: z63.string(),
11664
+ ended: z63.string(),
11665
+ loops: z63.number().int().nonnegative(),
11666
+ resolves: z63.number().int().nonnegative()
11667
+ });
11668
+ var InitiativeSchema = z63.object({
11669
+ slug: z63.string(),
11670
+ sessions: z63.array(SessionSchema),
11671
+ task_seq_backfill: z63.number().int().positive().nullable(),
11672
+ brief_repairs: z63.array(z63.string()),
11673
+ brief_blocked: z63.string().optional(),
11674
+ handoff: z63.enum(["archive-and-remove", "archive-exists", "absent"]),
11675
+ note: z63.string().optional()
11471
11676
  });
11472
- var ResultSchema48 = z62.object({
11473
- applied: z62.boolean(),
11474
- proposal: z62.string(),
11475
- initiatives: z62.array(InitiativeSchema),
11476
- repairs: z62.array(z62.object({ action: z62.string(), file: z62.string(), detail: z62.string() })),
11477
- uncovered: z62.array(z62.string())
11677
+ var ResultSchema49 = z63.object({
11678
+ applied: z63.boolean(),
11679
+ proposal: z63.string(),
11680
+ initiatives: z63.array(InitiativeSchema),
11681
+ repairs: z63.array(z63.object({ action: z63.string(), file: z63.string(), detail: z63.string() })),
11682
+ uncovered: z63.array(z63.string())
11478
11683
  });
11479
11684
  function describe2(plan, applied) {
11480
11685
  const initiatives = plan.initiatives.map((i) => ({
@@ -11550,8 +11755,8 @@ function render(result) {
11550
11755
  var migrate_default = defineCommand({
11551
11756
  name: "migrate",
11552
11757
  description: "Preview (or apply) the pending v2\u2192v3 open-loops migration.",
11553
- args: ArgsSchema52,
11554
- result: ResultSchema48,
11758
+ args: ArgsSchema53,
11759
+ result: ResultSchema49,
11555
11760
  cli: {
11556
11761
  options: {
11557
11762
  dry_run: { long: "--dry-run", description: "Report what would change; write nothing" },
@@ -11586,18 +11791,18 @@ var migrate_default = defineCommand({
11586
11791
 
11587
11792
  // src/commands/sync.ts
11588
11793
  import os7 from "os";
11589
- import { z as z63 } from "zod";
11590
- var ArgsSchema53 = z63.object({
11591
- message: z63.string().min(1).optional(),
11592
- require_clean: z63.boolean().optional()
11593
- });
11594
- var ResultSchema49 = z63.object({
11595
- branch: z63.string(),
11596
- committed: z63.boolean(),
11597
- committed_files: z63.number().int(),
11598
- rebased: z63.boolean(),
11599
- pushed: z63.boolean(),
11600
- summary: z63.string()
11794
+ import { z as z64 } from "zod";
11795
+ var ArgsSchema54 = z64.object({
11796
+ message: z64.string().min(1).optional(),
11797
+ require_clean: z64.boolean().optional()
11798
+ });
11799
+ var ResultSchema50 = z64.object({
11800
+ branch: z64.string(),
11801
+ committed: z64.boolean(),
11802
+ committed_files: z64.number().int(),
11803
+ rebased: z64.boolean(),
11804
+ pushed: z64.boolean(),
11805
+ summary: z64.string()
11601
11806
  });
11602
11807
  async function git(root, args) {
11603
11808
  return getGitRunner()("git", ["-C", root, ...args]);
@@ -11699,8 +11904,8 @@ async function push(root) {
11699
11904
  var sync_default = defineCommand({
11700
11905
  name: "sync",
11701
11906
  description: "Sync the active root over git: auto-commit local edits, pull --rebase, then push.",
11702
- args: ArgsSchema53,
11703
- result: ResultSchema49,
11907
+ args: ArgsSchema54,
11908
+ result: ResultSchema50,
11704
11909
  cli: {
11705
11910
  options: {
11706
11911
  message: {
@@ -11794,6 +11999,7 @@ var ALL_COMMANDS = [
11794
11999
  audit_default,
11795
12000
  list_default,
11796
12001
  context_graph_default,
12002
+ search_default,
11797
12003
  // discover / triage
11798
12004
  discover_default,
11799
12005
  fold_default,
@@ -11834,14 +12040,14 @@ import { readCommanderOption } from "@titan-design/registry";
11834
12040
 
11835
12041
  // src/utils/usage-log.ts
11836
12042
  import { promises as fs56 } from "fs";
11837
- import path66 from "path";
12043
+ import path67 from "path";
11838
12044
  function usageLogPath() {
11839
- return path66.join(getStateRoot(), "usage.jsonl");
12045
+ return path67.join(getStateRoot(), "usage.jsonl");
11840
12046
  }
11841
12047
  async function appendUsage(rec) {
11842
12048
  try {
11843
12049
  const file = usageLogPath();
11844
- await fs56.mkdir(path66.dirname(file), { recursive: true });
12050
+ await fs56.mkdir(path67.dirname(file), { recursive: true });
11845
12051
  await fs56.appendFile(file, JSON.stringify(rec) + "\n", "utf8");
11846
12052
  } catch {
11847
12053
  }