feat: random namespace generation in init

This commit updates the `npx torch-lock init` command to automatically generate a `torch-config.json` file if it doesn't already exist. The generated configuration includes a randomized `nostrLock.namespace` (e.g., `torch-a1b2c3d4`) to ensure unique discovery topics for each installation, preventing message collisions across different repositories.

- Modified `src/ops.mjs` to import `crypto` and implement the config generation logic in `cmdInit`.
- Added a test case in `test/ops.test.mjs` to verify the random namespace generation.
- Uses `torch-config.example.json` as a template.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-14 23:19:25 +00:00
1 parent 4690e4f2b2
commit 0f3fd3209f
2 files changed
+45

No files matched your search

+31
View File
@@ -1,6 +1,7 @@
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import crypto from 'node:crypto';
const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
@@ -112,6 +113,36 @@ export function cmdInit(force = false, cwd = process.cwd()) {
} }
} }
// 5. Create torch-config.json with random namespace if missing
const configPath = path.join(cwd, 'torch-config.json');
if (!fs.existsSync(configPath)) {
try {
const exampleConfigPath = path.join(PKG_ROOT, 'torch-config.example.json');
if (fs.existsSync(exampleConfigPath)) {
const exampleConfig = JSON.parse(fs.readFileSync(exampleConfigPath, 'utf8'));
// Generate random namespace
const randomSuffix = crypto.randomBytes(4).toString('hex');
const newNamespace = `torch-${randomSuffix}`;
if (exampleConfig.nostrLock) {
exampleConfig.nostrLock.namespace = newNamespace;
} else {
exampleConfig.nostrLock = { namespace: newNamespace };
}
fs.writeFileSync(configPath, JSON.stringify(exampleConfig, null, 2), 'utf8');
console.log(`Created ${path.relative(cwd, configPath)} with namespace "${newNamespace}"`);
} else {
console.warn(`Warning: Could not find ${exampleConfigPath} to generate torch-config.json`);
}
} catch (err) {
console.error(`Failed to create torch-config.json: ${err.message}`);
}
} else {
console.log(`Skipped ${path.relative(cwd, configPath)} (exists)`);
}
console.log('\nInitialization complete.'); console.log('\nInitialization complete.');
console.log('You can now customize the files in torch/ and torch/prompts/.'); console.log('You can now customize the files in torch/ and torch/prompts/.');
} }
+14
View File
@@ -121,3 +121,17 @@ test('torch-lock check respects local roster', async () => {
const result = JSON.parse(output); const result = JSON.parse(output);
assert.ok(result.available.includes('custom-agent-007'), 'Custom agent found in roster'); assert.ok(result.available.includes('custom-agent-007'), 'Custom agent found in roster');
}); });
test('cmdInit creates torch-config.json with random namespace', async () => {
const projectRoot = path.join(tempBase, 'project_config_init');
fs.mkdirSync(projectRoot, { recursive: true });
await cmdInit(false, projectRoot);
const configPath = path.join(projectRoot, 'torch-config.json');
assert.ok(fs.existsSync(configPath), 'torch-config.json created');
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
assert.match(config.nostrLock.namespace, /^torch-[a-f0-9]{8}$/, 'Namespace should match torch-<hex>');
assert.notStrictEqual(config.nostrLock.namespace, 'torch-example', 'Namespace should not be default');
});