@leejungkiin/awkit 1.1.7 → 1.2.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 (48) hide show
  1. package/README.md +36 -4
  2. package/bin/awk.js +2 -2
  3. package/package.json +6 -3
  4. package/skill-packs/neural-memory/skills/nm-memory-sync/SKILL.md +14 -1
  5. package/skills/gitnexus-intelligence/SKILL.md +224 -0
  6. package/skills/orchestrator/SKILL.md +9 -0
  7. package/skills/symphony-orchestrator/SKILL.md +9 -7
  8. package/workflows/gitnexus.md +123 -0
  9. package/symphony/LICENSE +0 -21
  10. package/symphony/README.md +0 -178
  11. package/symphony/app/api/agents/route.js +0 -152
  12. package/symphony/app/api/events/route.js +0 -22
  13. package/symphony/app/api/knowledge/route.js +0 -253
  14. package/symphony/app/api/locks/route.js +0 -29
  15. package/symphony/app/api/notes/route.js +0 -125
  16. package/symphony/app/api/preflight/route.js +0 -23
  17. package/symphony/app/api/projects/route.js +0 -116
  18. package/symphony/app/api/roles/route.js +0 -134
  19. package/symphony/app/api/skills/route.js +0 -82
  20. package/symphony/app/api/status/route.js +0 -18
  21. package/symphony/app/api/tasks/route.js +0 -157
  22. package/symphony/app/api/workflows/route.js +0 -61
  23. package/symphony/app/api/workspaces/route.js +0 -15
  24. package/symphony/app/globals.css +0 -2605
  25. package/symphony/app/layout.js +0 -20
  26. package/symphony/app/page.js +0 -2122
  27. package/symphony/cli/index.js +0 -1060
  28. package/symphony/core/agent-manager.js +0 -357
  29. package/symphony/core/context-bus.js +0 -100
  30. package/symphony/core/db.js +0 -223
  31. package/symphony/core/file-lock-manager.js +0 -154
  32. package/symphony/core/merge-pipeline.js +0 -234
  33. package/symphony/core/orchestrator.js +0 -236
  34. package/symphony/core/task-manager.js +0 -335
  35. package/symphony/core/workspace-manager.js +0 -168
  36. package/symphony/jsconfig.json +0 -7
  37. package/symphony/lib/core.mjs +0 -1034
  38. package/symphony/mcp/index.js +0 -29
  39. package/symphony/mcp/server.js +0 -110
  40. package/symphony/mcp/tools/context.js +0 -80
  41. package/symphony/mcp/tools/locks.js +0 -99
  42. package/symphony/mcp/tools/status.js +0 -82
  43. package/symphony/mcp/tools/tasks.js +0 -216
  44. package/symphony/mcp/tools/workspace.js +0 -143
  45. package/symphony/next.config.mjs +0 -7
  46. package/symphony/package.json +0 -53
  47. package/symphony/scripts/postinstall.js +0 -49
  48. package/symphony/symphony.config.js +0 -41
