@hasna/todos 0.11.69 → 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/index.js +603 -234
- 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 +2 -2
- package/dist/server/index.js +2 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1011,7 +1011,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1011
1011
|
this._exitCallback = (err) => {
|
|
1012
1012
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
1013
1013
|
throw err;
|
|
1014
|
-
}
|
|
1014
|
+
}
|
|
1015
1015
|
};
|
|
1016
1016
|
}
|
|
1017
1017
|
return this;
|
|
@@ -13681,6 +13681,299 @@ var init_task_commands = __esm(() => {
|
|
|
13681
13681
|
init_types();
|
|
13682
13682
|
});
|
|
13683
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
|
+
|
|
13684
13977
|
// src/db/builtin-templates.ts
|
|
13685
13978
|
var exports_builtin_templates = {};
|
|
13686
13979
|
__export(exports_builtin_templates, {
|
|
@@ -13695,8 +13988,8 @@ __export(exports_builtin_templates, {
|
|
|
13695
13988
|
BUILTIN_TEMPLATE_LIBRARY_SOURCE: () => BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
13696
13989
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
13697
13990
|
});
|
|
13698
|
-
import { mkdirSync as
|
|
13699
|
-
import { join as
|
|
13991
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
13992
|
+
import { join as join8 } from "path";
|
|
13700
13993
|
function templateMetadata(template) {
|
|
13701
13994
|
return {
|
|
13702
13995
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -13752,11 +14045,11 @@ function exportBuiltinTemplateFiles() {
|
|
|
13752
14045
|
}));
|
|
13753
14046
|
}
|
|
13754
14047
|
function writeBuiltinTemplateFiles(directory) {
|
|
13755
|
-
|
|
14048
|
+
mkdirSync6(directory, { recursive: true });
|
|
13756
14049
|
const files = [];
|
|
13757
14050
|
for (const entry of exportBuiltinTemplateFiles()) {
|
|
13758
|
-
const path =
|
|
13759
|
-
|
|
14051
|
+
const path = join8(directory, entry.filename);
|
|
14052
|
+
writeFileSync4(path, `${JSON.stringify(entry.template, null, 2)}
|
|
13760
14053
|
`, "utf-8");
|
|
13761
14054
|
files.push(path);
|
|
13762
14055
|
}
|
|
@@ -14024,7 +14317,7 @@ __export(exports_plan_template_commands, {
|
|
|
14024
14317
|
});
|
|
14025
14318
|
import chalk3 from "chalk";
|
|
14026
14319
|
function registerPlanTemplateCommands(program2) {
|
|
14027
|
-
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) => {
|
|
14028
14321
|
const globalOpts = program2.opts();
|
|
14029
14322
|
const projectId = autoProject(globalOpts);
|
|
14030
14323
|
if (opts.add) {
|
|
@@ -14033,11 +14326,71 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14033
14326
|
description: opts.description,
|
|
14034
14327
|
project_id: projectId
|
|
14035
14328
|
});
|
|
14329
|
+
const artifact = writePlanArtifact(plan);
|
|
14036
14330
|
if (globalOpts.json) {
|
|
14037
14331
|
output(plan, true);
|
|
14038
14332
|
} else {
|
|
14039
14333
|
console.log(chalk3.green("Plan created:"));
|
|
14040
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}`);
|
|
14041
14394
|
}
|
|
14042
14395
|
return;
|
|
14043
14396
|
}
|
|
@@ -14055,8 +14408,18 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14055
14408
|
}
|
|
14056
14409
|
const { listTasks: listTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
14057
14410
|
const tasks = listTasks2({ plan_id: resolvedId });
|
|
14411
|
+
const artifact = readPlanArtifact(plan, db);
|
|
14058
14412
|
if (globalOpts.json) {
|
|
14059
|
-
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);
|
|
14060
14423
|
return;
|
|
14061
14424
|
}
|
|
14062
14425
|
console.log(chalk3.bold(`Plan Details:
|
|
@@ -14068,6 +14431,8 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14068
14431
|
console.log(` ${chalk3.dim("Desc:")} ${plan.description}`);
|
|
14069
14432
|
if (plan.project_id)
|
|
14070
14433
|
console.log(` ${chalk3.dim("Project:")} ${plan.project_id}`);
|
|
14434
|
+
if (artifact)
|
|
14435
|
+
console.log(` ${chalk3.dim("Artifact:")} ${artifact.path}`);
|
|
14071
14436
|
console.log(` ${chalk3.dim("Created:")} ${plan.created_at}`);
|
|
14072
14437
|
if (tasks.length > 0) {
|
|
14073
14438
|
console.log(chalk3.bold(`
|
|
@@ -14108,11 +14473,14 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14108
14473
|
}
|
|
14109
14474
|
try {
|
|
14110
14475
|
const plan = updatePlan(resolvedId, { status: "completed" });
|
|
14476
|
+
const artifact = writePlanArtifact(plan);
|
|
14111
14477
|
if (globalOpts.json) {
|
|
14112
14478
|
output(plan, true);
|
|
14113
14479
|
} else {
|
|
14114
14480
|
console.log(chalk3.green("Plan completed:"));
|
|
14115
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}`);
|
|
14116
14484
|
}
|
|
14117
14485
|
} catch (e) {
|
|
14118
14486
|
handleError(e);
|
|
@@ -14390,14 +14758,14 @@ function registerPlanTemplateCommands(program2) {
|
|
|
14390
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) => {
|
|
14391
14759
|
const globalOpts = program2.opts();
|
|
14392
14760
|
const { importTemplate: importTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
14393
|
-
const { readFileSync:
|
|
14761
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
14394
14762
|
try {
|
|
14395
14763
|
const filePath = file || opts.file;
|
|
14396
14764
|
if (!filePath) {
|
|
14397
14765
|
console.error(chalk3.red("Provide a file path: todos template-import <file> or --file <path>"));
|
|
14398
14766
|
process.exit(1);
|
|
14399
14767
|
}
|
|
14400
|
-
const content =
|
|
14768
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
14401
14769
|
const json = JSON.parse(content);
|
|
14402
14770
|
const template = importTemplate2(json);
|
|
14403
14771
|
if (globalOpts.json) {
|
|
@@ -14441,6 +14809,7 @@ var init_plan_template_commands = __esm(() => {
|
|
|
14441
14809
|
init_database();
|
|
14442
14810
|
init_plans();
|
|
14443
14811
|
init_tasks();
|
|
14812
|
+
init_plan_artifacts();
|
|
14444
14813
|
init_helpers();
|
|
14445
14814
|
});
|
|
14446
14815
|
|
|
@@ -15009,16 +15378,16 @@ var init_saved_search_views = __esm(() => {
|
|
|
15009
15378
|
});
|
|
15010
15379
|
|
|
15011
15380
|
// src/lib/claude-tasks.ts
|
|
15012
|
-
import { existsSync as
|
|
15013
|
-
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";
|
|
15014
15383
|
function getTaskListDir(taskListId) {
|
|
15015
|
-
return
|
|
15384
|
+
return join9(HOME, ".claude", "tasks", taskListId);
|
|
15016
15385
|
}
|
|
15017
15386
|
function readClaudeTask(dir, filename) {
|
|
15018
|
-
return readJsonFile(
|
|
15387
|
+
return readJsonFile(join9(dir, filename));
|
|
15019
15388
|
}
|
|
15020
15389
|
function writeClaudeTask(dir, task) {
|
|
15021
|
-
writeJsonFile(
|
|
15390
|
+
writeJsonFile(join9(dir, `${task.id}.json`), task);
|
|
15022
15391
|
}
|
|
15023
15392
|
function toClaudeStatus(status) {
|
|
15024
15393
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -15030,14 +15399,14 @@ function toSqliteStatus(status) {
|
|
|
15030
15399
|
return status;
|
|
15031
15400
|
}
|
|
15032
15401
|
function readPrefixCounter(dir) {
|
|
15033
|
-
const path =
|
|
15034
|
-
if (!
|
|
15402
|
+
const path = join9(dir, ".prefix-counter");
|
|
15403
|
+
if (!existsSync9(path))
|
|
15035
15404
|
return 0;
|
|
15036
|
-
const val = parseInt(
|
|
15405
|
+
const val = parseInt(readFileSync5(path, "utf-8").trim(), 10);
|
|
15037
15406
|
return isNaN(val) ? 0 : val;
|
|
15038
15407
|
}
|
|
15039
15408
|
function writePrefixCounter(dir, value) {
|
|
15040
|
-
|
|
15409
|
+
writeFileSync5(join9(dir, ".prefix-counter"), String(value));
|
|
15041
15410
|
}
|
|
15042
15411
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
15043
15412
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -15064,7 +15433,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
15064
15433
|
}
|
|
15065
15434
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
15066
15435
|
const dir = getTaskListDir(taskListId);
|
|
15067
|
-
if (!
|
|
15436
|
+
if (!existsSync9(dir))
|
|
15068
15437
|
ensureDir2(dir);
|
|
15069
15438
|
const filter = {};
|
|
15070
15439
|
if (projectId)
|
|
@@ -15073,7 +15442,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
15073
15442
|
const existingByTodosId = new Map;
|
|
15074
15443
|
const files = listJsonFiles(dir);
|
|
15075
15444
|
for (const f of files) {
|
|
15076
|
-
const path =
|
|
15445
|
+
const path = join9(dir, f);
|
|
15077
15446
|
const ct = readClaudeTask(dir, f);
|
|
15078
15447
|
if (ct?.metadata?.["todos_id"]) {
|
|
15079
15448
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -15160,7 +15529,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
15160
15529
|
}
|
|
15161
15530
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
15162
15531
|
const dir = getTaskListDir(taskListId);
|
|
15163
|
-
if (!
|
|
15532
|
+
if (!existsSync9(dir)) {
|
|
15164
15533
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
15165
15534
|
}
|
|
15166
15535
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -15180,7 +15549,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
15180
15549
|
}
|
|
15181
15550
|
for (const f of files) {
|
|
15182
15551
|
try {
|
|
15183
|
-
const filePath =
|
|
15552
|
+
const filePath = join9(dir, f);
|
|
15184
15553
|
const ct = readClaudeTask(dir, f);
|
|
15185
15554
|
if (!ct)
|
|
15186
15555
|
continue;
|
|
@@ -15253,20 +15622,20 @@ var init_claude_tasks = __esm(() => {
|
|
|
15253
15622
|
});
|
|
15254
15623
|
|
|
15255
15624
|
// src/lib/agent-tasks.ts
|
|
15256
|
-
import { existsSync as
|
|
15257
|
-
import { join as
|
|
15625
|
+
import { existsSync as existsSync10 } from "fs";
|
|
15626
|
+
import { join as join10 } from "path";
|
|
15258
15627
|
function agentBaseDir(agent) {
|
|
15259
15628
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
15260
|
-
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");
|
|
15261
15630
|
}
|
|
15262
15631
|
function getTaskListDir2(agent, taskListId) {
|
|
15263
|
-
return
|
|
15632
|
+
return join10(agentBaseDir(agent), agent, taskListId);
|
|
15264
15633
|
}
|
|
15265
15634
|
function readAgentTask(dir, filename) {
|
|
15266
|
-
return readJsonFile(
|
|
15635
|
+
return readJsonFile(join10(dir, filename));
|
|
15267
15636
|
}
|
|
15268
15637
|
function writeAgentTask(dir, task) {
|
|
15269
|
-
writeJsonFile(
|
|
15638
|
+
writeJsonFile(join10(dir, `${task.id}.json`), task);
|
|
15270
15639
|
}
|
|
15271
15640
|
function taskToAgentTask(task, externalId, existingMeta) {
|
|
15272
15641
|
return {
|
|
@@ -15291,7 +15660,7 @@ function metadataKey(agent) {
|
|
|
15291
15660
|
}
|
|
15292
15661
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
15293
15662
|
const dir = getTaskListDir2(agent, taskListId);
|
|
15294
|
-
if (!
|
|
15663
|
+
if (!existsSync10(dir))
|
|
15295
15664
|
ensureDir2(dir);
|
|
15296
15665
|
const filter = {};
|
|
15297
15666
|
if (projectId)
|
|
@@ -15300,7 +15669,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
15300
15669
|
const existingByTodosId = new Map;
|
|
15301
15670
|
const files = listJsonFiles(dir);
|
|
15302
15671
|
for (const f of files) {
|
|
15303
|
-
const path =
|
|
15672
|
+
const path = join10(dir, f);
|
|
15304
15673
|
const at = readAgentTask(dir, f);
|
|
15305
15674
|
if (at?.metadata?.["todos_id"]) {
|
|
15306
15675
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -15374,7 +15743,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
15374
15743
|
}
|
|
15375
15744
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
15376
15745
|
const dir = getTaskListDir2(agent, taskListId);
|
|
15377
|
-
if (!
|
|
15746
|
+
if (!existsSync10(dir)) {
|
|
15378
15747
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
15379
15748
|
}
|
|
15380
15749
|
const files = listJsonFiles(dir);
|
|
@@ -15393,7 +15762,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
15393
15762
|
}
|
|
15394
15763
|
for (const f of files) {
|
|
15395
15764
|
try {
|
|
15396
|
-
const filePath =
|
|
15765
|
+
const filePath = join10(dir, f);
|
|
15397
15766
|
const at = readAgentTask(dir, f);
|
|
15398
15767
|
if (!at)
|
|
15399
15768
|
continue;
|
|
@@ -15546,8 +15915,8 @@ __export(exports_project_bootstrap, {
|
|
|
15546
15915
|
discoverProjectWorkspace: () => discoverProjectWorkspace,
|
|
15547
15916
|
bootstrapProject: () => bootstrapProject
|
|
15548
15917
|
});
|
|
15549
|
-
import { existsSync as
|
|
15550
|
-
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";
|
|
15551
15920
|
function safeStat(path) {
|
|
15552
15921
|
try {
|
|
15553
15922
|
return statSync3(path);
|
|
@@ -15556,7 +15925,7 @@ function safeStat(path) {
|
|
|
15556
15925
|
}
|
|
15557
15926
|
}
|
|
15558
15927
|
function canonicalPath(input) {
|
|
15559
|
-
const resolved =
|
|
15928
|
+
const resolved = resolve11(input);
|
|
15560
15929
|
const stats = safeStat(resolved);
|
|
15561
15930
|
if (stats?.isFile())
|
|
15562
15931
|
return dirname6(resolved);
|
|
@@ -15565,7 +15934,7 @@ function canonicalPath(input) {
|
|
|
15565
15934
|
function findUp(start, marker) {
|
|
15566
15935
|
let current = canonicalPath(start);
|
|
15567
15936
|
while (true) {
|
|
15568
|
-
if (
|
|
15937
|
+
if (existsSync11(resolve11(current, marker)))
|
|
15569
15938
|
return current;
|
|
15570
15939
|
const parent = dirname6(current);
|
|
15571
15940
|
if (parent === current)
|
|
@@ -15576,11 +15945,11 @@ function findUp(start, marker) {
|
|
|
15576
15945
|
function readPackageJson(path) {
|
|
15577
15946
|
if (!path)
|
|
15578
15947
|
return null;
|
|
15579
|
-
const file =
|
|
15580
|
-
if (!
|
|
15948
|
+
const file = resolve11(path, "package.json");
|
|
15949
|
+
if (!existsSync11(file))
|
|
15581
15950
|
return null;
|
|
15582
15951
|
try {
|
|
15583
|
-
const parsed = JSON.parse(
|
|
15952
|
+
const parsed = JSON.parse(readFileSync6(file, "utf-8"));
|
|
15584
15953
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
15585
15954
|
} catch {
|
|
15586
15955
|
return null;
|
|
@@ -15599,7 +15968,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
15599
15968
|
if (rootPackage?.workspaces)
|
|
15600
15969
|
markers.push("package.json#workspaces");
|
|
15601
15970
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
15602
|
-
if (
|
|
15971
|
+
if (existsSync11(resolve11(root, marker)))
|
|
15603
15972
|
markers.push(marker);
|
|
15604
15973
|
}
|
|
15605
15974
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -21122,9 +21491,9 @@ __export(exports_extract, {
|
|
|
21122
21491
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
21123
21492
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
21124
21493
|
});
|
|
21125
|
-
import { existsSync as
|
|
21494
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
|
|
21126
21495
|
import { createHash as createHash3 } from "crypto";
|
|
21127
|
-
import { relative as relative3, resolve as
|
|
21496
|
+
import { relative as relative3, resolve as resolve12, join as join11 } from "path";
|
|
21128
21497
|
function stableHash(value) {
|
|
21129
21498
|
return createHash3("sha256").update(value).digest("hex");
|
|
21130
21499
|
}
|
|
@@ -21132,12 +21501,12 @@ function normalizePathForMatch(value) {
|
|
|
21132
21501
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
21133
21502
|
}
|
|
21134
21503
|
function readGitignorePatterns(basePath) {
|
|
21135
|
-
const root = statSync4(basePath).isFile() ?
|
|
21136
|
-
const gitignorePath =
|
|
21137
|
-
if (!
|
|
21504
|
+
const root = statSync4(basePath).isFile() ? resolve12(basePath, "..") : basePath;
|
|
21505
|
+
const gitignorePath = join11(root, ".gitignore");
|
|
21506
|
+
if (!existsSync12(gitignorePath))
|
|
21138
21507
|
return [];
|
|
21139
21508
|
try {
|
|
21140
|
-
return
|
|
21509
|
+
return readFileSync7(gitignorePath, "utf-8").split(`
|
|
21141
21510
|
`).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!"));
|
|
21142
21511
|
} catch {
|
|
21143
21512
|
return [];
|
|
@@ -21268,7 +21637,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
21268
21637
|
return files.sort();
|
|
21269
21638
|
}
|
|
21270
21639
|
function buildCodebaseIndex(options) {
|
|
21271
|
-
const basePath =
|
|
21640
|
+
const basePath = resolve12(options.path);
|
|
21272
21641
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
21273
21642
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
21274
21643
|
const excludes = options.exclude || [];
|
|
@@ -21276,10 +21645,10 @@ function buildCodebaseIndex(options) {
|
|
|
21276
21645
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
21277
21646
|
const indexed = [];
|
|
21278
21647
|
for (const file of files) {
|
|
21279
|
-
const fullPath = statSync4(basePath).isFile() ? basePath :
|
|
21648
|
+
const fullPath = statSync4(basePath).isFile() ? basePath : join11(basePath, file);
|
|
21280
21649
|
try {
|
|
21281
|
-
const source =
|
|
21282
|
-
const relPath = statSync4(basePath).isFile() ? relative3(
|
|
21650
|
+
const source = readFileSync7(fullPath, "utf-8");
|
|
21651
|
+
const relPath = statSync4(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
|
|
21283
21652
|
indexed.push({
|
|
21284
21653
|
file: relPath,
|
|
21285
21654
|
checksum: stableHash(source).slice(0, 24),
|
|
@@ -21299,7 +21668,7 @@ function buildCodebaseIndex(options) {
|
|
|
21299
21668
|
};
|
|
21300
21669
|
}
|
|
21301
21670
|
function extractTodos(options, db) {
|
|
21302
|
-
const basePath =
|
|
21671
|
+
const basePath = resolve12(options.path);
|
|
21303
21672
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
21304
21673
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
21305
21674
|
const excludes = options.exclude || [];
|
|
@@ -21307,10 +21676,10 @@ function extractTodos(options, db) {
|
|
|
21307
21676
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
21308
21677
|
const allComments = [];
|
|
21309
21678
|
for (const file of files) {
|
|
21310
|
-
const fullPath = statSync4(basePath).isFile() ? basePath :
|
|
21679
|
+
const fullPath = statSync4(basePath).isFile() ? basePath : join11(basePath, file);
|
|
21311
21680
|
try {
|
|
21312
|
-
const source =
|
|
21313
|
-
const relPath = statSync4(basePath).isFile() ? relative3(
|
|
21681
|
+
const source = readFileSync7(fullPath, "utf-8");
|
|
21682
|
+
const relPath = statSync4(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
|
|
21314
21683
|
const comments = extractFromSource(source, relPath, tags);
|
|
21315
21684
|
allComments.push(...comments);
|
|
21316
21685
|
} catch {}
|
|
@@ -21404,7 +21773,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
21404
21773
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
21405
21774
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
21406
21775
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
21407
|
-
const root =
|
|
21776
|
+
const root = resolve12(options.path);
|
|
21408
21777
|
const runs = [];
|
|
21409
21778
|
let previous = new Map;
|
|
21410
21779
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -22575,7 +22944,7 @@ __export(exports_project_commands, {
|
|
|
22575
22944
|
registerProjectCommands: () => registerProjectCommands
|
|
22576
22945
|
});
|
|
22577
22946
|
import chalk4 from "chalk";
|
|
22578
|
-
import { basename as basename5, resolve as
|
|
22947
|
+
import { basename as basename5, resolve as resolve13 } from "path";
|
|
22579
22948
|
function collectOption(value, previous = []) {
|
|
22580
22949
|
return [...previous, value];
|
|
22581
22950
|
}
|
|
@@ -22917,7 +23286,7 @@ function registerProjectCommands(program2) {
|
|
|
22917
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) => {
|
|
22918
23287
|
const globalOpts = program2.opts();
|
|
22919
23288
|
if (opts.add) {
|
|
22920
|
-
const projectPath =
|
|
23289
|
+
const projectPath = resolve13(opts.add);
|
|
22921
23290
|
const name = opts.name || basename5(projectPath);
|
|
22922
23291
|
const existing = getProjectByPath(projectPath);
|
|
22923
23292
|
let project;
|
|
@@ -23025,7 +23394,7 @@ function registerProjectCommands(program2) {
|
|
|
23025
23394
|
console.error(chalk4.red(`Project not found: ${projectId}`));
|
|
23026
23395
|
process.exit(1);
|
|
23027
23396
|
}
|
|
23028
|
-
const entry = setMachineLocalPath2(resolved,
|
|
23397
|
+
const entry = setMachineLocalPath2(resolved, resolve13(projectPath));
|
|
23029
23398
|
if (useJson) {
|
|
23030
23399
|
output(entry, true);
|
|
23031
23400
|
} else {
|
|
@@ -23092,7 +23461,7 @@ function registerProjectCommands(program2) {
|
|
|
23092
23461
|
const patterns = opts.pattern ? opts.pattern.split(",").map((t) => t.trim().toUpperCase()) : undefined;
|
|
23093
23462
|
const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
|
|
23094
23463
|
const result = extractTodos2({
|
|
23095
|
-
path:
|
|
23464
|
+
path: resolve13(scanPath),
|
|
23096
23465
|
patterns,
|
|
23097
23466
|
project_id: projectId,
|
|
23098
23467
|
task_list_id: taskListId,
|
|
@@ -23153,7 +23522,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23153
23522
|
const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
|
|
23154
23523
|
const maxRuns = opts.maxRuns ? parseInt(opts.maxRuns, 10) : 1;
|
|
23155
23524
|
const result = await watchSourceTodos2({
|
|
23156
|
-
path:
|
|
23525
|
+
path: resolve13(scanPath),
|
|
23157
23526
|
patterns,
|
|
23158
23527
|
project_id: projectId,
|
|
23159
23528
|
task_list_id: taskListId,
|
|
@@ -23189,8 +23558,8 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23189
23558
|
const projectId = autoProject(globalOpts);
|
|
23190
23559
|
const writeOutput = async (content) => {
|
|
23191
23560
|
if (opts.output) {
|
|
23192
|
-
const { writeFileSync:
|
|
23193
|
-
|
|
23561
|
+
const { writeFileSync: writeFileSync6 } = await import("fs");
|
|
23562
|
+
writeFileSync6(resolve13(opts.output), content.endsWith(`
|
|
23194
23563
|
`) ? content : `${content}
|
|
23195
23564
|
`);
|
|
23196
23565
|
} else {
|
|
@@ -23205,12 +23574,12 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23205
23574
|
const exported = opts.encrypt ? createEncryptedBridgeBundle2(bundle, { profile: opts.encryptionProfile }) : bundle;
|
|
23206
23575
|
const json = JSON.stringify(exported, null, 2);
|
|
23207
23576
|
await writeOutput(json);
|
|
23208
|
-
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 } });
|
|
23209
23578
|
if (!opts.encrypt && !opts.allowPlaintextSensitive) {
|
|
23210
23579
|
console.error(chalk4.yellow("Warning: bridge exports are plaintext JSON. Use --encrypt for sensitive metadata, evidence, and artifact bundles."));
|
|
23211
23580
|
}
|
|
23212
23581
|
if (opts.output && !globalOpts.json) {
|
|
23213
|
-
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)}`));
|
|
23214
23583
|
}
|
|
23215
23584
|
return;
|
|
23216
23585
|
}
|
|
@@ -23223,21 +23592,21 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23223
23592
|
await writeOutput(JSON.stringify(tasks, null, 2));
|
|
23224
23593
|
}
|
|
23225
23594
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
23226
|
-
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 } });
|
|
23227
23596
|
});
|
|
23228
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) => {
|
|
23229
23598
|
const globalOpts = program2.opts();
|
|
23230
23599
|
try {
|
|
23231
|
-
const { readFileSync:
|
|
23600
|
+
const { readFileSync: readFileSync8 } = await import("fs");
|
|
23232
23601
|
const { importLocalBridgeBundle: importLocalBridgeBundle2 } = await Promise.resolve().then(() => (init_local_bridge(), exports_local_bridge));
|
|
23233
23602
|
const { decryptBridgeBundle: decryptBridgeBundle2, isEncryptedBridgeBundle: isEncryptedBridgeBundle2 } = await Promise.resolve().then(() => (init_local_encryption(), exports_local_encryption));
|
|
23234
|
-
const parsed = JSON.parse(
|
|
23603
|
+
const parsed = JSON.parse(readFileSync8(resolve13(file), "utf-8"));
|
|
23235
23604
|
const bundle = isEncryptedBridgeBundle2(parsed) ? opts.decrypt ? decryptBridgeBundle2(parsed) : (() => {
|
|
23236
23605
|
throw new Error("Bridge bundle is encrypted. Re-run with --decrypt and the configured key environment variable set.");
|
|
23237
23606
|
})() : parsed;
|
|
23238
23607
|
const result = importLocalBridgeBundle2(bundle, { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
|
|
23239
23608
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
23240
|
-
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 } });
|
|
23241
23610
|
if (globalOpts.json) {
|
|
23242
23611
|
output(result, true);
|
|
23243
23612
|
return;
|
|
@@ -23265,11 +23634,11 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
23265
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) => {
|
|
23266
23635
|
const globalOpts = program2.opts();
|
|
23267
23636
|
try {
|
|
23268
|
-
const { readFileSync:
|
|
23637
|
+
const { readFileSync: readFileSync8 } = await import("fs");
|
|
23269
23638
|
const { importTodosMarkdown: importTodosMarkdown2 } = await Promise.resolve().then(() => (init_todos_md(), exports_todos_md));
|
|
23270
|
-
const result = importTodosMarkdown2(
|
|
23639
|
+
const result = importTodosMarkdown2(readFileSync8(resolve13(file), "utf-8"), { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
|
|
23271
23640
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
23272
|
-
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 } });
|
|
23273
23642
|
if (globalOpts.json) {
|
|
23274
23643
|
output(result, true);
|
|
23275
23644
|
return;
|
|
@@ -24397,7 +24766,7 @@ __export(exports_retention_cleanup, {
|
|
|
24397
24766
|
applyRetentionCleanup: () => applyRetentionCleanup,
|
|
24398
24767
|
RETENTION_CLEANUP_CONFIRMATION: () => RETENTION_CLEANUP_CONFIRMATION
|
|
24399
24768
|
});
|
|
24400
|
-
import { existsSync as
|
|
24769
|
+
import { existsSync as existsSync13, unlinkSync } from "fs";
|
|
24401
24770
|
function normalizeScopes(scopes) {
|
|
24402
24771
|
if (!scopes || scopes.length === 0)
|
|
24403
24772
|
return [...ALL_SCOPES];
|
|
@@ -24600,7 +24969,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
24600
24969
|
for (const artifact of report.candidates.artifact_files) {
|
|
24601
24970
|
try {
|
|
24602
24971
|
const path = artifactStorePath(artifact.relative_path);
|
|
24603
|
-
if (!
|
|
24972
|
+
if (!existsSync13(path)) {
|
|
24604
24973
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
24605
24974
|
continue;
|
|
24606
24975
|
}
|
|
@@ -25278,8 +25647,8 @@ __export(exports_local_extensions, {
|
|
|
25278
25647
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
25279
25648
|
});
|
|
25280
25649
|
import { createHash as createHash5, createVerify } from "crypto";
|
|
25281
|
-
import { existsSync as
|
|
25282
|
-
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";
|
|
25283
25652
|
function isObject(value) {
|
|
25284
25653
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
25285
25654
|
}
|
|
@@ -25360,7 +25729,7 @@ function normalizeManifest(input) {
|
|
|
25360
25729
|
};
|
|
25361
25730
|
}
|
|
25362
25731
|
function parseJson(path) {
|
|
25363
|
-
return JSON.parse(
|
|
25732
|
+
return JSON.parse(readFileSync8(path, "utf8"));
|
|
25364
25733
|
}
|
|
25365
25734
|
function sha2563(bytes) {
|
|
25366
25735
|
return `sha256:${createHash5("sha256").update(bytes).digest("hex")}`;
|
|
@@ -25537,14 +25906,14 @@ function verifyExtensionSignature(input) {
|
|
|
25537
25906
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
25538
25907
|
}
|
|
25539
25908
|
function inspectExtensionSource(source2) {
|
|
25540
|
-
const resolved =
|
|
25541
|
-
if (!
|
|
25909
|
+
const resolved = resolve14(source2);
|
|
25910
|
+
if (!existsSync14(resolved))
|
|
25542
25911
|
throw new Error(`extension source not found: ${source2}`);
|
|
25543
25912
|
const stat = statSync5(resolved);
|
|
25544
|
-
const manifestPath = stat.isDirectory() ? [
|
|
25913
|
+
const manifestPath = stat.isDirectory() ? [join12(resolved, "todos.extension.json"), join12(resolved, "extension.json")].find(existsSync14) : resolved;
|
|
25545
25914
|
if (!manifestPath)
|
|
25546
25915
|
throw new Error(`extension directory ${source2} is missing todos.extension.json`);
|
|
25547
|
-
const raw =
|
|
25916
|
+
const raw = readFileSync8(manifestPath);
|
|
25548
25917
|
const parsed = parseJson(manifestPath);
|
|
25549
25918
|
const bundle = isObject(parsed) && isObject(parsed["manifest"]);
|
|
25550
25919
|
const manifest = normalizeManifest(bundle ? parsed["manifest"] : parsed);
|
|
@@ -25635,26 +26004,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
25635
26004
|
function projectExtensionSources(projectPath) {
|
|
25636
26005
|
if (!projectPath)
|
|
25637
26006
|
return [];
|
|
25638
|
-
const root =
|
|
26007
|
+
const root = resolve14(projectPath);
|
|
25639
26008
|
const candidates = [
|
|
25640
|
-
|
|
25641
|
-
|
|
26009
|
+
join12(root, "todos.extension.json"),
|
|
26010
|
+
join12(root, ".todos", "todos.extension.json")
|
|
25642
26011
|
];
|
|
25643
|
-
const extensionDir =
|
|
25644
|
-
if (
|
|
26012
|
+
const extensionDir = join12(root, ".todos", "extensions");
|
|
26013
|
+
if (existsSync14(extensionDir)) {
|
|
25645
26014
|
for (const entry of readdirSync3(extensionDir)) {
|
|
25646
26015
|
if (entry.startsWith("."))
|
|
25647
26016
|
continue;
|
|
25648
|
-
const full =
|
|
26017
|
+
const full = join12(extensionDir, entry);
|
|
25649
26018
|
if (statSync5(full).isDirectory() || entry.endsWith(".json"))
|
|
25650
26019
|
candidates.push(full);
|
|
25651
26020
|
}
|
|
25652
26021
|
}
|
|
25653
|
-
return candidates.filter(
|
|
26022
|
+
return candidates.filter(existsSync14);
|
|
25654
26023
|
}
|
|
25655
26024
|
function discoverLocalExtensions(options = {}) {
|
|
25656
26025
|
const config = loadConfig();
|
|
25657
|
-
const projectPath = options.project_path ?
|
|
26026
|
+
const projectPath = options.project_path ? resolve14(options.project_path) : null;
|
|
25658
26027
|
const configuredSources = [
|
|
25659
26028
|
...config.extension_sources || [],
|
|
25660
26029
|
...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -25662,7 +26031,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
25662
26031
|
const sources = Array.from(new Set([
|
|
25663
26032
|
...configuredSources,
|
|
25664
26033
|
...projectExtensionSources(projectPath || undefined)
|
|
25665
|
-
])).map((source2) => projectPath && !source2.startsWith("/") ?
|
|
26034
|
+
])).map((source2) => projectPath && !source2.startsWith("/") ? resolve14(projectPath, source2) : resolve14(source2));
|
|
25666
26035
|
const warnings = [];
|
|
25667
26036
|
const discovered = [];
|
|
25668
26037
|
for (const source2 of sources) {
|
|
@@ -25922,9 +26291,9 @@ __export(exports_policy_packs, {
|
|
|
25922
26291
|
getPolicyPack: () => getPolicyPack,
|
|
25923
26292
|
explainPolicyPack: () => explainPolicyPack
|
|
25924
26293
|
});
|
|
25925
|
-
import { relative as relative4, resolve as
|
|
26294
|
+
import { relative as relative4, resolve as resolve15 } from "path";
|
|
25926
26295
|
function normalizePath3(path) {
|
|
25927
|
-
return
|
|
26296
|
+
return resolve15(path);
|
|
25928
26297
|
}
|
|
25929
26298
|
function unique5(values) {
|
|
25930
26299
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -25979,7 +26348,7 @@ function commandMatches(commands, pattern) {
|
|
|
25979
26348
|
}
|
|
25980
26349
|
function pathMatches(paths, pattern, root) {
|
|
25981
26350
|
return paths.filter((path) => {
|
|
25982
|
-
const candidate = path.startsWith("/") ? path :
|
|
26351
|
+
const candidate = path.startsWith("/") ? path : resolve15(root, path);
|
|
25983
26352
|
if (!isPathInside3(root, candidate))
|
|
25984
26353
|
return matchesPattern3(path, pattern);
|
|
25985
26354
|
return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
|
|
@@ -26945,8 +27314,8 @@ var exports_doctor = {};
|
|
|
26945
27314
|
__export(exports_doctor, {
|
|
26946
27315
|
runTodosDoctor: () => runTodosDoctor
|
|
26947
27316
|
});
|
|
26948
|
-
import { chmodSync, copyFileSync, existsSync as
|
|
26949
|
-
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";
|
|
26950
27319
|
function tableExists(db, table) {
|
|
26951
27320
|
return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
|
|
26952
27321
|
}
|
|
@@ -27040,7 +27409,7 @@ function findMissingProjectRoots(db) {
|
|
|
27040
27409
|
continue;
|
|
27041
27410
|
if (!row.path.startsWith("/"))
|
|
27042
27411
|
continue;
|
|
27043
|
-
if (!
|
|
27412
|
+
if (!existsSync15(row.path))
|
|
27044
27413
|
missing++;
|
|
27045
27414
|
}
|
|
27046
27415
|
return missing;
|
|
@@ -27100,16 +27469,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
27100
27469
|
function createBackup(dbPath) {
|
|
27101
27470
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
27102
27471
|
return;
|
|
27103
|
-
if (!
|
|
27472
|
+
if (!existsSync15(dbPath))
|
|
27104
27473
|
return;
|
|
27105
27474
|
const stamp = now().replace(/[:.]/g, "-");
|
|
27106
|
-
const backupDir =
|
|
27475
|
+
const backupDir = join13(dirname7(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
|
|
27107
27476
|
const files = [];
|
|
27108
|
-
|
|
27477
|
+
mkdirSync7(backupDir, { recursive: true });
|
|
27109
27478
|
for (const source2 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
27110
|
-
if (!
|
|
27479
|
+
if (!existsSync15(source2))
|
|
27111
27480
|
continue;
|
|
27112
|
-
const target =
|
|
27481
|
+
const target = join13(backupDir, basename7(source2));
|
|
27113
27482
|
copyFileSync(source2, target);
|
|
27114
27483
|
files.push(target);
|
|
27115
27484
|
}
|
|
@@ -27335,7 +27704,7 @@ var init_doctor = __esm(() => {
|
|
|
27335
27704
|
});
|
|
27336
27705
|
|
|
27337
27706
|
// src/server/routes.ts
|
|
27338
|
-
import { join as
|
|
27707
|
+
import { join as join14, resolve as resolve16, sep as sep2 } from "path";
|
|
27339
27708
|
function parseFieldsParam(url) {
|
|
27340
27709
|
const fieldsParam = url.searchParams.get("fields");
|
|
27341
27710
|
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
@@ -28072,9 +28441,9 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
|
|
|
28072
28441
|
if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
|
|
28073
28442
|
return null;
|
|
28074
28443
|
if (path !== "/") {
|
|
28075
|
-
const filePath =
|
|
28076
|
-
const resolvedFile =
|
|
28077
|
-
const resolvedBase =
|
|
28444
|
+
const filePath = join14(ctx.dashboardDir, path);
|
|
28445
|
+
const resolvedFile = resolve16(filePath);
|
|
28446
|
+
const resolvedBase = resolve16(ctx.dashboardDir);
|
|
28078
28447
|
if (!resolvedFile.startsWith(resolvedBase + sep2) && resolvedFile !== resolvedBase) {
|
|
28079
28448
|
return json2({ error: "Forbidden" }, 403);
|
|
28080
28449
|
}
|
|
@@ -28082,7 +28451,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
|
|
|
28082
28451
|
if (res2)
|
|
28083
28452
|
return res2;
|
|
28084
28453
|
}
|
|
28085
|
-
const indexPath =
|
|
28454
|
+
const indexPath = join14(ctx.dashboardDir, "index.html");
|
|
28086
28455
|
const res = serveStaticFile2(indexPath);
|
|
28087
28456
|
if (res)
|
|
28088
28457
|
return res;
|
|
@@ -33077,8 +33446,8 @@ var exports_mention_resolver = {};
|
|
|
33077
33446
|
__export(exports_mention_resolver, {
|
|
33078
33447
|
resolveMentions: () => resolveMentions
|
|
33079
33448
|
});
|
|
33080
|
-
import { existsSync as
|
|
33081
|
-
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";
|
|
33082
33451
|
function blankResolution(parsed) {
|
|
33083
33452
|
return {
|
|
33084
33453
|
input: parsed.input,
|
|
@@ -33101,7 +33470,7 @@ function backlink(kind, key, label, target = key) {
|
|
|
33101
33470
|
return { kind, key, label, target };
|
|
33102
33471
|
}
|
|
33103
33472
|
function normalizeWorkspace(workspace) {
|
|
33104
|
-
return
|
|
33473
|
+
return resolve17(workspace || process.cwd());
|
|
33105
33474
|
}
|
|
33106
33475
|
function isInside(root, absolutePath) {
|
|
33107
33476
|
const rel = relative5(root, absolutePath);
|
|
@@ -33169,14 +33538,14 @@ function resolveFile(parsed, workspace) {
|
|
|
33169
33538
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
33170
33539
|
return resolution;
|
|
33171
33540
|
}
|
|
33172
|
-
const absolutePath =
|
|
33541
|
+
const absolutePath = resolve17(workspace, relPath);
|
|
33173
33542
|
if (!isInside(workspace, absolutePath)) {
|
|
33174
33543
|
resolution.path = relPath;
|
|
33175
33544
|
resolution.warnings.push("path escapes the workspace");
|
|
33176
33545
|
return resolution;
|
|
33177
33546
|
}
|
|
33178
33547
|
resolution.path = relPath;
|
|
33179
|
-
if (!
|
|
33548
|
+
if (!existsSync16(absolutePath)) {
|
|
33180
33549
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
33181
33550
|
return resolution;
|
|
33182
33551
|
}
|
|
@@ -33186,7 +33555,7 @@ function resolveFile(parsed, workspace) {
|
|
|
33186
33555
|
return resolution;
|
|
33187
33556
|
}
|
|
33188
33557
|
if (parsed.line !== undefined) {
|
|
33189
|
-
const lineCount =
|
|
33558
|
+
const lineCount = readFileSync9(absolutePath, "utf-8").split(/\r?\n/).length;
|
|
33190
33559
|
if (parsed.line < 1 || parsed.line > lineCount) {
|
|
33191
33560
|
resolution.warnings.push(`line ${parsed.line} is outside the file range 1-${lineCount}`);
|
|
33192
33561
|
return resolution;
|
|
@@ -33209,7 +33578,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
33209
33578
|
if (SKIP_DIRS3.has(entry.name))
|
|
33210
33579
|
continue;
|
|
33211
33580
|
}
|
|
33212
|
-
const absolutePath =
|
|
33581
|
+
const absolutePath = join15(current, entry.name);
|
|
33213
33582
|
if (entry.isDirectory()) {
|
|
33214
33583
|
if (!SKIP_DIRS3.has(entry.name))
|
|
33215
33584
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -33239,7 +33608,7 @@ function resolveSymbol(parsed, workspace, maxMatches) {
|
|
|
33239
33608
|
const pattern = symbolPattern(name);
|
|
33240
33609
|
const matches = [];
|
|
33241
33610
|
for (const file of walkSourceFiles(workspace)) {
|
|
33242
|
-
const lines =
|
|
33611
|
+
const lines = readFileSync9(file, "utf-8").split(/\r?\n/);
|
|
33243
33612
|
for (let index = 0;index < lines.length; index += 1) {
|
|
33244
33613
|
const line = lines[index];
|
|
33245
33614
|
const found = pattern.exec(line);
|
|
@@ -35973,8 +36342,8 @@ __export(exports_release_compatibility, {
|
|
|
35973
36342
|
createReleaseCompatibilityReport: () => createReleaseCompatibilityReport,
|
|
35974
36343
|
LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION: () => LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION
|
|
35975
36344
|
});
|
|
35976
|
-
import { readFileSync as
|
|
35977
|
-
import { join as
|
|
36345
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
36346
|
+
import { join as join16, resolve as resolve18 } from "path";
|
|
35978
36347
|
import { Database as Database2 } from "bun:sqlite";
|
|
35979
36348
|
function pass(id, message, details) {
|
|
35980
36349
|
return { id, status: "passed", message, details };
|
|
@@ -35986,7 +36355,7 @@ function warn(id, message, details) {
|
|
|
35986
36355
|
return { id, status: "warning", message, details };
|
|
35987
36356
|
}
|
|
35988
36357
|
function readPackageJson2(root) {
|
|
35989
|
-
return JSON.parse(
|
|
36358
|
+
return JSON.parse(readFileSync10(join16(root, "package.json"), "utf8"));
|
|
35990
36359
|
}
|
|
35991
36360
|
function sortedKeys(value) {
|
|
35992
36361
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -36082,7 +36451,7 @@ function checkChangelog() {
|
|
|
36082
36451
|
];
|
|
36083
36452
|
}
|
|
36084
36453
|
function createReleaseCompatibilityReport(options = {}) {
|
|
36085
|
-
const root =
|
|
36454
|
+
const root = resolve18(options.root ?? process.cwd());
|
|
36086
36455
|
const packageJson = readPackageJson2(root);
|
|
36087
36456
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
36088
36457
|
const checks = [
|
|
@@ -41665,7 +42034,7 @@ __export(exports_verification_providers, {
|
|
|
41665
42034
|
getVerificationRecord: () => getVerificationRecord,
|
|
41666
42035
|
discoverVerificationProviderCapabilities: () => discoverVerificationProviderCapabilities
|
|
41667
42036
|
});
|
|
41668
|
-
import { existsSync as
|
|
42037
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11 } from "fs";
|
|
41669
42038
|
function normalizeName6(name) {
|
|
41670
42039
|
const normalized = name.trim().toLowerCase();
|
|
41671
42040
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -41762,7 +42131,7 @@ function classifyLog(text) {
|
|
|
41762
42131
|
async function sleep3(ms) {
|
|
41763
42132
|
if (ms <= 0)
|
|
41764
42133
|
return;
|
|
41765
|
-
await new Promise((
|
|
42134
|
+
await new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
41766
42135
|
}
|
|
41767
42136
|
async function runCommandProvider(provider, input) {
|
|
41768
42137
|
const commandTemplate = input.command || provider.command;
|
|
@@ -41817,7 +42186,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
41817
42186
|
};
|
|
41818
42187
|
}
|
|
41819
42188
|
function runCiLogProvider(input) {
|
|
41820
|
-
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") : "");
|
|
41821
42190
|
return {
|
|
41822
42191
|
status: classifyLog(text),
|
|
41823
42192
|
attempts: 1,
|
|
@@ -41829,7 +42198,7 @@ function runBrowserProvider(input) {
|
|
|
41829
42198
|
if (!input.artifact_path) {
|
|
41830
42199
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
41831
42200
|
}
|
|
41832
|
-
if (!
|
|
42201
|
+
if (!existsSync17(input.artifact_path)) {
|
|
41833
42202
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
41834
42203
|
}
|
|
41835
42204
|
return {
|
|
@@ -44111,9 +44480,9 @@ __export(exports_local_backups, {
|
|
|
44111
44480
|
LOCAL_BACKUP_CHECKSUM_ALGORITHM: () => LOCAL_BACKUP_CHECKSUM_ALGORITHM
|
|
44112
44481
|
});
|
|
44113
44482
|
import { createHash as createHash8 } from "crypto";
|
|
44114
|
-
import { readFileSync as
|
|
44115
|
-
import { dirname as dirname8, resolve as
|
|
44116
|
-
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";
|
|
44117
44486
|
function stableJson(value) {
|
|
44118
44487
|
if (value === null || typeof value !== "object")
|
|
44119
44488
|
return JSON.stringify(value);
|
|
@@ -44214,14 +44583,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
44214
44583
|
return backup;
|
|
44215
44584
|
}
|
|
44216
44585
|
function writeLocalBackupFile(backup, outputPath) {
|
|
44217
|
-
const path =
|
|
44218
|
-
|
|
44219
|
-
|
|
44586
|
+
const path = resolve19(outputPath);
|
|
44587
|
+
mkdirSync8(dirname8(path), { recursive: true });
|
|
44588
|
+
writeFileSync6(path, `${JSON.stringify(backup, null, 2)}
|
|
44220
44589
|
`);
|
|
44221
44590
|
return path;
|
|
44222
44591
|
}
|
|
44223
44592
|
function readLocalBackupFile(path) {
|
|
44224
|
-
return JSON.parse(
|
|
44593
|
+
return JSON.parse(readFileSync12(resolve19(path), "utf-8"));
|
|
44225
44594
|
}
|
|
44226
44595
|
function verifyLocalBackup(value, options = {}, db) {
|
|
44227
44596
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -44417,8 +44786,8 @@ __export(exports_onboarding_fixtures, {
|
|
|
44417
44786
|
TODOS_ONBOARDING_FIXTURE_SOURCE: () => TODOS_ONBOARDING_FIXTURE_SOURCE,
|
|
44418
44787
|
TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION: () => TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION
|
|
44419
44788
|
});
|
|
44420
|
-
import { mkdirSync as
|
|
44421
|
-
import { join as
|
|
44789
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
44790
|
+
import { join as join17 } from "path";
|
|
44422
44791
|
function emptyData() {
|
|
44423
44792
|
return {
|
|
44424
44793
|
projects: [],
|
|
@@ -44748,11 +45117,11 @@ function getOnboardingFixtureBundle(name = "agent-project-demo") {
|
|
|
44748
45117
|
return getOnboardingFixture(name).bundle;
|
|
44749
45118
|
}
|
|
44750
45119
|
function writeOnboardingFixtureFiles(directory) {
|
|
44751
|
-
|
|
45120
|
+
mkdirSync9(directory, { recursive: true });
|
|
44752
45121
|
const files = [];
|
|
44753
45122
|
for (const fixture of allFixtures()) {
|
|
44754
|
-
const path =
|
|
44755
|
-
|
|
45123
|
+
const path = join17(directory, `${fixture.summary.name}.bridge.json`);
|
|
45124
|
+
writeFileSync7(path, `${JSON.stringify(fixture.bundle, null, 2)}
|
|
44756
45125
|
`, "utf-8");
|
|
44757
45126
|
files.push(path);
|
|
44758
45127
|
}
|
|
@@ -45399,7 +45768,7 @@ __export(exports_agent_replay_simulator, {
|
|
|
45399
45768
|
renderAgentReplaySimulationMarkdown: () => renderAgentReplaySimulationMarkdown
|
|
45400
45769
|
});
|
|
45401
45770
|
import { createHash as createHash10 } from "crypto";
|
|
45402
|
-
import { readFileSync as
|
|
45771
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
45403
45772
|
function isObject2(value) {
|
|
45404
45773
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
45405
45774
|
}
|
|
@@ -45632,7 +46001,7 @@ function simulateAgentReplay(input, options = {}) {
|
|
|
45632
46001
|
};
|
|
45633
46002
|
}
|
|
45634
46003
|
function simulateAgentReplayFile(path, options = {}) {
|
|
45635
|
-
const parsed = JSON.parse(
|
|
46004
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
45636
46005
|
return simulateAgentReplay(parsed, options);
|
|
45637
46006
|
}
|
|
45638
46007
|
function renderAgentReplaySimulationMarkdown(simulation) {
|
|
@@ -50919,28 +51288,28 @@ __export(exports_environment_snapshots, {
|
|
|
50919
51288
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
50920
51289
|
});
|
|
50921
51290
|
import { createHash as createHash12 } from "crypto";
|
|
50922
|
-
import { existsSync as
|
|
51291
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14, statSync as statSync8 } from "fs";
|
|
50923
51292
|
import { hostname as hostname2, platform, arch } from "os";
|
|
50924
|
-
import { dirname as dirname9, join as
|
|
51293
|
+
import { dirname as dirname9, join as join18, resolve as resolve20 } from "path";
|
|
50925
51294
|
import { tmpdir as tmpdir3 } from "os";
|
|
50926
51295
|
function sha2566(value) {
|
|
50927
51296
|
return createHash12("sha256").update(value).digest("hex");
|
|
50928
51297
|
}
|
|
50929
51298
|
function fileRecord(root, relativePath) {
|
|
50930
|
-
const path =
|
|
50931
|
-
if (!
|
|
51299
|
+
const path = join18(root, relativePath);
|
|
51300
|
+
if (!existsSync18(path))
|
|
50932
51301
|
return null;
|
|
50933
51302
|
const stat = statSync8(path);
|
|
50934
51303
|
if (!stat.isFile())
|
|
50935
51304
|
return null;
|
|
50936
|
-
const content =
|
|
51305
|
+
const content = readFileSync14(path);
|
|
50937
51306
|
return { path: relativePath, sha256: sha2566(content), size_bytes: content.length };
|
|
50938
51307
|
}
|
|
50939
51308
|
function manifestRecord(root, relativePath) {
|
|
50940
51309
|
const base = fileRecord(root, relativePath);
|
|
50941
51310
|
if (!base)
|
|
50942
51311
|
return null;
|
|
50943
|
-
const parsed = readJsonFile(
|
|
51312
|
+
const parsed = readJsonFile(join18(root, relativePath));
|
|
50944
51313
|
if (!parsed)
|
|
50945
51314
|
return { ...base, redacted: {} };
|
|
50946
51315
|
const redacted = redactValue({
|
|
@@ -51035,15 +51404,15 @@ function commandEnv(env, includeValues) {
|
|
|
51035
51404
|
function defaultSnapshotDir() {
|
|
51036
51405
|
const dbPath = getDatabasePath();
|
|
51037
51406
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
51038
|
-
return
|
|
51039
|
-
return
|
|
51407
|
+
return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
51408
|
+
return join18(dirname9(resolve20(dbPath)), "environment-snapshots");
|
|
51040
51409
|
}
|
|
51041
51410
|
function snapshotWithId(snapshot) {
|
|
51042
51411
|
const digest = sha2566(JSON.stringify(snapshot)).slice(0, 24);
|
|
51043
51412
|
return { id: `env_${digest}`, ...snapshot };
|
|
51044
51413
|
}
|
|
51045
51414
|
function captureEnvironmentSnapshot(input = {}) {
|
|
51046
|
-
const root =
|
|
51415
|
+
const root = resolve20(input.root || process.cwd());
|
|
51047
51416
|
const env = input.env || process.env;
|
|
51048
51417
|
const warnings = [];
|
|
51049
51418
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -51083,13 +51452,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
51083
51452
|
});
|
|
51084
51453
|
}
|
|
51085
51454
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
51086
|
-
const path = outputPath ?
|
|
51455
|
+
const path = outputPath ? resolve20(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
51087
51456
|
ensureDir2(dirname9(path));
|
|
51088
51457
|
writeJsonFile(path, snapshot);
|
|
51089
51458
|
return path;
|
|
51090
51459
|
}
|
|
51091
51460
|
function readEnvironmentSnapshot(path) {
|
|
51092
|
-
const snapshot = readJsonFile(
|
|
51461
|
+
const snapshot = readJsonFile(resolve20(path));
|
|
51093
51462
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
51094
51463
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
51095
51464
|
}
|
|
@@ -51614,27 +51983,27 @@ __export(exports_serve, {
|
|
|
51614
51983
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
51615
51984
|
MIME_TYPES: () => MIME_TYPES
|
|
51616
51985
|
});
|
|
51617
|
-
import { existsSync as
|
|
51618
|
-
import { join as
|
|
51986
|
+
import { existsSync as existsSync19 } from "fs";
|
|
51987
|
+
import { join as join19, dirname as dirname10, extname } from "path";
|
|
51619
51988
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
51620
51989
|
function resolveDashboardDir() {
|
|
51621
51990
|
const candidates = [];
|
|
51622
51991
|
try {
|
|
51623
51992
|
const scriptDir = dirname10(fileURLToPath2(import.meta.url));
|
|
51624
|
-
candidates.push(
|
|
51625
|
-
candidates.push(
|
|
51993
|
+
candidates.push(join19(scriptDir, "..", "dashboard", "dist"));
|
|
51994
|
+
candidates.push(join19(scriptDir, "..", "..", "dashboard", "dist"));
|
|
51626
51995
|
} catch {}
|
|
51627
51996
|
if (process.argv[1]) {
|
|
51628
51997
|
const mainDir = dirname10(process.argv[1]);
|
|
51629
|
-
candidates.push(
|
|
51630
|
-
candidates.push(
|
|
51998
|
+
candidates.push(join19(mainDir, "..", "dashboard", "dist"));
|
|
51999
|
+
candidates.push(join19(mainDir, "..", "..", "dashboard", "dist"));
|
|
51631
52000
|
}
|
|
51632
|
-
candidates.push(
|
|
52001
|
+
candidates.push(join19(process.cwd(), "dashboard", "dist"));
|
|
51633
52002
|
for (const candidate of candidates) {
|
|
51634
|
-
if (
|
|
52003
|
+
if (existsSync19(candidate))
|
|
51635
52004
|
return candidate;
|
|
51636
52005
|
}
|
|
51637
|
-
return
|
|
52006
|
+
return join19(process.cwd(), "dashboard", "dist");
|
|
51638
52007
|
}
|
|
51639
52008
|
function getProvidedApiKey(req) {
|
|
51640
52009
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -51684,7 +52053,7 @@ function json(data, status = 200, headers) {
|
|
|
51684
52053
|
});
|
|
51685
52054
|
}
|
|
51686
52055
|
function serveStaticFile(filePath) {
|
|
51687
|
-
if (!
|
|
52056
|
+
if (!existsSync19(filePath))
|
|
51688
52057
|
return null;
|
|
51689
52058
|
const ext = extname(filePath);
|
|
51690
52059
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -51765,7 +52134,7 @@ data: ${data}
|
|
|
51765
52134
|
filteredSseClients.delete(client);
|
|
51766
52135
|
}
|
|
51767
52136
|
const dashboardDir = resolveDashboardDir();
|
|
51768
|
-
const dashboardExists =
|
|
52137
|
+
const dashboardExists = existsSync19(dashboardDir);
|
|
51769
52138
|
if (!dashboardExists) {
|
|
51770
52139
|
console.error(`
|
|
51771
52140
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -53595,12 +53964,12 @@ __export(exports_config_serve_commands, {
|
|
|
53595
53964
|
registerConfigServeCommands: () => registerConfigServeCommands
|
|
53596
53965
|
});
|
|
53597
53966
|
import chalk6 from "chalk";
|
|
53598
|
-
import { existsSync as
|
|
53599
|
-
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";
|
|
53600
53969
|
function registerConfigServeCommands(program2) {
|
|
53601
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) => {
|
|
53602
53971
|
const globalOpts = program2.opts();
|
|
53603
|
-
const configPath =
|
|
53972
|
+
const configPath = join20(getTodosGlobalDir(), "config.json");
|
|
53604
53973
|
if (opts.get) {
|
|
53605
53974
|
const config2 = loadConfig();
|
|
53606
53975
|
const keys = opts.get.split(".");
|
|
@@ -53626,7 +53995,7 @@ function registerConfigServeCommands(program2) {
|
|
|
53626
53995
|
}
|
|
53627
53996
|
let config2 = {};
|
|
53628
53997
|
try {
|
|
53629
|
-
config2 = JSON.parse(
|
|
53998
|
+
config2 = JSON.parse(readFileSync15(configPath, "utf-8"));
|
|
53630
53999
|
} catch {}
|
|
53631
54000
|
const keys = key.split(".");
|
|
53632
54001
|
let obj = config2;
|
|
@@ -53637,9 +54006,9 @@ function registerConfigServeCommands(program2) {
|
|
|
53637
54006
|
}
|
|
53638
54007
|
obj[keys[keys.length - 1]] = parsedValue;
|
|
53639
54008
|
const dir = dirname11(configPath);
|
|
53640
|
-
if (!
|
|
53641
|
-
|
|
53642
|
-
|
|
54009
|
+
if (!existsSync20(dir))
|
|
54010
|
+
mkdirSync10(dir, { recursive: true });
|
|
54011
|
+
writeFileSync8(configPath, JSON.stringify(config2, null, 2));
|
|
53643
54012
|
if (globalOpts.json) {
|
|
53644
54013
|
output({ key, value: parsedValue }, true);
|
|
53645
54014
|
} else {
|
|
@@ -53766,7 +54135,7 @@ function registerConfigServeCommands(program2) {
|
|
|
53766
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) => {
|
|
53767
54136
|
const globalOpts = program2.opts();
|
|
53768
54137
|
const { listSecretFindings: listSecretFindings2 } = await Promise.resolve().then(() => (init_redaction(), exports_redaction));
|
|
53769
|
-
const value = opts.file ?
|
|
54138
|
+
const value = opts.file ? readFileSync15(opts.file, "utf-8") : text2 || "";
|
|
53770
54139
|
const findings = listSecretFindings2(value);
|
|
53771
54140
|
if (globalOpts.json) {
|
|
53772
54141
|
output({ ok: findings.length === 0, findings }, true);
|
|
@@ -55152,7 +55521,7 @@ __export(exports_query_commands, {
|
|
|
55152
55521
|
registerQueryCommands: () => registerQueryCommands
|
|
55153
55522
|
});
|
|
55154
55523
|
import chalk7 from "chalk";
|
|
55155
|
-
import { readFileSync as
|
|
55524
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "fs";
|
|
55156
55525
|
function parseJsonObjectOption2(value, label) {
|
|
55157
55526
|
if (!value)
|
|
55158
55527
|
return;
|
|
@@ -55811,9 +56180,9 @@ Repairs`));
|
|
|
55811
56180
|
const db = getDatabase();
|
|
55812
56181
|
const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
|
|
55813
56182
|
const { statSync: statSync9 } = await import("fs");
|
|
55814
|
-
const { join:
|
|
56183
|
+
const { join: join21 } = await import("path");
|
|
55815
56184
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
55816
|
-
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");
|
|
55817
56186
|
let size = "unknown";
|
|
55818
56187
|
try {
|
|
55819
56188
|
size = `${(statSync9(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -56430,7 +56799,7 @@ Repairs`));
|
|
|
56430
56799
|
const sessionId = opts.session || globalOpts.session || undefined;
|
|
56431
56800
|
try {
|
|
56432
56801
|
if (opts.import) {
|
|
56433
|
-
const bundle = JSON.parse(
|
|
56802
|
+
const bundle = JSON.parse(readFileSync16(opts.import, "utf-8"));
|
|
56434
56803
|
const result = importHandoffBundle(bundle, { apply: opts.apply }, db);
|
|
56435
56804
|
if (opts.json || globalOpts.json) {
|
|
56436
56805
|
console.log(JSON.stringify(result));
|
|
@@ -56446,7 +56815,7 @@ Repairs`));
|
|
|
56446
56815
|
const bundle = exportHandoffBundle(opts.export, db);
|
|
56447
56816
|
const json2 = JSON.stringify(bundle, null, 2);
|
|
56448
56817
|
if (opts.output) {
|
|
56449
|
-
|
|
56818
|
+
writeFileSync9(opts.output, `${json2}
|
|
56450
56819
|
`);
|
|
56451
56820
|
if (opts.json || globalOpts.json) {
|
|
56452
56821
|
console.log(JSON.stringify({ path: opts.output, handoff_id: bundle.handoff.id }));
|
|
@@ -56677,7 +57046,7 @@ Repairs`));
|
|
|
56677
57046
|
});
|
|
56678
57047
|
const content = format === "json" ? JSON.stringify(document, null, 2) : renderReleaseNotesMarkdown2(document);
|
|
56679
57048
|
if (opts.out) {
|
|
56680
|
-
|
|
57049
|
+
writeFileSync9(opts.out, content);
|
|
56681
57050
|
if (format !== "json")
|
|
56682
57051
|
console.log(chalk7.green(`Wrote release notes to ${opts.out}`));
|
|
56683
57052
|
return;
|
|
@@ -56792,7 +57161,7 @@ Repairs`));
|
|
|
56792
57161
|
redact: Boolean(opts.redact)
|
|
56793
57162
|
});
|
|
56794
57163
|
if (opts.out) {
|
|
56795
|
-
|
|
57164
|
+
writeFileSync9(opts.out, exported.content);
|
|
56796
57165
|
if (!(opts.json || globalOpts.json))
|
|
56797
57166
|
console.log(chalk7.green(`Wrote ${exported.events.length} events to ${opts.out}`));
|
|
56798
57167
|
}
|
|
@@ -56808,7 +57177,7 @@ Repairs`));
|
|
|
56808
57177
|
});
|
|
56809
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) => {
|
|
56810
57179
|
try {
|
|
56811
|
-
const result = importCalendarIcs(
|
|
57180
|
+
const result = importCalendarIcs(readFileSync16(path, "utf-8"));
|
|
56812
57181
|
if (opts.json || program2.opts().json) {
|
|
56813
57182
|
output(result, true);
|
|
56814
57183
|
return;
|
|
@@ -56947,7 +57316,7 @@ Repairs`));
|
|
|
56947
57316
|
const bundle = exportTaskBoardBundle(boardId);
|
|
56948
57317
|
const json2 = JSON.stringify(bundle, null, 2);
|
|
56949
57318
|
if (opts.out) {
|
|
56950
|
-
|
|
57319
|
+
writeFileSync9(opts.out, json2);
|
|
56951
57320
|
if (!(opts.json || program2.opts().json))
|
|
56952
57321
|
console.log(chalk7.green(`Wrote ${bundle.boards.length} board(s) to ${opts.out}`));
|
|
56953
57322
|
}
|
|
@@ -56959,7 +57328,7 @@ Repairs`));
|
|
|
56959
57328
|
});
|
|
56960
57329
|
board.command("import <path>").description("Import local board definitions from a JSON bundle").option("-j, --json", "Output JSON").action((path, opts) => {
|
|
56961
57330
|
try {
|
|
56962
|
-
const bundle = JSON.parse(
|
|
57331
|
+
const bundle = JSON.parse(readFileSync16(path, "utf-8"));
|
|
56963
57332
|
const result = importTaskBoardBundle(bundle);
|
|
56964
57333
|
if (opts.json || program2.opts().json) {
|
|
56965
57334
|
output(result, true);
|
|
@@ -57335,7 +57704,7 @@ Repairs`));
|
|
|
57335
57704
|
const { importExternalIssues: importExternalIssues2 } = await Promise.resolve().then(() => (init_external_issue_importers(), exports_external_issue_importers));
|
|
57336
57705
|
let body = text2 || "";
|
|
57337
57706
|
if (opts.file)
|
|
57338
|
-
body =
|
|
57707
|
+
body = readFileSync16(opts.file, "utf-8");
|
|
57339
57708
|
if (!body && !opts.url && !process.stdin.isTTY)
|
|
57340
57709
|
body = await Bun.stdin.text();
|
|
57341
57710
|
if (!body.trim() && !opts.url) {
|
|
@@ -57393,7 +57762,7 @@ Repairs`));
|
|
|
57393
57762
|
} = await Promise.resolve().then(() => (init_tester_issue_reports(), exports_tester_issue_reports));
|
|
57394
57763
|
let body = jsonText || "";
|
|
57395
57764
|
if (opts.file)
|
|
57396
|
-
body =
|
|
57765
|
+
body = readFileSync16(opts.file, "utf-8");
|
|
57397
57766
|
if (!body && !process.stdin.isTTY)
|
|
57398
57767
|
body = await Bun.stdin.text();
|
|
57399
57768
|
if (!body.trim()) {
|
|
@@ -57436,11 +57805,11 @@ Repairs`));
|
|
|
57436
57805
|
const inbox = program2.command("inbox").description("Capture local inbox items from pasted errors, CI logs, git context, files, or GitHub issue URLs");
|
|
57437
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) => {
|
|
57438
57807
|
const globalOpts = program2.opts();
|
|
57439
|
-
const { readFileSync:
|
|
57808
|
+
const { readFileSync: readFileSync17 } = await import("fs");
|
|
57440
57809
|
const { createInboxItem: createInboxItem2 } = await Promise.resolve().then(() => (init_inbox(), exports_inbox));
|
|
57441
57810
|
let body = text2 || "";
|
|
57442
57811
|
if (opts.file)
|
|
57443
|
-
body =
|
|
57812
|
+
body = readFileSync17(opts.file, "utf-8");
|
|
57444
57813
|
if (!body && !process.stdin.isTTY)
|
|
57445
57814
|
body = await Bun.stdin.text();
|
|
57446
57815
|
if (!body.trim()) {
|
|
@@ -57501,11 +57870,11 @@ ${diff}` : null].filter(Boolean).join(`
|
|
|
57501
57870
|
});
|
|
57502
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) => {
|
|
57503
57872
|
const globalOpts = program2.opts();
|
|
57504
|
-
const { readFileSync:
|
|
57873
|
+
const { readFileSync: readFileSync17 } = await import("fs");
|
|
57505
57874
|
const { previewNaturalLanguageIntake: previewNaturalLanguageIntake2 } = await Promise.resolve().then(() => (init_natural_language_intake(), exports_natural_language_intake));
|
|
57506
57875
|
let body = text2 || "";
|
|
57507
57876
|
if (opts.file)
|
|
57508
|
-
body =
|
|
57877
|
+
body = readFileSync17(opts.file, "utf-8");
|
|
57509
57878
|
if (!body && !process.stdin.isTTY)
|
|
57510
57879
|
body = await Bun.stdin.text();
|
|
57511
57880
|
if (!body.trim()) {
|
|
@@ -57629,45 +57998,45 @@ __export(exports_mcp_hooks_commands, {
|
|
|
57629
57998
|
});
|
|
57630
57999
|
import chalk8 from "chalk";
|
|
57631
58000
|
import { execSync as execSync3 } from "child_process";
|
|
57632
|
-
import { existsSync as
|
|
57633
|
-
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";
|
|
57634
58003
|
function getMcpBinaryPath() {
|
|
57635
58004
|
try {
|
|
57636
58005
|
const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
|
|
57637
58006
|
if (p)
|
|
57638
58007
|
return p;
|
|
57639
58008
|
} catch {}
|
|
57640
|
-
const bunBin =
|
|
57641
|
-
if (
|
|
58009
|
+
const bunBin = join21(HOME2, ".bun", "bin", "todos-mcp");
|
|
58010
|
+
if (existsSync21(bunBin))
|
|
57642
58011
|
return bunBin;
|
|
57643
58012
|
return "todos-mcp";
|
|
57644
58013
|
}
|
|
57645
58014
|
function readJsonFile2(path) {
|
|
57646
|
-
if (!
|
|
58015
|
+
if (!existsSync21(path))
|
|
57647
58016
|
return {};
|
|
57648
58017
|
try {
|
|
57649
|
-
return JSON.parse(
|
|
58018
|
+
return JSON.parse(readFileSync17(path, "utf-8"));
|
|
57650
58019
|
} catch {
|
|
57651
58020
|
return {};
|
|
57652
58021
|
}
|
|
57653
58022
|
}
|
|
57654
58023
|
function writeJsonFile2(path, data) {
|
|
57655
58024
|
const dir = dirname12(path);
|
|
57656
|
-
if (!
|
|
57657
|
-
|
|
57658
|
-
|
|
58025
|
+
if (!existsSync21(dir))
|
|
58026
|
+
mkdirSync11(dir, { recursive: true });
|
|
58027
|
+
writeFileSync10(path, JSON.stringify(data, null, 2) + `
|
|
57659
58028
|
`);
|
|
57660
58029
|
}
|
|
57661
58030
|
function readTomlFile(path) {
|
|
57662
|
-
if (!
|
|
58031
|
+
if (!existsSync21(path))
|
|
57663
58032
|
return "";
|
|
57664
|
-
return
|
|
58033
|
+
return readFileSync17(path, "utf-8");
|
|
57665
58034
|
}
|
|
57666
58035
|
function writeTomlFile(path, content) {
|
|
57667
58036
|
const dir = dirname12(path);
|
|
57668
|
-
if (!
|
|
57669
|
-
|
|
57670
|
-
|
|
58037
|
+
if (!existsSync21(dir))
|
|
58038
|
+
mkdirSync11(dir, { recursive: true });
|
|
58039
|
+
writeFileSync10(path, content);
|
|
57671
58040
|
}
|
|
57672
58041
|
function removeTomlBlock(content, blockName) {
|
|
57673
58042
|
const lines = content.split(`
|
|
@@ -57731,7 +58100,7 @@ function unregisterClaude(_global) {
|
|
|
57731
58100
|
}
|
|
57732
58101
|
}
|
|
57733
58102
|
function registerCodex(binPath) {
|
|
57734
|
-
const configPath =
|
|
58103
|
+
const configPath = join21(HOME2, ".codex", "config.toml");
|
|
57735
58104
|
let content = readTomlFile(configPath);
|
|
57736
58105
|
content = removeTomlBlock(content, "mcp_servers.todos");
|
|
57737
58106
|
const block = `
|
|
@@ -57745,7 +58114,7 @@ args = []
|
|
|
57745
58114
|
console.log(chalk8.green(`Codex CLI: registered in ${configPath}`));
|
|
57746
58115
|
}
|
|
57747
58116
|
function unregisterCodex() {
|
|
57748
|
-
const configPath =
|
|
58117
|
+
const configPath = join21(HOME2, ".codex", "config.toml");
|
|
57749
58118
|
let content = readTomlFile(configPath);
|
|
57750
58119
|
if (!content.includes("[mcp_servers.todos]")) {
|
|
57751
58120
|
console.log(chalk8.dim(`Codex CLI: todos not found in ${configPath}`));
|
|
@@ -57757,7 +58126,7 @@ function unregisterCodex() {
|
|
|
57757
58126
|
console.log(chalk8.green(`Codex CLI: unregistered from ${configPath}`));
|
|
57758
58127
|
}
|
|
57759
58128
|
function registerGemini(binPath) {
|
|
57760
|
-
const configPath =
|
|
58129
|
+
const configPath = join21(HOME2, ".gemini", "settings.json");
|
|
57761
58130
|
const config = readJsonFile2(configPath);
|
|
57762
58131
|
if (!config["mcpServers"]) {
|
|
57763
58132
|
config["mcpServers"] = {};
|
|
@@ -57771,7 +58140,7 @@ function registerGemini(binPath) {
|
|
|
57771
58140
|
console.log(chalk8.green(`Gemini CLI: registered in ${configPath}`));
|
|
57772
58141
|
}
|
|
57773
58142
|
function unregisterGemini() {
|
|
57774
|
-
const configPath =
|
|
58143
|
+
const configPath = join21(HOME2, ".gemini", "settings.json");
|
|
57775
58144
|
const config = readJsonFile2(configPath);
|
|
57776
58145
|
const servers = config["mcpServers"];
|
|
57777
58146
|
if (!servers || !("todos" in servers)) {
|
|
@@ -57828,9 +58197,9 @@ function registerMcpHooksCommands(program2) {
|
|
|
57828
58197
|
if (p)
|
|
57829
58198
|
todosBin = p;
|
|
57830
58199
|
} catch {}
|
|
57831
|
-
const hooksDir =
|
|
57832
|
-
if (!
|
|
57833
|
-
|
|
58200
|
+
const hooksDir = join21(process.cwd(), ".claude", "hooks");
|
|
58201
|
+
if (!existsSync21(hooksDir))
|
|
58202
|
+
mkdirSync11(hooksDir, { recursive: true });
|
|
57834
58203
|
const hookScript = `#!/usr/bin/env bash
|
|
57835
58204
|
# Auto-generated by: todos hooks install
|
|
57836
58205
|
# Syncs todos with Claude Code task list on tool use events.
|
|
@@ -57854,11 +58223,11 @@ esac
|
|
|
57854
58223
|
|
|
57855
58224
|
exit 0
|
|
57856
58225
|
`;
|
|
57857
|
-
const hookPath =
|
|
57858
|
-
|
|
58226
|
+
const hookPath = join21(hooksDir, "todos-sync.sh");
|
|
58227
|
+
writeFileSync10(hookPath, hookScript);
|
|
57859
58228
|
execSync3(`chmod +x "${hookPath}"`);
|
|
57860
58229
|
console.log(chalk8.green(`Hook script created: ${hookPath}`));
|
|
57861
|
-
const settingsPath =
|
|
58230
|
+
const settingsPath = join21(process.cwd(), ".claude", "settings.json");
|
|
57862
58231
|
const settings = readJsonFile2(settingsPath);
|
|
57863
58232
|
if (!settings["hooks"]) {
|
|
57864
58233
|
settings["hooks"] = {};
|
|
@@ -58727,18 +59096,18 @@ Artifacts:`));
|
|
|
58727
59096
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
58728
59097
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
58729
59098
|
const marker = "# todos-auto-link";
|
|
58730
|
-
if (
|
|
58731
|
-
const existing =
|
|
59099
|
+
if (existsSync21(hookPath)) {
|
|
59100
|
+
const existing = readFileSync17(hookPath, "utf-8");
|
|
58732
59101
|
if (existing.includes(marker)) {
|
|
58733
59102
|
console.log(chalk8.yellow("Hook already installed."));
|
|
58734
59103
|
return;
|
|
58735
59104
|
}
|
|
58736
|
-
|
|
59105
|
+
writeFileSync10(hookPath, existing + `
|
|
58737
59106
|
${marker}
|
|
58738
59107
|
$(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
58739
59108
|
`);
|
|
58740
59109
|
} else {
|
|
58741
|
-
|
|
59110
|
+
writeFileSync10(hookPath, `#!/usr/bin/env bash
|
|
58742
59111
|
${marker}
|
|
58743
59112
|
$(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
58744
59113
|
`);
|
|
@@ -58755,11 +59124,11 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
58755
59124
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
58756
59125
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
58757
59126
|
const marker = "# todos-auto-link";
|
|
58758
|
-
if (!
|
|
59127
|
+
if (!existsSync21(hookPath)) {
|
|
58759
59128
|
console.log(chalk8.dim("No post-commit hook found."));
|
|
58760
59129
|
return;
|
|
58761
59130
|
}
|
|
58762
|
-
const content =
|
|
59131
|
+
const content = readFileSync17(hookPath, "utf-8");
|
|
58763
59132
|
if (!content.includes(marker)) {
|
|
58764
59133
|
console.log(chalk8.dim("Hook not managed by todos."));
|
|
58765
59134
|
return;
|
|
@@ -58770,7 +59139,7 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
58770
59139
|
if (cleaned === "#!/usr/bin/env bash" || cleaned === "") {
|
|
58771
59140
|
(await import("fs")).unlinkSync(hookPath);
|
|
58772
59141
|
} else {
|
|
58773
|
-
|
|
59142
|
+
writeFileSync10(hookPath, cleaned + `
|
|
58774
59143
|
`);
|
|
58775
59144
|
}
|
|
58776
59145
|
console.log(chalk8.green("Post-commit hook removed."));
|
|
@@ -58939,9 +59308,9 @@ __export(exports_machines, {
|
|
|
58939
59308
|
});
|
|
58940
59309
|
import chalk10 from "chalk";
|
|
58941
59310
|
import { execSync as execSync4 } from "child_process";
|
|
58942
|
-
import { readFileSync as
|
|
59311
|
+
import { readFileSync as readFileSync18, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
|
|
58943
59312
|
import { tmpdir as tmpdir4 } from "os";
|
|
58944
|
-
import { join as
|
|
59313
|
+
import { join as join22 } from "path";
|
|
58945
59314
|
function getOrCreateLocalMachineName() {
|
|
58946
59315
|
return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
|
|
58947
59316
|
}
|
|
@@ -58979,11 +59348,11 @@ function remoteTempPath(sshAddress) {
|
|
|
58979
59348
|
}
|
|
58980
59349
|
function readRemoteBridgeBundle(sshAddress) {
|
|
58981
59350
|
const remotePath = remoteTempPath(sshAddress);
|
|
58982
|
-
const localPath =
|
|
59351
|
+
const localPath = join22(tmpdir4(), `todos-bridge-pull-${uuid()}.json`);
|
|
58983
59352
|
try {
|
|
58984
59353
|
runSsh(sshAddress, `todos export --format bridge --allow-plaintext-sensitive --output ${shellQuote(remotePath)}`, 120000);
|
|
58985
59354
|
scpFromRemote(sshAddress, remotePath, localPath);
|
|
58986
|
-
return JSON.parse(
|
|
59355
|
+
return JSON.parse(readFileSync18(localPath, "utf-8"));
|
|
58987
59356
|
} finally {
|
|
58988
59357
|
try {
|
|
58989
59358
|
runSsh(sshAddress, `rm -f ${shellQuote(remotePath)}`, 1e4);
|
|
@@ -58994,8 +59363,8 @@ function readRemoteBridgeBundle(sshAddress) {
|
|
|
58994
59363
|
}
|
|
58995
59364
|
}
|
|
58996
59365
|
function writeLocalBridgeBundle() {
|
|
58997
|
-
const localPath =
|
|
58998
|
-
|
|
59366
|
+
const localPath = join22(tmpdir4(), `todos-bridge-push-${uuid()}.json`);
|
|
59367
|
+
writeFileSync11(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
|
|
58999
59368
|
return localPath;
|
|
59000
59369
|
}
|
|
59001
59370
|
function pushLocalBridgeBundle(sshAddress, dryRun) {
|
|
@@ -60058,7 +60427,7 @@ __export(exports_onboarding_commands, {
|
|
|
60058
60427
|
registerOnboardingCommands: () => registerOnboardingCommands
|
|
60059
60428
|
});
|
|
60060
60429
|
import chalk17 from "chalk";
|
|
60061
|
-
import { resolve as
|
|
60430
|
+
import { resolve as resolve21 } from "path";
|
|
60062
60431
|
function registerOnboardingCommands(program2) {
|
|
60063
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) => {
|
|
60064
60433
|
const globalOpts = program2.opts();
|
|
@@ -60074,7 +60443,7 @@ function registerOnboardingCommands(program2) {
|
|
|
60074
60443
|
return;
|
|
60075
60444
|
}
|
|
60076
60445
|
if (opts.write) {
|
|
60077
|
-
const result = writeOnboardingFixtureFiles2(
|
|
60446
|
+
const result = writeOnboardingFixtureFiles2(resolve21(opts.write));
|
|
60078
60447
|
if (globalOpts.json) {
|
|
60079
60448
|
output(result, true);
|
|
60080
60449
|
return;
|
|
@@ -63522,8 +63891,8 @@ __export(exports_sdk_integration_fixtures, {
|
|
|
63522
63891
|
TODOS_SDK_INTEGRATION_FIXTURE_SCHEMA_VERSION: () => TODOS_SDK_INTEGRATION_FIXTURE_SCHEMA_VERSION,
|
|
63523
63892
|
TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT: () => TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT
|
|
63524
63893
|
});
|
|
63525
|
-
import { mkdirSync as
|
|
63526
|
-
import { join as
|
|
63894
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
63895
|
+
import { join as join23 } from "path";
|
|
63527
63896
|
function source5(version) {
|
|
63528
63897
|
return {
|
|
63529
63898
|
packageName: "@hasna/todos",
|
|
@@ -63619,7 +63988,7 @@ function createSdkIntegrationFixturePack(options = {}) {
|
|
|
63619
63988
|
};
|
|
63620
63989
|
}
|
|
63621
63990
|
function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
63622
|
-
|
|
63991
|
+
mkdirSync12(directory, { recursive: true });
|
|
63623
63992
|
const pack = createSdkIntegrationFixturePack(options);
|
|
63624
63993
|
const bundle = getOnboardingFixtureBundle("agent-project-demo");
|
|
63625
63994
|
const files = [
|
|
@@ -63630,8 +63999,8 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
|
63630
63999
|
];
|
|
63631
64000
|
const written = [];
|
|
63632
64001
|
for (const [name, payload] of files) {
|
|
63633
|
-
const file =
|
|
63634
|
-
|
|
64002
|
+
const file = join23(directory, name);
|
|
64003
|
+
writeFileSync12(file, `${JSON.stringify(payload, null, 2)}
|
|
63635
64004
|
`, "utf-8");
|
|
63636
64005
|
written.push(file);
|
|
63637
64006
|
}
|
|
@@ -63654,7 +64023,7 @@ __export(exports_sdk_fixture_commands, {
|
|
|
63654
64023
|
registerSdkFixtureCommands: () => registerSdkFixtureCommands
|
|
63655
64024
|
});
|
|
63656
64025
|
import chalk19 from "chalk";
|
|
63657
|
-
import { resolve as
|
|
64026
|
+
import { resolve as resolve22 } from "path";
|
|
63658
64027
|
function registerSdkFixtureCommands(program2) {
|
|
63659
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) => {
|
|
63660
64029
|
const globalOpts = program2.opts();
|
|
@@ -63665,7 +64034,7 @@ function registerSdkFixtureCommands(program2) {
|
|
|
63665
64034
|
writeSdkIntegrationFixtures: writeSdkIntegrationFixtures2
|
|
63666
64035
|
} = await Promise.resolve().then(() => (init_sdk_integration_fixtures(), exports_sdk_integration_fixtures));
|
|
63667
64036
|
if (opts.write) {
|
|
63668
|
-
const result = writeSdkIntegrationFixtures2(
|
|
64037
|
+
const result = writeSdkIntegrationFixtures2(resolve22(opts.write));
|
|
63669
64038
|
if (globalOpts.json) {
|
|
63670
64039
|
console.log(JSON.stringify(result));
|
|
63671
64040
|
return;
|
|
@@ -63895,7 +64264,7 @@ var exports_roadmap_commands = {};
|
|
|
63895
64264
|
__export(exports_roadmap_commands, {
|
|
63896
64265
|
registerRoadmapCommands: () => registerRoadmapCommands
|
|
63897
64266
|
});
|
|
63898
|
-
import { readFileSync as
|
|
64267
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
63899
64268
|
import chalk21 from "chalk";
|
|
63900
64269
|
function splitList3(value) {
|
|
63901
64270
|
return value?.split(";").flatMap((part) => part.split(",")).map((item) => item.trim()).filter(Boolean);
|
|
@@ -64106,7 +64475,7 @@ function registerRoadmapCommands(program2) {
|
|
|
64106
64475
|
const { exportRoadmapBundle: exportRoadmapBundle2, renderRoadmapMarkdown: renderRoadmapMarkdown2 } = await Promise.resolve().then(() => (init_roadmaps(), exports_roadmaps));
|
|
64107
64476
|
const content = opts.format === "markdown" ? renderRoadmapMarkdown2(roadmap) : JSON.stringify(exportRoadmapBundle2(roadmap), null, 2);
|
|
64108
64477
|
if (opts.out) {
|
|
64109
|
-
|
|
64478
|
+
writeFileSync13(opts.out, content);
|
|
64110
64479
|
if (!globalOpts.json)
|
|
64111
64480
|
console.log(chalk21.green(`Wrote roadmap export to ${opts.out}`));
|
|
64112
64481
|
}
|
|
@@ -64124,7 +64493,7 @@ function registerRoadmapCommands(program2) {
|
|
|
64124
64493
|
const globalOpts = globalOptions(program2);
|
|
64125
64494
|
try {
|
|
64126
64495
|
const { importRoadmapBundle: importRoadmapBundle2 } = await Promise.resolve().then(() => (init_roadmaps(), exports_roadmaps));
|
|
64127
|
-
const bundle = JSON.parse(
|
|
64496
|
+
const bundle = JSON.parse(readFileSync19(path, "utf8"));
|
|
64128
64497
|
const result = importRoadmapBundle2(bundle, { apply: Boolean(opts.apply) });
|
|
64129
64498
|
if (globalOpts.json) {
|
|
64130
64499
|
output(result, true);
|
|
@@ -64487,7 +64856,7 @@ __export(exports_local_backup_commands, {
|
|
|
64487
64856
|
registerLocalBackupCommands: () => registerLocalBackupCommands
|
|
64488
64857
|
});
|
|
64489
64858
|
import chalk26 from "chalk";
|
|
64490
|
-
import { resolve as
|
|
64859
|
+
import { resolve as resolve23 } from "path";
|
|
64491
64860
|
function globalOptions6(program2) {
|
|
64492
64861
|
const command = program2;
|
|
64493
64862
|
return command.optsWithGlobals?.() ?? program2.opts();
|
|
@@ -64509,10 +64878,10 @@ function registerLocalBackupCommands(program2) {
|
|
|
64509
64878
|
const projectId = opts.projectId ?? autoProject(globalOpts);
|
|
64510
64879
|
const backupBundle = createLocalBackup2({
|
|
64511
64880
|
project_id: projectId,
|
|
64512
|
-
output_path: opts.output ?
|
|
64881
|
+
output_path: opts.output ? resolve23(opts.output) : undefined
|
|
64513
64882
|
});
|
|
64514
64883
|
const result = {
|
|
64515
|
-
output_path: opts.output ?
|
|
64884
|
+
output_path: opts.output ? resolve23(opts.output) : null,
|
|
64516
64885
|
backup: backupBundle
|
|
64517
64886
|
};
|
|
64518
64887
|
if (opts.json || globalOpts.json) {
|