diff --git a/.scheduler-memory/session-mlnww6r0/retrieve.json b/.scheduler-memory/session-mlnww6r0/retrieve.json new file mode 100644 index 0000000..38da421 --- /dev/null +++ b/.scheduler-memory/session-mlnww6r0/retrieve.json @@ -0,0 +1,18 @@ +{ + "cadence": "weekly", + "operation": "retrieve", + "runId": "session-mlnww6r0", + "servicePath": "src/services/memory/index.js#getRelevantMemories", + "inputs": { + "agentId": "refactor-agent", + "promptPath": "", + "promptIntent": "scheduler memory retrieval", + "query": "scheduler | weekly | agent | refactor-agent | intent | scheduler memory retrieval", + "events": 1 + }, + "outputs": { + "ingestedCount": 1, + "retrievedCount": 1 + }, + "status": "ok" +} \ No newline at end of file diff --git a/.scheduler-memory/session-mlnww6r0/retrieve.ok b/.scheduler-memory/session-mlnww6r0/retrieve.ok new file mode 100644 index 0000000..84b1719 --- /dev/null +++ b/.scheduler-memory/session-mlnww6r0/retrieve.ok @@ -0,0 +1 @@ +MEMORY_RETRIEVED diff --git a/.scheduler-memory/session-mlnx056f/store.json b/.scheduler-memory/session-mlnx056f/store.json new file mode 100644 index 0000000..98e8dbb --- /dev/null +++ b/.scheduler-memory/session-mlnx056f/store.json @@ -0,0 +1,19 @@ +{ + "cadence": "weekly", + "operation": "store", + "runId": "session-mlnx056f", + "servicePath": "src/services/memory/index.js#ingestEvents", + "inputs": { + "agentId": "refactor-agent", + "promptPath": "", + "promptIntent": "scheduler memory store", + "events": 2 + }, + "outputs": { + "storedCount": 1, + "summaries": [ + "Store memory event A for weekly :: scheduler memory store Store memory event B for weekly :: scheduler memory store" + ] + }, + "status": "ok" +} \ No newline at end of file diff --git a/.scheduler-memory/session-mlnx056f/store.ok b/.scheduler-memory/session-mlnx056f/store.ok new file mode 100644 index 0000000..1e40bb6 --- /dev/null +++ b/.scheduler-memory/session-mlnx056f/store.ok @@ -0,0 +1 @@ +MEMORY_STORED diff --git a/src/cli-parser.mjs b/src/cli-parser.mjs new file mode 100644 index 0000000..e9d9c8a --- /dev/null +++ b/src/cli-parser.mjs @@ -0,0 +1,113 @@ +import { DEFAULT_DASHBOARD_PORT } from './constants.mjs'; + +/** + * Parses command-line arguments into a structured object. + * + * @param {string[]} argv - Arguments from process.argv.slice(2) + * @returns {Object} - Parsed arguments (command, flags, values) + */ +export function parseArgs(argv) { + const args = { + command: null, + agent: null, + cadence: null, + dryRun: false, + force: false, + port: DEFAULT_DASHBOARD_PORT, + logDir: 'task-logs', + ignoreLogs: false, + id: null, + type: null, + tags: [], + pinned: null, + limit: null, + offset: null, + retentionMs: null, + windowMs: null, + timeoutMs: null, + allRelaysDownMinutes: null, + minSuccessRate: null, + windowMinutes: null, + }; + let i = 0; + + if (argv.length > 0 && !argv[0].startsWith('-')) { + args.command = argv[0]; + i = 1; + } + + for (; i < argv.length; i++) { + const arg = argv[i]; + if (arg === '--agent' || arg === '-a') { + args.agent = argv[++i]; + } else if (arg === '--cadence' || arg === '-c') { + args.cadence = argv[++i]; + } else if (arg.startsWith('--agent=')) { + args.agent = arg.split('=')[1]; + } else if (arg.startsWith('--cadence=')) { + args.cadence = arg.split('=')[1]; + } else if (arg === '--dry-run') { + args.dryRun = true; + } else if (arg === '--force') { + args.force = true; + } else if (arg === '--port') { + args.port = parseInt(argv[++i], 10) || DEFAULT_DASHBOARD_PORT; + } else if (arg === '--log-dir') { + args.logDir = argv[++i]; + } else if (arg === '--ignore-logs') { + args.ignoreLogs = true; + } else if (arg === '--id') { + args.id = argv[++i]; + } else if (arg.startsWith('--id=')) { + args.id = arg.split('=')[1]; + } else if (arg === '--type') { + args.type = argv[++i]; + } else if (arg.startsWith('--type=')) { + args.type = arg.split('=')[1]; + } else if (arg === '--tags') { + args.tags = String(argv[++i]).split(',').map((tag) => tag.trim()).filter(Boolean); + } else if (arg.startsWith('--tags=')) { + args.tags = String(arg.split('=')[1]).split(',').map((tag) => tag.trim()).filter(Boolean); + } else if (arg === '--pinned') { + const value = String(argv[++i]).toLowerCase(); + args.pinned = value === 'true' ? true : value === 'false' ? false : null; + } else if (arg.startsWith('--pinned=')) { + const value = String(arg.split('=')[1]).toLowerCase(); + args.pinned = value === 'true' ? true : value === 'false' ? false : null; + } else if (arg === '--limit') { + args.limit = parseInt(argv[++i], 10); + } else if (arg.startsWith('--limit=')) { + args.limit = parseInt(arg.split('=')[1], 10); + } else if (arg === '--offset') { + args.offset = parseInt(argv[++i], 10); + } else if (arg.startsWith('--offset=')) { + args.offset = parseInt(arg.split('=')[1], 10); + } else if (arg === '--retention-ms') { + args.retentionMs = parseInt(argv[++i], 10); + } else if (arg.startsWith('--retention-ms=')) { + args.retentionMs = parseInt(arg.split('=')[1], 10); + } else if (arg === '--window-ms') { + args.windowMs = parseInt(argv[++i], 10); + } else if (arg.startsWith('--window-ms=')) { + args.windowMs = parseInt(arg.split('=')[1], 10); + } else if (arg === '--timeout-ms') { + args.timeoutMs = parseInt(argv[++i], 10); + } else if (arg.startsWith('--timeout-ms=')) { + args.timeoutMs = parseInt(arg.split('=')[1], 10); + } else if (arg === '--all-relays-down-minutes') { + args.allRelaysDownMinutes = parseInt(argv[++i], 10); + } else if (arg.startsWith('--all-relays-down-minutes=')) { + args.allRelaysDownMinutes = parseInt(arg.split('=')[1], 10); + } else if (arg === '--min-success-rate') { + args.minSuccessRate = parseFloat(argv[++i]); + } else if (arg.startsWith('--min-success-rate=')) { + args.minSuccessRate = parseFloat(arg.split('=')[1]); + } else if (arg === '--window-minutes') { + args.windowMinutes = parseInt(argv[++i], 10); + } else if (arg.startsWith('--window-minutes=')) { + args.windowMinutes = parseInt(arg.split('=')[1], 10); + } + } + + return args; +} diff --git a/src/lib.mjs b/src/lib.mjs index 411b86e..9541615 100644 --- a/src/lib.mjs +++ b/src/lib.mjs @@ -19,6 +19,7 @@ import { RACE_CHECK_DELAY_MS, } from './constants.mjs'; import { cmdInit, cmdUpdate } from './ops.mjs'; +import { parseArgs } from './cli-parser.mjs'; import { getRoster as _getRoster } from './roster.mjs'; import { queryLocks as _queryLocks, publishLock as _publishLock, parseLockEvent } from './lock-ops.mjs'; import { cmdDashboard } from './dashboard.mjs'; @@ -504,118 +505,6 @@ export async function cmdComplete(agent, cadence, dryRun = false, deps = {}) { return { status: 'completed', eventId: event.id }; } -/** - * Parses command-line arguments into a structured object. - * - * @param {string[]} argv - Arguments from process.argv.slice(2) - * @returns {Object} - Parsed arguments (command, flags, values) - */ -function parseArgs(argv) { - const args = { - command: null, - agent: null, - cadence: null, - dryRun: false, - force: false, - port: DEFAULT_DASHBOARD_PORT, - logDir: 'task-logs', - ignoreLogs: false, - id: null, - type: null, - tags: [], - pinned: null, - limit: null, - offset: null, - retentionMs: null, - windowMs: null, - timeoutMs: null, - allRelaysDownMinutes: null, - minSuccessRate: null, - windowMinutes: null, - }; - let i = 0; - - if (argv.length > 0 && !argv[0].startsWith('-')) { - args.command = argv[0]; - i = 1; - } - - for (; i < argv.length; i++) { - const arg = argv[i]; - if (arg === '--agent' || arg === '-a') { - args.agent = argv[++i]; - } else if (arg === '--cadence' || arg === '-c') { - args.cadence = argv[++i]; - } else if (arg.startsWith('--agent=')) { - args.agent = arg.split('=')[1]; - } else if (arg.startsWith('--cadence=')) { - args.cadence = arg.split('=')[1]; - } else if (arg === '--dry-run') { - args.dryRun = true; - } else if (arg === '--force') { - args.force = true; - } else if (arg === '--port') { - args.port = parseInt(argv[++i], 10) || DEFAULT_DASHBOARD_PORT; - } else if (arg === '--log-dir') { - args.logDir = argv[++i]; - } else if (arg === '--ignore-logs') { - args.ignoreLogs = true; - } else if (arg === '--id') { - args.id = argv[++i]; - } else if (arg.startsWith('--id=')) { - args.id = arg.split('=')[1]; - } else if (arg === '--type') { - args.type = argv[++i]; - } else if (arg.startsWith('--type=')) { - args.type = arg.split('=')[1]; - } else if (arg === '--tags') { - args.tags = String(argv[++i]).split(',').map((tag) => tag.trim()).filter(Boolean); - } else if (arg.startsWith('--tags=')) { - args.tags = String(arg.split('=')[1]).split(',').map((tag) => tag.trim()).filter(Boolean); - } else if (arg === '--pinned') { - const value = String(argv[++i]).toLowerCase(); - args.pinned = value === 'true' ? true : value === 'false' ? false : null; - } else if (arg.startsWith('--pinned=')) { - const value = String(arg.split('=')[1]).toLowerCase(); - args.pinned = value === 'true' ? true : value === 'false' ? false : null; - } else if (arg === '--limit') { - args.limit = parseInt(argv[++i], 10); - } else if (arg.startsWith('--limit=')) { - args.limit = parseInt(arg.split('=')[1], 10); - } else if (arg === '--offset') { - args.offset = parseInt(argv[++i], 10); - } else if (arg.startsWith('--offset=')) { - args.offset = parseInt(arg.split('=')[1], 10); - } else if (arg === '--retention-ms') { - args.retentionMs = parseInt(argv[++i], 10); - } else if (arg.startsWith('--retention-ms=')) { - args.retentionMs = parseInt(arg.split('=')[1], 10); - } else if (arg === '--window-ms') { - args.windowMs = parseInt(argv[++i], 10); - } else if (arg.startsWith('--window-ms=')) { - args.windowMs = parseInt(arg.split('=')[1], 10); - } else if (arg === '--timeout-ms') { - args.timeoutMs = parseInt(argv[++i], 10); - } else if (arg.startsWith('--timeout-ms=')) { - args.timeoutMs = parseInt(arg.split('=')[1], 10); - } else if (arg === '--all-relays-down-minutes') { - args.allRelaysDownMinutes = parseInt(argv[++i], 10); - } else if (arg.startsWith('--all-relays-down-minutes=')) { - args.allRelaysDownMinutes = parseInt(arg.split('=')[1], 10); - } else if (arg === '--min-success-rate') { - args.minSuccessRate = parseFloat(argv[++i]); - } else if (arg.startsWith('--min-success-rate=')) { - args.minSuccessRate = parseFloat(arg.split('=')[1]); - } else if (arg === '--window-minutes') { - args.windowMinutes = parseInt(argv[++i], 10); - } else if (arg.startsWith('--window-minutes=')) { - args.windowMinutes = parseInt(arg.split('=')[1], 10); - } - } - - return args; -} - function usage() { console.error(`Usage: torch-lock [options] diff --git a/src/prompts/weekly-scheduler.md b/src/prompts/weekly-scheduler.md index a0689e7..093cd3d 100644 --- a/src/prompts/weekly-scheduler.md +++ b/src/prompts/weekly-scheduler.md @@ -33,9 +33,9 @@ Canonical roster source: `src/prompts/roster.json` (`weekly` key). | 7 | perf-deepdive-agent | `perf-deepdive-agent.md` | | 8 | perf-optimization-agent | `perf-optimization-agent.md` | | 9 | pr-review-agent | `pr-review-agent.md` | -| 10 | prompt-fixer-agent | `prompt-fixer-agent.md` | -| 11 | prompt-maintenance-agent | `prompt-maintenance-agent.md` | -| 12 | prompt-safety-agent | `prompt-safety-agent.md` | +| 10 | prompt-maintenance-agent | `prompt-maintenance-agent.md` | +| 11 | prompt-safety-agent | `prompt-safety-agent.md` | +| 12 | prompt-fixer-agent | `prompt-fixer-agent.md` | | 13 | race-condition-agent | `race-condition-agent.md` | | 14 | refactor-agent | `refactor-agent.md` | | 15 | repo-fit-agent | `repo-fit-agent.md` | diff --git a/task-logs/weekly/2026-02-15T15-48-31Z__refactor-agent__completed.md b/task-logs/weekly/2026-02-15T15-48-31Z__refactor-agent__completed.md new file mode 100644 index 0000000..c1c97fd --- /dev/null +++ b/task-logs/weekly/2026-02-15T15-48-31Z__refactor-agent__completed.md @@ -0,0 +1,22 @@ +--- +agent: refactor-agent +cadence: weekly +date: 2026-02-15 +status: completed +--- + +# Weekly Task: Refactor Agent + +**Goal**: Perform small, incremental refactors. + +**Work**: +- Extracted `parseArgs` function from `src/lib.mjs` to a new module `src/cli-parser.mjs`. +- Added unit tests for `parseArgs` in `test/cli-parser.test.mjs`. +- Verified changes with `npm test` and `npm run lint`. +- Fixed roster drift in `src/prompts/weekly-scheduler.md`. + +**Result**: +- `src/lib.mjs` is cleaner and imports `parseArgs`. +- `src/cli-parser.mjs` is testable and tested. +- `src/prompts/weekly-scheduler.md` is synced with `roster.json`. +- All tests passed. diff --git a/test/cli-parser.test.mjs b/test/cli-parser.test.mjs new file mode 100644 index 0000000..fd2daa2 --- /dev/null +++ b/test/cli-parser.test.mjs @@ -0,0 +1,80 @@ +import { test } from 'node:test'; +import assert from 'node:assert'; +import { parseArgs } from '../src/cli-parser.mjs'; +import { DEFAULT_DASHBOARD_PORT } from '../src/constants.mjs'; + +test('parseArgs should parse basic command', () => { + const args = parseArgs(['check', '--cadence', 'daily']); + assert.strictEqual(args.command, 'check'); + assert.strictEqual(args.cadence, 'daily'); +}); + +test('parseArgs should parse agent and cadence', () => { + const args = parseArgs(['lock', '--agent', 'my-agent', '--cadence', 'weekly']); + assert.strictEqual(args.command, 'lock'); + assert.strictEqual(args.agent, 'my-agent'); + assert.strictEqual(args.cadence, 'weekly'); +}); + +test('parseArgs should parse equals sign syntax', () => { + const args = parseArgs(['lock', '--agent=my-agent', '--cadence=weekly']); + assert.strictEqual(args.command, 'lock'); + assert.strictEqual(args.agent, 'my-agent'); + assert.strictEqual(args.cadence, 'weekly'); +}); + +test('parseArgs should parse dry-run flag', () => { + const args = parseArgs(['lock', '--dry-run']); + assert.strictEqual(args.dryRun, true); +}); + +test('parseArgs should parse port with default', () => { + const args = parseArgs(['dashboard']); + assert.strictEqual(args.port, DEFAULT_DASHBOARD_PORT); +}); + +test('parseArgs should parse custom port', () => { + const args = parseArgs(['dashboard', '--port', '8080']); + assert.strictEqual(args.port, 8080); +}); + +test('parseArgs should parse ignore-logs flag', () => { + const args = parseArgs(['check', '--ignore-logs']); + assert.strictEqual(args.ignoreLogs, true); +}); + +test('parseArgs should parse memory flags', () => { + const args = parseArgs([ + 'list-memories', + '--id', '123', + '--type', 'retrieve', + '--tags', 'a,b', + '--pinned', 'true', + '--limit', '10', + '--offset', '5' + ]); + assert.strictEqual(args.id, '123'); + assert.strictEqual(args.type, 'retrieve'); + assert.deepStrictEqual(args.tags, ['a', 'b']); + assert.strictEqual(args.pinned, true); + assert.strictEqual(args.limit, 10); + assert.strictEqual(args.offset, 5); +}); + +test('parseArgs should parse memory flags with equals', () => { + const args = parseArgs([ + 'list-memories', + '--id=123', + '--type=retrieve', + '--tags=a,b', + '--pinned=false', + '--limit=10', + '--offset=5' + ]); + assert.strictEqual(args.id, '123'); + assert.strictEqual(args.type, 'retrieve'); + assert.deepStrictEqual(args.tags, ['a', 'b']); + assert.strictEqual(args.pinned, false); + assert.strictEqual(args.limit, 10); + assert.strictEqual(args.offset, 5); +});