diff --git a/memory-updates/2026-02-21T20-22-19Z__refactor-agent.md b/memory-updates/2026-02-21T20-22-19Z__refactor-agent.md new file mode 100644 index 0000000..efe8057 --- /dev/null +++ b/memory-updates/2026-02-21T20-22-19Z__refactor-agent.md @@ -0,0 +1,12 @@ +# Memory Update — refactor-agent — 2026-02-21 + +## Key findings +- Extracted `cmdRemove` successfully. +- `src/ops.mjs` was over 800 LOC, now lighter. + +## Patterns / reusable knowledge +- When extracting commands, remember to move or duplicate helper functions they depend on, or export them if shared. +- Tests often need renaming and import updates. + +## Warnings / gotchas +- `test/ops-remove.test.mjs` was renamed to `test/cmd-remove.test.mjs`. diff --git a/src/cmd-remove.mjs b/src/cmd-remove.mjs new file mode 100644 index 0000000..204b527 --- /dev/null +++ b/src/cmd-remove.mjs @@ -0,0 +1,256 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import readline from 'node:readline/promises'; +import { stdin as input, stdout as output } from 'node:process'; +import { TORCH_HOST_SCRIPTS } from './constants.mjs'; + +/** + * Detects the TORCH install directory within a project. + * + * Strategy: + * 1. If a 'torch/' directory exists with a roster.json or bin/, it's the install dir. + * 2. If the current directory's package.json has name "torch-lock", installed to '.'. + * 3. Returns null if TORCH is not detected. + * + * @param {string} cwd - The project root directory + * @returns {string|null} - The install directory name ('torch', '.', etc.) or null + */ +export function detectTorchInstallDir(cwd) { + // Check for 'torch/' subdirectory with TORCH markers + const torchSubdir = path.join(cwd, 'torch'); + if (fs.existsSync(torchSubdir)) { + const hasRoster = fs.existsSync(path.join(torchSubdir, 'roster.json')); + const hasBin = fs.existsSync(path.join(torchSubdir, 'bin')); + if (hasRoster || hasBin) { + return 'torch'; + } + } + + // Check if installed to current directory + const pkgPath = path.join(cwd, 'package.json'); + if (fs.existsSync(pkgPath)) { + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + if (pkg.name === 'torch-lock') { + return '.'; + } + } catch (_e) { + // Ignore parse errors + } + } + + return null; +} + +/** + * Removes a directory or file if it exists, logging the action. + * + * @param {string} target - Absolute path to remove + * @param {string} label - Human-readable label for log output + * @param {Function} log - Logging function + * @returns {boolean} - True if something was removed + */ +export function removeIfExists(target, label, log) { + if (!fs.existsSync(target)) return false; + + const stat = fs.statSync(target); + if (stat.isDirectory()) { + fs.rmSync(target, { recursive: true, force: true }); + } else { + fs.unlinkSync(target); + } + log(` Removed ${label}`); + return true; +} + +/** + * Removes TORCH torch:* scripts from the host package.json. + * + * @param {string} hostRoot - Project root containing package.json + * @param {Function} log - Logging function + * @returns {boolean} - True if any scripts were removed + */ +export function removeHostScripts(hostRoot, log) { + const hostPkgPath = path.join(hostRoot, 'package.json'); + if (!fs.existsSync(hostPkgPath)) return false; + + try { + const raw = fs.readFileSync(hostPkgPath, 'utf8'); + const pkg = JSON.parse(raw); + if (!pkg.scripts) return false; + + let modified = false; + for (const key of TORCH_HOST_SCRIPTS) { + if (key in pkg.scripts) { + delete pkg.scripts[key]; + log(` Removed script: "${key}"`); + modified = true; + } + } + + if (modified) { + fs.writeFileSync(hostPkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8'); + log(' Updated package.json.'); + } + return modified; + } catch (e) { + log(` Warning: Could not update package.json: ${e.message}`); + return false; + } +} + +/** + * Completely removes TORCH from a project that installed it via + * `npm install && npx torch-lock init`. + * + * What it removes: + * 1. The torch/ install directory (or equivalent) + * 2. torch-config.json at the project root + * 3. .torch/ hidden directory (prompt history) + * 4. .scheduler-memory/ directory (runtime memory store) + * 5. task-logs/ directory (scheduler run logs) + * 6. src/proposals/ directory (governance proposals) + * 7. torch:* scripts from the host package.json + * 8. The torch-lock npm package (node_modules/torch-lock) + * + * @param {boolean} force - If true, skip the confirmation prompt + * @param {string} cwd - Working directory (project root) + * @param {Object|null} mockAnswers - For testing: { confirm: true/false } + * @returns {Promise} + */ +export async function cmdRemove(force = false, cwd = process.cwd(), mockAnswers = null) { + const log = console.log; + const installDir = detectTorchInstallDir(cwd); + + if (!installDir) { + log('No TORCH installation detected in this directory.'); + log('Looked for:'); + log(' - A torch/ subdirectory containing roster.json or bin/'); + log(' - A package.json with name "torch-lock" (root install)'); + return; + } + + const isRootInstall = installDir === '.'; + const torchDir = path.resolve(cwd, installDir); + + // Build a manifest of what will be removed + const targets = []; + + if (!isRootInstall && fs.existsSync(torchDir)) { + targets.push({ path: torchDir, label: `${installDir}/ (TORCH install directory)` }); + } + + const configPath = path.join(cwd, 'torch-config.json'); + if (fs.existsSync(configPath)) { + targets.push({ path: configPath, label: 'torch-config.json' }); + } + + const dotTorch = path.join(cwd, '.torch'); + if (fs.existsSync(dotTorch)) { + targets.push({ path: dotTorch, label: '.torch/ (prompt history)' }); + } + + const schedulerMemory = path.join(cwd, '.scheduler-memory'); + if (fs.existsSync(schedulerMemory)) { + targets.push({ path: schedulerMemory, label: '.scheduler-memory/ (memory store)' }); + } + + const taskLogs = path.join(cwd, 'task-logs'); + if (fs.existsSync(taskLogs)) { + targets.push({ path: taskLogs, label: 'task-logs/ (scheduler logs)' }); + } + + const proposals = path.join(cwd, 'src', 'proposals'); + if (fs.existsSync(proposals)) { + targets.push({ path: proposals, label: 'src/proposals/ (governance proposals)' }); + } + + // Check for host scripts + const hostPkgPath = path.join(cwd, 'package.json'); + let hasHostScripts = false; + if (fs.existsSync(hostPkgPath)) { + try { + const pkg = JSON.parse(fs.readFileSync(hostPkgPath, 'utf8')); + if (pkg.scripts) { + hasHostScripts = TORCH_HOST_SCRIPTS.some(key => key in pkg.scripts); + } + } catch (_e) { /* ignore */ } + } + + if (targets.length === 0 && !hasHostScripts) { + log('Nothing to remove — no TORCH artifacts found.'); + return; + } + + // Show what will be removed + log('\nThe following TORCH artifacts will be removed:\n'); + for (const t of targets) { + log(` - ${t.label}`); + } + if (hasHostScripts) { + log(' - torch:* scripts from package.json'); + } + log(' - torch-lock npm package (via npm uninstall)'); + log(''); + + // Confirm unless --force + if (!force) { + let confirmed; + + if (mockAnswers) { + confirmed = mockAnswers.confirm; + } else { + const rl = readline.createInterface({ input, output }); + try { + const answer = await rl.question('Proceed with removal? (yes/no): '); + confirmed = answer.trim().toLowerCase() === 'yes'; + } finally { + rl.close(); + } + } + + if (!confirmed) { + log('Removal cancelled.'); + return; + } + } + + log('\nRemoving TORCH...\n'); + + // 1. Remove directories and files + for (const t of targets) { + removeIfExists(t.path, t.label, log); + } + + // 2. Clean up empty src/ directory if proposals was the only thing in it + const srcDir = path.join(cwd, 'src'); + if (fs.existsSync(srcDir)) { + try { + const entries = fs.readdirSync(srcDir); + if (entries.length === 0) { + fs.rmdirSync(srcDir); + log(' Removed empty src/ directory'); + } + } catch (_e) { /* leave it if not empty or permission error */ } + } + + // 3. Remove host package.json scripts + if (hasHostScripts) { + removeHostScripts(cwd, log); + } + + // 4. Uninstall the npm package + log('\n Running npm uninstall torch-lock...'); + try { + const { execSync } = await import('node:child_process'); + execSync('npm uninstall torch-lock', { cwd, stdio: 'pipe' }); + log(' Uninstalled torch-lock package.'); + } catch (e) { + log(` Warning: npm uninstall torch-lock failed: ${e.message}`); + log(' You may need to run "npm uninstall torch-lock" manually.'); + } + + log('\nTORCH has been completely removed from this project.'); + log('If you used TORCH environment variables (NOSTR_LOCK_*, TORCH_*),'); + log('remember to remove them from your shell profile or CI configuration.'); +} diff --git a/src/context/CONTEXT_2026-02-21T20-22-19Z.md b/src/context/CONTEXT_2026-02-21T20-22-19Z.md new file mode 100644 index 0000000..8af26e9 --- /dev/null +++ b/src/context/CONTEXT_2026-02-21T20-22-19Z.md @@ -0,0 +1,19 @@ +--- +agent: refactor-agent +cadence: weekly +session: 2026-02-21T20:22:19Z +run-start: 2026-02-21T20:22:19Z +prompt: src/prompts/weekly/refactor-agent.md +--- + +# Context + +## Goal +Refactor `src/ops.mjs` to improve modularity. + +## Scope +Extract `cmdRemove` and related helpers into `src/cmd-remove.mjs`. + +## Constraints +- Preserve backward compatibility by re-exporting. +- Add unit tests. diff --git a/src/decisions/DECISIONS_2026-02-21T20-22-19Z.md b/src/decisions/DECISIONS_2026-02-21T20-22-19Z.md new file mode 100644 index 0000000..375af91 --- /dev/null +++ b/src/decisions/DECISIONS_2026-02-21T20-22-19Z.md @@ -0,0 +1,21 @@ +--- +agent: refactor-agent +cadence: weekly +session: 2026-02-21T20:22:19Z +run-start: 2026-02-21T20:22:19Z +prompt: src/prompts/weekly/refactor-agent.md +--- + +# Decisions + +## Decision +Extracted `cmdRemove` to `src/cmd-remove.mjs`. + +## Rationale +To adhere to separation of concerns and reduce the size of `src/ops.mjs` (>800 LOC). + +## Decision +Removed duplicate export of `mergeRelayList` in `src/lock-utils.mjs`. + +## Rationale +It caused syntax errors blocking execution. diff --git a/src/lock-utils.mjs b/src/lock-utils.mjs index 8e68dd2..69fc281 100644 --- a/src/lock-utils.mjs +++ b/src/lock-utils.mjs @@ -62,10 +62,6 @@ export function withTimeout(promise, timeoutMs, timeoutMessage = 'Operation time ]); } -export function mergeRelayList(primaryRelays, fallbackRelays) { - return [...new Set([...primaryRelays, ...fallbackRelays])]; -} - const MAX_RANDOM = 281474976710655; // 2**48 - 1 export function secureRandom() { diff --git a/src/ops.mjs b/src/ops.mjs index d471aac..af500dc 100644 --- a/src/ops.mjs +++ b/src/ops.mjs @@ -4,8 +4,9 @@ import { fileURLToPath } from 'node:url'; import crypto from 'node:crypto'; import readline from 'node:readline/promises'; import { stdin as input, stdout as output } from 'node:process'; -import { DEFAULT_RELAYS, TORCH_HOST_SCRIPTS } from './constants.mjs'; +import { DEFAULT_RELAYS } from './constants.mjs'; import { ensureDir } from './utils.mjs'; +export { cmdRemove } from './cmd-remove.mjs'; const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); @@ -453,257 +454,6 @@ function injectScriptsIntoHost(hostRoot, installDirName) { } } -/** - * Detects the TORCH install directory within a project. - * - * Strategy: - * 1. If a 'torch/' directory exists with a roster.json or bin/, it's the install dir. - * 2. If the current directory's package.json has name "torch-lock", installed to '.'. - * 3. Returns null if TORCH is not detected. - * - * @param {string} cwd - The project root directory - * @returns {string|null} - The install directory name ('torch', '.', etc.) or null - */ -function detectTorchInstallDir(cwd) { - // Check for 'torch/' subdirectory with TORCH markers - const torchSubdir = path.join(cwd, 'torch'); - if (fs.existsSync(torchSubdir)) { - const hasRoster = fs.existsSync(path.join(torchSubdir, 'roster.json')); - const hasBin = fs.existsSync(path.join(torchSubdir, 'bin')); - if (hasRoster || hasBin) { - return 'torch'; - } - } - - // Check if installed to current directory - const pkgPath = path.join(cwd, 'package.json'); - if (fs.existsSync(pkgPath)) { - try { - const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); - if (pkg.name === 'torch-lock') { - return '.'; - } - } catch (_e) { - // Ignore parse errors - } - } - - return null; -} - -/** - * Removes a directory or file if it exists, logging the action. - * - * @param {string} target - Absolute path to remove - * @param {string} label - Human-readable label for log output - * @param {Function} log - Logging function - * @returns {boolean} - True if something was removed - */ -function removeIfExists(target, label, log) { - if (!fs.existsSync(target)) return false; - - const stat = fs.statSync(target); - if (stat.isDirectory()) { - fs.rmSync(target, { recursive: true, force: true }); - } else { - fs.unlinkSync(target); - } - log(` Removed ${label}`); - return true; -} - -/** - * Removes TORCH torch:* scripts from the host package.json. - * - * @param {string} hostRoot - Project root containing package.json - * @param {Function} log - Logging function - * @returns {boolean} - True if any scripts were removed - */ -function removeHostScripts(hostRoot, log) { - const hostPkgPath = path.join(hostRoot, 'package.json'); - if (!fs.existsSync(hostPkgPath)) return false; - - try { - const raw = fs.readFileSync(hostPkgPath, 'utf8'); - const pkg = JSON.parse(raw); - if (!pkg.scripts) return false; - - let modified = false; - for (const key of TORCH_HOST_SCRIPTS) { - if (key in pkg.scripts) { - delete pkg.scripts[key]; - log(` Removed script: "${key}"`); - modified = true; - } - } - - if (modified) { - fs.writeFileSync(hostPkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8'); - log(' Updated package.json.'); - } - return modified; - } catch (e) { - log(` Warning: Could not update package.json: ${e.message}`); - return false; - } -} - -/** - * Completely removes TORCH from a project that installed it via - * `npm install && npx torch-lock init`. - * - * What it removes: - * 1. The torch/ install directory (or equivalent) - * 2. torch-config.json at the project root - * 3. .torch/ hidden directory (prompt history) - * 4. .scheduler-memory/ directory (runtime memory store) - * 5. task-logs/ directory (scheduler run logs) - * 6. src/proposals/ directory (governance proposals) - * 7. torch:* scripts from the host package.json - * 8. The torch-lock npm package (node_modules/torch-lock) - * - * @param {boolean} force - If true, skip the confirmation prompt - * @param {string} cwd - Working directory (project root) - * @param {Object|null} mockAnswers - For testing: { confirm: true/false } - * @returns {Promise} - */ -export async function cmdRemove(force = false, cwd = process.cwd(), mockAnswers = null) { - const log = console.log; - const installDir = detectTorchInstallDir(cwd); - - if (!installDir) { - log('No TORCH installation detected in this directory.'); - log('Looked for:'); - log(' - A torch/ subdirectory containing roster.json or bin/'); - log(' - A package.json with name "torch-lock" (root install)'); - return; - } - - const isRootInstall = installDir === '.'; - const torchDir = path.resolve(cwd, installDir); - - // Build a manifest of what will be removed - const targets = []; - - if (!isRootInstall && fs.existsSync(torchDir)) { - targets.push({ path: torchDir, label: `${installDir}/ (TORCH install directory)` }); - } - - const configPath = path.join(cwd, 'torch-config.json'); - if (fs.existsSync(configPath)) { - targets.push({ path: configPath, label: 'torch-config.json' }); - } - - const dotTorch = path.join(cwd, '.torch'); - if (fs.existsSync(dotTorch)) { - targets.push({ path: dotTorch, label: '.torch/ (prompt history)' }); - } - - const schedulerMemory = path.join(cwd, '.scheduler-memory'); - if (fs.existsSync(schedulerMemory)) { - targets.push({ path: schedulerMemory, label: '.scheduler-memory/ (memory store)' }); - } - - const taskLogs = path.join(cwd, 'task-logs'); - if (fs.existsSync(taskLogs)) { - targets.push({ path: taskLogs, label: 'task-logs/ (scheduler logs)' }); - } - - const proposals = path.join(cwd, 'src', 'proposals'); - if (fs.existsSync(proposals)) { - targets.push({ path: proposals, label: 'src/proposals/ (governance proposals)' }); - } - - // Check for host scripts - const hostPkgPath = path.join(cwd, 'package.json'); - let hasHostScripts = false; - if (fs.existsSync(hostPkgPath)) { - try { - const pkg = JSON.parse(fs.readFileSync(hostPkgPath, 'utf8')); - if (pkg.scripts) { - hasHostScripts = TORCH_HOST_SCRIPTS.some(key => key in pkg.scripts); - } - } catch (_e) { /* ignore */ } - } - - if (targets.length === 0 && !hasHostScripts) { - log('Nothing to remove — no TORCH artifacts found.'); - return; - } - - // Show what will be removed - log('\nThe following TORCH artifacts will be removed:\n'); - for (const t of targets) { - log(` - ${t.label}`); - } - if (hasHostScripts) { - log(' - torch:* scripts from package.json'); - } - log(' - torch-lock npm package (via npm uninstall)'); - log(''); - - // Confirm unless --force - if (!force) { - let confirmed; - - if (mockAnswers) { - confirmed = mockAnswers.confirm; - } else { - const rl = readline.createInterface({ input, output }); - try { - const answer = await rl.question('Proceed with removal? (yes/no): '); - confirmed = answer.trim().toLowerCase() === 'yes'; - } finally { - rl.close(); - } - } - - if (!confirmed) { - log('Removal cancelled.'); - return; - } - } - - log('\nRemoving TORCH...\n'); - - // 1. Remove directories and files - for (const t of targets) { - removeIfExists(t.path, t.label, log); - } - - // 2. Clean up empty src/ directory if proposals was the only thing in it - const srcDir = path.join(cwd, 'src'); - if (fs.existsSync(srcDir)) { - try { - const entries = fs.readdirSync(srcDir); - if (entries.length === 0) { - fs.rmdirSync(srcDir); - log(' Removed empty src/ directory'); - } - } catch (_e) { /* leave it if not empty or permission error */ } - } - - // 3. Remove host package.json scripts - if (hasHostScripts) { - removeHostScripts(cwd, log); - } - - // 4. Uninstall the npm package - log('\n Running npm uninstall torch-lock...'); - try { - const { execSync } = await import('node:child_process'); - execSync('npm uninstall torch-lock', { cwd, stdio: 'pipe' }); - log(' Uninstalled torch-lock package.'); - } catch (e) { - log(` Warning: npm uninstall torch-lock failed: ${e.message}`); - log(' You may need to run "npm uninstall torch-lock" manually.'); - } - - log('\nTORCH has been completely removed from this project.'); - log('If you used TORCH environment variables (NOSTR_LOCK_*, TORCH_*),'); - log('remember to remove them from your shell profile or CI configuration.'); -} - export function cmdUpdate(force = false, cwd = process.cwd()) { // Update logic needs to know WHERE torch is installed. // We can look for torch directory? Or assume 'torch'? diff --git a/src/test_logs/TEST_LOG_2026-02-21T20-22-19Z.md b/src/test_logs/TEST_LOG_2026-02-21T20-22-19Z.md new file mode 100644 index 0000000..59fdb6f --- /dev/null +++ b/src/test_logs/TEST_LOG_2026-02-21T20-22-19Z.md @@ -0,0 +1,15 @@ +--- +agent: refactor-agent +cadence: weekly +session: 2026-02-21T20:22:19Z +run-start: 2026-02-21T20:22:19Z +prompt: src/prompts/weekly/refactor-agent.md +--- + +# Test Log + +- **Command**: `npm test` +- **Result**: Passed (122 tests). + +- **Command**: `node --test test/cmd-remove.test.mjs` +- **Result**: Passed. diff --git a/src/todo/TODO_2026-02-21T20-22-19Z.md b/src/todo/TODO_2026-02-21T20-22-19Z.md new file mode 100644 index 0000000..47e0e34 --- /dev/null +++ b/src/todo/TODO_2026-02-21T20-22-19Z.md @@ -0,0 +1,16 @@ +--- +agent: refactor-agent +cadence: weekly +session: 2026-02-21T20:22:19Z +run-start: 2026-02-21T20:22:19Z +prompt: src/prompts/weekly/refactor-agent.md +--- + +# Todo + +## Pending Tasks +- None. + +## Completed Tasks +- [x] Extract `cmdRemove`. +- [x] Update tests. diff --git a/task-logs/weekly/2026-02-14T05-21-35Z__event-schema-agent__failed.md b/task-logs/weekly/2026-02-14T05-21-35Z__event-schema-agent__failed.md deleted file mode 100644 index 720ab47..0000000 --- a/task-logs/weekly/2026-02-14T05-21-35Z__event-schema-agent__failed.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -agent: event-schema-agent -status: failed -date: 2026-02-14 ---- - -# Preflight Check Failed - -The `event-schema-agent` requires `src/lib/eventSchemas.js` as the canonical source of truth for event builders and sanitizers. This file does not exist in the `torch-lock` repository. - -## Findings - -1. **Missing Source of Truth**: `src/lib/eventSchemas.js` is referenced in the agent prompt but is absent from the codebase. -2. **Runtime Construction**: Event construction in this repository currently happens inline (e.g., in `src/nostr-lock.mjs`), which violates the pattern of using shared, canonical builders. -3. **Action**: Aborting execution. No validator harness can be generated without the canonical schemas. - -## Recommendations - -- Create `src/lib/eventSchemas.js` to centralize event construction (e.g., for the lock event). -- Update `event-schema-agent` prompt or repository documentation to reflect the actual location of schemas if they exist elsewhere. diff --git a/task-logs/weekly/2026-02-14T05-24-15Z__event-schema-agent__failed.md b/task-logs/weekly/2026-02-14T05-24-15Z__event-schema-agent__failed.md deleted file mode 100644 index 3676084..0000000 --- a/task-logs/weekly/2026-02-14T05-24-15Z__event-schema-agent__failed.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -agent: event-schema-agent -status: failed ---- -# Weekly Scheduler Run Failed - -reason: Lock backend error - -## Details -- cadence: weekly -- excluded: [] -- selected_agent: event-schema-agent -- lock_command: `AGENT_PLATFORM=codex npm run lock:lock -- --agent event-schema-agent --cadence weekly` -- lock_exit_code: 2 diff --git a/task-logs/weekly/2026-02-14T13-02-04Z__interop-agent__failed.md b/task-logs/weekly/2026-02-14T13-02-04Z__interop-agent__failed.md deleted file mode 100644 index a489f59..0000000 --- a/task-logs/weekly/2026-02-14T13-02-04Z__interop-agent__failed.md +++ /dev/null @@ -1 +0,0 @@ -Preflight check failed: Required files `src/lib/eventSchemas.js`, `src/lib/clientFacade.js` (or defaultClient.js), and `js/dmDecryptor.js` are missing from the repository. This agent appears to be misconfigured for the current repository structure. diff --git a/task-logs/weekly/2026-02-14T23-12-39Z__prompt-maintenance-agent__failed.md b/task-logs/weekly/2026-02-14T23-12-39Z__prompt-maintenance-agent__failed.md deleted file mode 100644 index ea92d37..0000000 --- a/task-logs/weekly/2026-02-14T23-12-39Z__prompt-maintenance-agent__failed.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -agent: prompt-maintenance-agent -status: failed ---- -# Weekly Scheduler Run Failed - -reason: Lock backend error - -## Details -- cadence: weekly -- log_dir: task-logs/weekly/ -- branch_prefix: agents/weekly/ -- prompt_dir: src/prompts/weekly/ -- excluded: [bug-reproducer-agent, changelog-agent, dead-code-agent, feature-proposer-agent, frontend-console-debug-agent, fuzz-agent, perf-deepdive-agent, perf-optimization-agent, pr-review-agent] -- selected_agent: prompt-maintenance-agent -- lock_command: `AGENT_PLATFORM=codex npm run lock:lock -- --agent prompt-maintenance-agent --cadence weekly` -- lock_exit_code: 2 -- next_action: Retry scheduler cycle after relay connectivity is restored. diff --git a/task-logs/weekly/2026-02-19T00-58-49Z__perf-optimization-agent__failed.md b/task-logs/weekly/2026-02-19T00-58-49Z__perf-optimization-agent__failed.md deleted file mode 100644 index 855cf33..0000000 --- a/task-logs/weekly/2026-02-19T00-58-49Z__perf-optimization-agent__failed.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -agent: perf-optimization-agent -cadence: weekly -platform: claude -status: failed -timestamp: "2026-02-19T00:58:49Z" -failure_class: backend_unavailable -failure_category: lock_backend_error ---- - -# Task Log — Failed - -## Reason - -Lock backend error - -## Detail - -Lock acquisition for `perf-optimization-agent` (weekly cadence) failed with exit code 2. -All Nostr relays returned `permanent_validation_error`: "Received network error or non-101 status code." -WebSocket connectivity to the relay pool is unavailable in this execution environment. - -No prompt was executed. `lock:complete` was NOT published. - -## Scheduler State - -- **Selected agent:** perf-optimization-agent -- **Selection algorithm:** - - Roster source: `src/prompts/roster.json` (weekly key) - - Latest log file: `2026-02-18T19-54-03Z__perf-deepdive-agent__completed.md` - - Previous agent: `perf-deepdive-agent` (from filename convention, index 6) - - start_index: `(6 + 1) mod 21 = 7` - - Candidate at index 7: `perf-optimization-agent` — not in excluded set → selected -- **Excluded set (from lock:check:weekly):** bug-reproducer-agent, changelog-agent, dead-code-agent, feature-proposer-agent, frontend-console-debug-agent, fuzz-agent, perf-deepdive-agent, test-coverage-agent, ui-ux-agent, weekly-synthesis-agent - -## Lock Failure Metadata - -- **lock_command:** `AGENT_PLATFORM=claude npm run lock:lock -- --agent perf-optimization-agent --cadence weekly` -- **backend_category:** relay_publish_non_retryable -- **lock_correlation_id:** c5e5d9fc-85f5-41ca-b4d2-3671f815d157 -- **lock_attempt_id:** 5403bebc-a9f5-4a30-a3dd-6df7af4ec213 -- **successCount:** 0 / 3 -- **requiredSuccesses:** 1 -- **relay_list:** - - wss://nos.lol (publish:primary, reason=permanent_validation_error) - - wss://relay.damus.io (publish:primary, reason=permanent_validation_error) - - wss://relay.primal.net (publish:primary, reason=permanent_validation_error) -- **lock_stderr_excerpt:** "Failed relay publish quorum in publish phase: 0/3 successful (required=1, timeout=15000ms, attempts=4)" - -## Retry Guidance - -1. Verify relay connectivity: `npm run lock:health -- --cadence weekly` -2. Retry lock acquisition: `AGENT_PLATFORM=claude npm run lock:lock -- --agent perf-optimization-agent --cadence weekly` -3. If all relays remain unhealthy, consult `docs/agent-handoffs/incidents/` for relay remediation guidance. -4. See incident runbook: `docs/agent-handoffs/learnings/2026-02-15-relay-health-preflight-job.md` - -## Prompt Not Executed - -The selected prompt `src/prompts/weekly/perf-optimization-agent.md` was NOT executed. diff --git a/task-logs/weekly/2026-02-19T05-06-16Z__pr-review-agent__failed.md b/task-logs/weekly/2026-02-19T05-06-16Z__pr-review-agent__failed.md deleted file mode 100644 index 12c3207..0000000 --- a/task-logs/weekly/2026-02-19T05-06-16Z__pr-review-agent__failed.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -agent: pr-review-agent -cadence: weekly -run_start: 2026-02-19T05:06:16Z -platform: linux -failure_reason: Validation failed (Verify: 1, Lint: 0) ---- -Run failed. diff --git a/task-logs/weekly/2026-02-21T20-29-33Z__refactor-agent__completed.md b/task-logs/weekly/2026-02-21T20-29-33Z__refactor-agent__completed.md new file mode 100644 index 0000000..ee4f3ce --- /dev/null +++ b/task-logs/weekly/2026-02-21T20-29-33Z__refactor-agent__completed.md @@ -0,0 +1,7 @@ +--- +agent: refactor-agent +cadence: weekly +platform: codex +--- + +Run completed successfully. \ No newline at end of file diff --git a/test/ops-remove.test.mjs b/test/cmd-remove.test.mjs similarity index 98% rename from test/ops-remove.test.mjs rename to test/cmd-remove.test.mjs index 1a79ad9..cb1aec6 100644 --- a/test/ops-remove.test.mjs +++ b/test/cmd-remove.test.mjs @@ -2,7 +2,8 @@ import { test, after } from 'node:test'; import assert from 'node:assert'; import fs from 'node:fs'; import path from 'node:path'; -import { cmdInit, cmdRemove } from '../src/ops.mjs'; +import { cmdInit } from '../src/ops.mjs'; +import { cmdRemove } from '../src/cmd-remove.mjs'; const MOCK_CONFIG = { installDir: 'torch',