@@ -1,335 +0,0 @@
1
- /**
2
- * Symphony Task Manager
3
- * CRUD operations for tasks with atomic claim/complete semantics.
4
- */
5
- const { nanoid } = require('nanoid');
6
- const { getDb } = require('./db');
7
-
8
- /**
9
- * Create a new task.
10
- * @param {string} title - Task title
11
- * @param {Object} [opts] - Optional fields
12
- * @returns {Object} Created task
13
- */
14
- function createTask(title, opts = {}) {
15
- const db = getDb();
16
- const id = opts.id || `sym-${nanoid(8)}`;
17
- const estimatedFiles = opts.estimatedFiles
18
- ? JSON.stringify(opts.estimatedFiles)
19
- : null;
20
- const requiredSkills = opts.requiredSkills
21
- ? JSON.stringify(opts.requiredSkills)
22
- : '[]';
23
-
24
- const stmt = db.prepare(`
25
- INSERT INTO tasks (id, title, description, status, priority, acceptance, phase, epic_id, estimated_files, project_id, required_skills)
26
- VALUES (?, ?, ?, 'ready', ?, ?, ?, ?, ?, ?, ?)
27
- `);
28
-
29
- stmt.run(
30
- id,
31
- title,
32
- opts.description || null,
33
- opts.priority || 2,
34
- opts.acceptance || null,
35
- opts.phase || null,
36
- opts.epicId || null,
37
- estimatedFiles,
38
- opts.projectId || null,
39
- requiredSkills
40
- );
41
-
42
- return getTask(id);
43
- }
44
-
45
- /**
46
- * Get a single task by ID.
47
- * @param {string} id - Task ID
48
- * @returns {Object|null}
49
- */
50
- function getTask(id) {
51
- const db = getDb();
52
- const row = db.prepare('SELECT * FROM tasks WHERE id = ?').get(id);
53
- return row ? normalizeTask(row) : null;
54
- }
55
-
56
- /**
57
- * List tasks with optional filters.
58
- * @param {Object} [filter] - { status, agentId, phase, epicId, project, limit }
59
- * @returns {Object[]}
60
- */
61
- function listTasks(filter = {}) {
62
- const db = getDb();
63
- const conditions = [];
64
- const params = [];
65
-
66
- if (filter.status) {
67
- conditions.push('status = ?');
68
- params.push(filter.status);
69
- }
70
- if (filter.agentId) {
71
- conditions.push('agent_id = ?');
72
- params.push(filter.agentId);
73
- }
74
- if (filter.phase) {
75
- conditions.push('phase = ?');
76
- params.push(filter.phase);
77
- }
78
- if (filter.epicId) {
79
- conditions.push('epic_id = ?');
80
- params.push(filter.epicId);
81
- }
82
- if (filter.project) {
83
- conditions.push('project_id = ?');
84
- params.push(filter.project);
85
- }
86
-
87
- const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
88
- const limit = filter.limit ? `LIMIT ${parseInt(filter.limit)}` : '';
89
- const order = 'ORDER BY priority ASC, created_at ASC';
90
-
91
- const rows = db.prepare(`SELECT * FROM tasks ${where} ${order} ${limit}`).all(...params);
92
- return rows.map(normalizeTask);
93
- }
94
-
95
- /**
96
- * Claim a task for an agent (atomic operation).
97
- * @param {string} taskId - Task ID
98
- * @param {string} agentId - Agent ID
99
- * @returns {Object} Updated task
100
- * @throws {Error} If task is not claimable
101
- */
102
- function claimTask(taskId, agentId) {
103
- const db = getDb();
104
-
105
- const claim = db.transaction(() => {
106
- const task = db.prepare('SELECT * FROM tasks WHERE id = ?').get(taskId);
107
- if (!task) throw new Error(`Task not found: ${taskId}`);
108
- if (task.status !== 'ready') {
109
- throw new Error(`Task ${taskId} is not claimable (status: ${task.status})`);
110
- }
111
-
112
- db.prepare(`
113
- UPDATE tasks
114
- SET status = 'claimed', agent_id = ?, claimed_at = datetime('now')
115
- WHERE id = ?
116
- `).run(agentId, taskId);
117
-
118
- return db.prepare('SELECT * FROM tasks WHERE id = ?').get(taskId);
119
- });
120
-
121
- return normalizeTask(claim());
122
- }
123
-
124
- /**
125
- * Update task progress.
126
- * @param {string} taskId - Task ID
127
- * @param {number} progress - Progress 0-100
128
- * @param {Object} [opts] - { currentFile, lastAction }
129
- */
130
- function updateProgress(taskId, progress, opts = {}) {
131
- const db = getDb();
132
- db.prepare(`
133
- UPDATE tasks SET progress = ?, status = 'in_progress' WHERE id = ?
134
- `).run(Math.min(100, Math.max(0, progress)), taskId);
135
- return getTask(taskId);
136
- }
137
-
138
- /**
139
- * Complete a task.
140
- * @param {string} taskId - Task ID
141
- * @param {string} summary - Completion summary
142
- * @param {string[]} [filesChanged] - List of changed files
143
- * @returns {Object} Updated task
144
- */
145
- function completeTask(taskId, summary, filesChanged = []) {
146
- const db = getDb();
147
- db.prepare(`
148
- UPDATE tasks
149
- SET status = 'done', summary = ?, progress = 100, completed_at = datetime('now')
150
- WHERE id = ?
151
- `).run(summary, taskId);
152
- return getTask(taskId);
153
- }
154
-
155
- /**
156
- * Abandon a task (agent gives up).
157
- * @param {string} taskId - Task ID
158
- * @param {string} reason - Reason for abandoning
159
- * @returns {Object} Updated task
160
- */
161
- function abandonTask(taskId, reason) {
162
- const db = getDb();
163
- db.prepare(`
164
- UPDATE tasks
165
- SET status = 'ready', agent_id = NULL, summary = ?, progress = 0
166
- WHERE id = ?
167
- `).run(`Abandoned: ${reason}`, taskId);
168
- return getTask(taskId);
169
- }
170
-
171
- /**
172
- * Move task to review status.
173
- * @param {string} taskId - Task ID
174
- * @returns {Object} Updated task
175
- */
176
- function reviewTask(taskId) {
177
- const db = getDb();
178
- db.prepare(`UPDATE tasks SET status = 'review' WHERE id = ?`).run(taskId);
179
- return getTask(taskId);
180
- }
181
-
182
- /**
183
- * Get task stats.
184
- * @returns {Object} { ready, claimed, in_progress, review, done, total }
185
- */
186
- function getStats() {
187
- const db = getDb();
188
- const rows = db.prepare(`
189
- SELECT status, COUNT(*) as count FROM tasks GROUP BY status
190
- `).all();
191
-
192
- const stats = { ready: 0, claimed: 0, in_progress: 0, review: 0, done: 0, abandoned: 0, total: 0 };
193
- for (const row of rows) {
194
- stats[row.status] = row.count;
195
- stats.total += row.count;
196
- }
197
- return stats;
198
- }
199
-
200
- /**
201
- * Normalize a task row from the database.
202
- */
203
- function normalizeTask(row) {
204
- return {
205
- ...row,
206
- estimated_files: row.estimated_files ? JSON.parse(row.estimated_files) : [],
207
- };
208
- }
209
-
210
- /**
211
- * Update task fields.
212
- * @param {string} taskId - Task ID
213
- * @param {Object} fields - { title, description, priority, acceptance, phase, sort_order }
214
- * @returns {Object} Updated task
215
- */
216
- function updateTask(taskId, fields) {
217
- const db = getDb();
218
- const allowed = ['title', 'description', 'priority', 'acceptance', 'phase', 'sort_order'];
219
- const sets = [];
220
- const params = [];
221
-
222
- for (const key of allowed) {
223
- if (fields[key] !== undefined) {
224
- sets.push(`${key} = ?`);
225
- params.push(fields[key]);
226
- }
227
- }
228
-
229
- if (sets.length === 0) return getTask(taskId);
230
-
231
- params.push(taskId);
232
- db.prepare(`UPDATE tasks SET ${sets.join(', ')} WHERE id = ?`).run(...params);
233
- return getTask(taskId);
234
- }
235
-
236
- /**
237
- * Delete a task (only draft or ready status).
238
- * @param {string} taskId - Task ID
239
- * @returns {boolean} Success
240
- */
241
- function deleteTask(taskId) {
242
- const db = getDb();
243
- const task = db.prepare('SELECT status FROM tasks WHERE id = ?').get(taskId);
244
- if (!task) throw new Error(`Task not found: ${taskId}`);
245
- if (!['draft', 'ready'].includes(task.status)) {
246
- throw new Error(`Cannot delete task in ${task.status} status`);
247
- }
248
- db.prepare('DELETE FROM tasks WHERE id = ?').run(taskId);
249
- return true;
250
- }
251
-
252
- /**
253
- * Approve a draft task → ready.
254
- * @param {string} taskId - Task ID
255
- * @returns {Object} Updated task
256
- */
257
- function approveTask(taskId) {
258
- const db = getDb();
259
- const task = db.prepare('SELECT status FROM tasks WHERE id = ?').get(taskId);
260
- if (!task) throw new Error(`Task not found: ${taskId}`);
261
- if (task.status !== 'draft') {
262
- throw new Error(`Task ${taskId} is not a draft (status: ${task.status})`);
263
- }
264
- db.prepare("UPDATE tasks SET status = 'ready' WHERE id = ?").run(taskId);
265
- return getTask(taskId);
266
- }
267
-
268
- /**
269
- * Batch approve multiple draft tasks → ready.
270
- * @param {string[]} taskIds - Array of task IDs
271
- * @returns {number} Number of approved tasks
272
- */
273
- function bulkApprove(taskIds) {
274
- const db = getDb();
275
- const stmt = db.prepare("UPDATE tasks SET status = 'ready' WHERE id = ? AND status = 'draft'");
276
- let count = 0;
277
- const run = db.transaction(() => {
278
- for (const id of taskIds) {
279
- const result = stmt.run(id);
280
- count += result.changes;
281
- }
282
- });
283
- run();
284
- return count;
285
- }
286
-
287
- /**
288
- * Reopen a done task → ready (reset agent, progress).
289
- * @param {string} taskId - Task ID
290
- * @returns {Object} Updated task
291
- */
292
- function reopenTask(taskId) {
293
- const db = getDb();
294
- db.prepare(`
295
- UPDATE tasks
296
- SET status = 'ready', agent_id = NULL, progress = 0,
297
- claimed_at = NULL, completed_at = NULL, summary = NULL
298
- WHERE id = ?
299
- `).run(taskId);
300
- return getTask(taskId);
301
- }
302
-
303
- /**
304
- * Reorder tasks by setting sort_order based on array position.
305
- * @param {string[]} orderedIds - Task IDs in desired order
306
- */
307
- function reorderTasks(orderedIds) {
308
- const db = getDb();
309
- const stmt = db.prepare('UPDATE tasks SET sort_order = ? WHERE id = ?');
310
- const run = db.transaction(() => {
311
- for (let i = 0; i < orderedIds.length; i++) {
312
- stmt.run(i, orderedIds[i]);
313
- }
314
- });
315
- run();
316
- }
317
-
318
- module.exports = {
319
- createTask,
320
- getTask,
321
- listTasks,
322
- claimTask,
323
- updateProgress,
324
- completeTask,
325
- abandonTask,
326
- reviewTask,
327
- getStats,
328
- updateTask,
329
- deleteTask,
330
- approveTask,
331
- bulkApprove,
332
- reopenTask,
333
- reorderTasks,
334
- };
335
-
@@ -1,168 +0,0 @@
1
- /**
2
- * Symphony Workspace Manager
3
- * Git worktree lifecycle management with hybrid clone/worktree support.
4
- */
5
- const { execSync } = require('child_process');
6
- const { nanoid } = require('nanoid');
7
- const { getDb } = require('./db');
8
- const path = require('path');
9
- const fs = require('fs');
10
-
11
- /**
12
- * Create a workspace for a task.
13
- * Uses git worktree (default) or full clone based on hybrid config.
14
- *
15
- * @param {string} taskId - Task ID
16
- * @param {string} repoPath - Path to the main repository
17
- * @param {Object} [opts] - { type: 'worktree'|'clone', branchPrefix }
18
- * @returns {Object} { id, path, branch, type }
19
- */
20
- function createWorkspace(taskId, repoPath, opts = {}) {
21
- const db = getDb();
22
- const type = opts.type || 'worktree';
23
- const branchPrefix = opts.branchPrefix || 'symphony/';
24
- const branch = `${branchPrefix}${sanitizeId(taskId)}`;
25
- const wsId = `ws-${nanoid(8)}`;
26
-
27
- const workspaceRoot = path.resolve(repoPath, '.symphony', 'workspaces');
28
- if (!fs.existsSync(workspaceRoot)) {
29
- fs.mkdirSync(workspaceRoot, { recursive: true });
30
- }
31
-
32
- const wsPath = path.join(workspaceRoot, sanitizeId(taskId));
33
-
34
- if (type === 'worktree') {
35
- createWorktree(repoPath, wsPath, branch);
36
- } else {
37
- cloneRepo(repoPath, wsPath, branch);
38
- }
39
-
40
- // Record in database
41
- db.prepare(`
42
- INSERT INTO workspaces (id, task_id, type, path, branch, status)
43
- VALUES (?, ?, ?, ?, ?, 'active')
44
- `).run(wsId, taskId, type, wsPath, branch);
45
-
46
- return { id: wsId, path: wsPath, branch, type };
47
- }
48
-
49
- /**
50
- * Remove a workspace.
51
- * @param {string} taskId - Task ID
52
- * @param {string} repoPath - Path to the main repository
53
- */
54
- function removeWorkspace(taskId, repoPath) {
55
- const db = getDb();
56
- const ws = db.prepare('SELECT * FROM workspaces WHERE task_id = ? AND status = ?').get(taskId, 'active');
57
- if (!ws) return;
58
-
59
- if (ws.type === 'worktree') {
60
- try {
61
- execSync(`git worktree remove "${ws.path}" --force`, {
62
- cwd: repoPath,
63
- stdio: 'pipe',
64
- });
65
- } catch (e) {
66
- // Fallback: manual cleanup
67
- if (fs.existsSync(ws.path)) {
68
- fs.rmSync(ws.path, { recursive: true, force: true });
69
- }
70
- try {
71
- execSync(`git worktree prune`, { cwd: repoPath, stdio: 'pipe' });
72
- } catch (_) { /* ignore */ }
73
- }
74
- } else {
75
- // Clone: just remove directory
76
- if (fs.existsSync(ws.path)) {
77
- fs.rmSync(ws.path, { recursive: true, force: true });
78
- }
79
- }
80
-
81
- db.prepare("UPDATE workspaces SET status = 'cleaned' WHERE task_id = ?").run(taskId);
82
- }
83
-
84
- /**
85
- * List all active workspaces.
86
- * @returns {Object[]}
87
- */
88
- function listWorkspaces() {
89
- const db = getDb();
90
- return db.prepare("SELECT * FROM workspaces WHERE status = 'active' ORDER BY created_at DESC").all();
91
- }
92
-
93
- /**
94
- * Get workspace for a task.
95
- * @param {string} taskId
96
- * @returns {Object|null}
97
- */
98
- function getWorkspace(taskId) {
99
- const db = getDb();
100
- return db.prepare("SELECT * FROM workspaces WHERE task_id = ? AND status = 'active'").get(taskId) || null;
101
- }
102
-
103
- /**
104
- * Mark workspace as merged.
105
- * @param {string} taskId
106
- */
107
- function markMerged(taskId) {
108
- const db = getDb();
109
- db.prepare("UPDATE workspaces SET status = 'merged', merged_at = datetime('now') WHERE task_id = ?").run(taskId);
110
- }
111
-
112
- // ─── Internal Helpers ────────────────────────────────────────────────────────
113
-
114
- function createWorktree(repoPath, wsPath, branch) {
115
- try {
116
- // Create new branch from current HEAD and checkout in worktree
117
- execSync(`git worktree add -b "${branch}" "${wsPath}"`, {
118
- cwd: repoPath,
119
- stdio: 'pipe',
120
- });
121
- } catch (e) {
122
- // Branch might already exist — try without -b
123
- try {
124
- execSync(`git worktree add "${wsPath}" "${branch}"`, {
125
- cwd: repoPath,
126
- stdio: 'pipe',
127
- });
128
- } catch (e2) {
129
- throw new Error(`Failed to create worktree: ${e2.message}`);
130
- }
131
- }
132
- }
133
-
134
- function cloneRepo(repoPath, wsPath, branch) {
135
- const remote = getRemoteUrl(repoPath);
136
- if (remote) {
137
- execSync(`git clone "${remote}" "${wsPath}"`, { stdio: 'pipe' });
138
- execSync(`git checkout -b "${branch}"`, { cwd: wsPath, stdio: 'pipe' });
139
- } else {
140
- // Local-only repo: just copy
141
- execSync(`git clone "${repoPath}" "${wsPath}"`, { stdio: 'pipe' });
142
- execSync(`git checkout -b "${branch}"`, { cwd: wsPath, stdio: 'pipe' });
143
- }
144
- }
145
-
146
- function getRemoteUrl(repoPath) {
147
- try {
148
- return execSync('git remote get-url origin', {
149
- cwd: repoPath,
150
- encoding: 'utf8',
151
- stdio: ['pipe', 'pipe', 'pipe'],
152
- }).trim();
153
- } catch (_) {
154
- return null;
155
- }
156
- }
157
-
158
- function sanitizeId(id) {
159
- return id.replace(/[^A-Za-z0-9._-]/g, '_');
160
- }
161
-
162
- module.exports = {
163
- createWorkspace,
164
- removeWorkspace,
165
- listWorkspaces,
166
- getWorkspace,
167
- markMerged,
168
- };
@@ -1,7 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "paths": {
4
- "@/*": ["./*"]
5
- }
6
- }
7
- }