wtt-connect 0.2.20 → 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/runner.js +107 -24
- package/src/store.js +16 -4
package/package.json
CHANGED
package/src/runner.js
CHANGED
|
@@ -2,6 +2,7 @@ import { WTTClient } from './wtt-client.js';
|
|
|
2
2
|
import { execFile } from 'node:child_process';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import fsp from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
5
6
|
import path from 'node:path';
|
|
6
7
|
import { promisify } from 'node:util';
|
|
7
8
|
import { WTTApi } from './wtt-api.js';
|
|
@@ -572,11 +573,11 @@ function parseUpgradeArgs(argsText = '') {
|
|
|
572
573
|
}
|
|
573
574
|
|
|
574
575
|
async function upgradeToolchain(config, targets) {
|
|
575
|
-
const
|
|
576
|
-
if (targets.includes('wtt-connect'))
|
|
577
|
-
if (targets.includes('codex'))
|
|
578
|
-
if (targets.includes('claude-code'))
|
|
579
|
-
if (!
|
|
576
|
+
const packageSpecs = [];
|
|
577
|
+
if (targets.includes('wtt-connect')) packageSpecs.push({ target: 'wtt-connect', spec: 'wtt-connect@latest' });
|
|
578
|
+
if (targets.includes('codex')) packageSpecs.push({ target: 'codex', spec: '@openai/codex@latest' });
|
|
579
|
+
if (targets.includes('claude-code')) packageSpecs.push({ target: 'claude-code', spec: '@anthropic-ai/claude-code@latest' });
|
|
580
|
+
if (!packageSpecs.length) return { message: upgradeHelp(), summary: {} };
|
|
580
581
|
|
|
581
582
|
const prefix = await resolveNpmPrefix(config);
|
|
582
583
|
const cache = process.env.NPM_CONFIG_CACHE
|
|
@@ -595,27 +596,29 @@ async function upgradeToolchain(config, targets) {
|
|
|
595
596
|
npm_config_cache: cache,
|
|
596
597
|
npm_config_nodedir: process.env.npm_config_nodedir || '/usr/local',
|
|
597
598
|
};
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
599
|
+
const installOutputs = [];
|
|
600
|
+
for (const pkg of packageSpecs) {
|
|
601
|
+
try {
|
|
602
|
+
const install = await installNpmGlobal(config, pkg.spec, { prefix, cache, registry, env });
|
|
603
|
+
installOutputs.push({ spec: pkg.spec, method: 'npm', stdout: install.stdout, stderr: install.stderr });
|
|
604
|
+
} catch (err) {
|
|
605
|
+
if (pkg.target !== 'wtt-connect') throw err;
|
|
606
|
+
const fallback = await installWttConnectFromRegistry(prefix, registry);
|
|
607
|
+
installOutputs.push({
|
|
608
|
+
spec: pkg.spec,
|
|
609
|
+
method: 'registry-tarball',
|
|
610
|
+
stdout: fallback.stdout,
|
|
611
|
+
stderr: `npm install failed; used registry tarball fallback.\n${err.stderr || err.message || err}`,
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
613
615
|
const after = await toolVersions(config, prefix);
|
|
614
616
|
const lines = [
|
|
615
617
|
'Toolchain upgrade completed.',
|
|
616
618
|
`- npm prefix: ${prefix}`,
|
|
617
619
|
`- npm cache: ${cache}`,
|
|
618
|
-
`- packages: ${
|
|
620
|
+
`- packages: ${packageSpecs.map((pkg) => pkg.spec).join(', ')}`,
|
|
621
|
+
`- install methods: ${installOutputs.map((out) => `${out.spec}:${out.method}`).join(', ')}`,
|
|
619
622
|
'',
|
|
620
623
|
'Versions:',
|
|
621
624
|
`- wtt-connect: ${before.wtt_connect || 'unknown'} -> ${after.wtt_connect || 'unknown'}`,
|
|
@@ -625,14 +628,18 @@ async function upgradeToolchain(config, targets) {
|
|
|
625
628
|
if (targets.includes('wtt-connect')) {
|
|
626
629
|
lines.push('', 'Note: `wtt-connect` was upgraded on disk. Restart this agent process to run the new connector version; Claude Code and Codex upgrades are used on the next run because they are spawned per request.');
|
|
627
630
|
}
|
|
628
|
-
const
|
|
629
|
-
|
|
631
|
+
const outputText = installOutputs
|
|
632
|
+
.map((out) => [`[${out.spec} via ${out.method}]`, out.stdout, out.stderr].filter(Boolean).join('\n'))
|
|
633
|
+
.join('\n\n')
|
|
634
|
+
.trim();
|
|
635
|
+
if (outputText) lines.push('', 'install output:', truncate(outputText, 4000));
|
|
630
636
|
return {
|
|
631
637
|
message: lines.join('\n'),
|
|
632
638
|
summary: {
|
|
633
639
|
prefix,
|
|
634
640
|
cache,
|
|
635
|
-
packages:
|
|
641
|
+
packages: packageSpecs.map((pkg) => pkg.spec),
|
|
642
|
+
install_methods: Object.fromEntries(installOutputs.map((out) => [out.spec, out.method])),
|
|
636
643
|
before,
|
|
637
644
|
after,
|
|
638
645
|
installed_at: new Date().toISOString(),
|
|
@@ -640,6 +647,82 @@ async function upgradeToolchain(config, targets) {
|
|
|
640
647
|
};
|
|
641
648
|
}
|
|
642
649
|
|
|
650
|
+
async function installNpmGlobal(config, spec, { prefix, cache, registry, env }) {
|
|
651
|
+
return execFileAsync('npm', [
|
|
652
|
+
'install',
|
|
653
|
+
'-g',
|
|
654
|
+
'--prefix',
|
|
655
|
+
prefix,
|
|
656
|
+
'--cache',
|
|
657
|
+
cache,
|
|
658
|
+
`--registry=${registry}`,
|
|
659
|
+
spec,
|
|
660
|
+
], {
|
|
661
|
+
cwd: config.workDir,
|
|
662
|
+
env,
|
|
663
|
+
timeout: 10 * 60_000,
|
|
664
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
async function installWttConnectFromRegistry(prefix, registry) {
|
|
669
|
+
const registryBase = String(registry || 'https://registry.npmjs.org').replace(/\/+$/, '');
|
|
670
|
+
const metadataUrl = `${registryBase}/wtt-connect`;
|
|
671
|
+
const metadata = await fetchJson(metadataUrl);
|
|
672
|
+
const version = metadata?.['dist-tags']?.latest;
|
|
673
|
+
const tarball = version ? metadata?.versions?.[version]?.dist?.tarball : '';
|
|
674
|
+
if (!version || !tarball) throw new Error(`wtt-connect metadata missing latest tarball from ${metadataUrl}`);
|
|
675
|
+
|
|
676
|
+
const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'wtt-connect-upgrade-'));
|
|
677
|
+
const archive = path.join(tmpDir, `wtt-connect-${version}.tgz`);
|
|
678
|
+
const extractDir = path.join(tmpDir, 'extract');
|
|
679
|
+
const libDir = path.join(prefix, 'lib', 'node_modules');
|
|
680
|
+
const binDir = path.join(prefix, 'bin');
|
|
681
|
+
const targetDir = path.join(libDir, 'wtt-connect');
|
|
682
|
+
const nextDir = path.join(libDir, `.wtt-connect-${version}-${process.pid}-${Date.now()}`);
|
|
683
|
+
try {
|
|
684
|
+
await execFileAsync('curl', ['-fsSL', tarball, '-o', archive], { timeout: 5 * 60_000, maxBuffer: 512 * 1024 });
|
|
685
|
+
await fsp.mkdir(extractDir, { recursive: true });
|
|
686
|
+
await execFileAsync('tar', ['-xzf', archive, '-C', extractDir], { timeout: 2 * 60_000, maxBuffer: 512 * 1024 });
|
|
687
|
+
await fsp.mkdir(libDir, { recursive: true });
|
|
688
|
+
await fsp.mkdir(binDir, { recursive: true });
|
|
689
|
+
await fsp.rm(nextDir, { recursive: true, force: true });
|
|
690
|
+
await fsp.rename(path.join(extractDir, 'package'), nextDir);
|
|
691
|
+
await fsp.rm(targetDir, { recursive: true, force: true });
|
|
692
|
+
await fsp.rename(nextDir, targetDir);
|
|
693
|
+
const entry = path.join(targetDir, 'bin', 'wtt-connect.js');
|
|
694
|
+
await fsp.chmod(entry, 0o755).catch(() => {});
|
|
695
|
+
const link = path.join(binDir, 'wtt-connect');
|
|
696
|
+
await fsp.rm(link, { force: true });
|
|
697
|
+
await fsp.symlink('../lib/node_modules/wtt-connect/bin/wtt-connect.js', link);
|
|
698
|
+
await writeToolVersion(prefix, 'wtt_connect', version);
|
|
699
|
+
return { stdout: `installed wtt-connect@${version} from ${tarball}`, stderr: '' };
|
|
700
|
+
} finally {
|
|
701
|
+
await fsp.rm(tmpDir, { recursive: true, force: true }).catch(() => {});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async function fetchJson(url) {
|
|
706
|
+
const res = await fetch(url);
|
|
707
|
+
if (!res.ok) throw new Error(`GET ${url} failed: ${res.status} ${res.statusText}`);
|
|
708
|
+
return res.json();
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
async function writeToolVersion(prefix, key, version) {
|
|
712
|
+
const toolchainDir = path.dirname(prefix);
|
|
713
|
+
const file = path.join(toolchainDir, 'tool-versions.json');
|
|
714
|
+
let current = {};
|
|
715
|
+
try {
|
|
716
|
+
current = JSON.parse(await fsp.readFile(file, 'utf8'));
|
|
717
|
+
} catch {
|
|
718
|
+
current = {};
|
|
719
|
+
}
|
|
720
|
+
current[key] = version;
|
|
721
|
+
current.updated_at = new Date().toISOString();
|
|
722
|
+
await fsp.mkdir(toolchainDir, { recursive: true });
|
|
723
|
+
await fsp.writeFile(file, `${JSON.stringify(current, null, 2)}\n`);
|
|
724
|
+
}
|
|
725
|
+
|
|
643
726
|
async function resolveNpmPrefix(config) {
|
|
644
727
|
const envPrefix = process.env.NPM_CONFIG_PREFIX || process.env.npm_config_prefix || '';
|
|
645
728
|
if (envPrefix) return path.resolve(envPrefix);
|
package/src/store.js
CHANGED
|
@@ -20,10 +20,22 @@ export class DurableStore {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
save() {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const dir = path.dirname(this.file);
|
|
24
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
25
|
+
const tmp = path.join(dir, `.${path.basename(this.file)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
26
|
+
try {
|
|
27
|
+
fs.writeFileSync(tmp, JSON.stringify(this.data, null, 2));
|
|
28
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
29
|
+
fs.renameSync(tmp, this.file);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
try { fs.rmSync(tmp, { force: true }); } catch {}
|
|
32
|
+
if (error && error.code === 'ENOENT') {
|
|
33
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
34
|
+
fs.writeFileSync(this.file, JSON.stringify(this.data, null, 2));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
getSession(sessionKey) {
|