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
@@ -950,6 +950,301 @@ export declare const toolMetrics: import("drizzle-orm/pg-core").PgTableWithColum
950
950
  };
951
951
  dialect: "pg";
952
952
  }>;
953
+ /**
954
+ * Kanban boards — one per project (unique projectId). Stores column/label
955
+ * configuration as JSON; cards live in kanban_cards.
956
+ */
957
+ export declare const kanbanBoards: import("drizzle-orm/pg-core").PgTableWithColumns<{
958
+ name: "kanban_boards";
959
+ schema: undefined;
960
+ columns: {
961
+ id: import("drizzle-orm/pg-core").PgColumn<{
962
+ name: "id";
963
+ tableName: "kanban_boards";
964
+ dataType: "string";
965
+ columnType: "PgUUID";
966
+ data: string;
967
+ driverParam: string;
968
+ notNull: true;
969
+ hasDefault: true;
970
+ isPrimaryKey: true;
971
+ isAutoincrement: false;
972
+ hasRuntimeDefault: false;
973
+ enumValues: undefined;
974
+ baseColumn: never;
975
+ identity: undefined;
976
+ generated: undefined;
977
+ }, {}, {}>;
978
+ projectId: import("drizzle-orm/pg-core").PgColumn<{
979
+ name: "project_id";
980
+ tableName: "kanban_boards";
981
+ dataType: "string";
982
+ columnType: "PgText";
983
+ data: string;
984
+ driverParam: string;
985
+ notNull: true;
986
+ hasDefault: false;
987
+ isPrimaryKey: false;
988
+ isAutoincrement: false;
989
+ hasRuntimeDefault: false;
990
+ enumValues: [string, ...string[]];
991
+ baseColumn: never;
992
+ identity: undefined;
993
+ generated: undefined;
994
+ }, {}, {}>;
995
+ columns: import("drizzle-orm/pg-core").PgColumn<{
996
+ name: "columns";
997
+ tableName: "kanban_boards";
998
+ dataType: "json";
999
+ columnType: "PgJsonb";
1000
+ data: unknown;
1001
+ driverParam: unknown;
1002
+ notNull: true;
1003
+ hasDefault: false;
1004
+ isPrimaryKey: false;
1005
+ isAutoincrement: false;
1006
+ hasRuntimeDefault: false;
1007
+ enumValues: undefined;
1008
+ baseColumn: never;
1009
+ identity: undefined;
1010
+ generated: undefined;
1011
+ }, {}, {}>;
1012
+ labels: import("drizzle-orm/pg-core").PgColumn<{
1013
+ name: "labels";
1014
+ tableName: "kanban_boards";
1015
+ dataType: "json";
1016
+ columnType: "PgJsonb";
1017
+ data: unknown;
1018
+ driverParam: unknown;
1019
+ notNull: true;
1020
+ hasDefault: true;
1021
+ isPrimaryKey: false;
1022
+ isAutoincrement: false;
1023
+ hasRuntimeDefault: false;
1024
+ enumValues: undefined;
1025
+ baseColumn: never;
1026
+ identity: undefined;
1027
+ generated: undefined;
1028
+ }, {}, {}>;
1029
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
1030
+ name: "created_at";
1031
+ tableName: "kanban_boards";
1032
+ dataType: "date";
1033
+ columnType: "PgTimestamp";
1034
+ data: Date;
1035
+ driverParam: string;
1036
+ notNull: true;
1037
+ hasDefault: true;
1038
+ isPrimaryKey: false;
1039
+ isAutoincrement: false;
1040
+ hasRuntimeDefault: false;
1041
+ enumValues: undefined;
1042
+ baseColumn: never;
1043
+ identity: undefined;
1044
+ generated: undefined;
1045
+ }, {}, {}>;
1046
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
1047
+ name: "updated_at";
1048
+ tableName: "kanban_boards";
1049
+ dataType: "date";
1050
+ columnType: "PgTimestamp";
1051
+ data: Date;
1052
+ driverParam: string;
1053
+ notNull: true;
1054
+ hasDefault: true;
1055
+ isPrimaryKey: false;
1056
+ isAutoincrement: false;
1057
+ hasRuntimeDefault: false;
1058
+ enumValues: undefined;
1059
+ baseColumn: never;
1060
+ identity: undefined;
1061
+ generated: undefined;
1062
+ }, {}, {}>;
1063
+ };
1064
+ dialect: "pg";
1065
+ }>;
1066
+ /**
1067
+ * Kanban cards — tasks on a board. position is a real for fractional indexing
1068
+ * (insert between two cards without rewriting all positions). columnId
1069
+ * references a column id in the parent board's columns JSON.
1070
+ */
1071
+ export declare const kanbanCards: import("drizzle-orm/pg-core").PgTableWithColumns<{
1072
+ name: "kanban_cards";
1073
+ schema: undefined;
1074
+ columns: {
1075
+ id: import("drizzle-orm/pg-core").PgColumn<{
1076
+ name: "id";
1077
+ tableName: "kanban_cards";
1078
+ dataType: "string";
1079
+ columnType: "PgUUID";
1080
+ data: string;
1081
+ driverParam: string;
1082
+ notNull: true;
1083
+ hasDefault: true;
1084
+ isPrimaryKey: true;
1085
+ isAutoincrement: false;
1086
+ hasRuntimeDefault: false;
1087
+ enumValues: undefined;
1088
+ baseColumn: never;
1089
+ identity: undefined;
1090
+ generated: undefined;
1091
+ }, {}, {}>;
1092
+ boardId: import("drizzle-orm/pg-core").PgColumn<{
1093
+ name: "board_id";
1094
+ tableName: "kanban_cards";
1095
+ dataType: "string";
1096
+ columnType: "PgUUID";
1097
+ data: string;
1098
+ driverParam: string;
1099
+ notNull: true;
1100
+ hasDefault: false;
1101
+ isPrimaryKey: false;
1102
+ isAutoincrement: false;
1103
+ hasRuntimeDefault: false;
1104
+ enumValues: undefined;
1105
+ baseColumn: never;
1106
+ identity: undefined;
1107
+ generated: undefined;
1108
+ }, {}, {}>;
1109
+ title: import("drizzle-orm/pg-core").PgColumn<{
1110
+ name: "title";
1111
+ tableName: "kanban_cards";
1112
+ dataType: "string";
1113
+ columnType: "PgText";
1114
+ data: string;
1115
+ driverParam: string;
1116
+ notNull: true;
1117
+ hasDefault: false;
1118
+ isPrimaryKey: false;
1119
+ isAutoincrement: false;
1120
+ hasRuntimeDefault: false;
1121
+ enumValues: [string, ...string[]];
1122
+ baseColumn: never;
1123
+ identity: undefined;
1124
+ generated: undefined;
1125
+ }, {}, {}>;
1126
+ description: import("drizzle-orm/pg-core").PgColumn<{
1127
+ name: "description";
1128
+ tableName: "kanban_cards";
1129
+ dataType: "string";
1130
+ columnType: "PgText";
1131
+ data: string;
1132
+ driverParam: string;
1133
+ notNull: false;
1134
+ hasDefault: false;
1135
+ isPrimaryKey: false;
1136
+ isAutoincrement: false;
1137
+ hasRuntimeDefault: false;
1138
+ enumValues: [string, ...string[]];
1139
+ baseColumn: never;
1140
+ identity: undefined;
1141
+ generated: undefined;
1142
+ }, {}, {}>;
1143
+ columnId: import("drizzle-orm/pg-core").PgColumn<{
1144
+ name: "column_id";
1145
+ tableName: "kanban_cards";
1146
+ dataType: "string";
1147
+ columnType: "PgText";
1148
+ data: string;
1149
+ driverParam: string;
1150
+ notNull: true;
1151
+ hasDefault: false;
1152
+ isPrimaryKey: false;
1153
+ isAutoincrement: false;
1154
+ hasRuntimeDefault: false;
1155
+ enumValues: [string, ...string[]];
1156
+ baseColumn: never;
1157
+ identity: undefined;
1158
+ generated: undefined;
1159
+ }, {}, {}>;
1160
+ priority: import("drizzle-orm/pg-core").PgColumn<{
1161
+ name: "priority";
1162
+ tableName: "kanban_cards";
1163
+ dataType: "string";
1164
+ columnType: "PgText";
1165
+ data: string;
1166
+ driverParam: string;
1167
+ notNull: true;
1168
+ hasDefault: true;
1169
+ isPrimaryKey: false;
1170
+ isAutoincrement: false;
1171
+ hasRuntimeDefault: false;
1172
+ enumValues: [string, ...string[]];
1173
+ baseColumn: never;
1174
+ identity: undefined;
1175
+ generated: undefined;
1176
+ }, {}, {}>;
1177
+ position: import("drizzle-orm/pg-core").PgColumn<{
1178
+ name: "position";
1179
+ tableName: "kanban_cards";
1180
+ dataType: "number";
1181
+ columnType: "PgReal";
1182
+ data: number;
1183
+ driverParam: string | number;
1184
+ notNull: true;
1185
+ hasDefault: true;
1186
+ isPrimaryKey: false;
1187
+ isAutoincrement: false;
1188
+ hasRuntimeDefault: false;
1189
+ enumValues: undefined;
1190
+ baseColumn: never;
1191
+ identity: undefined;
1192
+ generated: undefined;
1193
+ }, {}, {}>;
1194
+ labels: import("drizzle-orm/pg-core").PgColumn<{
1195
+ name: "labels";
1196
+ tableName: "kanban_cards";
1197
+ dataType: "json";
1198
+ columnType: "PgJsonb";
1199
+ data: unknown;
1200
+ driverParam: unknown;
1201
+ notNull: true;
1202
+ hasDefault: true;
1203
+ isPrimaryKey: false;
1204
+ isAutoincrement: false;
1205
+ hasRuntimeDefault: false;
1206
+ enumValues: undefined;
1207
+ baseColumn: never;
1208
+ identity: undefined;
1209
+ generated: undefined;
1210
+ }, {}, {}>;
1211
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
1212
+ name: "created_at";
1213
+ tableName: "kanban_cards";
1214
+ dataType: "date";
1215
+ columnType: "PgTimestamp";
1216
+ data: Date;
1217
+ driverParam: string;
1218
+ notNull: true;
1219
+ hasDefault: true;
1220
+ isPrimaryKey: false;
1221
+ isAutoincrement: false;
1222
+ hasRuntimeDefault: false;
1223
+ enumValues: undefined;
1224
+ baseColumn: never;
1225
+ identity: undefined;
1226
+ generated: undefined;
1227
+ }, {}, {}>;
1228
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
1229
+ name: "updated_at";
1230
+ tableName: "kanban_cards";
1231
+ dataType: "date";
1232
+ columnType: "PgTimestamp";
1233
+ data: Date;
1234
+ driverParam: string;
1235
+ notNull: true;
1236
+ hasDefault: true;
1237
+ isPrimaryKey: false;
1238
+ isAutoincrement: false;
1239
+ hasRuntimeDefault: false;
1240
+ enumValues: undefined;
1241
+ baseColumn: never;
1242
+ identity: undefined;
1243
+ generated: undefined;
1244
+ }, {}, {}>;
1245
+ };
1246
+ dialect: "pg";
1247
+ }>;
953
1248
  /** Type exports for insert/select operations. */
