@titan-design/active-work 0.4.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
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
writeFrontmatter,
|
|
77
77
|
writeNoteFile,
|
|
78
78
|
writeYaml
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-RLSQSE7I.js";
|
|
80
80
|
|
|
81
81
|
// src/cli.ts
|
|
82
82
|
import { Command, CommanderError } from "commander";
|
|
@@ -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(
|
|
1521
|
-
return { path:
|
|
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/
|
|
3852
|
+
// src/commands/search.ts
|
|
3853
3853
|
import { z as z33 } from "zod";
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
}
|
|
3872
|
-
var
|
|
3873
|
-
|
|
3874
|
-
|
|
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
|
|
3950
|
-
import { z as
|
|
3951
|
-
var argsSchema3 =
|
|
3952
|
-
slug:
|
|
3953
|
-
path:
|
|
3954
|
-
label:
|
|
3955
|
-
default:
|
|
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 =
|
|
3958
|
-
slug:
|
|
3959
|
-
label:
|
|
3960
|
-
path:
|
|
3961
|
-
default:
|
|
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:
|
|
4321
|
+
promoted: z35.boolean()
|
|
3964
4322
|
});
|
|
3965
4323
|
var DEFAULT_LABEL = "main";
|
|
3966
|
-
var samePath = (a, 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 =
|
|
3989
|
-
const briefPath =
|
|
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
|
|
4044
|
-
import { z as
|
|
4045
|
-
var argsSchema4 =
|
|
4046
|
-
slug:
|
|
4047
|
-
label:
|
|
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 =
|
|
4050
|
-
slug:
|
|
4051
|
-
default_label:
|
|
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 =
|
|
4063
|
-
const briefPath =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ??
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
4587
|
-
github_repos:
|
|
4588
|
-
local_repos:
|
|
4589
|
-
projects_root:
|
|
4590
|
-
});
|
|
4591
|
-
var
|
|
4592
|
-
source:
|
|
4593
|
-
ref:
|
|
4594
|
-
detail:
|
|
4595
|
-
metadata:
|
|
4596
|
-
slug_match:
|
|
4597
|
-
untracked:
|
|
4598
|
-
});
|
|
4599
|
-
var
|
|
4600
|
-
hits:
|
|
4601
|
-
errors:
|
|
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:
|
|
4607
|
-
result:
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
4656
|
-
ref:
|
|
4657
|
-
reason:
|
|
5013
|
+
var ArgsSchema34 = z38.object({
|
|
5014
|
+
ref: z38.string().min(1),
|
|
5015
|
+
reason: z38.string().optional()
|
|
4658
5016
|
});
|
|
4659
|
-
var
|
|
4660
|
-
ref:
|
|
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:
|
|
4666
|
-
result:
|
|
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
|
|
4685
|
-
import { z as
|
|
4686
|
-
var
|
|
4687
|
-
ref:
|
|
4688
|
-
into:
|
|
4689
|
-
note:
|
|
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
|
|
4692
|
-
ref:
|
|
4693
|
-
into:
|
|
4694
|
-
session_file:
|
|
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:
|
|
4700
|
-
result:
|
|
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 =
|
|
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
|
|
4760
|
-
import { z as
|
|
5117
|
+
import path45 from "path";
|
|
5118
|
+
import { z as z40 } from "zod";
|
|
4761
5119
|
import { stringify as yamlStringify } from "yaml";
|
|
4762
|
-
var
|
|
4763
|
-
ref:
|
|
4764
|
-
slug:
|
|
4765
|
-
title:
|
|
4766
|
-
ship_target:
|
|
4767
|
-
owner:
|
|
4768
|
-
worktree:
|
|
4769
|
-
});
|
|
4770
|
-
var
|
|
4771
|
-
slug:
|
|
4772
|
-
dir:
|
|
4773
|
-
ref:
|
|
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:
|
|
4779
|
-
result:
|
|
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(
|
|
4807
|
-
await fs32.mkdir(
|
|
4808
|
-
await fs32.mkdir(
|
|
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
|
-
|
|
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(
|
|
4829
|
-
await atomicWrite(
|
|
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
|
|
4860
|
-
var
|
|
4861
|
-
slug:
|
|
4862
|
-
offline:
|
|
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:
|
|
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:
|
|
5226
|
+
adhoc: z41.boolean().optional(),
|
|
4869
5227
|
// Skip the check for another session already live on this initiative.
|
|
4870
|
-
no_sibling_check:
|
|
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:
|
|
4876
|
-
result:
|
|
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
|
|
5287
|
+
import path46 from "path";
|
|
4930
5288
|
import { spawn as spawn2 } from "child_process";
|
|
4931
|
-
import { z as
|
|
4932
|
-
var
|
|
4933
|
-
slug:
|
|
4934
|
-
target:
|
|
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
|
|
4937
|
-
slug:
|
|
4938
|
-
target:
|
|
4939
|
-
file:
|
|
4940
|
-
validated:
|
|
4941
|
-
aborted:
|
|
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
|
|
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:
|
|
5029
|
-
result:
|
|
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
|
|
5400
|
+
import { z as z44 } from "zod";
|
|
5043
5401
|
|
|
5044
5402
|
// src/server/mcp.ts
|
|
5045
5403
|
import {
|
|
@@ -5055,9 +5413,8 @@ import {
|
|
|
5055
5413
|
toolNameToCommandName as pkgToolNameToCommandName
|
|
5056
5414
|
} from "@titan-design/registry";
|
|
5057
5415
|
|
|
5058
|
-
// src/
|
|
5059
|
-
var
|
|
5060
|
-
var startedAt = Date.now();
|
|
5416
|
+
// src/version.ts
|
|
5417
|
+
var BUILD_VERSION = "0.6.0";
|
|
5061
5418
|
|
|
5062
5419
|
// src/server/mcp.ts
|
|
5063
5420
|
var TOOL_NAME_PREFIX = "active__";
|
|
@@ -5068,7 +5425,7 @@ function mcpOptions() {
|
|
|
5068
5425
|
formatError,
|
|
5069
5426
|
toolPrefix: TOOL_NAME_PREFIX,
|
|
5070
5427
|
name: "@hjewkes/active-work",
|
|
5071
|
-
version:
|
|
5428
|
+
version: BUILD_VERSION
|
|
5072
5429
|
};
|
|
5073
5430
|
}
|
|
5074
5431
|
async function runMcpStdio() {
|
|
@@ -5080,7 +5437,7 @@ import { DaemonAlreadyRunningError, startDaemon } from "@titan-design/daemon";
|
|
|
5080
5437
|
|
|
5081
5438
|
// src/server/dashboard-routes.ts
|
|
5082
5439
|
import { promises as fs34 } from "fs";
|
|
5083
|
-
import
|
|
5440
|
+
import path47 from "path";
|
|
5084
5441
|
import { fileURLToPath } from "url";
|
|
5085
5442
|
var PLACEHOLDER_HTML = `<!doctype html>
|
|
5086
5443
|
<html lang="en">
|
|
@@ -5112,17 +5469,17 @@ var CONTENT_TYPES = {
|
|
|
5112
5469
|
".woff2": "font/woff2"
|
|
5113
5470
|
};
|
|
5114
5471
|
function contentTypeFor(filename) {
|
|
5115
|
-
const ext =
|
|
5472
|
+
const ext = path47.extname(filename).toLowerCase();
|
|
5116
5473
|
return CONTENT_TYPES[ext] ?? "application/octet-stream";
|
|
5117
5474
|
}
|
|
5118
5475
|
function dashboardDirCandidates() {
|
|
5119
|
-
const here =
|
|
5476
|
+
const here = path47.dirname(fileURLToPath(import.meta.url));
|
|
5120
5477
|
return [
|
|
5121
|
-
|
|
5478
|
+
path47.resolve(here, "dashboard"),
|
|
5122
5479
|
// bundled: dist/cli.js -> dist/dashboard
|
|
5123
|
-
|
|
5480
|
+
path47.resolve(here, "..", "dashboard"),
|
|
5124
5481
|
// legacy: dist/server -> dist/dashboard
|
|
5125
|
-
|
|
5482
|
+
path47.resolve(here, "..", "..", "dist", "dashboard")
|
|
5126
5483
|
// dev: src/server -> dist/dashboard
|
|
5127
5484
|
];
|
|
5128
5485
|
}
|
|
@@ -5139,205 +5496,67 @@ async function resolveDashboardDir() {
|
|
|
5139
5496
|
if ((await safeStat(dir)).exists) return dir;
|
|
5140
5497
|
}
|
|
5141
5498
|
return null;
|
|
5142
|
-
}
|
|
5143
|
-
async function handleDashboard(c) {
|
|
5144
|
-
const root = await resolveDashboardDir();
|
|
5145
|
-
if (!root) {
|
|
5146
|
-
return c.html(PLACEHOLDER_HTML, 200);
|
|
5147
|
-
}
|
|
5148
|
-
const url = new URL(c.req.url);
|
|
5149
|
-
const subpath = url.pathname.replace(/^\/ui\/?/, "");
|
|
5150
|
-
const relative = subpath === "" ? "index.html" : subpath;
|
|
5151
|
-
const target =
|
|
5152
|
-
if (!target.startsWith(root +
|
|
5153
|
-
return c.text("forbidden", 403);
|
|
5154
|
-
}
|
|
5155
|
-
const stat = await safeStat(target);
|
|
5156
|
-
if (!stat.exists || !stat.isFile) {
|
|
5157
|
-
const indexPath =
|
|
5158
|
-
const indexStat = await safeStat(indexPath);
|
|
5159
|
-
if (!indexStat.exists) {
|
|
5160
|
-
return c.html(PLACEHOLDER_HTML, 200);
|
|
5161
|
-
}
|
|
5162
|
-
const body2 = await fs34.readFile(indexPath);
|
|
5163
|
-
return c.body(new Uint8Array(body2), 200, {
|
|
5164
|
-
"content-type": "text/html; charset=utf-8"
|
|
5165
|
-
});
|
|
5166
|
-
}
|
|
5167
|
-
const body = await fs34.readFile(target);
|
|
5168
|
-
return c.body(new Uint8Array(body), 200, {
|
|
5169
|
-
"content-type": contentTypeFor(target)
|
|
5170
|
-
});
|
|
5171
|
-
}
|
|
5172
|
-
|
|
5173
|
-
// src/server/logger.ts
|
|
5174
|
-
import { mkdirSync, createWriteStream } from "fs";
|
|
5175
|
-
import path45 from "path";
|
|
5176
|
-
import pino, { multistream } from "pino";
|
|
5177
|
-
var cachedLogger;
|
|
5178
|
-
function buildLogger() {
|
|
5179
|
-
const stateRoot = getStateRoot();
|
|
5180
|
-
mkdirSync(stateRoot, { recursive: true });
|
|
5181
|
-
const logPath = path45.join(stateRoot, "daemon.log");
|
|
5182
|
-
const fileStream = createWriteStream(logPath, { flags: "a" });
|
|
5183
|
-
const stderrIsTTY = process.stderr.isTTY === true;
|
|
5184
|
-
const stderrStream = stderrIsTTY ? pino.transport({
|
|
5185
|
-
target: "pino-pretty",
|
|
5186
|
-
options: { destination: 2, colorize: true }
|
|
5187
|
-
}) : process.stderr;
|
|
5188
|
-
const streams = [{ stream: stderrStream }, { stream: fileStream }];
|
|
5189
|
-
return pino({ level: process.env.AW_LOG_LEVEL ?? "info" }, multistream(streams));
|
|
5190
|
-
}
|
|
5191
|
-
function getLogger() {
|
|
5192
|
-
cachedLogger ??= buildLogger();
|
|
5193
|
-
return cachedLogger;
|
|
5194
|
-
}
|
|
5195
|
-
|
|
5196
|
-
// src/server/session-index-watch.ts
|
|
5197
|
-
import { existsSync } from "fs";
|
|
5198
|
-
import { transcriptsRoot as transcriptsRoot2 } from "@titan-design/session-read";
|
|
5199
|
-
import { watchTree } from "@titan-design/daemon";
|
|
5200
|
-
|
|
5201
|
-
// src/session-index/graph.ts
|
|
5202
|
-
import Database from "better-sqlite3";
|
|
5203
|
-
import { openSessionGraph } from "@titan-design/session-graph";
|
|
5204
|
-
import { runMigrations, WatermarkTable } from "@titan-design/store-sqlite";
|
|
5205
|
-
import path46 from "path";
|
|
5206
|
-
|
|
5207
|
-
// src/workspace-index/schema.ts
|
|
5208
|
-
import { kitDdl } from "@titan-design/store-sqlite";
|
|
5209
|
-
import { MIGRATIONS as SESSION_GRAPH_MIGRATIONS } from "@titan-design/session-graph";
|
|
5210
|
-
var WORKSPACE_KIT = {
|
|
5211
|
-
watermark: "workspace_file",
|
|
5212
|
-
edge: "edge",
|
|
5213
|
-
spanFts: "search"
|
|
5214
|
-
};
|
|
5215
|
-
var WORKSPACE_SPAN_SOURCE_BASE = 1e9;
|
|
5216
|
-
var DOMAIN_DDL = `
|
|
5217
|
-
CREATE TABLE IF NOT EXISTS initiative (
|
|
5218
|
-
path TEXT PRIMARY KEY,
|
|
5219
|
-
initiative_ref TEXT NOT NULL UNIQUE,
|
|
5220
|
-
slug TEXT NOT NULL,
|
|
5221
|
-
title TEXT,
|
|
5222
|
-
state TEXT,
|
|
5223
|
-
rank INTEGER,
|
|
5224
|
-
ship_target TEXT,
|
|
5225
|
-
owner TEXT,
|
|
5226
|
-
task_prefix TEXT,
|
|
5227
|
-
updated TEXT
|
|
5228
|
-
);
|
|
5229
|
-
|
|
5230
|
-
CREATE TABLE IF NOT EXISTS note (
|
|
5231
|
-
path TEXT PRIMARY KEY,
|
|
5232
|
-
note_ref TEXT NOT NULL UNIQUE,
|
|
5233
|
-
initiative TEXT NOT NULL,
|
|
5234
|
-
filename TEXT NOT NULL,
|
|
5235
|
-
kind TEXT NOT NULL,
|
|
5236
|
-
title TEXT NOT NULL,
|
|
5237
|
-
created TEXT,
|
|
5238
|
-
tags TEXT,
|
|
5239
|
-
hits INTEGER NOT NULL DEFAULT 0,
|
|
5240
|
-
promoted_at TEXT
|
|
5241
|
-
);
|
|
5242
|
-
CREATE INDEX IF NOT EXISTS idx_note_initiative ON note(initiative);
|
|
5243
|
-
|
|
5244
|
-
CREATE TABLE IF NOT EXISTS workspace_task (
|
|
5245
|
-
path TEXT PRIMARY KEY,
|
|
5246
|
-
task_ref TEXT NOT NULL,
|
|
5247
|
-
initiative TEXT NOT NULL,
|
|
5248
|
-
task_id TEXT NOT NULL,
|
|
5249
|
-
title TEXT NOT NULL,
|
|
5250
|
-
status TEXT NOT NULL,
|
|
5251
|
-
priority INTEGER,
|
|
5252
|
-
severity TEXT,
|
|
5253
|
-
estimate REAL,
|
|
5254
|
-
tags TEXT,
|
|
5255
|
-
created TEXT,
|
|
5256
|
-
updated TEXT,
|
|
5257
|
-
done_at TEXT
|
|
5258
|
-
);
|
|
5259
|
-
CREATE INDEX IF NOT EXISTS idx_workspace_task_ref ON workspace_task(task_ref);
|
|
5260
|
-
|
|
5261
|
-
CREATE TABLE IF NOT EXISTS session_record (
|
|
5262
|
-
path TEXT PRIMARY KEY,
|
|
5263
|
-
session_ref TEXT NOT NULL,
|
|
5264
|
-
initiative TEXT NOT NULL,
|
|
5265
|
-
session_id TEXT NOT NULL,
|
|
5266
|
-
started TEXT,
|
|
5267
|
-
ended TEXT,
|
|
5268
|
-
track TEXT,
|
|
5269
|
-
parent_session_id TEXT
|
|
5270
|
-
);
|
|
5271
|
-
CREATE INDEX IF NOT EXISTS idx_session_record_ref ON session_record(session_ref);
|
|
5272
|
-
|
|
5273
|
-
CREATE TABLE IF NOT EXISTS source (
|
|
5274
|
-
path TEXT PRIMARY KEY,
|
|
5275
|
-
source_ref TEXT NOT NULL UNIQUE,
|
|
5276
|
-
initiative TEXT NOT NULL,
|
|
5277
|
-
title TEXT,
|
|
5278
|
-
kind TEXT,
|
|
5279
|
-
added TEXT
|
|
5280
|
-
);
|
|
5281
|
-
`;
|
|
5282
|
-
function nextVersion(chain) {
|
|
5283
|
-
return (chain[chain.length - 1]?.version ?? 0) + 1;
|
|
5284
|
-
}
|
|
5285
|
-
var SPAN_SOURCE_INDEX = `
|
|
5286
|
-
CREATE INDEX IF NOT EXISTS idx_search_span_source ON search_span(source_id);
|
|
5287
|
-
`;
|
|
5288
|
-
var WORKSPACE_MIGRATIONS = [
|
|
5289
|
-
{
|
|
5290
|
-
version: nextVersion(SESSION_GRAPH_MIGRATIONS),
|
|
5291
|
-
name: "workspace index tables",
|
|
5292
|
-
up: (db) => {
|
|
5293
|
-
db.exec(kitDdl({ watermark: WORKSPACE_KIT.watermark }));
|
|
5294
|
-
db.exec(DOMAIN_DDL);
|
|
5295
|
-
db.exec(SPAN_SOURCE_INDEX);
|
|
5499
|
+
}
|
|
5500
|
+
async function handleDashboard(c) {
|
|
5501
|
+
const root = await resolveDashboardDir();
|
|
5502
|
+
if (!root) {
|
|
5503
|
+
return c.html(PLACEHOLDER_HTML, 200);
|
|
5504
|
+
}
|
|
5505
|
+
const url = new URL(c.req.url);
|
|
5506
|
+
const subpath = url.pathname.replace(/^\/ui\/?/, "");
|
|
5507
|
+
const relative = subpath === "" ? "index.html" : subpath;
|
|
5508
|
+
const target = path47.resolve(root, relative);
|
|
5509
|
+
if (!target.startsWith(root + path47.sep) && target !== root) {
|
|
5510
|
+
return c.text("forbidden", 403);
|
|
5511
|
+
}
|
|
5512
|
+
const stat = await safeStat(target);
|
|
5513
|
+
if (!stat.exists || !stat.isFile) {
|
|
5514
|
+
const indexPath = path47.join(root, "index.html");
|
|
5515
|
+
const indexStat = await safeStat(indexPath);
|
|
5516
|
+
if (!indexStat.exists) {
|
|
5517
|
+
return c.html(PLACEHOLDER_HTML, 200);
|
|
5296
5518
|
}
|
|
5519
|
+
const body2 = await fs34.readFile(indexPath);
|
|
5520
|
+
return c.body(new Uint8Array(body2), 200, {
|
|
5521
|
+
"content-type": "text/html; charset=utf-8"
|
|
5522
|
+
});
|
|
5297
5523
|
}
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
identity TEXT NOT NULL,
|
|
5303
|
-
row_key TEXT NOT NULL,
|
|
5304
|
-
payload TEXT NOT NULL,
|
|
5305
|
-
origin TEXT NOT NULL,
|
|
5306
|
-
mode TEXT NOT NULL DEFAULT 'insert',
|
|
5307
|
-
preserved_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
5308
|
-
PRIMARY KEY (table_name, row_key)
|
|
5309
|
-
);
|
|
5310
|
-
`;
|
|
5311
|
-
var PRESERVE_MIGRATION = {
|
|
5312
|
-
version: nextVersion([...SESSION_GRAPH_MIGRATIONS, ...WORKSPACE_MIGRATIONS]),
|
|
5313
|
-
name: "preserved rows",
|
|
5314
|
-
up: (db) => db.exec(PRESERVE_DDL)
|
|
5315
|
-
};
|
|
5316
|
-
var MIGRATIONS = [
|
|
5317
|
-
...SESSION_GRAPH_MIGRATIONS,
|
|
5318
|
-
...WORKSPACE_MIGRATIONS,
|
|
5319
|
-
PRESERVE_MIGRATION
|
|
5320
|
-
];
|
|
5321
|
-
|
|
5322
|
-
// src/session-index/graph.ts
|
|
5323
|
-
var SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
|
|
5324
|
-
function defaultGraphPath() {
|
|
5325
|
-
return path46.join(getMinerRoot(), "graph.sqlite3");
|
|
5524
|
+
const body = await fs34.readFile(target);
|
|
5525
|
+
return c.body(new Uint8Array(body), 200, {
|
|
5526
|
+
"content-type": contentTypeFor(target)
|
|
5527
|
+
});
|
|
5326
5528
|
}
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
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));
|
|
5334
5547
|
}
|
|
5335
|
-
function
|
|
5336
|
-
|
|
5548
|
+
function getLogger() {
|
|
5549
|
+
cachedLogger ??= buildLogger();
|
|
5550
|
+
return cachedLogger;
|
|
5337
5551
|
}
|
|
5338
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
|
+
|
|
5339
5558
|
// src/session-index/refresh.ts
|
|
5340
|
-
import
|
|
5559
|
+
import path57 from "path";
|
|
5341
5560
|
import { promises as fs44 } from "fs";
|
|
5342
5561
|
import lockfile from "proper-lockfile";
|
|
5343
5562
|
import { discoverTranscripts, transcriptsRoot } from "@titan-design/session-read";
|
|
@@ -5345,7 +5564,7 @@ import { refreshCorpus, resetIndex } from "@titan-design/session-graph";
|
|
|
5345
5564
|
|
|
5346
5565
|
// src/session-index/tasks.ts
|
|
5347
5566
|
import { promises as fs35 } from "fs";
|
|
5348
|
-
import
|
|
5567
|
+
import path49 from "path";
|
|
5349
5568
|
var AMBIGUOUS = null;
|
|
5350
5569
|
async function initiativeSlugs(root) {
|
|
5351
5570
|
try {
|
|
@@ -5357,7 +5576,7 @@ async function initiativeSlugs(root) {
|
|
|
5357
5576
|
}
|
|
5358
5577
|
}
|
|
5359
5578
|
async function readInitiative(root, slug) {
|
|
5360
|
-
const dir =
|
|
5579
|
+
const dir = path49.join(root, slug, "tasks");
|
|
5361
5580
|
let files;
|
|
5362
5581
|
try {
|
|
5363
5582
|
files = await fs35.readdir(dir);
|
|
@@ -5369,7 +5588,7 @@ async function readInitiative(root, slug) {
|
|
|
5369
5588
|
for (const file of files) {
|
|
5370
5589
|
if (!file.endsWith(".yml")) continue;
|
|
5371
5590
|
try {
|
|
5372
|
-
const task = await readYaml(
|
|
5591
|
+
const task = await readYaml(path49.join(dir, file), TaskSchema);
|
|
5373
5592
|
found.push([task.id, { initiative: slug, title: task.title, status: task.status }]);
|
|
5374
5593
|
} catch {
|
|
5375
5594
|
continue;
|
|
@@ -5402,21 +5621,7 @@ function taskResolver(root) {
|
|
|
5402
5621
|
// src/workspace-index/refresh.ts
|
|
5403
5622
|
import { promises as fs43 } from "fs";
|
|
5404
5623
|
import matter4 from "gray-matter";
|
|
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
|
|
5441
|
-
const scoped = `${initiative}/${
|
|
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
|
|
5983
|
+
import path56 from "path";
|
|
5779
5984
|
|
|
5780
5985
|
// src/lint/index.ts
|
|
5781
5986
|
import { promises as fs41 } from "fs";
|
|
5782
|
-
import
|
|
5987
|
+
import path55 from "path";
|
|
5783
5988
|
|
|
5784
5989
|
// src/lint/brief.ts
|
|
5785
5990
|
import { promises as fs37 } from "fs";
|
|
5786
|
-
import
|
|
5991
|
+
import path50 from "path";
|
|
5787
5992
|
|
|
5788
5993
|
// src/lint/hashes.ts
|
|
5789
5994
|
import { promises as fs38 } from "fs";
|
|
5790
|
-
import
|
|
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(
|
|
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
|
|
6020
|
+
import path52 from "path";
|
|
5816
6021
|
|
|
5817
6022
|
// src/lint/task.ts
|
|
5818
6023
|
import { promises as fs39 } from "fs";
|
|
5819
|
-
import
|
|
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
|
|
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) =>
|
|
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(
|
|
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 =
|
|
5862
|
-
const brief =
|
|
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(
|
|
5865
|
-
taskFiles(
|
|
5866
|
-
filesIn(
|
|
5867
|
-
filesIn(
|
|
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]),
|
|
@@ -6031,16 +6236,17 @@ function isUnchanged(row, file) {
|
|
|
6031
6236
|
return row.lastOffset > 0 && row.fileSize === file.size && row.fileMtime === file.mtime;
|
|
6032
6237
|
}
|
|
6033
6238
|
var BATCH = 200;
|
|
6239
|
+
function describeFailure(err) {
|
|
6240
|
+
if (err instanceof z43.ZodError) {
|
|
6241
|
+
return err.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
6242
|
+
}
|
|
6243
|
+
return err instanceof Error ? err.message : String(err);
|
|
6244
|
+
}
|
|
6034
6245
|
async function readAttempt(file, watermarkId) {
|
|
6035
6246
|
try {
|
|
6036
6247
|
return { file, watermarkId, record: await readRecord(file), reason: null };
|
|
6037
6248
|
} catch (err) {
|
|
6038
|
-
return {
|
|
6039
|
-
file,
|
|
6040
|
-
watermarkId,
|
|
6041
|
-
record: null,
|
|
6042
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
6043
|
-
};
|
|
6249
|
+
return { file, watermarkId, record: null, reason: describeFailure(err) };
|
|
6044
6250
|
}
|
|
6045
6251
|
}
|
|
6046
6252
|
function applyBatch(graph, writer, batch) {
|
|
@@ -6273,7 +6479,7 @@ function refreshLockPath() {
|
|
|
6273
6479
|
}
|
|
6274
6480
|
async function withRefreshLock(fn) {
|
|
6275
6481
|
const target = refreshLockPath();
|
|
6276
|
-
await fs44.mkdir(
|
|
6482
|
+
await fs44.mkdir(path57.dirname(target), { recursive: true });
|
|
6277
6483
|
await fs44.writeFile(target, "", { flag: "a" });
|
|
6278
6484
|
const release = await lockfile.lock(target, {
|
|
6279
6485
|
realpath: false,
|
|
@@ -6287,7 +6493,7 @@ async function withRefreshLock(fn) {
|
|
|
6287
6493
|
}
|
|
6288
6494
|
}
|
|
6289
6495
|
async function runRefresh(options = {}) {
|
|
6290
|
-
const
|
|
6496
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6291
6497
|
const started = Date.now();
|
|
6292
6498
|
const graph = options.graph ?? openGraph(options.dbPath ?? defaultGraphPath());
|
|
6293
6499
|
const owned = options.graph === void 0;
|
|
@@ -6312,7 +6518,7 @@ async function runRefresh(options = {}) {
|
|
|
6312
6518
|
});
|
|
6313
6519
|
const preserved = replayPreserved(graph);
|
|
6314
6520
|
return {
|
|
6315
|
-
startedAt
|
|
6521
|
+
startedAt,
|
|
6316
6522
|
durationMs: Date.now() - started,
|
|
6317
6523
|
transcripts: discovered.length,
|
|
6318
6524
|
scanned: visiting.length,
|
|
@@ -6498,7 +6704,7 @@ async function runDaemon(options = {}) {
|
|
|
6498
6704
|
stateDir: getStateRoot(),
|
|
6499
6705
|
port: resolvePort(options),
|
|
6500
6706
|
watchRoot: getActiveRoot(),
|
|
6501
|
-
version:
|
|
6707
|
+
version: BUILD_VERSION,
|
|
6502
6708
|
logger: log,
|
|
6503
6709
|
health: () => ({ index: toHealthIndexState(indexWatch?.status()) }),
|
|
6504
6710
|
mountRoutes: (app) => {
|
|
@@ -6537,15 +6743,15 @@ async function runDaemon(options = {}) {
|
|
|
6537
6743
|
}
|
|
6538
6744
|
|
|
6539
6745
|
// src/commands/mcp-serve.ts
|
|
6540
|
-
var
|
|
6541
|
-
stdio:
|
|
6542
|
-
detach:
|
|
6543
|
-
port:
|
|
6746
|
+
var ArgsSchema39 = z44.object({
|
|
6747
|
+
stdio: z44.boolean().optional(),
|
|
6748
|
+
detach: z44.boolean().optional(),
|
|
6749
|
+
port: z44.number().int().positive().optional()
|
|
6544
6750
|
});
|
|
6545
|
-
var
|
|
6546
|
-
mode:
|
|
6547
|
-
pid:
|
|
6548
|
-
port:
|
|
6751
|
+
var ResultSchema35 = z44.object({
|
|
6752
|
+
mode: z44.enum(["stdio", "http", "detached"]),
|
|
6753
|
+
pid: z44.number().optional(),
|
|
6754
|
+
port: z44.number().optional()
|
|
6549
6755
|
});
|
|
6550
6756
|
function detachedSpawn(port) {
|
|
6551
6757
|
const entry = process.argv[1];
|
|
@@ -6567,8 +6773,8 @@ function detachedSpawn(port) {
|
|
|
6567
6773
|
var mcp_serve_default = defineCommand({
|
|
6568
6774
|
name: "mcp.serve",
|
|
6569
6775
|
description: "Start the MCP server. --stdio for stdio mode; --detach to fork the HTTP daemon; otherwise runs the HTTP daemon in the foreground.",
|
|
6570
|
-
args:
|
|
6571
|
-
result:
|
|
6776
|
+
args: ArgsSchema39,
|
|
6777
|
+
result: ResultSchema35,
|
|
6572
6778
|
cli: {
|
|
6573
6779
|
options: {
|
|
6574
6780
|
stdio: {
|
|
@@ -6600,11 +6806,11 @@ var mcp_serve_default = defineCommand({
|
|
|
6600
6806
|
});
|
|
6601
6807
|
|
|
6602
6808
|
// src/commands/mcp-stop.ts
|
|
6603
|
-
import { z as
|
|
6604
|
-
var
|
|
6605
|
-
var
|
|
6606
|
-
|
|
6607
|
-
|
|
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() })
|
|
6608
6814
|
]);
|
|
6609
6815
|
var SHUTDOWN_TIMEOUT_MS = 3e3;
|
|
6610
6816
|
var POLL_INTERVAL_MS = 100;
|
|
@@ -6619,8 +6825,8 @@ async function waitForExit(pid, timeoutMs) {
|
|
|
6619
6825
|
var mcp_stop_default = defineCommand({
|
|
6620
6826
|
name: "mcp.stop",
|
|
6621
6827
|
description: "Stop the running MCP HTTP daemon (sends SIGTERM, waits for exit).",
|
|
6622
|
-
args:
|
|
6623
|
-
result:
|
|
6828
|
+
args: ArgsSchema40,
|
|
6829
|
+
result: ResultSchema36,
|
|
6624
6830
|
async run() {
|
|
6625
6831
|
const pidEntry = await readPidFile();
|
|
6626
6832
|
if (!pidEntry) {
|
|
@@ -6649,13 +6855,13 @@ var mcp_stop_default = defineCommand({
|
|
|
6649
6855
|
|
|
6650
6856
|
// src/commands/mcp-restart.ts
|
|
6651
6857
|
import { spawn as spawn4 } from "child_process";
|
|
6652
|
-
import { z as
|
|
6653
|
-
var
|
|
6654
|
-
port:
|
|
6858
|
+
import { z as z46 } from "zod";
|
|
6859
|
+
var ArgsSchema41 = z46.object({
|
|
6860
|
+
port: z46.number().int().positive().optional()
|
|
6655
6861
|
});
|
|
6656
|
-
var
|
|
6657
|
-
pid:
|
|
6658
|
-
port:
|
|
6862
|
+
var ResultSchema37 = z46.object({
|
|
6863
|
+
pid: z46.number(),
|
|
6864
|
+
port: z46.number()
|
|
6659
6865
|
});
|
|
6660
6866
|
var SHUTDOWN_TIMEOUT_MS2 = 15e3;
|
|
6661
6867
|
var KILL_TIMEOUT_MS = 3e3;
|
|
@@ -6723,8 +6929,8 @@ async function confirmStarted(pid, port) {
|
|
|
6723
6929
|
var mcp_restart_default = defineCommand({
|
|
6724
6930
|
name: "mcp.restart",
|
|
6725
6931
|
description: "Restart the MCP HTTP daemon (stop, then spawn a fresh detached instance).",
|
|
6726
|
-
args:
|
|
6727
|
-
result:
|
|
6932
|
+
args: ArgsSchema41,
|
|
6933
|
+
result: ResultSchema37,
|
|
6728
6934
|
cli: {
|
|
6729
6935
|
options: {
|
|
6730
6936
|
port: {
|
|
@@ -6743,17 +6949,17 @@ var mcp_restart_default = defineCommand({
|
|
|
6743
6949
|
});
|
|
6744
6950
|
|
|
6745
6951
|
// src/commands/mcp-status.ts
|
|
6746
|
-
import { z as
|
|
6747
|
-
var
|
|
6748
|
-
var
|
|
6749
|
-
running:
|
|
6750
|
-
pid:
|
|
6751
|
-
port:
|
|
6752
|
-
version:
|
|
6753
|
-
uptime_ms:
|
|
6754
|
-
healthy:
|
|
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(),
|
|
6755
6961
|
/** Answering `/health` with no PID file naming it — see `removePidFile`. */
|
|
6756
|
-
orphaned:
|
|
6962
|
+
orphaned: z47.boolean().optional()
|
|
6757
6963
|
});
|
|
6758
6964
|
async function statusByPort(port) {
|
|
6759
6965
|
const health = await probeHealth(port);
|
|
@@ -6771,8 +6977,8 @@ async function statusByPort(port) {
|
|
|
6771
6977
|
var mcp_status_default = defineCommand({
|
|
6772
6978
|
name: "mcp.status",
|
|
6773
6979
|
description: "Report the MCP HTTP daemon status (pid, port, version, uptime).",
|
|
6774
|
-
args:
|
|
6775
|
-
result:
|
|
6980
|
+
args: ArgsSchema42,
|
|
6981
|
+
result: ResultSchema38,
|
|
6776
6982
|
async run() {
|
|
6777
6983
|
const entry = await readPidFile();
|
|
6778
6984
|
if (!entry) {
|
|
@@ -6805,20 +7011,20 @@ var mcp_status_default = defineCommand({
|
|
|
6805
7011
|
|
|
6806
7012
|
// src/commands/mcp-logs.ts
|
|
6807
7013
|
import { promises as fs45 } from "fs";
|
|
6808
|
-
import
|
|
6809
|
-
import { z as
|
|
6810
|
-
var
|
|
6811
|
-
lines:
|
|
7014
|
+
import path58 from "path";
|
|
7015
|
+
import { z as z48 } from "zod";
|
|
7016
|
+
var ArgsSchema43 = z48.object({
|
|
7017
|
+
lines: z48.number().int().positive().optional()
|
|
6812
7018
|
});
|
|
6813
|
-
var
|
|
6814
|
-
lines:
|
|
7019
|
+
var ResultSchema39 = z48.object({
|
|
7020
|
+
lines: z48.array(z48.string())
|
|
6815
7021
|
});
|
|
6816
7022
|
var DEFAULT_LINES = 50;
|
|
6817
7023
|
var mcp_logs_default = defineCommand({
|
|
6818
7024
|
name: "mcp.logs",
|
|
6819
7025
|
description: "Return the last N lines of the daemon log (default 50).",
|
|
6820
|
-
args:
|
|
6821
|
-
result:
|
|
7026
|
+
args: ArgsSchema43,
|
|
7027
|
+
result: ResultSchema39,
|
|
6822
7028
|
cli: {
|
|
6823
7029
|
options: {
|
|
6824
7030
|
lines: {
|
|
@@ -6829,7 +7035,7 @@ var mcp_logs_default = defineCommand({
|
|
|
6829
7035
|
},
|
|
6830
7036
|
async run(args) {
|
|
6831
7037
|
const n = args.lines ?? DEFAULT_LINES;
|
|
6832
|
-
const logPath =
|
|
7038
|
+
const logPath = path58.join(getStateRoot(), "daemon.log");
|
|
6833
7039
|
let content;
|
|
6834
7040
|
try {
|
|
6835
7041
|
content = await fs45.readFile(logPath, "utf8");
|
|
@@ -6848,7 +7054,7 @@ var mcp_logs_default = defineCommand({
|
|
|
6848
7054
|
});
|
|
6849
7055
|
|
|
6850
7056
|
// src/commands/miner-drain-ingest.ts
|
|
6851
|
-
import { z as
|
|
7057
|
+
import { z as z52 } from "zod";
|
|
6852
7058
|
|
|
6853
7059
|
// src/drain/transcript-reader.ts
|
|
6854
7060
|
import { nextOffset, prefixHash, readJsonLines, resumePoint } from "@titan-design/locator";
|
|
@@ -6859,40 +7065,40 @@ import { Clusterer } from "@titan-design/cluster";
|
|
|
6859
7065
|
|
|
6860
7066
|
// src/drain/store.ts
|
|
6861
7067
|
import { promises as fs46 } from "fs";
|
|
6862
|
-
import
|
|
7068
|
+
import path59 from "path";
|
|
6863
7069
|
|
|
6864
7070
|
// src/schemas/template.ts
|
|
6865
|
-
import { z as
|
|
6866
|
-
var LocatorSchema =
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
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()
|
|
6870
7076
|
]);
|
|
6871
|
-
var TemplateSchema =
|
|
6872
|
-
templateId:
|
|
6873
|
-
toolType:
|
|
6874
|
-
maskedSignature:
|
|
6875
|
-
createdAt:
|
|
6876
|
-
occurrenceCount:
|
|
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(),
|
|
6877
7083
|
exemplarLocator: LocatorSchema
|
|
6878
7084
|
});
|
|
6879
|
-
var OccurrenceSchema =
|
|
6880
|
-
templateId:
|
|
7085
|
+
var OccurrenceSchema = z49.object({
|
|
7086
|
+
templateId: z49.string().min(1),
|
|
6881
7087
|
locator: LocatorSchema,
|
|
6882
|
-
sessionId:
|
|
6883
|
-
timestamp:
|
|
6884
|
-
extractedParams:
|
|
7088
|
+
sessionId: z49.string().min(1),
|
|
7089
|
+
timestamp: z49.string().min(1),
|
|
7090
|
+
extractedParams: z49.record(z49.string(), z49.string()).optional()
|
|
6885
7091
|
});
|
|
6886
|
-
var TemplatesFileSchema =
|
|
6887
|
-
templates:
|
|
7092
|
+
var TemplatesFileSchema = z49.object({
|
|
7093
|
+
templates: z49.array(TemplateSchema).default([])
|
|
6888
7094
|
});
|
|
6889
7095
|
|
|
6890
7096
|
// src/drain/store.ts
|
|
6891
7097
|
function templatesPath(root) {
|
|
6892
|
-
return
|
|
7098
|
+
return path59.join(root, "templates.yml");
|
|
6893
7099
|
}
|
|
6894
7100
|
function occurrencesPath(root) {
|
|
6895
|
-
return
|
|
7101
|
+
return path59.join(root, "occurrences.jsonl");
|
|
6896
7102
|
}
|
|
6897
7103
|
async function loadTemplates(root = getMinerRoot()) {
|
|
6898
7104
|
try {
|
|
@@ -6930,31 +7136,31 @@ async function appendOccurrences(occurrences, root = getMinerRoot()) {
|
|
|
6930
7136
|
|
|
6931
7137
|
// src/drain/tree-store.ts
|
|
6932
7138
|
import { promises as fs47 } from "fs";
|
|
6933
|
-
import
|
|
6934
|
-
import { z as
|
|
6935
|
-
var PartitionSchema =
|
|
6936
|
-
partition:
|
|
6937
|
-
nextClusterId:
|
|
6938
|
-
clusters:
|
|
6939
|
-
|
|
6940
|
-
clusterId:
|
|
6941
|
-
tokens:
|
|
6942
|
-
size:
|
|
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()
|
|
6943
7149
|
})
|
|
6944
7150
|
),
|
|
6945
7151
|
/** `clusterId -> templateId`, as pairs so the file has a stable order. */
|
|
6946
|
-
templateIds:
|
|
7152
|
+
templateIds: z50.array(z50.tuple([z50.number().int().positive(), z50.string().min(1)]))
|
|
6947
7153
|
});
|
|
6948
|
-
var TreeSnapshotFileSchema =
|
|
6949
|
-
version:
|
|
6950
|
-
partitions:
|
|
7154
|
+
var TreeSnapshotFileSchema = z50.object({
|
|
7155
|
+
version: z50.literal(1).default(1),
|
|
7156
|
+
partitions: z50.array(PartitionSchema).default([])
|
|
6951
7157
|
});
|
|
6952
|
-
var LegacySnapshotFileSchema =
|
|
6953
|
-
version:
|
|
6954
|
-
trees:
|
|
7158
|
+
var LegacySnapshotFileSchema = z50.object({
|
|
7159
|
+
version: z50.literal(1),
|
|
7160
|
+
trees: z50.array(PartitionSchema.omit({ partition: true }).extend({ toolType: z50.string().min(1) }))
|
|
6955
7161
|
});
|
|
6956
7162
|
function snapshotPath(root) {
|
|
6957
|
-
return
|
|
7163
|
+
return path60.join(root, "drain-trees.json");
|
|
6958
7164
|
}
|
|
6959
7165
|
function empty() {
|
|
6960
7166
|
return { version: 1, partitions: [] };
|
|
@@ -7133,28 +7339,28 @@ function extractBlobs(line, toolNames) {
|
|
|
7133
7339
|
|
|
7134
7340
|
// src/drain/reader-state.ts
|
|
7135
7341
|
import { promises as fs48 } from "fs";
|
|
7136
|
-
import
|
|
7137
|
-
import { z as
|
|
7138
|
-
var TranscriptStateSchema =
|
|
7342
|
+
import path61 from "path";
|
|
7343
|
+
import { z as z51 } from "zod";
|
|
7344
|
+
var TranscriptStateSchema = z51.object({
|
|
7139
7345
|
/** `~`-relative path, matching `session-index/discover.ts`'s display form. */
|
|
7140
|
-
path:
|
|
7141
|
-
lastByteOffset:
|
|
7346
|
+
path: z51.string().min(1),
|
|
7347
|
+
lastByteOffset: z51.number().int().nonnegative().default(0),
|
|
7142
7348
|
/** sha256 of bytes `[0, lastByteOffset)`; detects rewrite vs. append. */
|
|
7143
|
-
prefixHash:
|
|
7349
|
+
prefixHash: z51.string().nullable().default(null),
|
|
7144
7350
|
/**
|
|
7145
7351
|
* `tool_use_id -> tool name` pairs seen but not yet consumed by a result.
|
|
7146
7352
|
* Persisted because a chunk boundary routinely falls between an assistant's
|
|
7147
7353
|
* `tool_use` and the user line carrying its result.
|
|
7148
7354
|
*/
|
|
7149
|
-
pendingToolNames:
|
|
7355
|
+
pendingToolNames: z51.record(z51.string(), z51.string()).default({})
|
|
7150
7356
|
});
|
|
7151
|
-
var ReaderStateSchema =
|
|
7152
|
-
version:
|
|
7153
|
-
transcripts:
|
|
7357
|
+
var ReaderStateSchema = z51.object({
|
|
7358
|
+
version: z51.literal(1).default(1),
|
|
7359
|
+
transcripts: z51.array(TranscriptStateSchema).default([])
|
|
7154
7360
|
});
|
|
7155
7361
|
var MAX_PENDING_TOOL_NAMES = 256;
|
|
7156
7362
|
function readerStatePath(root = getMinerRoot()) {
|
|
7157
|
-
return
|
|
7363
|
+
return path61.join(root, "reader-state.json");
|
|
7158
7364
|
}
|
|
7159
7365
|
async function loadReaderState(root = getMinerRoot()) {
|
|
7160
7366
|
try {
|
|
@@ -7261,7 +7467,7 @@ async function ingestLine(parsed, locator, toolNames, ingestor, counters, sample
|
|
|
7261
7467
|
}
|
|
7262
7468
|
}
|
|
7263
7469
|
async function runDrainIngest(options = {}) {
|
|
7264
|
-
const
|
|
7470
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7265
7471
|
const started = process.hrtime.bigint();
|
|
7266
7472
|
const root = options.root ?? getMinerRoot();
|
|
7267
7473
|
const corpusRoot = options.corpusRoot ?? transcriptsRoot3();
|
|
@@ -7308,7 +7514,7 @@ async function runDrainIngest(options = {}) {
|
|
|
7308
7514
|
await ingestor.flush();
|
|
7309
7515
|
await saveReaderState(state, root);
|
|
7310
7516
|
return {
|
|
7311
|
-
startedAt
|
|
7517
|
+
startedAt,
|
|
7312
7518
|
durationMs: Number(process.hrtime.bigint() - started) / 1e6,
|
|
7313
7519
|
transcripts: discovered.length,
|
|
7314
7520
|
scanned,
|
|
@@ -7321,33 +7527,33 @@ async function runDrainIngest(options = {}) {
|
|
|
7321
7527
|
}
|
|
7322
7528
|
|
|
7323
7529
|
// src/commands/miner-drain-ingest.ts
|
|
7324
|
-
var
|
|
7325
|
-
full:
|
|
7326
|
-
limit:
|
|
7327
|
-
verify_hashes:
|
|
7328
|
-
});
|
|
7329
|
-
var
|
|
7330
|
-
startedAt:
|
|
7331
|
-
durationMs:
|
|
7332
|
-
transcripts:
|
|
7333
|
-
scanned:
|
|
7334
|
-
unchanged:
|
|
7335
|
-
rewound:
|
|
7336
|
-
linesRead:
|
|
7337
|
-
malformedLines:
|
|
7338
|
-
blobs:
|
|
7339
|
-
ingested:
|
|
7340
|
-
newTemplates:
|
|
7341
|
-
templates:
|
|
7342
|
-
evicting:
|
|
7343
|
-
curve:
|
|
7344
|
-
errors:
|
|
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())
|
|
7345
7551
|
});
|
|
7346
7552
|
var miner_drain_ingest_default = defineCommand({
|
|
7347
7553
|
name: "miner.drain-ingest",
|
|
7348
7554
|
description: "Cluster new tool-result/error blobs from Claude transcripts into the template store.",
|
|
7349
|
-
args:
|
|
7350
|
-
result:
|
|
7555
|
+
args: ArgsSchema44,
|
|
7556
|
+
result: ResultSchema40,
|
|
7351
7557
|
cli: {
|
|
7352
7558
|
options: {
|
|
7353
7559
|
full: {
|
|
@@ -7374,52 +7580,52 @@ var miner_drain_ingest_default = defineCommand({
|
|
|
7374
7580
|
});
|
|
7375
7581
|
|
|
7376
7582
|
// src/commands/miner-refresh.ts
|
|
7377
|
-
import { z as
|
|
7378
|
-
var
|
|
7379
|
-
full:
|
|
7380
|
-
limit:
|
|
7381
|
-
verify_hashes:
|
|
7382
|
-
});
|
|
7383
|
-
var WorkspaceSchema =
|
|
7384
|
-
files:
|
|
7385
|
-
indexed:
|
|
7386
|
-
unchanged:
|
|
7387
|
-
removed:
|
|
7388
|
-
malformed:
|
|
7389
|
-
rows:
|
|
7390
|
-
initiative:
|
|
7391
|
-
note:
|
|
7392
|
-
task:
|
|
7393
|
-
session:
|
|
7394
|
-
source:
|
|
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()
|
|
7395
7601
|
}),
|
|
7396
|
-
edges:
|
|
7397
|
-
orphanRatio:
|
|
7398
|
-
});
|
|
7399
|
-
var
|
|
7400
|
-
startedAt:
|
|
7401
|
-
durationMs:
|
|
7402
|
-
transcripts:
|
|
7403
|
-
scanned:
|
|
7404
|
-
indexed:
|
|
7405
|
-
rewound:
|
|
7406
|
-
unchanged:
|
|
7407
|
-
quarantined:
|
|
7408
|
-
missing:
|
|
7409
|
-
reconciledMissing:
|
|
7410
|
-
factsAdded:
|
|
7411
|
-
turnsRolledUp:
|
|
7412
|
-
tasksRequested:
|
|
7413
|
-
tasksApplied:
|
|
7602
|
+
edges: z53.object({ holds: z53.number(), mentions: z53.number(), sharesTag: z53.number() }),
|
|
7603
|
+
orphanRatio: z53.number()
|
|
7604
|
+
});
|
|
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(),
|
|
7414
7620
|
workspace: WorkspaceSchema.nullable(),
|
|
7415
|
-
preserved:
|
|
7416
|
-
errors:
|
|
7621
|
+
preserved: z53.object({ restored: z53.number(), merged: z53.number(), skipped: z53.number() }),
|
|
7622
|
+
errors: z53.array(z53.string())
|
|
7417
7623
|
});
|
|
7418
7624
|
var miner_refresh_default = defineCommand({
|
|
7419
7625
|
name: "miner.refresh",
|
|
7420
7626
|
description: "Index new Claude session transcripts into the session-signal index.",
|
|
7421
|
-
args:
|
|
7422
|
-
result:
|
|
7627
|
+
args: ArgsSchema45,
|
|
7628
|
+
result: ResultSchema41,
|
|
7423
7629
|
cli: {
|
|
7424
7630
|
options: {
|
|
7425
7631
|
full: {
|
|
@@ -7445,7 +7651,7 @@ var miner_refresh_default = defineCommand({
|
|
|
7445
7651
|
|
|
7446
7652
|
// src/commands/miner-liveness.ts
|
|
7447
7653
|
import { existsSync as existsSync3 } from "fs";
|
|
7448
|
-
import { z as
|
|
7654
|
+
import { z as z54 } from "zod";
|
|
7449
7655
|
|
|
7450
7656
|
// src/session-index/liveness.ts
|
|
7451
7657
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -7562,22 +7768,22 @@ function runLiveness(db) {
|
|
|
7562
7768
|
}
|
|
7563
7769
|
|
|
7564
7770
|
// src/commands/miner-liveness.ts
|
|
7565
|
-
var
|
|
7566
|
-
var
|
|
7567
|
-
emptyColumns:
|
|
7568
|
-
|
|
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() })
|
|
7569
7775
|
),
|
|
7570
|
-
unusedRelations:
|
|
7571
|
-
undeclaredRelations:
|
|
7572
|
-
danglingNamespaces:
|
|
7573
|
-
|
|
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() })
|
|
7574
7780
|
),
|
|
7575
|
-
unmappedNamespaces:
|
|
7576
|
-
expectedEmptyColumns:
|
|
7577
|
-
|
|
7781
|
+
unmappedNamespaces: z54.array(z54.string()),
|
|
7782
|
+
expectedEmptyColumns: z54.array(
|
|
7783
|
+
z54.object({ table: z54.string(), column: z54.string(), reason: z54.string() })
|
|
7578
7784
|
),
|
|
7579
|
-
staleTranscripts:
|
|
7580
|
-
transcripts:
|
|
7785
|
+
staleTranscripts: z54.number(),
|
|
7786
|
+
transcripts: z54.number()
|
|
7581
7787
|
});
|
|
7582
7788
|
function report(result) {
|
|
7583
7789
|
const lines = [color.bold("active-work miner liveness")];
|
|
@@ -7629,8 +7835,8 @@ function report(result) {
|
|
|
7629
7835
|
var miner_liveness_default = defineCommand({
|
|
7630
7836
|
name: "miner.liveness",
|
|
7631
7837
|
description: "Report which declared index structures nothing ever populates: empty columns, unused edge relations, dangling refs, stale transcripts.",
|
|
7632
|
-
args:
|
|
7633
|
-
result:
|
|
7838
|
+
args: ArgsSchema46,
|
|
7839
|
+
result: ResultSchema42,
|
|
7634
7840
|
cli: { usage: "active-work miner liveness" },
|
|
7635
7841
|
async run(_args, ctx) {
|
|
7636
7842
|
const dbPath = defaultGraphPath();
|
|
@@ -7668,40 +7874,40 @@ var miner_liveness_default = defineCommand({
|
|
|
7668
7874
|
|
|
7669
7875
|
// src/commands/miner-status.ts
|
|
7670
7876
|
import { existsSync as existsSync4, statSync } from "fs";
|
|
7671
|
-
import { z as
|
|
7672
|
-
var
|
|
7673
|
-
var
|
|
7674
|
-
dbPath:
|
|
7675
|
-
schemaVersion:
|
|
7676
|
-
sizeBytes:
|
|
7677
|
-
counts:
|
|
7678
|
-
transcripts:
|
|
7679
|
-
sessions:
|
|
7680
|
-
facts:
|
|
7681
|
-
turns:
|
|
7682
|
-
edges:
|
|
7683
|
-
spans:
|
|
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()
|
|
7684
7890
|
}),
|
|
7685
|
-
transcripts:
|
|
7686
|
-
ok:
|
|
7687
|
-
quarantined:
|
|
7688
|
-
missing:
|
|
7891
|
+
transcripts: z55.object({
|
|
7892
|
+
ok: z55.number(),
|
|
7893
|
+
quarantined: z55.number(),
|
|
7894
|
+
missing: z55.number()
|
|
7689
7895
|
}),
|
|
7690
|
-
watermark:
|
|
7691
|
-
lastIndexedAt:
|
|
7692
|
-
behindBytes:
|
|
7896
|
+
watermark: z55.object({
|
|
7897
|
+
lastIndexedAt: z55.string().nullable(),
|
|
7898
|
+
behindBytes: z55.number()
|
|
7693
7899
|
}),
|
|
7694
|
-
fts:
|
|
7695
|
-
rows:
|
|
7696
|
-
orphanRows:
|
|
7697
|
-
needsFullRebuild:
|
|
7900
|
+
fts: z55.object({
|
|
7901
|
+
rows: z55.number(),
|
|
7902
|
+
orphanRows: z55.number(),
|
|
7903
|
+
needsFullRebuild: z55.boolean()
|
|
7698
7904
|
}),
|
|
7699
|
-
daemon:
|
|
7700
|
-
indexing:
|
|
7701
|
-
pending:
|
|
7702
|
-
lastRunAt:
|
|
7703
|
-
lastDurationMs:
|
|
7704
|
-
consecutiveErrors:
|
|
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()
|
|
7705
7911
|
}).nullable()
|
|
7706
7912
|
});
|
|
7707
7913
|
var ORPHAN_WARN_RATIO = 0.2;
|
|
@@ -7742,8 +7948,8 @@ async function emptyStatus(dbPath) {
|
|
|
7742
7948
|
var miner_status_default = defineCommand({
|
|
7743
7949
|
name: "miner.status",
|
|
7744
7950
|
description: "Report session-signal index size, freshness, and daemon indexing state.",
|
|
7745
|
-
args:
|
|
7746
|
-
result:
|
|
7951
|
+
args: ArgsSchema47,
|
|
7952
|
+
result: ResultSchema43,
|
|
7747
7953
|
async run() {
|
|
7748
7954
|
const dbPath = defaultGraphPath();
|
|
7749
7955
|
if (!existsSync4(dbPath)) return emptyStatus(dbPath);
|
|
@@ -7785,7 +7991,7 @@ var miner_status_default = defineCommand({
|
|
|
7785
7991
|
});
|
|
7786
7992
|
|
|
7787
7993
|
// src/commands/hooks-agent-chat-spawn.ts
|
|
7788
|
-
import { z as
|
|
7994
|
+
import { z as z57 } from "zod";
|
|
7789
7995
|
|
|
7790
7996
|
// src/utils/read-stdin-json.ts
|
|
7791
7997
|
async function readStdinJson(stream = process.stdin) {
|
|
@@ -7805,13 +8011,13 @@ async function readStdinJson(stream = process.stdin) {
|
|
|
7805
8011
|
|
|
7806
8012
|
// src/utils/agent-chat-hook-state.ts
|
|
7807
8013
|
import { promises as fs49 } from "fs";
|
|
7808
|
-
import
|
|
7809
|
-
import { z as
|
|
7810
|
-
var SpawnContextSchema =
|
|
7811
|
-
slug:
|
|
7812
|
-
sessionId:
|
|
7813
|
-
name:
|
|
7814
|
-
started:
|
|
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(),
|
|
7815
8021
|
/**
|
|
7816
8022
|
* The spawning session, already resolved from the payload's `parent`
|
|
7817
8023
|
* agentId to a session id. Resolved at spawn time on purpose: `parent` names
|
|
@@ -7819,16 +8025,16 @@ var SpawnContextSchema = z54.object({
|
|
|
7819
8025
|
* another live entry in this same directory — which is gone by the time
|
|
7820
8026
|
* on_complete runs, because reading one deletes it.
|
|
7821
8027
|
*/
|
|
7822
|
-
parentSessionId:
|
|
8028
|
+
parentSessionId: z56.string().min(1).nullable().default(null),
|
|
7823
8029
|
/** agent-chat profile and briefing slug, for the recorded session's prose. */
|
|
7824
|
-
profile:
|
|
7825
|
-
briefing:
|
|
8030
|
+
profile: z56.string().nullable().default(null),
|
|
8031
|
+
briefing: z56.string().nullable().default(null)
|
|
7826
8032
|
});
|
|
7827
8033
|
function stateDir() {
|
|
7828
|
-
return
|
|
8034
|
+
return path62.join(getStateRoot(), "agent-chat-hooks");
|
|
7829
8035
|
}
|
|
7830
8036
|
function stateFile(agentId) {
|
|
7831
|
-
return
|
|
8037
|
+
return path62.join(stateDir(), `${agentId}.json`);
|
|
7832
8038
|
}
|
|
7833
8039
|
async function stashSpawnContext(agentId, context) {
|
|
7834
8040
|
await fs49.mkdir(stateDir(), { recursive: true });
|
|
@@ -7854,10 +8060,10 @@ async function peekSpawnContext(agentId) {
|
|
|
7854
8060
|
}
|
|
7855
8061
|
|
|
7856
8062
|
// src/commands/hooks-agent-chat-spawn.ts
|
|
7857
|
-
var
|
|
7858
|
-
var
|
|
7859
|
-
matched:
|
|
7860
|
-
slug:
|
|
8063
|
+
var ArgsSchema48 = z57.object({});
|
|
8064
|
+
var ResultSchema44 = z57.object({
|
|
8065
|
+
matched: z57.boolean(),
|
|
8066
|
+
slug: z57.string().nullable()
|
|
7861
8067
|
});
|
|
7862
8068
|
function str2(source, key) {
|
|
7863
8069
|
const value = source?.[key];
|
|
@@ -7886,8 +8092,8 @@ async function handleOnSpawn(payload, activeRoot) {
|
|
|
7886
8092
|
var hooks_agent_chat_spawn_default = defineCommand({
|
|
7887
8093
|
name: "hooks.agent-chat-spawn",
|
|
7888
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.",
|
|
7889
|
-
args:
|
|
7890
|
-
result:
|
|
8095
|
+
args: ArgsSchema48,
|
|
8096
|
+
result: ResultSchema44,
|
|
7891
8097
|
cli: {
|
|
7892
8098
|
usage: "active-work hooks agent-chat-spawn (reads the on_spawn JSON payload from stdin)"
|
|
7893
8099
|
},
|
|
@@ -7899,11 +8105,11 @@ var hooks_agent_chat_spawn_default = defineCommand({
|
|
|
7899
8105
|
|
|
7900
8106
|
// src/commands/hooks-agent-chat-complete.ts
|
|
7901
8107
|
import { spawn as spawn5 } from "child_process";
|
|
7902
|
-
import { z as
|
|
7903
|
-
var
|
|
7904
|
-
var
|
|
7905
|
-
recorded:
|
|
7906
|
-
slug:
|
|
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()
|
|
7907
8113
|
});
|
|
7908
8114
|
function str3(source, key) {
|
|
7909
8115
|
const value = source?.[key];
|
|
@@ -7970,8 +8176,8 @@ async function handleOnComplete(payload) {
|
|
|
7970
8176
|
var hooks_agent_chat_complete_default = defineCommand({
|
|
7971
8177
|
name: "hooks.agent-chat-complete",
|
|
7972
8178
|
description: "agent-chat on_complete hook consumer (AW-99): record a spawned peer's run as a track:adhoc session via wrap.",
|
|
7973
|
-
args:
|
|
7974
|
-
result:
|
|
8179
|
+
args: ArgsSchema49,
|
|
8180
|
+
result: ResultSchema45,
|
|
7975
8181
|
cli: {
|
|
7976
8182
|
usage: "active-work hooks agent-chat-complete (reads the on_complete JSON payload from stdin)"
|
|
7977
8183
|
},
|
|
@@ -7982,7 +8188,7 @@ var hooks_agent_chat_complete_default = defineCommand({
|
|
|
7982
8188
|
});
|
|
7983
8189
|
|
|
7984
8190
|
// src/commands/setup.ts
|
|
7985
|
-
import { z as
|
|
8191
|
+
import { z as z60 } from "zod";
|
|
7986
8192
|
|
|
7987
8193
|
// src/setup/steps.ts
|
|
7988
8194
|
import { promises as fsp3, existsSync as existsSync5 } from "fs";
|
|
@@ -7998,7 +8204,7 @@ import { join } from "path";
|
|
|
7998
8204
|
|
|
7999
8205
|
// src/migrations/v1-to-v2-artifacts.ts
|
|
8000
8206
|
import { promises as fs50 } from "fs";
|
|
8001
|
-
import
|
|
8207
|
+
import path63 from "path";
|
|
8002
8208
|
import YAML4 from "yaml";
|
|
8003
8209
|
function asArray(value) {
|
|
8004
8210
|
return Array.isArray(value) ? value : [];
|
|
@@ -8058,7 +8264,7 @@ async function walkArtifactsFiles(activeRoot) {
|
|
|
8058
8264
|
for (const entry of entries) {
|
|
8059
8265
|
if (!entry.isDirectory()) continue;
|
|
8060
8266
|
if (entry.name.startsWith(".")) continue;
|
|
8061
|
-
const candidate =
|
|
8267
|
+
const candidate = path63.join(activeRoot, entry.name, "artifacts.yml");
|
|
8062
8268
|
try {
|
|
8063
8269
|
await fs50.access(candidate);
|
|
8064
8270
|
out.push(candidate);
|
|
@@ -8067,14 +8273,14 @@ async function walkArtifactsFiles(activeRoot) {
|
|
|
8067
8273
|
}
|
|
8068
8274
|
} catch {
|
|
8069
8275
|
}
|
|
8070
|
-
const archiveRoot =
|
|
8276
|
+
const archiveRoot = path63.resolve(activeRoot, "..");
|
|
8071
8277
|
try {
|
|
8072
8278
|
const domains = await fs50.readdir(archiveRoot, { withFileTypes: true });
|
|
8073
8279
|
for (const domain of domains) {
|
|
8074
8280
|
if (!domain.isDirectory()) continue;
|
|
8075
8281
|
if (domain.name.startsWith(".")) continue;
|
|
8076
|
-
if (
|
|
8077
|
-
const archiveDir =
|
|
8282
|
+
if (path63.join(archiveRoot, domain.name) === path63.resolve(activeRoot)) continue;
|
|
8283
|
+
const archiveDir = path63.join(archiveRoot, domain.name, "archive");
|
|
8078
8284
|
let archived;
|
|
8079
8285
|
try {
|
|
8080
8286
|
archived = await fs50.readdir(archiveDir, { withFileTypes: true });
|
|
@@ -8083,7 +8289,7 @@ async function walkArtifactsFiles(activeRoot) {
|
|
|
8083
8289
|
}
|
|
8084
8290
|
for (const entry of archived) {
|
|
8085
8291
|
if (!entry.isDirectory()) continue;
|
|
8086
|
-
const candidate =
|
|
8292
|
+
const candidate = path63.join(archiveDir, entry.name, "artifacts.yml");
|
|
8087
8293
|
try {
|
|
8088
8294
|
await fs50.access(candidate);
|
|
8089
8295
|
out.push(candidate);
|
|
@@ -8097,7 +8303,7 @@ async function walkArtifactsFiles(activeRoot) {
|
|
|
8097
8303
|
}
|
|
8098
8304
|
async function appendMigrationLog(activeRoot, lines) {
|
|
8099
8305
|
if (lines.length === 0) return;
|
|
8100
|
-
const logPath =
|
|
8306
|
+
const logPath = path63.join(activeRoot, ".migrations.log");
|
|
8101
8307
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
8102
8308
|
const body = lines.map((l) => `${stamp} v1->v2 ${l}
|
|
8103
8309
|
`).join("");
|
|
@@ -8129,11 +8335,11 @@ var v1ToV2Artifacts = {
|
|
|
8129
8335
|
|
|
8130
8336
|
// src/migrations/v2-to-v3-open-loops.ts
|
|
8131
8337
|
import { promises as fs53 } from "fs";
|
|
8132
|
-
import
|
|
8338
|
+
import path65 from "path";
|
|
8133
8339
|
|
|
8134
8340
|
// src/migrations/v3-proposal.ts
|
|
8135
8341
|
import { promises as fs51 } from "fs";
|
|
8136
|
-
import { z as
|
|
8342
|
+
import { z as z59 } from "zod";
|
|
8137
8343
|
|
|
8138
8344
|
// src/migrations/data/v3-open-loops-proposal.ts
|
|
8139
8345
|
var V3_OPEN_LOOPS_PROPOSAL = {
|
|
@@ -8929,36 +9135,36 @@ var KEBAB_SESSION_ID = SessionIdSchema.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
|
|
|
8929
9135
|
message: "session_id must be kebab-case ([a-z0-9-], no leading/trailing dash)"
|
|
8930
9136
|
});
|
|
8931
9137
|
var ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
8932
|
-
var AbandonedSchema =
|
|
9138
|
+
var AbandonedSchema = z59.object({ note: z59.string().min(1) });
|
|
8933
9139
|
var ProposalNextStepSchema = NextStepSchema.extend({
|
|
8934
9140
|
abandoned: AbandonedSchema.optional()
|
|
8935
9141
|
});
|
|
8936
|
-
var ProposalInitiativeSchema =
|
|
8937
|
-
slug:
|
|
9142
|
+
var ProposalInitiativeSchema = z59.object({
|
|
9143
|
+
slug: z59.string().min(1),
|
|
8938
9144
|
/**
|
|
8939
9145
|
* Real last-touch of the initiative, hand-supplied. Never `Date.now()` and
|
|
8940
9146
|
* never file mtime — several initiatives have mtimes months adrift from
|
|
8941
9147
|
* their true last-touch, and the whole point of back-dating is to preserve
|
|
8942
9148
|
* the staleness signal.
|
|
8943
9149
|
*/
|
|
8944
|
-
ended:
|
|
9150
|
+
ended: z59.string().regex(ISO_INSTANT, {
|
|
8945
9151
|
message: "ended must be an ISO 8601 instant with timezone"
|
|
8946
9152
|
}),
|
|
8947
9153
|
session_id: KEBAB_SESSION_ID,
|
|
8948
|
-
body:
|
|
8949
|
-
next_steps:
|
|
9154
|
+
body: z59.string().min(1),
|
|
9155
|
+
next_steps: z59.array(ProposalNextStepSchema).default([])
|
|
8950
9156
|
});
|
|
8951
|
-
var ProposalSchema =
|
|
9157
|
+
var ProposalSchema = z59.object({
|
|
8952
9158
|
/**
|
|
8953
9159
|
* When the abandonment decision was made. Hand-supplied rather than read
|
|
8954
9160
|
* from the clock: the second session's filename derives from it, and the
|
|
8955
9161
|
* migration keys idempotence on exact paths, so `Date.now()` would mint a
|
|
8956
9162
|
* fresh path — and a duplicate abandonment session — on every re-run.
|
|
8957
9163
|
*/
|
|
8958
|
-
abandoned_at:
|
|
9164
|
+
abandoned_at: z59.string().regex(ISO_INSTANT, {
|
|
8959
9165
|
message: "abandoned_at must be an ISO 8601 instant with timezone"
|
|
8960
9166
|
}).optional(),
|
|
8961
|
-
initiatives:
|
|
9167
|
+
initiatives: z59.array(ProposalInitiativeSchema)
|
|
8962
9168
|
}).superRefine((value, ctx) => {
|
|
8963
9169
|
const withAbandoned = value.initiatives.filter(
|
|
8964
9170
|
(i) => i.next_steps.some((n) => n.abandoned !== void 0)
|
|
@@ -9029,17 +9235,17 @@ async function loadProposal() {
|
|
|
9029
9235
|
|
|
9030
9236
|
// src/migrations/v3-repairs.ts
|
|
9031
9237
|
import { promises as fs52 } from "fs";
|
|
9032
|
-
import
|
|
9238
|
+
import path64 from "path";
|
|
9033
9239
|
var KNOWN_REPAIRS = [
|
|
9034
9240
|
{
|
|
9035
|
-
file:
|
|
9241
|
+
file: path64.join("audiobook", "sessions", "2026-07-23-0549-2026-07-26-book1-m4b-packaging.md"),
|
|
9036
9242
|
kind: "retrack",
|
|
9037
9243
|
why: "track is a branch name ('feat/tts-quality'), not one of canonical|sidecar|adhoc"
|
|
9038
9244
|
},
|
|
9039
9245
|
{
|
|
9040
|
-
file:
|
|
9246
|
+
file: path64.join("voltras-workspace", "sessions", "ARCHIVED-handoff-through-2026-07-15.md"),
|
|
9041
9247
|
kind: "relocate",
|
|
9042
|
-
target:
|
|
9248
|
+
target: path64.join("voltras-workspace", "sources", "ARCHIVED-handoff-through-2026-07-15.md"),
|
|
9043
9249
|
why: "not a session file \u2014 a hand-archived handoff parked in sessions/"
|
|
9044
9250
|
}
|
|
9045
9251
|
];
|
|
@@ -9098,7 +9304,7 @@ async function exists3(p) {
|
|
|
9098
9304
|
async function planRepairs(activeRoot) {
|
|
9099
9305
|
const plans = [];
|
|
9100
9306
|
for (const repair of KNOWN_REPAIRS) {
|
|
9101
|
-
const fullPath =
|
|
9307
|
+
const fullPath = path64.join(activeRoot, repair.file);
|
|
9102
9308
|
if (!await exists3(fullPath)) {
|
|
9103
9309
|
plans.push({ action: "skip", file: repair.file, detail: "already absent" });
|
|
9104
9310
|
continue;
|
|
@@ -9108,7 +9314,7 @@ async function planRepairs(activeRoot) {
|
|
|
9108
9314
|
continue;
|
|
9109
9315
|
}
|
|
9110
9316
|
const target = repair.target;
|
|
9111
|
-
if (await exists3(
|
|
9317
|
+
if (await exists3(path64.join(activeRoot, target))) {
|
|
9112
9318
|
plans.push({
|
|
9113
9319
|
action: "skip",
|
|
9114
9320
|
file: repair.file,
|
|
@@ -9122,7 +9328,7 @@ async function planRepairs(activeRoot) {
|
|
|
9122
9328
|
return plans;
|
|
9123
9329
|
}
|
|
9124
9330
|
async function applyRepair(activeRoot, plan) {
|
|
9125
|
-
const fullPath =
|
|
9331
|
+
const fullPath = path64.join(activeRoot, plan.file);
|
|
9126
9332
|
if (plan.action === "retrack" && plan.repaired !== void 0) {
|
|
9127
9333
|
await writeFrontmatter(
|
|
9128
9334
|
fullPath,
|
|
@@ -9133,15 +9339,15 @@ async function applyRepair(activeRoot, plan) {
|
|
|
9133
9339
|
return;
|
|
9134
9340
|
}
|
|
9135
9341
|
if (plan.action === "relocate") {
|
|
9136
|
-
const target =
|
|
9137
|
-
await fs52.mkdir(
|
|
9342
|
+
const target = path64.join(activeRoot, plan.target);
|
|
9343
|
+
await fs52.mkdir(path64.dirname(target), { recursive: true });
|
|
9138
9344
|
await fs52.rename(fullPath, target);
|
|
9139
9345
|
}
|
|
9140
9346
|
}
|
|
9141
9347
|
|
|
9142
9348
|
// src/migrations/v2-to-v3-open-loops.ts
|
|
9143
9349
|
var HANDOFF_FILE = "handoff.md";
|
|
9144
|
-
var HANDOFF_ARCHIVE =
|
|
9350
|
+
var HANDOFF_ARCHIVE = path65.join("sources", "handoff-archive.md");
|
|
9145
9351
|
async function pathExists(p) {
|
|
9146
9352
|
try {
|
|
9147
9353
|
await fs53.access(p);
|
|
@@ -9160,7 +9366,7 @@ async function listInitiativeSlugs3(activeRoot) {
|
|
|
9160
9366
|
const slugs = [];
|
|
9161
9367
|
for (const entry of entries) {
|
|
9162
9368
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
9163
|
-
if (await pathExists(
|
|
9369
|
+
if (await pathExists(path65.join(activeRoot, entry.name, "brief.md"))) {
|
|
9164
9370
|
slugs.push(entry.name);
|
|
9165
9371
|
}
|
|
9166
9372
|
}
|
|
@@ -9168,9 +9374,9 @@ async function listInitiativeSlugs3(activeRoot) {
|
|
|
9168
9374
|
}
|
|
9169
9375
|
async function maxOnDiskTaskNumber2(initiativeDir, prefix) {
|
|
9170
9376
|
const re = new RegExp(`^${prefix}-(\\d+)\\.yml$`);
|
|
9171
|
-
const tasksDir =
|
|
9377
|
+
const tasksDir = path65.join(initiativeDir, "tasks");
|
|
9172
9378
|
let max = 0;
|
|
9173
|
-
for (const dir of [tasksDir,
|
|
9379
|
+
for (const dir of [tasksDir, path65.join(tasksDir, "archive")]) {
|
|
9174
9380
|
let names;
|
|
9175
9381
|
try {
|
|
9176
9382
|
names = await fs53.readdir(dir);
|
|
@@ -9192,7 +9398,7 @@ async function nextTaskSeq(initiativeDir, frontmatter2) {
|
|
|
9192
9398
|
return max > 0 ? max : null;
|
|
9193
9399
|
}
|
|
9194
9400
|
async function planBrief(initiativeDir, slug) {
|
|
9195
|
-
const raw = await readRawFrontmatter(
|
|
9401
|
+
const raw = await readRawFrontmatter(path65.join(initiativeDir, "brief.md"));
|
|
9196
9402
|
const repaired = repairBriefFrontmatter(slug, raw.frontmatter);
|
|
9197
9403
|
const taskSeq = await nextTaskSeq(initiativeDir, repaired.frontmatter);
|
|
9198
9404
|
if (taskSeq === null && repaired.applied.length === 0) return { write: null };
|
|
@@ -9209,8 +9415,8 @@ async function planBrief(initiativeDir, slug) {
|
|
|
9209
9415
|
};
|
|
9210
9416
|
}
|
|
9211
9417
|
async function planHandoff(initiativeDir) {
|
|
9212
|
-
if (!await pathExists(
|
|
9213
|
-
if (await pathExists(
|
|
9418
|
+
if (!await pathExists(path65.join(initiativeDir, HANDOFF_FILE))) return "absent";
|
|
9419
|
+
if (await pathExists(path65.join(initiativeDir, HANDOFF_ARCHIVE))) return "archive-exists";
|
|
9214
9420
|
return "archive-and-remove";
|
|
9215
9421
|
}
|
|
9216
9422
|
function buildOpenSession(entry) {
|
|
@@ -9300,7 +9506,7 @@ function draftSessions(entry, abandonedAt) {
|
|
|
9300
9506
|
return [open, buildAbandonSession(entry, open.stem, abandonedAt)];
|
|
9301
9507
|
}
|
|
9302
9508
|
async function planInitiative(activeRoot, slug, entry, abandonedAt) {
|
|
9303
|
-
const initiativeDir =
|
|
9509
|
+
const initiativeDir = path65.join(activeRoot, slug);
|
|
9304
9510
|
const brief = await planBrief(initiativeDir, slug);
|
|
9305
9511
|
const base = {
|
|
9306
9512
|
slug,
|
|
@@ -9339,9 +9545,9 @@ async function planV2ToV3(activeRoot) {
|
|
|
9339
9545
|
return { proposalOrigin: origin, initiatives, repairs: await planRepairs(activeRoot) };
|
|
9340
9546
|
}
|
|
9341
9547
|
async function archiveHandoff(initiativeDir) {
|
|
9342
|
-
const source =
|
|
9343
|
-
const target =
|
|
9344
|
-
await fs53.mkdir(
|
|
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 });
|
|
9345
9551
|
await fs53.copyFile(source, target);
|
|
9346
9552
|
await fs53.rm(source);
|
|
9347
9553
|
}
|
|
@@ -9360,15 +9566,15 @@ async function writePlannedSession(activeRoot, slug, session) {
|
|
|
9360
9566
|
});
|
|
9361
9567
|
}
|
|
9362
9568
|
async function applyInitiative(activeRoot, plan) {
|
|
9363
|
-
const initiativeDir =
|
|
9364
|
-
await withFileLock(
|
|
9569
|
+
const initiativeDir = path65.join(activeRoot, plan.slug);
|
|
9570
|
+
await withFileLock(path65.join(initiativeDir, ".lock"), async () => {
|
|
9365
9571
|
for (const session of plan.sessions) {
|
|
9366
9572
|
if (session.exists) continue;
|
|
9367
9573
|
await writePlannedSession(activeRoot, plan.slug, session);
|
|
9368
9574
|
}
|
|
9369
9575
|
if (plan.brief !== null) {
|
|
9370
9576
|
await writeFrontmatter(
|
|
9371
|
-
|
|
9577
|
+
path65.join(initiativeDir, "brief.md"),
|
|
9372
9578
|
plan.brief.frontmatter,
|
|
9373
9579
|
plan.brief.body,
|
|
9374
9580
|
BriefFrontmatterSchema
|
|
@@ -9399,12 +9605,12 @@ var v2ToV3OpenLoops = {
|
|
|
9399
9605
|
|
|
9400
9606
|
// src/migrations/v3-to-v4-worktrees.ts
|
|
9401
9607
|
import { promises as fs54 } from "fs";
|
|
9402
|
-
import
|
|
9608
|
+
import path66 from "path";
|
|
9403
9609
|
import matter5 from "gray-matter";
|
|
9404
9610
|
import YAML5 from "yaml";
|
|
9405
9611
|
function normalize(value) {
|
|
9406
|
-
const expanded = value.startsWith("~") ?
|
|
9407
|
-
return
|
|
9612
|
+
const expanded = value.startsWith("~") ? path66.join(process.env.HOME ?? "", value.slice(1)) : value;
|
|
9613
|
+
return path66.resolve(expanded);
|
|
9408
9614
|
}
|
|
9409
9615
|
function toEntries(raw) {
|
|
9410
9616
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
@@ -9451,7 +9657,7 @@ async function readArtifacts2(file) {
|
|
|
9451
9657
|
}
|
|
9452
9658
|
}
|
|
9453
9659
|
async function migrateOne2(initiativeDir) {
|
|
9454
|
-
const briefPath =
|
|
9660
|
+
const briefPath = path66.join(initiativeDir, "brief.md");
|
|
9455
9661
|
let raw;
|
|
9456
9662
|
try {
|
|
9457
9663
|
raw = await fs54.readFile(briefPath, "utf8");
|
|
@@ -9464,7 +9670,7 @@ async function migrateOne2(initiativeDir) {
|
|
|
9464
9670
|
const incoming = toEntries(data.worktrees);
|
|
9465
9671
|
delete data.worktrees;
|
|
9466
9672
|
if (incoming.length > 0) {
|
|
9467
|
-
const artifactsPath2 =
|
|
9673
|
+
const artifactsPath2 = path66.join(initiativeDir, "artifacts.yml");
|
|
9468
9674
|
const current = await readArtifacts2(artifactsPath2);
|
|
9469
9675
|
await writeYaml(
|
|
9470
9676
|
artifactsPath2,
|
|
@@ -9489,9 +9695,9 @@ async function initiativeDirs(activeRoot) {
|
|
|
9489
9695
|
}
|
|
9490
9696
|
for (const entry of entries) {
|
|
9491
9697
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
9492
|
-
const dir =
|
|
9698
|
+
const dir = path66.join(activeRoot, entry.name);
|
|
9493
9699
|
try {
|
|
9494
|
-
await fs54.access(
|
|
9700
|
+
await fs54.access(path66.join(dir, "brief.md"));
|
|
9495
9701
|
out.push(dir);
|
|
9496
9702
|
} catch {
|
|
9497
9703
|
}
|
|
@@ -9506,12 +9712,12 @@ var v3ToV4Worktrees = {
|
|
|
9506
9712
|
const moved = [];
|
|
9507
9713
|
for (const dir of await initiativeDirs(activeRoot)) {
|
|
9508
9714
|
const count = await migrateOne2(dir);
|
|
9509
|
-
if (count > 0) moved.push(`${
|
|
9715
|
+
if (count > 0) moved.push(`${path66.basename(dir)} ${count} worktree(s)`);
|
|
9510
9716
|
}
|
|
9511
9717
|
if (moved.length === 0) return;
|
|
9512
9718
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
9513
9719
|
await fs54.appendFile(
|
|
9514
|
-
|
|
9720
|
+
path66.join(activeRoot, ".migrations.log"),
|
|
9515
9721
|
moved.map((line) => `${stamp} v3->v4 ${line}
|
|
9516
9722
|
`).join(""),
|
|
9517
9723
|
"utf8"
|
|
@@ -9564,10 +9770,10 @@ var SCHEMA_VERSION_FILENAME = ".schema-version";
|
|
|
9564
9770
|
var schemaVersionPath = (activeRoot) => join(activeRoot, SCHEMA_VERSION_FILENAME);
|
|
9565
9771
|
var isNodeErrnoException = (err) => typeof err === "object" && err !== null && "code" in err;
|
|
9566
9772
|
async function readSchemaVersion(activeRoot) {
|
|
9567
|
-
const
|
|
9773
|
+
const path68 = schemaVersionPath(activeRoot);
|
|
9568
9774
|
let raw;
|
|
9569
9775
|
try {
|
|
9570
|
-
raw = await readFile(
|
|
9776
|
+
raw = await readFile(path68, "utf8");
|
|
9571
9777
|
} catch (err) {
|
|
9572
9778
|
if (isNodeErrnoException(err) && err.code === "ENOENT") {
|
|
9573
9779
|
return 0;
|
|
@@ -9577,13 +9783,13 @@ async function readSchemaVersion(activeRoot) {
|
|
|
9577
9783
|
const trimmed = raw.trim();
|
|
9578
9784
|
if (trimmed === "" || !/^\d+$/.test(trimmed)) {
|
|
9579
9785
|
throw new Error(
|
|
9580
|
-
`Invalid schema version in ${
|
|
9786
|
+
`Invalid schema version in ${path68}: expected a positive integer, got ${JSON.stringify(raw)}`
|
|
9581
9787
|
);
|
|
9582
9788
|
}
|
|
9583
9789
|
const parsed = Number(trimmed);
|
|
9584
9790
|
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
9585
9791
|
throw new Error(
|
|
9586
|
-
`Invalid schema version in ${
|
|
9792
|
+
`Invalid schema version in ${path68}: expected a positive integer, got ${JSON.stringify(raw)}`
|
|
9587
9793
|
);
|
|
9588
9794
|
}
|
|
9589
9795
|
return parsed;
|
|
@@ -9596,10 +9802,10 @@ async function writeSchemaVersion(activeRoot, version) {
|
|
|
9596
9802
|
`, "utf8");
|
|
9597
9803
|
}
|
|
9598
9804
|
async function readRawSchemaVersion(activeRoot) {
|
|
9599
|
-
const
|
|
9805
|
+
const path68 = schemaVersionPath(activeRoot);
|
|
9600
9806
|
let raw;
|
|
9601
9807
|
try {
|
|
9602
|
-
raw = await readFile(
|
|
9808
|
+
raw = await readFile(path68, "utf8");
|
|
9603
9809
|
} catch (err) {
|
|
9604
9810
|
if (isNodeErrnoException(err) && err.code === "ENOENT") {
|
|
9605
9811
|
return { present: false };
|
|
@@ -9609,13 +9815,13 @@ async function readRawSchemaVersion(activeRoot) {
|
|
|
9609
9815
|
const trimmed = raw.trim();
|
|
9610
9816
|
if (trimmed === "" || !/^\d+$/.test(trimmed)) {
|
|
9611
9817
|
throw new Error(
|
|
9612
|
-
`Invalid schema version in ${
|
|
9818
|
+
`Invalid schema version in ${path68}: expected a non-negative integer, got ${JSON.stringify(raw)}`
|
|
9613
9819
|
);
|
|
9614
9820
|
}
|
|
9615
9821
|
const parsed = Number(trimmed);
|
|
9616
9822
|
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
9617
9823
|
throw new Error(
|
|
9618
|
-
`Invalid schema version in ${
|
|
9824
|
+
`Invalid schema version in ${path68}: expected a non-negative integer, got ${JSON.stringify(raw)}`
|
|
9619
9825
|
);
|
|
9620
9826
|
}
|
|
9621
9827
|
return { present: true, version: parsed };
|
|
@@ -10888,20 +11094,20 @@ async function runUninstall(deps = {}) {
|
|
|
10888
11094
|
}
|
|
10889
11095
|
|
|
10890
11096
|
// src/commands/setup.ts
|
|
10891
|
-
var
|
|
10892
|
-
update:
|
|
10893
|
-
yes:
|
|
11097
|
+
var ArgsSchema50 = z60.object({
|
|
11098
|
+
update: z60.boolean().optional(),
|
|
11099
|
+
yes: z60.boolean().optional()
|
|
10894
11100
|
});
|
|
10895
|
-
var StepSchema =
|
|
10896
|
-
name:
|
|
10897
|
-
ok:
|
|
10898
|
-
done:
|
|
10899
|
-
message:
|
|
10900
|
-
error:
|
|
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()
|
|
10901
11107
|
});
|
|
10902
|
-
var
|
|
10903
|
-
banner:
|
|
10904
|
-
steps:
|
|
11108
|
+
var ResultSchema46 = z60.object({
|
|
11109
|
+
banner: z60.string(),
|
|
11110
|
+
steps: z60.array(StepSchema)
|
|
10905
11111
|
});
|
|
10906
11112
|
function printStep(step) {
|
|
10907
11113
|
if (step.ok) {
|
|
@@ -10918,8 +11124,8 @@ function printStep(step) {
|
|
|
10918
11124
|
var setup_default = defineCommand({
|
|
10919
11125
|
name: "setup",
|
|
10920
11126
|
description: "Interactive wizard: verifies Node, scaffolds directories, registers the MCP server, and optionally starts the daemon and walks through ingestion.",
|
|
10921
|
-
args:
|
|
10922
|
-
result:
|
|
11127
|
+
args: ArgsSchema50,
|
|
11128
|
+
result: ResultSchema46,
|
|
10923
11129
|
cli: {
|
|
10924
11130
|
options: {
|
|
10925
11131
|
update: {
|
|
@@ -10954,25 +11160,25 @@ var setup_default = defineCommand({
|
|
|
10954
11160
|
});
|
|
10955
11161
|
|
|
10956
11162
|
// src/commands/uninstall.ts
|
|
10957
|
-
import { z as
|
|
10958
|
-
var
|
|
10959
|
-
yes:
|
|
11163
|
+
import { z as z61 } from "zod";
|
|
11164
|
+
var ArgsSchema51 = z61.object({
|
|
11165
|
+
yes: z61.boolean().optional()
|
|
10960
11166
|
});
|
|
10961
|
-
var StepSchema2 =
|
|
10962
|
-
name:
|
|
10963
|
-
done:
|
|
10964
|
-
message:
|
|
10965
|
-
error:
|
|
11167
|
+
var StepSchema2 = z61.object({
|
|
11168
|
+
name: z61.string(),
|
|
11169
|
+
done: z61.boolean(),
|
|
11170
|
+
message: z61.string().optional(),
|
|
11171
|
+
error: z61.string().optional()
|
|
10966
11172
|
});
|
|
10967
|
-
var
|
|
10968
|
-
steps:
|
|
10969
|
-
activeRootPreservedAt:
|
|
11173
|
+
var ResultSchema47 = z61.object({
|
|
11174
|
+
steps: z61.array(StepSchema2),
|
|
11175
|
+
activeRootPreservedAt: z61.string()
|
|
10970
11176
|
});
|
|
10971
11177
|
var uninstall_default = defineCommand({
|
|
10972
11178
|
name: "uninstall",
|
|
10973
11179
|
description: "Reverse what setup did: remove the skill, stop the daemon, unregister MCP. Preserves the active root.",
|
|
10974
|
-
args:
|
|
10975
|
-
result:
|
|
11180
|
+
args: ArgsSchema51,
|
|
11181
|
+
result: ResultSchema47,
|
|
10976
11182
|
cli: {
|
|
10977
11183
|
options: {
|
|
10978
11184
|
yes: {
|
|
@@ -11002,7 +11208,7 @@ var uninstall_default = defineCommand({
|
|
|
11002
11208
|
});
|
|
11003
11209
|
|
|
11004
11210
|
// src/commands/doctor.ts
|
|
11005
|
-
import { z as
|
|
11211
|
+
import { z as z62 } from "zod";
|
|
11006
11212
|
|
|
11007
11213
|
// src/doctor.ts
|
|
11008
11214
|
import { promises as fsp4 } from "fs";
|
|
@@ -11410,15 +11616,15 @@ async function runDoctor(deps = {}) {
|
|
|
11410
11616
|
}
|
|
11411
11617
|
|
|
11412
11618
|
// src/commands/doctor.ts
|
|
11413
|
-
var
|
|
11414
|
-
var CheckSchema =
|
|
11415
|
-
name:
|
|
11416
|
-
status:
|
|
11417
|
-
detail:
|
|
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()
|
|
11418
11624
|
});
|
|
11419
|
-
var
|
|
11420
|
-
ok:
|
|
11421
|
-
checks:
|
|
11625
|
+
var ResultSchema48 = z62.object({
|
|
11626
|
+
ok: z62.boolean(),
|
|
11627
|
+
checks: z62.array(CheckSchema)
|
|
11422
11628
|
});
|
|
11423
11629
|
function badge(status) {
|
|
11424
11630
|
if (status === "ok") return color.green("OK ");
|
|
@@ -11428,8 +11634,8 @@ function badge(status) {
|
|
|
11428
11634
|
var doctor_default = defineCommand({
|
|
11429
11635
|
name: "doctor",
|
|
11430
11636
|
description: "Health-check the install: Node, active root, daemon, MCP registration, skill, and supervision.",
|
|
11431
|
-
args:
|
|
11432
|
-
result:
|
|
11637
|
+
args: ArgsSchema52,
|
|
11638
|
+
result: ResultSchema48,
|
|
11433
11639
|
async run(_args, ctx) {
|
|
11434
11640
|
const report2 = await runDoctor();
|
|
11435
11641
|
if (ctx.format !== "json") {
|
|
@@ -11446,34 +11652,34 @@ var doctor_default = defineCommand({
|
|
|
11446
11652
|
});
|
|
11447
11653
|
|
|
11448
11654
|
// src/commands/migrate.ts
|
|
11449
|
-
import { z as
|
|
11450
|
-
var
|
|
11451
|
-
dry_run:
|
|
11452
|
-
apply:
|
|
11453
|
-
});
|
|
11454
|
-
var SessionSchema =
|
|
11455
|
-
kind:
|
|
11456
|
-
action:
|
|
11457
|
-
file:
|
|
11458
|
-
ended:
|
|
11459
|
-
loops:
|
|
11460
|
-
resolves:
|
|
11461
|
-
});
|
|
11462
|
-
var InitiativeSchema =
|
|
11463
|
-
slug:
|
|
11464
|
-
sessions:
|
|
11465
|
-
task_seq_backfill:
|
|
11466
|
-
brief_repairs:
|
|
11467
|
-
brief_blocked:
|
|
11468
|
-
handoff:
|
|
11469
|
-
note:
|
|
11470
|
-
});
|
|
11471
|
-
var
|
|
11472
|
-
applied:
|
|
11473
|
-
proposal:
|
|
11474
|
-
initiatives:
|
|
11475
|
-
repairs:
|
|
11476
|
-
uncovered:
|
|
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()
|
|
11676
|
+
});
|
|
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())
|
|
11477
11683
|
});
|
|
11478
11684
|
function describe2(plan, applied) {
|
|
11479
11685
|
const initiatives = plan.initiatives.map((i) => ({
|
|
@@ -11549,8 +11755,8 @@ function render(result) {
|
|
|
11549
11755
|
var migrate_default = defineCommand({
|
|
11550
11756
|
name: "migrate",
|
|
11551
11757
|
description: "Preview (or apply) the pending v2\u2192v3 open-loops migration.",
|
|
11552
|
-
args:
|
|
11553
|
-
result:
|
|
11758
|
+
args: ArgsSchema53,
|
|
11759
|
+
result: ResultSchema49,
|
|
11554
11760
|
cli: {
|
|
11555
11761
|
options: {
|
|
11556
11762
|
dry_run: { long: "--dry-run", description: "Report what would change; write nothing" },
|
|
@@ -11585,18 +11791,18 @@ var migrate_default = defineCommand({
|
|
|
11585
11791
|
|
|
11586
11792
|
// src/commands/sync.ts
|
|
11587
11793
|
import os7 from "os";
|
|
11588
|
-
import { z as
|
|
11589
|
-
var
|
|
11590
|
-
message:
|
|
11591
|
-
require_clean:
|
|
11592
|
-
});
|
|
11593
|
-
var
|
|
11594
|
-
branch:
|
|
11595
|
-
committed:
|
|
11596
|
-
committed_files:
|
|
11597
|
-
rebased:
|
|
11598
|
-
pushed:
|
|
11599
|
-
summary:
|
|
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()
|
|
11600
11806
|
});
|
|
11601
11807
|
async function git(root, args) {
|
|
11602
11808
|
return getGitRunner()("git", ["-C", root, ...args]);
|
|
@@ -11698,8 +11904,8 @@ async function push(root) {
|
|
|
11698
11904
|
var sync_default = defineCommand({
|
|
11699
11905
|
name: "sync",
|
|
11700
11906
|
description: "Sync the active root over git: auto-commit local edits, pull --rebase, then push.",
|
|
11701
|
-
args:
|
|
11702
|
-
result:
|
|
11907
|
+
args: ArgsSchema54,
|
|
11908
|
+
result: ResultSchema50,
|
|
11703
11909
|
cli: {
|
|
11704
11910
|
options: {
|
|
11705
11911
|
message: {
|
|
@@ -11793,6 +11999,7 @@ var ALL_COMMANDS = [
|
|
|
11793
11999
|
audit_default,
|
|
11794
12000
|
list_default,
|
|
11795
12001
|
context_graph_default,
|
|
12002
|
+
search_default,
|
|
11796
12003
|
// discover / triage
|
|
11797
12004
|
discover_default,
|
|
11798
12005
|
fold_default,
|
|
@@ -11833,14 +12040,14 @@ import { readCommanderOption } from "@titan-design/registry";
|
|
|
11833
12040
|
|
|
11834
12041
|
// src/utils/usage-log.ts
|
|
11835
12042
|
import { promises as fs56 } from "fs";
|
|
11836
|
-
import
|
|
12043
|
+
import path67 from "path";
|
|
11837
12044
|
function usageLogPath() {
|
|
11838
|
-
return
|
|
12045
|
+
return path67.join(getStateRoot(), "usage.jsonl");
|
|
11839
12046
|
}
|
|
11840
12047
|
async function appendUsage(rec) {
|
|
11841
12048
|
try {
|
|
11842
12049
|
const file = usageLogPath();
|
|
11843
|
-
await fs56.mkdir(
|
|
12050
|
+
await fs56.mkdir(path67.dirname(file), { recursive: true });
|
|
11844
12051
|
await fs56.appendFile(file, JSON.stringify(rec) + "\n", "utf8");
|
|
11845
12052
|
} catch {
|
|
11846
12053
|
}
|
|
@@ -12012,7 +12219,7 @@ function attachCommand(root, cmd) {
|
|
|
12012
12219
|
function buildProgram() {
|
|
12013
12220
|
const program = new Command();
|
|
12014
12221
|
program.exitOverride();
|
|
12015
|
-
program.name("active-work").description("active-work CLI \u2014 durable workspace state for engineering work").version(
|
|
12222
|
+
program.name("active-work").description("active-work CLI \u2014 durable workspace state for engineering work").version(BUILD_VERSION).option("--json", "emit machine-readable JSON envelope on stdout").addHelpText(
|
|
12016
12223
|
"after",
|
|
12017
12224
|
"\nRun `active-work <command> --help` for command-specific options.\nTip: `aw [slug]` launches Claude with the bootstrap prompt.\n"
|
|
12018
12225
|
);
|