New test files (83 tests): - src/agent-identity.test.ts — resolveAgentIdentity across locales/genders - src/env.test.ts — readEnvFile parsing, quoting, edge cases - src/jail-registry.test.ts — getJailIp with/without env override - src/local-hosts.test.ts — block markers, entries, render, upsert - src/mount-security.test.ts — validateMount allowlist enforcement - src/transcription.test.ts — initTranscription + transcribeAudio with mocked OpenAI setup/ TypeScript audit (tsconfig.setup.json): - agent-jails: JAILS value serialised to JSON string for emitStatus - environment.test: use import type for pg.Pool type cast - onboarding: wrap showProfileMenu in normalizePiTuiProfile - preflight.test: fix process.exit mock type + typed call array casts - sanoid: execSync → spawnSync for multi-arg zfs invocation - skills-memory: bracket access for legacy chunking_version field - upstream: pass process.cwd() to isGitRepo() - verify: import StripeKeyMode type, annotate stripeKeyMode variable Full suite: 69 files, 1162 tests passing; tsc --noEmit clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --- Build: pass | Tests: pass — Tests 1162 passed (1162) --- Build: pass | Tests: pass — Tests 1162 passed (1162)
109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
/**
|
|
* Step: upstream — Configure NanoClaw upstream remote for tracking improvements.
|
|
*
|
|
* Toggle: NANOCLAW_UPSTREAM_ENABLED in .env
|
|
* Remote: nanoclaw → github.com/qwibitai/nanoclaw
|
|
*
|
|
* This step is optional. When enabled, the agent can check for upstream
|
|
* improvements via the check_upstream_updates MCP tool. The operator
|
|
* decides what to apply — nothing is auto-merged.
|
|
*/
|
|
import { logger } from '../src/logger.js';
|
|
import {
|
|
addRemote,
|
|
fetchRemote,
|
|
getUpstreamConfig,
|
|
isGitRepo,
|
|
remoteExists,
|
|
writeEnvFlag,
|
|
} from '../src/upstream/git.js';
|
|
import { getUpstreamStatus } from '../src/upstream/status.js';
|
|
import { emitStatus } from './status.js';
|
|
|
|
function statusReport(fetch: boolean): void {
|
|
const status = getUpstreamStatus({ repoDir: process.cwd() });
|
|
const divergence = status.commits.length
|
|
? status.commits.map((commit) => `${commit.hash.slice(0, 7)} ${commit.subject}`).join(' | ')
|
|
: (fetch ? 'up-to-date' : 'not-fetched');
|
|
|
|
emitStatus('SETUP_UPSTREAM', {
|
|
NANOCLAW_REMOTE: status.remoteConfigured,
|
|
NANOCLAW_REMOTE_URL: status.remoteUrl,
|
|
DIVERGENCE: divergence,
|
|
ENABLED: status.enabled,
|
|
AHEAD_COUNT: status.aheadCount,
|
|
BEHIND_COUNT: status.behindCount,
|
|
STATUS: status.status,
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
}
|
|
|
|
export async function run(args: string[]): Promise<void> {
|
|
logger.info('Upstream configuration step');
|
|
|
|
if (!isGitRepo(process.cwd())) {
|
|
emitStatus('SETUP_UPSTREAM', {
|
|
STATUS: 'failed',
|
|
ERROR: 'not_a_git_repo',
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
process.exit(1);
|
|
}
|
|
|
|
const doEnable = args.includes('--enable');
|
|
const doDisable = args.includes('--disable');
|
|
const doFetch = args.includes('--fetch');
|
|
const doStatus = args.includes('--status') || (!doEnable && !doDisable && !doFetch);
|
|
|
|
if (doStatus) {
|
|
statusReport(false);
|
|
return;
|
|
}
|
|
|
|
if (doDisable) {
|
|
writeEnvFlag(process.cwd(), 'NANOCLAW_UPSTREAM_ENABLED', false);
|
|
logger.info('NanoClaw upstream tracking disabled');
|
|
emitStatus('SETUP_UPSTREAM', {
|
|
NANOCLAW_REMOTE: remoteExists(process.cwd(), 'nanoclaw'),
|
|
ENABLED: false,
|
|
STATUS: 'disabled',
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (doEnable) {
|
|
const config = getUpstreamConfig({ repoDir: process.cwd() });
|
|
|
|
if (!remoteExists(config.repoDir, config.remoteName)) {
|
|
logger.info({ url: config.remoteUrl }, 'Adding NanoClaw remote');
|
|
addRemote(config.repoDir, config.remoteName, config.remoteUrl);
|
|
logger.info('NanoClaw remote added');
|
|
} else {
|
|
logger.info('NanoClaw remote already configured');
|
|
}
|
|
|
|
writeEnvFlag(config.repoDir, 'NANOCLAW_UPSTREAM_ENABLED', true);
|
|
logger.info('Fetching NanoClaw upstream (no-tags, read-only)...');
|
|
fetchRemote(config.repoDir, config.remoteName);
|
|
statusReport(true);
|
|
return;
|
|
}
|
|
|
|
if (doFetch) {
|
|
const config = getUpstreamConfig({ repoDir: process.cwd() });
|
|
|
|
if (!remoteExists(config.repoDir, config.remoteName)) {
|
|
emitStatus('SETUP_UPSTREAM', {
|
|
STATUS: 'failed',
|
|
ERROR: 'remote_not_configured — run with --enable first',
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
process.exit(1);
|
|
}
|
|
logger.info('Fetching NanoClaw upstream (no-tags, read-only)...');
|
|
fetchRemote(config.repoDir, config.remoteName);
|
|
statusReport(true);
|
|
return;
|
|
}
|
|
}
|