954
1249
  export type ProjectRow = typeof projects.$inferSelect;
955
1250
  export type ProjectInsert = typeof projects.$inferInsert;
@@ -963,3 +1258,7 @@ export type FileSnapshotRow = typeof fileSnapshots.$inferSelect;
963
1258
  export type FileSnapshotInsert = typeof fileSnapshots.$inferInsert;
964
1259
  export type ToolMetricRow = typeof toolMetrics.$inferSelect;
965
1260
  export type ToolMetricInsert = typeof toolMetrics.$inferInsert;
1261
+ export type KanbanBoardRow = typeof kanbanBoards.$inferSelect;
1262
+ export type KanbanBoardInsert = typeof kanbanBoards.$inferInsert;
1263
+ export type KanbanCardRow = typeof kanbanCards.$inferSelect;
1264
+ export type KanbanCardInsert = typeof kanbanCards.$inferInsert;
package/dist/db/schema.js CHANGED
@@ -110,3 +110,39 @@ export const toolMetrics = pgTable('tool_metrics', {
110
110
  }, (table) => [
111
111
  uniqueIndex('uq_tool_metrics_model_tool_mode').on(table.model, table.tool, table.mode),
112
112
  ]);
113
+ /**
114
+ * Kanban boards — one per project (unique projectId). Stores column/label
115
+ * configuration as JSON; cards live in kanban_cards.
116
+ */
117
+ export const kanbanBoards = pgTable('kanban_boards', {
118
+ id: uuid('id').primaryKey().defaultRandom(),
119
+ projectId: text('project_id')
120
+ .notNull()
121
+ .references(() => projects.id, { onDelete: 'cascade' }),
122
+ /** Column definitions: [{ id, name }] */
123
+ columns: jsonb('columns').notNull(),
124
+ /** Label definitions: [{ id, name, color }] */
125
+ labels: jsonb('labels').notNull().default([]),
126
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
127
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
128
+ }, (table) => [uniqueIndex('uq_kanban_boards_project').on(table.projectId)]);
129
+ /**
130
+ * Kanban cards — tasks on a board. position is a real for fractional indexing
131
+ * (insert between two cards without rewriting all positions). columnId
132
+ * references a column id in the parent board's columns JSON.
133
+ */
134
+ export const kanbanCards = pgTable('kanban_cards', {
135
+ id: uuid('id').primaryKey().defaultRandom(),
136
+ boardId: uuid('board_id')
137
+ .notNull()
138
+ .references(() => kanbanBoards.id, { onDelete: 'cascade' }),
139
+ title: text('title').notNull(),
140
+ description: text('description'),
141
+ columnId: text('column_id').notNull(),
142
+ priority: text('priority').notNull().default('medium'),
143
+ position: real('position').notNull().default(0),
144
+ /** Label ids referencing board.labels[].id */
145
+ labels: jsonb('labels').notNull().default([]),
146
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
147
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
148
+ }, (table) => [index('idx_kanban_cards_board').on(table.boardId, table.columnId, table.position)]);
@@ -0,0 +1 @@
1
+ export { createKanbanStore } from './store.js';
@@ -0,0 +1 @@
1
+ export { createKanbanStore } from './store.js';
@@ -0,0 +1,8 @@
1
+ import type { DB } from '../db/client.js';
2
+ import type { KanbanStore } from '../shared/types/kanban.js';
3
+ /**
4
+ * Create a project-scoped KanbanStore backed by the given db handle.
5
+ * The board is created on first access (lazy) with the default 5 columns.
6
+ */
7
+ declare function createKanbanStore(handle: DB, projectId: string): KanbanStore;
8
+ export { createKanbanStore };
@@ -0,0 +1,158 @@
1
+ import { and, asc, eq, max } from 'drizzle-orm';
2
+ import { kanbanBoards, kanbanCards } from '../db/schema.js';
3
+ import { DEFAULT_KANBAN_COLUMNS } from '../shared/types/kanban.js';
4
+ /** Default column when none is specified. */
5
+ const DEFAULT_COLUMN_ID = 'todo';
6
+ /** Position increment — large gap avoids frequent re-indexing on reorder. */
7
+ const POSITION_GAP = 1000;
8
+ // ── Row → API mappers ──────────────────────────────────────
9
+ function rowToBoard(row) {
10
+ return {
11
+ id: row.id,
12
+ projectId: row.projectId,
13
+ columns: row.columns,
14
+ labels: row.labels,
15
+ createdAt: row.createdAt.toISOString(),
16
+ updatedAt: row.updatedAt.toISOString(),
17
+ };
18
+ }
19
+ function rowToCard(row) {
20
+ return {
21
+ id: row.id,
22
+ boardId: row.boardId,
23
+ title: row.title,
24
+ description: row.description,
25
+ columnId: row.columnId,
26
+ priority: row.priority,
27
+ position: row.position,
28
+ labels: row.labels,
29
+ createdAt: row.createdAt.toISOString(),
30
+ updatedAt: row.updatedAt.toISOString(),
31
+ };
32
+ }
33
+ // ── Factory ────────────────────────────────────────────────
34
+ /**
35
+ * Create a project-scoped KanbanStore backed by the given db handle.
36
+ * The board is created on first access (lazy) with the default 5 columns.
37
+ */
38
+ function createKanbanStore(handle, projectId) {
39
+ const db = handle.db;
40
+ /** Insert a default board if none exists (idempotent via unique projectId). */
41
+ async function getOrCreateBoardId() {
42
+ await db
43
+ .insert(kanbanBoards)
44
+ .values({
45
+ projectId,
46
+ columns: [...DEFAULT_KANBAN_COLUMNS],
47
+ labels: [],
48
+ })
49
+ .onConflictDoNothing({ target: kanbanBoards.projectId });
50
+ const [row] = await db
51
+ .select({ id: kanbanBoards.id })
52
+ .from(kanbanBoards)
53
+ .where(eq(kanbanBoards.projectId, projectId))
54
+ .limit(1);
55
+ // 行一定存在:上面 insert + onConflictDoNothing 保证了 projectId 对应的行已创建
56
+ return row.id;
57
+ }
58
+ /** Max position in a column (0 if empty). */
59
+ async function maxPos(boardId, columnId) {
60
+ const [row] = await db
61
+ .select({ m: max(kanbanCards.position) })
62
+ .from(kanbanCards)
63
+ .where(and(eq(kanbanCards.boardId, boardId), eq(kanbanCards.columnId, columnId)));
64
+ return row?.m ?? 0;
65
+ }
66
+ return {
67
+ async getBoard() {
68
+ const boardId = await getOrCreateBoardId();
69
+ const [boardRow] = await db
70
+ .select()
71
+ .from(kanbanBoards)
72
+ .where(eq(kanbanBoards.id, boardId))
73
+ .limit(1);
74
+ const board = boardRow;
75
+ const cards = await db
76
+ .select()
77
+ .from(kanbanCards)
78
+ .where(eq(kanbanCards.boardId, boardId))
79
+ .orderBy(asc(kanbanCards.columnId), asc(kanbanCards.position));
80
+ return { ...rowToBoard(board), cards: cards.map(rowToCard) };
81
+ },
82
+ async addCard(input) {
83
+ const boardId = await getOrCreateBoardId();
84
+ const columnId = input.columnId ?? DEFAULT_COLUMN_ID;
85
+ const position = (await maxPos(boardId, columnId)) + POSITION_GAP;
86
+ const [cardRow] = await db
87
+ .insert(kanbanCards)
88
+ .values({
89
+ boardId,
90
+ title: input.title,
91
+ description: input.description ?? null,
92
+ columnId,
93
+ priority: input.priority ?? 'medium',
94
+ position,
95
+ labels: input.labels ?? [],
96
+ })
97
+ .returning();
98
+ const row = cardRow;
99
+ return rowToCard(row);
100
+ },
101
+ async updateCard(id, patch) {
102
+ const [row] = await db
103
+ .update(kanbanCards)
104
+ .set({
105
+ ...(patch.title !== undefined && { title: patch.title }),
106
+ ...(patch.description !== undefined && { description: patch.description }),
107
+ ...(patch.priority !== undefined && { priority: patch.priority }),
108
+ ...(patch.labels !== undefined && { labels: patch.labels }),
109
+ updatedAt: new Date(),
110
+ })
111
+ .where(eq(kanbanCards.id, id))
112
+ .returning();
113
+ if (!row)
114
+ throw new Error(`Kanban card not found: ${id}`);
115
+ return rowToCard(row);
116
+ },
117
+ async moveCard(id, columnId, position) {
118
+ // If no explicit position, append to end of target column.
119
+ let newPos = position;
120
+ if (newPos === undefined) {
121
+ const [card] = await db
122
+ .select({ boardId: kanbanCards.boardId })
123
+ .from(kanbanCards)
124
+ .where(eq(kanbanCards.id, id))
125
+ .limit(1);
126
+ if (!card)
127
+ throw new Error(`Kanban card not found: ${id}`);
128
+ newPos = (await maxPos(card.boardId, columnId)) + POSITION_GAP;
129
+ }
130
+ const [row] = await db
131
+ .update(kanbanCards)
132
+ .set({ columnId, position: newPos, updatedAt: new Date() })
133
+ .where(eq(kanbanCards.id, id))
134
+ .returning();
135
+ if (!row)
136
+ throw new Error(`Kanban card not found: ${id}`);
137
+ return rowToCard(row);
138
+ },
139
+ async deleteCard(id) {
140
+ await db.delete(kanbanCards).where(eq(kanbanCards.id, id));
141
+ },
142
+ async updateBoard(patch) {
143
+ await getOrCreateBoardId();
144
+ const [boardRow] = await db
145
+ .update(kanbanBoards)
146
+ .set({
147
+ ...(patch.columns !== undefined && { columns: patch.columns }),
148
+ ...(patch.labels !== undefined && { labels: patch.labels }),
149
+ updatedAt: new Date(),
150
+ })
151
+ .where(eq(kanbanBoards.projectId, projectId))
152
+ .returning();
153
+ const row = boardRow;
154
+ return rowToBoard(row);
155
+ },
156
+ };
157
+ }
158
+ export { createKanbanStore };
@@ -5,4 +5,79 @@ export type ResolvedProject = {
5
5
  gitRemote: string | null;
6
6
  gitBranch: string | null;
7
7
  };
