wtt-connect 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -138,6 +138,12 @@ On macOS the same profile and state paths are used, while the service file is:
138
138
 
139
139
  A profile contains exactly one WTT identity: `WTT_AGENT_ID`, `WTT_TOKEN`, adapter, workdir, permission mode, and state directory. Multiple profiles may point at the same local `codex` or `claude` CLI binary; they must not share `WTT_AGENT_ID`, `WTT_TOKEN`, or `WTT_CONNECT_STATE_DIR`.
140
140
 
141
+ Workdir rules:
142
+
143
+ - If `--workdir` or `WTT_CONNECT_WORKDIR` is provided, that exact directory is used for agent execution, shell, terminal, runtime info, and adapter cwd.
144
+ - If no workdir is provided, `wtt-connect` uses `./workspaces/<agent_id>` under the current default directory. This prevents multiple claimed agents on the same host from sharing the `wtt-connect` package directory.
145
+ - For an existing profile, run `wtt-connect workdir <profile> /path/to/workspace --restart`. This updates `~/.config/wtt-connect/profiles/<profile>.env`, creates the directory, and restarts the service.
146
+
141
147
  Useful flags:
142
148
 
143
149
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wtt-connect",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "description": "WTT-native connector daemon for Codex, Claude Code, Cursor, Gemini, ACP, and other coding agent surfaces.",
6
6
  "type": "module",
