chore(ai): doc src/ops.mjs (docs-code-investigator)

- Added JSDoc to src/ops.mjs
- Created docs/ops-overview.md
- Updated run artifacts

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-22 18:23:40 +00:00
1 parent b221908637
commit 4e244dd847
8 files changed
+343 -15

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
# Ops Module Overview (`src/ops.mjs`)
## What this module does
This module implements the core CLI operations for the Torch agent system: `init` and `update`. It handles the scaffolding of the agent environment, including directory structure creation, asset copying, configuration generation, and upgrades.
## Initialization Flow (`cmdInit`)
1. **Resolve Configuration**:
- Queries user for install directory, namespace, hashtag, and relays.
- Validates inputs (prevents path injection).
2. **Ensure Directories**:
- Creates `torch/prompts/`, `src/proposals/`, `.torch/prompt-history/`.
3. **Install Assets**:
- Copies app directories (`src`, `bin`, `dashboard`, etc.).
- Copies static files (`META_PROMPTS.md`, scheduler docs).
- Copies prompts (`daily/`, `weekly/`).
4. **Configure**:
- Generates `torch-config.json`.
- Updates `.gitignore` to exclude `node_modules`.
- Generates `TORCH_DASHBOARD.md`.
5. **Inject Scripts**:
- Adds `torch:*` scripts to the host `package.json` if installed in a subdirectory.
## Update Flow (`cmdUpdate`)
1. **Detect Installation**:
- Finds the existing `torch` directory.
2. **Backup**:
- Creates a timestamped backup in `torch/_backups/`.
3. **Update App**:
- Overwrites application code (`src`, `bin`, etc.).
- Overwrites static files.
4. **Update Prompts**:
- Adds new prompts from the package.
- Preserves existing prompts (unless `--force` is used).
5. **Preserve Roster**:
- `roster.json` is preserved to avoid resetting rotation (unless `--force` is used).
## Public API
### `cmdInit(force, cwd, mockAnswers)`
Initializes a new Torch environment.
- `force`: Boolean, overwrite existing directory if not empty.
- `cwd`: Current working directory.
- `mockAnswers`: Optional object for testing (bypasses interactive prompts).
### `cmdUpdate(force, cwd)`
Updates an existing Torch environment.
- `force`: Boolean, overwrite modified prompts/roster.
- `cwd`: Current working directory.
## Key Invariants
- **Safe Installation**: `validateInstallDir` ensures the target directory name is safe (alphanumeric + safe chars).
- **Non-Destructive Defaults**: `init` fails if directory is not empty (unless forced). `update` preserves user data (prompts, roster, config) by default.
- **Backup First**: `update` always creates a full backup before modifying files.
## When to change
- When adding new CLI commands or workflows.
- When changing the directory structure or asset layout.
- When updating the default configuration logic or `torch-config.json` schema.
@@ -0,0 +1,13 @@
# Memory Update — docs-code-investigator — 2026-02-22
## Key findings
- `src/ops.mjs` handles `torch-lock init` and `update` logic, including directory scaffolding and config generation.
- The `update` logic preserves user modifications to prompts and rosters unless `--force` is used.
- `src/ops.mjs` was previously undocumented, now fully JSDoc'd.
## Patterns / reusable knowledge
- When documenting CLI tools, a high-level "overview" document (like `docs/ops-overview.md`) is valuable for understanding the flow beyond just function signatures.
- `src/ops.mjs` uses `src/prompts/` as the source of truth for assets, which is important for understanding how the agent system self-updates.
## Warnings / gotchas
- `cmdInit` and `cmdUpdate` interact with the filesystem extensively; ensure backups are verified (logic exists in `cmdUpdate`) before critical updates.
@@ -0,0 +1,29 @@
---
agent: docs-code-investigator
cadence: daily
run-start: 2026-02-22T18:16:24Z
---
# Context - Docs Code Investigator - 2026-02-22
Executed prompt: `src/prompts/daily/docs-code-investigator.md`
## Goal
To analyze and document `src/ops.mjs`, ensuring its behavior and public API are clear.
## Scope
- `src/ops.mjs`: Core CLI operations (`init`, `update`).
- `docs/ops-overview.md`: High-level overview.
## Constraints
- No behavioral changes.
- Non-invasive documentation only.
## Selection
- **Target File:** `src/ops.mjs`
- **Reason:** Large file (567 lines), core logic, lacked JSDoc.
- **Plan:**
1. Analyze `src/ops.mjs` flow.
2. Add JSDoc to all functions.
3. Add file-level flow comment.
4. Create `docs/ops-overview.md`.
@@ -0,0 +1,15 @@
---
agent: docs-code-investigator
cadence: daily
run-start: 2026-02-22T18:16:24Z
---
# Decisions - Docs Code Investigator - 2026-02-22
Executed prompt: `src/prompts/daily/docs-code-investigator.md`
## Decision 1: Document `src/ops.mjs`
- **Context:** `src/ops.mjs` is a large file (567 LOC) handling critical CLI operations (`init`, `update`) but lacked comprehensive JSDoc.
- **Decision:** Selected `src/ops.mjs` for documentation.
- **Rationale:** High-value target for improving maintainability and understanding of the deployment/update process.
- **Alternatives:** `src/services/memory/index.js` was also a candidate but `ops.mjs` seemed more central to current operations.
+164 -15
View File
@@ -6,14 +6,39 @@ import readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';
import { DEFAULT_RELAYS } from './constants.mjs';
import { ensureDir } from './utils.mjs';
// Re-export cmdRemove for CLI consumption
export { cmdRemove } from './cmd-remove.mjs';
/**
* Torch Operations Module
*
* Handles the initialization (`torch-lock init`) and update (`torch-lock update`)
* workflows for scaffolding the Torch agent environment.
*
* Flow (Init):
* 1. Resolve configuration (interactive or mock).
* 2. Ensure installation directories exist.
* 3. Install application assets (src, bin, scripts, etc.).
* 4. Install Torch-specific assets (roster, prompts).
* 5. Configure `torch-config.json` and `.gitignore`.
* 6. Generate dashboard link.
* 7. Inject convenience scripts into host `package.json`.
*
* Flow (Update):
* 1. Detect installation directory.
* 2. Create a backup of the current installation.
* 3. Update application directories/files (overwrite).
* 4. Update static files (overwrite).
* 5. Update prompts (add new, preserve existing).
*/
const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
// Source paths (in the package)
/** Source directory for prompts within the package. */
const SRC_PROMPTS_DIR = path.join(PKG_ROOT, 'src', 'prompts');
// Files to treat as "Static" (always overwrite on update, with transformations)
/** Files to treat as "Static" (always overwrite on update, with transformations). */
const STATIC_FILES = [
'META_PROMPTS.md',
'scheduler-flow.md',
@@ -21,13 +46,22 @@ const STATIC_FILES = [
'weekly-scheduler.md',
];
// Directories containing "Evolving" files (copy if missing, preserve if present)
/** Directories containing "Evolving" files (copy if missing, preserve if present). */
const EVOLVING_DIRS = ['daily', 'weekly'];
// New constants for full application install
/** Directories to sync from package root to install directory. */
const APP_DIRS = ['src', 'bin', 'dashboard', 'landing', 'assets', 'scripts'];
/** Individual files to sync from package root to install directory. */
const APP_FILES = ['package.json', 'build.mjs', 'README.md', 'torch-config.example.json', 'TORCH.md'];
/**
* Resolves the absolute paths for the installation.
*
* @param {string} root - The current working directory (project root).
* @param {string} installDirName - The name of the installation directory (e.g., 'torch' or '.').
* @returns {{root: string, torchDir: string, promptsDir: string, roster: string}} - Resolved paths.
*/
function getPaths(root, installDirName) {
const torchDir = path.resolve(root, installDirName);
return {
@@ -38,19 +72,29 @@ function getPaths(root, installDirName) {
};
}
/**
* Recursively copies a directory.
*
* @param {string} src - Source directory path.
* @param {string} dest - Destination directory path.
*/
function copyDir(src, dest) {
if (fs.existsSync(src)) {
fs.cpSync(src, dest, { recursive: true });
}
}
/**
* Transforms content by replacing source paths with installed paths.
*
* @param {string} content - The original file content.
* @param {string} installDirName - The name of the installation directory.
* @returns {string} - The transformed content.
*/
function transformContent(content, installDirName) {
// Replace source paths with user paths
// We assume the user is running from root, so 'src/prompts/daily/' becomes 'torch/prompts/daily/'
// If installDirName is different, we should use that.
// Note: These replacements are somewhat fragile regexes.
// We'll replace 'src/' with 'installDirName/' essentially?
// The original code replaced 'src/prompts/' with 'torch/prompts/'.
// If installDirName is '.', we want 'prompts/daily/'.
// If installDirName is 'torch', we want 'torch/prompts/daily/'.
@@ -65,6 +109,16 @@ function transformContent(content, installDirName) {
.replace(/TORCH\.md/g, `${prefix}TORCH.md`);
}
/**
* Copies a single file, optionally transforming content and overwriting.
*
* @param {string} src - Source file path.
* @param {string} dest - Destination file path.
* @param {boolean} [transform=false] - Whether to apply content transformations.
* @param {boolean} [overwrite=true] - Whether to overwrite existing files.
* @param {string} [installDirName='torch'] - The installation directory name (used for transform).
* @returns {boolean} - True if copied/overwritten, false if skipped or source missing.
*/
function copyFile(src, dest, transform = false, overwrite = true, installDirName = 'torch') {
if (fs.existsSync(dest) && !overwrite) {
return false; // Skipped
@@ -77,6 +131,12 @@ function copyFile(src, dest, transform = false, overwrite = true, installDirName
return true; // Copied/Overwritten
}
/**
* Syncs application directories from package to install location.
*
* @param {string} torchDir - The target installation directory.
* @param {'Copied'|'Updated'} [verb='Copied'] - Verb for logging.
*/
function syncAppDirectories(torchDir, verb = 'Copied') {
console.log(`${verb === 'Copied' ? 'Copying' : 'Updating'} application directories...`);
for (const dir of APP_DIRS) {
@@ -89,6 +149,13 @@ function syncAppDirectories(torchDir, verb = 'Copied') {
}
}
/**
* Syncs application files from package to install location.
*
* @param {string} torchDir - The target installation directory.
* @param {string} installDir - The relative installation path name.
* @param {'Copied'|'Updated'} [verb='Copied'] - Verb for logging.
*/
function syncAppFiles(torchDir, installDir, verb = 'Copied') {
console.log(`${verb === 'Copied' ? 'Copying' : 'Updating'} application files...`);
for (const file of APP_FILES) {
@@ -112,6 +179,12 @@ function syncAppFiles(torchDir, installDir, verb = 'Copied') {
}
}
/**
* Interactively queries the user for initialization parameters.
*
* @param {string} cwd - Current working directory.
* @returns {Promise<{installDir: string, namespace: string, hashtag: string, relays: string[]}>} - User configuration.
*/
async function interactiveInit(cwd) {
const rl = readline.createInterface({ input, output });
const currentDirName = path.basename(cwd);
@@ -153,6 +226,12 @@ async function interactiveInit(cwd) {
}
}
/**
* Validates the installation directory name for safety.
*
* @param {string} dir - The directory name to validate.
* @throws {Error} If the directory name contains invalid characters.
*/
function validateInstallDir(dir) {
if (dir === '.') return;
@@ -163,6 +242,13 @@ function validateInstallDir(dir) {
}
}
/**
* Resolves the configuration either interactively or from mock answers.
*
* @param {string} cwd - Current working directory.
* @param {Object} [mockAnswers] - Optional mock answers for testing.
* @returns {Promise<Object>} - Resolved configuration object.
*/
async function resolveConfiguration(cwd, mockAnswers) {
let config;
if (mockAnswers) {
@@ -175,6 +261,14 @@ async function resolveConfiguration(cwd, mockAnswers) {
return config;
}
/**
* Ensures the necessary directories exist for installation.
*
* @param {Object} paths - Path object from `getPaths`.
* @param {boolean} force - Whether to force overwrite/creation.
* @param {string} installDir - Installation directory name.
* @throws {Error} If directory exists and is not empty (unless forced).
*/
function ensureInstallDirectory(paths, force, installDir) {
if (fs.existsSync(paths.torchDir) && !force) {
const entries = fs.readdirSync(paths.torchDir);
@@ -186,18 +280,16 @@ function ensureInstallDirectory(paths, force, installDir) {
ensureDir(paths.promptsDir);
// Ensure governance directories
// We assume standard structure src/proposals and .torch/prompt-history
// even if installed in a subdirectory, these are usually repo-level.
// But if installed in 'torch', maybe they should be in 'torch/src/proposals'?
// For now, we follow the pattern that prompts are managed where the scheduler expects them.
// If we are in this repo, it's src/prompts.
// If torch is initializing a new repo, it might put prompts in installDir/prompts.
// However, governance service currently hardcodes 'src/proposals'.
// So we ensure 'src/proposals' relative to root.
ensureDir(path.join(paths.root, 'src', 'proposals'));
ensureDir(path.join(paths.root, '.torch', 'prompt-history'));
}
/**
* Orchestrates the installation of application assets.
*
* @param {string} torchDir - Target directory.
* @param {string} installDir - Install directory name.
*/
function installAppAssets(torchDir, installDir) {
// 1. Copy App Directories
syncAppDirectories(torchDir, 'Copied');
@@ -206,6 +298,12 @@ function installAppAssets(torchDir, installDir) {
syncAppFiles(torchDir, installDir, 'Copied');
}
/**
* Orchestrates the installation of Torch-specific assets (prompts, roster).
*
* @param {Object} paths - Paths object.
* @param {string} installDir - Install directory name.
*/
function installTorchAssets(paths, installDir) {
// 3. Copy Roster
const srcRoster = path.join(SRC_PROMPTS_DIR, 'roster.json');
@@ -242,6 +340,16 @@ function installTorchAssets(paths, installDir) {
}
}
/**
* Creates or updates the `torch-config.json` file.
*
* @param {string} cwd - Current working directory.
* @param {Object} paths - Paths object.
* @param {string} installDir - Install directory name.
* @param {string} namespace - Nostr namespace.
* @param {string[]} relays - List of relays.
* @param {string} hashtag - Dashboard hashtag.
*/
function configureTorch(cwd, paths, installDir, namespace, relays, hashtag) {
// 6. Create/Update torch-config.json
const configPath = path.join(paths.root, 'torch-config.json');
@@ -327,6 +435,11 @@ function configureTorch(cwd, paths, installDir, namespace, relays, hashtag) {
console.log(`Saved configuration to ${path.relative(cwd, configPath)}`);
}
/**
* Ensures `node_modules` is ignored in the target directory's `.gitignore`.
*
* @param {string} targetDir - The directory to check/update.
*/
function ensureGitIgnore(targetDir) {
const gitIgnorePath = path.join(targetDir, '.gitignore');
let content = '';
@@ -350,6 +463,12 @@ function ensureGitIgnore(targetDir) {
}
}
/**
* Injects torch scripts into the host `package.json` if installed in a subdirectory.
*
* @param {Object} paths - Paths object.
* @param {string} installDir - Install directory name.
*/
function injectHostScriptsIfNeeded(paths, installDir) {
// 7. Inject Scripts into Host Package.json
// If we are NOT installing to '.', the host package.json is in paths.root
@@ -358,6 +477,14 @@ function injectHostScriptsIfNeeded(paths, installDir) {
}
}
/**
* Main entry point for `torch-lock init`.
*
* @param {boolean} [force=false] - Force overwrite.
* @param {string} [cwd=process.cwd()] - Working directory.
* @param {Object} [mockAnswers=null] - Mock answers for testing.
* @returns {Promise<void>}
*/
export async function cmdInit(force = false, cwd = process.cwd(), mockAnswers = null) {
const config = await resolveConfiguration(cwd, mockAnswers);
const { installDir, namespace, relays } = config;
@@ -387,6 +514,15 @@ export async function cmdInit(force = false, cwd = process.cwd(), mockAnswers =
console.log(dashboardUrl);
}
/**
* Generates the `TORCH_DASHBOARD.md` file with a direct link to the dashboard.
*
* @param {Object} paths - Paths object.
* @param {string} namespace - Nostr namespace.
* @param {string[]} relays - List of relays.
* @param {string} hashtag - Dashboard hashtag.
* @returns {string} - The generated URL.
*/
function createDashboardLinkFile(paths, namespace, relays, hashtag) {
const encodedRelays = relays.map(r => encodeURIComponent(r)).join('%2C');
const dashboardUrl = `https://torch.thepr0m3th3an.net/dashboard/?hashtag=${hashtag}&namespace=${namespace}&relays=${encodedRelays}`;
@@ -413,6 +549,12 @@ To change these settings, edit \`torch-config.json\` in your project root.
return dashboardUrl;
}
/**
* Modifies the host `package.json` to include `torch:*` convenience scripts.
*
* @param {string} hostRoot - Path to the host project root.
* @param {string} installDirName - Installation directory name.
*/
function injectScriptsIntoHost(hostRoot, installDirName) {
const hostPkgPath = path.join(hostRoot, 'package.json');
if (!fs.existsSync(hostPkgPath)) {
@@ -454,6 +596,13 @@ function injectScriptsIntoHost(hostRoot, installDirName) {
}
}
/**
* Main entry point for `torch-lock update`.
*
* @param {boolean} [force=false] - Force overwrite.
* @param {string} [cwd=process.cwd()] - Working directory.
* @throws {Error} If torch installation is not found.
*/
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'?
@@ -0,0 +1,23 @@
---
agent: docs-code-investigator
cadence: daily
run-start: 2026-02-22T18:16:24Z
---
# Test Log - Docs Code Investigator - 2026-02-22
Executed prompt: `src/prompts/daily/docs-code-investigator.md`
## Verification Steps
### Linting
- Command: `npm run lint`
- Result: Passed (exit code 0). No errors.
### Unit Tests
- Command: `npm test`
- Result: Passed (exit code 0). 372 tests passed, 0 failures, 1 skipped.
### Manual Verification
- Command: Verify file existence
- Result: `docs/ops-overview.md` exists. `src/ops.mjs` modified.
+19
View File
@@ -0,0 +1,19 @@
---
agent: docs-code-investigator
cadence: daily
run-start: 2026-02-22T18:16:24Z
---
# TODO - Docs Code Investigator - 2026-02-22
Executed prompt: `src/prompts/daily/docs-code-investigator.md`
## Completed
- [x] Analyze `src/ops.mjs`.
- [x] Add JSDoc to `src/ops.mjs`.
- [x] Create `docs/ops-overview.md`.
- [x] Run `npm run lint`.
- [x] Run `npm test`.
## Pending
- [ ] Review `src/services/memory/index.js` for documentation improvements (future task).
@@ -0,0 +1,22 @@
---
agent: docs-code-investigator
platform: linux
---
# Task Completed
- **Agent:** docs-code-investigator
- **Cadence:** daily
- **Run Start:** 2026-02-22T18:16:24Z
- **Outcome:** Success
## Work Performed
1. Analyzed `src/ops.mjs` (567 LOC).
2. Added JSDoc to all functions in `src/ops.mjs`.
3. Created `docs/ops-overview.md` to document initialization and update flows.
4. Verified changes with `npm run lint` and `npm test`.
5. Recorded memory update.
## Learnings
- `src/ops.mjs` is the core CLI operation handler.
- Documenting it clarifies the `init` and `update` logic, including safety checks and backup procedures.