clawdie-ai/setup/upstream.ts

110 lines
3.3 KiB
TypeScript
Raw Normal View History

/**
* 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;
}
}