package/src/config.js CHANGED
@@ -26,7 +26,8 @@ export function loadConfig(argv = {}) {
26
26
  const token = process.env.WTT_TOKEN || process.env.WTT_AGENT_TOKEN || fileConfig.token || '';
27
27
  const adapter = process.env.WTT_CONNECT_ADAPTER || fileConfig.adapter || 'codex';
28
28
  const adapters = String(process.env.WTT_CONNECT_ADAPTERS || fileConfig.adapters || adapter).split(',').map((x) => x.trim()).filter(Boolean);
29
- const workDir = process.env.WTT_CONNECT_WORKDIR || fileConfig.workDir || process.cwd();
29
+ const explicitWorkDir = process.env.WTT_CONNECT_WORKDIR || fileConfig.workDir || '';
30
+ const workDir = resolveAgentWorkDir(explicitWorkDir, agentId);
30
31
  const stateDir = process.env.WTT_CONNECT_STATE_DIR || fileConfig.stateDir || path.join(workDir, '.wtt-connect');
31
32
  return {
32
33
  configFile: argv.config || process.env.WTT_CONNECT_CONFIG || '',
@@ -99,6 +100,20 @@ export function loadConfig(argv = {}) {
99
100
  };
100
101
  }
101
102
 
103
+ export function resolveAgentWorkDir(explicitWorkDir, agentId, baseDir = process.cwd()) {
104
+ if (explicitWorkDir) return path.resolve(String(explicitWorkDir));
105
+ return path.resolve(baseDir, 'workspaces', safeAgentPathSegment(agentId));
106
+ }
107
+
108
+ export function safeAgentPathSegment(agentId) {
109
+ const value = String(agentId || 'unbound-agent')
110
+ .trim()
111
+ .replace(/[^a-zA-Z0-9._-]+/g, '-')
112
+ .replace(/^-+|-+$/g, '')
113
+ .slice(0, 96);
114
+ return value || 'unbound-agent';
115
+ }
116
+
102
117
  function resolveOpenDesignSkillsDir() {
103
118
  const candidates = [
104
119
  path.resolve(process.cwd(), 'opendesign-skills'),
package/src/main.js CHANGED
@@ -10,7 +10,7 @@ import { DurableStore } from './store.js';
10
10
  import { log, redact } from './logger.js';
11
11
  import { adapterBin, normalizeProfileName } from './adapters/generic-cli.js';
12
12
  import { normalizeAdapterName } from './adapters/index.js';
13
- import { down, listProfiles, logs, resolveProfileEnvFile, restart, status, up } from './service-manager.js';
13
+ import { down, listProfiles, logs, resolveProfileEnvFile, restart, status, up, workdir } from './service-manager.js';
14
14
 
15
15
  export async function main(args) {
16
16
  const cmd = args[0] || 'help';
@@ -23,6 +23,7 @@ export async function main(args) {
23
23
  if (cmd === 'status') return status(argv);
24
24
  if (cmd === 'restart') return restart(argv);
25
25
  if (cmd === 'logs') return logs(argv);
26
+ if (cmd === 'workdir') return workdir(argv);
26
27
  if (cmd === 'down' || cmd === 'unlink') return down(argv);
27
28
  if (cmd === 'doctor') return doctor(loadConfig(argv));
28
29
  if (cmd === 'setup') return setup(loadConfig(argv), argv);
@@ -61,6 +62,7 @@ function parseArgs(args) {
61
62
  else if (a === '--allow-yolo' || a === '--allow-dangerous-permissions') out.allowYolo = true;
62
63
  else if (a === '--yes' || a === '-y') out.yes = true;
63
64
  else if (a === '--publish-progress') out.publishProgress = true;
65
+ else if (a === '--restart') out.restart = true;
64
66
  else if (a === '--enable-linger') out.enableLinger = true;
65
67
  else if (a === '--no-start') out.noStart = true;
66
68
  else if (a === '--node-bin') out.nodeBin = args[++i];
@@ -97,6 +99,8 @@ Commands:
97
99
  status [profile|all] Show systemd service status for profiles
98
100
  restart [profile|all] Restart one or all configured services
99
101
  logs <profile> [--lines 100] Show service logs
102
+ workdir <profile> [path] [--restart]
103
+ Show or update the agent execution directory
100
104
  down <profile> Stop/disable service; keep profile/state files
101
105
  unlink <profile> Alias for down
102
106
  setup [--claim-code] Register/write local .env and optionally print claim code
package/src/runner.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { WTTClient } from './wtt-client.js';
2
+ import fs from 'node:fs';
2
3
  import { WTTApi } from './wtt-api.js';
3
4
  import { SessionManager } from './session-manager.js';
4
5
  import { TTSManager } from './tts.js';
@@ -40,6 +41,7 @@ export class Runner {
40
41
  }
41
42
 
42
43
  async start() {
44
+ fs.mkdirSync(this.config.workDir, { recursive: true });
43
45
  log('info', 'wtt-connect starting', {
44
46
  agentId: this.config.agentId,
45
47
  adapters: this.registry.list().join(','),
@@ -4,6 +4,7 @@ import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import { normalizeAdapterName } from './adapters/index.js';
7
+ import { resolveAgentWorkDir } from './config.js';
7
8
 
8
9
  const DEFAULT_BASE_URL = 'https://www.waxbyte.com';
9
10
  const DEFAULT_MODE = 'full-auto';
@@ -32,7 +33,7 @@ export async function up(argv) {
32
33
  const stateDir = path.resolve(argv.stateDir || defaultStateDir(profile));
33
34
  const envFile = path.resolve(argv.envFile || profileEnvFile(profile));
34
35
  const root = packageRoot();
35
- const workDir = path.resolve(argv.workdir || argv.workDir || process.cwd());
36
+ const workDir = resolveAgentWorkDir(argv.workdir || argv.workDir || '', agentId, process.cwd());
36
37
  const baseUrl = argv.baseUrl || process.env.WTT_BASE_URL || DEFAULT_BASE_URL;
37
38
  const nodeBin = argv.nodeBin || process.execPath;
38
39
  const codexBin = argv.codexBin || findBinary('codex');
@@ -42,6 +43,7 @@ export async function up(argv) {
42
43
  ensureDir(configDir);
43
44
  ensureDir(path.dirname(envFile));
44
45
  ensureDir(stateDir);
46
+ ensureDir(workDir);
45
47
 
46
48
  const profileValues = {
47
49
  WTT_BASE_URL: baseUrl,
@@ -140,6 +142,30 @@ export function logs(argv) {
140
142
  throw new Error(`unsupported platform: ${process.platform}`);
141
143
  }
142
144
 
145
+ export function workdir(argv) {
146
+ const [profile = '', nextDir = ''] = argv._ || [];
147
+ if (!profile) throw new Error('usage: wtt-connect workdir <profile> [path] [--restart]');
148
+ const safe = sanitizeProfile(profile);
149
+ const envFile = profileEnvFile(safe);
150
+ if (!fs.existsSync(envFile)) throw new Error(`profile not found: ${safe}`);
151
+ const env = readEnv(envFile);
152
+ if (!nextDir) {
153
+ console.log(env.WTT_CONNECT_WORKDIR || '');
154
+ return;
155
+ }
156
+ const resolved = path.resolve(nextDir);
157
+ ensureDir(resolved);
158
+ env.WTT_CONNECT_WORKDIR = resolved;
159
+ writeProfileEnv(envFile, env);
160
+ console.log(`updated ${safe} workdir: ${resolved}`);
161
+ if (argv.restart) {
162
+ restartService(safe);
163
+ console.log(`${safe}: ${serviceStatus(safe)}`);
164
+ } else {
165
+ console.log(`restart required: wtt-connect restart ${safe}`);
166
+ }
167
+ }
168
+
143
169
  export function down(argv) {
144
170
  const [profile = ''] = argv._ || [];
145
171
  if (!profile) throw new Error('usage: wtt-connect down <profile>');