@danalexilewis/taskgraph 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/cli/block.js +114 -0
  4. package/dist/cli/context.js +139 -0
  5. package/dist/cli/done.js +98 -0
  6. package/dist/cli/edge.js +99 -0
  7. package/dist/cli/export.js +97 -0
  8. package/dist/cli/import.js +123 -0
  9. package/dist/cli/index.js +78 -0
  10. package/dist/cli/init.js +106 -0
  11. package/dist/cli/next.js +97 -0
  12. package/dist/cli/note.js +72 -0
  13. package/dist/cli/plan.js +108 -0
  14. package/dist/cli/portfolio.js +159 -0
  15. package/dist/cli/setup.js +142 -0
  16. package/dist/cli/show.js +142 -0
  17. package/dist/cli/split.js +191 -0
  18. package/dist/cli/start.js +94 -0
  19. package/dist/cli/status.js +149 -0
  20. package/dist/cli/task.js +92 -0
  21. package/dist/cli/utils.js +74 -0
  22. package/dist/db/commit.js +18 -0
  23. package/dist/db/connection.js +22 -0
  24. package/dist/db/escape.js +6 -0
  25. package/dist/db/migrate.js +159 -0
  26. package/dist/db/query.js +102 -0
  27. package/dist/domain/errors.js +33 -0
  28. package/dist/domain/invariants.js +103 -0
  29. package/dist/domain/types.js +120 -0
  30. package/dist/export/dot.js +21 -0
  31. package/dist/export/graph-data.js +41 -0
  32. package/dist/export/markdown.js +108 -0
  33. package/dist/export/mermaid.js +27 -0
  34. package/dist/plan-import/importer.js +155 -0
  35. package/dist/plan-import/parser.js +213 -0
  36. package/dist/template/.cursor/memory.md +14 -0
  37. package/dist/template/.cursor/rules/memory.mdc +11 -0
  38. package/dist/template/.cursor/rules/plan-authoring.mdc +42 -0
  39. package/dist/template/.cursor/rules/session-start.mdc +18 -0
  40. package/dist/template/.cursor/rules/taskgraph-workflow.mdc +35 -0
  41. package/dist/template/AGENT.md +73 -0
  42. package/dist/template/docs/backend.md +33 -0
  43. package/dist/template/docs/frontend.md +31 -0
  44. package/dist/template/docs/infra.md +26 -0
  45. package/dist/template/docs/skills/README.md +14 -0
  46. package/dist/template/docs/skills/plan-authoring.md +38 -0
  47. package/dist/template/docs/skills/refactoring-safely.md +21 -0
  48. package/dist/template/docs/skills/taskgraph-lifecycle-execution.md +23 -0
  49. package/package.json +47 -0
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.importCommand = importCommand;
4
+ const utils_1 = require("./utils");
5
+ const parser_1 = require("../plan-import/parser");
6
+ const importer_1 = require("../plan-import/importer");
7
+ const commit_1 = require("../db/commit");
8
+ const uuid_1 = require("uuid");
9
+ const neverthrow_1 = require("neverthrow");
10
+ const errors_1 = require("../domain/errors");
11
+ const query_1 = require("../db/query");
12
+ function importCommand(program) {
13
+ program
14
+ .command("import")
15
+ .description("Import tasks and edges from a markdown plan file")
16
+ .argument("<filePath>", "Path to the markdown plan file (e.g., plans/feature-auth.md)")
17
+ .requiredOption("--plan <planTitleOrId>", "Title or ID of the plan to associate tasks with")
18
+ .option("--format <format>", "Plan format: 'legacy' (TASK:/TITLE:/BLOCKED_BY:) or 'cursor' (YAML frontmatter with todos). Default: legacy", "legacy")
19
+ .action(async (filePath, options, cmd) => {
20
+ const result = await (0, utils_1.readConfig)().asyncAndThen((config) => {
21
+ const currentTimestamp = (0, query_1.now)();
22
+ const parseResult = options.format === "cursor"
23
+ ? (0, parser_1.parseCursorPlan)(filePath)
24
+ : (0, parser_1.parsePlanMarkdown)(filePath);
25
+ return parseResult.asyncAndThen((parsedPlan) => {
26
+ return neverthrow_1.ResultAsync.fromPromise((async () => {
27
+ const q = (0, query_1.query)(config.doltRepoPath);
28
+ const { planTitle, planIntent, tasks: parsedTasks, fileTree, risks, tests, } = parsedPlan;
29
+ let planId = null;
30
+ // Try to find plan by ID first
31
+ if (options.plan.length === 36 &&
32
+ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(options.plan)) {
33
+ const planResult = await q.select("plan", { columns: ["plan_id"], where: { plan_id: options.plan } });
34
+ if (planResult.isOk() && planResult.value.length > 0) {
35
+ planId = planResult.value[0].plan_id;
36
+ }
37
+ }
38
+ // If not found by ID, try to find by title
39
+ if (!planId) {
40
+ const planResult = await q.select("plan", { columns: ["plan_id"], where: { title: options.plan } });
41
+ if (planResult.isOk() && planResult.value.length > 0) {
42
+ planId = planResult.value[0].plan_id;
43
+ }
44
+ }
45
+ // If plan still not found, create a new one
46
+ if (!planId) {
47
+ planId = (0, uuid_1.v4)();
48
+ const newPlanTitle = planTitle || options.plan;
49
+ const newPlanIntent = planIntent || `Imported from ${filePath}`;
50
+ const insertPayload = {
51
+ plan_id: planId,
52
+ title: newPlanTitle,
53
+ intent: newPlanIntent,
54
+ source_path: filePath,
55
+ created_at: currentTimestamp,
56
+ updated_at: currentTimestamp,
57
+ };
58
+ if (options.format === "cursor") {
59
+ if (fileTree != null)
60
+ insertPayload.file_tree = fileTree;
61
+ if (risks != null)
62
+ insertPayload.risks = JSON.stringify(risks);
63
+ if (tests != null)
64
+ insertPayload.tests = JSON.stringify(tests);
65
+ }
66
+ const insertResult = await q.insert("plan", insertPayload);
67
+ if (insertResult.isErr())
68
+ throw insertResult.error;
69
+ console.log(`Created new plan '${newPlanTitle}' with ID: ${planId}`);
70
+ const commitResult = await (0, commit_1.doltCommit)(`plan: create ${newPlanTitle} from import`, config.doltRepoPath, cmd.parent?.opts().noCommit);
71
+ if (commitResult.isErr())
72
+ throw commitResult.error;
73
+ }
74
+ if (!planId) {
75
+ throw (0, errors_1.buildError)(errors_1.ErrorCode.PLAN_NOT_FOUND, "Could not find or create a plan for the import.");
76
+ }
77
+ if (options.format === "cursor" && (fileTree != null || risks != null || tests != null)) {
78
+ const planUpdatePayload = {
79
+ updated_at: currentTimestamp,
80
+ };
81
+ if (fileTree != null)
82
+ planUpdatePayload.file_tree = fileTree;
83
+ if (risks != null)
84
+ planUpdatePayload.risks = JSON.stringify(risks);
85
+ if (tests != null)
86
+ planUpdatePayload.tests = JSON.stringify(tests);
87
+ const planUpdateResult = await q.update("plan", planUpdatePayload, { plan_id: planId });
88
+ if (planUpdateResult.isErr())
89
+ throw planUpdateResult.error;
90
+ }
91
+ const upsertResult = await (0, importer_1.upsertTasksAndEdges)(planId, parsedTasks, config.doltRepoPath, cmd.parent?.opts().noCommit);
92
+ if (upsertResult.isErr())
93
+ throw upsertResult.error;
94
+ return {
95
+ filePath,
96
+ plan_id: planId,
97
+ importedTasksCount: upsertResult.value.importedTasksCount,
98
+ };
99
+ })(), (e) => e);
100
+ });
101
+ });
102
+ result.match((data) => {
103
+ const resultData = data;
104
+ if (!cmd.parent?.opts().json) {
105
+ console.log(`Successfully imported tasks and edges from ${resultData.filePath} to plan ${resultData.plan_id}.`);
106
+ }
107
+ else {
108
+ console.log(JSON.stringify(resultData, null, 2));
109
+ }
110
+ }, (error) => {
111
+ console.error(`Error importing plan from ${filePath}: ${error.message}`);
112
+ if (cmd.parent?.opts().json) {
113
+ console.log(JSON.stringify({
114
+ status: "error",
115
+ code: error.code,
116
+ message: error.message,
117
+ cause: error.cause,
118
+ }));
119
+ }
120
+ process.exit(1);
121
+ });
122
+ });
123
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commander_1 = require("commander");
4
+ const init_1 = require("./init");
5
+ const plan_1 = require("./plan");
6
+ const task_1 = require("./task");
7
+ const edge_1 = require("./edge");
8
+ const next_1 = require("./next");
9
+ const show_1 = require("./show");
10
+ const start_1 = require("./start");
11
+ const done_1 = require("./done");
12
+ const block_1 = require("./block");
13
+ const split_1 = require("./split");
14
+ const export_1 = require("./export");
15
+ const portfolio_1 = require("./portfolio");
16
+ const import_1 = require("./import");
17
+ const status_1 = require("./status");
18
+ const context_1 = require("./context");
19
+ const note_1 = require("./note");
20
+ const setup_1 = require("./setup");
21
+ const utils_1 = require("./utils");
22
+ const migrate_1 = require("../db/migrate");
23
+ const errors_1 = require("../domain/errors");
24
+ const program = new commander_1.Command();
25
+ /** Commands that create or scaffold; skip auto-migrate (no config or own migration path). */
26
+ const SKIP_MIGRATE_COMMANDS = new Set(["init", "setup"]);
27
+ function topLevelCommand(cmd) {
28
+ let c = cmd;
29
+ while (c.parent && c.parent.parent) {
30
+ c = c.parent;
31
+ }
32
+ return c;
33
+ }
34
+ program.hook("preAction", async (_thisCommand, actionCommand) => {
35
+ const top = topLevelCommand(actionCommand);
36
+ if (SKIP_MIGRATE_COMMANDS.has(top.name())) {
37
+ return;
38
+ }
39
+ const configResult = (0, utils_1.readConfig)();
40
+ if (configResult.isErr()) {
41
+ if (configResult.error.code === errors_1.ErrorCode.CONFIG_NOT_FOUND) {
42
+ return;
43
+ }
44
+ return;
45
+ }
46
+ const opts = (0, utils_1.rootOpts)(actionCommand);
47
+ const noCommit = opts.noCommit ?? false;
48
+ const runResult = await (0, migrate_1.ensureMigrations)(configResult.value.doltRepoPath, noCommit);
49
+ runResult.match(() => { }, (e) => {
50
+ console.error(`Migration failed: ${e.message}`);
51
+ process.exit(1);
52
+ });
53
+ });
54
+ program
55
+ .name("tg")
56
+ .description("Task Graph CLI for Centaur Development")
57
+ .version("0.1.0")
58
+ .option("--json", "Output machine-readable JSON", false)
59
+ .option("--no-commit", "Do not commit changes to Dolt", false)
60
+ .option("--commit-msg <msg>", "Override default commit message");
61
+ (0, init_1.initCommand)(program);
62
+ (0, setup_1.setupCommand)(program);
63
+ (0, plan_1.planCommand)(program);
64
+ (0, task_1.taskCommand)(program);
65
+ (0, edge_1.edgeCommand)(program);
66
+ (0, next_1.nextCommand)(program);
67
+ (0, show_1.showCommand)(program);
68
+ (0, start_1.startCommand)(program);
69
+ (0, done_1.doneCommand)(program);
70
+ (0, block_1.blockCommand)(program);
71
+ (0, split_1.splitCommand)(program);
72
+ (0, export_1.exportCommand)(program);
73
+ (0, portfolio_1.portfolioCommand)(program);
74
+ (0, import_1.importCommand)(program);
75
+ (0, status_1.statusCommand)(program);
76
+ (0, note_1.noteCommand)(program);
77
+ (0, context_1.contextCommand)(program);
78
+ program.parse(process.argv);
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.initCommand = initCommand;
37
+ const fs_1 = require("fs");
38
+ const execa_1 = require("execa");
39
+ const migrate_1 = require("../db/migrate");
40
+ const path = __importStar(require("path"));
41
+ const utils_1 = require("./utils");
42
+ const neverthrow_1 = require("neverthrow");
43
+ const errors_1 = require("../domain/errors");
44
+ const TASKGRAPH_DIR = ".taskgraph";
45
+ const CONFIG_FILE = path.join(TASKGRAPH_DIR, "config.json");
46
+ function initCommand(program) {
47
+ program
48
+ .command("init")
49
+ .description("Initializes the Dolt repository and applies migrations")
50
+ .option("--no-commit", "Do not commit changes to Dolt", false)
51
+ .action(async (options, cmd) => {
52
+ const repoPath = process.cwd();
53
+ const taskGraphPath = path.join(repoPath, TASKGRAPH_DIR);
54
+ const doltRepoPath = path.join(taskGraphPath, "dolt");
55
+ const initResult = await neverthrow_1.ResultAsync.fromPromise((async () => {
56
+ if (!(0, fs_1.existsSync)(taskGraphPath)) {
57
+ (0, fs_1.mkdirSync)(taskGraphPath);
58
+ }
59
+ if (!(0, fs_1.existsSync)(doltRepoPath)) {
60
+ // Create the doltRepoPath directory before initializing Dolt
61
+ (0, fs_1.mkdirSync)(doltRepoPath, { recursive: true });
62
+ console.log(`Creating Dolt repository at ${doltRepoPath}...`);
63
+ await (0, execa_1.execa)(process.env.DOLT_PATH || "dolt", ["init"], {
64
+ cwd: doltRepoPath,
65
+ }); // Changed cwd to doltRepoPath
66
+ console.log("Dolt repository created.");
67
+ }
68
+ else {
69
+ console.log(`Dolt repository already exists at ${doltRepoPath}.`);
70
+ }
71
+ return Promise.resolve(); // Explicitly return a Promise<void>
72
+ })(), // Invoked the async IIFE
73
+ (e) => (0, errors_1.buildError)(errors_1.ErrorCode.DB_QUERY_FAILED, "Failed to initialize Dolt repository", e))
74
+ .andThen(() => (0, migrate_1.applyMigrations)(doltRepoPath, options.noCommit))
75
+ .andThen(() => (0, migrate_1.applyTaskDimensionsMigration)(doltRepoPath, options.noCommit))
76
+ .andThen(() => (0, migrate_1.applyPlanRichFieldsMigration)(doltRepoPath, options.noCommit))
77
+ .andThen(() => (0, migrate_1.applyTaskSuggestedChangesMigration)(doltRepoPath, options.noCommit))
78
+ .andThen(() => (0, migrate_1.applyTaskDomainSkillJunctionMigration)(doltRepoPath, options.noCommit))
79
+ .andThen(() => {
80
+ const config = {
81
+ doltRepoPath: doltRepoPath,
82
+ };
83
+ // Use a valid ErrorCode, e.g., UNKNOWN_ERROR
84
+ return (0, utils_1.writeConfig)(config, repoPath).mapErr((e) => (0, errors_1.buildError)(errors_1.ErrorCode.UNKNOWN_ERROR, "Failed to write config", e));
85
+ });
86
+ initResult.match(() => {
87
+ if (!cmd.parent?.opts().json) {
88
+ console.log(`Configuration written to ${CONFIG_FILE}`);
89
+ console.log("Task Graph initialized successfully.");
90
+ }
91
+ // ... rest of the match block remains the same
92
+ }, (error) => {
93
+ const appError = error;
94
+ console.error(`Error initializing Task Graph: ${appError.message}`); // Used appError.message
95
+ if (cmd.parent?.opts().json) {
96
+ console.log(JSON.stringify({
97
+ status: "error",
98
+ code: appError.code,
99
+ message: appError.message,
100
+ cause: appError.cause,
101
+ }));
102
+ }
103
+ process.exit(1);
104
+ });
105
+ });
106
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nextCommand = nextCommand;
4
+ const utils_1 = require("./utils");
5
+ const neverthrow_1 = require("neverthrow");
6
+ const errors_1 = require("../domain/errors");
7
+ const query_1 = require("../db/query");
8
+ const escape_1 = require("../db/escape");
9
+ function nextCommand(program) {
10
+ program
11
+ .command("next")
12
+ .description("Select runnable tasks")
13
+ .option("--plan <planId>", "Optional filter by plan ID or title")
14
+ .option("--domain <domain>", "Filter by task domain (maps to docs/<domain>.md)")
15
+ .option("--skill <skill>", "Filter by task skill (maps to docs/skills/<skill>.md)")
16
+ .option("--change-type <type>", "Filter by change type: create, modify, refactor, fix, investigate, test, document")
17
+ .option("--limit <limit>", "Limit the number of tasks returned", "10")
18
+ .action(async (options, cmd) => {
19
+ const result = await (0, utils_1.readConfig)().asyncAndThen((config) => {
20
+ const limit = parseInt(options.limit, 10);
21
+ if (isNaN(limit) || limit <= 0) {
22
+ return (0, neverthrow_1.errAsync)((0, errors_1.buildError)(errors_1.ErrorCode.VALIDATION_FAILED, `Invalid limit: ${options.limit}. Must be a positive integer.`)); // Changed to errAsync
23
+ }
24
+ const q = (0, query_1.query)(config.doltRepoPath);
25
+ let planFilter = "";
26
+ if (options.plan) {
27
+ const isUUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(options.plan);
28
+ if (isUUID) {
29
+ planFilter = `AND p.plan_id = '${(0, escape_1.sqlEscape)(options.plan)}'`;
30
+ }
31
+ else {
32
+ planFilter = `AND p.title = '${(0, escape_1.sqlEscape)(options.plan)}'`;
33
+ }
34
+ }
35
+ let domainFilter = "";
36
+ if (options.domain) {
37
+ domainFilter = `AND EXISTS (SELECT 1 FROM \`task_domain\` td WHERE td.task_id = t.task_id AND td.domain = '${(0, escape_1.sqlEscape)(options.domain)}')`;
38
+ }
39
+ let skillFilter = "";
40
+ if (options.skill) {
41
+ skillFilter = `AND EXISTS (SELECT 1 FROM \`task_skill\` ts WHERE ts.task_id = t.task_id AND ts.skill = '${(0, escape_1.sqlEscape)(options.skill)}')`;
42
+ }
43
+ let changeTypeFilter = "";
44
+ if (options.changeType) {
45
+ changeTypeFilter = `AND t.\`change_type\` = '${(0, escape_1.sqlEscape)(options.changeType)}'`;
46
+ }
47
+ const nextTasksQuery = `
48
+ SELECT t.task_id, t.title, p.title as plan_title, t.risk, t.estimate_mins,
49
+ (SELECT COUNT(*) FROM \`edge\` e
50
+ JOIN \`task\` bt ON e.from_task_id = bt.task_id
51
+ WHERE e.to_task_id = t.task_id AND e.type = 'blocks'
52
+ AND bt.status NOT IN ('done','canceled')) as unmet_blockers
53
+ FROM \`task\` t
54
+ JOIN \`plan\` p ON t.plan_id = p.plan_id
55
+ WHERE t.status = 'todo'
56
+ ${planFilter}
57
+ ${domainFilter}
58
+ ${skillFilter}
59
+ ${changeTypeFilter}
60
+ HAVING unmet_blockers = 0
61
+ ORDER BY p.priority DESC, t.risk ASC,
62
+ CASE WHEN t.estimate_mins IS NULL THEN 1 ELSE 0 END,
63
+ t.estimate_mins ASC, t.created_at ASC
64
+ LIMIT ${limit}
65
+ `;
66
+ return q.raw(nextTasksQuery);
67
+ });
68
+ result.match((tasks) => {
69
+ const tasksArray = tasks;
70
+ if (!cmd.parent?.opts().json) {
71
+ if (tasksArray.length > 0) {
72
+ console.log("Runnable Tasks:");
73
+ tasksArray.forEach((task) => {
74
+ console.log(` ID: ${task.task_id}, Title: ${task.title}, Plan: ${task.plan_title}, Risk: ${task.risk}, Estimate: ${task.estimate_mins ?? "N/A"}`);
75
+ });
76
+ }
77
+ else {
78
+ console.log("No runnable tasks found.");
79
+ }
80
+ }
81
+ else {
82
+ console.log(JSON.stringify(tasksArray, null, 2));
83
+ }
84
+ }, (error) => {
85
+ console.error(`Error fetching next tasks: ${error.message}`);
86
+ if (cmd.parent?.opts().json) {
87
+ console.log(JSON.stringify({
88
+ status: "error",
89
+ code: error.code,
90
+ message: error.message,
91
+ cause: error.cause,
92
+ }));
93
+ }
94
+ process.exit(1);
95
+ });
96
+ });
97
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noteCommand = noteCommand;
4
+ const uuid_1 = require("uuid");
5
+ const commit_1 = require("../db/commit");
6
+ const utils_1 = require("./utils");
7
+ const neverthrow_1 = require("neverthrow");
8
+ const errors_1 = require("../domain/errors");
9
+ const query_1 = require("../db/query");
10
+ function noteCommand(program) {
11
+ program
12
+ .command("note")
13
+ .description("Append a note event to a task (breadcrumbs for other agents and the human)")
14
+ .argument("<taskId>", "ID of the task to annotate")
15
+ .option("--msg <text>", "Note message (required)")
16
+ .option("--agent <name>", "Agent identifier")
17
+ .action(async (taskId, options, cmd) => {
18
+ const msg = options.msg;
19
+ if (!msg || typeof msg !== "string") {
20
+ console.error("Error: --msg <text> is required.");
21
+ process.exit(1);
22
+ }
23
+ const agentName = options.agent ?? "default";
24
+ const result = await (0, utils_1.readConfig)().asyncAndThen((config) => {
25
+ const currentTimestamp = (0, query_1.now)();
26
+ const q = (0, query_1.query)(config.doltRepoPath);
27
+ return q
28
+ .select("task", {
29
+ columns: ["task_id"],
30
+ where: { task_id: taskId },
31
+ })
32
+ .andThen((rows) => {
33
+ if (rows.length === 0) {
34
+ return (0, neverthrow_1.err)((0, errors_1.buildError)(errors_1.ErrorCode.TASK_NOT_FOUND, `Task with ID ${taskId} not found.`));
35
+ }
36
+ return q
37
+ .insert("event", {
38
+ event_id: (0, uuid_1.v4)(),
39
+ task_id: taskId,
40
+ kind: "note",
41
+ body: (0, query_1.jsonObj)({
42
+ message: msg,
43
+ agent: agentName,
44
+ timestamp: currentTimestamp,
45
+ }),
46
+ created_at: currentTimestamp,
47
+ })
48
+ .andThen(() => (0, commit_1.doltCommit)(`task: note ${taskId}`, config.doltRepoPath, cmd.parent?.opts().noCommit))
49
+ .map(() => ({ task_id: taskId }));
50
+ });
51
+ });
52
+ result.match((data) => {
53
+ if (!cmd.parent?.opts().json) {
54
+ console.log(`Note added to task ${data.task_id}.`);
55
+ }
56
+ else {
57
+ console.log(JSON.stringify(data, null, 2));
58
+ }
59
+ }, (error) => {
60
+ console.error(`Error: ${error.message}`);
61
+ if (cmd.parent?.opts().json) {
62
+ console.log(JSON.stringify({
63
+ status: "error",
64
+ code: error.code,
65
+ message: error.message,
66
+ cause: error.cause,
67
+ }));
68
+ }
69
+ process.exit(1);
70
+ });
71
+ });
72
+ }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.planCommand = planCommand;
4
+ const commander_1 = require("commander");
5
+ const uuid_1 = require("uuid");
6
+ const commit_1 = require("../db/commit");
7
+ const utils_1 = require("./utils");
8
+ const query_1 = require("../db/query");
9
+ function planCommand(program) {
10
+ program
11
+ .command("plan")
12
+ .description("Manage plans")
13
+ .addCommand(planNewCommand())
14
+ .addCommand(planListCommand());
15
+ }
16
+ function planListCommand() {
17
+ return new commander_1.Command("list")
18
+ .alias("ls")
19
+ .description("List all plans")
20
+ .action(async (options, cmd) => {
21
+ const result = await (0, utils_1.readConfig)().asyncAndThen((config) => {
22
+ const q = (0, query_1.query)(config.doltRepoPath);
23
+ return q.select("plan", {
24
+ columns: ["plan_id", "title", "status", "created_at"],
25
+ orderBy: "`created_at` DESC",
26
+ });
27
+ });
28
+ result.match((plans) => {
29
+ const plansArray = plans;
30
+ if (!(0, utils_1.rootOpts)(cmd).json) {
31
+ if (plansArray.length > 0) {
32
+ console.log("Plans:");
33
+ plansArray.forEach((p) => {
34
+ console.log(` ${p.plan_id} ${p.title} (${p.status})`);
35
+ });
36
+ }
37
+ else {
38
+ console.log("No plans found.");
39
+ }
40
+ }
41
+ else {
42
+ console.log(JSON.stringify(plansArray, null, 2));
43
+ }
44
+ }, (error) => {
45
+ console.error(`Error listing plans: ${error.message}`);
46
+ if ((0, utils_1.rootOpts)(cmd).json) {
47
+ console.log(JSON.stringify({
48
+ status: "error",
49
+ code: error.code,
50
+ message: error.message,
51
+ cause: error.cause,
52
+ }));
53
+ }
54
+ process.exit(1);
55
+ });
56
+ });
57
+ }
58
+ function planNewCommand() {
59
+ return new commander_1.Command("new")
60
+ .description("Create a new plan")
61
+ .argument("<title>", "Title of the plan")
62
+ .option("--intent <intent>", "Intent of the plan", "")
63
+ .option("--source <path>", "Source path (e.g., plans/feature-x.md)")
64
+ .action(async (title, options, cmd) => {
65
+ const result = await (0, utils_1.readConfig)().asyncAndThen((config) => {
66
+ // Removed async, added type
67
+ const plan_id = (0, uuid_1.v4)();
68
+ const currentTimestamp = (0, query_1.now)();
69
+ const q = (0, query_1.query)(config.doltRepoPath);
70
+ return q
71
+ .insert("plan", {
72
+ plan_id,
73
+ title,
74
+ intent: options.intent,
75
+ source_path: options.source ?? null,
76
+ created_at: currentTimestamp,
77
+ updated_at: currentTimestamp,
78
+ })
79
+ .andThen(() => (0, commit_1.doltCommit)(`plan: create ${title}`, config.doltRepoPath, (0, utils_1.rootOpts)(cmd).noCommit))
80
+ .map(() => ({
81
+ plan_id,
82
+ title,
83
+ intent: options.intent,
84
+ source_path: options.source,
85
+ }));
86
+ });
87
+ result.match((data) => {
88
+ const resultData = data;
89
+ if (!(0, utils_1.rootOpts)(cmd).json) {
90
+ console.log(`Plan created with ID: ${resultData.plan_id}`);
91
+ }
92
+ else {
93
+ console.log(JSON.stringify(resultData, null, 2));
94
+ }
95
+ }, (error) => {
96
+ console.error(`Error creating plan: ${error.message}`);
97
+ if ((0, utils_1.rootOpts)(cmd).json) {
98
+ console.log(JSON.stringify({
99
+ status: "error",
100
+ code: error.code,
101
+ message: error.message,
102
+ cause: error.cause,
103
+ }));
104
+ }
105
+ process.exit(1);
106
+ });
107
+ });
108
+ }