c0de-agent 1.5.0 → 1.7.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 (53) hide show
  1. package/dist/core/agent.js +4 -0
  2. package/dist/core/config.js +1 -1
  3. package/dist/core/index.d.ts +1 -1
  4. package/dist/core/loop.js +15 -0
  5. package/dist/core/prompt-registry.d.ts +2 -2
  6. package/dist/core/prompt-registry.js +42 -3
  7. package/dist/core/slash.js +40 -6
  8. package/dist/core/types.d.ts +10 -1
  9. package/dist/core/workflow.d.ts +1 -1
  10. package/dist/core/workflow.js +54 -6
  11. package/dist/core/workflows/runtime.d.ts +3 -0
  12. package/dist/core/workflows/runtime.js +2 -2
  13. package/dist/db/schema.d.ts +299 -0
  14. package/dist/db/schema.js +36 -0
  15. package/dist/kanban/index.d.ts +1 -0
  16. package/dist/kanban/index.js +1 -0
  17. package/dist/kanban/store.d.ts +8 -0
  18. package/dist/kanban/store.js +158 -0
  19. package/dist/project/resolve.d.ts +75 -0
  20. package/dist/project/resolve.js +253 -1
  21. package/dist/server/app.js +6 -0
  22. package/dist/server/context.js +2 -1
  23. package/dist/server/dev.js +3 -1
  24. package/dist/server/routes/chat.js +12 -0
  25. package/dist/server/routes/commands.js +1 -0
  26. package/dist/server/routes/files.js +252 -4
  27. package/dist/server/routes/kanban.d.ts +4 -0
  28. package/dist/server/routes/kanban.js +74 -0
  29. package/dist/server/routes/terminal.js +2 -1
  30. package/dist/server/routes/todo.d.ts +4 -0
  31. package/dist/server/routes/todo.js +107 -0
  32. package/dist/server/routes/workflows.js +51 -11
  33. package/dist/server/server.d.ts +8 -1
  34. package/dist/server/server.js +113 -23
  35. package/dist/server/terminal/pty-manager.d.ts +14 -0
  36. package/dist/server/terminal/pty-manager.js +105 -7
  37. package/dist/shared/types/agent.d.ts +9 -0
  38. package/dist/shared/types/config.d.ts +6 -0
  39. package/dist/shared/types/index.d.ts +1 -0
  40. package/dist/shared/types/kanban.d.ts +75 -0
  41. package/dist/shared/types/kanban.js +24 -0
  42. package/dist/shared/types/tool.d.ts +17 -0
  43. package/dist/tools/builtin/kanban.d.ts +32 -0
  44. package/dist/tools/builtin/kanban.js +203 -0
  45. package/dist/tools/builtin/todo.d.ts +67 -0
  46. package/dist/tools/builtin/todo.js +517 -0
  47. package/dist/tools/index.d.ts +3 -1
  48. package/dist/tools/index.js +6 -1
  49. package/dist/tools/types.d.ts +32 -1
  50. package/drizzle/0004_smooth_red_skull.sql +26 -0
  51. package/drizzle/meta/0004_snapshot.json +849 -0
  52. package/drizzle/meta/_journal.json +7 -0
  53. package/package.json +4 -1
