teleportation-cli 1.3.0 ā 1.4.1
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/.claude/hooks/permission_request.mjs +11 -4
- package/.claude/hooks/post_tool_use.mjs +1 -3
- package/.claude/hooks/pre_tool_use.mjs +255 -289
- package/.claude/hooks/session-register.mjs +44 -29
- package/.claude/hooks/session_end.mjs +29 -3
- package/.claude/hooks/session_start.mjs +57 -1
- package/.claude/hooks/stop.mjs +245 -242
- package/.claude/hooks/user_prompt_submit.mjs +1 -3
- package/lib/config/manager.js +45 -1
- package/lib/daemon/session-file-registry.js +207 -0
- package/lib/daemon/task-executor-v2.js +239 -29
- package/lib/daemon/teleportation-daemon.js +469 -29
- package/lib/daemon/timeline-analyzer.js +19 -13
- package/lib/daemon/transcript-ingestion.js +310 -51
- package/lib/daemon/utils.js +0 -9
- package/lib/install/installer.js +126 -3
- package/lib/install/uhr-installer.js +32 -18
- package/lib/intelligence/benchmark.js +240 -0
- package/lib/intelligence/index.js +29 -0
- package/lib/intelligence/rebuild-policies.js +169 -0
- package/lib/intelligence/schema.js +259 -0
- package/lib/intelligence/transcript-mine.js +339 -0
- package/lib/session/metadata.js +23 -5
- package/lib/transcript-sync/lifecycle.js +88 -0
- package/lib/transcript-sync/repo-context.js +45 -0
- package/lib/transcript-sync/worker.js +233 -0
- package/lib/utils/log-sanitizer.js +65 -0
- package/package.json +2 -1
- package/scripts/sync-transcripts.sh +272 -0
- package/teleportation-cli.cjs +295 -4
package/teleportation-cli.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const { execSync } = require('child_process');
|
|
7
|
+
const { execSync, spawnSync } = require('child_process');
|
|
8
8
|
const os = require('os');
|
|
9
9
|
|
|
10
10
|
const CLI_VERSION = '1.2.2';
|
|
@@ -246,6 +246,14 @@ function commandHelp() {
|
|
|
246
246
|
console.log(' ' + c.green('daemon restart') + ' Restart the daemon');
|
|
247
247
|
console.log(' ' + c.green('daemon status') + ' Show daemon status');
|
|
248
248
|
console.log(' ' + c.green('daemon health') + ' Check daemon health\n');
|
|
249
|
+
|
|
250
|
+
console.log(c.yellow('Transcript Sync:'));
|
|
251
|
+
console.log(' ' + c.green('transcript-sync start') + ' Start transcript sync worker');
|
|
252
|
+
console.log(' ' + c.green('transcript-sync stop') + ' Stop transcript sync worker');
|
|
253
|
+
console.log(' ' + c.green('transcript-sync restart') + ' Restart transcript sync worker');
|
|
254
|
+
console.log(' ' + c.green('transcript-sync status') + ' Show transcript sync status');
|
|
255
|
+
console.log(' ' + c.green('transcript-sync run-now') + ' Run transcript sync immediately');
|
|
256
|
+
console.log(' ' + c.green('transcript-sync health') + ' Check transcript sync health\n');
|
|
249
257
|
|
|
250
258
|
console.log(c.yellow('Inbox & Messaging:'));
|
|
251
259
|
console.log(' ' + c.green('command "<text>"') + ' Enqueue a command message for this session');
|
|
@@ -315,14 +323,24 @@ async function commandOn() {
|
|
|
315
323
|
const hooksDir = path.join(TELEPORTATION_DIR, '.claude', 'hooks');
|
|
316
324
|
const uhrResult = await installViaUhr(manifestPath, hooksDir);
|
|
317
325
|
|
|
318
|
-
|
|
326
|
+
// Verify UHR actually wrote the Claude settings file ā it can return
|
|
327
|
+
// success=true while silently skipping the write when the manifest
|
|
328
|
+
// contains platforms (gemini-cli, cursor) not in its lockfile.
|
|
329
|
+
const globalSettings = path.join(os.homedir(), '.claude', 'settings.json');
|
|
330
|
+
const uhrActuallyWorked = uhrResult.success && fs.existsSync(globalSettings);
|
|
331
|
+
|
|
332
|
+
if (uhrActuallyWorked) {
|
|
319
333
|
console.log(c.green('\nš Teleportation Remote Control ENABLED!'));
|
|
320
334
|
console.log(c.cyan('\nInstalled via UHR (Universal Hook Registry)'));
|
|
321
335
|
if (uhrResult.warnings.length > 0) {
|
|
322
336
|
uhrResult.warnings.forEach(w => console.log(c.yellow(` ā ļø ${w}`)));
|
|
323
337
|
}
|
|
324
338
|
} else {
|
|
325
|
-
|
|
339
|
+
if (uhrResult.success && !fs.existsSync(globalSettings)) {
|
|
340
|
+
console.log(c.yellow(' ā ļø UHR reported success but did not write ~/.claude/settings.json'));
|
|
341
|
+
} else {
|
|
342
|
+
console.log(c.yellow(` ā ļø UHR install failed: ${uhrResult.reason}`));
|
|
343
|
+
}
|
|
326
344
|
console.log(c.dim(' Falling back to legacy installer...'));
|
|
327
345
|
await _legacyInstall();
|
|
328
346
|
}
|
|
@@ -797,6 +815,18 @@ async function commandOff() {
|
|
|
797
815
|
}
|
|
798
816
|
}
|
|
799
817
|
|
|
818
|
+
// Remove Teleportation-managed Cursor hooks while preserving third-party entries
|
|
819
|
+
try {
|
|
820
|
+
const installerPath = path.join(TELEPORTATION_DIR, 'lib', 'install', 'installer.js');
|
|
821
|
+
const { uninstallCursorHooks } = await import('file://' + installerPath);
|
|
822
|
+
const result = await uninstallCursorHooks();
|
|
823
|
+
if (result?.success) {
|
|
824
|
+
console.log(c.green('ā
Removed Teleportation hooks from ~/.cursor/hooks.json'));
|
|
825
|
+
}
|
|
826
|
+
} catch (e) {
|
|
827
|
+
console.log(c.yellow(`ā ļø Could not update Cursor hooks: ${e.message}`));
|
|
828
|
+
}
|
|
829
|
+
|
|
800
830
|
console.log(c.yellow('\nš Teleportation Remote Control DISABLED'));
|
|
801
831
|
console.log(c.cyan('Services are still running. Stop with: ./teleportation stop\n'));
|
|
802
832
|
}
|
|
@@ -2262,6 +2292,12 @@ async function commandConfig(args) {
|
|
|
2262
2292
|
console.log(c.cyan('\nNotification Settings:'));
|
|
2263
2293
|
console.log(` Enabled: ${config.notifications?.enabled ? c.green('yes') : c.yellow('no')}`);
|
|
2264
2294
|
console.log(` Sound: ${config.notifications?.sound ? c.green('enabled') : c.yellow('disabled')}`);
|
|
2295
|
+
|
|
2296
|
+
console.log(c.cyan('\nTranscript Sync Settings:'));
|
|
2297
|
+
console.log(` Enabled: ${config.transcriptSync?.enabled ? c.green('yes') : c.yellow('no')}`);
|
|
2298
|
+
console.log(` Interval: ${c.green(((config.transcriptSync?.intervalMs || 0) / 1000) + ' seconds')}`);
|
|
2299
|
+
console.log(` Mode: ${c.green(config.transcriptSync?.mode || 'local')}`);
|
|
2300
|
+
console.log(` Scope: ${c.green('auto (current git repo)')}`);
|
|
2265
2301
|
|
|
2266
2302
|
console.log(c.cyan(`\nConfig file: ${DEFAULT_CONFIG_PATH}\n`));
|
|
2267
2303
|
|
|
@@ -2289,6 +2325,13 @@ async function commandConfig(args) {
|
|
|
2289
2325
|
console.log(c.cyan('Example: teleportation config set notifications.sound true\n'));
|
|
2290
2326
|
return;
|
|
2291
2327
|
}
|
|
2328
|
+
|
|
2329
|
+
// Transcript sync is repo-driven; users should only choose mode.
|
|
2330
|
+
if (key.startsWith('transcriptSync.') && key !== 'transcriptSync.mode') {
|
|
2331
|
+
console.log(c.red('ā Only transcriptSync.mode is user-configurable\n'));
|
|
2332
|
+
console.log(c.cyan('Use: teleportation config set transcriptSync.mode local|push|pull|bidirectional\n'));
|
|
2333
|
+
return;
|
|
2334
|
+
}
|
|
2292
2335
|
|
|
2293
2336
|
// Try to parse value as JSON, number, or boolean
|
|
2294
2337
|
let value = valueStr;
|
|
@@ -2927,6 +2970,248 @@ async function commandDaemon(args) {
|
|
|
2927
2970
|
}
|
|
2928
2971
|
}
|
|
2929
2972
|
|
|
2973
|
+
async function commandTranscriptSync(args) {
|
|
2974
|
+
const subCommand = args[0] || 'status';
|
|
2975
|
+
const statePath = path.join(HOME_DIR, '.teleportation', 'transcript-sync-state.json');
|
|
2976
|
+
|
|
2977
|
+
try {
|
|
2978
|
+
const lifecyclePath = path.join(TELEPORTATION_DIR, 'lib', 'transcript-sync', 'lifecycle.js');
|
|
2979
|
+
const configPath = path.join(TELEPORTATION_DIR, 'lib', 'config', 'manager.js');
|
|
2980
|
+
const repoContextPath = path.join(TELEPORTATION_DIR, 'lib', 'transcript-sync', 'repo-context.js');
|
|
2981
|
+
const syncScriptPath = path.join(TELEPORTATION_DIR, 'scripts', 'sync-transcripts.sh');
|
|
2982
|
+
const { loadConfig, setConfigValue } = await import('file://' + configPath);
|
|
2983
|
+
const { getRepoSyncContext } = await import('file://' + repoContextPath);
|
|
2984
|
+
const loadLifecycle = async () => {
|
|
2985
|
+
try {
|
|
2986
|
+
return await import('file://' + lifecyclePath);
|
|
2987
|
+
} catch (error) {
|
|
2988
|
+
if (error.message.includes('@derivativelabs/agent-process')) {
|
|
2989
|
+
throw new Error('Missing dependency: @derivativelabs/agent-process. Run `bun install` and retry.');
|
|
2990
|
+
}
|
|
2991
|
+
throw error;
|
|
2992
|
+
}
|
|
2993
|
+
};
|
|
2994
|
+
|
|
2995
|
+
switch (subCommand) {
|
|
2996
|
+
case 'start': {
|
|
2997
|
+
console.log(c.yellow('Starting transcript sync worker...\n'));
|
|
2998
|
+
const { startTranscriptSync } = await loadLifecycle();
|
|
2999
|
+
const result = await startTranscriptSync();
|
|
3000
|
+
try {
|
|
3001
|
+
await setConfigValue('transcriptSync.enabled', true);
|
|
3002
|
+
} catch (e) {
|
|
3003
|
+
console.log(c.yellow(`ā ļø Could not update transcriptSync.enabled: ${e.message}`));
|
|
3004
|
+
}
|
|
3005
|
+
console.log(c.green(`ā
Transcript sync started (PID: ${result.pid})\n`));
|
|
3006
|
+
break;
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
case 'stop': {
|
|
3010
|
+
console.log(c.yellow('Stopping transcript sync worker...\n'));
|
|
3011
|
+
const { stopTranscriptSync } = await loadLifecycle();
|
|
3012
|
+
const result = await stopTranscriptSync();
|
|
3013
|
+
try {
|
|
3014
|
+
await setConfigValue('transcriptSync.enabled', false);
|
|
3015
|
+
} catch (e) {
|
|
3016
|
+
console.log(c.yellow(`ā ļø Could not update transcriptSync.enabled: ${e.message}`));
|
|
3017
|
+
}
|
|
3018
|
+
if (result.success) {
|
|
3019
|
+
console.log(c.green(`ā
Transcript sync stopped${result.forced ? ' (forced)' : ''}\n`));
|
|
3020
|
+
} else {
|
|
3021
|
+
console.log(c.red('ā Failed to stop transcript sync\n'));
|
|
3022
|
+
process.exit(1);
|
|
3023
|
+
}
|
|
3024
|
+
break;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
case 'restart': {
|
|
3028
|
+
console.log(c.yellow('Restarting transcript sync worker...\n'));
|
|
3029
|
+
const { restartTranscriptSync } = await loadLifecycle();
|
|
3030
|
+
const result = await restartTranscriptSync();
|
|
3031
|
+
try {
|
|
3032
|
+
await setConfigValue('transcriptSync.enabled', true);
|
|
3033
|
+
} catch (e) {
|
|
3034
|
+
console.log(c.yellow(`ā ļø Could not update transcriptSync.enabled: ${e.message}`));
|
|
3035
|
+
}
|
|
3036
|
+
console.log(c.green(`ā
Transcript sync restarted (PID: ${result.pid})`));
|
|
3037
|
+
console.log(c.cyan(`Previous worker ${result.wasRunning ? 'was running' : 'was not running'}\n`));
|
|
3038
|
+
break;
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
case 'run-now': {
|
|
3042
|
+
const cfg = await loadConfig();
|
|
3043
|
+
const ts = cfg.transcriptSync || {};
|
|
3044
|
+
const repoContext = getRepoSyncContext(TELEPORTATION_DIR);
|
|
3045
|
+
const machineId = repoContext.machineId || os.hostname().split('.')[0];
|
|
3046
|
+
const mode = ts.mode || 'local';
|
|
3047
|
+
const mirrorDir = repoContext.mirrorDir;
|
|
3048
|
+
const peer = repoContext.peer || '';
|
|
3049
|
+
const peerMirrorDir = repoContext.peerMirrorDir || '';
|
|
3050
|
+
const now = new Date().toISOString();
|
|
3051
|
+
let previousState = {};
|
|
3052
|
+
if (fs.existsSync(statePath)) {
|
|
3053
|
+
try {
|
|
3054
|
+
previousState = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
3055
|
+
} catch {
|
|
3056
|
+
previousState = {};
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
if (['push', 'pull', 'bidirectional'].includes(mode) && !peer) {
|
|
3061
|
+
console.log(c.red(`ā transcriptSync.mode is "${mode}" but no auto peer is configured for this repo\n`));
|
|
3062
|
+
console.log(c.cyan('Set repo peer once: git config teleportation.transcriptSyncPeer "<user@host>"\n'));
|
|
3063
|
+
process.exit(1);
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
const syncArgs = ['--machine-id', machineId, '--mirror-dir', mirrorDir, '--mode', mode];
|
|
3067
|
+
if (peer) syncArgs.push('--peer', peer);
|
|
3068
|
+
if (peerMirrorDir) syncArgs.push('--peer-mirror-dir', peerMirrorDir);
|
|
3069
|
+
|
|
3070
|
+
console.log(c.yellow('Running transcript sync now...\n'));
|
|
3071
|
+
const result = spawnSync(syncScriptPath, syncArgs, {
|
|
3072
|
+
env: process.env,
|
|
3073
|
+
encoding: 'utf8'
|
|
3074
|
+
});
|
|
3075
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
3076
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
3077
|
+
const stderrText = result.stderr || '';
|
|
3078
|
+
const hasRsyncErrors = /rsync\([^)]+\): error:/i.test(stderrText);
|
|
3079
|
+
if (result.status !== 0) {
|
|
3080
|
+
fs.writeFileSync(statePath, JSON.stringify({
|
|
3081
|
+
...previousState,
|
|
3082
|
+
running: previousState.running ?? false,
|
|
3083
|
+
lastRunAt: now,
|
|
3084
|
+
lastExitCode: result.status || 1,
|
|
3085
|
+
lastMode: mode,
|
|
3086
|
+
lastPeer: peer || null,
|
|
3087
|
+
machineId,
|
|
3088
|
+
lastSuccessAt: previousState.lastSuccessAt || null,
|
|
3089
|
+
lastErrorAt: now,
|
|
3090
|
+
skipped: false,
|
|
3091
|
+
skipReason: null,
|
|
3092
|
+
lastOutput: (result.stdout || '').slice(-4000),
|
|
3093
|
+
lastError: (result.stderr || '').slice(-4000)
|
|
3094
|
+
}, null, 2), { mode: 0o600 });
|
|
3095
|
+
console.log(c.red('\nā transcript-sync run-now failed\n'));
|
|
3096
|
+
process.exit(result.status || 1);
|
|
3097
|
+
}
|
|
3098
|
+
if (hasRsyncErrors) {
|
|
3099
|
+
fs.writeFileSync(statePath, JSON.stringify({
|
|
3100
|
+
...previousState,
|
|
3101
|
+
running: previousState.running ?? false,
|
|
3102
|
+
lastRunAt: now,
|
|
3103
|
+
lastExitCode: 1,
|
|
3104
|
+
lastMode: mode,
|
|
3105
|
+
lastPeer: peer || null,
|
|
3106
|
+
machineId,
|
|
3107
|
+
lastSuccessAt: previousState.lastSuccessAt || null,
|
|
3108
|
+
lastErrorAt: now,
|
|
3109
|
+
skipped: false,
|
|
3110
|
+
skipReason: null,
|
|
3111
|
+
lastOutput: (result.stdout || '').slice(-4000),
|
|
3112
|
+
lastError: (result.stderr || '').slice(-4000)
|
|
3113
|
+
}, null, 2), { mode: 0o600 });
|
|
3114
|
+
console.log(c.red('\nā transcript-sync run-now detected rsync errors in output\n'));
|
|
3115
|
+
process.exit(1);
|
|
3116
|
+
}
|
|
3117
|
+
fs.writeFileSync(statePath, JSON.stringify({
|
|
3118
|
+
...previousState,
|
|
3119
|
+
running: previousState.running ?? false,
|
|
3120
|
+
lastRunAt: now,
|
|
3121
|
+
lastExitCode: 0,
|
|
3122
|
+
lastMode: mode,
|
|
3123
|
+
lastPeer: peer || null,
|
|
3124
|
+
machineId,
|
|
3125
|
+
lastSuccessAt: now,
|
|
3126
|
+
lastErrorAt: previousState.lastErrorAt || null,
|
|
3127
|
+
skipped: false,
|
|
3128
|
+
skipReason: null,
|
|
3129
|
+
lastOutput: (result.stdout || '').slice(-4000),
|
|
3130
|
+
lastError: (result.stderr || '').slice(-4000)
|
|
3131
|
+
}, null, 2), { mode: 0o600 });
|
|
3132
|
+
console.log(c.green('\nā
transcript-sync run-now completed\n'));
|
|
3133
|
+
break;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
case 'status':
|
|
3137
|
+
case 'health': {
|
|
3138
|
+
let status = { running: false, pid: null, uptime: null };
|
|
3139
|
+
try {
|
|
3140
|
+
const { getTranscriptSyncStatus } = await loadLifecycle();
|
|
3141
|
+
status = await getTranscriptSyncStatus();
|
|
3142
|
+
} catch (error) {
|
|
3143
|
+
if (subCommand === 'health') {
|
|
3144
|
+
throw error;
|
|
3145
|
+
}
|
|
3146
|
+
console.log(c.yellow(`ā ļø ${error.message}`));
|
|
3147
|
+
}
|
|
3148
|
+
const cfg = await loadConfig();
|
|
3149
|
+
const ts = cfg.transcriptSync || {};
|
|
3150
|
+
const repoContext = getRepoSyncContext(TELEPORTATION_DIR);
|
|
3151
|
+
let state = null;
|
|
3152
|
+
|
|
3153
|
+
if (fs.existsSync(statePath)) {
|
|
3154
|
+
try {
|
|
3155
|
+
state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
3156
|
+
} catch {
|
|
3157
|
+
state = null;
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
console.log(c.purple('Transcript Sync Status\n'));
|
|
3162
|
+
console.log(`Worker: ${status.running ? c.green(`running (PID: ${status.pid})`) : c.red('stopped')}`);
|
|
3163
|
+
if (status.uptime) {
|
|
3164
|
+
console.log(`Uptime: ${c.cyan(Math.round(status.uptime / 60000) + 'm')}`);
|
|
3165
|
+
}
|
|
3166
|
+
console.log(`Enabled: ${ts.enabled ? c.green('yes') : c.yellow('no')}`);
|
|
3167
|
+
console.log(`Interval: ${c.cyan(((ts.intervalMs || 300000) / 1000) + 's')}`);
|
|
3168
|
+
console.log(`Mode: ${c.cyan(ts.mode || 'local')}`);
|
|
3169
|
+
console.log(`Repo key: ${c.cyan(repoContext.repoKey)}`);
|
|
3170
|
+
console.log(`Machine ID: ${c.cyan(repoContext.machineId || os.hostname().split('.')[0])}`);
|
|
3171
|
+
console.log(`Peer: ${c.cyan(repoContext.peer || '(auto-unset)')}`);
|
|
3172
|
+
console.log(`Mirror dir: ${c.cyan(repoContext.mirrorDir)}`);
|
|
3173
|
+
|
|
3174
|
+
if (state) {
|
|
3175
|
+
if (state.lastRunAt) console.log(`Last run: ${c.cyan(state.lastRunAt)}`);
|
|
3176
|
+
if (state.lastSuccessAt) console.log(`Last success: ${c.green(state.lastSuccessAt)}`);
|
|
3177
|
+
if (state.lastErrorAt) console.log(`Last error: ${c.red(state.lastErrorAt)}`);
|
|
3178
|
+
if (state.skipReason) console.log(`Last skip: ${c.yellow(state.skipReason)}`);
|
|
3179
|
+
} else {
|
|
3180
|
+
console.log(c.yellow('State: no transcript sync state file yet'));
|
|
3181
|
+
}
|
|
3182
|
+
console.log('');
|
|
3183
|
+
|
|
3184
|
+
if (subCommand === 'health') {
|
|
3185
|
+
if (!status.running) {
|
|
3186
|
+
console.log(c.red('ā transcript-sync is not running\n'));
|
|
3187
|
+
process.exit(1);
|
|
3188
|
+
}
|
|
3189
|
+
if (state && state.lastErrorAt && !state.lastSuccessAt) {
|
|
3190
|
+
console.log(c.red('ā transcript-sync has errors and no successful run yet\n'));
|
|
3191
|
+
process.exit(1);
|
|
3192
|
+
}
|
|
3193
|
+
console.log(c.green('ā
transcript-sync health check passed\n'));
|
|
3194
|
+
}
|
|
3195
|
+
break;
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
default:
|
|
3199
|
+
console.log(c.red(`Unknown transcript-sync command: ${subCommand}\n`));
|
|
3200
|
+
console.log(c.cyan('Available commands:'));
|
|
3201
|
+
console.log(' teleportation transcript-sync start');
|
|
3202
|
+
console.log(' teleportation transcript-sync stop');
|
|
3203
|
+
console.log(' teleportation transcript-sync restart');
|
|
3204
|
+
console.log(' teleportation transcript-sync status');
|
|
3205
|
+
console.log(' teleportation transcript-sync run-now');
|
|
3206
|
+
console.log(' teleportation transcript-sync health\n');
|
|
3207
|
+
process.exit(1);
|
|
3208
|
+
}
|
|
3209
|
+
} catch (error) {
|
|
3210
|
+
console.log(c.red(`ā transcript-sync command failed: ${error.message}\n`));
|
|
3211
|
+
process.exit(1);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
|
|
2930
3215
|
// Away Mode Commands (Task 9.0)
|
|
2931
3216
|
async function commandAwayMode() {
|
|
2932
3217
|
console.log(c.yellow('š Marking session as away and starting daemon...\n'));
|
|
@@ -3523,7 +3808,7 @@ const command = process.argv[2] || 'help';
|
|
|
3523
3808
|
const args = process.argv.slice(3);
|
|
3524
3809
|
|
|
3525
3810
|
// Handle async commands that need to complete before exit
|
|
3526
|
-
const asyncCommands = ['login', 'logout', 'status', 'test', 'env', 'config', 'daemon', 'away', 'back', 'daemon-status', 'command', 'inbox', 'inbox-ack', 'install-hooks', 'update', 'remote', 'off'];
|
|
3811
|
+
const asyncCommands = ['login', 'logout', 'status', 'test', 'env', 'config', 'daemon', 'away', 'back', 'daemon-status', 'command', 'inbox', 'inbox-ack', 'install-hooks', 'update', 'remote', 'off', 'transcript-sync'];
|
|
3527
3812
|
// Keep this list in sync with switch cases below
|
|
3528
3813
|
asyncCommands.push('github');
|
|
3529
3814
|
if (asyncCommands.includes(command)) {
|
|
@@ -3637,6 +3922,12 @@ try {
|
|
|
3637
3922
|
process.exit(1);
|
|
3638
3923
|
});
|
|
3639
3924
|
break;
|
|
3925
|
+
case 'transcript-sync':
|
|
3926
|
+
commandTranscriptSync(args).catch(err => {
|
|
3927
|
+
console.error(c.red('ā Error:'), err.message);
|
|
3928
|
+
process.exit(1);
|
|
3929
|
+
});
|
|
3930
|
+
break;
|
|
3640
3931
|
case 'away':
|
|
3641
3932
|
commandAwayMode().catch(err => {
|
|
3642
3933
|
console.error(c.red('ā Error:'), err.message);
|