8
+ /** 文件 git 状态分类(用于文件树高亮)。按「最值得注意」优先级排列。 */
9
+ export type GitStatusCode = 'modified' | 'staged' | 'untracked' | 'conflict' | 'deleted' | 'ignored';
10
+ /** 目录聚合时的优先级(越大越优先展示)。ignored 最低:被忽略目录下若有真实变更仍显示变更态。 */
11
+ export declare const GIT_STATUS_PRIORITY: Record<GitStatusCode, number>;
12
+ export declare function getGitStatus(cwd: string): Record<string, GitStatusCode> | null;
13
+ /** 检查给定路径中哪些被 gitignore 规则覆盖。
14
+ *
15
+ * 用 git check-ignore 只查询传入的路径(不递归),返回被忽略路径的集合。
16
+ * 只检查当前展开目录的直接子项(通常 10-50 个),不递归进 node_modules 等。
17
+ * 非 git 仓库或无忽略文件时返回空集。
18
+ *
19
+ * 注意:git check-ignore 在「无路径被忽略」或「非 git 仓库」时退出码为 1,
20
+ * 这两种情况都返回空集。 */
21
+ export declare function checkIgnored(cwd: string, paths: string[]): Set<string>;
22
+ /** 追加条目到 .gitignore(去重,文件不存在则创建)。 */
23
+ export declare function appendToGitignore(cwd: string, patterns: string[]): void;
24
+ /**
25
+ * 取当前分支名(非 git 仓库返回 null)。
26
+ */
27
+ export declare function getGitBranch(cwd: string): string | null;
28
+ /** 最后一次提交摘要(供分支名 hover tooltip)。 */
29
+ export interface GitLastCommit {
30
+ subject: string;
31
+ hash: string;
32
+ author: string;
33
+ date: string;
34
+ }
35
+ /**
36
+ * 取最后一次提交信息(subject/hash/author/相对时间)。
37
+ * 非 git 仓库或无提交(如全新仓库)返回 null。
38
+ */
39
+ export declare function getGitLastCommit(cwd: string): GitLastCommit | null;
40
+ /**
41
+ * 取工作区变更摘要(供 LLM 生成 commit message)。
42
+ * 包含 staged + unstaged diff(相对 HEAD)和 untracked 文件名列表。
43
+ * 非 git 仓库或无变更返回 null。
44
+ */
45
+ export declare function getGitDiffSummary(cwd: string): {
46
+ diff: string;
47
+ fileCount: number;
48
+ } | null;
49
+ /**
50
+ * 执行 git add -A + git commit。成功返回 commit 短 hash,失败返回 error 信息。
51
+ */
52
+ export declare function performGitCommit(cwd: string, message: string): {
53
+ hash: string;
54
+ } | {
55
+ error: string;
56
+ };
57
+ /** 分支信息。 */
58
+ export interface GitBranchInfo {
59
+ name: string;
60
+ current: boolean;
61
+ lastSubject: string | null;
62
+ }
63
+ /**
64
+ * 列出本地分支及当前分支标记(非 git 仓库返回 null)。
65
+ */
66
+ export declare function listGitBranches(cwd: string): GitBranchInfo[] | null;
67
+ /**
68
+ * 切换到指定分支(git checkout)。成功返回分支名,失败返回 error。
69
+ */
70
+ export declare function checkoutGitBranch(cwd: string, branch: string): {
71
+ branch: string;
72
+ } | {
73
+ error: string;
74
+ };
75
+ /**
76
+ * 创建并切换到新分支。成功返回分支名,失败返回 error。
77
+ */
78
+ export declare function createGitBranch(cwd: string, name: string): {
79
+ branch: string;
80
+ } | {
81
+ error: string;
82
+ };
8
83
  export declare function resolveProject(directory: string): ResolvedProject;