@@ -0,0 +1,203 @@
1
+ // kanban tool: project-scoped task board for agent collaboration.
2
+ // Mirrors the todo tool's ToolDef pattern but persists to DB (per-project)
3
+ // instead of in-memory session state. Agents can add, move, update, delete
4
+ // tasks and view the full board — enabling human↔agent and agent↔agent
5
+ // coordination via a shared kanban board.
6
+ // =============================================================================
7
+ // Summary formatter
8
+ // =============================================================================
9
+ /** Priority display symbol for compact board summary. */
10
+ const PRIORITY_SYMBOL = {
11
+ high: '🔴',
12
+ medium: '🟡',
13
+ low: '⚪',
14
+ };
15
+ function formatBoardSummary(board, errors = []) {
16
+ const lines = [];
17
+ if (errors.length > 0)
18
+ lines.push(`Errors: ${errors.join('; ')}`);
19
+ for (const col of board.columns) {
20
+ const cards = board.cards.filter((c) => c.columnId === col.id);
21
+ lines.push(`## ${col.name} (${cards.length})`);
22
+ for (const card of cards) {
23
+ const shortId = card.id.slice(0, 8);
24
+ const sym = PRIORITY_SYMBOL[card.priority] ?? '';
25
+ lines.push(` ${sym} [${shortId}] ${card.title}`);
26
+ if (card.description) {
27
+ const preview = card.description.length > 80 ? `${card.description.slice(0, 77)}…` : card.description;
28
+ lines.push(` ${preview}`);
29
+ }
30
+ }
31
+ if (cards.length === 0)
32
+ lines.push(' (empty)');
33
+ }
34
+ const total = board.cards.length;
35
+ lines.push(`\nTotal: ${total} card(s).`);
36
+ if (total === 0)
37
+ lines.push('Board is empty — use kanban add to create tasks.');
38
+ return lines.join('\n');
39
+ }
40
+ // =============================================================================
41
+ // Schema
42
+ // =============================================================================
43
+ const kanbanParameters = {
44
+ type: 'object',
45
+ description: 'Apply a single kanban board operation',
46
+ properties: {
47
+ op: {
48
+ type: 'string',
49
+ enum: ['view', 'add', 'update', 'move', 'delete'],
50
+ description: 'Operation to apply',
51
+ },
52
+ title: { type: 'string', description: 'Task title (for add, update)' },
53
+ description: { type: 'string', description: 'Task description (for add, update)' },
54
+ id: { type: 'string', description: 'Card id (for update, move, delete)' },
55
+ columnId: {
56
+ type: 'string',
57
+ description: 'Column id to place/move the card (for add, move)',
58
+ },
59
+ priority: {
60
+ type: 'string',
61
+ enum: ['high', 'medium', 'low'],
62
+ description: 'Priority level (for add, update)',
63
+ },
64
+ labels: {
65
+ type: 'array',
66
+ items: { type: 'string' },
67
+ description: 'Label ids (for add, update)',
68
+ },
69
+ position: {
70
+ type: 'number',
71
+ description: 'Position within column (for move). Omit to append.',
72
+ },
73
+ },
74
+ required: ['op'],
75
+ additionalProperties: false,
76
+ };
77
+ // =============================================================================
78
+ // Tool definition
79
+ // =============================================================================
80
+ /** kanban tool: project-scoped task board for human↔agent collaboration.
81
+ * Permission: auto (operates on the project's kanban board, no system side effects).
82
+ * State persists in DB via ctx.kanbanStore (dependency-reversal, like todoState). */
83
+ export const kanbanTool = {
84
+ name: 'kanban',
85
+ description: `Manage the project's shared kanban task board. 5 operations:
86
+ - view: list all columns and cards (read-only)
87
+ - add: create a new task card (title required; optional description, columnId defaults to todo, priority defaults to medium, labels)
88
+ - update: edit a card's title/description/priority/labels (id required)
89
+ - move: move a card to a different column or reorder (id + columnId required; optional position)
90
+ - delete: remove a card (id required)
91
+
92
+ The board is shared across all sessions and agents in the same project — use it to coordinate work, track tasks visible to the user, and break down complex projects. Column ids are: todo, in_progress, in_review, done, cancelled (customizable by the user via the board config UI).`,
93
+ parameters: kanbanParameters,
94
+ permission: 'auto',
95
+ execute: async (input, ctx) => {
96
+ const params = input;
97
+ const store = ctx.kanbanStore;
98
+ if (!store) {
99
+ return { _tag: 'error', error: 'Kanban store not available in this context' };
100
+ }
101
+ const errors = [];
102
+ try {
103
+ switch (params.op) {
104
+ case 'view': {
105
+ const board = await store.getBoard();
106
+ return {
107
+ _tag: 'success',
108
+ output: formatBoardSummary(board),
109
+ metadata: { board },
110
+ };
111
+ }
112
+ case 'add': {
113
+ const addTitle = params.title?.trim();
114
+ if (!addTitle) {
115
+ errors.push('title is required for add');
116
+ }
117
+ if (errors.length > 0)
118
+ break;
119
+ const card = await store.addCard({
120
+ title: addTitle,
121
+ description: params.description ?? null,
122
+ columnId: params.columnId,
123
+ priority: params.priority,
124
+ labels: params.labels,
125
+ });
126
+ const board = await store.getBoard();
127
+ return {
128
+ _tag: 'success',
129
+ output: `Card added: [${card.id.slice(0, 8)}] "${card.title}"\n\n${formatBoardSummary(board)}`,
130
+ metadata: { card, board },
131
+ };
132
+ }
133
+ case 'update': {
134
+ const updateId = params.id?.trim();
135
+ if (!updateId) {
136
+ errors.push('id is required for update');
137
+ }
138
+ if (errors.length > 0)
139
+ break;
140
+ const card = await store.updateCard(updateId, {
141
+ ...(params.title !== undefined && { title: params.title }),
142
+ ...(params.description !== undefined && { description: params.description }),
143
+ ...(params.priority !== undefined && { priority: params.priority }),
144
+ ...(params.labels !== undefined && { labels: params.labels }),
145
+ });
146
+ const board = await store.getBoard();
147
+ return {
148
+ _tag: 'success',
149
+ output: `Card updated: [${card.id.slice(0, 8)}] "${card.title}"\n\n${formatBoardSummary(board)}`,
150
+ metadata: { card, board },
151
+ };
152
+ }
153
+ case 'move': {
154
+ const moveId = params.id?.trim();
155
+ const targetCol = params.columnId?.trim();
156
+ if (!moveId) {
157
+ errors.push('id is required for move');
158
+ }
159
+ if (!targetCol) {
160
+ errors.push('columnId is required for move');
161
+ }
162
+ if (errors.length > 0)
163
+ break;
164
+ const card = await store.moveCard(moveId, targetCol, params.position);
165
+ const board = await store.getBoard();
166
+ return {
167
+ _tag: 'success',
168
+ output: `Card moved: [${card.id.slice(0, 8)}] "${card.title}" → ${targetCol}\n\n${formatBoardSummary(board)}`,
169
+ metadata: { card, board },
170
+ };
171
+ }
172
+ case 'delete': {
173
+ const deleteId = params.id?.trim();
174
+ if (!deleteId) {
175
+ errors.push('id is required for delete');
176
+ }
177
+ if (errors.length > 0)
178
+ break;
179
+ await store.deleteCard(deleteId);
180
+ const board = await store.getBoard();
181
+ return {
182
+ _tag: 'success',
183
+ output: `Card deleted: ${deleteId.slice(0, 8)}\n\n${formatBoardSummary(board)}`,
184
+ metadata: { board },
185
+ };
186
+ }
187
+ default:
188
+ errors.push(`Unknown op: ${params.op}`);
189
+ }
190
+ }
191
+ catch (e) {
192
+ errors.push(e instanceof Error ? e.message : String(e));
193
+ }
194
+ // Errors are surfaced in output text (like todo tool) so the LLM can read
195
+ // and retry. Return success to avoid skewing tool metrics.
196
+ const board = await store.getBoard();
197
+ return {
198
+ _tag: 'success',
199
+ output: formatBoardSummary(board, errors),
200
+ metadata: { board },
201
+ };
202
+ },
203
+ };
@@ -0,0 +1,67 @@
1
+ import type { ToolDef } from '../../shared/types/tool.js';
2
+ type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'abandoned';
3
+ type TodoItem = {
4
+ content: string;
5
+ status: TodoStatus;
6
+ };
7
+ type TodoPhase = {
8
+ name: string;
9
+ tasks: TodoItem[];
10
+ };
11
+ /** A single todo operation entry (the tool's input params). */
12
+ type TodoInput = {
13
+ op: 'init';
14
+ list?: {
15
+ phase: string;
16
+ items: string[];
17
+ }[];
18
+ phase?: string;
19
+ items?: string[];
20
+ } | {
21
+ op: 'start';
22
+ task: string;
23
+ } | {
24
+ op: 'done';
25
+ task?: string;
26
+ phase?: string;
27
+ } | {
28
+ op: 'drop';
29
+ task?: string;
30
+ phase?: string;
31
+ } | {
32
+ op: 'rm';
33
+ task?: string;
34
+ phase?: string;
35
+ } | {
36
+ op: 'append';
37
+ phase: string;
38
+ items: string[];
39
+ } | {
40
+ op: 'view';
41
+ };
42
+ /** Deep-clone phases (mutation-safe). */
43
+ export declare function clonePhases(phases: TodoPhase[]): TodoPhase[];
44
+ /** Return the active todo task, preferring in_progress over the first pending. */
45
+ export declare function nextActionableTask(phases: readonly TodoPhase[]): TodoItem | undefined;
46
+ /** Report whether `content` likely names the same work as any entry in
47
+ * `descriptions`. Normalize-then-equal first, with a substring fallback
48
+ * in either direction (≥6 char overlap on the contained side). */
49
+ export declare function todoMatchesAnyDescription(content: string, descriptions: readonly string[]): boolean;
50
+ /** Render todo phases as a Markdown checklist suitable for editing/copying. */
51
+ export declare function phasesToMarkdown(phases: TodoPhase[]): string;
52
+ /** Parse a Markdown checklist back into todo phases. */
53
+ export declare function markdownToPhases(md: string): {
54
+ phases: TodoPhase[];
55
+ errors: string[];
56
+ };
57
+ /** Extract the latest todo phases from stored messages (tool results).
58
+ * Scans backwards for the most recent `todo` tool result with phases metadata. */
59
+ export declare function getLatestTodoPhasesFromMessages(messages: {
60
+ role: string;
61
+ content: unknown[];
62
+ }[]): TodoPhase[];
63
+ /** todo tool: phased task tracking with 7 operations.
64
+ * Permission: auto (no side effects beyond session state).
65
+ * State is held in-memory via ctx.todoState hook (dependency-reversal). */
66
+ export declare const todoTool: ToolDef;
67
+ export type { TodoInput, TodoItem, TodoPhase, TodoStatus };