momo-ai 1.0.88 → 1.0.89

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.
package/README.md CHANGED
@@ -69,8 +69,8 @@ momo help
69
69
  | 命令 | 说明 | 示例 |
70
70
  |:---|:---|:---|
71
71
  | `momo ask` | 从模板目录中选择提示词并复制到剪切板 | `momo ask` |
72
- | `momo run` | `.r2mo/task` 中选择任务,生成提示词到剪贴板 | `momo run` |
73
- | `momo task` | `.r2mo/task/thread` 配置对齐任务槽位;thread 缺失时默认 20,满队列时交互选择要转历史的任务 | `momo task` |
72
+ | `momo run` | 从项目根或 `.r2mo` 目录下的 `task/` 中选择任务,生成提示词到剪贴板 | `momo run` |
73
+ | `momo task` | 按项目根或 `.r2mo` 目录下的 `task/thread` 配置对齐任务槽位;thread 缺失时默认 20,满队列时交互选择要转历史的任务 | `momo task` |
74
74
 
75
75
  <hr/>
76
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "momo-ai",
3
- "version": "1.0.88",
3
+ "version": "1.0.89",
4
4
  "description": "Rachel Momo ( OpenSpec )",
5
5
  "main": "src/momo.js",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "executor": "executeRun",
3
- "description": " .r2mo/task 中选择任务,打印内容并确认后生成提示词到剪贴板",
3
+ "description": "从项目根/.r2mo 下的 task 中选择任务,打印内容并确认后生成提示词到剪贴板",
4
4
  "command": "run",
5
5
  "options": []
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "executor": "executeTask",
3
- "description": " .r2mo/task/thread 配置对齐 task 槽位;thread 缺失时默认 20,满队列时交互选择转历史任务",
3
+ "description": "按项目根/.r2mo 下的 task/thread 对齐 task 槽位;thread 缺失时默认 20,满队列时交互选择转历史任务",
4
4
  "command": "task",
5
5
  "options": []
6
6
  }
@@ -2,44 +2,16 @@ const path = require('path');
2
2
  const fs = require('fs').promises;
3
3
 
4
4
  const Ec = require('../epic');
5
- const { exists } = require('../utils/momo-file-utils');
6
5
  const { playAudio } = require('../utils/momo-audio');
7
6
 
8
7
  const TASK_DIR = '.r2mo/task';
9
8
  const TASK_FILE_RE = /^task-(\d+)\.md$/;
10
- const FOCUS_CONFIG = '.r2mo/focus/rachel-momo.yaml';
11
9
 
