sqlew 3.7.2 → 3.7.4

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 (117) hide show
  1. package/CHANGELOG.md +237 -0
  2. package/LICENSE +0 -0
  3. package/README.md +2 -2
  4. package/assets/config.example.toml +0 -0
  5. package/assets/kanban-style.png +0 -0
  6. package/assets/sample-agents/README.md +0 -0
  7. package/assets/sample-agents/sqlew-architect.md +0 -0
  8. package/assets/sample-agents/sqlew-researcher.md +0 -0
  9. package/assets/sample-agents/sqlew-scrum-master.md +0 -0
  10. package/assets/schema.sql +0 -0
  11. package/assets/sqlew-logo.png +0 -0
  12. package/dist/cli/db-export.d.ts +29 -0
  13. package/dist/cli/db-export.d.ts.map +1 -0
  14. package/dist/cli/db-export.js +251 -0
  15. package/dist/cli/db-export.js.map +1 -0
  16. package/dist/cli/db-import.d.ts +31 -0
  17. package/dist/cli/db-import.d.ts.map +1 -0
  18. package/dist/cli/db-import.js +258 -0
  19. package/dist/cli/db-import.js.map +1 -0
  20. package/dist/cli.js +24 -2
  21. package/dist/cli.js.map +1 -1
  22. package/dist/config/knex/bootstrap/20251025020452_create_master_tables.d.ts.map +1 -1
  23. package/dist/config/knex/bootstrap/20251025020452_create_master_tables.js +12 -3
  24. package/dist/config/knex/bootstrap/20251025020452_create_master_tables.js.map +1 -1
  25. package/dist/config/knex/enhancements/20251106000000_fix_master_tables_project_id_v3_7_3.d.ts +29 -0
  26. package/dist/config/knex/enhancements/20251106000000_fix_master_tables_project_id_v3_7_3.d.ts.map +1 -0
  27. package/dist/config/knex/enhancements/20251106000000_fix_master_tables_project_id_v3_7_3.js +556 -0
  28. package/dist/config/knex/enhancements/20251106000000_fix_master_tables_project_id_v3_7_3.js.map +1 -0
  29. package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.d.ts.map +1 -1
  30. package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.js +110 -9
  31. package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.js.map +1 -1
  32. package/dist/database.d.ts +3 -3
  33. package/dist/database.d.ts.map +1 -1
  34. package/dist/database.js +30 -12
  35. package/dist/database.js.map +1 -1
  36. package/dist/tests/migration-idempotency.test.js +11 -10
  37. package/dist/tests/migration-idempotency.test.js.map +1 -1
  38. package/dist/tests/migration-upgrade-paths.test.js +6 -5
  39. package/dist/tests/migration-upgrade-paths.test.js.map +1 -1
  40. package/dist/tests/migrations/test-all-versions-real.js +3 -2
  41. package/dist/tests/migrations/test-all-versions-real.js.map +1 -1
  42. package/dist/tests/project-detector.test.d.ts +10 -0
  43. package/dist/tests/project-detector.test.d.ts.map +1 -0
  44. package/dist/tests/project-detector.test.js +156 -0
  45. package/dist/tests/project-detector.test.js.map +1 -0
  46. package/dist/tests/tasks.auto-pruning-partial.test.js +1 -1
  47. package/dist/tests/tasks.auto-pruning-partial.test.js.map +1 -1
  48. package/dist/tests/tasks.link-file-backward-compat.test.js +3 -3
  49. package/dist/tests/tasks.link-file-backward-compat.test.js.map +1 -1
  50. package/dist/tests/tasks.watch-files-action.test.js +1 -1
  51. package/dist/tests/tasks.watch-files-action.test.js.map +1 -1
  52. package/dist/tests/tasks.watch-files-parameter.test.js +2 -2
  53. package/dist/tests/tasks.watch-files-parameter.test.js.map +1 -1
  54. package/dist/tools/constraints.js +1 -1
  55. package/dist/tools/constraints.js.map +1 -1
  56. package/dist/tools/context.js +2 -2
  57. package/dist/tools/context.js.map +1 -1
  58. package/dist/tools/files.js +2 -2
  59. package/dist/tools/files.js.map +1 -1
  60. package/dist/tools/tasks.d.ts.map +1 -1
  61. package/dist/tools/tasks.js +7 -5
  62. package/dist/tools/tasks.js.map +1 -1
  63. package/dist/types.d.ts +121 -0
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/utils/exporter/export.d.ts +100 -0
  66. package/dist/utils/exporter/export.d.ts.map +1 -0
  67. package/dist/utils/exporter/export.js +363 -0
  68. package/dist/utils/exporter/export.js.map +1 -0
  69. package/dist/utils/importer/import.d.ts +29 -0
  70. package/dist/utils/importer/import.d.ts.map +1 -0
  71. package/dist/utils/importer/import.js +514 -0
  72. package/dist/utils/importer/import.js.map +1 -0
  73. package/dist/utils/importer/master-tables.d.ts +18 -0
  74. package/dist/utils/importer/master-tables.d.ts.map +1 -0
  75. package/dist/utils/importer/master-tables.js +255 -0
  76. package/dist/utils/importer/master-tables.js.map +1 -0
  77. package/dist/utils/importer/topological-sort.d.ts +61 -0
  78. package/dist/utils/importer/topological-sort.d.ts.map +1 -0
  79. package/dist/utils/importer/topological-sort.js +143 -0
  80. package/dist/utils/importer/topological-sort.js.map +1 -0
  81. package/dist/utils/project-detector.d.ts +42 -0
  82. package/dist/utils/project-detector.d.ts.map +1 -0
  83. package/dist/utils/project-detector.js +130 -0
  84. package/dist/utils/project-detector.js.map +1 -0
  85. package/docs/ACCEPTANCE_CRITERIA.md +0 -0
  86. package/docs/AI_AGENT_GUIDE.md +0 -0
  87. package/docs/ARCHITECTURE.md +0 -0
  88. package/docs/AUTO_FILE_TRACKING.md +0 -1
  89. package/docs/BEST_PRACTICES.md +0 -0
  90. package/docs/CONFIGURATION.md +0 -0
  91. package/docs/DATABASE_AUTH.md +1 -2
  92. package/docs/DECISION_CONTEXT.md +0 -0
  93. package/docs/DECISION_TO_TASK_MIGRATION_GUIDE.md +0 -0
  94. package/docs/GIT_AWARE_AUTO_COMPLETE.md +0 -0
  95. package/docs/SHARED_CONCEPTS.md +0 -0
  96. package/docs/SPECIALIZED_AGENTS.md +0 -0
  97. package/docs/TASK_ACTIONS.md +0 -0
  98. package/docs/TASK_DEPENDENCIES.md +0 -0
  99. package/docs/TASK_LINKING.md +0 -0
  100. package/docs/TASK_MIGRATION.md +0 -0
  101. package/docs/TASK_OVERVIEW.md +0 -0
  102. package/docs/TASK_PRUNING.md +0 -0
  103. package/docs/TASK_SYSTEM.md +0 -0
  104. package/docs/TOOL_REFERENCE.md +0 -2
  105. package/docs/TOOL_SELECTION.md +0 -0
  106. package/docs/WORKFLOWS.md +0 -0
  107. package/docs/{DATABASE_MIGRATION.md → cli/DATABASE_MIGRATION.md} +71 -32
  108. package/docs/cli/DATA_EXPORT_IMPORT.md +400 -0
  109. package/docs/cli/README.md +227 -0
  110. package/package.json +3 -2
  111. package/docs/BASEADAPTER_IMPLEMENTATION.md +0 -399
  112. package/docs/HELP_PREVIEW_COMPARISON.md +0 -259
  113. package/docs/MIGRATION_CHAIN.md +0 -293
  114. package/docs/MIGRATION_v2.md +0 -538
  115. package/docs/MIGRATION_v3.3.md +0 -602
  116. package/docs/MIGRATION_v3.6.0.md +0 -170
  117. package/docs/MULTI_PROJECT_ARCHITECTURE.md +0 -497
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Master Table Import with Smart Merge
3
+ *
4
+ * Handles importing master tables with intelligent ID remapping:
5
+ * - Project-scoped tables (m_files, m_tags, m_scopes): Smart merge on UNIQUE (project_id, name/path)
6
+ * - Global tables (m_agents, m_context_keys, etc.): Always create new IDs
7
+ *
8
+ * Architectural Decision: Decision #253 - Smart merge for project-scoped master tables
9
+ */
10
+ /**
11
+ * Import master tables and build ID mappings
12
+ *
13
+ * @param ctx - Import context with target project ID
14
+ * @returns Updated context with ID mappings populated
15
+ */
16
+ export async function importMasterTables(ctx) {
17
+ console.error(' Importing master tables...');
18
+ // Import order: no dependencies between master tables
19
+ await importAgents(ctx);
20
+ await importFiles(ctx);
21
+ await importContextKeys(ctx);
22
+ await importTags(ctx);
23
+ await importScopes(ctx);
24
+ await importConstraintCategories(ctx);
25
+ await importLayers(ctx);
26
+ await importTaskStatuses(ctx);
27
+ console.error(` ✓ Master tables imported (${getTotalMappings(ctx)} ID mappings created)`);
28
+ return ctx;
29
+ }
30
+ /**
31
+ * Import m_agents (global, create or reuse by name)
32
+ */
33
+ async function importAgents(ctx) {
34
+ const agents = ctx.jsonData.master_tables.agents || [];
35
+ for (const agent of agents) {
36
+ // Check if agent exists by name (global lookup)
37
+ const existing = await ctx.knex('m_agents')
38
+ .where({ name: agent.name })
39
+ .first();
40
+ if (existing) {
41
+ // Reuse existing global agent
42
+ ctx.mappings.agents.set(agent.id, existing.id);
43
+ }
44
+ else {
45
+ // Create new agent
46
+ const [newId] = await ctx.knex('m_agents').insert({
47
+ name: agent.name,
48
+ last_active_ts: agent.last_active_ts
49
+ });
50
+ ctx.mappings.agents.set(agent.id, newId);
51
+ }
52
+ }
53
+ ctx.stats.master_tables.agents_created = agents.length;
54
+ }
55
+ /**
56
+ * Import m_files (project-scoped, smart merge)
57
+ */
58
+ async function importFiles(ctx) {
59
+ const files = ctx.jsonData.master_tables.files || [];
60
+ let created = 0;
61
+ let reused = 0;
62
+ for (const file of files) {
63
+ // Check if file already exists in target project
64
+ const existing = await ctx.knex('m_files')
65
+ .where({
66
+ project_id: ctx.projectId,
67
+ path: file.path
68
+ })
69
+ .first();
70
+ if (existing) {
71
+ // Reuse existing ID
72
+ ctx.mappings.files.set(file.id, existing.id);
73
+ reused++;
74
+ }
75
+ else {
76
+ // Create new file entry
77
+ const [newId] = await ctx.knex('m_files').insert({
78
+ project_id: ctx.projectId,
79
+ path: file.path
80
+ });
81
+ ctx.mappings.files.set(file.id, newId);
82
+ created++;
83
+ }
84
+ }
85
+ ctx.stats.master_tables.files_created = created;
86
+ ctx.stats.master_tables.files_reused = reused;
87
+ }
88
+ /**
89
+ * Import m_context_keys (global, always create new)
90
+ *
91
+ * CRITICAL: context_keys.id IS the decision ID (t_decisions.key_id PRIMARY KEY)
92
+ * Never reuse context_keys even if key string matches
93
+ *
94
+ * Architectural Decision: Decision #251 - Context key isolation
95
+ */
96
+ async function importContextKeys(ctx) {
97
+ const keys = ctx.jsonData.master_tables.context_keys || [];
98
+ for (const key of keys) {
99
+ // Always create new context key (even if key string matches)
100
+ const [newId] = await ctx.knex('m_context_keys').insert({
101
+ key: key.key
102
+ });
103
+ ctx.mappings.context_keys.set(key.id, newId);
104
+ }
105
+ ctx.stats.master_tables.context_keys_created = keys.length;
106
+ }
107
+ /**
108
+ * Import m_tags (project-scoped, smart merge)
109
+ */
110
+ async function importTags(ctx) {
111
+ const tags = ctx.jsonData.master_tables.tags || [];
112
+ let created = 0;
113
+ let reused = 0;
114
+ for (const tag of tags) {
115
+ // Check if tag already exists in target project
116
+ const existing = await ctx.knex('m_tags')
117
+ .where({
118
+ project_id: ctx.projectId,
119
+ name: tag.name
120
+ })
121
+ .first();
122
+ if (existing) {
123
+ // Reuse existing ID
124
+ ctx.mappings.tags.set(tag.id, existing.id);
125
+ reused++;
126
+ }
127
+ else {
128
+ // Create new tag entry
129
+ const [newId] = await ctx.knex('m_tags').insert({
130
+ project_id: ctx.projectId,
131
+ name: tag.name
132
+ });
133
+ ctx.mappings.tags.set(tag.id, newId);
134
+ created++;
135
+ }
136
+ }
137
+ ctx.stats.master_tables.tags_created = created;
138
+ ctx.stats.master_tables.tags_reused = reused;
139
+ }
140
+ /**
141
+ * Import m_scopes (project-scoped, smart merge)
142
+ */
143
+ async function importScopes(ctx) {
144
+ const scopes = ctx.jsonData.master_tables.scopes || [];
145
+ let created = 0;
146
+ let reused = 0;
147
+ for (const scope of scopes) {
148
+ // Check if scope already exists in target project
149
+ const existing = await ctx.knex('m_scopes')
150
+ .where({
151
+ project_id: ctx.projectId,
152
+ name: scope.name
153
+ })
154
+ .first();
155
+ if (existing) {
156
+ // Reuse existing ID
157
+ ctx.mappings.scopes.set(scope.id, existing.id);
158
+ reused++;
159
+ }
160
+ else {
161
+ // Create new scope entry
162
+ const [newId] = await ctx.knex('m_scopes').insert({
163
+ project_id: ctx.projectId,
164
+ name: scope.name
165
+ });
166
+ ctx.mappings.scopes.set(scope.id, newId);
167
+ created++;
168
+ }
169
+ }
170
+ ctx.stats.master_tables.scopes_created = created;
171
+ ctx.stats.master_tables.scopes_reused = reused;
172
+ }
173
+ /**
174
+ * Import m_constraint_categories (global, create or reuse by name)
175
+ */
176
+ async function importConstraintCategories(ctx) {
177
+ const categories = ctx.jsonData.master_tables.constraint_categories || [];
178
+ for (const category of categories) {
179
+ // Check if category exists by name (global lookup)
180
+ const existing = await ctx.knex('m_constraint_categories')
181
+ .where({ name: category.name })
182
+ .first();
183
+ if (existing) {
184
+ // Reuse existing global category
185
+ ctx.mappings.constraint_categories.set(category.id, existing.id);
186
+ }
187
+ else {
188
+ // Create new category
189
+ const [newId] = await ctx.knex('m_constraint_categories').insert({
190
+ name: category.name
191
+ });
192
+ ctx.mappings.constraint_categories.set(category.id, newId);
193
+ }
194
+ }
195
+ }
196
+ /**
197
+ * Import m_layers (global, create or reuse by name)
198
+ */
199
+ async function importLayers(ctx) {
200
+ const layers = ctx.jsonData.master_tables.layers || [];
201
+ for (const layer of layers) {
202
+ // Check if layer exists by name (global lookup)
203
+ const existing = await ctx.knex('m_layers')
204
+ .where({ name: layer.name })
205
+ .first();
206
+ if (existing) {
207
+ // Reuse existing global layer
208
+ ctx.mappings.layers.set(layer.id, existing.id);
209
+ }
210
+ else {
211
+ // Create new layer
212
+ const [newId] = await ctx.knex('m_layers').insert({
213
+ name: layer.name
214
+ });
215
+ ctx.mappings.layers.set(layer.id, newId);
216
+ }
217
+ }
218
+ }
219
+ /**
220
+ * Import m_task_statuses (global, create or reuse by name)
221
+ */
222
+ async function importTaskStatuses(ctx) {
223
+ const statuses = ctx.jsonData.master_tables.task_statuses || [];
224
+ for (const status of statuses) {
225
+ // Check if status exists by name (global lookup)
226
+ const existing = await ctx.knex('m_task_statuses')
227
+ .where({ name: status.name })
228
+ .first();
229
+ if (existing) {
230
+ // Reuse existing global status
231
+ ctx.mappings.task_statuses.set(status.id, existing.id);
232
+ }
233
+ else {
234
+ // Create new status
235
+ const [newId] = await ctx.knex('m_task_statuses').insert({
236
+ name: status.name
237
+ });
238
+ ctx.mappings.task_statuses.set(status.id, newId);
239
+ }
240
+ }
241
+ }
242
+ /**
243
+ * Get total number of ID mappings created
244
+ */
245
+ function getTotalMappings(ctx) {
246
+ return (ctx.mappings.agents.size +
247
+ ctx.mappings.files.size +
248
+ ctx.mappings.context_keys.size +
249
+ ctx.mappings.tags.size +
250
+ ctx.mappings.scopes.size +
251
+ ctx.mappings.constraint_categories.size +
252
+ ctx.mappings.layers.size +
253
+ ctx.mappings.task_statuses.size);
254
+ }
255
+ //# sourceMappingURL=master-tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"master-tables.js","sourceRoot":"","sources":["../../../src/utils/importer/master-tables.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Topological Sort for Task Dependencies
3
+ *
4
+ * Implements BFS-based topological sorting to determine safe import order for tasks
5
+ * with dependencies. This ensures blocker tasks are imported before blocked tasks,
6
+ * satisfying foreign key constraints in t_task_dependencies.
7
+ */
8
+ import type { TaskDependencyGraph } from '../../types.js';
9
+ /**
10
+ * Task dependency record from exported JSON
11
+ */
12
+ export interface TaskDependency {
13
+ blocker_task_id: number;
14
+ blocked_task_id: number;
15
+ created_ts: number;
16
+ }
17
+ /**
18
+ * Build dependency graph from task dependency records
19
+ *
20
+ * @param dependencies - Array of task dependencies from export
21
+ * @param allTaskIds - Set of all task IDs (some tasks may have no dependencies)
22
+ * @returns Dependency graph with adjacency lists
23
+ */
24
+ export declare function buildDependencyGraph(dependencies: TaskDependency[], allTaskIds: Set<number>): TaskDependencyGraph;
25
+ /**
26
+ * Topological sort using BFS (Kahn's algorithm)
27
+ *
28
+ * Ensures tasks are ordered such that all dependencies are satisfied:
29
+ * - A task appears in the sorted list AFTER all tasks it depends on
30
+ * - Blocker tasks appear before blocked tasks
31
+ *
32
+ * @param graph - Dependency graph from buildDependencyGraph
33
+ * @returns Array of task IDs in safe import order
34
+ * @throws Error if circular dependency detected
35
+ */
36
+ export declare function topologicalSort(graph: TaskDependencyGraph): number[];
37
+ /**
38
+ * Sort tasks by dependency order for import
39
+ *
40
+ * High-level function that combines graph building and topological sorting.
41
+ *
42
+ * @param tasks - Array of tasks from export
43
+ * @param dependencies - Array of task dependencies from export
44
+ * @returns Array of tasks sorted in safe import order
45
+ * @throws Error if circular dependency detected
46
+ */
47
+ export declare function sortTasksByDependencies<T extends {
48
+ id: number;
49
+ }>(tasks: T[], dependencies: TaskDependency[]): T[];
50
+ /**
51
+ * Validate task dependencies for circular references
52
+ *
53
+ * @param dependencies - Array of task dependencies
54
+ * @param allTaskIds - Set of all valid task IDs
55
+ * @returns Validation result with errors if any
56
+ */
57
+ export declare function validateTaskDependencies(dependencies: TaskDependency[], allTaskIds: Set<number>): {
58
+ valid: boolean;
59
+ errors: string[];
60
+ };
61
+ //# sourceMappingURL=topological-sort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topological-sort.d.ts","sourceRoot":"","sources":["../../../src/utils/importer/topological-sort.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,cAAc,EAAE,EAC9B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACtB,mBAAmB,CA4BrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAoCpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAC9D,KAAK,EAAE,CAAC,EAAE,EACV,YAAY,EAAE,cAAc,EAAE,GAC7B,CAAC,EAAE,CAiBL;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,cAAc,EAAE,EAC9B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACtB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAkCtC"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Topological Sort for Task Dependencies
3
+ *
4
+ * Implements BFS-based topological sorting to determine safe import order for tasks
5
+ * with dependencies. This ensures blocker tasks are imported before blocked tasks,
6
+ * satisfying foreign key constraints in t_task_dependencies.
7
+ */
8
+ /**
9
+ * Build dependency graph from task dependency records
10
+ *
11
+ * @param dependencies - Array of task dependencies from export
12
+ * @param allTaskIds - Set of all task IDs (some tasks may have no dependencies)
13
+ * @returns Dependency graph with adjacency lists
14
+ */
15
+ export function buildDependencyGraph(dependencies, allTaskIds) {
16
+ const children = new Map();
17
+ const parents = new Map();
18
+ // Build adjacency lists
19
+ for (const dep of dependencies) {
20
+ // Add to children map (blocker -> [blocked])
21
+ if (!children.has(dep.blocker_task_id)) {
22
+ children.set(dep.blocker_task_id, []);
23
+ }
24
+ children.get(dep.blocker_task_id).push(dep.blocked_task_id);
25
+ // Add to parents map (blocked -> [blockers])
26
+ if (!parents.has(dep.blocked_task_id)) {
27
+ parents.set(dep.blocked_task_id, []);
28
+ }
29
+ parents.get(dep.blocked_task_id).push(dep.blocker_task_id);
30
+ }
31
+ // Find roots (tasks that are never blocked)
32
+ const roots = Array.from(allTaskIds).filter(id => !parents.has(id));
33
+ return {
34
+ roots,
35
+ children,
36
+ parents,
37
+ allTaskIds
38
+ };
39
+ }
40
+ /**
41
+ * Topological sort using BFS (Kahn's algorithm)
42
+ *
43
+ * Ensures tasks are ordered such that all dependencies are satisfied:
44
+ * - A task appears in the sorted list AFTER all tasks it depends on
45
+ * - Blocker tasks appear before blocked tasks
46
+ *
47
+ * @param graph - Dependency graph from buildDependencyGraph
48
+ * @returns Array of task IDs in safe import order
49
+ * @throws Error if circular dependency detected
50
+ */
51
+ export function topologicalSort(graph) {
52
+ const sorted = [];
53
+ const visited = new Set();
54
+ const queue = [...graph.roots];
55
+ while (queue.length > 0) {
56
+ const taskId = queue.shift();
57
+ // Skip if already visited (shouldn't happen in DAG, but safety check)
58
+ if (visited.has(taskId))
59
+ continue;
60
+ visited.add(taskId);
61
+ sorted.push(taskId);
62
+ // Add children whose dependencies are all satisfied
63
+ const childIds = graph.children.get(taskId) || [];
64
+ for (const childId of childIds) {
65
+ const parentIds = graph.parents.get(childId) || [];
66
+ // Check if all parents (blockers) have been visited
67
+ if (parentIds.every((parentId) => visited.has(parentId))) {
68
+ queue.push(childId);
69
+ }
70
+ }
71
+ }
72
+ // Detect circular dependencies
73
+ if (sorted.length < graph.allTaskIds.size) {
74
+ const unvisited = Array.from(graph.allTaskIds).filter(id => !visited.has(id));
75
+ throw new Error(`Circular dependency detected in tasks. ` +
76
+ `Cannot determine import order. Unvisited task IDs: ${unvisited.join(', ')}`);
77
+ }
78
+ return sorted;
79
+ }
80
+ /**
81
+ * Sort tasks by dependency order for import
82
+ *
83
+ * High-level function that combines graph building and topological sorting.
84
+ *
85
+ * @param tasks - Array of tasks from export
86
+ * @param dependencies - Array of task dependencies from export
87
+ * @returns Array of tasks sorted in safe import order
88
+ * @throws Error if circular dependency detected
89
+ */
90
+ export function sortTasksByDependencies(tasks, dependencies) {
91
+ // Extract all task IDs
92
+ const allTaskIds = new Set(tasks.map(t => t.id));
93
+ // Build dependency graph
94
+ const graph = buildDependencyGraph(dependencies, allTaskIds);
95
+ // Perform topological sort
96
+ const sortedIds = topologicalSort(graph);
97
+ // Map sorted IDs back to task objects
98
+ const taskMap = new Map(tasks.map(t => [t.id, t]));
99
+ const sortedTasks = sortedIds
100
+ .map(id => taskMap.get(id))
101
+ .filter((t) => t !== undefined);
102
+ return sortedTasks;
103
+ }
104
+ /**
105
+ * Validate task dependencies for circular references
106
+ *
107
+ * @param dependencies - Array of task dependencies
108
+ * @param allTaskIds - Set of all valid task IDs
109
+ * @returns Validation result with errors if any
110
+ */
111
+ export function validateTaskDependencies(dependencies, allTaskIds) {
112
+ const errors = [];
113
+ // Check for self-dependencies
114
+ for (const dep of dependencies) {
115
+ if (dep.blocker_task_id === dep.blocked_task_id) {
116
+ errors.push(`Task ${dep.blocker_task_id} cannot depend on itself`);
117
+ }
118
+ }
119
+ // Check for invalid task IDs
120
+ for (const dep of dependencies) {
121
+ if (!allTaskIds.has(dep.blocker_task_id)) {
122
+ errors.push(`Blocker task ${dep.blocker_task_id} not found in task list`);
123
+ }
124
+ if (!allTaskIds.has(dep.blocked_task_id)) {
125
+ errors.push(`Blocked task ${dep.blocked_task_id} not found in task list`);
126
+ }
127
+ }
128
+ // Try to detect circular dependencies
129
+ if (errors.length === 0) {
130
+ try {
131
+ const graph = buildDependencyGraph(dependencies, allTaskIds);
132
+ topologicalSort(graph);
133
+ }
134
+ catch (error) {
135
+ errors.push(error instanceof Error ? error.message : String(error));
136
+ }
137
+ }
138
+ return {
139
+ valid: errors.length === 0,
140
+ errors
141
+ };
142
+ }
143
+ //# sourceMappingURL=topological-sort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topological-sort.js","sourceRoot":"","sources":["../../../src/utils/importer/topological-sort.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,YAA8B,EAC9B,UAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE5C,wBAAwB;IACxB,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,6CAA6C;QAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACvC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAE,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAE7D,6CAA6C;QAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAE,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9D,CAAC;IAED,4CAA4C;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpE,OAAO;QACL,KAAK;QACL,QAAQ;QACR,OAAO;QACP,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,KAA0B;IACxD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,KAAK,GAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAEzC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAE9B,sEAAsE;QACtE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QAElC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEpB,oDAAoD;QACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAClD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAEnD,oDAAoD;YACpD,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBACjE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9E,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,sDAAsD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAU,EACV,YAA8B;IAE9B,uBAAuB;IACvB,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEjD,yBAAyB;IACzB,MAAM,KAAK,GAAG,oBAAoB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAE7D,2BAA2B;IAC3B,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAEzC,sCAAsC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,SAAS;SAC1B,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAU,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAE1C,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,YAA8B,EAC9B,UAAuB;IAEvB,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,8BAA8B;IAC9B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,eAAe,KAAK,GAAG,CAAC,eAAe,EAAE,CAAC;YAChD,MAAM,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,eAAe,0BAA0B,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,eAAe,yBAAyB,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,eAAe,yBAAyB,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,sCAAsC;IACtC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,oBAAoB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAC7D,eAAe,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Project name detection utility
3
+ *
4
+ * Extracts project detection logic from index.ts for reuse in:
5
+ * - Migrations (sync version)
6
+ * - Index.ts (async version with VCS support)
7
+ * - Tests
8
+ *
9
+ * Detection Priority:
10
+ * 1. config.toml [project] name (authoritative)
11
+ * 2. Git remote URL (best-effort)
12
+ * 3. Directory name (fallback)
13
+ */
14
+ /**
15
+ * Detection result with source attribution
16
+ */
17
+ export interface DetectedProject {
18
+ name: string;
19
+ source: 'config' | 'git' | 'directory';
20
+ }
21
+ /**
22
+ * Detect project name (async version with VCS support)
23
+ *
24
+ * Use this in index.ts and other runtime code where async operations are available.
25
+ *
26
+ * @param projectRoot - Project root directory
27
+ * @param configPath - Optional path to config.toml (defaults to .sqlew/config.toml)
28
+ * @returns Project name and detection source
29
+ */
30
+ export declare function detectProjectName(projectRoot: string, configPath?: string): Promise<DetectedProject>;
31
+ /**
32
+ * Detect project name (sync version without VCS support)
33
+ *
34
+ * Use this in migrations where async operations are not available.
35
+ * Detection order: config → directory (skips VCS)
36
+ *
37
+ * @param projectRoot - Project root directory
38
+ * @param configPath - Optional path to config.toml (defaults to .sqlew/config.toml)
39
+ * @returns Project name and detection source
40
+ */
41
+ export declare function detectProjectNameSync(projectRoot: string, configPath?: string): DetectedProject;
42
+ //# sourceMappingURL=project-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-detector.d.ts","sourceRoot":"","sources":["../../src/utils/project-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG,WAAW,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CAe1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,eAAe,CASjB"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Project name detection utility
3
+ *
4
+ * Extracts project detection logic from index.ts for reuse in:
5
+ * - Migrations (sync version)
6
+ * - Index.ts (async version with VCS support)
7
+ * - Tests
8
+ *
9
+ * Detection Priority:
10
+ * 1. config.toml [project] name (authoritative)
11
+ * 2. Git remote URL (best-effort)
12
+ * 3. Directory name (fallback)
13
+ */
14
+ import { existsSync, readFileSync } from 'fs';
15
+ import { resolve, sep } from 'path';
16
+ import { parse as parseTOML } from 'smol-toml';
17
+ import { DEFAULT_CONFIG_PATH } from '../config/loader.js';
18
+ import { detectVCS } from './vcs-adapter.js';
19
+ /**
20
+ * Detect project name (async version with VCS support)
21
+ *
22
+ * Use this in index.ts and other runtime code where async operations are available.
23
+ *
24
+ * @param projectRoot - Project root directory
25
+ * @param configPath - Optional path to config.toml (defaults to .sqlew/config.toml)
26
+ * @returns Project name and detection source
27
+ */
28
+ export async function detectProjectName(projectRoot, configPath) {
29
+ // Priority 1: Check config.toml
30
+ const fromConfig = detectFromConfig(projectRoot, configPath);
31
+ if (fromConfig) {
32
+ return fromConfig;
33
+ }
34
+ // Priority 2: Try VCS detection (async)
35
+ const fromVCS = await detectFromVCS(projectRoot);
36
+ if (fromVCS) {
37
+ return fromVCS;
38
+ }
39
+ // Priority 3: Fallback to directory name
40
+ return detectFromDirectory(projectRoot);
41
+ }
42
+ /**
43
+ * Detect project name (sync version without VCS support)
44
+ *
45
+ * Use this in migrations where async operations are not available.
46
+ * Detection order: config → directory (skips VCS)
47
+ *
48
+ * @param projectRoot - Project root directory
49
+ * @param configPath - Optional path to config.toml (defaults to .sqlew/config.toml)
50
+ * @returns Project name and detection source
51
+ */
52
+ export function detectProjectNameSync(projectRoot, configPath) {
53
+ // Priority 1: Check config.toml
54
+ const fromConfig = detectFromConfig(projectRoot, configPath);
55
+ if (fromConfig) {
56
+ return fromConfig;
57
+ }
58
+ // Priority 2: Fallback to directory name (skip VCS in sync mode)
59
+ return detectFromDirectory(projectRoot);
60
+ }
61
+ /**
62
+ * Try to detect project name from config.toml
63
+ *
64
+ * @param projectRoot - Project root directory
65
+ * @param configPath - Optional path to config.toml
66
+ * @returns Project name or null if not found
67
+ */
68
+ function detectFromConfig(projectRoot, configPath) {
69
+ const finalPath = configPath || DEFAULT_CONFIG_PATH;
70
+ const absolutePath = resolve(projectRoot, finalPath);
71
+ if (!existsSync(absolutePath)) {
72
+ return null;
73
+ }
74
+ try {
75
+ const content = readFileSync(absolutePath, 'utf-8');
76
+ const parsed = parseTOML(content);
77
+ if (parsed.project?.name && parsed.project.name.trim().length > 0) {
78
+ return {
79
+ name: parsed.project.name,
80
+ source: 'config',
81
+ };
82
+ }
83
+ }
84
+ catch {
85
+ // Parse error - skip config source
86
+ }
87
+ return null;
88
+ }
89
+ /**
90
+ * Try to detect project name from VCS (async)
91
+ *
92
+ * @param projectRoot - Project root directory
93
+ * @returns Project name or null if not found
94
+ */
95
+ async function detectFromVCS(projectRoot) {
96
+ try {
97
+ const vcsAdapter = await detectVCS(projectRoot);
98
+ if (vcsAdapter) {
99
+ const detectedName = await vcsAdapter.extractProjectName();
100
+ if (detectedName) {
101
+ return {
102
+ name: detectedName,
103
+ source: 'git',
104
+ };
105
+ }
106
+ }
107
+ }
108
+ catch {
109
+ // VCS detection failed - continue to fallback
110
+ }
111
+ return null;
112
+ }
113
+ /**
114
+ * Detect project name from directory name (fallback)
115
+ *
116
+ * @param projectRoot - Project root directory
117
+ * @returns Project name from directory
118
+ */
119
+ function detectFromDirectory(projectRoot) {
120
+ // Handle both Unix (/) and Windows (\) path separators
121
+ const pathSeparator = projectRoot.includes('/') ? '/' : sep;
122
+ const dirSegments = projectRoot.split(pathSeparator).filter(s => s.length > 0);
123
+ // Extract last directory name, fallback to 'default' if empty
124
+ const dirName = dirSegments[dirSegments.length - 1] || 'default';
125
+ return {
126
+ name: dirName,
127
+ source: 'directory',
128
+ };
129
+ }
130
+ //# sourceMappingURL=project-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-detector.js","sourceRoot":"","sources":["../../src/utils/project-detector.ts"],"names":[],"mappings":"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"}
File without changes
File without changes
File without changes