@hasna/todos 0.11.52 → 0.11.53
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/README.md +14 -1
- package/dashboard/dist/assets/{index-C3fBxEWP.js → index-aJefI7kh.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/cli/commands/config-serve-commands.d.ts.map +1 -1
- package/dist/cli/commands/machines.d.ts.map +1 -1
- package/dist/cli/commands/storage-commands.d.ts +3 -0
- package/dist/cli/commands/storage-commands.d.ts.map +1 -0
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts +6 -0
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +3306 -445
- package/dist/contracts.js +289 -8
- package/dist/db/artifacts.d.ts.map +1 -1
- package/dist/db/builtin-templates.d.ts +0 -1
- package/dist/db/builtin-templates.d.ts.map +1 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/tags.d.ts +26 -0
- package/dist/db/tags.d.ts.map +1 -0
- package/dist/db/task-commits.d.ts +14 -6
- package/dist/db/task-commits.d.ts.map +1 -1
- package/dist/db/tasks.d.ts +1 -1
- package/dist/db/tasks.d.ts.map +1 -1
- package/dist/index.d.ts +32 -60
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2473 -200
- package/dist/lib/agent-adapter-docs.d.ts +1 -1
- package/dist/lib/agent-adapter-docs.d.ts.map +1 -1
- package/dist/lib/agent-coordination.d.ts.map +1 -1
- package/dist/lib/agent-run-dispatcher.d.ts +5 -2
- package/dist/lib/agent-run-dispatcher.d.ts.map +1 -1
- package/dist/lib/agent-workflow-demo.d.ts +1 -1
- package/dist/lib/agent-workflow-demo.d.ts.map +1 -1
- package/dist/lib/db-backup.d.ts.map +1 -1
- package/dist/lib/headless-boundaries.d.ts +2 -2
- package/dist/lib/headless-boundaries.d.ts.map +1 -1
- package/dist/lib/import-export-bridge.d.ts.map +1 -1
- package/dist/lib/inbox-intake.d.ts.map +1 -1
- package/dist/lib/issue-importers.d.ts.map +1 -1
- package/dist/lib/machine-topology.d.ts +1 -1
- package/dist/lib/machine-topology.d.ts.map +1 -1
- package/dist/lib/native-storage-status.d.ts +65 -0
- package/dist/lib/native-storage-status.d.ts.map +1 -0
- package/dist/lib/nl-intake.d.ts.map +1 -1
- package/dist/lib/notification-reminders.d.ts.map +1 -1
- package/dist/lib/plan-execution.d.ts +1 -0
- package/dist/lib/plan-execution.d.ts.map +1 -1
- package/dist/lib/release-checks.d.ts.map +1 -1
- package/dist/lib/resource-snapshots.d.ts.map +1 -1
- package/dist/lib/saved-views.d.ts.map +1 -1
- package/dist/lib/secret-redaction.d.ts +1 -1
- package/dist/lib/secret-redaction.d.ts.map +1 -1
- package/dist/lib/task-scheduling.d.ts +1 -1
- package/dist/lib/task-scheduling.d.ts.map +1 -1
- package/dist/lib/template-library.d.ts +1 -1
- package/dist/lib/template-library.d.ts.map +1 -1
- package/dist/lib/user-scaffolds.d.ts.map +1 -1
- package/dist/lib/verification-evidence.d.ts +4 -4
- package/dist/lib/verification-evidence.d.ts.map +1 -1
- package/dist/lib/verification-providers.d.ts +3 -3
- package/dist/lib/verification-providers.d.ts.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +526 -50
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp/tools/task-project-tools.d.ts.map +1 -1
- package/dist/registry.js +289 -8
- package/dist/release-provenance.json +7 -0
- package/dist/server/index.js +552 -52
- package/dist/server/serve.d.ts.map +1 -1
- package/dist/storage/config.d.ts +86 -0
- package/dist/storage/config.d.ts.map +1 -0
- package/dist/storage/factory.d.ts +17 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/hybrid.d.ts +26 -0
- package/dist/storage/hybrid.d.ts.map +1 -0
- package/dist/storage/index.d.ts +15 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/local-sqlite.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts +11 -0
- package/dist/storage/postgres-adapter.d.ts.map +1 -0
- package/dist/storage/postgres-sync.d.ts +44 -0
- package/dist/storage/postgres-sync.d.ts.map +1 -0
- package/dist/storage/s3-artifact-sync.d.ts +75 -0
- package/dist/storage/s3-artifact-sync.d.ts.map +1 -0
- package/dist/storage/s3-artifacts.d.ts +51 -0
- package/dist/storage/s3-artifacts.d.ts.map +1 -0
- package/dist/storage/sqlite-snapshot.d.ts +5 -0
- package/dist/storage/sqlite-snapshot.d.ts.map +1 -0
- package/dist/storage.d.ts +2 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +2053 -10
- package/package.json +1 -1
- package/dist/cli/brains.d.ts +0 -3
- package/dist/cli/brains.d.ts.map +0 -1
- package/dist/db/file-locks.d.ts +0 -43
- package/dist/db/file-locks.d.ts.map +0 -1
- package/dist/db/project-agent-roles.d.ts +0 -34
- package/dist/db/project-agent-roles.d.ts.map +0 -1
- package/dist/db/task-claim.d.ts +0 -7
- package/dist/db/task-claim.d.ts.map +0 -1
- package/dist/db/task-workflow.d.ts +0 -7
- package/dist/db/task-workflow.d.ts.map +0 -1
- package/dist/lib/north-star.d.ts +0 -33
- package/dist/lib/north-star.d.ts.map +0 -1
- package/dist/lib/public-release-gate.d.ts +0 -57
- package/dist/lib/public-release-gate.d.ts.map +0 -1
- package/dist/lib/task-runner.d.ts +0 -101
- package/dist/lib/task-runner.d.ts.map +0 -1
- package/dist/mcp/tools/access-profiles.d.ts +0 -8
- package/dist/mcp/tools/access-profiles.d.ts.map +0 -1
- package/dist/mcp/tools/activity-audit.d.ts +0 -9
- package/dist/mcp/tools/activity-audit.d.ts.map +0 -1
- package/dist/mcp/tools/agent-adapter-docs.d.ts +0 -8
- package/dist/mcp/tools/agent-adapter-docs.d.ts.map +0 -1
- package/dist/mcp/tools/agent-coordination.d.ts +0 -9
- package/dist/mcp/tools/agent-coordination.d.ts.map +0 -1
- package/dist/mcp/tools/agent-runs.d.ts +0 -9
- package/dist/mcp/tools/agent-runs.d.ts.map +0 -1
- package/dist/mcp/tools/agent-workflow-demo.d.ts +0 -8
- package/dist/mcp/tools/agent-workflow-demo.d.ts.map +0 -1
- package/dist/mcp/tools/approval-gates.d.ts +0 -9
- package/dist/mcp/tools/approval-gates.d.ts.map +0 -1
- package/dist/mcp/tools/artifacts.d.ts +0 -9
- package/dist/mcp/tools/artifacts.d.ts.map +0 -1
- package/dist/mcp/tools/branch-work-plans.d.ts +0 -8
- package/dist/mcp/tools/branch-work-plans.d.ts.map +0 -1
- package/dist/mcp/tools/cli-docs.d.ts +0 -8
- package/dist/mcp/tools/cli-docs.d.ts.map +0 -1
- package/dist/mcp/tools/command-aliases.d.ts +0 -8
- package/dist/mcp/tools/command-aliases.d.ts.map +0 -1
- package/dist/mcp/tools/context-packs.d.ts +0 -9
- package/dist/mcp/tools/context-packs.d.ts.map +0 -1
- package/dist/mcp/tools/crypto.d.ts +0 -8
- package/dist/mcp/tools/crypto.d.ts.map +0 -1
- package/dist/mcp/tools/db-backup.d.ts +0 -8
- package/dist/mcp/tools/db-backup.d.ts.map +0 -1
- package/dist/mcp/tools/decision-records.d.ts +0 -9
- package/dist/mcp/tools/decision-records.d.ts.map +0 -1
- package/dist/mcp/tools/dependency-graph.d.ts +0 -9
- package/dist/mcp/tools/dependency-graph.d.ts.map +0 -1
- package/dist/mcp/tools/failure-triage.d.ts +0 -9
- package/dist/mcp/tools/failure-triage.d.ts.map +0 -1
- package/dist/mcp/tools/feature-manifest.d.ts +0 -8
- package/dist/mcp/tools/feature-manifest.d.ts.map +0 -1
- package/dist/mcp/tools/git-traceability.d.ts +0 -9
- package/dist/mcp/tools/git-traceability.d.ts.map +0 -1
- package/dist/mcp/tools/goal.d.ts +0 -9
- package/dist/mcp/tools/goal.d.ts.map +0 -1
- package/dist/mcp/tools/handoff-packets.d.ts +0 -9
- package/dist/mcp/tools/handoff-packets.d.ts.map +0 -1
- package/dist/mcp/tools/import-export-bridge.d.ts +0 -9
- package/dist/mcp/tools/import-export-bridge.d.ts.map +0 -1
- package/dist/mcp/tools/inbox-intake.d.ts +0 -9
- package/dist/mcp/tools/inbox-intake.d.ts.map +0 -1
- package/dist/mcp/tools/issue-importers.d.ts +0 -9
- package/dist/mcp/tools/issue-importers.d.ts.map +0 -1
- package/dist/mcp/tools/json-schemas.d.ts +0 -8
- package/dist/mcp/tools/json-schemas.d.ts.map +0 -1
- package/dist/mcp/tools/machine-topology.d.ts +0 -8
- package/dist/mcp/tools/machine-topology.d.ts.map +0 -1
- package/dist/mcp/tools/mention-resolver.d.ts +0 -9
- package/dist/mcp/tools/mention-resolver.d.ts.map +0 -1
- package/dist/mcp/tools/nl-intake.d.ts +0 -9
- package/dist/mcp/tools/nl-intake.d.ts.map +0 -1
- package/dist/mcp/tools/notification-reminders.d.ts +0 -9
- package/dist/mcp/tools/notification-reminders.d.ts.map +0 -1
- package/dist/mcp/tools/parity.d.ts +0 -8
- package/dist/mcp/tools/parity.d.ts.map +0 -1
- package/dist/mcp/tools/plan-execution.d.ts +0 -9
- package/dist/mcp/tools/plan-execution.d.ts.map +0 -1
- package/dist/mcp/tools/policy-packs.d.ts +0 -9
- package/dist/mcp/tools/policy-packs.d.ts.map +0 -1
- package/dist/mcp/tools/project-bootstrap.d.ts +0 -8
- package/dist/mcp/tools/project-bootstrap.d.ts.map +0 -1
- package/dist/mcp/tools/release-checks.d.ts +0 -8
- package/dist/mcp/tools/release-checks.d.ts.map +0 -1
- package/dist/mcp/tools/release-notes.d.ts +0 -9
- package/dist/mcp/tools/release-notes.d.ts.map +0 -1
- package/dist/mcp/tools/report-exports.d.ts +0 -9
- package/dist/mcp/tools/report-exports.d.ts.map +0 -1
- package/dist/mcp/tools/resource-subscriptions.d.ts +0 -8
- package/dist/mcp/tools/resource-subscriptions.d.ts.map +0 -1
- package/dist/mcp/tools/run-records.d.ts +0 -9
- package/dist/mcp/tools/run-records.d.ts.map +0 -1
- package/dist/mcp/tools/sandbox.d.ts +0 -8
- package/dist/mcp/tools/sandbox.d.ts.map +0 -1
- package/dist/mcp/tools/saved-views.d.ts +0 -9
- package/dist/mcp/tools/saved-views.d.ts.map +0 -1
- package/dist/mcp/tools/secret-redaction.d.ts +0 -8
- package/dist/mcp/tools/secret-redaction.d.ts.map +0 -1
- package/dist/mcp/tools/task-dedupe.d.ts +0 -9
- package/dist/mcp/tools/task-dedupe.d.ts.map +0 -1
- package/dist/mcp/tools/task-scheduling.d.ts +0 -9
- package/dist/mcp/tools/task-scheduling.d.ts.map +0 -1
- package/dist/mcp/tools/template-library.d.ts +0 -8
- package/dist/mcp/tools/template-library.d.ts.map +0 -1
- package/dist/mcp/tools/terminal-notifications.d.ts +0 -9
- package/dist/mcp/tools/terminal-notifications.d.ts.map +0 -1
- package/dist/mcp/tools/todos-md.d.ts +0 -8
- package/dist/mcp/tools/todos-md.d.ts.map +0 -1
- package/dist/mcp/tools/user-scaffolds.d.ts +0 -8
- package/dist/mcp/tools/user-scaffolds.d.ts.map +0 -1
- package/dist/mcp/tools/verification.d.ts +0 -9
- package/dist/mcp/tools/verification.d.ts.map +0 -1
- package/dist/mcp/tools/webhooks.d.ts +0 -8
- package/dist/mcp/tools/webhooks.d.ts.map +0 -1
- package/dist/mcp/tools/workspace-trust.d.ts +0 -8
- package/dist/mcp/tools/workspace-trust.d.ts.map +0 -1
- package/dist/test/no-network.d.ts +0 -7
- package/dist/test/no-network.d.ts.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -1273,6 +1273,15 @@ function ensureSchema(db) {
|
|
|
1273
1273
|
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
1274
1274
|
tag TEXT NOT NULL, PRIMARY KEY (task_id, tag)
|
|
1275
1275
|
)`);
|
|
1276
|
+
ensureTable("tags", `
|
|
1277
|
+
CREATE TABLE tags (
|
|
1278
|
+
id TEXT PRIMARY KEY,
|
|
1279
|
+
name TEXT NOT NULL UNIQUE,
|
|
1280
|
+
color TEXT,
|
|
1281
|
+
description TEXT,
|
|
1282
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1283
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1284
|
+
)`);
|
|
1276
1285
|
ensureTable("task_dependencies", `
|
|
1277
1286
|
CREATE TABLE task_dependencies (
|
|
1278
1287
|
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
@@ -1486,6 +1495,36 @@ function ensureSchema(db) {
|
|
|
1486
1495
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_git_refs_task ON task_git_refs(task_id)");
|
|
1487
1496
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_git_refs_lookup ON task_git_refs(ref_type, name)");
|
|
1488
1497
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_git_refs_url ON task_git_refs(url)");
|
|
1498
|
+
ensureTable("task_commits", `
|
|
1499
|
+
CREATE TABLE task_commits (
|
|
1500
|
+
id TEXT PRIMARY KEY,
|
|
1501
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
1502
|
+
sha TEXT NOT NULL,
|
|
1503
|
+
message TEXT,
|
|
1504
|
+
author TEXT,
|
|
1505
|
+
files_changed TEXT,
|
|
1506
|
+
committed_at TEXT,
|
|
1507
|
+
branch TEXT,
|
|
1508
|
+
pr_url TEXT,
|
|
1509
|
+
pr_number INTEGER,
|
|
1510
|
+
pr_state TEXT,
|
|
1511
|
+
ci_snapshot TEXT,
|
|
1512
|
+
release_tag TEXT,
|
|
1513
|
+
repo_path TEXT,
|
|
1514
|
+
traceability TEXT DEFAULT '{}',
|
|
1515
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1516
|
+
UNIQUE(task_id, sha)
|
|
1517
|
+
)`);
|
|
1518
|
+
ensureColumn("task_commits", "branch", "TEXT");
|
|
1519
|
+
ensureColumn("task_commits", "pr_url", "TEXT");
|
|
1520
|
+
ensureColumn("task_commits", "pr_number", "INTEGER");
|
|
1521
|
+
ensureColumn("task_commits", "pr_state", "TEXT");
|
|
1522
|
+
ensureColumn("task_commits", "ci_snapshot", "TEXT");
|
|
1523
|
+
ensureColumn("task_commits", "release_tag", "TEXT");
|
|
1524
|
+
ensureColumn("task_commits", "repo_path", "TEXT");
|
|
1525
|
+
ensureColumn("task_commits", "traceability", "TEXT DEFAULT '{}'");
|
|
1526
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_commits_task ON task_commits(task_id)");
|
|
1527
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_commits_sha ON task_commits(sha)");
|
|
1489
1528
|
ensureTable("task_verifications", `
|
|
1490
1529
|
CREATE TABLE task_verifications (
|
|
1491
1530
|
id TEXT PRIMARY KEY,
|
|
@@ -1670,6 +1709,9 @@ function ensureSchema(db) {
|
|
|
1670
1709
|
ensureColumn("tasks", "max_retries", "INTEGER DEFAULT 3");
|
|
1671
1710
|
ensureColumn("tasks", "retry_after", "TEXT");
|
|
1672
1711
|
ensureColumn("tasks", "sla_minutes", "INTEGER");
|
|
1712
|
+
ensureColumn("tasks", "scheduled_start_at", "TEXT");
|
|
1713
|
+
ensureColumn("tasks", "priority_score", "INTEGER");
|
|
1714
|
+
ensureColumn("tasks", "priority_reason", "TEXT");
|
|
1673
1715
|
ensureColumn("tasks", "archived_at", "TEXT");
|
|
1674
1716
|
ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
|
|
1675
1717
|
ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
|
|
@@ -1792,6 +1834,7 @@ function ensureSchema(db) {
|
|
|
1792
1834
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_lists_slug ON task_lists(slug)");
|
|
1793
1835
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_tags_tag ON task_tags(tag)");
|
|
1794
1836
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_tags_task ON task_tags(task_id)");
|
|
1837
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tags_name ON tags(name)");
|
|
1795
1838
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_plans_project ON plans(project_id)");
|
|
1796
1839
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_plans_status ON plans(status)");
|
|
1797
1840
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_plans_task_list ON plans(task_list_id)");
|
|
@@ -1929,6 +1972,217 @@ function ensureSchema(db) {
|
|
|
1929
1972
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_cycles_dates ON cycles(start_date, end_date)");
|
|
1930
1973
|
ensureColumn("tasks", "cycle_id", "TEXT REFERENCES cycles(id) ON DELETE SET NULL");
|
|
1931
1974
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_cycle ON tasks(cycle_id) WHERE cycle_id IS NOT NULL");
|
|
1975
|
+
ensureTable("labels", `
|
|
1976
|
+
CREATE TABLE labels (
|
|
1977
|
+
id TEXT PRIMARY KEY,
|
|
1978
|
+
project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
|
|
1979
|
+
name TEXT NOT NULL,
|
|
1980
|
+
color TEXT,
|
|
1981
|
+
description TEXT,
|
|
1982
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1983
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1984
|
+
UNIQUE(project_id, name)
|
|
1985
|
+
)`);
|
|
1986
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_labels_project ON labels(project_id)");
|
|
1987
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_labels_name ON labels(name)");
|
|
1988
|
+
ensureTable("task_labels", `
|
|
1989
|
+
CREATE TABLE task_labels (
|
|
1990
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
1991
|
+
label_id TEXT NOT NULL REFERENCES labels(id) ON DELETE CASCADE,
|
|
1992
|
+
PRIMARY KEY (task_id, label_id)
|
|
1993
|
+
)`);
|
|
1994
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_labels_task ON task_labels(task_id)");
|
|
1995
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_labels_label ON task_labels(label_id)");
|
|
1996
|
+
ensureTable("custom_field_definitions", `
|
|
1997
|
+
CREATE TABLE custom_field_definitions (
|
|
1998
|
+
id TEXT PRIMARY KEY,
|
|
1999
|
+
project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
|
|
2000
|
+
name TEXT NOT NULL,
|
|
2001
|
+
slug TEXT NOT NULL,
|
|
2002
|
+
field_type TEXT NOT NULL CHECK(field_type IN ('text', 'number', 'boolean', 'date', 'enum')),
|
|
2003
|
+
options TEXT DEFAULT '[]',
|
|
2004
|
+
required INTEGER NOT NULL DEFAULT 0,
|
|
2005
|
+
default_value TEXT,
|
|
2006
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
2007
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2008
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2009
|
+
UNIQUE(project_id, slug)
|
|
2010
|
+
)`);
|
|
2011
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_custom_fields_project ON custom_field_definitions(project_id)");
|
|
2012
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_custom_fields_slug ON custom_field_definitions(slug)");
|
|
2013
|
+
ensureTable("task_custom_field_values", `
|
|
2014
|
+
CREATE TABLE task_custom_field_values (
|
|
2015
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
2016
|
+
field_id TEXT NOT NULL REFERENCES custom_field_definitions(id) ON DELETE CASCADE,
|
|
2017
|
+
value TEXT,
|
|
2018
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2019
|
+
PRIMARY KEY (task_id, field_id)
|
|
2020
|
+
)`);
|
|
2021
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_custom_values_task ON task_custom_field_values(task_id)");
|
|
2022
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_custom_values_field ON task_custom_field_values(field_id)");
|
|
2023
|
+
ensureTable("saved_views", `
|
|
2024
|
+
CREATE TABLE saved_views (
|
|
2025
|
+
id TEXT PRIMARY KEY,
|
|
2026
|
+
name TEXT NOT NULL UNIQUE,
|
|
2027
|
+
slug TEXT NOT NULL UNIQUE,
|
|
2028
|
+
entity_type TEXT NOT NULL DEFAULT 'task',
|
|
2029
|
+
filters TEXT NOT NULL DEFAULT '{}',
|
|
2030
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2031
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2032
|
+
)`);
|
|
2033
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_saved_views_slug ON saved_views(slug)");
|
|
2034
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_saved_views_entity ON saved_views(entity_type)");
|
|
2035
|
+
ensureTable("decision_records", `
|
|
2036
|
+
CREATE TABLE decision_records (
|
|
2037
|
+
id TEXT PRIMARY KEY,
|
|
2038
|
+
project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
|
|
2039
|
+
task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
|
|
2040
|
+
plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
|
|
2041
|
+
agent_id TEXT,
|
|
2042
|
+
sequence_num INTEGER NOT NULL,
|
|
2043
|
+
short_ref TEXT NOT NULL UNIQUE,
|
|
2044
|
+
title TEXT NOT NULL,
|
|
2045
|
+
status TEXT NOT NULL DEFAULT 'proposed' CHECK(status IN ('proposed', 'accepted', 'deprecated', 'superseded', 'rejected')),
|
|
2046
|
+
context TEXT,
|
|
2047
|
+
decision TEXT NOT NULL,
|
|
2048
|
+
consequences TEXT,
|
|
2049
|
+
alternatives TEXT DEFAULT '[]',
|
|
2050
|
+
tags TEXT DEFAULT '[]',
|
|
2051
|
+
supersedes_id TEXT REFERENCES decision_records(id) ON DELETE SET NULL,
|
|
2052
|
+
superseded_by_id TEXT REFERENCES decision_records(id) ON DELETE SET NULL,
|
|
2053
|
+
metadata TEXT DEFAULT '{}',
|
|
2054
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2055
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2056
|
+
)`);
|
|
2057
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_decision_records_project ON decision_records(project_id)");
|
|
2058
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_decision_records_task ON decision_records(task_id)");
|
|
2059
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_decision_records_plan ON decision_records(plan_id)");
|
|
2060
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_decision_records_status ON decision_records(status)");
|
|
2061
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_decision_records_short_ref ON decision_records(short_ref)");
|
|
2062
|
+
ensureTable("knowledge_snapshots", `
|
|
2063
|
+
CREATE TABLE knowledge_snapshots (
|
|
2064
|
+
id TEXT PRIMARY KEY,
|
|
2065
|
+
project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
|
|
2066
|
+
title TEXT NOT NULL,
|
|
2067
|
+
summary TEXT,
|
|
2068
|
+
content_hash TEXT NOT NULL,
|
|
2069
|
+
snapshot TEXT NOT NULL,
|
|
2070
|
+
decision_ids TEXT DEFAULT '[]',
|
|
2071
|
+
topics TEXT DEFAULT '[]',
|
|
2072
|
+
source TEXT NOT NULL DEFAULT 'auto' CHECK(source IN ('manual', 'auto', 'import')),
|
|
2073
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2074
|
+
)`);
|
|
2075
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_knowledge_snapshots_project ON knowledge_snapshots(project_id)");
|
|
2076
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_knowledge_snapshots_hash ON knowledge_snapshots(content_hash)");
|
|
2077
|
+
ensureTable("verification_records", `
|
|
2078
|
+
CREATE TABLE verification_records (
|
|
2079
|
+
id TEXT PRIMARY KEY,
|
|
2080
|
+
task_id TEXT REFERENCES tasks(id) ON DELETE CASCADE,
|
|
2081
|
+
provider_name TEXT NOT NULL,
|
|
2082
|
+
provider_type TEXT NOT NULL,
|
|
2083
|
+
status TEXT NOT NULL DEFAULT 'unknown' CHECK(status IN ('passed', 'failed', 'unknown')),
|
|
2084
|
+
summary TEXT,
|
|
2085
|
+
evidence TEXT DEFAULT '{}',
|
|
2086
|
+
artifact_id TEXT,
|
|
2087
|
+
started_at TEXT,
|
|
2088
|
+
completed_at TEXT,
|
|
2089
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2090
|
+
)`);
|
|
2091
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_verification_records_task ON verification_records(task_id)");
|
|
2092
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_verification_records_status ON verification_records(status)");
|
|
2093
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_verification_records_created ON verification_records(created_at)");
|
|
2094
|
+
ensureTable("task_leases", `
|
|
2095
|
+
CREATE TABLE task_leases (
|
|
2096
|
+
task_id TEXT PRIMARY KEY REFERENCES tasks(id) ON DELETE CASCADE,
|
|
2097
|
+
agent_id TEXT NOT NULL,
|
|
2098
|
+
acquired_at TEXT NOT NULL,
|
|
2099
|
+
expires_at TEXT NOT NULL,
|
|
2100
|
+
heartbeat_at TEXT,
|
|
2101
|
+
steal_count INTEGER NOT NULL DEFAULT 0,
|
|
2102
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2103
|
+
)`);
|
|
2104
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_leases_agent ON task_leases(agent_id)");
|
|
2105
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_leases_expires ON task_leases(expires_at)");
|
|
2106
|
+
ensureTable("reminder_preferences", `
|
|
2107
|
+
CREATE TABLE reminder_preferences (
|
|
2108
|
+
id TEXT PRIMARY KEY,
|
|
2109
|
+
due_soon_hours INTEGER NOT NULL DEFAULT 24,
|
|
2110
|
+
sla_warning_minutes INTEGER NOT NULL DEFAULT 30,
|
|
2111
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
2112
|
+
desktop_notify INTEGER NOT NULL DEFAULT 0,
|
|
2113
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2114
|
+
)`);
|
|
2115
|
+
ensureTable("notification_reminders", `
|
|
2116
|
+
CREATE TABLE notification_reminders (
|
|
2117
|
+
id TEXT PRIMARY KEY,
|
|
2118
|
+
task_id TEXT REFERENCES tasks(id) ON DELETE CASCADE,
|
|
2119
|
+
reminder_type TEXT NOT NULL CHECK(reminder_type IN ('due_soon', 'due_overdue', 'sla_warning', 'sla_breach', 'custom')),
|
|
2120
|
+
title TEXT NOT NULL,
|
|
2121
|
+
message TEXT,
|
|
2122
|
+
trigger_at TEXT NOT NULL,
|
|
2123
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'fired', 'dismissed', 'snoozed')),
|
|
2124
|
+
snoozed_until TEXT,
|
|
2125
|
+
project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
|
|
2126
|
+
agent_id TEXT,
|
|
2127
|
+
priority TEXT NOT NULL DEFAULT 'medium',
|
|
2128
|
+
metadata TEXT DEFAULT '{}',
|
|
2129
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2130
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2131
|
+
fired_at TEXT,
|
|
2132
|
+
dismissed_at TEXT
|
|
2133
|
+
)`);
|
|
2134
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_notification_reminders_task ON notification_reminders(task_id)");
|
|
2135
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_notification_reminders_status ON notification_reminders(status)");
|
|
2136
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_notification_reminders_trigger ON notification_reminders(trigger_at)");
|
|
2137
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_notification_reminders_project ON notification_reminders(project_id)");
|
|
2138
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_notification_reminders_agent ON notification_reminders(agent_id)");
|
|
2139
|
+
ensureTable("run_records", `
|
|
2140
|
+
CREATE TABLE run_records (
|
|
2141
|
+
id TEXT PRIMARY KEY,
|
|
2142
|
+
agent_run_id TEXT,
|
|
2143
|
+
agent_id TEXT,
|
|
2144
|
+
objective TEXT,
|
|
2145
|
+
plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
|
|
2146
|
+
claimed_task_ids TEXT DEFAULT '[]',
|
|
2147
|
+
commands TEXT DEFAULT '[]',
|
|
2148
|
+
stdout_summary TEXT,
|
|
2149
|
+
stderr_summary TEXT,
|
|
2150
|
+
files_touched TEXT DEFAULT '[]',
|
|
2151
|
+
verification_results TEXT DEFAULT '[]',
|
|
2152
|
+
artifact_ids TEXT DEFAULT '[]',
|
|
2153
|
+
status_transitions TEXT DEFAULT '[]',
|
|
2154
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'completed', 'failed', 'archived')),
|
|
2155
|
+
replay_bundle TEXT,
|
|
2156
|
+
metadata TEXT DEFAULT '{}',
|
|
2157
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2158
|
+
completed_at TEXT,
|
|
2159
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2160
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2161
|
+
)`);
|
|
2162
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_run_records_agent_run ON run_records(agent_run_id)");
|
|
2163
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_run_records_agent ON run_records(agent_id)");
|
|
2164
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_run_records_plan ON run_records(plan_id)");
|
|
2165
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_run_records_status ON run_records(status)");
|
|
2166
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_run_records_started ON run_records(started_at)");
|
|
2167
|
+
ensureTable("activity_log", `
|
|
2168
|
+
CREATE TABLE activity_log (
|
|
2169
|
+
id TEXT PRIMARY KEY,
|
|
2170
|
+
entity_type TEXT NOT NULL,
|
|
2171
|
+
entity_id TEXT NOT NULL,
|
|
2172
|
+
action TEXT NOT NULL,
|
|
2173
|
+
field TEXT,
|
|
2174
|
+
old_value TEXT,
|
|
2175
|
+
new_value TEXT,
|
|
2176
|
+
actor_id TEXT,
|
|
2177
|
+
session_id TEXT,
|
|
2178
|
+
machine_id TEXT,
|
|
2179
|
+
metadata TEXT DEFAULT '{}',
|
|
2180
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2181
|
+
)`);
|
|
2182
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_activity_log_entity ON activity_log(entity_type, entity_id)");
|
|
2183
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_activity_log_actor ON activity_log(actor_id)");
|
|
2184
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_activity_log_action ON activity_log(action)");
|
|
2185
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_activity_log_created ON activity_log(created_at)");
|
|
1932
2186
|
ensureTable("api_keys", `
|
|
1933
2187
|
CREATE TABLE api_keys (
|
|
1934
2188
|
id TEXT PRIMARY KEY,
|
|
@@ -2380,11 +2634,17 @@ function ensureDir(filePath) {
|
|
|
2380
2634
|
}
|
|
2381
2635
|
}
|
|
2382
2636
|
function getDatabase(dbPath) {
|
|
2383
|
-
if (_db)
|
|
2384
|
-
return _db;
|
|
2385
2637
|
const path = dbPath || getDbPath();
|
|
2638
|
+
if (_db && _dbPath === path)
|
|
2639
|
+
return _db;
|
|
2640
|
+
if (_db && _dbPath !== path) {
|
|
2641
|
+
_db.close();
|
|
2642
|
+
_db = null;
|
|
2643
|
+
_dbPath = null;
|
|
2644
|
+
}
|
|
2386
2645
|
ensureDir(path);
|
|
2387
2646
|
_db = new Database(path);
|
|
2647
|
+
_dbPath = path;
|
|
2388
2648
|
_db.run("PRAGMA journal_mode = WAL");
|
|
2389
2649
|
_db.run("PRAGMA busy_timeout = 5000");
|
|
2390
2650
|
_db.run("PRAGMA foreign_keys = ON");
|
|
@@ -2397,10 +2657,12 @@ function closeDatabase() {
|
|
|
2397
2657
|
if (_db) {
|
|
2398
2658
|
_db.close();
|
|
2399
2659
|
_db = null;
|
|
2660
|
+
_dbPath = null;
|
|
2400
2661
|
}
|
|
2401
2662
|
}
|
|
2402
2663
|
function resetDatabase() {
|
|
2403
2664
|
_db = null;
|
|
2665
|
+
_dbPath = null;
|
|
2404
2666
|
}
|
|
2405
2667
|
function now() {
|
|
2406
2668
|
return new Date().toISOString();
|
|
@@ -2461,7 +2723,7 @@ function resolvePartialId(db, table, partialId) {
|
|
|
2461
2723
|
}
|
|
2462
2724
|
return null;
|
|
2463
2725
|
}
|
|
2464
|
-
var LOCK_EXPIRY_MINUTES = 30, _db = null, ALLOWED_TABLES;
|
|
2726
|
+
var LOCK_EXPIRY_MINUTES = 30, _db = null, _dbPath = null, ALLOWED_TABLES;
|
|
2465
2727
|
var init_database = __esm(() => {
|
|
2466
2728
|
init_schema();
|
|
2467
2729
|
init_machines();
|
|
@@ -3784,9 +4046,10 @@ function redactExportRecord(record) {
|
|
|
3784
4046
|
}
|
|
3785
4047
|
return base;
|
|
3786
4048
|
}
|
|
3787
|
-
var REDACTION_PLACEHOLDER = "[REDACTED]", DEFAULT_PATTERNS, DEFAULT_ALLOWLIST, customRedactors;
|
|
4049
|
+
var SECRET_REDACTION_SCHEMA, REDACTION_PLACEHOLDER = "[REDACTED]", DEFAULT_PATTERNS, DEFAULT_ALLOWLIST, customRedactors;
|
|
3788
4050
|
var init_secret_redaction = __esm(() => {
|
|
3789
4051
|
init_redaction();
|
|
4052
|
+
SECRET_REDACTION_SCHEMA = ["todos", "secret_redaction", "v1"].join(".");
|
|
3790
4053
|
DEFAULT_PATTERNS = [
|
|
3791
4054
|
{ name: "openai_sk", pattern: /\bsk-[a-zA-Z0-9]{10,}\b/g },
|
|
3792
4055
|
{ name: "github_pat", pattern: /\bghp_[a-zA-Z0-9]{20,}\b/g },
|
|
@@ -7654,11 +7917,19 @@ function getTaskVerifications(taskId, db) {
|
|
|
7654
7917
|
}
|
|
7655
7918
|
function getTaskTraceability(taskId, db) {
|
|
7656
7919
|
const d = db || getDatabase();
|
|
7920
|
+
const commits = getTaskCommits(taskId, d);
|
|
7921
|
+
const gitRefs = getTaskGitRefs(taskId, d);
|
|
7657
7922
|
return {
|
|
7658
7923
|
task_id: taskId,
|
|
7659
|
-
commits
|
|
7660
|
-
git_refs:
|
|
7661
|
-
verifications: getTaskVerifications(taskId, d)
|
|
7924
|
+
commits,
|
|
7925
|
+
git_refs: gitRefs,
|
|
7926
|
+
verifications: getTaskVerifications(taskId, d),
|
|
7927
|
+
branches: Array.from(new Set([
|
|
7928
|
+
...commits.map((commit) => commit.branch).filter((branch) => Boolean(branch)),
|
|
7929
|
+
...gitRefs.filter((ref) => ref.ref_type === "branch").map((ref) => ref.name)
|
|
7930
|
+
])).sort(),
|
|
7931
|
+
release_tags: Array.from(new Set(commits.map((commit) => commit.release_tag).filter((tag) => Boolean(tag)))).sort(),
|
|
7932
|
+
pull_requests: commits.filter((commit) => commit.pr_url).map((commit) => ({ url: commit.pr_url, state: commit.pr_state, number: commit.pr_number }))
|
|
7662
7933
|
};
|
|
7663
7934
|
}
|
|
7664
7935
|
var init_task_commits = __esm(() => {
|
|
@@ -9184,22 +9455,27 @@ function getHeadlessBoundaryManifest() {
|
|
|
9184
9455
|
notes: [
|
|
9185
9456
|
"Use todos CLI or todos-mcp for agent workflows.",
|
|
9186
9457
|
"todos serve exposes a local-only REST API on 127.0.0.1 \u2014 not a hosted SaaS.",
|
|
9187
|
-
"
|
|
9458
|
+
"Remote sync is explicit opt-in from CLI/MCP, never from the dashboard."
|
|
9188
9459
|
]
|
|
9189
9460
|
};
|
|
9190
9461
|
}
|
|
9191
|
-
var HEADLESS_BOUNDARY_VERSION = "todos.headless-boundary.v1", FORBIDDEN_HOSTED_HOSTS, FORBIDDEN_WEB_PATTERNS, LOCAL_HOSTS;
|
|
9462
|
+
var HEADLESS_BOUNDARY_VERSION = "todos.headless-boundary.v1", FORBIDDEN_HOSTED_HOSTS, PRIVATE_PLATFORM_ORG, HOSTED_TODOS_PACKAGE, FORBIDDEN_WEB_PATTERNS, LOCAL_HOSTS;
|
|
9192
9463
|
var init_headless_boundaries = __esm(() => {
|
|
9193
9464
|
FORBIDDEN_HOSTED_HOSTS = [
|
|
9194
9465
|
"todos.md",
|
|
9195
9466
|
"www.todos.md",
|
|
9196
9467
|
"preview.todos.md",
|
|
9197
9468
|
"pay.hasna.tools",
|
|
9198
|
-
"platform
|
|
9469
|
+
["platform", "todos"].join("-")
|
|
9199
9470
|
];
|
|
9471
|
+
PRIVATE_PLATFORM_ORG = ["hasna", "studio"].join("");
|
|
9472
|
+
HOSTED_TODOS_PACKAGE = ["platform", "todos"].join("-");
|
|
9200
9473
|
FORBIDDEN_WEB_PATTERNS = [
|
|
9201
9474
|
{ name: "hosted todos.md API", pattern: /https?:\/\/(?:www\.)?todos\.md/i },
|
|
9202
|
-
{
|
|
9475
|
+
{
|
|
9476
|
+
name: "hosted platform package",
|
|
9477
|
+
pattern: new RegExp(`@${PRIVATE_PLATFORM_ORG}/${HOSTED_TODOS_PACKAGE}|${PRIVATE_PLATFORM_ORG}/${HOSTED_TODOS_PACKAGE}`, "i")
|
|
9478
|
+
},
|
|
9203
9479
|
{ name: "browser sign-in flow", pattern: /\/sign-?in\b|\/login\b.*(?:oauth|session|auth)/i },
|
|
9204
9480
|
{ name: "Stripe billing UI", pattern: /\bstripe\.(?:com|js)\b|\bcheckout\.sessions?\b/i },
|
|
9205
9481
|
{ name: "hosted OAuth redirect", pattern: /oauth.*redirect.*todos\.md/i }
|
|
@@ -31716,6 +31992,13 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
31716
31992
|
}
|
|
31717
31993
|
return current.version;
|
|
31718
31994
|
}
|
|
31995
|
+
function resolveAssignee(value) {
|
|
31996
|
+
try {
|
|
31997
|
+
return resolveId(value, "agents");
|
|
31998
|
+
} catch {
|
|
31999
|
+
return value;
|
|
32000
|
+
}
|
|
32001
|
+
}
|
|
31719
32002
|
if (shouldRegisterTool("create_task")) {
|
|
31720
32003
|
server.tool("create_task", "Create a new task in a project. Pass short_id=null to auto-generate.", {
|
|
31721
32004
|
title: exports_external.string().describe("Task title"),
|
|
@@ -31738,7 +32021,7 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
31738
32021
|
const { depends_on, assigned_to, project_id, task_list_id, tags, estimate, confidence, retry_count, deadline, ...rest } = params;
|
|
31739
32022
|
const resolved = { ...rest };
|
|
31740
32023
|
if (assigned_to)
|
|
31741
|
-
resolved.assigned_to =
|
|
32024
|
+
resolved.assigned_to = resolveAssignee(assigned_to);
|
|
31742
32025
|
if (project_id)
|
|
31743
32026
|
resolved.project_id = resolveId(project_id, "projects");
|
|
31744
32027
|
if (task_list_id)
|
|
@@ -31782,7 +32065,7 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
31782
32065
|
if (params.task_list_id)
|
|
31783
32066
|
resolved.task_list_id = resolveId(params.task_list_id, "task_lists");
|
|
31784
32067
|
if (params.assigned_to)
|
|
31785
|
-
resolved.assigned_to =
|
|
32068
|
+
resolved.assigned_to = resolveAssignee(params.assigned_to);
|
|
31786
32069
|
const tasks = listTasks(resolved, undefined);
|
|
31787
32070
|
if (tasks.length === 0)
|
|
31788
32071
|
return { content: [{ type: "text", text: "No tasks found." }] };
|
|
@@ -31879,7 +32162,7 @@ ${task.description}` : null
|
|
|
31879
32162
|
if (resolved.assigned_to === "")
|
|
31880
32163
|
resolved.assigned_to = null;
|
|
31881
32164
|
if (resolved.assigned_to && typeof resolved.assigned_to === "string")
|
|
31882
|
-
resolved.assigned_to =
|
|
32165
|
+
resolved.assigned_to = resolveAssignee(resolved.assigned_to);
|
|
31883
32166
|
if (resolved.project_id && typeof resolved.project_id === "string")
|
|
31884
32167
|
resolved.project_id = resolveId(resolved.project_id, "projects");
|
|
31885
32168
|
if (resolved.task_list_id && typeof resolved.task_list_id === "string")
|
|
@@ -32093,6 +32376,25 @@ var init_project_bootstrap = __esm(() => {
|
|
|
32093
32376
|
function rowToLabel(row) {
|
|
32094
32377
|
return { ...row };
|
|
32095
32378
|
}
|
|
32379
|
+
function normalizeName(name) {
|
|
32380
|
+
return name.trim().toLowerCase();
|
|
32381
|
+
}
|
|
32382
|
+
function createLabel(input, db) {
|
|
32383
|
+
const d = db || getDatabase();
|
|
32384
|
+
const id = uuid();
|
|
32385
|
+
const ts = now();
|
|
32386
|
+
d.run(`INSERT INTO labels (id, project_id, name, color, description, created_at, updated_at)
|
|
32387
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`, [id, input.project_id ?? null, input.name.trim(), input.color ?? null, input.description ?? null, ts, ts]);
|
|
32388
|
+
return rowToLabel(d.query("SELECT * FROM labels WHERE id = ?").get(id));
|
|
32389
|
+
}
|
|
32390
|
+
function getLabel(idOrName, db) {
|
|
32391
|
+
const d = db || getDatabase();
|
|
32392
|
+
let row = d.query("SELECT * FROM labels WHERE id = ?").get(idOrName);
|
|
32393
|
+
if (!row) {
|
|
32394
|
+
row = d.query("SELECT * FROM labels WHERE lower(name) = ?").get(normalizeName(idOrName));
|
|
32395
|
+
}
|
|
32396
|
+
return row ? rowToLabel(row) : null;
|
|
32397
|
+
}
|
|
32096
32398
|
function listLabels(projectId, db) {
|
|
32097
32399
|
const d = db || getDatabase();
|
|
32098
32400
|
if (projectId) {
|
|
@@ -32100,10 +32402,164 @@ function listLabels(projectId, db) {
|
|
|
32100
32402
|
}
|
|
32101
32403
|
return d.query("SELECT * FROM labels ORDER BY name").all().map(rowToLabel);
|
|
32102
32404
|
}
|
|
32405
|
+
function updateLabel(idOrName, input, db) {
|
|
32406
|
+
const d = db || getDatabase();
|
|
32407
|
+
const existing = getLabel(idOrName, d);
|
|
32408
|
+
if (!existing)
|
|
32409
|
+
throw new Error(`Label not found: ${idOrName}`);
|
|
32410
|
+
const ts = now();
|
|
32411
|
+
d.run(`UPDATE labels SET
|
|
32412
|
+
name = COALESCE(?, name),
|
|
32413
|
+
color = COALESCE(?, color),
|
|
32414
|
+
description = COALESCE(?, description),
|
|
32415
|
+
updated_at = ?
|
|
32416
|
+
WHERE id = ?`, [input.name?.trim() ?? null, input.color ?? null, input.description ?? null, ts, existing.id]);
|
|
32417
|
+
return getLabel(existing.id, d);
|
|
32418
|
+
}
|
|
32419
|
+
function deleteLabel(idOrName, db) {
|
|
32420
|
+
const d = db || getDatabase();
|
|
32421
|
+
const existing = getLabel(idOrName, d);
|
|
32422
|
+
if (!existing)
|
|
32423
|
+
return false;
|
|
32424
|
+
d.run("DELETE FROM task_labels WHERE label_id = ?", [existing.id]);
|
|
32425
|
+
return d.run("DELETE FROM labels WHERE id = ?", [existing.id]).changes > 0;
|
|
32426
|
+
}
|
|
32427
|
+
function assignLabelToTask(taskId, labelIdOrName, db) {
|
|
32428
|
+
const d = db || getDatabase();
|
|
32429
|
+
const label = getLabel(labelIdOrName, d);
|
|
32430
|
+
if (!label)
|
|
32431
|
+
throw new Error(`Label not found: ${labelIdOrName}`);
|
|
32432
|
+
d.run("INSERT OR IGNORE INTO task_labels (task_id, label_id) VALUES (?, ?)", [taskId, label.id]);
|
|
32433
|
+
d.run("INSERT OR IGNORE INTO task_tags (task_id, tag) VALUES (?, ?)", [taskId, label.name]);
|
|
32434
|
+
return label;
|
|
32435
|
+
}
|
|
32103
32436
|
var init_labels = __esm(() => {
|
|
32104
32437
|
init_database();
|
|
32105
32438
|
});
|
|
32106
32439
|
|
|
32440
|
+
// src/db/tags.ts
|
|
32441
|
+
function normalizeName2(name) {
|
|
32442
|
+
return name.trim();
|
|
32443
|
+
}
|
|
32444
|
+
function taskCount(name, db) {
|
|
32445
|
+
const row = db.query("SELECT COUNT(*) AS count FROM task_tags WHERE tag = ?").get(name);
|
|
32446
|
+
return row?.count ?? 0;
|
|
32447
|
+
}
|
|
32448
|
+
function rowToTag(row, db) {
|
|
32449
|
+
return {
|
|
32450
|
+
...row,
|
|
32451
|
+
task_count: taskCount(row.name, db)
|
|
32452
|
+
};
|
|
32453
|
+
}
|
|
32454
|
+
function virtualTag(name, db) {
|
|
32455
|
+
return {
|
|
32456
|
+
id: name,
|
|
32457
|
+
name,
|
|
32458
|
+
color: null,
|
|
32459
|
+
description: null,
|
|
32460
|
+
task_count: taskCount(name, db),
|
|
32461
|
+
created_at: null,
|
|
32462
|
+
updated_at: null
|
|
32463
|
+
};
|
|
32464
|
+
}
|
|
32465
|
+
function getTagRow(idOrName, db) {
|
|
32466
|
+
return db.query("SELECT * FROM tags WHERE id = ?").get(idOrName) ?? db.query("SELECT * FROM tags WHERE lower(name) = lower(?)").get(idOrName);
|
|
32467
|
+
}
|
|
32468
|
+
function updateTaskTagJson(oldName, newName, db) {
|
|
32469
|
+
const rows = db.query("SELECT id, tags FROM tasks WHERE tags IS NOT NULL AND tags != '[]'").all();
|
|
32470
|
+
const update = db.prepare("UPDATE tasks SET tags = ?, updated_at = ? WHERE id = ?");
|
|
32471
|
+
const ts = now();
|
|
32472
|
+
for (const row of rows) {
|
|
32473
|
+
if (!row.tags)
|
|
32474
|
+
continue;
|
|
32475
|
+
let tags;
|
|
32476
|
+
try {
|
|
32477
|
+
tags = JSON.parse(row.tags);
|
|
32478
|
+
} catch {
|
|
32479
|
+
continue;
|
|
32480
|
+
}
|
|
32481
|
+
if (!tags.includes(oldName))
|
|
32482
|
+
continue;
|
|
32483
|
+
const next = newName ? Array.from(new Set(tags.map((tag) => tag === oldName ? newName : tag))) : tags.filter((tag) => tag !== oldName);
|
|
32484
|
+
update.run(JSON.stringify(next), ts, row.id);
|
|
32485
|
+
}
|
|
32486
|
+
}
|
|
32487
|
+
function renameTaskTagRows(oldName, newName, db) {
|
|
32488
|
+
const rows = db.query("SELECT task_id FROM task_tags WHERE tag = ?").all(oldName);
|
|
32489
|
+
const insert = db.prepare("INSERT OR IGNORE INTO task_tags (task_id, tag) VALUES (?, ?)");
|
|
32490
|
+
for (const row of rows)
|
|
32491
|
+
insert.run(row.task_id, newName);
|
|
32492
|
+
db.run("DELETE FROM task_tags WHERE tag = ?", [oldName]);
|
|
32493
|
+
}
|
|
32494
|
+
function createTag(input, db) {
|
|
32495
|
+
const d = db || getDatabase();
|
|
32496
|
+
const name = normalizeName2(input.name);
|
|
32497
|
+
if (!name)
|
|
32498
|
+
throw new Error("Tag name is required");
|
|
32499
|
+
const id = uuid();
|
|
32500
|
+
const ts = now();
|
|
32501
|
+
d.run(`INSERT INTO tags (id, name, color, description, created_at, updated_at)
|
|
32502
|
+
VALUES (?, ?, ?, ?, ?, ?)`, [id, name, input.color ?? null, input.description ?? null, ts, ts]);
|
|
32503
|
+
return rowToTag(d.query("SELECT * FROM tags WHERE id = ?").get(id), d);
|
|
32504
|
+
}
|
|
32505
|
+
function listTags(db) {
|
|
32506
|
+
const d = db || getDatabase();
|
|
32507
|
+
const rows = d.query("SELECT * FROM tags ORDER BY name").all();
|
|
32508
|
+
const tagsByName = new Map(rows.map((row) => [row.name.toLowerCase(), rowToTag(row, d)]));
|
|
32509
|
+
const taskTags = d.query("SELECT tag, COUNT(*) AS count FROM task_tags GROUP BY tag ORDER BY tag").all();
|
|
32510
|
+
for (const row of taskTags) {
|
|
32511
|
+
const key = row.tag.toLowerCase();
|
|
32512
|
+
if (!tagsByName.has(key))
|
|
32513
|
+
tagsByName.set(key, { ...virtualTag(row.tag, d), task_count: row.count });
|
|
32514
|
+
}
|
|
32515
|
+
return [...tagsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
32516
|
+
}
|
|
32517
|
+
function getTag(idOrName, db) {
|
|
32518
|
+
const d = db || getDatabase();
|
|
32519
|
+
const row = getTagRow(idOrName, d);
|
|
32520
|
+
if (row)
|
|
32521
|
+
return rowToTag(row, d);
|
|
32522
|
+
const existing = d.query("SELECT tag FROM task_tags WHERE lower(tag) = lower(?) LIMIT 1").get(idOrName);
|
|
32523
|
+
return existing ? virtualTag(existing.tag, d) : null;
|
|
32524
|
+
}
|
|
32525
|
+
function updateTag(idOrName, input, db) {
|
|
32526
|
+
const d = db || getDatabase();
|
|
32527
|
+
const existing = getTag(idOrName, d);
|
|
32528
|
+
if (!existing)
|
|
32529
|
+
throw new Error(`Tag not found: ${idOrName}`);
|
|
32530
|
+
const row = getTagRow(existing.id, d);
|
|
32531
|
+
if (!row)
|
|
32532
|
+
createTag({ name: existing.name, color: existing.color ?? undefined, description: existing.description ?? undefined }, d);
|
|
32533
|
+
const stored = getTagRow(existing.id, d) ?? getTagRow(existing.name, d);
|
|
32534
|
+
if (!stored)
|
|
32535
|
+
throw new Error(`Tag not found: ${idOrName}`);
|
|
32536
|
+
const nextName = input.name !== undefined ? normalizeName2(input.name) : stored.name;
|
|
32537
|
+
if (!nextName)
|
|
32538
|
+
throw new Error("Tag name is required");
|
|
32539
|
+
const duplicate = getTagRow(nextName, d);
|
|
32540
|
+
if (duplicate && duplicate.id !== stored.id)
|
|
32541
|
+
throw new Error(`Tag already exists: ${nextName}`);
|
|
32542
|
+
if (nextName !== stored.name) {
|
|
32543
|
+
renameTaskTagRows(stored.name, nextName, d);
|
|
32544
|
+
updateTaskTagJson(stored.name, nextName, d);
|
|
32545
|
+
}
|
|
32546
|
+
d.run(`UPDATE tags SET name = ?, color = COALESCE(?, color), description = COALESCE(?, description), updated_at = ? WHERE id = ?`, [nextName, input.color ?? null, input.description ?? null, now(), stored.id]);
|
|
32547
|
+
return getTag(stored.id, d);
|
|
32548
|
+
}
|
|
32549
|
+
function deleteTag(idOrName, db) {
|
|
32550
|
+
const d = db || getDatabase();
|
|
32551
|
+
const existing = getTag(idOrName, d);
|
|
32552
|
+
if (!existing)
|
|
32553
|
+
return false;
|
|
32554
|
+
d.run("DELETE FROM tags WHERE id = ? OR lower(name) = lower(?)", [existing.id, existing.name]);
|
|
32555
|
+
d.run("DELETE FROM task_tags WHERE tag = ?", [existing.name]);
|
|
32556
|
+
updateTaskTagJson(existing.name, null, d);
|
|
32557
|
+
return true;
|
|
32558
|
+
}
|
|
32559
|
+
var init_tags = __esm(() => {
|
|
32560
|
+
init_database();
|
|
32561
|
+
});
|
|
32562
|
+
|
|
32107
32563
|
// src/lib/retention-cleanup.ts
|
|
32108
32564
|
import { existsSync as existsSync9, unlinkSync } from "fs";
|
|
32109
32565
|
function normalizeScopes(scopes) {
|
|
@@ -34338,18 +34794,18 @@ var init_local_fields = __esm(() => {
|
|
|
34338
34794
|
});
|
|
34339
34795
|
|
|
34340
34796
|
// src/lib/workflow-states.ts
|
|
34341
|
-
function
|
|
34797
|
+
function normalizeName3(value) {
|
|
34342
34798
|
return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
34343
34799
|
}
|
|
34344
34800
|
function isTaskStatus(value) {
|
|
34345
34801
|
return TASK_STATUSES.includes(value);
|
|
34346
34802
|
}
|
|
34347
34803
|
function normalizeState(input) {
|
|
34348
|
-
const name =
|
|
34804
|
+
const name = normalizeName3(input.name || "");
|
|
34349
34805
|
if (!name || !isTaskStatus(input.canonical_status))
|
|
34350
34806
|
return null;
|
|
34351
|
-
const aliases = [...new Set((input.aliases || []).map(
|
|
34352
|
-
const transitions = input.transitions ? [...new Set(input.transitions.map(
|
|
34807
|
+
const aliases = [...new Set((input.aliases || []).map(normalizeName3).filter((alias) => alias && alias !== name))].sort();
|
|
34808
|
+
const transitions = input.transitions ? [...new Set(input.transitions.map(normalizeName3).filter(Boolean))].sort() : null;
|
|
34353
34809
|
return {
|
|
34354
34810
|
name,
|
|
34355
34811
|
canonical_status: input.canonical_status,
|
|
@@ -34378,7 +34834,7 @@ function listWorkflowStates(projectPath) {
|
|
|
34378
34834
|
return mergeWorkflowConfig(workflowConfig);
|
|
34379
34835
|
}
|
|
34380
34836
|
function resolveWorkflowState(input, projectPath) {
|
|
34381
|
-
const normalized =
|
|
34837
|
+
const normalized = normalizeName3(input);
|
|
34382
34838
|
const states = listWorkflowStates(projectPath);
|
|
34383
34839
|
const byName = states.find((state) => state.name === normalized);
|
|
34384
34840
|
if (byName)
|
|
@@ -35368,10 +35824,10 @@ function summarizeTasks(taskIds, planIds, runIds, db) {
|
|
|
35368
35824
|
const completed = tasks.filter((task) => task.status === "completed");
|
|
35369
35825
|
const inProgress = tasks.filter((task) => task.status === "in_progress");
|
|
35370
35826
|
const pending = tasks.filter((task) => task.status === "pending");
|
|
35371
|
-
const
|
|
35372
|
-
const percent =
|
|
35827
|
+
const taskCount2 = tasks.length;
|
|
35828
|
+
const percent = taskCount2 === 0 ? 0 : Math.round(completed.length / taskCount2 * 100);
|
|
35373
35829
|
return {
|
|
35374
|
-
task_count:
|
|
35830
|
+
task_count: taskCount2,
|
|
35375
35831
|
completed_count: completed.length,
|
|
35376
35832
|
in_progress_count: inProgress.length,
|
|
35377
35833
|
pending_count: pending.length,
|
|
@@ -35379,7 +35835,7 @@ function summarizeTasks(taskIds, planIds, runIds, db) {
|
|
|
35379
35835
|
plan_count: planIds.length,
|
|
35380
35836
|
run_count: runIds.length,
|
|
35381
35837
|
percent_complete: percent,
|
|
35382
|
-
readiness:
|
|
35838
|
+
readiness: taskCount2 === 0 ? "empty" : blocked.length > 0 ? "blocked" : completed.length === taskCount2 ? "complete" : inProgress.length > 0 ? "in_progress" : "ready"
|
|
35383
35839
|
};
|
|
35384
35840
|
}
|
|
35385
35841
|
function createRoadmap(input) {
|
|
@@ -36558,7 +37014,7 @@ function normalizeScope(scope) {
|
|
|
36558
37014
|
}
|
|
36559
37015
|
return "tasks";
|
|
36560
37016
|
}
|
|
36561
|
-
function
|
|
37017
|
+
function normalizeName4(name) {
|
|
36562
37018
|
const normalized = name.trim();
|
|
36563
37019
|
if (!normalized)
|
|
36564
37020
|
throw new Error("Saved view name is required");
|
|
@@ -36808,7 +37264,7 @@ function runSavedSearch(filters = {}, scope = "tasks", db) {
|
|
|
36808
37264
|
}
|
|
36809
37265
|
function saveSearchView(input, db) {
|
|
36810
37266
|
const d = db || getDatabase();
|
|
36811
|
-
const name =
|
|
37267
|
+
const name = normalizeName4(input.name);
|
|
36812
37268
|
const timestamp3 = now();
|
|
36813
37269
|
const existing = getSearchView(name, d);
|
|
36814
37270
|
if (existing) {
|
|
@@ -38465,10 +38921,10 @@ Tasks:` : null,
|
|
|
38465
38921
|
if (shouldRegisterTool("list_tags")) {
|
|
38466
38922
|
server.tool("list_tags", "List all distinct task tags in use, with task counts.", async () => {
|
|
38467
38923
|
try {
|
|
38468
|
-
const rows =
|
|
38924
|
+
const rows = listTags();
|
|
38469
38925
|
if (rows.length === 0)
|
|
38470
38926
|
return { content: [{ type: "text", text: "No tags found." }] };
|
|
38471
|
-
const lines = rows.map((r) => `${r.
|
|
38927
|
+
const lines = rows.map((r) => `${r.color ? "[" + r.color + "] " : ""}${r.name} (${r.task_count})`);
|
|
38472
38928
|
return { content: [{ type: "text", text: lines.join(`
|
|
38473
38929
|
`) }] };
|
|
38474
38930
|
} catch (e) {
|
|
@@ -39037,8 +39493,8 @@ var init_task_project_tools = __esm(() => {
|
|
|
39037
39493
|
init_comments();
|
|
39038
39494
|
init_task_runs();
|
|
39039
39495
|
init_project_bootstrap();
|
|
39040
|
-
init_database();
|
|
39041
39496
|
init_labels();
|
|
39497
|
+
init_tags();
|
|
39042
39498
|
init_redaction();
|
|
39043
39499
|
init_retention_cleanup();
|
|
39044
39500
|
init_mention_resolver();
|
|
@@ -65564,7 +66020,7 @@ var init_agent_run_dispatcher = __esm(() => {
|
|
|
65564
66020
|
|
|
65565
66021
|
// src/lib/verification-providers.ts
|
|
65566
66022
|
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
65567
|
-
function
|
|
66023
|
+
function normalizeName5(name) {
|
|
65568
66024
|
const normalized = name.trim().toLowerCase();
|
|
65569
66025
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
65570
66026
|
throw new Error("verification provider name must use lowercase letters, numbers, dashes, or underscores");
|
|
@@ -65583,10 +66039,10 @@ function timeoutMs(value) {
|
|
|
65583
66039
|
return Math.max(1, Math.min(24 * 60 * 60000, Math.floor(value)));
|
|
65584
66040
|
}
|
|
65585
66041
|
function getProvider(name) {
|
|
65586
|
-
return loadConfig().verification_providers?.[
|
|
66042
|
+
return loadConfig().verification_providers?.[normalizeName5(name)] || null;
|
|
65587
66043
|
}
|
|
65588
66044
|
function upsertVerificationProvider(input) {
|
|
65589
|
-
const name =
|
|
66045
|
+
const name = normalizeName5(input.name);
|
|
65590
66046
|
const config2 = loadConfig();
|
|
65591
66047
|
const existing = config2.verification_providers?.[name];
|
|
65592
66048
|
const timestamp3 = new Date().toISOString();
|
|
@@ -65616,7 +66072,7 @@ function listVerificationProviders() {
|
|
|
65616
66072
|
return Object.values(loadConfig().verification_providers || {}).sort((a, b) => a.name.localeCompare(b.name));
|
|
65617
66073
|
}
|
|
65618
66074
|
function removeVerificationProvider(name) {
|
|
65619
|
-
const normalized =
|
|
66075
|
+
const normalized = normalizeName5(name);
|
|
65620
66076
|
const config2 = loadConfig();
|
|
65621
66077
|
if (!config2.verification_providers?.[normalized])
|
|
65622
66078
|
return false;
|
|
@@ -69952,7 +70408,7 @@ import { basename as basename5, join as join10, resolve as resolve13 } from "pat
|
|
|
69952
70408
|
function isObject3(value) {
|
|
69953
70409
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
69954
70410
|
}
|
|
69955
|
-
function
|
|
70411
|
+
function normalizeName6(name) {
|
|
69956
70412
|
const normalized = name.trim().toLowerCase();
|
|
69957
70413
|
if (!/^[a-z0-9][a-z0-9_.-]{0,63}$/.test(normalized)) {
|
|
69958
70414
|
throw new Error("extension name must use lowercase letters, numbers, dots, dashes, or underscores");
|
|
@@ -69970,7 +70426,7 @@ function permissionList(value) {
|
|
|
69970
70426
|
function normalizeManifest(input) {
|
|
69971
70427
|
if (!isObject3(input))
|
|
69972
70428
|
throw new Error("extension manifest must be a JSON object");
|
|
69973
|
-
const name =
|
|
70429
|
+
const name = normalizeName6(String(input["name"] || ""));
|
|
69974
70430
|
const version2 = String(input["version"] || "").trim();
|
|
69975
70431
|
if (!version2)
|
|
69976
70432
|
throw new Error("extension manifest requires version");
|
|
@@ -69978,7 +70434,7 @@ function normalizeManifest(input) {
|
|
|
69978
70434
|
todos: typeof input["compatibility"]["todos"] === "string" ? input["compatibility"]["todos"] : undefined
|
|
69979
70435
|
} : undefined;
|
|
69980
70436
|
const commands = Array.isArray(input["commands"]) ? input["commands"].filter(isObject3).map((command) => ({
|
|
69981
|
-
name:
|
|
70437
|
+
name: normalizeName6(String(command["name"] || "")),
|
|
69982
70438
|
command: typeof command["command"] === "string" ? command["command"] : undefined,
|
|
69983
70439
|
description: typeof command["description"] === "string" ? command["description"] : undefined,
|
|
69984
70440
|
permissions: permissionList(command["permissions"]),
|
|
@@ -69987,12 +70443,12 @@ function normalizeManifest(input) {
|
|
|
69987
70443
|
network: typeof command["network"] === "boolean" ? command["network"] : undefined
|
|
69988
70444
|
})) : [];
|
|
69989
70445
|
const mcpTools = Array.isArray(input["mcp_tools"]) ? input["mcp_tools"].filter(isObject3).map((tool) => ({
|
|
69990
|
-
name:
|
|
70446
|
+
name: normalizeName6(String(tool["name"] || "")),
|
|
69991
70447
|
description: typeof tool["description"] === "string" ? tool["description"] : undefined,
|
|
69992
70448
|
permissions: permissionList(tool["permissions"])
|
|
69993
70449
|
})) : [];
|
|
69994
70450
|
const templates = Array.isArray(input["templates"]) ? input["templates"].filter(isObject3).map((template) => ({
|
|
69995
|
-
name:
|
|
70451
|
+
name: normalizeName6(String(template["name"] || "")),
|
|
69996
70452
|
kind: typeof template["kind"] === "string" ? template["kind"] : undefined,
|
|
69997
70453
|
description: typeof template["description"] === "string" ? template["description"] : undefined,
|
|
69998
70454
|
path: typeof template["path"] === "string" ? template["path"] : undefined,
|
|
@@ -70001,7 +70457,7 @@ function normalizeManifest(input) {
|
|
|
70001
70457
|
permissions: permissionList(template["permissions"])
|
|
70002
70458
|
})) : [];
|
|
70003
70459
|
const renderers = Array.isArray(input["renderers"]) ? input["renderers"].filter(isObject3).map((renderer) => ({
|
|
70004
|
-
name:
|
|
70460
|
+
name: normalizeName6(String(renderer["name"] || "")),
|
|
70005
70461
|
target: typeof renderer["target"] === "string" ? renderer["target"] : "",
|
|
70006
70462
|
description: typeof renderer["description"] === "string" ? renderer["description"] : undefined,
|
|
70007
70463
|
command: typeof renderer["command"] === "string" ? renderer["command"] : undefined,
|
|
@@ -70400,10 +70856,10 @@ function listLocalExtensions() {
|
|
|
70400
70856
|
return Object.values(loadConfig().extension_registry || {}).sort((a, b) => a.name.localeCompare(b.name));
|
|
70401
70857
|
}
|
|
70402
70858
|
function getLocalExtension(name) {
|
|
70403
|
-
return loadConfig().extension_registry?.[
|
|
70859
|
+
return loadConfig().extension_registry?.[normalizeName6(name)] || null;
|
|
70404
70860
|
}
|
|
70405
70861
|
function removeLocalExtension(name) {
|
|
70406
|
-
const normalized =
|
|
70862
|
+
const normalized = normalizeName6(name);
|
|
70407
70863
|
const config2 = loadConfig();
|
|
70408
70864
|
if (!config2.extension_registry?.[normalized])
|
|
70409
70865
|
return false;
|
|
@@ -75914,8 +76370,6 @@ var init_builtin_templates = __esm(() => {
|
|
|
75914
76370
|
},
|
|
75915
76371
|
{
|
|
75916
76372
|
name: "open-source-project",
|
|
75917
|
-
version: 1,
|
|
75918
|
-
category: "project",
|
|
75919
76373
|
description: "Full open-source project bootstrap \u2014 scaffold to publish",
|
|
75920
76374
|
category: "open-source",
|
|
75921
76375
|
version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
|
|
@@ -75941,7 +76395,7 @@ var init_builtin_templates = __esm(() => {
|
|
|
75941
76395
|
},
|
|
75942
76396
|
{
|
|
75943
76397
|
name: "release",
|
|
75944
|
-
version:
|
|
76398
|
+
version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
|
|
75945
76399
|
category: "ops",
|
|
75946
76400
|
description: "Version release workflow \u2014 test, changelog, publish, verify",
|
|
75947
76401
|
variables: [
|
|
@@ -75958,7 +76412,7 @@ var init_builtin_templates = __esm(() => {
|
|
|
75958
76412
|
},
|
|
75959
76413
|
{
|
|
75960
76414
|
name: "docs-refresh",
|
|
75961
|
-
version:
|
|
76415
|
+
version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
|
|
75962
76416
|
category: "workflow",
|
|
75963
76417
|
description: "Documentation refresh \u2014 audit, update, verify links",
|
|
75964
76418
|
variables: [{ name: "scope", required: true, description: "Docs scope (README, API, AGENTS.md)" }],
|
|
@@ -75971,7 +76425,7 @@ var init_builtin_templates = __esm(() => {
|
|
|
75971
76425
|
},
|
|
75972
76426
|
{
|
|
75973
76427
|
name: "migration",
|
|
75974
|
-
version:
|
|
76428
|
+
version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
|
|
75975
76429
|
category: "ops",
|
|
75976
76430
|
description: "Schema/data migration workflow",
|
|
75977
76431
|
variables: [
|
|
@@ -75988,7 +76442,7 @@ var init_builtin_templates = __esm(() => {
|
|
|
75988
76442
|
},
|
|
75989
76443
|
{
|
|
75990
76444
|
name: "incident-response",
|
|
75991
|
-
version:
|
|
76445
|
+
version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
|
|
75992
76446
|
category: "ops",
|
|
75993
76447
|
description: "Incident triage, mitigation, postmortem",
|
|
75994
76448
|
variables: [{ name: "incident", required: true, description: "Incident summary" }],
|
|
@@ -76035,8 +76489,8 @@ function registerTemplateTools(server, { shouldRegisterTool, resolveId, formatEr
|
|
|
76035
76489
|
const { createTemplate: createTemplate2, getTemplateWithTasks: getTemplateWithTasks2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
76036
76490
|
const t = createTemplate2(params);
|
|
76037
76491
|
const withTasks = getTemplateWithTasks2(t.id);
|
|
76038
|
-
const
|
|
76039
|
-
const taskInfo =
|
|
76492
|
+
const taskCount2 = withTasks?.tasks.length ?? 0;
|
|
76493
|
+
const taskInfo = taskCount2 > 0 ? ` | ${taskCount2} task(s)` : "";
|
|
76040
76494
|
return { content: [{ type: "text", text: `Template created: ${t.id.slice(0, 8)} | ${t.name} | "${t.title_pattern}"${taskInfo}` }] };
|
|
76041
76495
|
} catch (e) {
|
|
76042
76496
|
return { content: [{ type: "text", text: formatError2(e) }], isError: true };
|
|
@@ -76740,6 +77194,26 @@ function getMcpVersion() {
|
|
|
76740
77194
|
function hasVersionFlag() {
|
|
76741
77195
|
return process.argv.includes("--version") || process.argv.includes("-V");
|
|
76742
77196
|
}
|
|
77197
|
+
function hasHelpFlag() {
|
|
77198
|
+
return process.argv.includes("--help") || process.argv.includes("-h");
|
|
77199
|
+
}
|
|
77200
|
+
function printHelp() {
|
|
77201
|
+
console.log(`Usage: todos-mcp [options]
|
|
77202
|
+
|
|
77203
|
+
Start the @hasna/todos MCP server.
|
|
77204
|
+
|
|
77205
|
+
Options:
|
|
77206
|
+
--stdio Use stdio transport
|
|
77207
|
+
--port <port> Use Streamable HTTP on the given port
|
|
77208
|
+
-V, --version output the version number
|
|
77209
|
+
-h, --help display help for command
|
|
77210
|
+
|
|
77211
|
+
Environment:
|
|
77212
|
+
TODOS_MCP_STDIO=true Force stdio transport
|
|
77213
|
+
TODOS_MCP_PORT=<port> HTTP port when not using stdio
|
|
77214
|
+
TODOS_PROFILE=<profile> Tool profile filter
|
|
77215
|
+
TODOS_TOOL_GROUPS=<list> Comma-separated tool group filter`);
|
|
77216
|
+
}
|
|
76743
77217
|
function shouldRegisterTool(name) {
|
|
76744
77218
|
return shouldRegisterToolForProfile(name);
|
|
76745
77219
|
}
|
|
@@ -76955,6 +77429,10 @@ var init_mcp3 = __esm(() => {
|
|
|
76955
77429
|
console.log(getMcpVersion());
|
|
76956
77430
|
process.exit(0);
|
|
76957
77431
|
}
|
|
77432
|
+
if (hasHelpFlag()) {
|
|
77433
|
+
printHelp();
|
|
77434
|
+
process.exit(0);
|
|
77435
|
+
}
|
|
76958
77436
|
agentFocusMap = new Map;
|
|
76959
77437
|
isDirectRun = process.argv[1]?.endsWith("/mcp/index.ts") || process.argv[1]?.endsWith("/mcp/index.js");
|
|
76960
77438
|
if (isDirectRun) {
|
|
@@ -77247,8 +77725,6 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
77247
77725
|
return handleMcpHttpRequest2(req, buildServer2);
|
|
77248
77726
|
}
|
|
77249
77727
|
if (method === "OPTIONS") {
|
|
77250
|
-
const reqOrigin2 = req.headers.get("origin") || undefined;
|
|
77251
|
-
const allowed = reqOrigin2 && (reqOrigin2 === `http://localhost:${port}` || reqOrigin2 === "http://localhost:0");
|
|
77252
77728
|
return new Response(null, {
|
|
77253
77729
|
headers: corsHeaders || {
|
|
77254
77730
|
Vary: "Origin"
|
|
@@ -77517,11 +77993,30 @@ var init_serve = __esm(() => {
|
|
|
77517
77993
|
|
|
77518
77994
|
// src/server/index.ts
|
|
77519
77995
|
init_package_version();
|
|
77520
|
-
init_serve();
|
|
77521
77996
|
var DEFAULT_PORT = 19427;
|
|
77522
77997
|
function hasVersionFlag2() {
|
|
77523
77998
|
return process.argv.includes("--version") || process.argv.includes("-V");
|
|
77524
77999
|
}
|
|
78000
|
+
function hasHelpFlag2() {
|
|
78001
|
+
return process.argv.includes("--help") || process.argv.includes("-h");
|
|
78002
|
+
}
|
|
78003
|
+
function printHelp2() {
|
|
78004
|
+
console.log(`Usage: todos-serve [options]
|
|
78005
|
+
|
|
78006
|
+
Start the @hasna/todos dashboard server.
|
|
78007
|
+
|
|
78008
|
+
Options:
|
|
78009
|
+
--port <port> HTTP port to bind. Defaults to ${DEFAULT_PORT}
|
|
78010
|
+
--host <host> Hostname to bind. Defaults to 127.0.0.1
|
|
78011
|
+
--api-key <key> Require this API key for dashboard/API requests
|
|
78012
|
+
--no-open Do not open the dashboard in a browser
|
|
78013
|
+
-V, --version output the version number
|
|
78014
|
+
-h, --help display help for command
|
|
78015
|
+
|
|
78016
|
+
Environment:
|
|
78017
|
+
TODOS_NO_OPEN=true Do not open the dashboard in a browser
|
|
78018
|
+
TODOS_API_KEY=<key> Require this API key for dashboard/API requests`);
|
|
78019
|
+
}
|
|
77525
78020
|
function parsePort() {
|
|
77526
78021
|
const portArg = process.argv.find((a) => a === "--port" || a.startsWith("--port="));
|
|
77527
78022
|
if (portArg) {
|
|
@@ -77557,13 +78052,18 @@ async function main2() {
|
|
|
77557
78052
|
console.log(getPackageVersion());
|
|
77558
78053
|
return;
|
|
77559
78054
|
}
|
|
78055
|
+
if (hasHelpFlag2()) {
|
|
78056
|
+
printHelp2();
|
|
78057
|
+
return;
|
|
78058
|
+
}
|
|
77560
78059
|
const requestedPort = parsePort();
|
|
77561
78060
|
const port = await findFreePort(requestedPort);
|
|
77562
78061
|
if (port !== requestedPort) {
|
|
77563
78062
|
console.log(`Port ${requestedPort} in use, using ${port}`);
|
|
77564
78063
|
}
|
|
77565
78064
|
const noOpen = process.argv.includes("--no-open") || process.env["TODOS_NO_OPEN"] === "true";
|
|
77566
|
-
startServer(
|
|
78065
|
+
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_serve(), exports_serve));
|
|
78066
|
+
startServer2(port, {
|
|
77567
78067
|
open: !noOpen,
|
|
77568
78068
|
host: parseStringArg("--host"),
|
|
77569
78069
|
apiKey: parseStringArg("--api-key")
|