memorix 1.2.2 → 1.2.3

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 (139) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/TEAM.md +86 -86
  3. package/dist/cli/index.js +34 -18
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/index.js +17 -8
  6. package/dist/index.js.map +1 -1
  7. package/dist/maintenance-runner.js.map +1 -1
  8. package/dist/memcode-runtime/CHANGELOG.md +7 -0
  9. package/dist/sdk.js +17 -8
  10. package/dist/sdk.js.map +1 -1
  11. package/docs/DESIGN_DECISIONS.md +357 -357
  12. package/docs/dev-log/progress.txt +18 -8
  13. package/package.json +1 -1
  14. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  15. package/src/audit/index.ts +156 -156
  16. package/src/cli/commands/audit-list.ts +89 -89
  17. package/src/cli/commands/background.ts +659 -659
  18. package/src/cli/commands/formation.ts +48 -48
  19. package/src/cli/commands/git-hook-install.ts +111 -111
  20. package/src/cli/commands/handoff.ts +54 -54
  21. package/src/cli/commands/hooks-status.ts +63 -63
  22. package/src/cli/commands/ingest-commit.ts +153 -153
  23. package/src/cli/commands/ingest-image.ts +66 -66
  24. package/src/cli/commands/ingest-log.ts +180 -180
  25. package/src/cli/commands/ingest.ts +44 -44
  26. package/src/cli/commands/integrate-shared.ts +15 -15
  27. package/src/cli/commands/lock.ts +82 -82
  28. package/src/cli/commands/message.ts +104 -104
  29. package/src/cli/commands/poll.ts +58 -58
  30. package/src/cli/commands/purge-all-memory.ts +85 -85
  31. package/src/cli/commands/purge-project-memory.ts +83 -83
  32. package/src/cli/commands/reasoning.ts +118 -118
  33. package/src/cli/commands/serve-shared.ts +118 -118
  34. package/src/cli/commands/session.ts +15 -7
  35. package/src/cli/commands/skills.ts +114 -114
  36. package/src/cli/commands/task.ts +167 -167
  37. package/src/cli/commands/transfer.ts +47 -47
  38. package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
  39. package/src/cli/tui/ChatView.tsx +234 -234
  40. package/src/cli/tui/CommandBar.tsx +312 -312
  41. package/src/cli/tui/ContextRail.tsx +118 -118
  42. package/src/cli/tui/HeaderBar.tsx +72 -72
  43. package/src/cli/tui/LogoBanner.tsx +51 -51
  44. package/src/cli/tui/Sidebar.tsx +179 -179
  45. package/src/cli/tui/index.ts +41 -41
  46. package/src/cli/tui/markdown-render.tsx +371 -371
  47. package/src/cli/tui/session-service.ts +3 -2
  48. package/src/cli/tui/use-mouse.ts +157 -157
  49. package/src/cli/tui/useNavigation.ts +56 -56
  50. package/src/cli/update-checker.ts +211 -211
  51. package/src/cli/version.ts +7 -7
  52. package/src/cli/workbench.ts +1 -1
  53. package/src/compact/token-budget.ts +74 -74
  54. package/src/dashboard/project-classification.ts +64 -64
  55. package/src/embedding/fastembed-provider.ts +142 -142
  56. package/src/embedding/transformers-provider.ts +111 -111
  57. package/src/git/extractor.ts +209 -209
  58. package/src/git/hooks-path.ts +85 -85
  59. package/src/hooks/pattern-detector.ts +173 -173
  60. package/src/hooks/significance-filter.ts +250 -250
  61. package/src/llm/memory-manager.ts +328 -328
  62. package/src/llm/provider.ts +885 -885
  63. package/src/llm/quality.ts +248 -248
  64. package/src/memory/attribution-guard.ts +249 -249
  65. package/src/memory/disclosure-policy.ts +135 -135
  66. package/src/memory/entity-extractor.ts +197 -197
  67. package/src/memory/formation/evaluate.ts +217 -217
  68. package/src/memory/formation/extract.ts +361 -361
  69. package/src/memory/formation/index.ts +417 -417
  70. package/src/memory/formation/resolve.ts +344 -344
  71. package/src/memory/formation/types.ts +315 -315
  72. package/src/memory/freshness.ts +122 -122
  73. package/src/memory/graph.ts +197 -197
  74. package/src/memory/refs.ts +94 -94
  75. package/src/memory/secret-filter.ts +79 -79
  76. package/src/memory/session.ts +24 -9
  77. package/src/multimodal/image-loader.ts +143 -143
  78. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  79. package/src/orchestrate/adapters/claude.ts +111 -111
  80. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  81. package/src/orchestrate/adapters/codex.ts +41 -41
  82. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  83. package/src/orchestrate/adapters/gemini.ts +42 -42
  84. package/src/orchestrate/adapters/index.ts +73 -73
  85. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  86. package/src/orchestrate/adapters/opencode.ts +47 -47
  87. package/src/orchestrate/adapters/spawn-helper.ts +286 -286
  88. package/src/orchestrate/adapters/types.ts +77 -77
  89. package/src/orchestrate/capability-router.ts +284 -284
  90. package/src/orchestrate/context-compact.ts +188 -188
  91. package/src/orchestrate/cost-tracker.ts +219 -219
  92. package/src/orchestrate/error-recovery.ts +191 -191
  93. package/src/orchestrate/evidence.ts +140 -140
  94. package/src/orchestrate/ledger.ts +110 -110
  95. package/src/orchestrate/memorix-bridge.ts +343 -343
  96. package/src/orchestrate/output-budget.ts +80 -80
  97. package/src/orchestrate/permission.ts +152 -152
  98. package/src/orchestrate/pipeline-trace.ts +131 -131
  99. package/src/orchestrate/prompt-builder.ts +155 -155
  100. package/src/orchestrate/ring-buffer.ts +37 -37
  101. package/src/orchestrate/task-graph.ts +389 -389
  102. package/src/orchestrate/worktree.ts +232 -232
  103. package/src/project/aliases.ts +374 -374
  104. package/src/project/detector.ts +268 -268
  105. package/src/rules/adapters/claude-code.ts +99 -99
  106. package/src/rules/adapters/codex.ts +97 -97
  107. package/src/rules/adapters/copilot.ts +124 -124
  108. package/src/rules/adapters/cursor.ts +114 -114
  109. package/src/rules/adapters/kiro.ts +126 -126
  110. package/src/rules/adapters/trae.ts +56 -56
  111. package/src/rules/adapters/windsurf.ts +83 -83
  112. package/src/rules/syncer.ts +235 -235
  113. package/src/sdk.ts +299 -299
  114. package/src/search/intent-detector.ts +289 -289
  115. package/src/search/query-expansion.ts +52 -52
  116. package/src/server/formation-timeout.ts +27 -27
  117. package/src/server.ts +7 -2
  118. package/src/skills/mini-skills.ts +386 -386
  119. package/src/store/chat-store.ts +119 -119
  120. package/src/store/graph-store.ts +249 -249
  121. package/src/store/mini-skill-store.ts +349 -349
  122. package/src/store/persistence-json.ts +212 -212
  123. package/src/store/persistence.ts +291 -291
  124. package/src/store/project-affinity.ts +195 -195
  125. package/src/team/event-bus.ts +76 -76
  126. package/src/team/file-locks.ts +173 -173
  127. package/src/team/handoff.ts +161 -161
  128. package/src/team/messages.ts +203 -203
  129. package/src/team/poll.ts +132 -132
  130. package/src/team/tasks.ts +211 -211
  131. package/src/workspace/mcp-adapters/codex.ts +191 -191
  132. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  133. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  134. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  135. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  136. package/src/workspace/mcp-adapters/trae.ts +134 -134
  137. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  138. package/src/workspace/sanitizer.ts +60 -60
  139. package/src/workspace/workflow-sync.ts +131 -131
