@hasna/todos 0.11.68 → 0.11.70
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/commands/plan-template-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts +1 -0
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +639 -240
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +527 -230
- package/dist/lib/plan-artifacts.d.ts +69 -0
- package/dist/lib/plan-artifacts.d.ts.map +1 -0
- package/dist/release-provenance.json +3 -3
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -12448,6 +12448,7 @@ __export(exports_helpers, {
|
|
|
12448
12448
|
resolveTaskId: () => resolveTaskId,
|
|
12449
12449
|
resolveExplicitProject: () => resolveExplicitProject,
|
|
12450
12450
|
priorityColors: () => priorityColors,
|
|
12451
|
+
printJson: () => printJson,
|
|
12451
12452
|
output: () => output,
|
|
12452
12453
|
normalizeStatusList: () => normalizeStatusList,
|
|
12453
12454
|
normalizeStatus: () => normalizeStatus,
|
|
@@ -12460,6 +12461,7 @@ __export(exports_helpers, {
|
|
|
12460
12461
|
});
|
|
12461
12462
|
import chalk from "chalk";
|
|
12462
12463
|
import { execSync } from "child_process";
|
|
12464
|
+
import { writeSync } from "fs";
|
|
12463
12465
|
import { resolve as resolve8 } from "path";
|
|
12464
12466
|
function handleError(e) {
|
|
12465
12467
|
console.error(chalk.red(e instanceof Error ? e.message : String(e)));
|
|
@@ -12556,9 +12558,35 @@ function normalizeStatusList(statuses) {
|
|
|
12556
12558
|
return statuses.map(normalizeStatus);
|
|
12557
12559
|
return normalizeStatus(statuses);
|
|
12558
12560
|
}
|
|
12561
|
+
function writeStdoutSync(text) {
|
|
12562
|
+
const buffer = Buffer.from(text);
|
|
12563
|
+
let offset = 0;
|
|
12564
|
+
while (offset < buffer.length) {
|
|
12565
|
+
try {
|
|
12566
|
+
const written = writeSync(1, buffer, offset, buffer.length - offset);
|
|
12567
|
+
if (written <= 0)
|
|
12568
|
+
throw new Error("Unable to write complete stdout payload");
|
|
12569
|
+
offset += written;
|
|
12570
|
+
} catch (error) {
|
|
12571
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
|
|
12572
|
+
if (code === "EPIPE") {
|
|
12573
|
+
return;
|
|
12574
|
+
}
|
|
12575
|
+
if (code === "EAGAIN" || code === "EWOULDBLOCK" || code === "EINTR") {
|
|
12576
|
+
Atomics.wait(stdoutRetrySignal, 0, 0, 1);
|
|
12577
|
+
continue;
|
|
12578
|
+
}
|
|
12579
|
+
throw error;
|
|
12580
|
+
}
|
|
12581
|
+
}
|
|
12582
|
+
}
|
|
12583
|
+
function printJson(data) {
|
|
12584
|
+
writeStdoutSync(`${JSON.stringify(data, null, 2)}
|
|
12585
|
+
`);
|
|
12586
|
+
}
|
|
12559
12587
|
function output(data, jsonMode) {
|
|
12560
12588
|
if (jsonMode) {
|
|
12561
|
-
|
|
12589
|
+
printJson(data);
|
|
12562
12590
|
}
|
|
12563
12591
|
}
|
|
12564
12592
|
function formatTaskLine(t) {
|
|
@@ -12570,11 +12598,13 @@ function formatTaskLine(t) {
|
|
|
12570
12598
|
const plan = t.plan_id ? chalk.magenta(` [plan:${t.plan_id.slice(0, 8)}]`) : "";
|
|
12571
12599
|
return `${chalk.dim(t.id.slice(0, 8))} ${statusFn(t.status.padEnd(11))} ${priorityFn(t.priority.padEnd(8))} ${t.title}${assigned}${lock}${tags}${plan}`;
|
|
12572
12600
|
}
|
|
12573
|
-
var statusColors, priorityColors;
|
|
12601
|
+
var stdoutRetryBuffer, stdoutRetrySignal, statusColors, priorityColors;
|
|
12574
12602
|
var init_helpers = __esm(() => {
|
|
12575
12603
|
init_database();
|
|
12576
12604
|
init_projects();
|
|
12577
12605
|
init_package_version();
|
|
12606
|
+
stdoutRetryBuffer = new SharedArrayBuffer(4);
|
|
12607
|
+
stdoutRetrySignal = new Int32Array(stdoutRetryBuffer);
|
|
12578
12608
|
statusColors = {
|
|
12579
12609
|
pending: chalk.yellow,
|
|
12580
12610
|
in_progress: chalk.blue,
|
|
@@ -13651,6 +13681,299 @@ var init_task_commands = __esm(() => {
|
|
|
13651
13681
|
init_types();
|
|
13652
13682
|
});
|
|
13653
13683
|
|
|
13684
|
+
// src/lib/plan-artifacts.ts
|
|
13685
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
13686
|
+
import { join as join7, resolve as resolve10 } from "path";
|
|
13687
|
+
function assertSafePathSegment(value, label) {
|
|
13688
|
+
const trimmed = value.trim();
|
|
13689
|
+
if (!trimmed || trimmed === "." || trimmed === ".." || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
13690
|
+
throw new Error(`Invalid ${label} for plan artifact path`);
|
|
13691
|
+
}
|
|
13692
|
+
if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {
|
|
13693
|
+
throw new Error(`Invalid ${label} for plan artifact path`);
|
|
13694
|
+
}
|
|
13695
|
+
return trimmed;
|
|
13696
|
+
}
|
|
13697
|
+
function frontmatterScalar(value) {
|
|
13698
|
+
return JSON.stringify(value);
|
|
13699
|
+
}
|
|
13700
|
+
function parseFrontmatterScalar(value) {
|
|
13701
|
+
const trimmed = value.trim();
|
|
13702
|
+
if (trimmed === "null")
|
|
13703
|
+
return null;
|
|
13704
|
+
try {
|
|
13705
|
+
const parsed = JSON.parse(trimmed);
|
|
13706
|
+
if (parsed === null || typeof parsed === "string")
|
|
13707
|
+
return parsed;
|
|
13708
|
+
} catch {}
|
|
13709
|
+
return trimmed.replace(/^["']|["']$/g, "") || null;
|
|
13710
|
+
}
|
|
13711
|
+
function markdownEscape(text) {
|
|
13712
|
+
return text.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
13713
|
+
}
|
|
13714
|
+
function markdownLine(text) {
|
|
13715
|
+
return markdownEscape(text).replace(/\s+/g, " ").trim();
|
|
13716
|
+
}
|
|
13717
|
+
function projectSlugMatches(project, ref) {
|
|
13718
|
+
const normalized = slugify(ref);
|
|
13719
|
+
return Boolean(normalized) && (project.task_list_id === normalized || slugify(project.name) === normalized);
|
|
13720
|
+
}
|
|
13721
|
+
function resolvePlanArtifactProject(input) {
|
|
13722
|
+
const db = input.db || getDatabase();
|
|
13723
|
+
const ref = input.project_id || input.project_ref;
|
|
13724
|
+
if (!ref)
|
|
13725
|
+
throw new Error("Plan artifacts require a project id or project reference");
|
|
13726
|
+
const byPath = getProjectByPath(resolve10(ref), db);
|
|
13727
|
+
if (byPath)
|
|
13728
|
+
return byPath;
|
|
13729
|
+
const resolvedId = resolvePartialId(db, "projects", ref);
|
|
13730
|
+
if (resolvedId) {
|
|
13731
|
+
const project2 = getProject(resolvedId, db);
|
|
13732
|
+
if (project2)
|
|
13733
|
+
return project2;
|
|
13734
|
+
}
|
|
13735
|
+
const project = listProjects(db).find((candidate) => projectSlugMatches(candidate, ref));
|
|
13736
|
+
if (project)
|
|
13737
|
+
return project;
|
|
13738
|
+
throw new Error(`Project not found for plan artifacts: ${ref}`);
|
|
13739
|
+
}
|
|
13740
|
+
function resolvePlanArtifactPaths(input) {
|
|
13741
|
+
const project = resolvePlanArtifactProject(input);
|
|
13742
|
+
const projectId = assertSafePathSegment(project.id, "project id");
|
|
13743
|
+
const projectRoot = resolve10(project.path);
|
|
13744
|
+
const directory = join7(projectRoot, ".hasna", "todos", "plans", projectId);
|
|
13745
|
+
const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
|
|
13746
|
+
return {
|
|
13747
|
+
project_id: project.id,
|
|
13748
|
+
project_root: projectRoot,
|
|
13749
|
+
directory,
|
|
13750
|
+
file_path: planId ? join7(directory, `${planId}.md`) : directory
|
|
13751
|
+
};
|
|
13752
|
+
}
|
|
13753
|
+
function buildPlanArtifactSnapshot(plan, tasks = [], artifactUpdatedAt = new Date().toISOString()) {
|
|
13754
|
+
if (!plan.project_id)
|
|
13755
|
+
throw new Error("Plan artifacts require a project-scoped plan");
|
|
13756
|
+
const taskReferences = tasks.map((task) => ({
|
|
13757
|
+
task_id: task.id,
|
|
13758
|
+
title: task.title,
|
|
13759
|
+
status: task.status,
|
|
13760
|
+
priority: task.priority
|
|
13761
|
+
}));
|
|
13762
|
+
const body = renderPlanArtifactBody(plan, taskReferences);
|
|
13763
|
+
return {
|
|
13764
|
+
metadata: {
|
|
13765
|
+
schema: PLAN_MARKDOWN_SCHEMA,
|
|
13766
|
+
plan_id: plan.id,
|
|
13767
|
+
project_id: plan.project_id,
|
|
13768
|
+
task_list_id: plan.task_list_id ?? null,
|
|
13769
|
+
agent_id: plan.agent_id ?? null,
|
|
13770
|
+
stable_id: plan.id,
|
|
13771
|
+
name: plan.name,
|
|
13772
|
+
status: plan.status,
|
|
13773
|
+
created_at: plan.created_at,
|
|
13774
|
+
updated_at: plan.updated_at,
|
|
13775
|
+
artifact_updated_at: artifactUpdatedAt
|
|
13776
|
+
},
|
|
13777
|
+
task_references: taskReferences,
|
|
13778
|
+
body
|
|
13779
|
+
};
|
|
13780
|
+
}
|
|
13781
|
+
function renderPlanArtifactBody(plan, tasks) {
|
|
13782
|
+
const lines = [`# ${markdownLine(plan.name) || plan.id}`, ""];
|
|
13783
|
+
if (plan.description?.trim()) {
|
|
13784
|
+
lines.push(markdownEscape(plan.description), "");
|
|
13785
|
+
}
|
|
13786
|
+
lines.push("## Tasks", "");
|
|
13787
|
+
if (tasks.length === 0) {
|
|
13788
|
+
lines.push("_No tasks are currently attached to this plan._", "");
|
|
13789
|
+
} else {
|
|
13790
|
+
for (const task of tasks) {
|
|
13791
|
+
const check = task.status === "completed" ? "x" : " ";
|
|
13792
|
+
lines.push(`- [${check}] ${markdownLine(task.title) || task.task_id}`);
|
|
13793
|
+
lines.push(` <!-- todos: task_id=${task.task_id} status=${task.status} priority=${task.priority} -->`);
|
|
13794
|
+
}
|
|
13795
|
+
lines.push("");
|
|
13796
|
+
}
|
|
13797
|
+
return lines.join(`
|
|
13798
|
+
`);
|
|
13799
|
+
}
|
|
13800
|
+
function renderPlanArtifactMarkdown(snapshot) {
|
|
13801
|
+
const metadata = snapshot.metadata;
|
|
13802
|
+
const lines = [
|
|
13803
|
+
"---",
|
|
13804
|
+
`schema: ${frontmatterScalar(metadata.schema)}`,
|
|
13805
|
+
`plan_id: ${frontmatterScalar(metadata.plan_id)}`,
|
|
13806
|
+
`project_id: ${frontmatterScalar(metadata.project_id)}`,
|
|
13807
|
+
`task_list_id: ${frontmatterScalar(metadata.task_list_id)}`,
|
|
13808
|
+
`agent_id: ${frontmatterScalar(metadata.agent_id)}`,
|
|
13809
|
+
`stable_id: ${frontmatterScalar(metadata.stable_id)}`,
|
|
13810
|
+
`name: ${frontmatterScalar(metadata.name)}`,
|
|
13811
|
+
`status: ${frontmatterScalar(metadata.status)}`,
|
|
13812
|
+
`created_at: ${frontmatterScalar(metadata.created_at)}`,
|
|
13813
|
+
`updated_at: ${frontmatterScalar(metadata.updated_at)}`,
|
|
13814
|
+
`artifact_updated_at: ${frontmatterScalar(metadata.artifact_updated_at)}`,
|
|
13815
|
+
"---",
|
|
13816
|
+
"",
|
|
13817
|
+
snapshot.body
|
|
13818
|
+
];
|
|
13819
|
+
return `${lines.join(`
|
|
13820
|
+
`).replace(/\n{3,}/g, `
|
|
13821
|
+
|
|
13822
|
+
`).trimEnd()}
|
|
13823
|
+
`;
|
|
13824
|
+
}
|
|
13825
|
+
function parsePlanArtifactMarkdown(markdown) {
|
|
13826
|
+
const match = markdown.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
13827
|
+
if (!match)
|
|
13828
|
+
throw new Error("Invalid plan artifact: missing frontmatter");
|
|
13829
|
+
const rawMetadata = {};
|
|
13830
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
13831
|
+
const separator = line.indexOf(":");
|
|
13832
|
+
if (separator === -1)
|
|
13833
|
+
continue;
|
|
13834
|
+
const key = line.slice(0, separator).trim();
|
|
13835
|
+
const value = line.slice(separator + 1);
|
|
13836
|
+
rawMetadata[key] = parseFrontmatterScalar(value);
|
|
13837
|
+
}
|
|
13838
|
+
if (rawMetadata.schema !== PLAN_MARKDOWN_SCHEMA) {
|
|
13839
|
+
throw new Error(`Unsupported plan artifact schema: ${rawMetadata.schema ?? "unknown"}`);
|
|
13840
|
+
}
|
|
13841
|
+
const required = ["plan_id", "project_id", "stable_id", "name", "status", "created_at", "updated_at", "artifact_updated_at"];
|
|
13842
|
+
for (const key of required) {
|
|
13843
|
+
if (!rawMetadata[key])
|
|
13844
|
+
throw new Error(`Invalid plan artifact: missing ${key}`);
|
|
13845
|
+
}
|
|
13846
|
+
const body = match[2] ?? "";
|
|
13847
|
+
return {
|
|
13848
|
+
metadata: {
|
|
13849
|
+
schema: PLAN_MARKDOWN_SCHEMA,
|
|
13850
|
+
plan_id: rawMetadata.plan_id,
|
|
13851
|
+
project_id: rawMetadata.project_id,
|
|
13852
|
+
task_list_id: rawMetadata.task_list_id ?? null,
|
|
13853
|
+
agent_id: rawMetadata.agent_id ?? null,
|
|
13854
|
+
stable_id: rawMetadata.stable_id,
|
|
13855
|
+
name: rawMetadata.name,
|
|
13856
|
+
status: rawMetadata.status,
|
|
13857
|
+
created_at: rawMetadata.created_at,
|
|
13858
|
+
updated_at: rawMetadata.updated_at,
|
|
13859
|
+
artifact_updated_at: rawMetadata.artifact_updated_at
|
|
13860
|
+
},
|
|
13861
|
+
task_references: parseTaskReferences(body),
|
|
13862
|
+
body
|
|
13863
|
+
};
|
|
13864
|
+
}
|
|
13865
|
+
function parseTaskReferences(body) {
|
|
13866
|
+
const references = [];
|
|
13867
|
+
const taskLine = /^\s*-\s+\[[ xX]\]\s+(.+)$/;
|
|
13868
|
+
const metadataLine = /<!--\s*todos:\s*task_id=([A-Za-z0-9._-]+)\s+status=([A-Za-z_]+)\s+priority=([A-Za-z_]+)\s*-->/;
|
|
13869
|
+
const lines = body.split(/\r?\n/);
|
|
13870
|
+
for (let index = 0;index < lines.length; index++) {
|
|
13871
|
+
const titleMatch = lines[index].match(taskLine);
|
|
13872
|
+
if (!titleMatch)
|
|
13873
|
+
continue;
|
|
13874
|
+
const metadataMatch = lines[index + 1]?.match(metadataLine);
|
|
13875
|
+
if (!metadataMatch)
|
|
13876
|
+
continue;
|
|
13877
|
+
references.push({
|
|
13878
|
+
task_id: metadataMatch[1],
|
|
13879
|
+
title: titleMatch[1].trim(),
|
|
13880
|
+
status: metadataMatch[2],
|
|
13881
|
+
priority: metadataMatch[3]
|
|
13882
|
+
});
|
|
13883
|
+
}
|
|
13884
|
+
return references;
|
|
13885
|
+
}
|
|
13886
|
+
function writePlanArtifact(plan, db) {
|
|
13887
|
+
if (!plan.project_id)
|
|
13888
|
+
return null;
|
|
13889
|
+
const d = db || getDatabase();
|
|
13890
|
+
const tasks = listTasks({ plan_id: plan.id, include_archived: true }, d);
|
|
13891
|
+
const paths = resolvePlanArtifactPaths({ project_id: plan.project_id, plan_id: plan.id, db: d });
|
|
13892
|
+
const snapshot = buildPlanArtifactSnapshot(plan, tasks);
|
|
13893
|
+
mkdirSync5(paths.directory, { recursive: true });
|
|
13894
|
+
writeFileSync3(paths.file_path, renderPlanArtifactMarkdown(snapshot), "utf8");
|
|
13895
|
+
return { path: paths.file_path, snapshot };
|
|
13896
|
+
}
|
|
13897
|
+
function readPlanArtifact(plan, db) {
|
|
13898
|
+
if (!plan.project_id)
|
|
13899
|
+
return null;
|
|
13900
|
+
const d = db || getDatabase();
|
|
13901
|
+
const paths = resolvePlanArtifactPaths({ project_id: plan.project_id, plan_id: plan.id, db: d });
|
|
13902
|
+
if (!existsSync8(paths.file_path))
|
|
13903
|
+
return null;
|
|
13904
|
+
const markdown = readFileSync4(paths.file_path, "utf8");
|
|
13905
|
+
return {
|
|
13906
|
+
path: paths.file_path,
|
|
13907
|
+
markdown,
|
|
13908
|
+
...parsePlanArtifactMarkdown(markdown)
|
|
13909
|
+
};
|
|
13910
|
+
}
|
|
13911
|
+
function inspectPlanArtifact(plan, db) {
|
|
13912
|
+
if (!plan.project_id)
|
|
13913
|
+
return null;
|
|
13914
|
+
const d = db || getDatabase();
|
|
13915
|
+
const paths = resolvePlanArtifactPaths({ project_id: plan.project_id, plan_id: plan.id, db: d });
|
|
13916
|
+
if (!existsSync8(paths.file_path)) {
|
|
13917
|
+
return {
|
|
13918
|
+
path: paths.file_path,
|
|
13919
|
+
exists: false,
|
|
13920
|
+
parse_error: null,
|
|
13921
|
+
metadata: null,
|
|
13922
|
+
task_references: [],
|
|
13923
|
+
conflicts: []
|
|
13924
|
+
};
|
|
13925
|
+
}
|
|
13926
|
+
try {
|
|
13927
|
+
const artifact = parsePlanArtifactMarkdown(readFileSync4(paths.file_path, "utf8"));
|
|
13928
|
+
return {
|
|
13929
|
+
path: paths.file_path,
|
|
13930
|
+
exists: true,
|
|
13931
|
+
parse_error: null,
|
|
13932
|
+
metadata: artifact.metadata,
|
|
13933
|
+
task_references: artifact.task_references,
|
|
13934
|
+
conflicts: comparePlanArtifact(plan, artifact, listTasks({ plan_id: plan.id, include_archived: true }, d))
|
|
13935
|
+
};
|
|
13936
|
+
} catch (error) {
|
|
13937
|
+
return {
|
|
13938
|
+
path: paths.file_path,
|
|
13939
|
+
exists: true,
|
|
13940
|
+
parse_error: error instanceof Error ? error.message : String(error),
|
|
13941
|
+
metadata: null,
|
|
13942
|
+
task_references: [],
|
|
13943
|
+
conflicts: []
|
|
13944
|
+
};
|
|
13945
|
+
}
|
|
13946
|
+
}
|
|
13947
|
+
function comparePlanArtifact(plan, artifact, tasks) {
|
|
13948
|
+
const conflicts = [];
|
|
13949
|
+
compare("plan_id", plan.id, artifact.metadata.plan_id, conflicts);
|
|
13950
|
+
compare("project_id", plan.project_id ?? null, artifact.metadata.project_id, conflicts);
|
|
13951
|
+
compare("name", plan.name, artifact.metadata.name, conflicts);
|
|
13952
|
+
compare("status", plan.status, artifact.metadata.status, conflicts);
|
|
13953
|
+
compare("updated_at", plan.updated_at, artifact.metadata.updated_at, conflicts);
|
|
13954
|
+
const dbTaskIds = tasks.map((task) => task.id).sort();
|
|
13955
|
+
const artifactTaskIds = artifact.task_references.map((task) => task.task_id).sort();
|
|
13956
|
+
if (dbTaskIds.join(",") !== artifactTaskIds.join(",")) {
|
|
13957
|
+
conflicts.push({
|
|
13958
|
+
field: "task_references",
|
|
13959
|
+
database: dbTaskIds.join(",") || null,
|
|
13960
|
+
artifact: artifactTaskIds.join(",") || null
|
|
13961
|
+
});
|
|
13962
|
+
}
|
|
13963
|
+
return conflicts;
|
|
13964
|
+
}
|
|
13965
|
+
function compare(field, database, artifact, conflicts) {
|
|
13966
|
+
if ((database ?? null) !== (artifact ?? null)) {
|
|
13967
|
+
conflicts.push({ field, database: database ?? null, artifact: artifact ?? null });
|
|
13968
|
+
}
|
|
13969
|
+
}
|
|
13970
|
+
var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
|
|
13971
|
+
var init_plan_artifacts = __esm(() => {
|
|
13972
|
+
init_database();
|
|
13973
|
+
init_projects();
|
|
13974
|
+
init_tasks();
|
|
13975
|
+
});
|
|
13976
|
+
|
|
13654
13977
|
// src/db/builtin-templates.ts
|
|
13655
13978
|
var exports_builtin_templates = {};
|
|
13656
13979
|
__export(exports_builtin_templates, {
|
|
@@ -13665,8 +13988,8 @@ __export(exports_builtin_templates, {
|
|
|
13665
13988
|
BUILTIN_TEMPLATE_LIBRARY_SOURCE: () => BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
13666
13989
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
13667
13990
|
});
|
|
13668
|
-
import { mkdirSync as
|
|
13669
|
-
import { join as
|
|
13991
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
13992
|
+
import { join as join8 } from "path";
|
|
13670
13993
|
function templateMetadata(template) {
|
|
13671
13994
|
return {
|
|
13672
13995
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -13722,11 +14045,11 @@ function exportBuiltinTemplateFiles() {
|
|
|
13722
14045
|
}));
|
|
13723
14046
|
}
|
|
13724
14047
|
function writeBuiltinTemplateFiles(directory) {
|
|
13725
|
-
|
|
14048
|
+
mkdirSync6(directory, { recursive: true });
|
|
13726
14049
|
const files = [];
|
|
13727
14050
|
for (const entry of exportBuiltinTemplateFiles()) {
|
|
13728
|
-
const path =
|
|
13729
|
-
|
|
14051
|
+
const path = join8(directory, entry.filename);
|
|
14052
|
+
writeFileSync4(path, `${JSON.stringify(entry.template, null, 2)}
|
|
13730
14053
|
`, "utf-8");
|
|
13731
14054
|
files.push(path);
|
|
13732
14055
|
}
|
|
@@ -13994,7 +14317,7 @@ __export(exports_plan_template_commands, {
|
|
|
13994
14317
|
});
|
|
13995
14318
|
import chalk3 from "chalk";
|
|
13996
14319
|
function registerPlanTemplateCommands(program2) {
|
|
13997
|
-
program2.command("plans").description("List and manage plans").option("--add <name>", "Create a plan").option("-d, --description <text>", "Plan description (with --add)").option("--show <id>", "Show plan details with its tasks").option("--delete <id>", "Delete a plan").option("--complete <id>", "Mark a plan as completed").action((opts) => {
|
|
14320
|
+
program2.command("plans").description("List and manage plans").option("--add <name>", "Create a plan").option("-d, --description <text>", "Plan description (with --add)").option("--show <id>", "Show plan details with its tasks").option("--artifact <id>", "Show local Markdown artifact diagnostics for a plan").option("--write-artifacts", "Write local Markdown artifacts for all project-scoped plans in scope").option("--delete <id>", "Delete a plan").option("--complete <id>", "Mark a plan as completed").action((opts) => {
|
|
13998
14321
|
const globalOpts = program2.opts();
|
|
13999
14322
|
const projectId = autoProject(globalOpts);
|
|
14000
14323
|
if (opts.add) {
|
|
@@ -14003,11 +14326,71 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14003
14326
|
description: opts.description,
|
|
14004
14327
|
project_id: projectId
|
|
14005
14328
|
});
|
|
14329
|
+
const artifact = writePlanArtifact(plan);
|
|
14006
14330
|
if (globalOpts.json) {
|
|
14007
14331
|
output(plan, true);
|
|
14008
14332
|
} else {
|
|
14009
14333
|
console.log(chalk3.green("Plan created:"));
|
|
14010
14334
|
console.log(`${chalk3.dim(plan.id.slice(0, 8))} ${chalk3.bold(plan.name)} ${chalk3.cyan(`[${plan.status}]`)}`);
|
|
14335
|
+
if (artifact)
|
|
14336
|
+
console.log(`${chalk3.dim("Artifact:")} ${artifact.path}`);
|
|
14337
|
+
}
|
|
14338
|
+
return;
|
|
14339
|
+
}
|
|
14340
|
+
if (opts.artifact) {
|
|
14341
|
+
const db = getDatabase();
|
|
14342
|
+
const resolvedId = resolvePartialId(db, "plans", opts.artifact);
|
|
14343
|
+
if (!resolvedId) {
|
|
14344
|
+
console.error(chalk3.red(`Could not resolve plan ID: ${opts.artifact}`));
|
|
14345
|
+
process.exit(1);
|
|
14346
|
+
}
|
|
14347
|
+
const plan = getPlan(resolvedId);
|
|
14348
|
+
if (!plan) {
|
|
14349
|
+
console.error(chalk3.red(`Plan not found: ${opts.artifact}`));
|
|
14350
|
+
process.exit(1);
|
|
14351
|
+
}
|
|
14352
|
+
const inspection = inspectPlanArtifact(plan, db);
|
|
14353
|
+
if (!inspection) {
|
|
14354
|
+
const result = { plan_id: plan.id, artifact: null, reason: "plan is not project-scoped" };
|
|
14355
|
+
if (globalOpts.json)
|
|
14356
|
+
output(result, true);
|
|
14357
|
+
else
|
|
14358
|
+
console.log(chalk3.dim("Plan is not project-scoped; no local Markdown artifact path is available."));
|
|
14359
|
+
return;
|
|
14360
|
+
}
|
|
14361
|
+
if (globalOpts.json) {
|
|
14362
|
+
output({ plan, artifact: inspection }, true);
|
|
14363
|
+
return;
|
|
14364
|
+
}
|
|
14365
|
+
console.log(chalk3.bold(`Plan Artifact:
|
|
14366
|
+
`));
|
|
14367
|
+
console.log(` ${chalk3.dim("Plan:")} ${plan.id}`);
|
|
14368
|
+
console.log(` ${chalk3.dim("Path:")} ${inspection.path}`);
|
|
14369
|
+
console.log(` ${chalk3.dim("Exists:")} ${inspection.exists ? "yes" : "no"}`);
|
|
14370
|
+
if (inspection.parse_error)
|
|
14371
|
+
console.log(` ${chalk3.dim("Parse:")} ${chalk3.red(inspection.parse_error)}`);
|
|
14372
|
+
console.log(` ${chalk3.dim("Conflicts:")} ${inspection.conflicts.length}`);
|
|
14373
|
+
for (const conflict of inspection.conflicts) {
|
|
14374
|
+
console.log(` ${conflict.field}: db=${conflict.database ?? "null"} artifact=${conflict.artifact ?? "null"}`);
|
|
14375
|
+
}
|
|
14376
|
+
return;
|
|
14377
|
+
}
|
|
14378
|
+
if (opts.writeArtifacts) {
|
|
14379
|
+
const plans2 = listPlans(projectId);
|
|
14380
|
+
const written = plans2.map((plan) => ({ plan, artifact: writePlanArtifact(plan) })).filter((entry) => entry.artifact);
|
|
14381
|
+
const result = {
|
|
14382
|
+
count: written.length,
|
|
14383
|
+
artifacts: written.map((entry) => ({
|
|
14384
|
+
plan_id: entry.plan.id,
|
|
14385
|
+
path: entry.artifact.path
|
|
14386
|
+
}))
|
|
14387
|
+
};
|
|
14388
|
+
if (globalOpts.json) {
|
|
14389
|
+
output(result, true);
|
|
14390
|
+
} else {
|
|
14391
|
+
console.log(chalk3.green(`Wrote ${written.length} plan artifact(s).`));
|
|
14392
|
+
for (const artifact of result.artifacts)
|
|
14393
|
+
console.log(`${chalk3.dim(artifact.plan_id.slice(0, 8))} ${artifact.path}`);
|
|
14011
14394
|
}
|
|
14012
14395
|
return;
|
|
14013
14396
|
}
|
|
@@ -14025,8 +14408,18 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14025
14408
|
}
|
|
14026
14409
|
const { listTasks: listTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
14027
14410
|
const tasks = listTasks2({ plan_id: resolvedId });
|
|
14411
|
+
const artifact = readPlanArtifact(plan, db);
|
|
14028
14412
|
if (globalOpts.json) {
|
|
14029
|
-
output({
|
|
14413
|
+
output({
|
|
14414
|
+
plan,
|
|
14415
|
+
tasks,
|
|
14416
|
+
artifact: artifact ? {
|
|
14417
|
+
path: artifact.path,
|
|
14418
|
+
metadata: artifact.metadata,
|
|
14419
|
+
task_references: artifact.task_references,
|
|
14420
|
+
body: artifact.body
|
|
14421
|
+
} : null
|
|
14422
|
+
}, true);
|
|
14030
14423
|
return;
|
|
14031
14424
|
}
|
|
14032
14425
|
console.log(chalk3.bold(`Plan Details:
|
|
@@ -14038,6 +14431,8 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14038
14431
|
console.log(` ${chalk3.dim("Desc:")} ${plan.description}`);
|
|
14039
14432
|
if (plan.project_id)
|
|
14040
14433
|
console.log(` ${chalk3.dim("Project:")} ${plan.project_id}`);
|
|
14434
|
+
if (artifact)
|
|
14435
|
+
console.log(` ${chalk3.dim("Artifact:")} ${artifact.path}`);
|
|
14041
14436
|
console.log(` ${chalk3.dim("Created:")} ${plan.created_at}`);
|
|
14042
14437
|
if (tasks.length > 0) {
|
|
14043
14438
|
console.log(chalk3.bold(`
|
|
@@ -14078,11 +14473,14 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14078
14473
|
}
|
|
14079
14474
|
try {
|
|
14080
14475
|
const plan = updatePlan(resolvedId, { status: "completed" });
|
|
14476
|
+
const artifact = writePlanArtifact(plan);
|
|
14081
14477
|
if (globalOpts.json) {
|
|
14082
14478
|
output(plan, true);
|
|
14083
14479
|
} else {
|
|
14084
14480
|
console.log(chalk3.green("Plan completed:"));
|
|
14085
14481
|
console.log(`${chalk3.dim(plan.id.slice(0, 8))} ${chalk3.bold(plan.name)} ${chalk3.cyan(`[${plan.status}]`)}`);
|
|
14482
|
+
if (artifact)
|
|
14483
|
+
console.log(`${chalk3.dim("Artifact:")} ${artifact.path}`);
|
|
14086
14484
|
}
|
|
14087
14485
|
} catch (e) {
|
|
14088
14486
|
handleError(e);
|
|
@@ -14360,14 +14758,14 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14360
14758
|
program2.command("template-import [file]").alias("templates-import").description("Import a template from a JSON file").option("--file <path>", "Path to template JSON file (alternative to positional arg)").action(async (file, opts) => {
|
|
14361
14759
|
const globalOpts = program2.opts();
|
|
14362
14760
|
const { importTemplate: importTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
14363
|
-
const { readFileSync:
|
|
14761
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
14364
14762
|
try {
|
|
14365
14763
|
const filePath = file || opts.file;
|
|
14366
14764
|
if (!filePath) {
|
|
14367
14765
|
console.error(chalk3.red("Provide a file path: todos template-import <file> or --file <path>"));
|
|
14368
14766
|
process.exit(1);
|
|
14369
14767
|
}
|
|
14370
|
-
const content =
|
|
14768
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
14371
14769
|
const json = JSON.parse(content);
|
|
14372
14770
|
const template = importTemplate2(json);
|
|
14373
14771
|
if (globalOpts.json) {
|
|
@@ -14411,6 +14809,7 @@ var init_plan_template_commands = __esm(() => {
|
|
|
14411
14809
|
init_database();
|
|
14412
14810
|
init_plans();
|
|
14413
14811
|
init_tasks();
|
|
14812
|
+
init_plan_artifacts();
|
|
14414
14813
|
init_helpers();
|
|
14415
14814
|
});
|
|
14416
14815
|
|
|
@@ -14979,16 +15378,16 @@ var init_saved_search_views = __esm(() => {
|
|
|
14979
15378
|
});
|
|
14980
15379
|
|
|
14981
15380
|
// src/lib/claude-tasks.ts
|
|
14982
|
-
import { existsSync as
|
|
14983
|
-
import { join as
|
|
15381
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5, readdirSync as readdirSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
15382
|
+
import { join as join9 } from "path";
|
|
14984
15383
|
function getTaskListDir(taskListId) {
|
|
14985
|
-
return
|
|
15384
|
+
return join9(HOME, ".claude", "tasks", taskListId);
|
|
14986
15385
|
}
|
|
14987
15386
|
function readClaudeTask(dir, filename) {
|
|
14988
|
-
return readJsonFile(
|
|
15387
|
+
return readJsonFile(join9(dir, filename));
|
|
14989
15388
|
}
|
|
14990
15389
|
function writeClaudeTask(dir, task) {
|
|
14991
|
-
writeJsonFile(
|
|
15390
|
+
writeJsonFile(join9(dir, `${task.id}.json`), task);
|
|
14992
15391
|
}
|
|
14993
15392
|
function toClaudeStatus(status) {
|
|
14994
15393
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -15000,14 +15399,14 @@ function toSqliteStatus(status) {
|
|
|
15000
15399
|
return status;
|
|
15001
15400
|
}
|
|
15002
15401
|
function readPrefixCounter(dir) {
|
|
15003
|
-
const path =
|
|
15004
|
-
if (!
|
|
15402
|
+
const path = join9(dir, ".prefix-counter");
|
|
15403
|
+
if (!existsSync9(path))
|
|
15005
15404
|
return 0;
|
|
15006
|
-
const val = parseInt(
|
|
15405
|
+
const val = parseInt(readFileSync5(path, "utf-8").trim(), 10);
|
|
15007
15406
|
return isNaN(val) ? 0 : val;
|
|
15008
15407
|
}
|
|
15009
15408
|
function writePrefixCounter(dir, value) {
|
|
15010
|
-
|
|
15409
|
+
writeFileSync5(join9(dir, ".prefix-counter"), String(value));
|
|
15011
15410
|
}
|
|
15012
15411
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
15013
15412
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -15034,7 +15433,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
15034
15433
|
}
|
|
15035
15434
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
15036
15435
|
const dir = getTaskListDir(taskListId);
|
|
15037
|
-
if (!
|
|
15436
|
+
if (!existsSync9(dir))
|
|
15038
15437
|
ensureDir2(dir);
|
|
15039
15438
|
const filter = {};
|
|
15040
15439
|
if (projectId)
|
|
@@ -15043,7 +15442,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
15043
15442
|
const existingByTodosId = new Map;
|
|
15044
15443
|
const files = listJsonFiles(dir);
|
|
15045
15444
|
for (const f of files) {
|
|
15046
|
-
const path =
|
|
15445
|
+
const path = join9(dir, f);
|
|
15047
15446
|
const ct = readClaudeTask(dir, f);
|
|
15048
15447
|
if (ct?.metadata?.["todos_id"]) {
|
|
15049
15448
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -15130,7 +15529,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
15130
15529
|
}
|
|
15131
15530
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
15132
15531
|
const dir = getTaskListDir(taskListId);
|
|
15133
|
-
if (!
|
|
15532
|
+
if (!existsSync9(dir)) {
|
|
15134
15533
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
15135
15534
|
}
|
|
15136
15535
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -15150,7 +15549,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
15150
15549
|
}
|
|
15151
15550
|
for (const f of files) {
|
|
15152
15551
|
try {
|
|
15153
|
-
const filePath =
|
|
15552
|
+
const filePath = join9(dir, f);
|
|
15154
15553
|
const ct = readClaudeTask(dir, f);
|
|
15155
15554
|
if (!ct)
|
|
15156
15555
|
continue;
|
|
@@ -15223,20 +15622,20 @@ var init_claude_tasks = __esm(() => {
|
|
|
15223
15622
|
});
|
|
15224
15623
|
|
|
15225
15624
|
// src/lib/agent-tasks.ts
|
|
15226
|
-
import { existsSync as
|
|
15227
|
-
import { join as
|
|
15625
|
+
import { existsSync as existsSync10 } from "fs";
|
|
15626
|
+
import { join as join10 } from "path";
|
|
15228
15627
|
function agentBaseDir(agent) {
|
|
15229
15628
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
15230
|
-
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
15629
|
+
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join10(getTodosGlobalDir(), "agents");
|
|
15231
15630
|
}
|
|
15232
15631
|
function getTaskListDir2(agent, taskListId) {
|
|
15233
|
-
return
|
|
15632
|
+
return join10(agentBaseDir(agent), agent, taskListId);
|
|
15234
15633
|
}
|
|
15235
15634
|
function readAgentTask(dir, filename) {
|
|
15236
|
-
return readJsonFile(
|
|
15635
|
+
return readJsonFile(join10(dir, filename));
|
|
15237
15636
|
}
|
|
15238
15637
|
function writeAgentTask(dir, task) {
|
|
15239
|
-
writeJsonFile(
|
|
15638
|
+
writeJsonFile(join10(dir, `${task.id}.json`), task);
|
|
15240
15639
|
}
|
|
15241
15640
|
function taskToAgentTask(task, externalId, existingMeta) {
|
|
15242
15641
|
return {
|
|
@@ -15261,7 +15660,7 @@ function metadataKey(agent) {
|
|
|
15261
15660
|
}
|
|
15262
15661
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
15263
15662
|
const dir = getTaskListDir2(agent, taskListId);
|
|
15264
|
-
if (!
|
|
15663
|
+
if (!existsSync10(dir))
|
|
15265
15664
|
ensureDir2(dir);
|
|
15266
15665
|
const filter = {};
|
|
15267
15666
|
if (projectId)
|
|
@@ -15270,7 +15669,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
15270
15669
|
const existingByTodosId = new Map;
|
|
15271
15670
|
const files = listJsonFiles(dir);
|
|
15272
15671
|
for (const f of files) {
|
|
15273
|
-
const path =
|
|
15672
|
+
const path = join10(dir, f);
|
|
15274
15673
|
const at = readAgentTask(dir, f);
|
|
15275
15674
|
if (at?.metadata?.["todos_id"]) {
|
|
15276
15675
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -15344,7 +15743,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
15344
15743
|
}
|
|
15345
15744
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
15346
15745
|
const dir = getTaskListDir2(agent, taskListId);
|
|
15347
|
-
if (!
|
|
15746
|
+
if (!existsSync10(dir)) {
|
|
15348
15747
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
15349
15748
|
}
|
|
15350
15749
|
const files = listJsonFiles(dir);
|
|
@@ -15363,7 +15762,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
15363
15762
|
}
|
|
15364
15763
|
for (const f of files) {
|
|
15365
15764
|
try {
|
|
15366
|
-
const filePath =
|
|
15765
|
+
const filePath = join10(dir, f);
|
|
15367
15766
|
const at = readAgentTask(dir, f);
|
|
15368
15767
|
if (!at)
|
|
15369
15768
|
continue;
|
|
@@ -15516,8 +15915,8 @@ __export(exports_project_bootstrap, {
|
|
|
15516
15915
|
discoverProjectWorkspace: () => discoverProjectWorkspace,
|
|
15517
15916
|
bootstrapProject: () => bootstrapProject
|
|
15518
15917
|
});
|
|
15519
|
-
import { existsSync as
|
|
15520
|
-
import { basename as basename4, dirname as dirname6, resolve as
|
|
15918
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
15919
|
+
import { basename as basename4, dirname as dirname6, resolve as resolve11 } from "path";
|
|
15521
15920
|
function safeStat(path) {
|
|
15522
15921
|
try {
|
|
15523
15922
|
return statSync3(path);
|
|
@@ -15526,7 +15925,7 @@ function safeStat(path) {
|
|
|
15526
15925
|
}
|
|
15527
15926
|
}
|
|
15528
15927
|
function canonicalPath(input) {
|
|
15529
|
-
const resolved =
|
|
15928
|
+
const resolved = resolve11(input);
|
|
15530
15929
|
const stats = safeStat(resolved);
|
|
15531
15930
|
if (stats?.isFile())
|
|
15532
15931
|
return dirname6(resolved);
|
|
@@ -15535,7 +15934,7 @@ function canonicalPath(input) {
|
|
|
15535
15934
|
function findUp(start, marker) {
|
|
15536
15935
|
let current = canonicalPath(start);
|
|
15537
15936
|
while (true) {
|
|
15538
|
-
if (
|
|
15937
|
+
if (existsSync11(resolve11(current, marker)))
|
|
15539
15938
|
return current;
|
|
15540
15939
|
const parent = dirname6(current);
|
|
15541
15940
|
if (parent === current)
|
|
@@ -15546,11 +15945,11 @@ function findUp(start, marker) {
|
|
|
15546
15945
|
function readPackageJson(path) {
|
|
15547
15946
|
if (!path)
|
|
15548
15947
|
return null;
|
|
15549
|
-
const file =
|
|
15550
|
-
if (!
|
|
15948
|
+
const file = resolve11(path, "package.json");
|
|
15949
|
+
if (!existsSync11(file))
|
|
15551
15950
|
return null;
|
|
15552
15951
|
try {
|
|
15553
|
-
const parsed = JSON.parse(
|
|
15952
|
+
const parsed = JSON.parse(readFileSync6(file, "utf-8"));
|
|
15554
15953
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
15555
15954
|
} catch {
|
|
15556
15955
|
return null;
|
|
@@ -15569,7 +15968,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
15569
15968
|
if (rootPackage?.workspaces)
|
|
15570
15969
|
markers.push("package.json#workspaces");
|
|
15571
15970
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
15572
|
-
if (
|
|
15971
|
+
if (existsSync11(resolve11(root, marker)))
|
|
15573
15972
|
markers.push(marker);
|
|
15574
15973
|
}
|
|
15575
15974
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -21092,9 +21491,9 @@ __export(exports_extract, {
|
|
|
21092
21491
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
21093
21492
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
21094
21493
|
});
|
|
21095
|
-
import { existsSync as
|
|
21494
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
|
|
21096
21495
|
import { createHash as createHash3 } from "crypto";
|
|
21097
|
-
import { relative as relative3, resolve as
|
|
21496
|
+
import { relative as relative3, resolve as resolve12, join as join11 } from "path";
|
|
21098
21497
|
function stableHash(value) {
|
|
21099
21498
|
return createHash3("sha256").update(value).digest("hex");
|
|
21100
21499
|
}
|
|
@@ -21102,12 +21501,12 @@ function normalizePathForMatch(value) {
|
|
|
21102
21501
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
21103
21502
|
}
|
|
21104
21503
|
function readGitignorePatterns(basePath) {
|
|
21105
|
-
const root = statSync4(basePath).isFile() ?
|
|
21106
|
-
const gitignorePath =
|
|
21107
|
-
if (!
|
|
21504
|
+
const root = statSync4(basePath).isFile() ? resolve12(basePath, "..") : basePath;
|
|
21505
|
+
const gitignorePath = join11(root, ".gitignore");
|
|
21506
|
+
if (!existsSync12(gitignorePath))
|
|
21108
21507
|
return [];
|
|
21109
21508
|
try {
|
|
21110
|
-
return
|
|
21509
|
+
return readFileSync7(gitignorePath, "utf-8").split(`
|
|
21111
21510
|
`).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!"));
|
|
21112
21511
|
} catch {
|
|
21113
21512
|
return [];
|
|
@@ -21238,7 +21637,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
21238
21637
|
return files.sort();
|
|
21239
21638
|
}
|
|
21240
21639
|
function buildCodebaseIndex(options) {
|
|
21241
|
-
const basePath =
|
|
21640
|
+
const basePath = resolve12(options.path);
|
|
21242
21641
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
21243
21642
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
21244
21643
|
const excludes = options.exclude || [];
|
|
@@ -21246,10 +21645,10 @@ function buildCodebaseIndex(options) {
|
|
|
21246
21645
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
21247
21646
|
const indexed = [];
|
|
21248
21647
|
for (const file of files) {
|
|
21249
|
-
const fullPath = statSync4(basePath).isFile() ? basePath :
|
|
21648
|
+
const fullPath = statSync4(basePath).isFile() ? basePath : join11(basePath, file);
|
|
21250
21649
|
try {
|
|
21251
|
-
const source =
|
|
21252
|
-
const relPath = statSync4(basePath).isFile() ? relative3(
|
|
21650
|
+
const source = readFileSync7(fullPath, "utf-8");
|
|
21651
|
+
const relPath = statSync4(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
|
|
21253
21652
|
indexed.push({
|
|
21254
21653
|
file: relPath,
|
|
21255
21654
|
checksum: stableHash(source).slice(0, 24),
|
|
@@ -21269,7 +21668,7 @@ function buildCodebaseIndex(options) {
|
|
|
21269
21668
|
};
|
|
21270
21669
|
}
|
|
21271
21670
|
function extractTodos(options, db) {
|
|
21272
|
-
const basePath =
|
|
21671
|
+
const basePath = resolve12(options.path);
|
|
21273
21672
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
21274
21673
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
21275
21674
|
const excludes = options.exclude || [];
|
|
@@ -21277,10 +21676,10 @@ function extractTodos(options, db) {
|
|
|
21277
21676
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
21278
21677
|
const allComments = [];
|
|
21279
21678
|
for (const file of files) {
|
|
21280
|
-
const fullPath = statSync4(basePath).isFile() ? basePath :
|
|
21679
|
+
const fullPath = statSync4(basePath).isFile() ? basePath : join11(basePath, file);
|
|
21281
21680
|
try {
|
|
21282
|
-
const source =
|
|
21283
|
-
const relPath = statSync4(basePath).isFile() ? relative3(
|
|
21681
|
+
const source = readFileSync7(fullPath, "utf-8");
|
|
21682
|
+
const relPath = statSync4(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
|
|
21284
21683
|
const comments = extractFromSource(source, relPath, tags);
|
|
21285
21684
|
allComments.push(...comments);
|
|
21286
21685
|
} catch {}
|
|
@@ -21374,7 +21773,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
21374
21773
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
21375
21774
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
21376
21775
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
21377
|
-
const root =
|
|
21776
|
+
const root = resolve12(options.path);
|
|
21378
21777
|
const runs = [];
|
|
21379
21778
|
let previous = new Map;
|
|
21380
21779
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -22545,7 +22944,7 @@ __export(exports_project_commands, {
|
|
|
22545
22944
|
registerProjectCommands: () => registerProjectCommands
|
|
22546
22945
|
});
|
|
22547
22946
|
import chalk4 from "chalk";
|
|
22548
|
-
import { basename as basename5, resolve as
|
|
22947
|
+
import { basename as basename5, resolve as resolve13 } from "path";
|
|
22549
22948
|
function collectOption(value, previous = []) {
|
|
22550
22949
|
return [...previous, value];
|
|
22551
22950
|
}
|
|
@@ -22887,7 +23286,7 @@ function registerProjectCommands(program2) {
|
|
|
22887
23286
|
program2.command("projects").description("List and manage projects").option("--add <path>", "Register a project by path").option("--name <name>", "Project name (with --add)").option("--task-list-id <id>", "Custom task list ID (with --add)").action(async (opts) => {
|
|
22888
23287
|
const globalOpts = program2.opts();
|
|
22889
23288
|
if (opts.add) {
|
|
22890
|
-
const projectPath =
|
|
23289
|
+
const projectPath = resolve13(opts.add);
|
|
22891
23290
|
const name = opts.name || basename5(projectPath);
|
|
22892
23291
|
const existing = getProjectByPath(projectPath);
|
|
22893
23292
|
let project;
|
|
@@ -22995,7 +23394,7 @@ function registerProjectCommands(program2) {
|
|
|
22995
23394
|
console.error(chalk4.red(`Project not found: ${projectId}`));
|
|
22996
23395
|
process.exit(1);
|
|
22997
23396
|
}
|
|
22998
|
-
const entry = setMachineLocalPath2(resolved,
|
|
23397
|
+
const entry = setMachineLocalPath2(resolved, resolve13(projectPath));
|
|
22999
23398
|
if (useJson) {
|
|
23000
23399
|
output(entry, true);
|
|
23001
23400
|
} else {
|
|
@@ -23062,7 +23461,7 @@ function registerProjectCommands(program2) {
|
|
|
23062
23461
|
const patterns = opts.pattern ? opts.pattern.split(",").map((t) => t.trim().toUpperCase()) : undefined;
|
|
23063
23462
|
const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
|
|
23064
23463
|
const result = extractTodos2({
|
|
23065
|
-
path:
|
|
23464
|
+
path: resolve13(scanPath),
|
|
23066
23465
|
patterns,
|
|
23067
23466
|
project_id: projectId,
|
|
23068
23467
|
task_list_id: taskListId,
|
|
@@ -23123,7 +23522,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23123
23522
|
const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
|
|
23124
23523
|
const maxRuns = opts.maxRuns ? parseInt(opts.maxRuns, 10) : 1;
|
|
23125
23524
|
const result = await watchSourceTodos2({
|
|
23126
|
-
path:
|
|
23525
|
+
path: resolve13(scanPath),
|
|
23127
23526
|
patterns,
|
|
23128
23527
|
project_id: projectId,
|
|
23129
23528
|
task_list_id: taskListId,
|
|
@@ -23159,8 +23558,8 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23159
23558
|
const projectId = autoProject(globalOpts);
|
|
23160
23559
|
const writeOutput = async (content) => {
|
|
23161
23560
|
if (opts.output) {
|
|
23162
|
-
const { writeFileSync:
|
|
23163
|
-
|
|
23561
|
+
const { writeFileSync: writeFileSync6 } = await import("fs");
|
|
23562
|
+
writeFileSync6(resolve13(opts.output), content.endsWith(`
|
|
23164
23563
|
`) ? content : `${content}
|
|
23165
23564
|
`);
|
|
23166
23565
|
} else {
|
|
@@ -23175,12 +23574,12 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23175
23574
|
const exported = opts.encrypt ? createEncryptedBridgeBundle2(bundle, { profile: opts.encryptionProfile }) : bundle;
|
|
23176
23575
|
const json = JSON.stringify(exported, null, 2);
|
|
23177
23576
|
await writeOutput(json);
|
|
23178
|
-
emitLocalEventHooksQuiet3({ type: "export.finished", payload: { format: "bridge", encrypted: Boolean(opts.encrypt), project_id: projectId, output: opts.output ?
|
|
23577
|
+
emitLocalEventHooksQuiet3({ type: "export.finished", payload: { format: "bridge", encrypted: Boolean(opts.encrypt), project_id: projectId, output: opts.output ? resolve13(opts.output) : null, stats: bundle.stats } });
|
|
23179
23578
|
if (!opts.encrypt && !opts.allowPlaintextSensitive) {
|
|
23180
23579
|
console.error(chalk4.yellow("Warning: bridge exports are plaintext JSON. Use --encrypt for sensitive metadata, evidence, and artifact bundles."));
|
|
23181
23580
|
}
|
|
23182
23581
|
if (opts.output && !globalOpts.json) {
|
|
23183
|
-
console.log(chalk4.green(`${opts.encrypt ? "Encrypted bridge export" : "Bridge export"} written to ${
|
|
23582
|
+
console.log(chalk4.green(`${opts.encrypt ? "Encrypted bridge export" : "Bridge export"} written to ${resolve13(opts.output)}`));
|
|
23184
23583
|
}
|
|
23185
23584
|
return;
|
|
23186
23585
|
}
|
|
@@ -23193,21 +23592,21 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23193
23592
|
await writeOutput(JSON.stringify(tasks, null, 2));
|
|
23194
23593
|
}
|
|
23195
23594
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
23196
|
-
emitLocalEventHooksQuiet2({ type: "export.finished", payload: { format: opts.format, project_id: projectId, output: opts.output ?
|
|
23595
|
+
emitLocalEventHooksQuiet2({ type: "export.finished", payload: { format: opts.format, project_id: projectId, output: opts.output ? resolve13(opts.output) : null, count: exportedCount } });
|
|
23197
23596
|
});
|
|
23198
23597
|
program2.command("bridge-import <file>").description("Dry-run or apply a local hasna/todos bridge export bundle").option("--apply", "Apply the import. Defaults to dry-run.").option("--decrypt", "Decrypt an encrypted bridge export before importing").option("--resolve-conflicts", "Safely merge existing local tasks by filling blank fields, unioning tags, and recording unresolved divergences").action(async (file, opts) => {
|
|
23199
23598
|
const globalOpts = program2.opts();
|
|
23200
23599
|
try {
|
|
23201
|
-
const { readFileSync:
|
|
23600
|
+
const { readFileSync: readFileSync8 } = await import("fs");
|
|
23202
23601
|
const { importLocalBridgeBundle: importLocalBridgeBundle2 } = await Promise.resolve().then(() => (init_local_bridge(), exports_local_bridge));
|
|
23203
23602
|
const { decryptBridgeBundle: decryptBridgeBundle2, isEncryptedBridgeBundle: isEncryptedBridgeBundle2 } = await Promise.resolve().then(() => (init_local_encryption(), exports_local_encryption));
|
|
23204
|
-
const parsed = JSON.parse(
|
|
23603
|
+
const parsed = JSON.parse(readFileSync8(resolve13(file), "utf-8"));
|
|
23205
23604
|
const bundle = isEncryptedBridgeBundle2(parsed) ? opts.decrypt ? decryptBridgeBundle2(parsed) : (() => {
|
|
23206
23605
|
throw new Error("Bridge bundle is encrypted. Re-run with --decrypt and the configured key environment variable set.");
|
|
23207
23606
|
})() : parsed;
|
|
23208
23607
|
const result = importLocalBridgeBundle2(bundle, { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
|
|
23209
23608
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
23210
|
-
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file:
|
|
23609
|
+
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve13(file), dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, conflicts: result.conflicts.length, issues: result.issues.length } });
|
|
23211
23610
|
if (globalOpts.json) {
|
|
23212
23611
|
output(result, true);
|
|
23213
23612
|
return;
|
|
@@ -23235,11 +23634,11 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23235
23634
|
program2.command("todos-md-import <file>").alias("markdown-import").alias("import-md").description("Dry-run or apply a local todos.md Markdown import").option("--apply", "Apply the import. Defaults to dry-run.").option("--resolve-conflicts", "Safely merge embedded bridge task conflicts while preserving local divergent fields").action(async (file, opts) => {
|
|
23236
23635
|
const globalOpts = program2.opts();
|
|
23237
23636
|
try {
|
|
23238
|
-
const { readFileSync:
|
|
23637
|
+
const { readFileSync: readFileSync8 } = await import("fs");
|
|
23239
23638
|
const { importTodosMarkdown: importTodosMarkdown2 } = await Promise.resolve().then(() => (init_todos_md(), exports_todos_md));
|
|
23240
|
-
const result = importTodosMarkdown2(
|
|
23639
|
+
const result = importTodosMarkdown2(readFileSync8(resolve13(file), "utf-8"), { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
|
|
23241
23640
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
23242
|
-
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file:
|
|
23641
|
+
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve13(file), format: "todos.md", dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, issues: result.issues.length } });
|
|
23243
23642
|
if (globalOpts.json) {
|
|
23244
23643
|
output(result, true);
|
|
23245
23644
|
return;
|
|
@@ -24367,7 +24766,7 @@ __export(exports_retention_cleanup, {
|
|
|
24367
24766
|
applyRetentionCleanup: () => applyRetentionCleanup,
|
|
24368
24767
|
RETENTION_CLEANUP_CONFIRMATION: () => RETENTION_CLEANUP_CONFIRMATION
|
|
24369
24768
|
});
|
|
24370
|
-
import { existsSync as
|
|
24769
|
+
import { existsSync as existsSync13, unlinkSync } from "fs";
|
|
24371
24770
|
function normalizeScopes(scopes) {
|
|
24372
24771
|
if (!scopes || scopes.length === 0)
|
|
24373
24772
|
return [...ALL_SCOPES];
|
|
@@ -24570,7 +24969,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
24570
24969
|
for (const artifact of report.candidates.artifact_files) {
|
|
24571
24970
|
try {
|
|
24572
24971
|
const path = artifactStorePath(artifact.relative_path);
|
|
24573
|
-
if (!
|
|
24972
|
+
if (!existsSync13(path)) {
|
|
24574
24973
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
24575
24974
|
continue;
|
|
24576
24975
|
}
|
|
@@ -25248,8 +25647,8 @@ __export(exports_local_extensions, {
|
|
|
25248
25647
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
25249
25648
|
});
|
|
25250
25649
|
import { createHash as createHash5, createVerify } from "crypto";
|
|
25251
|
-
import { existsSync as
|
|
25252
|
-
import { basename as basename6, join as
|
|
25650
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
25651
|
+
import { basename as basename6, join as join12, resolve as resolve14 } from "path";
|
|
25253
25652
|
function isObject(value) {
|
|
25254
25653
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
25255
25654
|
}
|
|
@@ -25330,7 +25729,7 @@ function normalizeManifest(input) {
|
|
|
25330
25729
|
};
|
|
25331
25730
|
}
|
|
25332
25731
|
function parseJson(path) {
|
|
25333
|
-
return JSON.parse(
|
|
25732
|
+
return JSON.parse(readFileSync8(path, "utf8"));
|
|
25334
25733
|
}
|
|
25335
25734
|
function sha2563(bytes) {
|
|
25336
25735
|
return `sha256:${createHash5("sha256").update(bytes).digest("hex")}`;
|
|
@@ -25507,14 +25906,14 @@ function verifyExtensionSignature(input) {
|
|
|
25507
25906
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
25508
25907
|
}
|
|
25509
25908
|
function inspectExtensionSource(source2) {
|
|
25510
|
-
const resolved =
|
|
25511
|
-
if (!
|
|
25909
|
+
const resolved = resolve14(source2);
|
|
25910
|
+
if (!existsSync14(resolved))
|
|
25512
25911
|
throw new Error(`extension source not found: ${source2}`);
|
|
25513
25912
|
const stat = statSync5(resolved);
|
|
25514
|
-
const manifestPath = stat.isDirectory() ? [
|
|
25913
|
+
const manifestPath = stat.isDirectory() ? [join12(resolved, "todos.extension.json"), join12(resolved, "extension.json")].find(existsSync14) : resolved;
|
|
25515
25914
|
if (!manifestPath)
|
|
25516
25915
|
throw new Error(`extension directory ${source2} is missing todos.extension.json`);
|
|
25517
|
-
const raw =
|
|
25916
|
+
const raw = readFileSync8(manifestPath);
|
|
25518
25917
|
const parsed = parseJson(manifestPath);
|
|
25519
25918
|
const bundle = isObject(parsed) && isObject(parsed["manifest"]);
|
|
25520
25919
|
const manifest = normalizeManifest(bundle ? parsed["manifest"] : parsed);
|
|
@@ -25605,26 +26004,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
25605
26004
|
function projectExtensionSources(projectPath) {
|
|
25606
26005
|
if (!projectPath)
|
|
25607
26006
|
return [];
|
|
25608
|
-
const root =
|
|
26007
|
+
const root = resolve14(projectPath);
|
|
25609
26008
|
const candidates = [
|
|
25610
|
-
|
|
25611
|
-
|
|
26009
|
+
join12(root, "todos.extension.json"),
|
|
26010
|
+
join12(root, ".todos", "todos.extension.json")
|
|
25612
26011
|
];
|
|
25613
|
-
const extensionDir =
|
|
25614
|
-
if (
|
|
26012
|
+
const extensionDir = join12(root, ".todos", "extensions");
|
|
26013
|
+
if (existsSync14(extensionDir)) {
|
|
25615
26014
|
for (const entry of readdirSync3(extensionDir)) {
|
|
25616
26015
|
if (entry.startsWith("."))
|
|
25617
26016
|
continue;
|
|
25618
|
-
const full =
|
|
26017
|
+
const full = join12(extensionDir, entry);
|
|
25619
26018
|
if (statSync5(full).isDirectory() || entry.endsWith(".json"))
|
|
25620
26019
|
candidates.push(full);
|
|
25621
26020
|
}
|
|
25622
26021
|
}
|
|
25623
|
-
return candidates.filter(
|
|
26022
|
+
return candidates.filter(existsSync14);
|
|
25624
26023
|
}
|
|
25625
26024
|
function discoverLocalExtensions(options = {}) {
|
|
25626
26025
|
const config = loadConfig();
|
|
25627
|
-
const projectPath = options.project_path ?
|
|
26026
|
+
const projectPath = options.project_path ? resolve14(options.project_path) : null;
|
|
25628
26027
|
const configuredSources = [
|
|
25629
26028
|
...config.extension_sources || [],
|
|
25630
26029
|
...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -25632,7 +26031,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
25632
26031
|
const sources = Array.from(new Set([
|
|
25633
26032
|
...configuredSources,
|
|
25634
26033
|
...projectExtensionSources(projectPath || undefined)
|
|
25635
|
-
])).map((source2) => projectPath && !source2.startsWith("/") ?
|
|
26034
|
+
])).map((source2) => projectPath && !source2.startsWith("/") ? resolve14(projectPath, source2) : resolve14(source2));
|
|
25636
26035
|
const warnings = [];
|
|
25637
26036
|
const discovered = [];
|
|
25638
26037
|
for (const source2 of sources) {
|
|
@@ -25892,9 +26291,9 @@ __export(exports_policy_packs, {
|
|
|
25892
26291
|
getPolicyPack: () => getPolicyPack,
|
|
25893
26292
|
explainPolicyPack: () => explainPolicyPack
|
|
25894
26293
|
});
|
|
25895
|
-
import { relative as relative4, resolve as
|
|
26294
|
+
import { relative as relative4, resolve as resolve15 } from "path";
|
|
25896
26295
|
function normalizePath3(path) {
|
|
25897
|
-
return
|
|
26296
|
+
return resolve15(path);
|
|
25898
26297
|
}
|
|
25899
26298
|
function unique5(values) {
|
|
25900
26299
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -25949,7 +26348,7 @@ function commandMatches(commands, pattern) {
|
|
|
25949
26348
|
}
|
|
25950
26349
|
function pathMatches(paths, pattern, root) {
|
|
25951
26350
|
return paths.filter((path) => {
|
|
25952
|
-
const candidate = path.startsWith("/") ? path :
|
|
26351
|
+
const candidate = path.startsWith("/") ? path : resolve15(root, path);
|
|
25953
26352
|
if (!isPathInside3(root, candidate))
|
|
25954
26353
|
return matchesPattern3(path, pattern);
|
|
25955
26354
|
return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
|
|
@@ -26915,8 +27314,8 @@ var exports_doctor = {};
|
|
|
26915
27314
|
__export(exports_doctor, {
|
|
26916
27315
|
runTodosDoctor: () => runTodosDoctor
|
|
26917
27316
|
});
|
|
26918
|
-
import { chmodSync, copyFileSync, existsSync as
|
|
26919
|
-
import { basename as basename7, dirname as dirname7, join as
|
|
27317
|
+
import { chmodSync, copyFileSync, existsSync as existsSync15, mkdirSync as mkdirSync7, statSync as statSync6 } from "fs";
|
|
27318
|
+
import { basename as basename7, dirname as dirname7, join as join13 } from "path";
|
|
26920
27319
|
function tableExists(db, table) {
|
|
26921
27320
|
return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
|
|
26922
27321
|
}
|
|
@@ -27010,7 +27409,7 @@ function findMissingProjectRoots(db) {
|
|
|
27010
27409
|
continue;
|
|
27011
27410
|
if (!row.path.startsWith("/"))
|
|
27012
27411
|
continue;
|
|
27013
|
-
if (!
|
|
27412
|
+
if (!existsSync15(row.path))
|
|
27014
27413
|
missing++;
|
|
27015
27414
|
}
|
|
27016
27415
|
return missing;
|
|
@@ -27070,16 +27469,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
27070
27469
|
function createBackup(dbPath) {
|
|
27071
27470
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
27072
27471
|
return;
|
|
27073
|
-
if (!
|
|
27472
|
+
if (!existsSync15(dbPath))
|
|
27074
27473
|
return;
|
|
27075
27474
|
const stamp = now().replace(/[:.]/g, "-");
|
|
27076
|
-
const backupDir =
|
|
27475
|
+
const backupDir = join13(dirname7(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
|
|
27077
27476
|
const files = [];
|
|
27078
|
-
|
|
27477
|
+
mkdirSync7(backupDir, { recursive: true });
|
|
27079
27478
|
for (const source2 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
27080
|
-
if (!
|
|
27479
|
+
if (!existsSync15(source2))
|
|
27081
27480
|
continue;
|
|
27082
|
-
const target =
|
|
27481
|
+
const target = join13(backupDir, basename7(source2));
|
|
27083
27482
|
copyFileSync(source2, target);
|
|
27084
27483
|
files.push(target);
|
|
27085
27484
|
}
|
|
@@ -27305,7 +27704,7 @@ var init_doctor = __esm(() => {
|
|
|
27305
27704
|
});
|
|
27306
27705
|
|
|
27307
27706
|
// src/server/routes.ts
|
|
27308
|
-
import { join as
|
|
27707
|
+
import { join as join14, resolve as resolve16, sep as sep2 } from "path";
|
|
27309
27708
|
function parseFieldsParam(url) {
|
|
27310
27709
|
const fieldsParam = url.searchParams.get("fields");
|
|
27311
27710
|
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
@@ -28042,9 +28441,9 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
|
|
|
28042
28441
|
if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
|
|
28043
28442
|
return null;
|
|
28044
28443
|
if (path !== "/") {
|
|
28045
|
-
const filePath =
|
|
28046
|
-
const resolvedFile =
|
|
28047
|
-
const resolvedBase =
|
|
28444
|
+
const filePath = join14(ctx.dashboardDir, path);
|
|
28445
|
+
const resolvedFile = resolve16(filePath);
|
|
28446
|
+
const resolvedBase = resolve16(ctx.dashboardDir);
|
|
28048
28447
|
if (!resolvedFile.startsWith(resolvedBase + sep2) && resolvedFile !== resolvedBase) {
|
|
28049
28448
|
return json2({ error: "Forbidden" }, 403);
|
|
28050
28449
|
}
|
|
@@ -28052,7 +28451,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
|
|
|
28052
28451
|
if (res2)
|
|
28053
28452
|
return res2;
|
|
28054
28453
|
}
|
|
28055
|
-
const indexPath =
|
|
28454
|
+
const indexPath = join14(ctx.dashboardDir, "index.html");
|
|
28056
28455
|
const res = serveStaticFile2(indexPath);
|
|
28057
28456
|
if (res)
|
|
28058
28457
|
return res;
|
|
@@ -33047,8 +33446,8 @@ var exports_mention_resolver = {};
|
|
|
33047
33446
|
__export(exports_mention_resolver, {
|
|
33048
33447
|
resolveMentions: () => resolveMentions
|
|
33049
33448
|
});
|
|
33050
|
-
import { existsSync as
|
|
33051
|
-
import { basename as basename8, isAbsolute, join as
|
|
33449
|
+
import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync7 } from "fs";
|
|
33450
|
+
import { basename as basename8, isAbsolute, join as join15, relative as relative5, resolve as resolve17, sep as sep3 } from "path";
|
|
33052
33451
|
function blankResolution(parsed) {
|
|
33053
33452
|
return {
|
|
33054
33453
|
input: parsed.input,
|
|
@@ -33071,7 +33470,7 @@ function backlink(kind, key, label, target = key) {
|
|
|
33071
33470
|
return { kind, key, label, target };
|
|
33072
33471
|
}
|
|
33073
33472
|
function normalizeWorkspace(workspace) {
|
|
33074
|
-
return
|
|
33473
|
+
return resolve17(workspace || process.cwd());
|
|
33075
33474
|
}
|
|
33076
33475
|
function isInside(root, absolutePath) {
|
|
33077
33476
|
const rel = relative5(root, absolutePath);
|
|
@@ -33139,14 +33538,14 @@ function resolveFile(parsed, workspace) {
|
|
|
33139
33538
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
33140
33539
|
return resolution;
|
|
33141
33540
|
}
|
|
33142
|
-
const absolutePath =
|
|
33541
|
+
const absolutePath = resolve17(workspace, relPath);
|
|
33143
33542
|
if (!isInside(workspace, absolutePath)) {
|
|
33144
33543
|
resolution.path = relPath;
|
|
33145
33544
|
resolution.warnings.push("path escapes the workspace");
|
|
33146
33545
|
return resolution;
|
|
33147
33546
|
}
|
|
33148
33547
|
resolution.path = relPath;
|
|
33149
|
-
if (!
|
|
33548
|
+
if (!existsSync16(absolutePath)) {
|
|
33150
33549
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
33151
33550
|
return resolution;
|
|
33152
33551
|
}
|
|
@@ -33156,7 +33555,7 @@ function resolveFile(parsed, workspace) {
|
|
|
33156
33555
|
return resolution;
|
|
33157
33556
|
}
|
|
33158
33557
|
if (parsed.line !== undefined) {
|
|
33159
|
-
const lineCount =
|
|
33558
|
+
const lineCount = readFileSync9(absolutePath, "utf-8").split(/\r?\n/).length;
|
|
33160
33559
|
if (parsed.line < 1 || parsed.line > lineCount) {
|
|
33161
33560
|
resolution.warnings.push(`line ${parsed.line} is outside the file range 1-${lineCount}`);
|
|
33162
33561
|
return resolution;
|
|
@@ -33179,7 +33578,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
33179
33578
|
if (SKIP_DIRS3.has(entry.name))
|
|
33180
33579
|
continue;
|
|
33181
33580
|
}
|
|
33182
|
-
const absolutePath =
|
|
33581
|
+
const absolutePath = join15(current, entry.name);
|
|
33183
33582
|
if (entry.isDirectory()) {
|
|
33184
33583
|
if (!SKIP_DIRS3.has(entry.name))
|
|
33185
33584
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -33209,7 +33608,7 @@ function resolveSymbol(parsed, workspace, maxMatches) {
|
|
|
33209
33608
|
const pattern = symbolPattern(name);
|
|
33210
33609
|
const matches = [];
|
|
33211
33610
|
for (const file of walkSourceFiles(workspace)) {
|
|
33212
|
-
const lines =
|
|
33611
|
+
const lines = readFileSync9(file, "utf-8").split(/\r?\n/);
|
|
33213
33612
|
for (let index = 0;index < lines.length; index += 1) {
|
|
33214
33613
|
const line = lines[index];
|
|
33215
33614
|
const found = pattern.exec(line);
|
|
@@ -35943,8 +36342,8 @@ __export(exports_release_compatibility, {
|
|
|
35943
36342
|
createReleaseCompatibilityReport: () => createReleaseCompatibilityReport,
|
|
35944
36343
|
LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION: () => LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION
|
|
35945
36344
|
});
|
|
35946
|
-
import { readFileSync as
|
|
35947
|
-
import { join as
|
|
36345
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
36346
|
+
import { join as join16, resolve as resolve18 } from "path";
|
|
35948
36347
|
import { Database as Database2 } from "bun:sqlite";
|
|
35949
36348
|
function pass(id, message, details) {
|
|
35950
36349
|
return { id, status: "passed", message, details };
|
|
@@ -35956,7 +36355,7 @@ function warn(id, message, details) {
|
|
|
35956
36355
|
return { id, status: "warning", message, details };
|
|
35957
36356
|
}
|
|
35958
36357
|
function readPackageJson2(root) {
|
|
35959
|
-
return JSON.parse(
|
|
36358
|
+
return JSON.parse(readFileSync10(join16(root, "package.json"), "utf8"));
|
|
35960
36359
|
}
|
|
35961
36360
|
function sortedKeys(value) {
|
|
35962
36361
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -36052,7 +36451,7 @@ function checkChangelog() {
|
|
|
36052
36451
|
];
|
|
36053
36452
|
}
|
|
36054
36453
|
function createReleaseCompatibilityReport(options = {}) {
|
|
36055
|
-
const root =
|
|
36454
|
+
const root = resolve18(options.root ?? process.cwd());
|
|
36056
36455
|
const packageJson = readPackageJson2(root);
|
|
36057
36456
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
36058
36457
|
const checks = [
|
|
@@ -41635,7 +42034,7 @@ __export(exports_verification_providers, {
|
|
|
41635
42034
|
getVerificationRecord: () => getVerificationRecord,
|
|
41636
42035
|
discoverVerificationProviderCapabilities: () => discoverVerificationProviderCapabilities
|
|
41637
42036
|
});
|
|
41638
|
-
import { existsSync as
|
|
42037
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11 } from "fs";
|
|
41639
42038
|
function normalizeName6(name) {
|
|
41640
42039
|
const normalized = name.trim().toLowerCase();
|
|
41641
42040
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -41732,7 +42131,7 @@ function classifyLog(text) {
|
|
|
41732
42131
|
async function sleep3(ms) {
|
|
41733
42132
|
if (ms <= 0)
|
|
41734
42133
|
return;
|
|
41735
|
-
await new Promise((
|
|
42134
|
+
await new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
41736
42135
|
}
|
|
41737
42136
|
async function runCommandProvider(provider, input) {
|
|
41738
42137
|
const commandTemplate = input.command || provider.command;
|
|
@@ -41787,7 +42186,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
41787
42186
|
};
|
|
41788
42187
|
}
|
|
41789
42188
|
function runCiLogProvider(input) {
|
|
41790
|
-
const text = input.log_text ?? (input.log_path &&
|
|
42189
|
+
const text = input.log_text ?? (input.log_path && existsSync17(input.log_path) ? readFileSync11(input.log_path, "utf-8") : "");
|
|
41791
42190
|
return {
|
|
41792
42191
|
status: classifyLog(text),
|
|
41793
42192
|
attempts: 1,
|
|
@@ -41799,7 +42198,7 @@ function runBrowserProvider(input) {
|
|
|
41799
42198
|
if (!input.artifact_path) {
|
|
41800
42199
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
41801
42200
|
}
|
|
41802
|
-
if (!
|
|
42201
|
+
if (!existsSync17(input.artifact_path)) {
|
|
41803
42202
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
41804
42203
|
}
|
|
41805
42204
|
return {
|
|
@@ -44081,9 +44480,9 @@ __export(exports_local_backups, {
|
|
|
44081
44480
|
LOCAL_BACKUP_CHECKSUM_ALGORITHM: () => LOCAL_BACKUP_CHECKSUM_ALGORITHM
|
|
44082
44481
|
});
|
|
44083
44482
|
import { createHash as createHash8 } from "crypto";
|
|
44084
|
-
import { readFileSync as
|
|
44085
|
-
import { dirname as dirname8, resolve as
|
|
44086
|
-
import { mkdirSync as
|
|
44483
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
|
|
44484
|
+
import { dirname as dirname8, resolve as resolve19 } from "path";
|
|
44485
|
+
import { mkdirSync as mkdirSync8 } from "fs";
|
|
44087
44486
|
function stableJson(value) {
|
|
44088
44487
|
if (value === null || typeof value !== "object")
|
|
44089
44488
|
return JSON.stringify(value);
|
|
@@ -44184,14 +44583,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
44184
44583
|
return backup;
|
|
44185
44584
|
}
|
|
44186
44585
|
function writeLocalBackupFile(backup, outputPath) {
|
|
44187
|
-
const path =
|
|
44188
|
-
|
|
44189
|
-
|
|
44586
|
+
const path = resolve19(outputPath);
|
|
44587
|
+
mkdirSync8(dirname8(path), { recursive: true });
|
|
44588
|
+
writeFileSync6(path, `${JSON.stringify(backup, null, 2)}
|
|
44190
44589
|
`);
|
|
44191
44590
|
return path;
|
|
44192
44591
|
}
|
|
44193
44592
|
function readLocalBackupFile(path) {
|
|
44194
|
-
return JSON.parse(
|
|
44593
|
+
return JSON.parse(readFileSync12(resolve19(path), "utf-8"));
|
|
44195
44594
|
}
|
|
44196
44595
|
function verifyLocalBackup(value, options = {}, db) {
|
|
44197
44596
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -44387,8 +44786,8 @@ __export(exports_onboarding_fixtures, {
|
|
|
44387
44786
|
TODOS_ONBOARDING_FIXTURE_SOURCE: () => TODOS_ONBOARDING_FIXTURE_SOURCE,
|
|
44388
44787
|
TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION: () => TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION
|
|
44389
44788
|
});
|
|
44390
|
-
import { mkdirSync as
|
|
44391
|
-
import { join as
|
|
44789
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
44790
|
+
import { join as join17 } from "path";
|
|
44392
44791
|
function emptyData() {
|
|
44393
44792
|
return {
|
|
44394
44793
|
projects: [],
|
|
@@ -44718,11 +45117,11 @@ function getOnboardingFixtureBundle(name = "agent-project-demo") {
|
|
|
44718
45117
|
return getOnboardingFixture(name).bundle;
|
|
44719
45118
|
}
|
|
44720
45119
|
function writeOnboardingFixtureFiles(directory) {
|
|
44721
|
-
|
|
45120
|
+
mkdirSync9(directory, { recursive: true });
|
|
44722
45121
|
const files = [];
|
|
44723
45122
|
for (const fixture of allFixtures()) {
|
|
44724
|
-
const path =
|
|
44725
|
-
|
|
45123
|
+
const path = join17(directory, `${fixture.summary.name}.bridge.json`);
|
|
45124
|
+
writeFileSync7(path, `${JSON.stringify(fixture.bundle, null, 2)}
|
|
44726
45125
|
`, "utf-8");
|
|
44727
45126
|
files.push(path);
|
|
44728
45127
|
}
|
|
@@ -45369,7 +45768,7 @@ __export(exports_agent_replay_simulator, {
|
|
|
45369
45768
|
renderAgentReplaySimulationMarkdown: () => renderAgentReplaySimulationMarkdown
|
|
45370
45769
|
});
|
|
45371
45770
|
import { createHash as createHash10 } from "crypto";
|
|
45372
|
-
import { readFileSync as
|
|
45771
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
45373
45772
|
function isObject2(value) {
|
|
45374
45773
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
45375
45774
|
}
|
|
@@ -45602,7 +46001,7 @@ function simulateAgentReplay(input, options = {}) {
|
|
|
45602
46001
|
};
|
|
45603
46002
|
}
|
|
45604
46003
|
function simulateAgentReplayFile(path, options = {}) {
|
|
45605
|
-
const parsed = JSON.parse(
|
|
46004
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
45606
46005
|
return simulateAgentReplay(parsed, options);
|
|
45607
46006
|
}
|
|
45608
46007
|
function renderAgentReplaySimulationMarkdown(simulation) {
|
|
@@ -50889,28 +51288,28 @@ __export(exports_environment_snapshots, {
|
|
|
50889
51288
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
50890
51289
|
});
|
|
50891
51290
|
import { createHash as createHash12 } from "crypto";
|
|
50892
|
-
import { existsSync as
|
|
51291
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14, statSync as statSync8 } from "fs";
|
|
50893
51292
|
import { hostname as hostname2, platform, arch } from "os";
|
|
50894
|
-
import { dirname as dirname9, join as
|
|
51293
|
+
import { dirname as dirname9, join as join18, resolve as resolve20 } from "path";
|
|
50895
51294
|
import { tmpdir as tmpdir3 } from "os";
|
|
50896
51295
|
function sha2566(value) {
|
|
50897
51296
|
return createHash12("sha256").update(value).digest("hex");
|
|
50898
51297
|
}
|
|
50899
51298
|
function fileRecord(root, relativePath) {
|
|
50900
|
-
const path =
|
|
50901
|
-
if (!
|
|
51299
|
+
const path = join18(root, relativePath);
|
|
51300
|
+
if (!existsSync18(path))
|
|
50902
51301
|
return null;
|
|
50903
51302
|
const stat = statSync8(path);
|
|
50904
51303
|
if (!stat.isFile())
|
|
50905
51304
|
return null;
|
|
50906
|
-
const content =
|
|
51305
|
+
const content = readFileSync14(path);
|
|
50907
51306
|
return { path: relativePath, sha256: sha2566(content), size_bytes: content.length };
|
|
50908
51307
|
}
|
|
50909
51308
|
function manifestRecord(root, relativePath) {
|
|
50910
51309
|
const base = fileRecord(root, relativePath);
|
|
50911
51310
|
if (!base)
|
|
50912
51311
|
return null;
|
|
50913
|
-
const parsed = readJsonFile(
|
|
51312
|
+
const parsed = readJsonFile(join18(root, relativePath));
|
|
50914
51313
|
if (!parsed)
|
|
50915
51314
|
return { ...base, redacted: {} };
|
|
50916
51315
|
const redacted = redactValue({
|
|
@@ -51005,15 +51404,15 @@ function commandEnv(env, includeValues) {
|
|
|
51005
51404
|
function defaultSnapshotDir() {
|
|
51006
51405
|
const dbPath = getDatabasePath();
|
|
51007
51406
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
51008
|
-
return
|
|
51009
|
-
return
|
|
51407
|
+
return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
51408
|
+
return join18(dirname9(resolve20(dbPath)), "environment-snapshots");
|
|
51010
51409
|
}
|
|
51011
51410
|
function snapshotWithId(snapshot) {
|
|
51012
51411
|
const digest = sha2566(JSON.stringify(snapshot)).slice(0, 24);
|
|
51013
51412
|
return { id: `env_${digest}`, ...snapshot };
|
|
51014
51413
|
}
|
|
51015
51414
|
function captureEnvironmentSnapshot(input = {}) {
|
|
51016
|
-
const root =
|
|
51415
|
+
const root = resolve20(input.root || process.cwd());
|
|
51017
51416
|
const env = input.env || process.env;
|
|
51018
51417
|
const warnings = [];
|
|
51019
51418
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -51053,13 +51452,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
51053
51452
|
});
|
|
51054
51453
|
}
|
|
51055
51454
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
51056
|
-
const path = outputPath ?
|
|
51455
|
+
const path = outputPath ? resolve20(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
51057
51456
|
ensureDir2(dirname9(path));
|
|
51058
51457
|
writeJsonFile(path, snapshot);
|
|
51059
51458
|
return path;
|
|
51060
51459
|
}
|
|
51061
51460
|
function readEnvironmentSnapshot(path) {
|
|
51062
|
-
const snapshot = readJsonFile(
|
|
51461
|
+
const snapshot = readJsonFile(resolve20(path));
|
|
51063
51462
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
51064
51463
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
51065
51464
|
}
|
|
@@ -51584,27 +51983,27 @@ __export(exports_serve, {
|
|
|
51584
51983
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
51585
51984
|
MIME_TYPES: () => MIME_TYPES
|
|
51586
51985
|
});
|
|
51587
|
-
import { existsSync as
|
|
51588
|
-
import { join as
|
|
51986
|
+
import { existsSync as existsSync19 } from "fs";
|
|
51987
|
+
import { join as join19, dirname as dirname10, extname } from "path";
|
|
51589
51988
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
51590
51989
|
function resolveDashboardDir() {
|
|
51591
51990
|
const candidates = [];
|
|
51592
51991
|
try {
|
|
51593
51992
|
const scriptDir = dirname10(fileURLToPath2(import.meta.url));
|
|
51594
|
-
candidates.push(
|
|
51595
|
-
candidates.push(
|
|
51993
|
+
candidates.push(join19(scriptDir, "..", "dashboard", "dist"));
|
|
51994
|
+
candidates.push(join19(scriptDir, "..", "..", "dashboard", "dist"));
|
|
51596
51995
|
} catch {}
|
|
51597
51996
|
if (process.argv[1]) {
|
|
51598
51997
|
const mainDir = dirname10(process.argv[1]);
|
|
51599
|
-
candidates.push(
|
|
51600
|
-
candidates.push(
|
|
51998
|
+
candidates.push(join19(mainDir, "..", "dashboard", "dist"));
|
|
51999
|
+
candidates.push(join19(mainDir, "..", "..", "dashboard", "dist"));
|
|
51601
52000
|
}
|
|
51602
|
-
candidates.push(
|
|
52001
|
+
candidates.push(join19(process.cwd(), "dashboard", "dist"));
|
|
51603
52002
|
for (const candidate of candidates) {
|
|
51604
|
-
if (
|
|
52003
|
+
if (existsSync19(candidate))
|
|
51605
52004
|
return candidate;
|
|
51606
52005
|
}
|
|
51607
|
-
return
|
|
52006
|
+
return join19(process.cwd(), "dashboard", "dist");
|
|
51608
52007
|
}
|
|
51609
52008
|
function getProvidedApiKey(req) {
|
|
51610
52009
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -51654,7 +52053,7 @@ function json(data, status = 200, headers) {
|
|
|
51654
52053
|
});
|
|
51655
52054
|
}
|
|
51656
52055
|
function serveStaticFile(filePath) {
|
|
51657
|
-
if (!
|
|
52056
|
+
if (!existsSync19(filePath))
|
|
51658
52057
|
return null;
|
|
51659
52058
|
const ext = extname(filePath);
|
|
51660
52059
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -51735,7 +52134,7 @@ data: ${data}
|
|
|
51735
52134
|
filteredSseClients.delete(client);
|
|
51736
52135
|
}
|
|
51737
52136
|
const dashboardDir = resolveDashboardDir();
|
|
51738
|
-
const dashboardExists =
|
|
52137
|
+
const dashboardExists = existsSync19(dashboardDir);
|
|
51739
52138
|
if (!dashboardExists) {
|
|
51740
52139
|
console.error(`
|
|
51741
52140
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -53565,12 +53964,12 @@ __export(exports_config_serve_commands, {
|
|
|
53565
53964
|
registerConfigServeCommands: () => registerConfigServeCommands
|
|
53566
53965
|
});
|
|
53567
53966
|
import chalk6 from "chalk";
|
|
53568
|
-
import { existsSync as
|
|
53569
|
-
import { dirname as dirname11, join as
|
|
53967
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
|
|
53968
|
+
import { dirname as dirname11, join as join20 } from "path";
|
|
53570
53969
|
function registerConfigServeCommands(program2) {
|
|
53571
53970
|
program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
|
|
53572
53971
|
const globalOpts = program2.opts();
|
|
53573
|
-
const configPath =
|
|
53972
|
+
const configPath = join20(getTodosGlobalDir(), "config.json");
|
|
53574
53973
|
if (opts.get) {
|
|
53575
53974
|
const config2 = loadConfig();
|
|
53576
53975
|
const keys = opts.get.split(".");
|
|
@@ -53596,7 +53995,7 @@ function registerConfigServeCommands(program2) {
|
|
|
53596
53995
|
}
|
|
53597
53996
|
let config2 = {};
|
|
53598
53997
|
try {
|
|
53599
|
-
config2 = JSON.parse(
|
|
53998
|
+
config2 = JSON.parse(readFileSync15(configPath, "utf-8"));
|
|
53600
53999
|
} catch {}
|
|
53601
54000
|
const keys = key.split(".");
|
|
53602
54001
|
let obj = config2;
|
|
@@ -53607,9 +54006,9 @@ function registerConfigServeCommands(program2) {
|
|
|
53607
54006
|
}
|
|
53608
54007
|
obj[keys[keys.length - 1]] = parsedValue;
|
|
53609
54008
|
const dir = dirname11(configPath);
|
|
53610
|
-
if (!
|
|
53611
|
-
|
|
53612
|
-
|
|
54009
|
+
if (!existsSync20(dir))
|
|
54010
|
+
mkdirSync10(dir, { recursive: true });
|
|
54011
|
+
writeFileSync8(configPath, JSON.stringify(config2, null, 2));
|
|
53613
54012
|
if (globalOpts.json) {
|
|
53614
54013
|
output({ key, value: parsedValue }, true);
|
|
53615
54014
|
} else {
|
|
@@ -53736,7 +54135,7 @@ function registerConfigServeCommands(program2) {
|
|
|
53736
54135
|
redaction.command("scan [text]").description("Scan text or a file for secret-like values without printing values").option("--file <path>", "File to scan").action(async (text2, opts) => {
|
|
53737
54136
|
const globalOpts = program2.opts();
|
|
53738
54137
|
const { listSecretFindings: listSecretFindings2 } = await Promise.resolve().then(() => (init_redaction(), exports_redaction));
|
|
53739
|
-
const value = opts.file ?
|
|
54138
|
+
const value = opts.file ? readFileSync15(opts.file, "utf-8") : text2 || "";
|
|
53740
54139
|
const findings = listSecretFindings2(value);
|
|
53741
54140
|
if (globalOpts.json) {
|
|
53742
54141
|
output({ ok: findings.length === 0, findings }, true);
|
|
@@ -55122,7 +55521,7 @@ __export(exports_query_commands, {
|
|
|
55122
55521
|
registerQueryCommands: () => registerQueryCommands
|
|
55123
55522
|
});
|
|
55124
55523
|
import chalk7 from "chalk";
|
|
55125
|
-
import { readFileSync as
|
|
55524
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "fs";
|
|
55126
55525
|
function parseJsonObjectOption2(value, label) {
|
|
55127
55526
|
if (!value)
|
|
55128
55527
|
return;
|
|
@@ -55781,9 +56180,9 @@ Repairs`));
|
|
|
55781
56180
|
const db = getDatabase();
|
|
55782
56181
|
const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
|
|
55783
56182
|
const { statSync: statSync9 } = await import("fs");
|
|
55784
|
-
const { join:
|
|
56183
|
+
const { join: join21 } = await import("path");
|
|
55785
56184
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
55786
|
-
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] ||
|
|
56185
|
+
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join21(home, ".hasna", "todos", "todos.db");
|
|
55787
56186
|
let size = "unknown";
|
|
55788
56187
|
try {
|
|
55789
56188
|
size = `${(statSync9(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -56400,7 +56799,7 @@ Repairs`));
|
|
|
56400
56799
|
const sessionId = opts.session || globalOpts.session || undefined;
|
|
56401
56800
|
try {
|
|
56402
56801
|
if (opts.import) {
|
|
56403
|
-
const bundle = JSON.parse(
|
|
56802
|
+
const bundle = JSON.parse(readFileSync16(opts.import, "utf-8"));
|
|
56404
56803
|
const result = importHandoffBundle(bundle, { apply: opts.apply }, db);
|
|
56405
56804
|
if (opts.json || globalOpts.json) {
|
|
56406
56805
|
console.log(JSON.stringify(result));
|
|
@@ -56416,7 +56815,7 @@ Repairs`));
|
|
|
56416
56815
|
const bundle = exportHandoffBundle(opts.export, db);
|
|
56417
56816
|
const json2 = JSON.stringify(bundle, null, 2);
|
|
56418
56817
|
if (opts.output) {
|
|
56419
|
-
|
|
56818
|
+
writeFileSync9(opts.output, `${json2}
|
|
56420
56819
|
`);
|
|
56421
56820
|
if (opts.json || globalOpts.json) {
|
|
56422
56821
|
console.log(JSON.stringify({ path: opts.output, handoff_id: bundle.handoff.id }));
|
|
@@ -56647,7 +57046,7 @@ Repairs`));
|
|
|
56647
57046
|
});
|
|
56648
57047
|
const content = format === "json" ? JSON.stringify(document, null, 2) : renderReleaseNotesMarkdown2(document);
|
|
56649
57048
|
if (opts.out) {
|
|
56650
|
-
|
|
57049
|
+
writeFileSync9(opts.out, content);
|
|
56651
57050
|
if (format !== "json")
|
|
56652
57051
|
console.log(chalk7.green(`Wrote release notes to ${opts.out}`));
|
|
56653
57052
|
return;
|
|
@@ -56762,7 +57161,7 @@ Repairs`));
|
|
|
56762
57161
|
redact: Boolean(opts.redact)
|
|
56763
57162
|
});
|
|
56764
57163
|
if (opts.out) {
|
|
56765
|
-
|
|
57164
|
+
writeFileSync9(opts.out, exported.content);
|
|
56766
57165
|
if (!(opts.json || globalOpts.json))
|
|
56767
57166
|
console.log(chalk7.green(`Wrote ${exported.events.length} events to ${opts.out}`));
|
|
56768
57167
|
}
|
|
@@ -56778,7 +57177,7 @@ Repairs`));
|
|
|
56778
57177
|
});
|
|
56779
57178
|
calendar.command("import <path>").description("Import VEVENT entries from an ICS file as local imported calendar items").option("-j, --json", "Output JSON").action((path, opts) => {
|
|
56780
57179
|
try {
|
|
56781
|
-
const result = importCalendarIcs(
|
|
57180
|
+
const result = importCalendarIcs(readFileSync16(path, "utf-8"));
|
|
56782
57181
|
if (opts.json || program2.opts().json) {
|
|
56783
57182
|
output(result, true);
|
|
56784
57183
|
return;
|
|
@@ -56917,7 +57316,7 @@ Repairs`));
|
|
|
56917
57316
|
const bundle = exportTaskBoardBundle(boardId);
|
|
56918
57317
|
const json2 = JSON.stringify(bundle, null, 2);
|
|
56919
57318
|
if (opts.out) {
|
|
56920
|
-
|
|
57319
|
+
writeFileSync9(opts.out, json2);
|
|
56921
57320
|
if (!(opts.json || program2.opts().json))
|
|
56922
57321
|
console.log(chalk7.green(`Wrote ${bundle.boards.length} board(s) to ${opts.out}`));
|
|
56923
57322
|
}
|
|
@@ -56929,7 +57328,7 @@ Repairs`));
|
|
|
56929
57328
|
});
|
|
56930
57329
|
board.command("import <path>").description("Import local board definitions from a JSON bundle").option("-j, --json", "Output JSON").action((path, opts) => {
|
|
56931
57330
|
try {
|
|
56932
|
-
const bundle = JSON.parse(
|
|
57331
|
+
const bundle = JSON.parse(readFileSync16(path, "utf-8"));
|
|
56933
57332
|
const result = importTaskBoardBundle(bundle);
|
|
56934
57333
|
if (opts.json || program2.opts().json) {
|
|
56935
57334
|
output(result, true);
|
|
@@ -57305,7 +57704,7 @@ Repairs`));
|
|
|
57305
57704
|
const { importExternalIssues: importExternalIssues2 } = await Promise.resolve().then(() => (init_external_issue_importers(), exports_external_issue_importers));
|
|
57306
57705
|
let body = text2 || "";
|
|
57307
57706
|
if (opts.file)
|
|
57308
|
-
body =
|
|
57707
|
+
body = readFileSync16(opts.file, "utf-8");
|
|
57309
57708
|
if (!body && !opts.url && !process.stdin.isTTY)
|
|
57310
57709
|
body = await Bun.stdin.text();
|
|
57311
57710
|
if (!body.trim() && !opts.url) {
|
|
@@ -57363,7 +57762,7 @@ Repairs`));
|
|
|
57363
57762
|
} = await Promise.resolve().then(() => (init_tester_issue_reports(), exports_tester_issue_reports));
|
|
57364
57763
|
let body = jsonText || "";
|
|
57365
57764
|
if (opts.file)
|
|
57366
|
-
body =
|
|
57765
|
+
body = readFileSync16(opts.file, "utf-8");
|
|
57367
57766
|
if (!body && !process.stdin.isTTY)
|
|
57368
57767
|
body = await Bun.stdin.text();
|
|
57369
57768
|
if (!body.trim()) {
|
|
@@ -57406,11 +57805,11 @@ Repairs`));
|
|
|
57406
57805
|
const inbox = program2.command("inbox").description("Capture local inbox items from pasted errors, CI logs, git context, files, or GitHub issue URLs");
|
|
57407
57806
|
inbox.command("add [text]").description("Create a local inbox item and linked task from text, stdin, or a file").option("--file <path>", "Read captured context from a file").option("--source-type <type>", "pasted_error, ci_log, git_context, github_issue, file, or other").option("--source-name <name>", "Human-readable source name").option("--source-url <url>", "Source URL, including GitHub issue URLs").option("--title <title>", "Task/inbox title").option("--priority <priority>", "Task priority").option("--tags <tags>", "Comma-separated extra tags").option("--metadata <json>", "Additional JSON metadata").option("--no-task", "Only store inbox item; do not create a linked task").option("-j, --json", "Output as JSON").action(async (text2, opts) => {
|
|
57408
57807
|
const globalOpts = program2.opts();
|
|
57409
|
-
const { readFileSync:
|
|
57808
|
+
const { readFileSync: readFileSync17 } = await import("fs");
|
|
57410
57809
|
const { createInboxItem: createInboxItem2 } = await Promise.resolve().then(() => (init_inbox(), exports_inbox));
|
|
57411
57810
|
let body = text2 || "";
|
|
57412
57811
|
if (opts.file)
|
|
57413
|
-
body =
|
|
57812
|
+
body = readFileSync17(opts.file, "utf-8");
|
|
57414
57813
|
if (!body && !process.stdin.isTTY)
|
|
57415
57814
|
body = await Bun.stdin.text();
|
|
57416
57815
|
if (!body.trim()) {
|
|
@@ -57471,11 +57870,11 @@ ${diff}` : null].filter(Boolean).join(`
|
|
|
57471
57870
|
});
|
|
57472
57871
|
inbox.command("parse [text]").description("Preview or apply deterministic local natural-language task intake").option("--file <path>", "Read natural-language input from a file").option("--priority <priority>", "Default priority for parsed tasks", "medium").option("--project <id>", "Project ID for applied tasks").option("--list <id>", "Task list ID for applied tasks").option("--reference-date <iso>", "Reference date for due today/tomorrow/next week").option("--apply", "Create parsed tasks; default is dry-run preview").option("-j, --json", "Output as JSON").action(async (text2, opts) => {
|
|
57473
57872
|
const globalOpts = program2.opts();
|
|
57474
|
-
const { readFileSync:
|
|
57873
|
+
const { readFileSync: readFileSync17 } = await import("fs");
|
|
57475
57874
|
const { previewNaturalLanguageIntake: previewNaturalLanguageIntake2 } = await Promise.resolve().then(() => (init_natural_language_intake(), exports_natural_language_intake));
|
|
57476
57875
|
let body = text2 || "";
|
|
57477
57876
|
if (opts.file)
|
|
57478
|
-
body =
|
|
57877
|
+
body = readFileSync17(opts.file, "utf-8");
|
|
57479
57878
|
if (!body && !process.stdin.isTTY)
|
|
57480
57879
|
body = await Bun.stdin.text();
|
|
57481
57880
|
if (!body.trim()) {
|
|
@@ -57599,45 +57998,45 @@ __export(exports_mcp_hooks_commands, {
|
|
|
57599
57998
|
});
|
|
57600
57999
|
import chalk8 from "chalk";
|
|
57601
58000
|
import { execSync as execSync3 } from "child_process";
|
|
57602
|
-
import { existsSync as
|
|
57603
|
-
import { dirname as dirname12, join as
|
|
58001
|
+
import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, chmodSync as chmodSync2 } from "fs";
|
|
58002
|
+
import { dirname as dirname12, join as join21 } from "path";
|
|
57604
58003
|
function getMcpBinaryPath() {
|
|
57605
58004
|
try {
|
|
57606
58005
|
const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
|
|
57607
58006
|
if (p)
|
|
57608
58007
|
return p;
|
|
57609
58008
|
} catch {}
|
|
57610
|
-
const bunBin =
|
|
57611
|
-
if (
|
|
58009
|
+
const bunBin = join21(HOME2, ".bun", "bin", "todos-mcp");
|
|
58010
|
+
if (existsSync21(bunBin))
|
|
57612
58011
|
return bunBin;
|
|
57613
58012
|
return "todos-mcp";
|
|
57614
58013
|
}
|
|
57615
58014
|
function readJsonFile2(path) {
|
|
57616
|
-
if (!
|
|
58015
|
+
if (!existsSync21(path))
|
|
57617
58016
|
return {};
|
|
57618
58017
|
try {
|
|
57619
|
-
return JSON.parse(
|
|
58018
|
+
return JSON.parse(readFileSync17(path, "utf-8"));
|
|
57620
58019
|
} catch {
|
|
57621
58020
|
return {};
|
|
57622
58021
|
}
|
|
57623
58022
|
}
|
|
57624
58023
|
function writeJsonFile2(path, data) {
|
|
57625
58024
|
const dir = dirname12(path);
|
|
57626
|
-
if (!
|
|
57627
|
-
|
|
57628
|
-
|
|
58025
|
+
if (!existsSync21(dir))
|
|
58026
|
+
mkdirSync11(dir, { recursive: true });
|
|
58027
|
+
writeFileSync10(path, JSON.stringify(data, null, 2) + `
|
|
57629
58028
|
`);
|
|
57630
58029
|
}
|
|
57631
58030
|
function readTomlFile(path) {
|
|
57632
|
-
if (!
|
|
58031
|
+
if (!existsSync21(path))
|
|
57633
58032
|
return "";
|
|
57634
|
-
return
|
|
58033
|
+
return readFileSync17(path, "utf-8");
|
|
57635
58034
|
}
|
|
57636
58035
|
function writeTomlFile(path, content) {
|
|
57637
58036
|
const dir = dirname12(path);
|
|
57638
|
-
if (!
|
|
57639
|
-
|
|
57640
|
-
|
|
58037
|
+
if (!existsSync21(dir))
|
|
58038
|
+
mkdirSync11(dir, { recursive: true });
|
|
58039
|
+
writeFileSync10(path, content);
|
|
57641
58040
|
}
|
|
57642
58041
|
function removeTomlBlock(content, blockName) {
|
|
57643
58042
|
const lines = content.split(`
|
|
@@ -57701,7 +58100,7 @@ function unregisterClaude(_global) {
|
|
|
57701
58100
|
}
|
|
57702
58101
|
}
|
|
57703
58102
|
function registerCodex(binPath) {
|
|
57704
|
-
const configPath =
|
|
58103
|
+
const configPath = join21(HOME2, ".codex", "config.toml");
|
|
57705
58104
|
let content = readTomlFile(configPath);
|
|
57706
58105
|
content = removeTomlBlock(content, "mcp_servers.todos");
|
|
57707
58106
|
const block = `
|
|
@@ -57715,7 +58114,7 @@ args = []
|
|
|
57715
58114
|
console.log(chalk8.green(`Codex CLI: registered in ${configPath}`));
|
|
57716
58115
|
}
|
|
57717
58116
|
function unregisterCodex() {
|
|
57718
|
-
const configPath =
|
|
58117
|
+
const configPath = join21(HOME2, ".codex", "config.toml");
|
|
57719
58118
|
let content = readTomlFile(configPath);
|
|
57720
58119
|
if (!content.includes("[mcp_servers.todos]")) {
|
|
57721
58120
|
console.log(chalk8.dim(`Codex CLI: todos not found in ${configPath}`));
|
|
@@ -57727,7 +58126,7 @@ function unregisterCodex() {
|
|
|
57727
58126
|
console.log(chalk8.green(`Codex CLI: unregistered from ${configPath}`));
|
|
57728
58127
|
}
|
|
57729
58128
|
function registerGemini(binPath) {
|
|
57730
|
-
const configPath =
|
|
58129
|
+
const configPath = join21(HOME2, ".gemini", "settings.json");
|
|
57731
58130
|
const config = readJsonFile2(configPath);
|
|
57732
58131
|
if (!config["mcpServers"]) {
|
|
57733
58132
|
config["mcpServers"] = {};
|
|
@@ -57741,7 +58140,7 @@ function registerGemini(binPath) {
|
|
|
57741
58140
|
console.log(chalk8.green(`Gemini CLI: registered in ${configPath}`));
|
|
57742
58141
|
}
|
|
57743
58142
|
function unregisterGemini() {
|
|
57744
|
-
const configPath =
|
|
58143
|
+
const configPath = join21(HOME2, ".gemini", "settings.json");
|
|
57745
58144
|
const config = readJsonFile2(configPath);
|
|
57746
58145
|
const servers = config["mcpServers"];
|
|
57747
58146
|
if (!servers || !("todos" in servers)) {
|
|
@@ -57798,9 +58197,9 @@ function registerMcpHooksCommands(program2) {
|
|
|
57798
58197
|
if (p)
|
|
57799
58198
|
todosBin = p;
|
|
57800
58199
|
} catch {}
|
|
57801
|
-
const hooksDir =
|
|
57802
|
-
if (!
|
|
57803
|
-
|
|
58200
|
+
const hooksDir = join21(process.cwd(), ".claude", "hooks");
|
|
58201
|
+
if (!existsSync21(hooksDir))
|
|
58202
|
+
mkdirSync11(hooksDir, { recursive: true });
|
|
57804
58203
|
const hookScript = `#!/usr/bin/env bash
|
|
57805
58204
|
# Auto-generated by: todos hooks install
|
|
57806
58205
|
# Syncs todos with Claude Code task list on tool use events.
|
|
@@ -57824,11 +58223,11 @@ esac
|
|
|
57824
58223
|
|
|
57825
58224
|
exit 0
|
|
57826
58225
|
`;
|
|
57827
|
-
const hookPath =
|
|
57828
|
-
|
|
58226
|
+
const hookPath = join21(hooksDir, "todos-sync.sh");
|
|
58227
|
+
writeFileSync10(hookPath, hookScript);
|
|
57829
58228
|
execSync3(`chmod +x "${hookPath}"`);
|
|
57830
58229
|
console.log(chalk8.green(`Hook script created: ${hookPath}`));
|
|
57831
|
-
const settingsPath =
|
|
58230
|
+
const settingsPath = join21(process.cwd(), ".claude", "settings.json");
|
|
57832
58231
|
const settings = readJsonFile2(settingsPath);
|
|
57833
58232
|
if (!settings["hooks"]) {
|
|
57834
58233
|
settings["hooks"] = {};
|
|
@@ -58697,18 +59096,18 @@ Artifacts:`));
|
|
|
58697
59096
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
58698
59097
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
58699
59098
|
const marker = "# todos-auto-link";
|
|
58700
|
-
if (
|
|
58701
|
-
const existing =
|
|
59099
|
+
if (existsSync21(hookPath)) {
|
|
59100
|
+
const existing = readFileSync17(hookPath, "utf-8");
|
|
58702
59101
|
if (existing.includes(marker)) {
|
|
58703
59102
|
console.log(chalk8.yellow("Hook already installed."));
|
|
58704
59103
|
return;
|
|
58705
59104
|
}
|
|
58706
|
-
|
|
59105
|
+
writeFileSync10(hookPath, existing + `
|
|
58707
59106
|
${marker}
|
|
58708
59107
|
$(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
58709
59108
|
`);
|
|
58710
59109
|
} else {
|
|
58711
|
-
|
|
59110
|
+
writeFileSync10(hookPath, `#!/usr/bin/env bash
|
|
58712
59111
|
${marker}
|
|
58713
59112
|
$(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
58714
59113
|
`);
|
|
@@ -58725,11 +59124,11 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
58725
59124
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
58726
59125
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
58727
59126
|
const marker = "# todos-auto-link";
|
|
58728
|
-
if (!
|
|
59127
|
+
if (!existsSync21(hookPath)) {
|
|
58729
59128
|
console.log(chalk8.dim("No post-commit hook found."));
|
|
58730
59129
|
return;
|
|
58731
59130
|
}
|
|
58732
|
-
const content =
|
|
59131
|
+
const content = readFileSync17(hookPath, "utf-8");
|
|
58733
59132
|
if (!content.includes(marker)) {
|
|
58734
59133
|
console.log(chalk8.dim("Hook not managed by todos."));
|
|
58735
59134
|
return;
|
|
@@ -58740,7 +59139,7 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
58740
59139
|
if (cleaned === "#!/usr/bin/env bash" || cleaned === "") {
|
|
58741
59140
|
(await import("fs")).unlinkSync(hookPath);
|
|
58742
59141
|
} else {
|
|
58743
|
-
|
|
59142
|
+
writeFileSync10(hookPath, cleaned + `
|
|
58744
59143
|
`);
|
|
58745
59144
|
}
|
|
58746
59145
|
console.log(chalk8.green("Post-commit hook removed."));
|
|
@@ -58909,9 +59308,9 @@ __export(exports_machines, {
|
|
|
58909
59308
|
});
|
|
58910
59309
|
import chalk10 from "chalk";
|
|
58911
59310
|
import { execSync as execSync4 } from "child_process";
|
|
58912
|
-
import { readFileSync as
|
|
59311
|
+
import { readFileSync as readFileSync18, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
|
|
58913
59312
|
import { tmpdir as tmpdir4 } from "os";
|
|
58914
|
-
import { join as
|
|
59313
|
+
import { join as join22 } from "path";
|
|
58915
59314
|
function getOrCreateLocalMachineName() {
|
|
58916
59315
|
return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
|
|
58917
59316
|
}
|
|
@@ -58949,11 +59348,11 @@ function remoteTempPath(sshAddress) {
|
|
|
58949
59348
|
}
|
|
58950
59349
|
function readRemoteBridgeBundle(sshAddress) {
|
|
58951
59350
|
const remotePath = remoteTempPath(sshAddress);
|
|
58952
|
-
const localPath =
|
|
59351
|
+
const localPath = join22(tmpdir4(), `todos-bridge-pull-${uuid()}.json`);
|
|
58953
59352
|
try {
|
|
58954
59353
|
runSsh(sshAddress, `todos export --format bridge --allow-plaintext-sensitive --output ${shellQuote(remotePath)}`, 120000);
|
|
58955
59354
|
scpFromRemote(sshAddress, remotePath, localPath);
|
|
58956
|
-
return JSON.parse(
|
|
59355
|
+
return JSON.parse(readFileSync18(localPath, "utf-8"));
|
|
58957
59356
|
} finally {
|
|
58958
59357
|
try {
|
|
58959
59358
|
runSsh(sshAddress, `rm -f ${shellQuote(remotePath)}`, 1e4);
|
|
@@ -58964,8 +59363,8 @@ function readRemoteBridgeBundle(sshAddress) {
|
|
|
58964
59363
|
}
|
|
58965
59364
|
}
|
|
58966
59365
|
function writeLocalBridgeBundle() {
|
|
58967
|
-
const localPath =
|
|
58968
|
-
|
|
59366
|
+
const localPath = join22(tmpdir4(), `todos-bridge-push-${uuid()}.json`);
|
|
59367
|
+
writeFileSync11(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
|
|
58969
59368
|
return localPath;
|
|
58970
59369
|
}
|
|
58971
59370
|
function pushLocalBridgeBundle(sshAddress, dryRun) {
|
|
@@ -59403,7 +59802,7 @@ __export(exports_environment_snapshots2, {
|
|
|
59403
59802
|
registerEnvironmentSnapshotCommands: () => registerEnvironmentSnapshotCommands
|
|
59404
59803
|
});
|
|
59405
59804
|
import chalk12 from "chalk";
|
|
59406
|
-
function
|
|
59805
|
+
function printJson2(value) {
|
|
59407
59806
|
console.log(JSON.stringify(value, null, 2));
|
|
59408
59807
|
}
|
|
59409
59808
|
function registerEnvironmentSnapshotCommands(program2) {
|
|
@@ -59421,7 +59820,7 @@ function registerEnvironmentSnapshotCommands(program2) {
|
|
|
59421
59820
|
include_env_values: Boolean(opts.includeEnvValues)
|
|
59422
59821
|
});
|
|
59423
59822
|
if (globalOpts.json) {
|
|
59424
|
-
|
|
59823
|
+
printJson2(result);
|
|
59425
59824
|
return;
|
|
59426
59825
|
}
|
|
59427
59826
|
console.log(chalk12.green("Captured") + ` ${result.snapshot.id}`);
|
|
@@ -59438,7 +59837,7 @@ function registerEnvironmentSnapshotCommands(program2) {
|
|
|
59438
59837
|
} catch (error) {
|
|
59439
59838
|
const message = error instanceof Error ? error.message : String(error);
|
|
59440
59839
|
if (globalOpts.json)
|
|
59441
|
-
|
|
59840
|
+
printJson2({ error: message });
|
|
59442
59841
|
else
|
|
59443
59842
|
console.error(chalk12.red(`Error: ${message}`));
|
|
59444
59843
|
process.exit(1);
|
|
@@ -59449,7 +59848,7 @@ function registerEnvironmentSnapshotCommands(program2) {
|
|
|
59449
59848
|
try {
|
|
59450
59849
|
const comparison = compareEnvironmentSnapshotFiles(left, right);
|
|
59451
59850
|
if (globalOpts.json) {
|
|
59452
|
-
|
|
59851
|
+
printJson2(comparison);
|
|
59453
59852
|
return;
|
|
59454
59853
|
}
|
|
59455
59854
|
console.log(`left: ${comparison.left_id}`);
|
|
@@ -59464,7 +59863,7 @@ function registerEnvironmentSnapshotCommands(program2) {
|
|
|
59464
59863
|
} catch (error) {
|
|
59465
59864
|
const message = error instanceof Error ? error.message : String(error);
|
|
59466
59865
|
if (globalOpts.json)
|
|
59467
|
-
|
|
59866
|
+
printJson2({ error: message });
|
|
59468
59867
|
else
|
|
59469
59868
|
console.error(chalk12.red(`Error: ${message}`));
|
|
59470
59869
|
process.exit(1);
|
|
@@ -60028,7 +60427,7 @@ __export(exports_onboarding_commands, {
|
|
|
60028
60427
|
registerOnboardingCommands: () => registerOnboardingCommands
|
|
60029
60428
|
});
|
|
60030
60429
|
import chalk17 from "chalk";
|
|
60031
|
-
import { resolve as
|
|
60430
|
+
import { resolve as resolve21 } from "path";
|
|
60032
60431
|
function registerOnboardingCommands(program2) {
|
|
60033
60432
|
program2.command("onboarding").alias("demo-fixtures").description("List, show, write, or import bundled local onboarding fixtures").option("--show <name>", "Show one fixture bridge bundle as JSON").option("--write <dir>", "Write all bundled fixture bridge bundles to a directory").option("--import <name>", "Dry-run or apply an onboarding fixture import").option("--apply", "Apply an onboarding fixture import. Defaults to dry-run.").option("--resolve-conflicts", "Safely merge existing local tasks while preserving divergent fields").action(async (opts) => {
|
|
60034
60433
|
const globalOpts = program2.opts();
|
|
@@ -60044,7 +60443,7 @@ function registerOnboardingCommands(program2) {
|
|
|
60044
60443
|
return;
|
|
60045
60444
|
}
|
|
60046
60445
|
if (opts.write) {
|
|
60047
|
-
const result = writeOnboardingFixtureFiles2(
|
|
60446
|
+
const result = writeOnboardingFixtureFiles2(resolve21(opts.write));
|
|
60048
60447
|
if (globalOpts.json) {
|
|
60049
60448
|
output(result, true);
|
|
60050
60449
|
return;
|
|
@@ -63492,8 +63891,8 @@ __export(exports_sdk_integration_fixtures, {
|
|
|
63492
63891
|
TODOS_SDK_INTEGRATION_FIXTURE_SCHEMA_VERSION: () => TODOS_SDK_INTEGRATION_FIXTURE_SCHEMA_VERSION,
|
|
63493
63892
|
TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT: () => TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT
|
|
63494
63893
|
});
|
|
63495
|
-
import { mkdirSync as
|
|
63496
|
-
import { join as
|
|
63894
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
63895
|
+
import { join as join23 } from "path";
|
|
63497
63896
|
function source5(version) {
|
|
63498
63897
|
return {
|
|
63499
63898
|
packageName: "@hasna/todos",
|
|
@@ -63589,7 +63988,7 @@ function createSdkIntegrationFixturePack(options = {}) {
|
|
|
63589
63988
|
};
|
|
63590
63989
|
}
|
|
63591
63990
|
function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
63592
|
-
|
|
63991
|
+
mkdirSync12(directory, { recursive: true });
|
|
63593
63992
|
const pack = createSdkIntegrationFixturePack(options);
|
|
63594
63993
|
const bundle = getOnboardingFixtureBundle("agent-project-demo");
|
|
63595
63994
|
const files = [
|
|
@@ -63600,8 +63999,8 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
|
63600
63999
|
];
|
|
63601
64000
|
const written = [];
|
|
63602
64001
|
for (const [name, payload] of files) {
|
|
63603
|
-
const file =
|
|
63604
|
-
|
|
64002
|
+
const file = join23(directory, name);
|
|
64003
|
+
writeFileSync12(file, `${JSON.stringify(payload, null, 2)}
|
|
63605
64004
|
`, "utf-8");
|
|
63606
64005
|
written.push(file);
|
|
63607
64006
|
}
|
|
@@ -63624,7 +64023,7 @@ __export(exports_sdk_fixture_commands, {
|
|
|
63624
64023
|
registerSdkFixtureCommands: () => registerSdkFixtureCommands
|
|
63625
64024
|
});
|
|
63626
64025
|
import chalk19 from "chalk";
|
|
63627
|
-
import { resolve as
|
|
64026
|
+
import { resolve as resolve22 } from "path";
|
|
63628
64027
|
function registerSdkFixtureCommands(program2) {
|
|
63629
64028
|
program2.command("sdk-fixtures").description("List, show, or write local SDK integration fixtures").option("--show", "Print the full fixture pack JSON").option("--write <dir>", "Write fixture pack, bridge fixture, contract snapshots, and example index to a directory").action(async (opts) => {
|
|
63630
64029
|
const globalOpts = program2.opts();
|
|
@@ -63635,7 +64034,7 @@ function registerSdkFixtureCommands(program2) {
|
|
|
63635
64034
|
writeSdkIntegrationFixtures: writeSdkIntegrationFixtures2
|
|
63636
64035
|
} = await Promise.resolve().then(() => (init_sdk_integration_fixtures(), exports_sdk_integration_fixtures));
|
|
63637
64036
|
if (opts.write) {
|
|
63638
|
-
const result = writeSdkIntegrationFixtures2(
|
|
64037
|
+
const result = writeSdkIntegrationFixtures2(resolve22(opts.write));
|
|
63639
64038
|
if (globalOpts.json) {
|
|
63640
64039
|
console.log(JSON.stringify(result));
|
|
63641
64040
|
return;
|
|
@@ -63865,7 +64264,7 @@ var exports_roadmap_commands = {};
|
|
|
63865
64264
|
__export(exports_roadmap_commands, {
|
|
63866
64265
|
registerRoadmapCommands: () => registerRoadmapCommands
|
|
63867
64266
|
});
|
|
63868
|
-
import { readFileSync as
|
|
64267
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
63869
64268
|
import chalk21 from "chalk";
|
|
63870
64269
|
function splitList3(value) {
|
|
63871
64270
|
return value?.split(";").flatMap((part) => part.split(",")).map((item) => item.trim()).filter(Boolean);
|
|
@@ -64076,7 +64475,7 @@ function registerRoadmapCommands(program2) {
|
|
|
64076
64475
|
const { exportRoadmapBundle: exportRoadmapBundle2, renderRoadmapMarkdown: renderRoadmapMarkdown2 } = await Promise.resolve().then(() => (init_roadmaps(), exports_roadmaps));
|
|
64077
64476
|
const content = opts.format === "markdown" ? renderRoadmapMarkdown2(roadmap) : JSON.stringify(exportRoadmapBundle2(roadmap), null, 2);
|
|
64078
64477
|
if (opts.out) {
|
|
64079
|
-
|
|
64478
|
+
writeFileSync13(opts.out, content);
|
|
64080
64479
|
if (!globalOpts.json)
|
|
64081
64480
|
console.log(chalk21.green(`Wrote roadmap export to ${opts.out}`));
|
|
64082
64481
|
}
|
|
@@ -64094,7 +64493,7 @@ function registerRoadmapCommands(program2) {
|
|
|
64094
64493
|
const globalOpts = globalOptions(program2);
|
|
64095
64494
|
try {
|
|
64096
64495
|
const { importRoadmapBundle: importRoadmapBundle2 } = await Promise.resolve().then(() => (init_roadmaps(), exports_roadmaps));
|
|
64097
|
-
const bundle = JSON.parse(
|
|
64496
|
+
const bundle = JSON.parse(readFileSync19(path, "utf8"));
|
|
64098
64497
|
const result = importRoadmapBundle2(bundle, { apply: Boolean(opts.apply) });
|
|
64099
64498
|
if (globalOpts.json) {
|
|
64100
64499
|
output(result, true);
|
|
@@ -64457,7 +64856,7 @@ __export(exports_local_backup_commands, {
|
|
|
64457
64856
|
registerLocalBackupCommands: () => registerLocalBackupCommands
|
|
64458
64857
|
});
|
|
64459
64858
|
import chalk26 from "chalk";
|
|
64460
|
-
import { resolve as
|
|
64859
|
+
import { resolve as resolve23 } from "path";
|
|
64461
64860
|
function globalOptions6(program2) {
|
|
64462
64861
|
const command = program2;
|
|
64463
64862
|
return command.optsWithGlobals?.() ?? program2.opts();
|
|
@@ -64479,10 +64878,10 @@ function registerLocalBackupCommands(program2) {
|
|
|
64479
64878
|
const projectId = opts.projectId ?? autoProject(globalOpts);
|
|
64480
64879
|
const backupBundle = createLocalBackup2({
|
|
64481
64880
|
project_id: projectId,
|
|
64482
|
-
output_path: opts.output ?
|
|
64881
|
+
output_path: opts.output ? resolve23(opts.output) : undefined
|
|
64483
64882
|
});
|
|
64484
64883
|
const result = {
|
|
64485
|
-
output_path: opts.output ?
|
|
64884
|
+
output_path: opts.output ? resolve23(opts.output) : null,
|
|
64486
64885
|
backup: backupBundle
|
|
64487
64886
|
};
|
|
64488
64887
|
if (opts.json || globalOpts.json) {
|