@hasna/todos 0.13.5 → 0.13.7
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/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +418 -177
- package/dist/contracts.js +29 -3
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +43 -7
- package/dist/lib/creator-identity.d.ts +100 -0
- package/dist/lib/creator-identity.d.ts.map +1 -0
- package/dist/lib/onboarding-fixtures.d.ts.map +1 -1
- package/dist/mcp/index.js +177 -75
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/registry.js +29 -3
- package/dist/release-provenance.json +5 -5
- package/dist/server/index.js +167 -65
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/local-sqlite.d.ts.map +1 -1
- package/dist/storage.js +41 -6
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2123,7 +2123,7 @@ var package_default;
|
|
|
2123
2123
|
var init_package = __esm(() => {
|
|
2124
2124
|
package_default = {
|
|
2125
2125
|
name: "@hasna/todos",
|
|
2126
|
-
version: "0.13.
|
|
2126
|
+
version: "0.13.7",
|
|
2127
2127
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
2128
2128
|
type: "module",
|
|
2129
2129
|
main: "dist/index.js",
|
|
@@ -5871,6 +5871,7 @@ function unresolvedRelatedTask(id) {
|
|
|
5871
5871
|
reason: null,
|
|
5872
5872
|
spawned_from_session: null,
|
|
5873
5873
|
assigned_by: null,
|
|
5874
|
+
created_by: null,
|
|
5874
5875
|
assigned_from_project: null,
|
|
5875
5876
|
task_type: null,
|
|
5876
5877
|
cost_tokens: 0,
|
|
@@ -9035,6 +9036,7 @@ function ensureSchema(db) {
|
|
|
9035
9036
|
ensureColumn("tasks", "reason", "TEXT");
|
|
9036
9037
|
ensureColumn("tasks", "spawned_from_session", "TEXT");
|
|
9037
9038
|
ensureColumn("tasks", "assigned_by", "TEXT");
|
|
9039
|
+
ensureColumn("tasks", "created_by", "TEXT");
|
|
9038
9040
|
ensureColumn("tasks", "assigned_from_project", "TEXT");
|
|
9039
9041
|
ensureColumn("tasks", "started_at", "TEXT");
|
|
9040
9042
|
ensureColumn("tasks", "task_type", "TEXT");
|
|
@@ -9197,6 +9199,8 @@ function ensureSchema(db) {
|
|
|
9197
9199
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_project ON project_sources(project_id)");
|
|
9198
9200
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_type ON project_sources(type)");
|
|
9199
9201
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_by ON tasks(assigned_by)");
|
|
9202
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by)");
|
|
9203
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_created ON tasks(assigned_to, created_by)");
|
|
9200
9204
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_source ON task_relationships(source_task_id)");
|
|
9201
9205
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_target ON task_relationships(target_task_id)");
|
|
9202
9206
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_type ON task_relationships(relationship_type)");
|
|
@@ -15346,13 +15350,14 @@ function createTask(input, db) {
|
|
|
15346
15350
|
const timestamp2 = now();
|
|
15347
15351
|
const tags = input.tags || [];
|
|
15348
15352
|
const machineId = currentStorageMachineId(d);
|
|
15353
|
+
const createdBy = input.created_by || input.agent_id || null;
|
|
15349
15354
|
const assignedBy = input.assigned_by || input.agent_id;
|
|
15350
15355
|
const assignedFromProject = input.assigned_from_project || null;
|
|
15351
15356
|
let id = uuid();
|
|
15352
15357
|
for (let attempt = 0;attempt < 3; attempt++) {
|
|
15353
15358
|
try {
|
|
15354
|
-
d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, cycle_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, sla_minutes, confidence, retry_count, max_retries, retry_after, requires_approval, approved_by, approved_at, recurrence_rule, recurrence_parent_id, spawns_template_id, reason, spawned_from_session, assigned_by, assigned_from_project, task_type, machine_id)
|
|
15355
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
15359
|
+
d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, cycle_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, sla_minutes, confidence, retry_count, max_retries, retry_after, requires_approval, approved_by, approved_at, recurrence_rule, recurrence_parent_id, spawns_template_id, reason, spawned_from_session, assigned_by, created_by, assigned_from_project, task_type, machine_id)
|
|
15360
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
15356
15361
|
id,
|
|
15357
15362
|
null,
|
|
15358
15363
|
input.project_id || null,
|
|
@@ -15388,6 +15393,7 @@ function createTask(input, db) {
|
|
|
15388
15393
|
input.reason || null,
|
|
15389
15394
|
input.spawned_from_session || null,
|
|
15390
15395
|
assignedBy || null,
|
|
15396
|
+
createdBy,
|
|
15391
15397
|
assignedFromProject || null,
|
|
15392
15398
|
input.task_type || null,
|
|
15393
15399
|
machineId
|
|
@@ -15497,6 +15503,14 @@ function listTasks(filter = {}, db) {
|
|
|
15497
15503
|
conditions.push("agent_id = ?");
|
|
15498
15504
|
params.push(filter.agent_id);
|
|
15499
15505
|
}
|
|
15506
|
+
if (filter.created_by) {
|
|
15507
|
+
conditions.push("LOWER(created_by) = LOWER(?)");
|
|
15508
|
+
params.push(filter.created_by);
|
|
15509
|
+
}
|
|
15510
|
+
if (filter.not_created_by) {
|
|
15511
|
+
conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
|
|
15512
|
+
params.push(filter.not_created_by);
|
|
15513
|
+
}
|
|
15500
15514
|
if (filter.session_id) {
|
|
15501
15515
|
conditions.push("session_id = ?");
|
|
15502
15516
|
params.push(filter.session_id);
|
|
@@ -15650,6 +15664,14 @@ function countTasks(filter = {}, db) {
|
|
|
15650
15664
|
conditions.push("agent_id = ?");
|
|
15651
15665
|
params.push(filter.agent_id);
|
|
15652
15666
|
}
|
|
15667
|
+
if (filter.created_by) {
|
|
15668
|
+
conditions.push("LOWER(created_by) = LOWER(?)");
|
|
15669
|
+
params.push(filter.created_by);
|
|
15670
|
+
}
|
|
15671
|
+
if (filter.not_created_by) {
|
|
15672
|
+
conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
|
|
15673
|
+
params.push(filter.not_created_by);
|
|
15674
|
+
}
|
|
15653
15675
|
if (filter.session_id) {
|
|
15654
15676
|
conditions.push("session_id = ?");
|
|
15655
15677
|
params.push(filter.session_id);
|
|
@@ -15710,6 +15732,10 @@ function updateTask(id, input, db) {
|
|
|
15710
15732
|
sets.push("description = ?");
|
|
15711
15733
|
params.push(input.description);
|
|
15712
15734
|
}
|
|
15735
|
+
if (input.agent_id !== undefined) {
|
|
15736
|
+
sets.push("agent_id = ?");
|
|
15737
|
+
params.push(input.agent_id);
|
|
15738
|
+
}
|
|
15713
15739
|
if (input.status !== undefined) {
|
|
15714
15740
|
if (input.status === "completed") {
|
|
15715
15741
|
checkCompletionGuard(task, task.assigned_to || task.agent_id || null, d);
|
|
@@ -18810,6 +18836,82 @@ var init_tasks = __esm(() => {
|
|
|
18810
18836
|
init_calendar();
|
|
18811
18837
|
});
|
|
18812
18838
|
|
|
18839
|
+
// src/lib/creator-identity.ts
|
|
18840
|
+
import { existsSync as existsSync8, rmSync as rmSync2 } from "fs";
|
|
18841
|
+
import { join as join7 } from "path";
|
|
18842
|
+
function identityFilePath() {
|
|
18843
|
+
return join7(getTodosGlobalDir(), "identity.json");
|
|
18844
|
+
}
|
|
18845
|
+
function readPersistedIdentity() {
|
|
18846
|
+
const path = identityFilePath();
|
|
18847
|
+
if (!existsSync8(path))
|
|
18848
|
+
return null;
|
|
18849
|
+
const parsed = readJsonFile(path);
|
|
18850
|
+
if (!parsed || typeof parsed.agent_id !== "string" || !parsed.agent_id.trim())
|
|
18851
|
+
return null;
|
|
18852
|
+
return parsed;
|
|
18853
|
+
}
|
|
18854
|
+
function detectIdentityCollision(agentId, agentName) {
|
|
18855
|
+
const existing = readPersistedIdentity();
|
|
18856
|
+
if (!existing)
|
|
18857
|
+
return null;
|
|
18858
|
+
const sameId = canonicalAgentRef(existing.agent_id) === canonicalAgentRef(agentId);
|
|
18859
|
+
const sameName = Boolean(agentName) && canonicalAgentRef(existing.agent_name || "") === canonicalAgentRef(agentName);
|
|
18860
|
+
if (sameId || sameName)
|
|
18861
|
+
return null;
|
|
18862
|
+
return { existing };
|
|
18863
|
+
}
|
|
18864
|
+
function persistIdentity(identity) {
|
|
18865
|
+
const record = {
|
|
18866
|
+
agent_id: identity.agent_id,
|
|
18867
|
+
...identity.agent_name ? { agent_name: identity.agent_name } : {},
|
|
18868
|
+
...identity.session_id ? { session_id: identity.session_id } : {},
|
|
18869
|
+
registered_at: new Date().toISOString()
|
|
18870
|
+
};
|
|
18871
|
+
ensureDir(getTodosGlobalDir());
|
|
18872
|
+
writeJsonFile(identityFilePath(), record);
|
|
18873
|
+
return record;
|
|
18874
|
+
}
|
|
18875
|
+
function clearPersistedIdentity() {
|
|
18876
|
+
const path = identityFilePath();
|
|
18877
|
+
if (!existsSync8(path))
|
|
18878
|
+
return false;
|
|
18879
|
+
try {
|
|
18880
|
+
rmSync2(path);
|
|
18881
|
+
return true;
|
|
18882
|
+
} catch {
|
|
18883
|
+
return false;
|
|
18884
|
+
}
|
|
18885
|
+
}
|
|
18886
|
+
function canonicalAgentRef(value) {
|
|
18887
|
+
return value.trim().toLowerCase();
|
|
18888
|
+
}
|
|
18889
|
+
function isProcessBoundSource(source) {
|
|
18890
|
+
return source === "explicit" || source === "env";
|
|
18891
|
+
}
|
|
18892
|
+
function resolveWritableIdentity(explicit) {
|
|
18893
|
+
const resolved = resolveCreatorIdentity(explicit);
|
|
18894
|
+
if (!isProcessBoundSource(resolved.source))
|
|
18895
|
+
return { agent_id: null, source: "none" };
|
|
18896
|
+
return resolved;
|
|
18897
|
+
}
|
|
18898
|
+
function resolveCreatorIdentity(explicit) {
|
|
18899
|
+
const fromExplicit = explicit?.trim();
|
|
18900
|
+
if (fromExplicit)
|
|
18901
|
+
return { agent_id: canonicalAgentRef(fromExplicit), source: "explicit" };
|
|
18902
|
+
const fromEnv = (process.env["TODOS_AGENT_ID"] || process.env["HASNA_TODOS_AGENT_ID"] || "").trim();
|
|
18903
|
+
if (fromEnv)
|
|
18904
|
+
return { agent_id: canonicalAgentRef(fromEnv), source: "env" };
|
|
18905
|
+
const persisted = readPersistedIdentity();
|
|
18906
|
+
if (persisted) {
|
|
18907
|
+
return { agent_id: canonicalAgentRef(persisted.agent_name || persisted.agent_id), source: "persisted" };
|
|
18908
|
+
}
|
|
18909
|
+
return { agent_id: null, source: "none" };
|
|
18910
|
+
}
|
|
18911
|
+
var init_creator_identity = __esm(() => {
|
|
18912
|
+
init_sync_utils();
|
|
18913
|
+
});
|
|
18914
|
+
|
|
18813
18915
|
// src/cli/output-redaction.ts
|
|
18814
18916
|
function redactBroadTask(task) {
|
|
18815
18917
|
return redactValue(task);
|
|
@@ -18830,7 +18932,7 @@ __export(exports_task_routing, {
|
|
|
18830
18932
|
setTaskWorkflowPointers: () => setTaskWorkflowPointers,
|
|
18831
18933
|
getTaskRouteState: () => getTaskRouteState
|
|
18832
18934
|
});
|
|
18833
|
-
import { existsSync as
|
|
18935
|
+
import { existsSync as existsSync9, statSync as statSync3 } from "fs";
|
|
18834
18936
|
function machineLocalPath(project, db) {
|
|
18835
18937
|
const machineId = process.env["TODOS_MACHINE_ID"];
|
|
18836
18938
|
if (!machineId)
|
|
@@ -18870,7 +18972,7 @@ function routeConcurrencyKey(task, project, taskList, projectPath) {
|
|
|
18870
18972
|
}
|
|
18871
18973
|
function directoryExists(path) {
|
|
18872
18974
|
try {
|
|
18873
|
-
return
|
|
18975
|
+
return existsSync9(path) && statSync3(path).isDirectory();
|
|
18874
18976
|
} catch {
|
|
18875
18977
|
return false;
|
|
18876
18978
|
}
|
|
@@ -19307,10 +19409,16 @@ function computeLocalReparent(current, opts) {
|
|
|
19307
19409
|
return patch;
|
|
19308
19410
|
}
|
|
19309
19411
|
function registerTaskCommands(program2) {
|
|
19310
|
-
program2.command("add <title>").description("Create a new task").option("-d, --description <text>", "Task description").option("-p, --priority <level>", "Priority: low, medium, high, critical").option("--parent <id>", "Parent task ID").option("-t, --tags <tags>", "Comma-separated tags").option("--tag <tags>", "Comma-separated tags (alias for --tags)").option("--plan <id>", "Assign to a plan").option("--assign <agent>", "Assign to agent").option("--status <status>", "Initial status").option("--list <id>", "Task list ID").option("--task-list <id>", "Task list ID (alias for --list)").option("--estimated <minutes>", "Estimated time in minutes").option("--sla-minutes <minutes>", "SLA minutes before unfinished work is escalated").option("--sla <minutes>", "Alias for --sla-minutes").option("--approval", "Require approval before completion").option("--recurrence <rule>", "Recurrence rule, e.g. 'every day', 'every weekday', 'every 2 weeks'").option("--due <date>", "Due date (ISO string or YYYY-MM-DD)").option("--reason <text>", "Why this task exists").option("--project <id>", "Assign to project by ID or slug (overrides auto-detect)").action(async (title, opts) => {
|
|
19412
|
+
program2.command("add <title>").description("Create a new task").option("-d, --description <text>", "Task description").option("-p, --priority <level>", "Priority: low, medium, high, critical").option("--parent <id>", "Parent task ID").option("-t, --tags <tags>", "Comma-separated tags").option("--tag <tags>", "Comma-separated tags (alias for --tags)").option("--plan <id>", "Assign to a plan").option("--assign <agent>", "Assign to agent").option("--status <status>", "Initial status").option("--list <id>", "Task list ID").option("--task-list <id>", "Task list ID (alias for --list)").option("--estimated <minutes>", "Estimated time in minutes").option("--sla-minutes <minutes>", "SLA minutes before unfinished work is escalated").option("--sla <minutes>", "Alias for --sla-minutes").option("--approval", "Require approval before completion").option("--recurrence <rule>", "Recurrence rule, e.g. 'every day', 'every weekday', 'every 2 weeks'").option("--due <date>", "Due date (ISO string or YYYY-MM-DD)").option("--reason <text>", "Why this task exists").option("--project <id>", "Assign to project by ID or slug (overrides auto-detect)").option("--unassigned", "Deliberately file this task with no assignee").option("--created-by <agent>", "Record a different filer than the resolved agent identity").action(async (title, opts) => {
|
|
19311
19413
|
const globalOpts = program2.opts();
|
|
19312
19414
|
opts.tags = opts.tags || opts.tag;
|
|
19313
19415
|
opts.list = opts.list || opts.taskList;
|
|
19416
|
+
const creator = resolveCreatorIdentity(opts.createdBy || globalOpts.agent);
|
|
19417
|
+
const router = resolveWritableIdentity(opts.createdBy || globalOpts.agent);
|
|
19418
|
+
const assignee = opts.assign || (opts.unassigned ? undefined : router.agent_id || undefined);
|
|
19419
|
+
if (!assignee && !opts.unassigned) {
|
|
19420
|
+
console.error(chalk2.yellow("Warning: task is ownerless and unattributable \u2014 export TODOS_AGENT_ID=<name> for this session, or pass --agent/--assign <agent> or --unassigned."));
|
|
19421
|
+
}
|
|
19314
19422
|
const cloud = getTodosCloudClient();
|
|
19315
19423
|
if (cloud) {
|
|
19316
19424
|
let task3;
|
|
@@ -19332,10 +19440,11 @@ function registerTaskCommands(program2) {
|
|
|
19332
19440
|
parent_id: opts.parent ? await resolveTaskIdForCommand(opts.parent, cloud) : undefined,
|
|
19333
19441
|
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
|
|
19334
19442
|
plan_id: cloudPlan?.id,
|
|
19335
|
-
assigned_to:
|
|
19443
|
+
assigned_to: assignee,
|
|
19336
19444
|
status: parseStatus(opts.status),
|
|
19337
19445
|
task_list_id: cloudTaskListId,
|
|
19338
|
-
agent_id: globalOpts.agent,
|
|
19446
|
+
agent_id: globalOpts.agent || router.agent_id || undefined,
|
|
19447
|
+
created_by: creator.agent_id || undefined,
|
|
19339
19448
|
session_id: globalOpts.session,
|
|
19340
19449
|
project_id: cloudProjectId,
|
|
19341
19450
|
estimated_minutes: opts.estimated !== undefined ? parseIntOption(opts.estimated, "--estimated") : undefined,
|
|
@@ -19377,10 +19486,11 @@ function registerTaskCommands(program2) {
|
|
|
19377
19486
|
parent_id: opts.parent ? resolveTaskId(opts.parent) : undefined,
|
|
19378
19487
|
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
|
|
19379
19488
|
plan_id: opts.plan ? resolvePlanId(opts.plan) : undefined,
|
|
19380
|
-
assigned_to:
|
|
19489
|
+
assigned_to: assignee,
|
|
19381
19490
|
status: parseStatus(opts.status),
|
|
19382
19491
|
task_list_id: taskListId,
|
|
19383
|
-
agent_id: globalOpts.agent,
|
|
19492
|
+
agent_id: globalOpts.agent || router.agent_id || undefined,
|
|
19493
|
+
created_by: creator.agent_id || undefined,
|
|
19384
19494
|
session_id: globalOpts.session,
|
|
19385
19495
|
project_id: projectId,
|
|
19386
19496
|
working_dir: process.cwd(),
|
|
@@ -19534,14 +19644,14 @@ function registerTaskCommands(program2) {
|
|
|
19534
19644
|
console.log(` ${chalk2.dim("Manifest:")} ${state.pointers.latest_manifest_path}`);
|
|
19535
19645
|
}
|
|
19536
19646
|
});
|
|
19537
|
-
program2.command("list").description("List tasks").option("-s, --status <status>", "Filter by status").option("-p, --priority <priority>", "Filter by priority").option("--assigned <agent>", "Filter by assigned agent").option("--tags <tags>", "Filter by tags (comma-separated)").option("--tag <tags>", "Filter by tags (alias for --tags)").option("-a, --all", "Show all tasks (including completed/cancelled)").option("--list <ref>", "Filter by task list UUID, unique UUID prefix, or project-scoped slug").option("--task-list <ref>", "Filter by task list UUID, unique UUID prefix, or project-scoped slug (alias for --list)").option("--project-name <name>", "Filter by project name").option("--agent-name <name>", "Filter by agent name/assigned").option("--sort <field>", "Sort by: updated, created, priority, status").option("--format <fmt>", "Output format: table (default), compact, csv, json").option("--due-today", "Only tasks due today or earlier").option("--overdue", "Only overdue tasks (past due_at)").option("--recurring", "Only recurring tasks").option("--limit <n>", "Max tasks to return").action(async (opts) => {
|
|
19647
|
+
program2.command("list").description("List tasks").option("-s, --status <status>", "Filter by status").option("-p, --priority <priority>", "Filter by priority").option("--assigned <agent>", "Filter by assigned agent").option("--created-by <agent>", "Filter by the agent who FILED the task").option("--not-created-by <agent>", "Exclude tasks filed by this agent").option("--inbox", "Work assigned to my identity that a DIFFERENT agent filed").option("--tags <tags>", "Filter by tags (comma-separated)").option("--tag <tags>", "Filter by tags (alias for --tags)").option("-a, --all", "Show all tasks (including completed/cancelled)").option("--list <ref>", "Filter by task list UUID, unique UUID prefix, or project-scoped slug").option("--task-list <ref>", "Filter by task list UUID, unique UUID prefix, or project-scoped slug (alias for --list)").option("--project-name <name>", "Filter by project name").option("--agent-name <name>", "Filter by agent name/assigned").option("--sort <field>", "Sort by: updated, created, priority, status").option("--format <fmt>", "Output format: table (default), compact, csv, json").option("--due-today", "Only tasks due today or earlier").option("--overdue", "Only overdue tasks (past due_at)").option("--recurring", "Only recurring tasks").option("--limit <n>", "Max tasks to return").action(async (opts) => {
|
|
19538
19648
|
const globalOpts = program2.opts();
|
|
19539
19649
|
opts.tags = opts.tags || opts.tag;
|
|
19540
19650
|
opts.list = opts.list || opts.taskList;
|
|
19541
19651
|
const cloud = getTodosCloudClient();
|
|
19542
19652
|
const cloudProjectRef = globalOpts.project || opts.projectName;
|
|
19543
19653
|
const projectId = cloud && cloudProjectRef ? await cloudResolveProjectRef(cloud, cloudProjectRef) : cloud ? undefined : autoProject(globalOpts);
|
|
19544
|
-
const hasAssignedFilter = Boolean(opts.assigned || opts.agentName);
|
|
19654
|
+
const hasAssignedFilter = Boolean(opts.assigned || opts.agentName || opts.inbox);
|
|
19545
19655
|
const hasExplicitProjectFilter = Boolean(globalOpts.project || opts.projectName);
|
|
19546
19656
|
const allowedSortFields = new Set(["updated", "created", "priority", "status"]);
|
|
19547
19657
|
if (opts.sort && !allowedSortFields.has(opts.sort)) {
|
|
@@ -19574,6 +19684,19 @@ function registerTaskCommands(program2) {
|
|
|
19574
19684
|
filter["priority"] = opts.priority;
|
|
19575
19685
|
if (opts.assigned)
|
|
19576
19686
|
filter["assigned_to"] = opts.assigned;
|
|
19687
|
+
if (opts.createdBy)
|
|
19688
|
+
filter["created_by"] = canonicalAgentRef(opts.createdBy);
|
|
19689
|
+
if (opts.notCreatedBy)
|
|
19690
|
+
filter["not_created_by"] = canonicalAgentRef(opts.notCreatedBy);
|
|
19691
|
+
if (opts.inbox) {
|
|
19692
|
+
const me = resolveCreatorIdentity(program2.opts().agent);
|
|
19693
|
+
if (!me.agent_id) {
|
|
19694
|
+
console.error(chalk2.red("--inbox needs an agent identity. Run `todos init <name>` or pass --agent <id>."));
|
|
19695
|
+
process.exit(1);
|
|
19696
|
+
}
|
|
19697
|
+
filter["assigned_to"] = me.agent_id;
|
|
19698
|
+
filter["not_created_by"] = me.agent_id;
|
|
19699
|
+
}
|
|
19577
19700
|
if (opts.tags)
|
|
19578
19701
|
filter["tags"] = opts.tags.split(",").map((t) => t.trim());
|
|
19579
19702
|
if (opts.projectName && !cloud) {
|
|
@@ -19598,7 +19721,32 @@ function registerTaskCommands(program2) {
|
|
|
19598
19721
|
}
|
|
19599
19722
|
filter["limit"] = parsedLimit;
|
|
19600
19723
|
}
|
|
19601
|
-
|
|
19724
|
+
const creatorFilterActive = Boolean(filter["created_by"] || filter["not_created_by"]);
|
|
19725
|
+
const requestedLimit = filter["limit"];
|
|
19726
|
+
const serverFilter = creatorFilterActive && cloud && requestedLimit !== undefined ? (() => {
|
|
19727
|
+
const { limit: _dropped, ...rest } = filter;
|
|
19728
|
+
return rest;
|
|
19729
|
+
})() : filter;
|
|
19730
|
+
let tasks = cloud ? await cloudListTasks(cloud, serverFilter) : listTasks(serverFilter);
|
|
19731
|
+
if (cloud && creatorFilterActive) {
|
|
19732
|
+
if (tasks.length > 0 && tasks.every((t) => !("created_by" in t))) {
|
|
19733
|
+
console.error(chalk2.yellow(`Warning: this server does not record task authorship, so the creator filter matched nothing to exclude.
|
|
19734
|
+
` + " Results are unfiltered. The API needs upgrading past the release that added created_by."));
|
|
19735
|
+
}
|
|
19736
|
+
const wantCreatedBy = filter["created_by"];
|
|
19737
|
+
const excludeCreatedBy = filter["not_created_by"];
|
|
19738
|
+
tasks = tasks.filter((t) => {
|
|
19739
|
+
const raw = t.created_by ?? null;
|
|
19740
|
+
const author = raw === null ? null : canonicalAgentRef(raw);
|
|
19741
|
+
if (wantCreatedBy && author !== canonicalAgentRef(wantCreatedBy))
|
|
19742
|
+
return false;
|
|
19743
|
+
if (excludeCreatedBy && author !== null && author === canonicalAgentRef(excludeCreatedBy))
|
|
19744
|
+
return false;
|
|
19745
|
+
return true;
|
|
19746
|
+
});
|
|
19747
|
+
if (requestedLimit !== undefined)
|
|
19748
|
+
tasks = tasks.slice(0, requestedLimit);
|
|
19749
|
+
}
|
|
19602
19750
|
if (opts.dueToday) {
|
|
19603
19751
|
const todayEnd = new Date;
|
|
19604
19752
|
todayEnd.setHours(23, 59, 59, 999);
|
|
@@ -20004,7 +20152,7 @@ ${chalk2.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
20004
20152
|
console.log(` ${chalk2.dim(h.created_at)} ${chalk2.bold(h.action)}${field}${change}${agent}`);
|
|
20005
20153
|
}
|
|
20006
20154
|
});
|
|
20007
|
-
program2.command("update <id>").description("Update a task").option("--title <text>", "New title").option("-d, --description <text>", "New description").option("-s, --status <status>", "New status").option("-p, --priority <priority>", "New priority").option("--assign <agent>", "Assign to agent").option("--tags <tags>", "New tags (comma-separated)").option("--tag <tags>", "New tags (alias for --tags)").option("--list <id>", "Move to a task list (UUID authoritative; project-scoped slug accepted)").option("--task-list <id>", "Move to a task list (alias for --list)").option("--clear-list", "Detach from its task list (reset task_list_id to null)").option("--project <id>", "Re-parent the task to another project (by ID, slug, or path); see also `todos move`").option("--working-dir <path>", "Repair the task's working_dir to a specific path (routing metadata)").option("--clear-working-dir", "Reset the task's working_dir to null (undo path for routing repairs)").option("--plan <id>", "Move to a plan").option("--clear-plan", "Remove from its current plan").option("--estimated <minutes>", "Estimated time in minutes").option("--sla-minutes <minutes>", "SLA minutes before unfinished work is escalated").option("--sla <minutes>", "Alias for --sla-minutes").option("--due <date>", "Due date (ISO string or YYYY-MM-DD), empty to clear").option("--recurrence <rule>", "Recurrence rule, empty to clear").option("--approval", "Require approval before completion").option("--clear-approval", "Remove the approval requirement").action(async (id, opts) => {
|
|
20155
|
+
program2.command("update <id>").description("Update a task").option("--title <text>", "New title").option("-d, --description <text>", "New description").option("-s, --status <status>", "New status").option("-p, --priority <priority>", "New priority").option("--assign <agent>", "Assign to agent").option("--set-agent <agent>", 'Repair the agent_id stamped on this row (use "" to clear it as unattributable)').option("--tags <tags>", "New tags (comma-separated)").option("--tag <tags>", "New tags (alias for --tags)").option("--list <id>", "Move to a task list (UUID authoritative; project-scoped slug accepted)").option("--task-list <id>", "Move to a task list (alias for --list)").option("--clear-list", "Detach from its task list (reset task_list_id to null)").option("--project <id>", "Re-parent the task to another project (by ID, slug, or path); see also `todos move`").option("--working-dir <path>", "Repair the task's working_dir to a specific path (routing metadata)").option("--clear-working-dir", "Reset the task's working_dir to null (undo path for routing repairs)").option("--plan <id>", "Move to a plan").option("--clear-plan", "Remove from its current plan").option("--estimated <minutes>", "Estimated time in minutes").option("--sla-minutes <minutes>", "SLA minutes before unfinished work is escalated").option("--sla <minutes>", "Alias for --sla-minutes").option("--due <date>", "Due date (ISO string or YYYY-MM-DD), empty to clear").option("--recurrence <rule>", "Recurrence rule, empty to clear").option("--approval", "Require approval before completion").option("--clear-approval", "Remove the approval requirement").action(async (id, opts) => {
|
|
20008
20156
|
const globalOpts = program2.opts();
|
|
20009
20157
|
opts.tags = opts.tags || opts.tag;
|
|
20010
20158
|
opts.list = opts.list || opts.taskList;
|
|
@@ -20042,6 +20190,7 @@ ${chalk2.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
20042
20190
|
status: parseStatus(opts.status),
|
|
20043
20191
|
priority: parsePriority(opts.priority),
|
|
20044
20192
|
assigned_to: opts.assign,
|
|
20193
|
+
agent_id: opts.setAgent !== undefined ? opts.setAgent === "" ? null : canonicalAgentRef(opts.setAgent) : undefined,
|
|
20045
20194
|
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
|
|
20046
20195
|
plan_id: plan?.id ?? (opts.clearPlan ? null : undefined),
|
|
20047
20196
|
...reparent2,
|
|
@@ -20083,6 +20232,7 @@ ${chalk2.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
20083
20232
|
status: parseStatus(opts.status),
|
|
20084
20233
|
priority: parsePriority(opts.priority),
|
|
20085
20234
|
assigned_to: opts.assign,
|
|
20235
|
+
agent_id: opts.setAgent !== undefined ? opts.setAgent === "" ? null : canonicalAgentRef(opts.setAgent) : undefined,
|
|
20086
20236
|
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
|
|
20087
20237
|
plan_id: planId,
|
|
20088
20238
|
...reparent,
|
|
@@ -20482,14 +20632,15 @@ var init_task_commands = __esm(() => {
|
|
|
20482
20632
|
init_tasks();
|
|
20483
20633
|
init_task_lists();
|
|
20484
20634
|
init_cloud_router();
|
|
20635
|
+
init_creator_identity();
|
|
20485
20636
|
init_helpers();
|
|
20486
20637
|
init_output_redaction();
|
|
20487
20638
|
init_types();
|
|
20488
20639
|
});
|
|
20489
20640
|
|
|
20490
20641
|
// src/lib/plan-artifacts.ts
|
|
20491
|
-
import { existsSync as
|
|
20492
|
-
import { join as
|
|
20642
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
20643
|
+
import { join as join8, resolve as resolve10 } from "path";
|
|
20493
20644
|
function assertSafePathSegment(value, label) {
|
|
20494
20645
|
const trimmed = value.trim();
|
|
20495
20646
|
if (!trimmed || trimmed === "." || trimmed === ".." || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
@@ -20550,7 +20701,7 @@ function resolvePlanArtifactPaths(input) {
|
|
|
20550
20701
|
const project = resolvePlanArtifactProject(input);
|
|
20551
20702
|
const projectId = assertSafePathSegment(project.id, "project id");
|
|
20552
20703
|
const projectRoot = resolve10(project.path);
|
|
20553
|
-
const directory =
|
|
20704
|
+
const directory = join8(projectRoot, ".hasna", "todos", "plans", projectId);
|
|
20554
20705
|
const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
|
|
20555
20706
|
const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
|
|
20556
20707
|
const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
|
|
@@ -20558,7 +20709,7 @@ function resolvePlanArtifactPaths(input) {
|
|
|
20558
20709
|
project_id: project.id,
|
|
20559
20710
|
project_root: projectRoot,
|
|
20560
20711
|
directory,
|
|
20561
|
-
file_path: fileName ?
|
|
20712
|
+
file_path: fileName ? join8(directory, fileName) : directory
|
|
20562
20713
|
};
|
|
20563
20714
|
}
|
|
20564
20715
|
function resolvePlanArtifactCandidatePaths(plan, db) {
|
|
@@ -20724,7 +20875,7 @@ function readPlanArtifact(plan, db) {
|
|
|
20724
20875
|
return null;
|
|
20725
20876
|
const d = db || getDatabase();
|
|
20726
20877
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
20727
|
-
const path =
|
|
20878
|
+
const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
20728
20879
|
if (!path)
|
|
20729
20880
|
return null;
|
|
20730
20881
|
const markdown = readFileSync4(path, "utf8");
|
|
@@ -20739,7 +20890,7 @@ function inspectPlanArtifact(plan, db) {
|
|
|
20739
20890
|
return null;
|
|
20740
20891
|
const d = db || getDatabase();
|
|
20741
20892
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
20742
|
-
const path =
|
|
20893
|
+
const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
20743
20894
|
if (!path) {
|
|
20744
20895
|
return {
|
|
20745
20896
|
path: paths.primary.file_path,
|
|
@@ -20819,7 +20970,7 @@ __export(exports_builtin_templates, {
|
|
|
20819
20970
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
20820
20971
|
});
|
|
20821
20972
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
20822
|
-
import { join as
|
|
20973
|
+
import { join as join9 } from "path";
|
|
20823
20974
|
function templateMetadata(template) {
|
|
20824
20975
|
return {
|
|
20825
20976
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -20878,7 +21029,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
20878
21029
|
mkdirSync7(directory, { recursive: true });
|
|
20879
21030
|
const files = [];
|
|
20880
21031
|
for (const entry of exportBuiltinTemplateFiles()) {
|
|
20881
|
-
const path =
|
|
21032
|
+
const path = join9(directory, entry.filename);
|
|
20882
21033
|
writeFileSync5(path, `${JSON.stringify(entry.template, null, 2)}
|
|
20883
21034
|
`, "utf-8");
|
|
20884
21035
|
files.push(path);
|
|
@@ -22650,16 +22801,16 @@ var init_saved_search_views = __esm(() => {
|
|
|
22650
22801
|
});
|
|
22651
22802
|
|
|
22652
22803
|
// src/lib/claude-tasks.ts
|
|
22653
|
-
import { existsSync as
|
|
22654
|
-
import { join as
|
|
22804
|
+
import { existsSync as existsSync11, readFileSync as readFileSync5, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
22805
|
+
import { join as join10 } from "path";
|
|
22655
22806
|
function getTaskListDir(taskListId) {
|
|
22656
|
-
return
|
|
22807
|
+
return join10(HOME, ".claude", "tasks", taskListId);
|
|
22657
22808
|
}
|
|
22658
22809
|
function readClaudeTask(dir, filename) {
|
|
22659
|
-
return readJsonFile(
|
|
22810
|
+
return readJsonFile(join10(dir, filename));
|
|
22660
22811
|
}
|
|
22661
22812
|
function writeClaudeTask(dir, task) {
|
|
22662
|
-
writeJsonFile(
|
|
22813
|
+
writeJsonFile(join10(dir, `${task.id}.json`), task);
|
|
22663
22814
|
}
|
|
22664
22815
|
function toClaudeStatus(status) {
|
|
22665
22816
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -22671,14 +22822,14 @@ function toSqliteStatus(status) {
|
|
|
22671
22822
|
return status;
|
|
22672
22823
|
}
|
|
22673
22824
|
function readPrefixCounter(dir) {
|
|
22674
|
-
const path =
|
|
22675
|
-
if (!
|
|
22825
|
+
const path = join10(dir, ".prefix-counter");
|
|
22826
|
+
if (!existsSync11(path))
|
|
22676
22827
|
return 0;
|
|
22677
22828
|
const val = parseInt(readFileSync5(path, "utf-8").trim(), 10);
|
|
22678
22829
|
return isNaN(val) ? 0 : val;
|
|
22679
22830
|
}
|
|
22680
22831
|
function writePrefixCounter(dir, value) {
|
|
22681
|
-
writeFileSync6(
|
|
22832
|
+
writeFileSync6(join10(dir, ".prefix-counter"), String(value));
|
|
22682
22833
|
}
|
|
22683
22834
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
22684
22835
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -22705,7 +22856,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
22705
22856
|
}
|
|
22706
22857
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
22707
22858
|
const dir = getTaskListDir(taskListId);
|
|
22708
|
-
if (!
|
|
22859
|
+
if (!existsSync11(dir))
|
|
22709
22860
|
ensureDir(dir);
|
|
22710
22861
|
const filter = {};
|
|
22711
22862
|
if (projectId)
|
|
@@ -22714,7 +22865,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
22714
22865
|
const existingByTodosId = new Map;
|
|
22715
22866
|
const files = listJsonFiles(dir);
|
|
22716
22867
|
for (const f of files) {
|
|
22717
|
-
const path =
|
|
22868
|
+
const path = join10(dir, f);
|
|
22718
22869
|
const ct = readClaudeTask(dir, f);
|
|
22719
22870
|
if (ct?.metadata?.["todos_id"]) {
|
|
22720
22871
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -22801,7 +22952,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
22801
22952
|
}
|
|
22802
22953
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
22803
22954
|
const dir = getTaskListDir(taskListId);
|
|
22804
|
-
if (!
|
|
22955
|
+
if (!existsSync11(dir)) {
|
|
22805
22956
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
22806
22957
|
}
|
|
22807
22958
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -22821,7 +22972,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
22821
22972
|
}
|
|
22822
22973
|
for (const f of files) {
|
|
22823
22974
|
try {
|
|
22824
|
-
const filePath =
|
|
22975
|
+
const filePath = join10(dir, f);
|
|
22825
22976
|
const ct = readClaudeTask(dir, f);
|
|
22826
22977
|
if (!ct)
|
|
22827
22978
|
continue;
|
|
@@ -22894,20 +23045,20 @@ var init_claude_tasks = __esm(() => {
|
|
|
22894
23045
|
});
|
|
22895
23046
|
|
|
22896
23047
|
// src/lib/agent-tasks.ts
|
|
22897
|
-
import { existsSync as
|
|
22898
|
-
import { join as
|
|
23048
|
+
import { existsSync as existsSync12 } from "fs";
|
|
23049
|
+
import { join as join11 } from "path";
|
|
22899
23050
|
function agentBaseDir(agent) {
|
|
22900
23051
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
22901
|
-
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
23052
|
+
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join11(getTodosGlobalDir(), "agents");
|
|
22902
23053
|
}
|
|
22903
23054
|
function getTaskListDir2(agent, taskListId) {
|
|
22904
|
-
return
|
|
23055
|
+
return join11(agentBaseDir(agent), agent, taskListId);
|
|
22905
23056
|
}
|
|
22906
23057
|
function readAgentTask(dir, filename) {
|
|
22907
|
-
return readJsonFile(
|
|
23058
|
+
return readJsonFile(join11(dir, filename));
|
|
22908
23059
|
}
|
|
22909
23060
|
function writeAgentTask(dir, task) {
|
|
22910
|
-
writeJsonFile(
|
|
23061
|
+
writeJsonFile(join11(dir, `${task.id}.json`), task);
|
|
22911
23062
|
}
|
|
22912
23063
|
function taskToAgentTask(task, externalId, existingMeta) {
|
|
22913
23064
|
return {
|
|
@@ -22932,7 +23083,7 @@ function metadataKey(agent) {
|
|
|
22932
23083
|
}
|
|
22933
23084
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
22934
23085
|
const dir = getTaskListDir2(agent, taskListId);
|
|
22935
|
-
if (!
|
|
23086
|
+
if (!existsSync12(dir))
|
|
22936
23087
|
ensureDir(dir);
|
|
22937
23088
|
const filter = {};
|
|
22938
23089
|
if (projectId)
|
|
@@ -22941,7 +23092,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
22941
23092
|
const existingByTodosId = new Map;
|
|
22942
23093
|
const files = listJsonFiles(dir);
|
|
22943
23094
|
for (const f of files) {
|
|
22944
|
-
const path =
|
|
23095
|
+
const path = join11(dir, f);
|
|
22945
23096
|
const at = readAgentTask(dir, f);
|
|
22946
23097
|
if (at?.metadata?.["todos_id"]) {
|
|
22947
23098
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -23015,7 +23166,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
23015
23166
|
}
|
|
23016
23167
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
23017
23168
|
const dir = getTaskListDir2(agent, taskListId);
|
|
23018
|
-
if (!
|
|
23169
|
+
if (!existsSync12(dir)) {
|
|
23019
23170
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
23020
23171
|
}
|
|
23021
23172
|
const files = listJsonFiles(dir);
|
|
@@ -23034,7 +23185,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
23034
23185
|
}
|
|
23035
23186
|
for (const f of files) {
|
|
23036
23187
|
try {
|
|
23037
|
-
const filePath =
|
|
23188
|
+
const filePath = join11(dir, f);
|
|
23038
23189
|
const at = readAgentTask(dir, f);
|
|
23039
23190
|
if (!at)
|
|
23040
23191
|
continue;
|
|
@@ -23187,7 +23338,7 @@ __export(exports_project_bootstrap, {
|
|
|
23187
23338
|
discoverProjectWorkspace: () => discoverProjectWorkspace,
|
|
23188
23339
|
bootstrapProject: () => bootstrapProject
|
|
23189
23340
|
});
|
|
23190
|
-
import { existsSync as
|
|
23341
|
+
import { existsSync as existsSync13, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
23191
23342
|
import { basename as basename4, dirname as dirname6, resolve as resolve11 } from "path";
|
|
23192
23343
|
function safeStat(path) {
|
|
23193
23344
|
try {
|
|
@@ -23206,7 +23357,7 @@ function canonicalPath(input) {
|
|
|
23206
23357
|
function findUp(start, marker) {
|
|
23207
23358
|
let current = canonicalPath(start);
|
|
23208
23359
|
while (true) {
|
|
23209
|
-
if (
|
|
23360
|
+
if (existsSync13(resolve11(current, marker)))
|
|
23210
23361
|
return current;
|
|
23211
23362
|
const parent = dirname6(current);
|
|
23212
23363
|
if (parent === current)
|
|
@@ -23218,7 +23369,7 @@ function readPackageJson(path) {
|
|
|
23218
23369
|
if (!path)
|
|
23219
23370
|
return null;
|
|
23220
23371
|
const file = resolve11(path, "package.json");
|
|
23221
|
-
if (!
|
|
23372
|
+
if (!existsSync13(file))
|
|
23222
23373
|
return null;
|
|
23223
23374
|
try {
|
|
23224
23375
|
const parsed = JSON.parse(readFileSync6(file, "utf-8"));
|
|
@@ -23240,7 +23391,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
23240
23391
|
if (rootPackage?.workspaces)
|
|
23241
23392
|
markers.push("package.json#workspaces");
|
|
23242
23393
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
23243
|
-
if (
|
|
23394
|
+
if (existsSync13(resolve11(root, marker)))
|
|
23244
23395
|
markers.push(marker);
|
|
23245
23396
|
}
|
|
23246
23397
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -23574,9 +23725,9 @@ __export(exports_extract, {
|
|
|
23574
23725
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
23575
23726
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
23576
23727
|
});
|
|
23577
|
-
import { existsSync as
|
|
23728
|
+
import { existsSync as existsSync14, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
|
|
23578
23729
|
import { createHash as createHash4 } from "crypto";
|
|
23579
|
-
import { relative as relative3, resolve as resolve12, join as
|
|
23730
|
+
import { relative as relative3, resolve as resolve12, join as join12 } from "path";
|
|
23580
23731
|
function stableHash(value) {
|
|
23581
23732
|
return createHash4("sha256").update(value).digest("hex");
|
|
23582
23733
|
}
|
|
@@ -23585,8 +23736,8 @@ function normalizePathForMatch(value) {
|
|
|
23585
23736
|
}
|
|
23586
23737
|
function readGitignorePatterns(basePath) {
|
|
23587
23738
|
const root = statSync5(basePath).isFile() ? resolve12(basePath, "..") : basePath;
|
|
23588
|
-
const gitignorePath =
|
|
23589
|
-
if (!
|
|
23739
|
+
const gitignorePath = join12(root, ".gitignore");
|
|
23740
|
+
if (!existsSync14(gitignorePath))
|
|
23590
23741
|
return [];
|
|
23591
23742
|
try {
|
|
23592
23743
|
return readFileSync7(gitignorePath, "utf-8").split(`
|
|
@@ -23728,7 +23879,7 @@ function buildCodebaseIndex(options) {
|
|
|
23728
23879
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
23729
23880
|
const indexed = [];
|
|
23730
23881
|
for (const file of files) {
|
|
23731
|
-
const fullPath = statSync5(basePath).isFile() ? basePath :
|
|
23882
|
+
const fullPath = statSync5(basePath).isFile() ? basePath : join12(basePath, file);
|
|
23732
23883
|
try {
|
|
23733
23884
|
const source = readFileSync7(fullPath, "utf-8");
|
|
23734
23885
|
const relPath = statSync5(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
|
|
@@ -23759,7 +23910,7 @@ function extractTodos(options, db) {
|
|
|
23759
23910
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
23760
23911
|
const allComments = [];
|
|
23761
23912
|
for (const file of files) {
|
|
23762
|
-
const fullPath = statSync5(basePath).isFile() ? basePath :
|
|
23913
|
+
const fullPath = statSync5(basePath).isFile() ? basePath : join12(basePath, file);
|
|
23763
23914
|
try {
|
|
23764
23915
|
const source = readFileSync7(fullPath, "utf-8");
|
|
23765
23916
|
const relPath = statSync5(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
|
|
@@ -26810,8 +26961,16 @@ function resolveCloudAgentByNameOrId(agents, nameOrId) {
|
|
|
26810
26961
|
return null;
|
|
26811
26962
|
return matches.reduce((freshest, candidate) => new Date(candidate.last_seen_at).getTime() > new Date(freshest.last_seen_at).getTime() ? candidate : freshest);
|
|
26812
26963
|
}
|
|
26964
|
+
function clearIdentityIfMine(agentId, agentName) {
|
|
26965
|
+
const persisted = readPersistedIdentity();
|
|
26966
|
+
if (!persisted)
|
|
26967
|
+
return;
|
|
26968
|
+
if (persisted.agent_id === agentId || agentName && persisted.agent_name === agentName) {
|
|
26969
|
+
clearPersistedIdentity();
|
|
26970
|
+
}
|
|
26971
|
+
}
|
|
26813
26972
|
function registerAgentCommands(program2) {
|
|
26814
|
-
program2.command("init <name>").alias("register").description("Register an agent and get a short UUID (alias: register)").option("-d, --description <text>", "Agent description").action(async (name, opts) => {
|
|
26973
|
+
program2.command("init <name>").alias("register").description("Register an agent and get a short UUID (alias: register)").option("-d, --description <text>", "Agent description").option("--force", "Take over the machine-wide persisted identity even if another session holds it").action(async (name, opts) => {
|
|
26815
26974
|
const globalOpts = program2.opts();
|
|
26816
26975
|
try {
|
|
26817
26976
|
const cloud = getTodosCloudClient();
|
|
@@ -26821,14 +26980,25 @@ function registerAgentCommands(program2) {
|
|
|
26821
26980
|
console.error(chalk5.red("CONFLICT:"), result.message);
|
|
26822
26981
|
process.exit(1);
|
|
26823
26982
|
}
|
|
26983
|
+
const collision = detectIdentityCollision(result.id, result.name);
|
|
26984
|
+
if (collision && !opts.force) {
|
|
26985
|
+
const held = collision.existing.agent_name || collision.existing.agent_id;
|
|
26986
|
+
console.error(chalk5.red(`This machine already has a persisted todos identity: ${held} (registered ${collision.existing.registered_at}).`));
|
|
26987
|
+
console.error(chalk5.yellow(`Overwriting it would make that session attribute its tasks to you.
|
|
26988
|
+
` + `For a concurrent session, set a per-process identity instead \u2014 it outranks the file and cannot collide:
|
|
26989
|
+
` + ` export TODOS_AGENT_ID=${result.name}
|
|
26990
|
+
Or pass --force to take over the machine-wide identity.`));
|
|
26991
|
+
process.exit(2);
|
|
26992
|
+
}
|
|
26993
|
+
persistIdentity({ agent_id: result.id, agent_name: result.name, ...globalOpts.session ? { session_id: globalOpts.session } : {} });
|
|
26824
26994
|
if (globalOpts.json) {
|
|
26825
|
-
output(result, true);
|
|
26995
|
+
output({ ...result, identity_persisted: true }, true);
|
|
26826
26996
|
} else {
|
|
26827
26997
|
console.log(chalk5.green("Agent registered:"));
|
|
26828
26998
|
console.log(` ${chalk5.dim("ID:")} ${result.id}`);
|
|
26829
26999
|
console.log(` ${chalk5.dim("Name:")} ${result.name}`);
|
|
26830
27000
|
console.log(`
|
|
26831
|
-
|
|
27001
|
+
${chalk5.dim("Identity saved \u2014 later commands attribute to this agent automatically.")}`);
|
|
26832
27002
|
}
|
|
26833
27003
|
} catch (e) {
|
|
26834
27004
|
handleError(e);
|
|
@@ -26885,6 +27055,7 @@ Use ${chalk5.cyan(`--agent ${result.id}`)} on future commands.`);
|
|
|
26885
27055
|
if (!result.released) {
|
|
26886
27056
|
handleError(new Error("Release denied: session_id does not match agent's current session."));
|
|
26887
27057
|
}
|
|
27058
|
+
clearIdentityIfMine(result.agent.id, result.agent.name);
|
|
26888
27059
|
if (globalOpts.json) {
|
|
26889
27060
|
console.log(JSON.stringify({ agent_id: result.agent.id, name: result.agent.name, released: true }));
|
|
26890
27061
|
} else {
|
|
@@ -26901,6 +27072,7 @@ Use ${chalk5.cyan(`--agent ${result.id}`)} on future commands.`);
|
|
|
26901
27072
|
if (!released) {
|
|
26902
27073
|
handleError(new Error("Release denied: session_id does not match agent's current session."));
|
|
26903
27074
|
}
|
|
27075
|
+
clearIdentityIfMine(a.id, a.name);
|
|
26904
27076
|
if (globalOpts.json) {
|
|
26905
27077
|
console.log(JSON.stringify({ agent_id: a.id, name: a.name, released: true }));
|
|
26906
27078
|
} else {
|
|
@@ -27241,6 +27413,7 @@ var init_agent_commands = __esm(() => {
|
|
|
27241
27413
|
init_task_lists();
|
|
27242
27414
|
init_tasks();
|
|
27243
27415
|
init_helpers();
|
|
27416
|
+
init_creator_identity();
|
|
27244
27417
|
init_cloud_router();
|
|
27245
27418
|
});
|
|
27246
27419
|
|
|
@@ -27283,8 +27456,8 @@ async function findFreePort(start) {
|
|
|
27283
27456
|
var DEFAULT_PORT = 19427;
|
|
27284
27457
|
|
|
27285
27458
|
// src/lib/db-backup.ts
|
|
27286
|
-
import { existsSync as
|
|
27287
|
-
import { dirname as dirname7, join as
|
|
27459
|
+
import { existsSync as existsSync15, copyFileSync, mkdirSync as mkdirSync8, readFileSync as readFileSync8, renameSync, statSync as statSync6, writeFileSync as writeFileSync7, unlinkSync } from "fs";
|
|
27460
|
+
import { dirname as dirname7, join as join13, resolve as resolve14 } from "path";
|
|
27288
27461
|
import { Database as Database2 } from "bun:sqlite";
|
|
27289
27462
|
function resolveDbPath(dbPath) {
|
|
27290
27463
|
if (dbPath)
|
|
@@ -27300,7 +27473,7 @@ function resolveDbPath(dbPath) {
|
|
|
27300
27473
|
}
|
|
27301
27474
|
function backupDatabase(outputPath, sourcePath) {
|
|
27302
27475
|
const source = resolveDbPath(sourcePath);
|
|
27303
|
-
if (!
|
|
27476
|
+
if (!existsSync15(source))
|
|
27304
27477
|
throw new Error(`Database not found: ${source}`);
|
|
27305
27478
|
mkdirSync8(dirname7(outputPath), { recursive: true });
|
|
27306
27479
|
closeDatabase();
|
|
@@ -27325,7 +27498,7 @@ function backupDatabase(outputPath, sourcePath) {
|
|
|
27325
27498
|
function checkDatabaseIntegrity(dbPath) {
|
|
27326
27499
|
const path = dbPath ? resolve14(dbPath) : resolveDbPath();
|
|
27327
27500
|
const errors = [];
|
|
27328
|
-
if (!
|
|
27501
|
+
if (!existsSync15(path)) {
|
|
27329
27502
|
return {
|
|
27330
27503
|
schema_version: DB_BACKUP_SCHEMA,
|
|
27331
27504
|
path,
|
|
@@ -27390,7 +27563,7 @@ function checkDatabaseIntegrity(dbPath) {
|
|
|
27390
27563
|
function defaultBackupPath(dbPath) {
|
|
27391
27564
|
const base = dbPath ? dirname7(resolve14(dbPath)) : dirname7(resolveDbPath());
|
|
27392
27565
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
27393
|
-
return
|
|
27566
|
+
return join13(base, "backups", `todos-${stamp}.db`);
|
|
27394
27567
|
}
|
|
27395
27568
|
var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
|
|
27396
27569
|
var init_db_backup = __esm(() => {
|
|
@@ -27407,7 +27580,7 @@ __export(exports_evidence_redaction, {
|
|
|
27407
27580
|
TODOS_EVIDENCE_REDACTION_CONFIRM: () => TODOS_EVIDENCE_REDACTION_CONFIRM
|
|
27408
27581
|
});
|
|
27409
27582
|
import { chmodSync } from "fs";
|
|
27410
|
-
import { join as
|
|
27583
|
+
import { join as join14 } from "path";
|
|
27411
27584
|
function unique4(values) {
|
|
27412
27585
|
return Array.from(new Set((values ?? []).map((value) => value.trim()).filter(Boolean)));
|
|
27413
27586
|
}
|
|
@@ -27754,7 +27927,7 @@ function redactEvidenceRows(options, db) {
|
|
|
27754
27927
|
}
|
|
27755
27928
|
function defaultEvidenceRedactionBackupPath(dbPath) {
|
|
27756
27929
|
const base = defaultBackupPath(dbPath);
|
|
27757
|
-
return
|
|
27930
|
+
return join14(base.replace(/\.db$/, ""), "pre-redaction.db");
|
|
27758
27931
|
}
|
|
27759
27932
|
var TODOS_EVIDENCE_REDACTION_SCHEMA = "todos.evidence_redaction.v1", TODOS_EVIDENCE_REDACTION_CONFIRM = "REDACT_TODOS_EVIDENCE";
|
|
27760
27933
|
var init_evidence_redaction = __esm(() => {
|
|
@@ -27770,7 +27943,7 @@ __export(exports_retention_cleanup, {
|
|
|
27770
27943
|
applyRetentionCleanup: () => applyRetentionCleanup,
|
|
27771
27944
|
RETENTION_CLEANUP_CONFIRMATION: () => RETENTION_CLEANUP_CONFIRMATION
|
|
27772
27945
|
});
|
|
27773
|
-
import { existsSync as
|
|
27946
|
+
import { existsSync as existsSync16, unlinkSync as unlinkSync2 } from "fs";
|
|
27774
27947
|
function normalizeScopes(scopes) {
|
|
27775
27948
|
if (!scopes || scopes.length === 0)
|
|
27776
27949
|
return [...ALL_SCOPES];
|
|
@@ -27973,7 +28146,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
27973
28146
|
for (const artifact of report.candidates.artifact_files) {
|
|
27974
28147
|
try {
|
|
27975
28148
|
const path = artifactStorePath(artifact.relative_path);
|
|
27976
|
-
if (!
|
|
28149
|
+
if (!existsSync16(path)) {
|
|
27977
28150
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
27978
28151
|
continue;
|
|
27979
28152
|
}
|
|
@@ -28649,8 +28822,8 @@ __export(exports_local_extensions, {
|
|
|
28649
28822
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
28650
28823
|
});
|
|
28651
28824
|
import { createHash as createHash6, createVerify } from "crypto";
|
|
28652
|
-
import { existsSync as
|
|
28653
|
-
import { basename as basename6, join as
|
|
28825
|
+
import { existsSync as existsSync17, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync7 } from "fs";
|
|
28826
|
+
import { basename as basename6, join as join15, resolve as resolve15 } from "path";
|
|
28654
28827
|
function isObject(value) {
|
|
28655
28828
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
28656
28829
|
}
|
|
@@ -28909,10 +29082,10 @@ function verifyExtensionSignature(input) {
|
|
|
28909
29082
|
}
|
|
28910
29083
|
function inspectExtensionSource(source2) {
|
|
28911
29084
|
const resolved = resolve15(source2);
|
|
28912
|
-
if (!
|
|
29085
|
+
if (!existsSync17(resolved))
|
|
28913
29086
|
throw new Error(`extension source not found: ${source2}`);
|
|
28914
29087
|
const stat = statSync7(resolved);
|
|
28915
|
-
const manifestPath = stat.isDirectory() ? [
|
|
29088
|
+
const manifestPath = stat.isDirectory() ? [join15(resolved, "todos.extension.json"), join15(resolved, "extension.json")].find(existsSync17) : resolved;
|
|
28916
29089
|
if (!manifestPath)
|
|
28917
29090
|
throw new Error(`extension directory ${source2} is missing todos.extension.json`);
|
|
28918
29091
|
const raw = readFileSync9(manifestPath);
|
|
@@ -29008,20 +29181,20 @@ function projectExtensionSources(projectPath) {
|
|
|
29008
29181
|
return [];
|
|
29009
29182
|
const root = resolve15(projectPath);
|
|
29010
29183
|
const candidates = [
|
|
29011
|
-
|
|
29012
|
-
|
|
29184
|
+
join15(root, "todos.extension.json"),
|
|
29185
|
+
join15(root, ".todos", "todos.extension.json")
|
|
29013
29186
|
];
|
|
29014
|
-
const extensionDir =
|
|
29015
|
-
if (
|
|
29187
|
+
const extensionDir = join15(root, ".todos", "extensions");
|
|
29188
|
+
if (existsSync17(extensionDir)) {
|
|
29016
29189
|
for (const entry of readdirSync3(extensionDir)) {
|
|
29017
29190
|
if (entry.startsWith("."))
|
|
29018
29191
|
continue;
|
|
29019
|
-
const full =
|
|
29192
|
+
const full = join15(extensionDir, entry);
|
|
29020
29193
|
if (statSync7(full).isDirectory() || entry.endsWith(".json"))
|
|
29021
29194
|
candidates.push(full);
|
|
29022
29195
|
}
|
|
29023
29196
|
}
|
|
29024
|
-
return candidates.filter(
|
|
29197
|
+
return candidates.filter(existsSync17);
|
|
29025
29198
|
}
|
|
29026
29199
|
function discoverLocalExtensions(options = {}) {
|
|
29027
29200
|
const config = loadConfig();
|
|
@@ -31109,6 +31282,10 @@ class PostgresJsonRecordStore {
|
|
|
31109
31282
|
conds.push(`payload->>'assigned_to' = ${p(filter.assigned_to)}`);
|
|
31110
31283
|
if (filter.agent_id !== undefined)
|
|
31111
31284
|
conds.push(`payload->>'agent_id' = ${p(filter.agent_id)}`);
|
|
31285
|
+
if (filter.created_by !== undefined)
|
|
31286
|
+
conds.push(`LOWER(payload->>'created_by') = LOWER(${p(filter.created_by)})`);
|
|
31287
|
+
if (filter.not_created_by !== undefined)
|
|
31288
|
+
conds.push(`(payload->>'created_by' IS NULL OR LOWER(payload->>'created_by') <> LOWER(${p(filter.not_created_by)}))`);
|
|
31112
31289
|
if (filter.session_id !== undefined)
|
|
31113
31290
|
conds.push(`payload->>'session_id' = ${p(filter.session_id)}`);
|
|
31114
31291
|
if (filter.tags?.length) {
|
|
@@ -31622,7 +31799,7 @@ async function createTask2(input, store, context) {
|
|
|
31622
31799
|
description: input.description ?? null,
|
|
31623
31800
|
status: input.status ?? "pending",
|
|
31624
31801
|
priority: input.priority ?? "medium",
|
|
31625
|
-
agent_id: input.agent_id ?? null,
|
|
31802
|
+
agent_id: input.agent_id ?? context?.agentId ?? null,
|
|
31626
31803
|
assigned_to: input.assigned_to ?? null,
|
|
31627
31804
|
session_id: input.session_id ?? context?.sessionId ?? null,
|
|
31628
31805
|
working_dir: input.working_dir ?? null,
|
|
@@ -31647,7 +31824,8 @@ async function createTask2(input, store, context) {
|
|
|
31647
31824
|
confidence: input.confidence ?? null,
|
|
31648
31825
|
reason: input.reason ?? null,
|
|
31649
31826
|
spawned_from_session: input.spawned_from_session ?? null,
|
|
31650
|
-
assigned_by: input.assigned_by ?? null,
|
|
31827
|
+
assigned_by: input.assigned_by ?? input.agent_id ?? context?.agentId ?? null,
|
|
31828
|
+
created_by: input.created_by ?? input.agent_id ?? context?.agentId ?? null,
|
|
31651
31829
|
assigned_from_project: input.assigned_from_project ?? null,
|
|
31652
31830
|
task_type: input.task_type ?? null,
|
|
31653
31831
|
cost_tokens: 0,
|
|
@@ -31684,7 +31862,8 @@ async function updateTask2(id, input, store) {
|
|
|
31684
31862
|
tags: input.tags ?? existing.tags,
|
|
31685
31863
|
metadata: input.metadata ?? existing.metadata,
|
|
31686
31864
|
requires_approval: input.requires_approval ?? existing.requires_approval,
|
|
31687
|
-
task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id
|
|
31865
|
+
task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id,
|
|
31866
|
+
created_by: existing.created_by
|
|
31688
31867
|
};
|
|
31689
31868
|
await store.upsert("tasks", task);
|
|
31690
31869
|
return task;
|
|
@@ -33412,8 +33591,8 @@ var exports_doctor = {};
|
|
|
33412
33591
|
__export(exports_doctor, {
|
|
33413
33592
|
runTodosDoctor: () => runTodosDoctor
|
|
33414
33593
|
});
|
|
33415
|
-
import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, existsSync as
|
|
33416
|
-
import { basename as basename7, dirname as dirname8, join as
|
|
33594
|
+
import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, existsSync as existsSync18, mkdirSync as mkdirSync9, statSync as statSync8 } from "fs";
|
|
33595
|
+
import { basename as basename7, dirname as dirname8, join as join16 } from "path";
|
|
33417
33596
|
function tableExists3(db, table) {
|
|
33418
33597
|
return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
|
|
33419
33598
|
}
|
|
@@ -33507,7 +33686,7 @@ function findMissingProjectRoots(db) {
|
|
|
33507
33686
|
continue;
|
|
33508
33687
|
if (!row.path.startsWith("/"))
|
|
33509
33688
|
continue;
|
|
33510
|
-
if (!
|
|
33689
|
+
if (!existsSync18(row.path))
|
|
33511
33690
|
missing++;
|
|
33512
33691
|
}
|
|
33513
33692
|
return missing;
|
|
@@ -33567,16 +33746,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
33567
33746
|
function createBackup(dbPath) {
|
|
33568
33747
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
33569
33748
|
return;
|
|
33570
|
-
if (!
|
|
33749
|
+
if (!existsSync18(dbPath))
|
|
33571
33750
|
return;
|
|
33572
33751
|
const stamp = now().replace(/[:.]/g, "-");
|
|
33573
|
-
const backupDir =
|
|
33752
|
+
const backupDir = join16(dirname8(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
|
|
33574
33753
|
const files = [];
|
|
33575
33754
|
mkdirSync9(backupDir, { recursive: true });
|
|
33576
33755
|
for (const source2 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
33577
|
-
if (!
|
|
33756
|
+
if (!existsSync18(source2))
|
|
33578
33757
|
continue;
|
|
33579
|
-
const target =
|
|
33758
|
+
const target = join16(backupDir, basename7(source2));
|
|
33580
33759
|
copyFileSync2(source2, target);
|
|
33581
33760
|
files.push(target);
|
|
33582
33761
|
}
|
|
@@ -33835,7 +34014,7 @@ var init_doctor = __esm(() => {
|
|
|
33835
34014
|
});
|
|
33836
34015
|
|
|
33837
34016
|
// src/server/routes.ts
|
|
33838
|
-
import { join as
|
|
34017
|
+
import { join as join17, resolve as resolve17, sep as sep4 } from "path";
|
|
33839
34018
|
function parseFieldsParam(url) {
|
|
33840
34019
|
const fieldsParam = url.searchParams.get("fields");
|
|
33841
34020
|
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
@@ -34016,11 +34195,15 @@ async function handleCreateTask(req, ctx, json2, taskToSummary2) {
|
|
|
34016
34195
|
const body = await req.json();
|
|
34017
34196
|
if (!body.title)
|
|
34018
34197
|
return json2({ error: "Missing 'title'" }, 400);
|
|
34198
|
+
const createdBy = body.created_by ?? body.agent_id ?? "dashboard";
|
|
34019
34199
|
const task = createTask({
|
|
34020
34200
|
title: body.title,
|
|
34021
34201
|
description: body.description,
|
|
34022
34202
|
priority: body.priority,
|
|
34023
|
-
project_id: body.project_id
|
|
34203
|
+
project_id: body.project_id,
|
|
34204
|
+
agent_id: body.agent_id ?? createdBy,
|
|
34205
|
+
created_by: createdBy,
|
|
34206
|
+
...body.assigned_to ? { assigned_to: body.assigned_to } : {}
|
|
34024
34207
|
});
|
|
34025
34208
|
ctx.broadcastEvent({ type: "task", task_id: task.id, action: "created", agent_id: task.agent_id, project_id: task.project_id });
|
|
34026
34209
|
return json2(taskToSummary2(task), 201);
|
|
@@ -34626,7 +34809,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
|
|
|
34626
34809
|
if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
|
|
34627
34810
|
return null;
|
|
34628
34811
|
if (path !== "/") {
|
|
34629
|
-
const filePath =
|
|
34812
|
+
const filePath = join17(ctx.dashboardDir, path);
|
|
34630
34813
|
const resolvedFile = resolve17(filePath);
|
|
34631
34814
|
const resolvedBase = resolve17(ctx.dashboardDir);
|
|
34632
34815
|
if (!resolvedFile.startsWith(resolvedBase + sep4) && resolvedFile !== resolvedBase) {
|
|
@@ -34636,7 +34819,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
|
|
|
34636
34819
|
if (res2)
|
|
34637
34820
|
return res2;
|
|
34638
34821
|
}
|
|
34639
|
-
const indexPath =
|
|
34822
|
+
const indexPath = join17(ctx.dashboardDir, "index.html");
|
|
34640
34823
|
const res = serveStaticFile2(indexPath);
|
|
34641
34824
|
if (res)
|
|
34642
34825
|
return res;
|
|
@@ -35124,7 +35307,11 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
|
|
|
35124
35307
|
sync: true
|
|
35125
35308
|
},
|
|
35126
35309
|
tasks: {
|
|
35127
|
-
create: (input) => createTask(
|
|
35310
|
+
create: (input, context) => createTask({
|
|
35311
|
+
...input,
|
|
35312
|
+
agent_id: input.agent_id ?? context?.agentId,
|
|
35313
|
+
created_by: input.created_by ?? input.agent_id ?? context?.agentId
|
|
35314
|
+
}, database()),
|
|
35128
35315
|
get: (id) => getTask(id, database()),
|
|
35129
35316
|
resolveRef: (ref) => resolveTaskRefLocal(database(), ref),
|
|
35130
35317
|
list: (filter = {}) => listTasksMaybeSearch(filter, database()),
|
|
@@ -37740,6 +37927,8 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
37740
37927
|
...url.searchParams.get("task_list_id") ? { task_list_id: url.searchParams.get("task_list_id") } : {},
|
|
37741
37928
|
...url.searchParams.get("assigned_to") ? { assigned_to: url.searchParams.get("assigned_to") } : {},
|
|
37742
37929
|
...url.searchParams.get("agent_id") ? { agent_id: url.searchParams.get("agent_id") } : {},
|
|
37930
|
+
...url.searchParams.get("created_by") ? { created_by: url.searchParams.get("created_by") } : {},
|
|
37931
|
+
...url.searchParams.get("not_created_by") ? { not_created_by: url.searchParams.get("not_created_by") } : {},
|
|
37743
37932
|
...url.searchParams.get("tags") ? {
|
|
37744
37933
|
tags: url.searchParams.get("tags").split(",").map((tag) => tag.trim()).filter(Boolean)
|
|
37745
37934
|
} : {},
|
|
@@ -42985,6 +43174,8 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
42985
43174
|
project_id: exports_external.string().optional().describe("Project ID"),
|
|
42986
43175
|
task_list_id: exports_external.string().optional().describe("Task list ID"),
|
|
42987
43176
|
assigned_to: exports_external.string().optional().describe("Agent ID or name to assign to"),
|
|
43177
|
+
created_by: exports_external.string().optional().describe("Agent who FILED this task. Defaults to the ambient agent identity (todos init / TODOS_AGENT_ID)."),
|
|
43178
|
+
unassigned: exports_external.boolean().optional().describe("Deliberately file with no assignee. Without it, the task defaults to the filer."),
|
|
42988
43179
|
depends_on: exports_external.array(exports_external.string()).optional().describe("Array of task IDs this task depends on"),
|
|
42989
43180
|
short_id: exports_external.string().nullable().optional().describe("Short ID (auto-generated if not provided, disabled if null)"),
|
|
42990
43181
|
tags: exports_external.array(exports_external.string()).optional().describe("Tags for the task"),
|
|
@@ -42995,12 +43186,19 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
42995
43186
|
retry_count: exports_external.number().optional().describe("Max retry count for agent failures")
|
|
42996
43187
|
}, async (params) => {
|
|
42997
43188
|
try {
|
|
42998
|
-
const { depends_on, assigned_to, project_id, task_list_id, tags, estimate, confidence, retry_count, deadline, ...rest } = params;
|
|
43189
|
+
const { depends_on, assigned_to, project_id, task_list_id, tags, estimate, confidence, retry_count, deadline, created_by, unassigned, ...rest } = params;
|
|
43190
|
+
const creator = resolveCreatorIdentity(created_by);
|
|
43191
|
+
const router = resolveWritableIdentity(created_by);
|
|
43192
|
+
const assignee = assigned_to || (unassigned ? undefined : router.agent_id || undefined);
|
|
42999
43193
|
const cloud = getTodosCloudClient();
|
|
43000
43194
|
if (cloud) {
|
|
43001
43195
|
const payload = { ...rest };
|
|
43002
|
-
if (
|
|
43003
|
-
payload.
|
|
43196
|
+
if (creator.agent_id)
|
|
43197
|
+
payload.created_by = creator.agent_id;
|
|
43198
|
+
if (router.agent_id)
|
|
43199
|
+
payload.agent_id = payload.agent_id ?? router.agent_id;
|
|
43200
|
+
if (assignee)
|
|
43201
|
+
payload.assigned_to = assignee;
|
|
43004
43202
|
if (project_id)
|
|
43005
43203
|
payload.project_id = project_id;
|
|
43006
43204
|
if (task_list_id)
|
|
@@ -43021,8 +43219,12 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
43021
43219
|
return { content: [{ type: "text", text: mutationTaskResponse(created) }] };
|
|
43022
43220
|
}
|
|
43023
43221
|
const resolved = { ...rest };
|
|
43024
|
-
if (
|
|
43025
|
-
resolved.
|
|
43222
|
+
if (creator.agent_id)
|
|
43223
|
+
resolved.created_by = creator.agent_id;
|
|
43224
|
+
if (router.agent_id)
|
|
43225
|
+
resolved.agent_id = resolved.agent_id ?? router.agent_id;
|
|
43226
|
+
if (assignee)
|
|
43227
|
+
resolved.assigned_to = resolveAssignee(assignee);
|
|
43026
43228
|
if (project_id)
|
|
43027
43229
|
resolved.project_id = resolveId(project_id, "projects");
|
|
43028
43230
|
if (task_list_id)
|
|
@@ -43108,6 +43310,8 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
43108
43310
|
project_id: exports_external.string().optional().describe("Filter by project"),
|
|
43109
43311
|
task_list_id: exports_external.string().optional().describe("Filter by task list"),
|
|
43110
43312
|
assigned_to: exports_external.string().optional().describe("Filter by assignee (agent ID or name, empty string = unassigned)"),
|
|
43313
|
+
created_by: exports_external.string().optional().describe("Filter by the agent who FILED the task"),
|
|
43314
|
+
not_created_by: exports_external.string().optional().describe('Exclude tasks filed by this agent. With assigned_to=<me> this is the "my inbox, minus my own filings" query.'),
|
|
43111
43315
|
tags: exports_external.array(exports_external.string()).optional().describe("Filter by tags (AND logic)"),
|
|
43112
43316
|
created_after: exports_external.string().optional().describe("ISO date \u2014 tasks created after this date"),
|
|
43113
43317
|
created_before: exports_external.string().optional().describe("ISO date \u2014 tasks created before this date"),
|
|
@@ -43300,6 +43504,7 @@ var init_task_crud2 = __esm(() => {
|
|
|
43300
43504
|
init_tasks();
|
|
43301
43505
|
init_types();
|
|
43302
43506
|
init_token_utils();
|
|
43507
|
+
init_creator_identity();
|
|
43303
43508
|
init_cloud_router();
|
|
43304
43509
|
});
|
|
43305
43510
|
|
|
@@ -43496,8 +43701,8 @@ var exports_mention_resolver = {};
|
|
|
43496
43701
|
__export(exports_mention_resolver, {
|
|
43497
43702
|
resolveMentions: () => resolveMentions
|
|
43498
43703
|
});
|
|
43499
|
-
import { existsSync as
|
|
43500
|
-
import { basename as basename8, isAbsolute, join as
|
|
43704
|
+
import { existsSync as existsSync19, readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync9 } from "fs";
|
|
43705
|
+
import { basename as basename8, isAbsolute, join as join18, relative as relative5, resolve as resolve18, sep as sep5 } from "path";
|
|
43501
43706
|
function blankResolution(parsed) {
|
|
43502
43707
|
return {
|
|
43503
43708
|
input: parsed.input,
|
|
@@ -43595,7 +43800,7 @@ function resolveFile(parsed, workspace) {
|
|
|
43595
43800
|
return resolution;
|
|
43596
43801
|
}
|
|
43597
43802
|
resolution.path = relPath;
|
|
43598
|
-
if (!
|
|
43803
|
+
if (!existsSync19(absolutePath)) {
|
|
43599
43804
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
43600
43805
|
return resolution;
|
|
43601
43806
|
}
|
|
@@ -43628,7 +43833,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
43628
43833
|
if (SKIP_DIRS2.has(entry2.name))
|
|
43629
43834
|
continue;
|
|
43630
43835
|
}
|
|
43631
|
-
const absolutePath =
|
|
43836
|
+
const absolutePath = join18(current, entry2.name);
|
|
43632
43837
|
if (entry2.isDirectory()) {
|
|
43633
43838
|
if (!SKIP_DIRS2.has(entry2.name))
|
|
43634
43839
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -46395,7 +46600,7 @@ __export(exports_release_compatibility, {
|
|
|
46395
46600
|
LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION: () => LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION
|
|
46396
46601
|
});
|
|
46397
46602
|
import { readFileSync as readFileSync11 } from "fs";
|
|
46398
|
-
import { join as
|
|
46603
|
+
import { join as join19, resolve as resolve19 } from "path";
|
|
46399
46604
|
import { Database as Database3 } from "bun:sqlite";
|
|
46400
46605
|
function pass(id, message, details) {
|
|
46401
46606
|
return { id, status: "passed", message, details };
|
|
@@ -46407,7 +46612,7 @@ function warn(id, message, details) {
|
|
|
46407
46612
|
return { id, status: "warning", message, details };
|
|
46408
46613
|
}
|
|
46409
46614
|
function readPackageJson2(root) {
|
|
46410
|
-
return JSON.parse(readFileSync11(
|
|
46615
|
+
return JSON.parse(readFileSync11(join19(root, "package.json"), "utf8"));
|
|
46411
46616
|
}
|
|
46412
46617
|
function sortedKeys(value) {
|
|
46413
46618
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -52350,7 +52555,7 @@ __export(exports_verification_providers, {
|
|
|
52350
52555
|
getVerificationRecord: () => getVerificationRecord,
|
|
52351
52556
|
discoverVerificationProviderCapabilities: () => discoverVerificationProviderCapabilities
|
|
52352
52557
|
});
|
|
52353
|
-
import { existsSync as
|
|
52558
|
+
import { existsSync as existsSync20, readFileSync as readFileSync12 } from "fs";
|
|
52354
52559
|
function normalizeName6(name) {
|
|
52355
52560
|
const normalized = name.trim().toLowerCase();
|
|
52356
52561
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -52502,7 +52707,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
52502
52707
|
};
|
|
52503
52708
|
}
|
|
52504
52709
|
function runCiLogProvider(input) {
|
|
52505
|
-
const text = input.log_text ?? (input.log_path &&
|
|
52710
|
+
const text = input.log_text ?? (input.log_path && existsSync20(input.log_path) ? readFileSync12(input.log_path, "utf-8") : "");
|
|
52506
52711
|
return {
|
|
52507
52712
|
status: classifyLog(text),
|
|
52508
52713
|
attempts: 1,
|
|
@@ -52514,7 +52719,7 @@ function runBrowserProvider(input) {
|
|
|
52514
52719
|
if (!input.artifact_path) {
|
|
52515
52720
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
52516
52721
|
}
|
|
52517
|
-
if (!
|
|
52722
|
+
if (!existsSync20(input.artifact_path)) {
|
|
52518
52723
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
52519
52724
|
}
|
|
52520
52725
|
return {
|
|
@@ -55103,7 +55308,7 @@ __export(exports_onboarding_fixtures, {
|
|
|
55103
55308
|
TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION: () => TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION
|
|
55104
55309
|
});
|
|
55105
55310
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
55106
|
-
import { join as
|
|
55311
|
+
import { join as join20 } from "path";
|
|
55107
55312
|
function emptyData() {
|
|
55108
55313
|
return {
|
|
55109
55314
|
projects: [],
|
|
@@ -55171,6 +55376,7 @@ function task(input) {
|
|
|
55171
55376
|
reason: "Bundled deterministic onboarding fixture",
|
|
55172
55377
|
spawned_from_session: null,
|
|
55173
55378
|
assigned_by: null,
|
|
55379
|
+
created_by: null,
|
|
55174
55380
|
assigned_from_project: null,
|
|
55175
55381
|
task_type: "onboarding",
|
|
55176
55382
|
cost_tokens: 0,
|
|
@@ -55437,7 +55643,7 @@ function writeOnboardingFixtureFiles(directory) {
|
|
|
55437
55643
|
mkdirSync11(directory, { recursive: true });
|
|
55438
55644
|
const files = [];
|
|
55439
55645
|
for (const fixture of allFixtures()) {
|
|
55440
|
-
const path =
|
|
55646
|
+
const path = join20(directory, `${fixture.summary.name}.bridge.json`);
|
|
55441
55647
|
writeFileSync9(path, `${JSON.stringify(fixture.bundle, null, 2)}
|
|
55442
55648
|
`, "utf-8");
|
|
55443
55649
|
files.push(path);
|
|
@@ -61649,16 +61855,16 @@ __export(exports_environment_snapshots, {
|
|
|
61649
61855
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
61650
61856
|
});
|
|
61651
61857
|
import { createHash as createHash13 } from "crypto";
|
|
61652
|
-
import { existsSync as
|
|
61858
|
+
import { existsSync as existsSync21, readFileSync as readFileSync15, statSync as statSync10 } from "fs";
|
|
61653
61859
|
import { hostname as hostname2, platform, arch } from "os";
|
|
61654
|
-
import { dirname as dirname10, join as
|
|
61860
|
+
import { dirname as dirname10, join as join21, resolve as resolve21 } from "path";
|
|
61655
61861
|
import { tmpdir as tmpdir4 } from "os";
|
|
61656
61862
|
function sha2567(value) {
|
|
61657
61863
|
return createHash13("sha256").update(value).digest("hex");
|
|
61658
61864
|
}
|
|
61659
61865
|
function fileRecord(root, relativePath) {
|
|
61660
|
-
const path =
|
|
61661
|
-
if (!
|
|
61866
|
+
const path = join21(root, relativePath);
|
|
61867
|
+
if (!existsSync21(path))
|
|
61662
61868
|
return null;
|
|
61663
61869
|
const stat = statSync10(path);
|
|
61664
61870
|
if (!stat.isFile())
|
|
@@ -61670,7 +61876,7 @@ function manifestRecord(root, relativePath) {
|
|
|
61670
61876
|
const base = fileRecord(root, relativePath);
|
|
61671
61877
|
if (!base)
|
|
61672
61878
|
return null;
|
|
61673
|
-
const parsed = readJsonFile(
|
|
61879
|
+
const parsed = readJsonFile(join21(root, relativePath));
|
|
61674
61880
|
if (!parsed)
|
|
61675
61881
|
return { ...base, redacted: {} };
|
|
61676
61882
|
const redacted = redactValue({
|
|
@@ -61765,8 +61971,8 @@ function commandEnv(env, includeValues) {
|
|
|
61765
61971
|
function defaultSnapshotDir() {
|
|
61766
61972
|
const dbPath = getDatabasePath();
|
|
61767
61973
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
61768
|
-
return
|
|
61769
|
-
return
|
|
61974
|
+
return join21(tmpdir4(), "hasna-todos", "environment-snapshots");
|
|
61975
|
+
return join21(dirname10(resolve21(dbPath)), "environment-snapshots");
|
|
61770
61976
|
}
|
|
61771
61977
|
function snapshotWithId(snapshot) {
|
|
61772
61978
|
const digest = sha2567(JSON.stringify(snapshot)).slice(0, 24);
|
|
@@ -61813,7 +62019,7 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
61813
62019
|
});
|
|
61814
62020
|
}
|
|
61815
62021
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
61816
|
-
const path = outputPath ? resolve21(outputPath) :
|
|
62022
|
+
const path = outputPath ? resolve21(outputPath) : join21(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
61817
62023
|
ensureDir(dirname10(path));
|
|
61818
62024
|
writeJsonFile(path, snapshot);
|
|
61819
62025
|
return path;
|
|
@@ -62621,27 +62827,27 @@ __export(exports_serve, {
|
|
|
62621
62827
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
62622
62828
|
MIME_TYPES: () => MIME_TYPES
|
|
62623
62829
|
});
|
|
62624
|
-
import { existsSync as
|
|
62625
|
-
import { join as
|
|
62830
|
+
import { existsSync as existsSync22 } from "fs";
|
|
62831
|
+
import { join as join22, dirname as dirname11, extname } from "path";
|
|
62626
62832
|
import { fileURLToPath } from "url";
|
|
62627
62833
|
function resolveDashboardDir() {
|
|
62628
62834
|
const candidates = [];
|
|
62629
62835
|
try {
|
|
62630
62836
|
const scriptDir = dirname11(fileURLToPath(import.meta.url));
|
|
62631
|
-
candidates.push(
|
|
62632
|
-
candidates.push(
|
|
62837
|
+
candidates.push(join22(scriptDir, "..", "dashboard", "dist"));
|
|
62838
|
+
candidates.push(join22(scriptDir, "..", "..", "dashboard", "dist"));
|
|
62633
62839
|
} catch {}
|
|
62634
62840
|
if (process.argv[1]) {
|
|
62635
62841
|
const mainDir = dirname11(process.argv[1]);
|
|
62636
|
-
candidates.push(
|
|
62637
|
-
candidates.push(
|
|
62842
|
+
candidates.push(join22(mainDir, "..", "dashboard", "dist"));
|
|
62843
|
+
candidates.push(join22(mainDir, "..", "..", "dashboard", "dist"));
|
|
62638
62844
|
}
|
|
62639
|
-
candidates.push(
|
|
62845
|
+
candidates.push(join22(process.cwd(), "dashboard", "dist"));
|
|
62640
62846
|
for (const candidate of candidates) {
|
|
62641
|
-
if (
|
|
62847
|
+
if (existsSync22(candidate))
|
|
62642
62848
|
return candidate;
|
|
62643
62849
|
}
|
|
62644
|
-
return
|
|
62850
|
+
return join22(process.cwd(), "dashboard", "dist");
|
|
62645
62851
|
}
|
|
62646
62852
|
function getProvidedApiKey(req) {
|
|
62647
62853
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -62713,7 +62919,7 @@ function json(data, status = 200, headers) {
|
|
|
62713
62919
|
});
|
|
62714
62920
|
}
|
|
62715
62921
|
function serveStaticFile(filePath) {
|
|
62716
|
-
if (!
|
|
62922
|
+
if (!existsSync22(filePath))
|
|
62717
62923
|
return null;
|
|
62718
62924
|
const ext = extname(filePath);
|
|
62719
62925
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -62814,7 +63020,7 @@ data: ${data}
|
|
|
62814
63020
|
filteredSseClients.delete(client);
|
|
62815
63021
|
}
|
|
62816
63022
|
const dashboardDir = resolveDashboardDir();
|
|
62817
|
-
const dashboardExists =
|
|
63023
|
+
const dashboardExists = existsSync22(dashboardDir);
|
|
62818
63024
|
if (!dashboardExists) {
|
|
62819
63025
|
console.error(`
|
|
62820
63026
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -64687,12 +64893,12 @@ __export(exports_config_serve_commands, {
|
|
|
64687
64893
|
registerConfigServeCommands: () => registerConfigServeCommands
|
|
64688
64894
|
});
|
|
64689
64895
|
import chalk6 from "chalk";
|
|
64690
|
-
import { existsSync as
|
|
64691
|
-
import { dirname as dirname12, join as
|
|
64896
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
64897
|
+
import { dirname as dirname12, join as join23 } from "path";
|
|
64692
64898
|
function registerConfigServeCommands(program2) {
|
|
64693
64899
|
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) => {
|
|
64694
64900
|
const globalOpts = program2.opts();
|
|
64695
|
-
const configPath =
|
|
64901
|
+
const configPath = join23(getTodosGlobalDir(), "config.json");
|
|
64696
64902
|
if (opts.get) {
|
|
64697
64903
|
const config2 = loadConfig();
|
|
64698
64904
|
const keys = opts.get.split(".");
|
|
@@ -64729,7 +64935,7 @@ function registerConfigServeCommands(program2) {
|
|
|
64729
64935
|
}
|
|
64730
64936
|
obj[keys[keys.length - 1]] = parsedValue;
|
|
64731
64937
|
const dir = dirname12(configPath);
|
|
64732
|
-
if (!
|
|
64938
|
+
if (!existsSync23(dir))
|
|
64733
64939
|
mkdirSync12(dir, { recursive: true });
|
|
64734
64940
|
writeFileSync10(configPath, JSON.stringify(config2, null, 2));
|
|
64735
64941
|
if (globalOpts.json) {
|
|
@@ -65909,8 +66115,8 @@ __export(exports_routing_doctor, {
|
|
|
65909
66115
|
classifyTaskRouting: () => classifyTaskRouting,
|
|
65910
66116
|
TODOS_ROUTING_DOCTOR_SCHEMA_VERSION: () => TODOS_ROUTING_DOCTOR_SCHEMA_VERSION
|
|
65911
66117
|
});
|
|
65912
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
65913
|
-
import { basename as basename9, dirname as dirname13, join as
|
|
66118
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync24, mkdirSync as mkdirSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
66119
|
+
import { basename as basename9, dirname as dirname13, join as join24 } from "path";
|
|
65914
66120
|
function normalizePath5(path) {
|
|
65915
66121
|
if (!path)
|
|
65916
66122
|
return null;
|
|
@@ -66212,16 +66418,16 @@ function evaluateTaskRouting(ctx) {
|
|
|
66212
66418
|
function createBackup2(dbPath, generatedAt) {
|
|
66213
66419
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
66214
66420
|
return;
|
|
66215
|
-
if (!
|
|
66421
|
+
if (!existsSync24(dbPath))
|
|
66216
66422
|
return;
|
|
66217
66423
|
const stamp = generatedAt.replace(/[:.]/g, "-");
|
|
66218
|
-
const backupDir =
|
|
66424
|
+
const backupDir = join24(dirname13(dbPath), `${basename9(dbPath)}.routing-doctor-backup-${stamp}`);
|
|
66219
66425
|
const files = [];
|
|
66220
66426
|
mkdirSync13(backupDir, { recursive: true });
|
|
66221
66427
|
for (const source3 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
66222
|
-
if (!
|
|
66428
|
+
if (!existsSync24(source3))
|
|
66223
66429
|
continue;
|
|
66224
|
-
const target =
|
|
66430
|
+
const target = join24(backupDir, basename9(source3));
|
|
66225
66431
|
copyFileSync3(source3, target);
|
|
66226
66432
|
files.push(target);
|
|
66227
66433
|
}
|
|
@@ -66325,7 +66531,7 @@ function runRoutingDoctor(options = {}) {
|
|
|
66325
66531
|
}
|
|
66326
66532
|
const applied = repairs.filter((r) => r.applied);
|
|
66327
66533
|
if (applied.length > 0) {
|
|
66328
|
-
const undoPath = options.undoRecordPath ??
|
|
66534
|
+
const undoPath = options.undoRecordPath ?? join24(process.cwd(), `todos-routing-doctor-undo-${generatedAt.replace(/[:.]/g, "-")}.json`);
|
|
66329
66535
|
const undoRecord = {
|
|
66330
66536
|
schema_version: TODOS_ROUTING_DOCTOR_SCHEMA_VERSION,
|
|
66331
66537
|
purpose: "Undo record for routing-doctor --apply. Restore each field with the prior value below.",
|
|
@@ -66424,8 +66630,8 @@ __export(exports_task_route_sources, {
|
|
|
66424
66630
|
});
|
|
66425
66631
|
import { Database as Database4 } from "bun:sqlite";
|
|
66426
66632
|
import { createHash as createHash14 } from "crypto";
|
|
66427
|
-
import { existsSync as
|
|
66428
|
-
import { basename as basename10, dirname as dirname14, join as
|
|
66633
|
+
import { existsSync as existsSync25, readdirSync as readdirSync5, statSync as statSync11 } from "fs";
|
|
66634
|
+
import { basename as basename10, dirname as dirname14, join as join25, resolve as resolve22 } from "path";
|
|
66429
66635
|
function normalizePath6(input) {
|
|
66430
66636
|
return resolve22(input);
|
|
66431
66637
|
}
|
|
@@ -66489,8 +66695,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
66489
66695
|
const rootPath = normalizePath6(sourceRoot);
|
|
66490
66696
|
const errors2 = [];
|
|
66491
66697
|
const stores = [];
|
|
66492
|
-
if (!
|
|
66493
|
-
const ref = createStoreRef(
|
|
66698
|
+
if (!existsSync25(rootPath)) {
|
|
66699
|
+
const ref = createStoreRef(join25(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
66494
66700
|
errors2.push({
|
|
66495
66701
|
...ref,
|
|
66496
66702
|
code: "SOURCE_ROOT_MISSING",
|
|
@@ -66502,7 +66708,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
66502
66708
|
try {
|
|
66503
66709
|
rootStat = statSync11(rootPath);
|
|
66504
66710
|
} catch (error2) {
|
|
66505
|
-
const ref = createStoreRef(
|
|
66711
|
+
const ref = createStoreRef(join25(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
66506
66712
|
errors2.push({
|
|
66507
66713
|
...ref,
|
|
66508
66714
|
code: "SOURCE_ROOT_UNREADABLE",
|
|
@@ -66515,8 +66721,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
66515
66721
|
return { stores, errors: errors2 };
|
|
66516
66722
|
}
|
|
66517
66723
|
function scanDirectory(dir, depth) {
|
|
66518
|
-
const candidate =
|
|
66519
|
-
if (
|
|
66724
|
+
const candidate = join25(dir, TODO_STORE_RELATIVE_PATH);
|
|
66725
|
+
if (existsSync25(candidate)) {
|
|
66520
66726
|
stores.push(createStoreRef(candidate));
|
|
66521
66727
|
}
|
|
66522
66728
|
if (depth >= ROOT_SCAN_MAX_DEPTH)
|
|
@@ -66536,7 +66742,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
66536
66742
|
for (const entry2 of entries) {
|
|
66537
66743
|
if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
|
|
66538
66744
|
continue;
|
|
66539
|
-
scanDirectory(
|
|
66745
|
+
scanDirectory(join25(dir, entry2.name), depth + 1);
|
|
66540
66746
|
}
|
|
66541
66747
|
}
|
|
66542
66748
|
scanDirectory(rootPath, 0);
|
|
@@ -66562,7 +66768,7 @@ function collectStoreRefs(input) {
|
|
|
66562
66768
|
};
|
|
66563
66769
|
}
|
|
66564
66770
|
function openReadonlyStore(ref) {
|
|
66565
|
-
if (!
|
|
66771
|
+
if (!existsSync25(ref.source_db_path)) {
|
|
66566
66772
|
throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
|
|
66567
66773
|
}
|
|
66568
66774
|
return new Database4(ref.source_db_path, { readonly: true, create: false });
|
|
@@ -66736,7 +66942,7 @@ var init_task_route_sources = __esm(() => {
|
|
|
66736
66942
|
init_task_crud();
|
|
66737
66943
|
init_redaction();
|
|
66738
66944
|
init_task_routing();
|
|
66739
|
-
TODO_STORE_RELATIVE_PATH =
|
|
66945
|
+
TODO_STORE_RELATIVE_PATH = join25(".hasna", "todos", "todos.db");
|
|
66740
66946
|
SKIPPED_SCAN_DIRS = new Set([
|
|
66741
66947
|
".git",
|
|
66742
66948
|
".hg",
|
|
@@ -68245,9 +68451,9 @@ Findings`));
|
|
|
68245
68451
|
const db = getDatabase();
|
|
68246
68452
|
const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
|
|
68247
68453
|
const { statSync: statSync12 } = await import("fs");
|
|
68248
|
-
const { join:
|
|
68454
|
+
const { join: join26 } = await import("path");
|
|
68249
68455
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
68250
|
-
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] ||
|
|
68456
|
+
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join26(home, ".hasna", "todos", "todos.db");
|
|
68251
68457
|
let size = "unknown";
|
|
68252
68458
|
try {
|
|
68253
68459
|
size = `${(statSync12(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -70161,21 +70367,21 @@ __export(exports_mcp_hooks_commands, {
|
|
|
70161
70367
|
});
|
|
70162
70368
|
import chalk9 from "chalk";
|
|
70163
70369
|
import { execSync as execSync3 } from "child_process";
|
|
70164
|
-
import { existsSync as
|
|
70165
|
-
import { dirname as dirname15, join as
|
|
70370
|
+
import { existsSync as existsSync26, readFileSync as readFileSync18, writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, chmodSync as chmodSync3 } from "fs";
|
|
70371
|
+
import { dirname as dirname15, join as join26 } from "path";
|
|
70166
70372
|
function getMcpBinaryPath() {
|
|
70167
70373
|
try {
|
|
70168
70374
|
const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
|
|
70169
70375
|
if (p)
|
|
70170
70376
|
return p;
|
|
70171
70377
|
} catch {}
|
|
70172
|
-
const bunBin =
|
|
70173
|
-
if (
|
|
70378
|
+
const bunBin = join26(HOME2, ".bun", "bin", "todos-mcp");
|
|
70379
|
+
if (existsSync26(bunBin))
|
|
70174
70380
|
return bunBin;
|
|
70175
70381
|
return "todos-mcp";
|
|
70176
70382
|
}
|
|
70177
70383
|
function readJsonFile2(path) {
|
|
70178
|
-
if (!
|
|
70384
|
+
if (!existsSync26(path))
|
|
70179
70385
|
return {};
|
|
70180
70386
|
try {
|
|
70181
70387
|
return JSON.parse(readFileSync18(path, "utf-8"));
|
|
@@ -70185,19 +70391,19 @@ function readJsonFile2(path) {
|
|
|
70185
70391
|
}
|
|
70186
70392
|
function writeJsonFile2(path, data) {
|
|
70187
70393
|
const dir = dirname15(path);
|
|
70188
|
-
if (!
|
|
70394
|
+
if (!existsSync26(dir))
|
|
70189
70395
|
mkdirSync14(dir, { recursive: true });
|
|
70190
70396
|
writeFileSync13(path, JSON.stringify(data, null, 2) + `
|
|
70191
70397
|
`);
|
|
70192
70398
|
}
|
|
70193
70399
|
function readTomlFile(path) {
|
|
70194
|
-
if (!
|
|
70400
|
+
if (!existsSync26(path))
|
|
70195
70401
|
return "";
|
|
70196
70402
|
return readFileSync18(path, "utf-8");
|
|
70197
70403
|
}
|
|
70198
70404
|
function writeTomlFile(path, content) {
|
|
70199
70405
|
const dir = dirname15(path);
|
|
70200
|
-
if (!
|
|
70406
|
+
if (!existsSync26(dir))
|
|
70201
70407
|
mkdirSync14(dir, { recursive: true });
|
|
70202
70408
|
writeFileSync13(path, content);
|
|
70203
70409
|
}
|
|
@@ -70262,7 +70468,7 @@ function unregisterClaude(_global) {
|
|
|
70262
70468
|
}
|
|
70263
70469
|
}
|
|
70264
70470
|
function registerCodex(binPath) {
|
|
70265
|
-
const configPath =
|
|
70471
|
+
const configPath = join26(HOME2, ".codex", "config.toml");
|
|
70266
70472
|
let content = readTomlFile(configPath);
|
|
70267
70473
|
content = removeTomlBlock(content, "mcp_servers.todos");
|
|
70268
70474
|
const block = `
|
|
@@ -70276,7 +70482,7 @@ args = ["--stdio"]
|
|
|
70276
70482
|
console.log(chalk9.green(`Codex CLI: registered in ${configPath}`));
|
|
70277
70483
|
}
|
|
70278
70484
|
function unregisterCodex() {
|
|
70279
|
-
const configPath =
|
|
70485
|
+
const configPath = join26(HOME2, ".codex", "config.toml");
|
|
70280
70486
|
let content = readTomlFile(configPath);
|
|
70281
70487
|
if (!content.includes("[mcp_servers.todos]")) {
|
|
70282
70488
|
console.log(chalk9.dim(`Codex CLI: todos not found in ${configPath}`));
|
|
@@ -70288,7 +70494,7 @@ function unregisterCodex() {
|
|
|
70288
70494
|
console.log(chalk9.green(`Codex CLI: unregistered from ${configPath}`));
|
|
70289
70495
|
}
|
|
70290
70496
|
function registerGemini(binPath) {
|
|
70291
|
-
const configPath =
|
|
70497
|
+
const configPath = join26(HOME2, ".gemini", "settings.json");
|
|
70292
70498
|
const config = readJsonFile2(configPath);
|
|
70293
70499
|
if (!config["mcpServers"]) {
|
|
70294
70500
|
config["mcpServers"] = {};
|
|
@@ -70302,7 +70508,7 @@ function registerGemini(binPath) {
|
|
|
70302
70508
|
console.log(chalk9.green(`Gemini CLI: registered in ${configPath}`));
|
|
70303
70509
|
}
|
|
70304
70510
|
function unregisterGemini() {
|
|
70305
|
-
const configPath =
|
|
70511
|
+
const configPath = join26(HOME2, ".gemini", "settings.json");
|
|
70306
70512
|
const config = readJsonFile2(configPath);
|
|
70307
70513
|
const servers = config["mcpServers"];
|
|
70308
70514
|
if (!servers || !("todos" in servers)) {
|
|
@@ -70313,8 +70519,37 @@ function unregisterGemini() {
|
|
|
70313
70519
|
writeJsonFile2(configPath, config);
|
|
70314
70520
|
console.log(chalk9.green(`Gemini CLI: unregistered from ${configPath}`));
|
|
70315
70521
|
}
|
|
70522
|
+
function cursorConfigPath(global) {
|
|
70523
|
+
return global ? join26(HOME2, ".cursor", "mcp.json") : join26(process.cwd(), ".cursor", "mcp.json");
|
|
70524
|
+
}
|
|
70525
|
+
function registerCursor(binPath, global) {
|
|
70526
|
+
const configPath = cursorConfigPath(global);
|
|
70527
|
+
const config = readJsonFile2(configPath);
|
|
70528
|
+
if (!config["mcpServers"]) {
|
|
70529
|
+
config["mcpServers"] = {};
|
|
70530
|
+
}
|
|
70531
|
+
const servers = config["mcpServers"];
|
|
70532
|
+
servers["todos"] = {
|
|
70533
|
+
command: binPath,
|
|
70534
|
+
args: ["--stdio"]
|
|
70535
|
+
};
|
|
70536
|
+
writeJsonFile2(configPath, config);
|
|
70537
|
+
console.log(chalk9.green(`Cursor (${global ? "user" : "project"}): registered in ${configPath}`));
|
|
70538
|
+
}
|
|
70539
|
+
function unregisterCursor(global) {
|
|
70540
|
+
const configPath = cursorConfigPath(global);
|
|
70541
|
+
const config = readJsonFile2(configPath);
|
|
70542
|
+
const servers = config["mcpServers"];
|
|
70543
|
+
if (!servers || !("todos" in servers)) {
|
|
70544
|
+
console.log(chalk9.dim(`Cursor: todos not found in ${configPath}`));
|
|
70545
|
+
return;
|
|
70546
|
+
}
|
|
70547
|
+
delete servers["todos"];
|
|
70548
|
+
writeJsonFile2(configPath, config);
|
|
70549
|
+
console.log(chalk9.green(`Cursor (${global ? "user" : "project"}): unregistered from ${configPath}`));
|
|
70550
|
+
}
|
|
70316
70551
|
function registerMcp(agent, global) {
|
|
70317
|
-
const agents = agent === "all" ? ["claude", "codex", "gemini"] : [agent];
|
|
70552
|
+
const agents = agent === "all" ? ["claude", "codex", "gemini", "cursor"] : [agent];
|
|
70318
70553
|
const binPath = getMcpBinaryPath();
|
|
70319
70554
|
for (const a of agents) {
|
|
70320
70555
|
switch (a) {
|
|
@@ -70327,13 +70562,16 @@ function registerMcp(agent, global) {
|
|
|
70327
70562
|
case "gemini":
|
|
70328
70563
|
registerGemini(binPath);
|
|
70329
70564
|
break;
|
|
70565
|
+
case "cursor":
|
|
70566
|
+
registerCursor(binPath, global);
|
|
70567
|
+
break;
|
|
70330
70568
|
default:
|
|
70331
|
-
console.error(chalk9.red(`Unknown agent: ${a}. Use: claude, codex, gemini, all`));
|
|
70569
|
+
console.error(chalk9.red(`Unknown agent: ${a}. Use: claude, codex, gemini, cursor, all`));
|
|
70332
70570
|
}
|
|
70333
70571
|
}
|
|
70334
70572
|
}
|
|
70335
70573
|
function unregisterMcp(agent, global) {
|
|
70336
|
-
const agents = agent === "all" ? ["claude", "codex", "gemini"] : [agent];
|
|
70574
|
+
const agents = agent === "all" ? ["claude", "codex", "gemini", "cursor"] : [agent];
|
|
70337
70575
|
for (const a of agents) {
|
|
70338
70576
|
switch (a) {
|
|
70339
70577
|
case "claude":
|
|
@@ -70345,8 +70583,11 @@ function unregisterMcp(agent, global) {
|
|
|
70345
70583
|
case "gemini":
|
|
70346
70584
|
unregisterGemini();
|
|
70347
70585
|
break;
|
|
70586
|
+
case "cursor":
|
|
70587
|
+
unregisterCursor(global);
|
|
70588
|
+
break;
|
|
70348
70589
|
default:
|
|
70349
|
-
console.error(chalk9.red(`Unknown agent: ${a}. Use: claude, codex, gemini, all`));
|
|
70590
|
+
console.error(chalk9.red(`Unknown agent: ${a}. Use: claude, codex, gemini, cursor, all`));
|
|
70350
70591
|
}
|
|
70351
70592
|
}
|
|
70352
70593
|
}
|
|
@@ -70359,8 +70600,8 @@ function registerMcpHooksCommands(program2) {
|
|
|
70359
70600
|
if (p)
|
|
70360
70601
|
todosBin = p;
|
|
70361
70602
|
} catch {}
|
|
70362
|
-
const hooksDir =
|
|
70363
|
-
if (!
|
|
70603
|
+
const hooksDir = join26(process.cwd(), ".claude", "hooks");
|
|
70604
|
+
if (!existsSync26(hooksDir))
|
|
70364
70605
|
mkdirSync14(hooksDir, { recursive: true });
|
|
70365
70606
|
const hookScript = `#!/usr/bin/env bash
|
|
70366
70607
|
# Auto-generated by: todos hooks install
|
|
@@ -70385,11 +70626,11 @@ esac
|
|
|
70385
70626
|
|
|
70386
70627
|
exit 0
|
|
70387
70628
|
`;
|
|
70388
|
-
const hookPath =
|
|
70629
|
+
const hookPath = join26(hooksDir, "todos-sync.sh");
|
|
70389
70630
|
writeFileSync13(hookPath, hookScript);
|
|
70390
70631
|
execSync3(`chmod +x "${hookPath}"`);
|
|
70391
70632
|
console.log(chalk9.green(`Hook script created: ${hookPath}`));
|
|
70392
|
-
const settingsPath =
|
|
70633
|
+
const settingsPath = join26(process.cwd(), ".claude", "settings.json");
|
|
70393
70634
|
const settings = readJsonFile2(settingsPath);
|
|
70394
70635
|
if (!settings["hooks"]) {
|
|
70395
70636
|
settings["hooks"] = {};
|
|
@@ -70418,7 +70659,7 @@ exit 0
|
|
|
70418
70659
|
console.log(chalk9.green(`Claude Code hooks configured in: ${settingsPath}`));
|
|
70419
70660
|
console.log(chalk9.dim("Task list ID auto-detected from project."));
|
|
70420
70661
|
});
|
|
70421
|
-
program2.command("mcp").description("Start MCP server (stdio)").option("--register <agent>", "Register MCP server with an agent (claude, codex, gemini, all)").option("--unregister <agent>", "Unregister MCP server from an agent (claude, codex, gemini, all)").option("-g, --global", "Register/unregister globally (user-level) instead of project-level").action(async (opts) => {
|
|
70662
|
+
program2.command("mcp").description("Start MCP server (stdio)").option("--register <agent>", "Register MCP server with an agent (claude, codex, gemini, cursor, all)").option("--unregister <agent>", "Unregister MCP server from an agent (claude, codex, gemini, cursor, all)").option("-g, --global", "Register/unregister globally (user-level) instead of project-level").action(async (opts) => {
|
|
70422
70663
|
if (opts.register) {
|
|
70423
70664
|
registerMcp(opts.register, opts.global);
|
|
70424
70665
|
return;
|
|
@@ -71320,7 +71561,7 @@ Artifacts:`));
|
|
|
71320
71561
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
71321
71562
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
71322
71563
|
const marker = "# todos-auto-link";
|
|
71323
|
-
if (
|
|
71564
|
+
if (existsSync26(hookPath)) {
|
|
71324
71565
|
const existing = readFileSync18(hookPath, "utf-8");
|
|
71325
71566
|
if (existing.includes(marker)) {
|
|
71326
71567
|
console.log(chalk9.yellow("Hook already installed."));
|
|
@@ -71347,7 +71588,7 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
71347
71588
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
71348
71589
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
71349
71590
|
const marker = "# todos-auto-link";
|
|
71350
|
-
if (!
|
|
71591
|
+
if (!existsSync26(hookPath)) {
|
|
71351
71592
|
console.log(chalk9.dim("No post-commit hook found."));
|
|
71352
71593
|
return;
|
|
71353
71594
|
}
|
|
@@ -71533,7 +71774,7 @@ import chalk11 from "chalk";
|
|
|
71533
71774
|
import { execSync as execSync4 } from "child_process";
|
|
71534
71775
|
import { readFileSync as readFileSync19, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
|
|
71535
71776
|
import { tmpdir as tmpdir5 } from "os";
|
|
71536
|
-
import { join as
|
|
71777
|
+
import { join as join27 } from "path";
|
|
71537
71778
|
function getOrCreateLocalMachineName() {
|
|
71538
71779
|
return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
|
|
71539
71780
|
}
|
|
@@ -71571,7 +71812,7 @@ function remoteTempPath(sshAddress) {
|
|
|
71571
71812
|
}
|
|
71572
71813
|
function readRemoteBridgeBundle(sshAddress) {
|
|
71573
71814
|
const remotePath = remoteTempPath(sshAddress);
|
|
71574
|
-
const localPath =
|
|
71815
|
+
const localPath = join27(tmpdir5(), `todos-bridge-pull-${uuid()}.json`);
|
|
71575
71816
|
try {
|
|
71576
71817
|
runSsh(sshAddress, `todos export --format bridge --allow-plaintext-sensitive --output ${shellQuote(remotePath)}`, 120000);
|
|
71577
71818
|
scpFromRemote(sshAddress, remotePath, localPath);
|
|
@@ -71586,7 +71827,7 @@ function readRemoteBridgeBundle(sshAddress) {
|
|
|
71586
71827
|
}
|
|
71587
71828
|
}
|
|
71588
71829
|
function writeLocalBridgeBundle() {
|
|
71589
|
-
const localPath =
|
|
71830
|
+
const localPath = join27(tmpdir5(), `todos-bridge-push-${uuid()}.json`);
|
|
71590
71831
|
writeFileSync14(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
|
|
71591
71832
|
return localPath;
|
|
71592
71833
|
}
|
|
@@ -76161,7 +76402,7 @@ __export(exports_sdk_integration_fixtures, {
|
|
|
76161
76402
|
TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT: () => TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT
|
|
76162
76403
|
});
|
|
76163
76404
|
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
76164
|
-
import { join as
|
|
76405
|
+
import { join as join28 } from "path";
|
|
76165
76406
|
function source5(version) {
|
|
76166
76407
|
return {
|
|
76167
76408
|
packageName: "@hasna/todos",
|
|
@@ -76268,7 +76509,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
|
76268
76509
|
];
|
|
76269
76510
|
const written = [];
|
|
76270
76511
|
for (const [name, payload] of files) {
|
|
76271
|
-
const file =
|
|
76512
|
+
const file = join28(directory, name);
|
|
76272
76513
|
writeFileSync15(file, `${JSON.stringify(payload, null, 2)}
|
|
76273
76514
|
`, "utf-8");
|
|
76274
76515
|
written.push(file);
|