@@ -32,7 +32,7 @@ export default defineCommand({
32
32
  const asJson = !!args.json;
33
33
 
34
34
  try {
35
- const { project, dataDir, teamStore } = await getCliProjectContext({
35
+ const { project, dataDir, teamStore, reader } = await getCliProjectContext({
36
36
  projectRoot: args.projectRoot as string | undefined,
37
37
  });
38
38
 
@@ -46,11 +46,6 @@ export default defineCommand({
46
46
  emitError('use requires --agent or --agentType so Memorix can activate a coordination identity.', asJson);
47
47
  return;
48
48
  }
49
- const result = await startSession(dataDir, project.id, {
50
- sessionId: args.sessionId as string | undefined,
51
- agent: args.agent as string | undefined,
52
- });
53
-
54
49
  const shouldJoinTeam = !!args.joinTeam;
55
50
  let agentRecord: ReturnType<typeof teamStore.registerAgent> | null = null;
56
51
  let teamJoinNotice: string | null = null;
@@ -72,6 +67,19 @@ export default defineCommand({
72
67
  teamJoinNotice = 'Coordination join skipped: provide --agent or --agentType to create a coordination identity.';
73
68
  }
74
69
 
70
+ const contextReader = agentRecord
71
+ ? {
72
+ projectId: project.id,
73
+ agentId: agentRecord.agent_id,
74
+ isTeamMember: agentRecord.status === 'active',
75
+ }
76
+ : reader;
77
+ const result = await startSession(dataDir, project.id, {
78
+ sessionId: args.sessionId as string | undefined,
79
+ agent: args.agent as string | undefined,
80
+ reader: contextReader,
81
+ });
82
+
75
83
  let identityActivated = false;
76
84
  if (args.use && agentRecord) {
77
85
  await saveCliIdentity(dataDir, {
@@ -178,7 +186,7 @@ export default defineCommand({
178
186
  case 'context': {
179
187
  const limit = parsePositiveInt(args.limit as string | undefined, 3);
180
188
  const [context, sessions] = await Promise.all([
181
- getSessionContext(dataDir, project.id, limit),
189
+ getSessionContext(dataDir, project.id, limit, reader),
182
190
  listSessions(dataDir, project.id),
183
191
  ]);
184
192
  const active = sessions.filter((session) => session.status === 'active').length;
@@ -1,128 +1,128 @@
1
- import { defineCommand } from 'citty';
1
+ import { defineCommand } from 'citty';
2
2
  import type { AgentTarget } from '../../types.js';
3
3
  import { getObservationStore } from '../../store/obs-store.js';
4
4
  import { filterReadableObservations, resolveObservationVisibility } from '../../memory/visibility.js';
5
- import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
6
-
7
- export default defineCommand({
8
- meta: {
9
- name: 'skills',
10
- description: 'Discover, generate, and inspect project skills from the CLI',
11
- },
12
- args: {
13
- name: { type: 'string', description: 'Skill name for "show"' },
14
- target: { type: 'string', description: 'Target agent for generated skills' },
15
- write: { type: 'boolean', description: 'Write generated skills to disk' },
16
- json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
17
- },
18
- run: async ({ args }) => {
19
- const action = (args._ as string[])?.[0] || '';
20
- const asJson = !!args.json;
21
-
22
- try {
5
+ import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
6
+
7
+ export default defineCommand({
8
+ meta: {
9
+ name: 'skills',
10
+ description: 'Discover, generate, and inspect project skills from the CLI',
11
+ },
12
+ args: {
13
+ name: { type: 'string', description: 'Skill name for "show"' },
14
+ target: { type: 'string', description: 'Target agent for generated skills' },
15
+ write: { type: 'boolean', description: 'Write generated skills to disk' },
16
+ json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
17
+ },
18
+ run: async ({ args }) => {
19
+ const action = (args._ as string[])?.[0] || '';
20
+ const asJson = !!args.json;
21
+
22
+ try {
23
23
  const { project, reader } = await getCliProjectContext();
24
- const { SkillsEngine } = await import('../../skills/engine.js');
25
- const engine = new SkillsEngine(project.rootPath);
26
-
27
- switch (action) {
28
- case 'list': {
29
- const skills = engine.listSkills();
30
- emitResult(
31
- { project, skills },
32
- skills.length === 0
33
- ? 'No skills found in project or global agent directories.'
34
- : skills.map((skill) => `- ${skill.name} (${skill.sourceAgent})`).join('\n'),
35
- asJson,
36
- );
37
- return;
38
- }
39
-
40
- case 'generate': {
24
+ const { SkillsEngine } = await import('../../skills/engine.js');
25
+ const engine = new SkillsEngine(project.rootPath);
26
+
27
+ switch (action) {
28
+ case 'list': {
29
+ const skills = engine.listSkills();
30
+ emitResult(
31
+ { project, skills },
32
+ skills.length === 0
33
+ ? 'No skills found in project or global agent directories.'
34
+ : skills.map((skill) => `- ${skill.name} (${skill.sourceAgent})`).join('\n'),
35
+ asJson,
36
+ );
37
+ return;
38
+ }
39
+
40
+ case 'generate': {
41
41
  const observations = filterReadableObservations(
42
42
  await getObservationStore().loadAll(),
43
43
  reader,
44
44
  ).filter((observation) => resolveObservationVisibility(observation) === 'project')
45
45
  .map((obs) => ({
46
- id: obs.id,
47
- entityName: obs.entityName,
48
- type: obs.type,
49
- title: obs.title,
50
- narrative: obs.narrative,
51
- facts: obs.facts,
52
- concepts: obs.concepts,
53
- filesModified: obs.filesModified,
54
- createdAt: obs.createdAt,
55
- status: obs.status,
56
- source: obs.source,
57
- }));
58
- const skills = engine.generateFromObservations(observations);
59
- const written: string[] = [];
60
- if (args.write && args.target) {
61
- for (const skill of skills) {
62
- const writtenPath = engine.writeSkill(skill, args.target as AgentTarget);
63
- if (writtenPath) written.push(writtenPath);
64
- }
65
- }
66
- emitResult(
67
- { project, skills, written },
68
- skills.length === 0
69
- ? 'No skill-worthy patterns found yet.'
70
- : skills.map((skill) => `- ${skill.name}: ${skill.description}`).join('\n'),
71
- asJson,
72
- );
73
- return;
74
- }
75
-
76
- case 'show': {
77
- const name = (args.name as string | undefined)?.trim();
78
- if (!name) {
79
- emitError('name is required for "memorix skills show"', asJson);
80
- return;
81
- }
82
- const direct = engine.injectSkill(name);
83
- if (direct) {
84
- emitResult({ project, skill: direct }, direct.content, asJson);
85
- return;
86
- }
87
-
46
+ id: obs.id,
47
+ entityName: obs.entityName,
48
+ type: obs.type,
49
+ title: obs.title,
50
+ narrative: obs.narrative,
51
+ facts: obs.facts,
52
+ concepts: obs.concepts,
53
+ filesModified: obs.filesModified,
54
+ createdAt: obs.createdAt,
55
+ status: obs.status,
56
+ source: obs.source,
57
+ }));
58
+ const skills = engine.generateFromObservations(observations);
59
+ const written: string[] = [];
60
+ if (args.write && args.target) {
61
+ for (const skill of skills) {
62
+ const writtenPath = engine.writeSkill(skill, args.target as AgentTarget);
63
+ if (writtenPath) written.push(writtenPath);
64
+ }
65
+ }
66
+ emitResult(
67
+ { project, skills, written },
68
+ skills.length === 0
69
+ ? 'No skill-worthy patterns found yet.'
70
+ : skills.map((skill) => `- ${skill.name}: ${skill.description}`).join('\n'),
71
+ asJson,
72
+ );
73
+ return;
74
+ }
75
+
76
+ case 'show': {
77
+ const name = (args.name as string | undefined)?.trim();
78
+ if (!name) {
79
+ emitError('name is required for "memorix skills show"', asJson);
80
+ return;
81
+ }
82
+ const direct = engine.injectSkill(name);
83
+ if (direct) {
84
+ emitResult({ project, skill: direct }, direct.content, asJson);
85
+ return;
86
+ }
87
+
88
88
  const observations = filterReadableObservations(
89
89
  await getObservationStore().loadAll(),
90
90
  reader,
91
91
  ).filter((observation) => resolveObservationVisibility(observation) === 'project')
92
92
  .map((obs) => ({
93
- id: obs.id,
94
- entityName: obs.entityName,
95
- type: obs.type,
96
- title: obs.title,
97
- narrative: obs.narrative,
98
- facts: obs.facts,
99
- concepts: obs.concepts,
100
- filesModified: obs.filesModified,
101
- createdAt: obs.createdAt,
102
- status: obs.status,
103
- source: obs.source,
104
- }));
105
- const generated = engine.generateFromObservations(observations);
106
- const skill = generated.find((entry) => entry.name.toLowerCase() === name.toLowerCase());
107
- if (!skill) {
108
- emitError(`Skill "${name}" not found`, asJson);
109
- return;
110
- }
111
- emitResult({ project, skill }, skill.content, asJson);
112
- return;
113
- }
114
-
115
- default:
116
- console.log('Memorix Skills Commands');
117
- console.log('');
118
- console.log('Usage:');
119
- console.log(' memorix skills list');
120
- console.log(' memorix skills generate [--write --target codex]');
121
- console.log(' memorix skills show --name <skill>');
122
- }
123
- } catch (error) {
124
- emitError(error instanceof Error ? error.message : String(error), asJson);
125
- }
126
- },
127
- });
128
-
93
+ id: obs.id,
94
+ entityName: obs.entityName,
95
+ type: obs.type,
96
+ title: obs.title,
97
+ narrative: obs.narrative,
98
+ facts: obs.facts,
99
+ concepts: obs.concepts,
100
+ filesModified: obs.filesModified,
101
+ createdAt: obs.createdAt,
102
+ status: obs.status,
103
+ source: obs.source,
104
+ }));
105
+ const generated = engine.generateFromObservations(observations);
106
+ const skill = generated.find((entry) => entry.name.toLowerCase() === name.toLowerCase());
107
+ if (!skill) {
108
+ emitError(`Skill "${name}" not found`, asJson);
109
+ return;
110
+ }
111
+ emitResult({ project, skill }, skill.content, asJson);
112
+ return;
113
+ }
114
+
115
+ default:
116
+ console.log('Memorix Skills Commands');
117
+ console.log('');
118
+ console.log('Usage:');
119
+ console.log(' memorix skills list');
120
+ console.log(' memorix skills generate [--write --target codex]');
121
+ console.log(' memorix skills show --name <skill>');
122
+ }
123
+ } catch (error) {
124
+ emitError(error instanceof Error ? error.message : String(error), asJson);
125
+ }
126
+ },
127
+ });
128
+
@@ -1,4 +1,4 @@
1
- import { defineCommand } from 'citty';
1
+ import { defineCommand } from 'citty';
2
2
  import {
3
3
  emitError,
4
4
  emitResult,
@@ -8,194 +8,194 @@ import {
8
8
  resolveCliActorId,
9
9
  shortId,
10
10
  } from './operator-shared.js';
11
-
12
- export default defineCommand({
13
- meta: {
14
- name: 'task',
15
- description: 'Create, claim, complete, and inspect team tasks',
16
- },
17
- args: {
18
- description: { type: 'string', description: 'Task description (for create)' },
19
- deps: { type: 'string', description: 'Comma-separated dependency task IDs' },
20
- taskId: { type: 'string', description: 'Task ID for claim, complete, fail, or release' },
21
- agentId: { type: 'string', description: 'Agent ID for claim, complete, fail, release, or agent-aware list' },
22
- result: { type: 'string', description: 'Completion or failure summary' },
23
- status: { type: 'string', description: 'Filter by status for list' },
24
- available: { type: 'boolean', description: 'Show only claimable tasks' },
25
- metadata: { type: 'string', description: 'JSON metadata object for create' },
26
- requiredRole: { type: 'string', description: 'Required role for this task' },
27
- preferredRole: { type: 'string', description: 'Preferred role for this task' },
28
- json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
29
- },
30
- run: async ({ args }) => {
31
- const action = (args._ as string[])?.[0] || '';
32
- const asJson = !!args.json;
33
-
34
- try {
11
+
12
+ export default defineCommand({
13
+ meta: {
14
+ name: 'task',
15
+ description: 'Create, claim, complete, and inspect team tasks',
16
+ },
17
+ args: {
18
+ description: { type: 'string', description: 'Task description (for create)' },
19
+ deps: { type: 'string', description: 'Comma-separated dependency task IDs' },
20
+ taskId: { type: 'string', description: 'Task ID for claim, complete, fail, or release' },
21
+ agentId: { type: 'string', description: 'Agent ID for claim, complete, fail, release, or agent-aware list' },
22
+ result: { type: 'string', description: 'Completion or failure summary' },
23
+ status: { type: 'string', description: 'Filter by status for list' },
24
+ available: { type: 'boolean', description: 'Show only claimable tasks' },
25
+ metadata: { type: 'string', description: 'JSON metadata object for create' },
26
+ requiredRole: { type: 'string', description: 'Required role for this task' },
27
+ preferredRole: { type: 'string', description: 'Preferred role for this task' },
28
+ json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
29
+ },
30
+ run: async ({ args }) => {
31
+ const action = (args._ as string[])?.[0] || '';
32
+ const asJson = !!args.json;
33
+
34
+ try {
35
35
  const { project, teamStore, identity } = await getCliProjectContext();
36
36
  const agentId = resolveCliActorId(args.agentId, identity);
37
-
38
- switch (action) {
39
- case 'create': {
40
- if (!args.description) {
41
- emitError('description is required for "memorix task create"', asJson);
42
- return;
43
- }
44
-
45
- const metadata = parseOptionalJsonObject(args.metadata as string | undefined, 'metadata');
46
- if (metadata) {
47
- const { checkPipelineGuards } = await import('../../orchestrate/planner.js');
48
- const guard = checkPipelineGuards({
49
- existingTasks: teamStore.listTasks(project.id),
50
- newTaskMeta: metadata,
51
- });
52
- if (!guard.allowed) {
53
- emitError(guard.reason, asJson);
54
- return;
55
- }
56
- }
57
-
58
- const task = teamStore.createTask({
59
- projectId: project.id,
60
- description: args.description as string,
61
- deps: parseCsvList(args.deps as string | undefined),
62
- metadata,
37
+
38
+ switch (action) {
39
+ case 'create': {
40
+ if (!args.description) {
41
+ emitError('description is required for "memorix task create"', asJson);
42
+ return;
43
+ }
44
+
45
+ const metadata = parseOptionalJsonObject(args.metadata as string | undefined, 'metadata');
46
+ if (metadata) {
47
+ const { checkPipelineGuards } = await import('../../orchestrate/planner.js');
48
+ const guard = checkPipelineGuards({
49
+ existingTasks: teamStore.listTasks(project.id),
50
+ newTaskMeta: metadata,
51
+ });
52
+ if (!guard.allowed) {
53
+ emitError(guard.reason, asJson);
54
+ return;
55
+ }
56
+ }
57
+
58
+ const task = teamStore.createTask({
59
+ projectId: project.id,
60
+ description: args.description as string,
61
+ deps: parseCsvList(args.deps as string | undefined),
62
+ metadata,
63
63
  createdBy: agentId,
64
- requiredRole: args.requiredRole as string | undefined,
65
- preferredRole: args.preferredRole as string | undefined,
66
- });
67
- const deps = teamStore.getTaskDeps(task.task_id);
68
- emitResult(
69
- { project, task, deps },
70
- `Task created: ${shortId(task.task_id)} "${task.description}"${deps.length > 0 ? ` (${deps.length} dep)` : ''}`,
71
- asJson,
72
- );
73
- return;
74
- }
75
-
76
- case 'claim': {
64
+ requiredRole: args.requiredRole as string | undefined,
65
+ preferredRole: args.preferredRole as string | undefined,
66
+ });
67
+ const deps = teamStore.getTaskDeps(task.task_id);
68
+ emitResult(
69
+ { project, task, deps },
70
+ `Task created: ${shortId(task.task_id)} "${task.description}"${deps.length > 0 ? ` (${deps.length} dep)` : ''}`,
71
+ asJson,
72
+ );
73
+ return;
74
+ }
75
+
76
+ case 'claim': {
77
77
  if (!args.taskId || !agentId) {
78
78
  emitError('taskId and an active CLI identity or agentId are required for "memorix task claim"', asJson);
79
79
  return;
80
80
  }
81
81
  const result = teamStore.claimTask(args.taskId as string, agentId);
82
- if (!result.success) {
83
- emitError(result.reason ?? 'Unable to claim task', asJson);
84
- return;
85
- }
86
- emitResult(
87
- { project, result },
88
- `Task claimed: ${result.task?.description ?? args.taskId}${result.hint ? `\nHint: ${result.hint}` : ''}`,
89
- asJson,
90
- );
91
- return;
92
- }
93
-
94
- case 'complete': {
82
+ if (!result.success) {
83
+ emitError(result.reason ?? 'Unable to claim task', asJson);
84
+ return;
85
+ }
86
+ emitResult(
87
+ { project, result },
88
+ `Task claimed: ${result.task?.description ?? args.taskId}${result.hint ? `\nHint: ${result.hint}` : ''}`,
89
+ asJson,
90
+ );
91
+ return;
92
+ }
93
+
94
+ case 'complete': {
95
95
  if (!args.taskId || !agentId || !args.result) {
96
96
  emitError('taskId, result, and an active CLI identity or agentId are required for "memorix task complete"', asJson);
97
97
  return;
98
98
  }
99
99
  const result = teamStore.completeTask(args.taskId as string, agentId, args.result as string);
100
- if (!result.success) {
101
- emitError(result.reason ?? 'Unable to complete task', asJson);
102
- return;
103
- }
104
- emitResult(
105
- { project, task: teamStore.getTask(args.taskId as string), result: args.result },
106
- `Task completed: ${shortId(args.taskId as string)}`,
107
- asJson,
108
- );
109
- return;
110
- }
111
-
112
- case 'fail': {
100
+ if (!result.success) {
101
+ emitError(result.reason ?? 'Unable to complete task', asJson);
102
+ return;
103
+ }
104
+ emitResult(
105
+ { project, task: teamStore.getTask(args.taskId as string), result: args.result },
106
+ `Task completed: ${shortId(args.taskId as string)}`,
107
+ asJson,
108
+ );
109
+ return;
110
+ }
111
+
112
+ case 'fail': {
113
113
  if (!args.taskId || !agentId || !args.result) {
114
114
  emitError('taskId, result, and an active CLI identity or agentId are required for "memorix task fail"', asJson);
115
115
  return;
116
116
  }
117
117
  const result = teamStore.failTask(args.taskId as string, agentId, args.result as string);
118
- if (!result.success) {
119
- emitError(result.reason ?? 'Unable to fail task', asJson);
120
- return;
121
- }
122
- emitResult(
123
- { project, task: teamStore.getTask(args.taskId as string), result: args.result },
124
- `Task failed: ${shortId(args.taskId as string)}`,
125
- asJson,
126
- );
127
- return;
128
- }
129
-
130
- case 'release': {
118
+ if (!result.success) {
119
+ emitError(result.reason ?? 'Unable to fail task', asJson);
120
+ return;
121
+ }
122
+ emitResult(
123
+ { project, task: teamStore.getTask(args.taskId as string), result: args.result },
124
+ `Task failed: ${shortId(args.taskId as string)}`,
125
+ asJson,
126
+ );
127
+ return;
128
+ }
129
+
130
+ case 'release': {
131
131
  if (!args.taskId || !agentId) {
132
132
  emitError('taskId and an active CLI identity or agentId are required for "memorix task release"', asJson);
133
133
  return;
134
134
  }
135
135
  const result = teamStore.releaseTask(args.taskId as string, agentId);
136
- if (!result.success) {
137
- emitError(result.reason ?? 'Unable to release task', asJson);
138
- return;
139
- }
140
- emitResult(
141
- { project, task: teamStore.getTask(args.taskId as string) },
142
- `Task released: ${shortId(args.taskId as string)}`,
143
- asJson,
144
- );
145
- return;
146
- }
147
-
148
- case 'list': {
149
- const tasks =
136
+ if (!result.success) {
137
+ emitError(result.reason ?? 'Unable to release task', asJson);
138
+ return;
139
+ }
140
+ emitResult(
141
+ { project, task: teamStore.getTask(args.taskId as string) },
142
+ `Task released: ${shortId(args.taskId as string)}`,
143
+ asJson,
144
+ );
145
+ return;
146
+ }
147
+
148
+ case 'list': {
149
+ const tasks =
150
150
  args.available && agentId
151
151
  ? teamStore.listTasksForAgent(project.id, agentId)
152
- : teamStore.listTasks(
153
- project.id,
154
- args.available
155
- ? { available: true }
156
- : args.status
157
- ? { status: args.status as string }
158
- : undefined,
159
- );
160
- const payload = tasks.map((task) => ({
161
- ...task,
162
- deps: teamStore.getTaskDeps(task.task_id),
163
- }));
164
- emitResult(
165
- { project, tasks: payload },
166
- tasks.length === 0
167
- ? 'No tasks found.'
168
- : payload
169
- .map((task) => {
170
- const assignee = task.assignee_agent_id
171
- ? teamStore.getAgent(task.assignee_agent_id)?.name ?? shortId(task.assignee_agent_id)
172
- : 'unassigned';
173
- const roleTag = task.required_role
174
- ? `[${task.required_role}${task.preferred_role && task.preferred_role !== task.required_role ? ` -> ${task.preferred_role}` : ''}]`
175
- : task.preferred_role
176
- ? `[~${task.preferred_role}]`
177
- : '';
178
- return `- ${task.status}: ${shortId(task.task_id)} "${task.description}" - ${assignee} ${roleTag}`.trim();
179
- })
180
- .join('\n'),
181
- asJson,
182
- );
183
- return;
184
- }
185
-
186
- default:
187
- console.log('Memorix Task Commands');
188
- console.log('');
189
- console.log('Usage:');
190
- console.log(' memorix task create --description "..." [--agentId <id>] [--deps id1,id2]');
191
- console.log(' memorix task claim --taskId <id> --agentId <id>');
192
- console.log(' memorix task complete --taskId <id> --agentId <id> --result "..."');
193
- console.log(' memorix task fail --taskId <id> --agentId <id> --result "..."');
194
- console.log(' memorix task release --taskId <id> --agentId <id>');
195
- console.log(' memorix task list [--status pending|in_progress|completed|failed] [--available --agentId <id>]');
196
- }
197
- } catch (error) {
198
- emitError(error instanceof Error ? error.message : String(error), asJson);
199
- }
200
- },
201
- });
152
+ : teamStore.listTasks(
153
+ project.id,
154
+ args.available
155
+ ? { available: true }
156
+ : args.status
157
+ ? { status: args.status as string }
158
+ : undefined,
159
+ );
160
+ const payload = tasks.map((task) => ({
161
+ ...task,
162
+ deps: teamStore.getTaskDeps(task.task_id),
163
+ }));
164
+ emitResult(
165
+ { project, tasks: payload },
166
+ tasks.length === 0
167
+ ? 'No tasks found.'
168
+ : payload
169
+ .map((task) => {
170
+ const assignee = task.assignee_agent_id
171
+ ? teamStore.getAgent(task.assignee_agent_id)?.name ?? shortId(task.assignee_agent_id)
172
+ : 'unassigned';
173
+ const roleTag = task.required_role
174
+ ? `[${task.required_role}${task.preferred_role && task.preferred_role !== task.required_role ? ` -> ${task.preferred_role}` : ''}]`
175
+ : task.preferred_role
176
+ ? `[~${task.preferred_role}]`
177
+ : '';
178
+ return `- ${task.status}: ${shortId(task.task_id)} "${task.description}" - ${assignee} ${roleTag}`.trim();
179
+ })
180
+ .join('\n'),
181
+ asJson,
182
+ );
183
+ return;
184
+ }
185
+
186
+ default:
187
+ console.log('Memorix Task Commands');
188
+ console.log('');
189
+ console.log('Usage:');
190
+ console.log(' memorix task create --description "..." [--agentId <id>] [--deps id1,id2]');
191
+ console.log(' memorix task claim --taskId <id> --agentId <id>');
192
+ console.log(' memorix task complete --taskId <id> --agentId <id> --result "..."');
193
+ console.log(' memorix task fail --taskId <id> --agentId <id> --result "..."');
194
+ console.log(' memorix task release --taskId <id> --agentId <id>');
195
+ console.log(' memorix task list [--status pending|in_progress|completed|failed] [--available --agentId <id>]');
196
+ }
197
+ } catch (error) {
198
+ emitError(error instanceof Error ? error.message : String(error), asJson);
199
+ }
200
+ },
201
+ });