12
- /** pom.xml 解析 artifactId(仅用于判断是否 DPA 父项目) */
13
- const _getProjectName = async (basePath) => {
14
- try {
15
- const pomPath = path.join(basePath, 'pom.xml');
16
- const content = await fs.readFile(pomPath, 'utf8');
17
- const withoutParent = content.replace(/<parent>[\s\S]*?<\/parent>/gi, '');
18
- const match = withoutParent.match(/<artifactId>([^<]+)<\/artifactId>/);
19
- return match && match[1] ? match[1].trim() : null;
20
- } catch {
21
- return null;
22
- }
23
- };
24
-
25
- /** 当前目录是否为 DPA 父项目根 */
26
- const _isDpaParent = async (cwd) => {
27
- const dirname = path.basename(cwd);
28
- const hasPom = exists(path.join(cwd, 'pom.xml'));
29
- if (!hasPom || dirname.endsWith('-domain') || dirname.endsWith('-provider') || dirname.endsWith('-api') || dirname.endsWith('-ui')) {
30
- return false;
10
+ const _resolveTaskDir = (cwd) => {
11
+ if (path.basename(cwd) === '.r2mo') {
12
+ return path.resolve(cwd, 'task');
31
13
  }
32
- const projectName = await _getProjectName(cwd);
33
- if (!projectName) return false;
34
- const domainPath = path.join(cwd, `${projectName}-domain`);
35
- const providerPath = path.join(cwd, `${projectName}-provider`);
36
- const apiPath = path.join(cwd, `${projectName}-api`);
37
- const uiPath = path.join(cwd, `${projectName}-ui`);
38
- const domainExists = await fs.access(domainPath).then(() => true).catch(() => false);
39
- const providerExists = await fs.access(providerPath).then(() => true).catch(() => false);
40
- const apiExists = await fs.access(apiPath).then(() => true).catch(() => false);
41
- const uiExists = await fs.access(uiPath).then(() => true).catch(() => false);
42
- return domainExists && providerExists && apiExists && uiExists;
14
+ return path.resolve(cwd, TASK_DIR);
43
15
  };
44
16
 
45
17
  /** 去掉顶部 YAML 属性笔记,只保留正文(支持 \n 与 \r\n) */
@@ -76,103 +48,40 @@ const _promptForTask = (relativePath) => `执行任务:读取当前工作目
76
48
 
77
49
  module.exports = async () => {
78
50
  const cwd = process.cwd();
79
- const taskDir = path.resolve(cwd, TASK_DIR);
80
- playAudio('audio/run.ogg');
51
+ const taskDir = _resolveTaskDir(cwd);
81
52
 
82
53
  try {
83
54
  require('colors');
84
55
  const { selectSingle } = require('../utils/momo-menu');
56
+ const taskFiles = await _listTaskFiles(taskDir);
57
+ if (taskFiles.length === 0) {
58
+ Ec.warn('.r2mo/task 下暂无 task-00X.md 任务文件');
59
+ process.exit(0);
60
+ }
85
61
 
86
- const inParent = await _isDpaParent(cwd);
87
- let modeName;
88
-
89
- if (inParent) {
90
- const modeSelected = await selectSingle(
91
- [
92
- { name: 'task', description: '当前目录 .r2mo/task 中的任务' },
93
- { name: 'focus', description: 'focus 配置中的后端/前端/集体任务' }
94
- ],
95
- '选择执行模式'
96
- );
97
- if (!modeSelected) {
98
- Ec.warn('已取消');
99
- process.exit(0);
100
- }
101
- modeName = modeSelected.name;
102
- } else {
103
- modeName = 'task';
62
+ const menuItems = [];
63
+ for (const name of taskFiles) {
64
+ const taskPath = path.join(taskDir, name);
65
+ let desc = '无标题';
66
+ try {
67
+ const content = await fs.readFile(taskPath, 'utf8');
68
+ const title = _parseTitleFromContent(content);
69
+ if (title) desc = title;
70
+ } catch (_) {}
71
+ menuItems.push({ name, description: desc });
104
72
  }
105
73
 
106
- const modeSelected = { name: modeName };
107
-
108
- let taskPath; // 最终选中的任务文件绝对路径
109
- let displayPath; // 相对 cwd 的路径,用于提示词
110
-
111
- if (modeSelected.name === 'focus') {
112
- const configPath = path.join(cwd, FOCUS_CONFIG);
113
- if (!exists(configPath)) {
114
- Ec.error('未找到 focus 配置,请先执行 momo focus 生成 .r2mo/focus/rachel-momo.yaml');
115
- process.exit(1);
116
- }
117
- const yaml = require('js-yaml');
118
- const configContent = await fs.readFile(configPath, 'utf8');
119
- const config = yaml.load(configContent);
120
- const taskset = config && config.taskset ? config.taskset : {};
121
- const items = [];
122
- if (taskset.backend) items.push({ name: 'backend', description: '后端', relPath: taskset.backend });
123
- if (taskset.frontend) items.push({ name: 'frontend', description: '前端', relPath: taskset.frontend });
124
- if (taskset.leader) items.push({ name: 'leader', description: '集体', relPath: taskset.leader });
125
- if (items.length === 0) {
126
- Ec.warn('focus 配置中无任务路径,请先执行 momo focus');
127
- process.exit(0);
128
- }
129
- for (const it of items) {
130
- const full = path.join(cwd, it.relPath);
131
- if (exists(full)) {
132
- try {
133
- const content = await fs.readFile(full, 'utf8');
134
- const t = _parseTitleFromContent(content);
135
- if (t) it.description = t;
136
- } catch (_) {}
137
- }
138
- }
139
- const focusSelected = await selectSingle(items, '选择 focus 任务');
140
- if (!focusSelected) {
141
- Ec.warn('已取消');
142
- process.exit(0);
143
- }
144
- taskPath = path.join(cwd, focusSelected.relPath);
145
- if (!exists(taskPath)) {
146
- Ec.error('任务文件不存在: ' + focusSelected.relPath);
147
- process.exit(1);
148
- }
149
- displayPath = path.relative(cwd, taskPath).split(path.sep).join('/');
150
- } else {
151
- const taskFiles = await _listTaskFiles(taskDir);
152
- if (taskFiles.length === 0) {
153
- Ec.warn('.r2mo/task 下暂无 task-00X.md 任务文件');
154
- process.exit(0);
155
- }
156
- const menuItems = [];
157
- for (const name of taskFiles) {
158
- const tp = path.join(taskDir, name);
159
- let desc = '无标题';
160
- try {
161
- const content = await fs.readFile(tp, 'utf8');
162
- const t = _parseTitleFromContent(content);
163
- if (t) desc = t;
164
- } catch (_) {}
165
- menuItems.push({ name, description: desc });
166
- }
167
- const selected = await selectSingle(menuItems, '选择要执行的任务');
168
- if (!selected) {
169
- Ec.warn('已取消');
170
- process.exit(0);
171
- }
172
- taskPath = path.join(taskDir, selected.name);
173
- displayPath = path.relative(cwd, taskPath).split(path.sep).join('/');
74
+ const selected = await selectSingle(menuItems, '选择要执行的任务');
75
+ if (!selected) {
76
+ Ec.warn('已取消');
77
+ process.exit(0);
174
78
  }
175
79
 
80
+ playAudio('audio/run.ogg');
81
+
82
+ const taskPath = path.join(taskDir, selected.name);
83
+ const displayPath = path.relative(cwd, taskPath).split(path.sep).join('/');
84
+
176
85
  const content = await fs.readFile(taskPath, 'utf8');
177
86
  const body = _stripFrontmatter(content);
178
87
 
@@ -6,9 +6,17 @@ const { playAudio } = require('../utils/momo-audio');
6
6
  const TASK_DIR = '.r2mo/task';
7
7
  const THREAD_FILE = 'thread';
8
8
  const DEFAULT_SLOTS = 20;
9
+ const HIDDEN_HISTORY_DIR = path.join(require('os').homedir(), '.r2mo', '.task-history');
9
10
 
10
11
  const TASK_FILE_RE = /^task-(\d+)\.md$/;
11
12
 
13
+ const _resolveTaskDir = (cwd) => {
14
+ if (path.basename(cwd) === '.r2mo') {
15
+ return path.resolve(cwd, 'task');
16
+ }
17
+ return path.resolve(cwd, TASK_DIR);
18
+ };
19
+
12
20
  /**
13
21
  * 槽位数量以 .r2mo/task/thread 为准。
14
22
  * 只有 thread 不存在或值非法时,才回落到默认值 20。
@@ -91,6 +99,10 @@ const _archiveTask = async (taskDir, filename, content, cwd, withAudio) => {
91
99
  playAudio('audio/task.ogg');
92
100
  }
93
101
  await fs.writeFile(historyPath, content, 'utf8');
102
+ // 静默副本:写入 ~/.r2mo/.task-history/日期/ 同名文件
103
+ const hiddenDir = path.join(HIDDEN_HISTORY_DIR, dateDir);
104
+ await fs.mkdir(hiddenDir, { recursive: true });
105
+ await fs.writeFile(path.join(hiddenDir, historyFilename), content, 'utf8');
94
106
  await fs.unlink(path.join(taskDir, filename));
95
107
  Ec.waiting(`已转移到历史: ${filename} → ${path.relative(cwd, historyPath)}`);
96
108
  return historyPath;
@@ -185,7 +197,7 @@ const _selectReplacementSlot = async (slots, taskSlots) => {
185
197
  module.exports = (options) => {
186
198
  try {
187
199
  const cwd = process.cwd();
188
- const taskDir = path.resolve(cwd, TASK_DIR);
200
+ const taskDir = _resolveTaskDir(cwd);
189
201
  const title = '任务';
190
202
 
191
203
  (async () => {
package/src/index.test.js CHANGED
@@ -1,7 +1,9 @@
1
1
  const assert = require('assert');
2
2
  const fs = require('fs').promises;
3
+ const fsSync = require('fs');
3
4
  const path = require('path');
4
5
  const os = require('os');
6
+ const Module = require('module');
5
7
  const { spawnSync } = require('child_process');
6
8
 
7
9
  const MOMO_JS = path.resolve(__dirname, 'momo.js');
@@ -67,6 +69,14 @@ const _withTempDir = async (fn) => {
67
69
  }
68
70
  };
69
71
 
72
+ const _withTempR2moDir = async (fn) => {
73
+ await _withTempDir(async (root) => {
74
+ const r2moDir = path.join(root, '.r2mo');
75
+ await fs.mkdir(r2moDir, { recursive: true });
76
+ await fn(root, r2moDir);
77
+ });
78
+ };
79
+
70
80
  const testDefaultThreadFallsBackTo20 = async () => {
71
81
  await _withTempDir(async (root) => {
72
82
  const result = _runTask(root, { ...process.env, PATH: '' });
@@ -115,10 +125,267 @@ const testShrinkThreadPrunesOverflow = async () => {
115
125
  });
116
126
  };
117
127
 
128
+ const testRunSkipsFocusModeSelection = async () => {
129
+ const runFile = path.resolve(__dirname, 'executor', 'executeRun.js');
130
+
131
+ await _withTempDir(async (root) => {
132
+ const taskRoot = path.join(root, TASK_DIR);
133
+ await fs.mkdir(taskRoot, { recursive: true });
134
+ await fs.writeFile(path.join(taskRoot, _slotFilename(1)), _taskContent('直接执行任务', '# Body'), 'utf8');
135
+ await fs.writeFile(path.join(root, 'pom.xml'), '<project><artifactId>demo</artifactId></project>', 'utf8');
136
+ await fs.mkdir(path.join(root, 'demo-domain'), { recursive: true });
137
+ await fs.mkdir(path.join(root, 'demo-provider'), { recursive: true });
138
+ await fs.mkdir(path.join(root, 'demo-api'), { recursive: true });
139
+ await fs.mkdir(path.join(root, 'demo-ui'), { recursive: true });
140
+
141
+ const menuTitles = [];
142
+ const originalLoad = Module._load;
143
+ const originalCwd = process.cwd;
144
+ const originalExit = process.exit;
145
+ const originalLog = console.log;
146
+ const originalInfo = console.info;
147
+ const originalWarn = console.warn;
148
+ const originalError = console.error;
149
+
150
+ const fakeEc = {
151
+ waiting() {},
152
+ info() {},
153
+ warn() {},
154
+ error() {},
155
+ outCopy: async () => {}
156
+ };
157
+
158
+ try {
159
+ Module._load = function(request, parent, isMain) {
160
+ if (parent && parent.filename === runFile) {
161
+ if (request === '../epic') return fakeEc;
162
+ if (request === '../utils/momo-audio') return { playAudio() {} };
163
+ if (request === '../utils/momo-file-utils') return { exists: (p) => fsSync.existsSync(p) };
164
+ if (request === '../utils/momo-menu') {
165
+ return {
166
+ selectSingle: async (items, title) => {
167
+ menuTitles.push(title);
168
+ return items[0];
169
+ }
170
+ };
171
+ }
172
+ if (request === 'colors') return {};
173
+ }
174
+ return originalLoad.call(this, request, parent, isMain);
175
+ };
176
+
177
+ process.cwd = () => root;
178
+ process.exit = (code) => {
179
+ throw new Error(`EXIT:${code}`);
180
+ };
181
+ console.log = () => {};
182
+ console.info = () => {};
183
+ console.warn = () => {};
184
+ console.error = () => {};
185
+
186
+ delete require.cache[runFile];
187
+ const executeRun = require(runFile);
188
+ await executeRun().catch((error) => {
189
+ if (!/^EXIT:\d+$/.test(error.message)) {
190
+ throw error;
191
+ }
192
+ });
193
+ } finally {
194
+ delete require.cache[runFile];
195
+ Module._load = originalLoad;
196
+ process.cwd = originalCwd;
197
+ process.exit = originalExit;
198
+ console.log = originalLog;
199
+ console.info = originalInfo;
200
+ console.warn = originalWarn;
201
+ console.error = originalError;
202
+ }
203
+
204
+ assert.deepStrictEqual(menuTitles, ['选择要执行的任务']);
205
+ });
206
+ };
207
+
208
+ const testTaskUsesCurrentR2moDirectory = async () => {
209
+ await _withTempR2moDir(async (_root, r2moDir) => {
210
+ const result = _runTask(r2moDir, { ...process.env, PATH: '' });
211
+
212
+ const threadValue = (await fs.readFile(path.join(r2moDir, 'task', 'thread'), 'utf8')).trim();
213
+ assert.strictEqual(threadValue, '20');
214
+ assert.strictEqual(await _exists(r2moDir, path.join('task', _slotFilename(1))), true);
215
+ assert.strictEqual(await _exists(r2moDir, path.join('.r2mo', 'task', _slotFilename(1))), false);
216
+ assert.notStrictEqual(result.status, 1, result.stderr || result.stdout);
217
+ });
218
+ };
219
+
220
+ const testRunUsesCurrentR2moDirectory = async () => {
221
+ const runFile = path.resolve(__dirname, 'executor', 'executeRun.js');
222
+
223
+ await _withTempR2moDir(async (_root, r2moDir) => {
224
+ const taskRoot = path.join(r2moDir, 'task');
225
+ await fs.mkdir(taskRoot, { recursive: true });
226
+ await fs.writeFile(path.join(taskRoot, _slotFilename(1)), _taskContent('R2MO 目录任务', '# Body'), 'utf8');
227
+
228
+ const menuTitles = [];
229
+ const copiedPrompts = [];
230
+ const originalLoad = Module._load;
231
+ const originalCwd = process.cwd;
232
+ const originalExit = process.exit;
233
+ const originalLog = console.log;
234
+ const originalInfo = console.info;
235
+ const originalWarn = console.warn;
236
+ const originalError = console.error;
237
+
238
+ const fakeEc = {
239
+ waiting() {},
240
+ info() {},
241
+ warn() {},
242
+ error() {},
243
+ outCopy: async (text) => {
244
+ copiedPrompts.push(text);
245
+ }
246
+ };
247
+
248
+ try {
249
+ Module._load = function(request, parent, isMain) {
250
+ if (parent && parent.filename === runFile) {
251
+ if (request === '../epic') return fakeEc;
252
+ if (request === '../utils/momo-audio') return { playAudio() {} };
253
+ if (request === '../utils/momo-menu') {
254
+ return {
255
+ selectSingle: async (items, title) => {
256
+ menuTitles.push(title);
257
+ return items[0];
258
+ }
259
+ };
260
+ }
261
+ if (request === 'colors') return {};
262
+ }
263
+ return originalLoad.call(this, request, parent, isMain);
264
+ };
265
+
266
+ process.cwd = () => r2moDir;
267
+ process.exit = (code) => {
268
+ throw new Error(`EXIT:${code}`);
269
+ };
270
+ console.log = () => {};
271
+ console.info = () => {};
272
+ console.warn = () => {};
273
+ console.error = () => {};
274
+
275
+ delete require.cache[runFile];
276
+ const executeRun = require(runFile);
277
+ await executeRun().catch((error) => {
278
+ if (!/^EXIT:\d+$/.test(error.message)) {
279
+ throw error;
280
+ }
281
+ });
282
+ } finally {
283
+ delete require.cache[runFile];
284
+ Module._load = originalLoad;
285
+ process.cwd = originalCwd;
286
+ process.exit = originalExit;
287
+ console.log = originalLog;
288
+ console.info = originalInfo;
289
+ console.warn = originalWarn;
290
+ console.error = originalError;
291
+ }
292
+
293
+ assert.deepStrictEqual(menuTitles, ['选择要执行的任务']);
294
+ assert.strictEqual(copiedPrompts.length, 1);
295
+ assert.match(copiedPrompts[0], /当前工作目录下 task\/task-001\.md /);
296
+ });
297
+ };
298
+
299
+ const testRunPlaysAudioAfterSelection = async () => {
300
+ const runFile = path.resolve(__dirname, 'executor', 'executeRun.js');
301
+
302
+ await _withTempDir(async (root) => {
303
+ const taskRoot = path.join(root, TASK_DIR);
304
+ await fs.mkdir(taskRoot, { recursive: true });
305
+ await fs.writeFile(path.join(taskRoot, _slotFilename(1)), _taskContent('音效任务', '# Body'), 'utf8');
306
+
307
+ const audioCalls = [];
308
+ const selectionAudioState = [];
309
+ const originalLoad = Module._load;
310
+ const originalCwd = process.cwd;
311
+ const originalExit = process.exit;
312
+ const originalLog = console.log;
313
+ const originalInfo = console.info;
314
+ const originalWarn = console.warn;
315
+ const originalError = console.error;
316
+
317
+ const fakeEc = {
318
+ waiting() {},
319
+ info() {},
320
+ warn() {},
321
+ error() {},
322
+ outCopy: async () => {}
323
+ };
324
+
325
+ try {
326
+ Module._load = function(request, parent, isMain) {
327
+ if (parent && parent.filename === runFile) {
328
+ if (request === '../epic') return fakeEc;
329
+ if (request === '../utils/momo-audio') {
330
+ return {
331
+ playAudio: (name) => {
332
+ audioCalls.push(name);
333
+ }
334
+ };
335
+ }
336
+ if (request === '../utils/momo-menu') {
337
+ return {
338
+ selectSingle: async (items) => {
339
+ selectionAudioState.push(audioCalls.slice());
340
+ return items[0];
341
+ }
342
+ };
343
+ }
344
+ if (request === 'colors') return {};
345
+ }
346
+ return originalLoad.call(this, request, parent, isMain);
347
+ };
348
+
349
+ process.cwd = () => root;
350
+ process.exit = (code) => {
351
+ throw new Error(`EXIT:${code}`);
352
+ };
353
+ console.log = () => {};
354
+ console.info = () => {};
355
+ console.warn = () => {};
356
+ console.error = () => {};
357
+
358
+ delete require.cache[runFile];
359
+ const executeRun = require(runFile);
360
+ await executeRun().catch((error) => {
361
+ if (!/^EXIT:\d+$/.test(error.message)) {
362
+ throw error;
363
+ }
364
+ });
365
+ } finally {
366
+ delete require.cache[runFile];
367
+ Module._load = originalLoad;
368
+ process.cwd = originalCwd;
369
+ process.exit = originalExit;
370
+ console.log = originalLog;
371
+ console.info = originalInfo;
372
+ console.warn = originalWarn;
373
+ console.error = originalError;
374
+ }
375
+
376
+ assert.deepStrictEqual(selectionAudioState, [[]]);
377
+ assert.deepStrictEqual(audioCalls, ['audio/run.ogg']);
378
+ });
379
+ };
380
+
118
381
  const main = async () => {
119
382
  await testDefaultThreadFallsBackTo20();
120
383
  await testThreadOverridesDefault();
121
384
  await testShrinkThreadPrunesOverflow();
385
+ await testRunSkipsFocusModeSelection();
386
+ await testTaskUsesCurrentR2moDirectory();
387
+ await testRunUsesCurrentR2moDirectory();
388
+ await testRunPlaysAudioAfterSelection();
122
389
  console.log('task tests passed');
123
390
  };
124
391
 
@@ -1,3 +0,0 @@
1
- {
2
- "lastSentAt": "2026-04-10T02:07:43.701Z"
3
- }
@@ -1,191 +0,0 @@
1
- {
2
- "version": "1.0.0",
3
- "lastScanned": 1776301703639,
4
- "projectRoot": "/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain",
5
- "techStack": {
6
- "languages": [
7
- {
8
- "name": "JavaScript/TypeScript",
9
- "version": null,
10
- "confidence": "high",
11
- "markers": [
12
- "package.json"
13
- ]
14
- }
15
- ],
16
- "frameworks": [],
17
- "packageManager": "npm",
18
- "runtime": null
19
- },
20
- "build": {
21
- "buildCommand": null,
22
- "testCommand": "npm test",
23
- "lintCommand": null,
24
- "devCommand": null,
25
- "scripts": {
26
- "test": "src/index.test.js"
27
- }
28
- },
29
- "conventions": {
30
- "namingStyle": null,
31
- "importStyle": null,
32
- "testPattern": null,
33
- "fileOrganization": null
34
- },
35
- "structure": {
36
- "isMonorepo": false,
37
- "workspaces": [],
38
- "mainDirectories": [
39
- "docs",
40
- "src"
41
- ],
42
- "gitBranches": {
43
- "defaultBranch": "master",
44
- "branchingStrategy": null
45
- }
46
- },
47
- "customNotes": [],
48
- "directoryMap": {
49
- "docs": {
50
- "path": "docs",
51
- "purpose": "Documentation",
52
- "fileCount": 0,
53
- "lastAccessed": 1776301703596,
54
- "keyFiles": []
55
- },
56
- "skills": {
57
- "path": "skills",
58
- "purpose": null,
59
- "fileCount": 0,
60
- "lastAccessed": 1776301703597,
61
- "keyFiles": []
62
- },
63
- "src": {
64
- "path": "src",
65
- "purpose": "Source code",
66
- "fileCount": 2,
67
- "lastAccessed": 1776301703611,
68
- "keyFiles": [
69
- "lain.js",
70
- "momo.js"
71
- ]
72
- }
73
- },
74
- "hotPaths": [
75
- {
76
- "path": "src/executor/executeTask.js",
77
- "accessCount": 8,
78
- "lastAccessed": 1776352988772,
79
- "type": "file"
80
- },
81
- {
82
- "path": "src/executor/executeRun.js",
83
- "accessCount": 6,
84
- "lastAccessed": 1776302572942,
85
- "type": "file"
86
- },
87
- {
88
- "path": "src",
89
- "accessCount": 6,
90
- "lastAccessed": 1776302580506,
91
- "type": "directory"
92
- },
93
- {
94
- "path": "src/utils/momo-audio.js",
95
- "accessCount": 5,
96
- "lastAccessed": 1776302802009,
97
- "type": "file"
98
- },
99
- {
100
- "path": "src/_template/.obsidian/community-plugins.json",
101
- "accessCount": 4,
102
- "lastAccessed": 1775786409382,
103
- "type": "file"
104
- },
105
- {
106
- "path": ".obsidian/community-plugins.json",
107
- "accessCount": 4,
108
- "lastAccessed": 1775786409838,
109
- "type": "file"
110
- },
111
- {
112
- "path": "src/commander/task.json",
113
- "accessCount": 2,
114
- "lastAccessed": 1776352973218,
115
- "type": "file"
116
- },
117
- {
118
- "path": "src/_template/LAIN/.obsidian/community-plugins.json",
119
- "accessCount": 1,
120
- "lastAccessed": 1775786211402,
121
- "type": "file"
122
- },
123
- {
124
- "path": "package.json",
125
- "accessCount": 1,
126
- "lastAccessed": 1776302161925,
127
- "type": "file"
128
- },
129
- {
130
- "path": "src/commander",
131
- "accessCount": 1,
132
- "lastAccessed": 1776302162007,
133
- "type": "directory"
134
- },
135
- {
136
- "path": "src/commander/run.json",
137
- "accessCount": 1,
138
- "lastAccessed": 1776302188582,
139
- "type": "file"
140
- },
141
- {
142
- "path": "src/epic/momo.fn.out.js",
143
- "accessCount": 1,
144
- "lastAccessed": 1776302188717,
145
- "type": "file"
146
- },
147
- {
148
- "path": "src/momo.js",
149
- "accessCount": 1,
150
- "lastAccessed": 1776302402340,
151
- "type": "file"
152
- },
153
- {
154
- "path": "src/executor/index.js",
155
- "accessCount": 1,
156
- "lastAccessed": 1776302402605,
157
- "type": "file"
158
- },
159
- {
160
- "path": "src/utils/momo-menu.js",
161
- "accessCount": 1,
162
- "lastAccessed": 1776302439510,
163
- "type": "file"
164
- },
165
- {
166
- "path": "src/utils/momo-file-utils.js",
167
- "accessCount": 1,
168
- "lastAccessed": 1776302439713,
169
- "type": "file"
170
- },
171
- {
172
- "path": "src/executor/executeOpen.js",
173
- "accessCount": 1,
174
- "lastAccessed": 1776302439732,
175
- "type": "file"
176
- },
177
- {
178
- "path": "",
179
- "accessCount": 1,
180
- "lastAccessed": 1776302580716,
181
- "type": "directory"
182
- },
183
- {
184
- "path": "publish.sh",
185
- "accessCount": 1,
186
- "lastAccessed": 1776303501941,
187
- "type": "file"
188
- }
189
- ],
190
- "userDirectives": []
191
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "2327d169-ea62-4881-a6e6-c88bf089e8b8",
3
- "ended_at": "2026-04-11T16:20:12.066Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "24968ee6-c99b-47be-a904-68fcce1b08ba",
3
- "ended_at": "2026-03-30T07:17:31.410Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "3158a19c-5915-4c7e-8a1e-83d65c25bb4a",
3
- "ended_at": "2026-03-29T01:57:21.393Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5",
3
- "ended_at": "2026-03-31T06:27:53.386Z",
4
- "reason": "other",
5
- "agents_spawned": 2,
6
- "agents_completed": 2,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "7fa8f05b-d348-424b-a9bf-7e84aaacdc29",
3
- "ended_at": "2026-04-01T10:35:29.009Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "81b2f444-6a18-4a87-9a51-1492771689e7",
3
- "ended_at": "2026-04-10T01:22:08.599Z",
4
- "reason": "prompt_input_exit",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "d7901fcc-6318-4bc6-ba68-81722b1a4231",
3
- "ended_at": "2026-03-29T03:41:06.062Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "e12400d6-5242-491c-b32a-21db817a0d61",
3
- "ended_at": "2026-03-30T06:30:50.982Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "ee30b9d7-e57d-48b5-8363-c1d7cc7adae3",
3
- "ended_at": "2026-04-16T08:17:04.768Z",
4
- "reason": "other",
5
- "agents_spawned": 2,
6
- "agents_completed": 2,
7
- "modes_used": []
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "session_id": "f23b8556-e76e-4986-b4ba-fbfc3fec8da6",
3
- "ended_at": "2026-04-16T17:06:41.136Z",
4
- "reason": "other",
5
- "agents_spawned": 0,
6
- "agents_completed": 0,
7
- "modes_used": []
8
- }
@@ -1,4 +0,0 @@
1
- {
2
- "updatedAt": "2026-04-16T08:17:04.773Z",
3
- "missions": []
4
- }