clawdex-mobile 1.1.2 → 1.3.0
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 +4 -0
- package/apps/mobile/src/screens/MainScreen.tsx +0 -38
- package/bin/clawdex.js +148 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -207,6 +207,10 @@ Published CLI equivalent:
|
|
|
207
207
|
- `npm install -g clawdex-mobile@latest` — install/upgrade the published CLI
|
|
208
208
|
- `clawdex init` — full interactive onboarding + auto-start
|
|
209
209
|
- `clawdex stop` — stop running Expo + bridge for this project
|
|
210
|
+
- `clawdex upgrade` / `clawdex update` — upgrade global CLI package to latest
|
|
211
|
+
- `clawdex upgrade --version 1.1.2` — upgrade to a specific published version
|
|
212
|
+
- `clawdex upgrade --restart` — stop services, upgrade, then restart via `clawdex init`
|
|
213
|
+
- `clawdex version` — print installed CLI version
|
|
210
214
|
- `clawdex init --no-start` — onboarding without launching bridge/expo
|
|
211
215
|
- `clawdex init --platform ios` — auto-start with iOS target
|
|
212
216
|
|
|
@@ -131,7 +131,6 @@ const RUN_WATCHDOG_MS = 60_000;
|
|
|
131
131
|
const LIKELY_RUNNING_RECENT_UPDATE_MS = 30_000;
|
|
132
132
|
const ACTIVE_CHAT_SYNC_INTERVAL_MS = 2_000;
|
|
133
133
|
const IDLE_CHAT_SYNC_INTERVAL_MS = 2_500;
|
|
134
|
-
const THREAD_RESUME_RETRY_MS = 1_500;
|
|
135
134
|
const CHAT_MODEL_PREFERENCES_FILE = 'chat-model-preferences.json';
|
|
136
135
|
const CHAT_MODEL_PREFERENCES_VERSION = 1;
|
|
137
136
|
const INLINE_OPTION_LINE_PATTERN =
|
|
@@ -451,7 +450,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
451
450
|
const externalStatusFullSyncNextAllowedAtRef = useRef(0);
|
|
452
451
|
const threadRuntimeSnapshotsRef = useRef<Record<string, ThreadRuntimeSnapshot>>({});
|
|
453
452
|
const threadReasoningBuffersRef = useRef<Record<string, string>>({});
|
|
454
|
-
const threadResumeLastAttemptAtRef = useRef<Record<string, number>>({});
|
|
455
453
|
const chatModelPreferencesRef = useRef<Record<string, ChatModelPreference>>({});
|
|
456
454
|
const [chatModelPreferencesLoaded, setChatModelPreferencesLoaded] = useState(false);
|
|
457
455
|
const preferredStartCwd = normalizeWorkspacePath(defaultStartCwd);
|
|
@@ -612,29 +610,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
612
610
|
externalStatusFullSyncQueuedThreadRef.current = null;
|
|
613
611
|
}, []);
|
|
614
612
|
|
|
615
|
-
const ensureThreadResumeSubscription = useCallback(
|
|
616
|
-
(threadId: string, options?: { force?: boolean }) => {
|
|
617
|
-
const normalizedThreadId = threadId.trim();
|
|
618
|
-
if (!normalizedThreadId) {
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
const now = Date.now();
|
|
623
|
-
const lastAttemptAt = threadResumeLastAttemptAtRef.current[normalizedThreadId] ?? 0;
|
|
624
|
-
if (!options?.force && now - lastAttemptAt < THREAD_RESUME_RETRY_MS) {
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
threadResumeLastAttemptAtRef.current[normalizedThreadId] = now;
|
|
629
|
-
api
|
|
630
|
-
.resumeThread(normalizedThreadId, {
|
|
631
|
-
approvalPolicy: activeApprovalPolicy,
|
|
632
|
-
})
|
|
633
|
-
.catch(() => {});
|
|
634
|
-
},
|
|
635
|
-
[activeApprovalPolicy, api]
|
|
636
|
-
);
|
|
637
|
-
|
|
638
613
|
const drainExternalStatusFullSyncQueue = useCallback(() => {
|
|
639
614
|
if (externalStatusFullSyncInFlightRef.current) {
|
|
640
615
|
return;
|
|
@@ -4084,10 +4059,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
4084
4059
|
const threadId =
|
|
4085
4060
|
readString(params?.threadId) ?? readString(params?.thread_id);
|
|
4086
4061
|
if (threadId && threadId === currentId) {
|
|
4087
|
-
// External clients (CLI/TUI) may start turns without pushing full live
|
|
4088
|
-
// notifications through this app-server process. Force a lightweight
|
|
4089
|
-
// resume attempt to attach to fresh stream state early.
|
|
4090
|
-
ensureThreadResumeSubscription(threadId, { force: true });
|
|
4091
4062
|
api
|
|
4092
4063
|
.getChatSummary(threadId)
|
|
4093
4064
|
.then((summary) => {
|
|
@@ -4107,7 +4078,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
4107
4078
|
});
|
|
4108
4079
|
|
|
4109
4080
|
if (isChatSummaryLikelyRunning(summary)) {
|
|
4110
|
-
ensureThreadResumeSubscription(threadId);
|
|
4111
4081
|
bumpRunWatchdog();
|
|
4112
4082
|
setActivity((prev) =>
|
|
4113
4083
|
prev.tone === 'running'
|
|
@@ -4176,7 +4146,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
4176
4146
|
clearRunWatchdog,
|
|
4177
4147
|
refreshPendingApprovalsForThread,
|
|
4178
4148
|
scheduleExternalStatusFullSync,
|
|
4179
|
-
ensureThreadResumeSubscription,
|
|
4180
4149
|
registerTurnStarted,
|
|
4181
4150
|
pushActiveCommand,
|
|
4182
4151
|
upsertThreadRuntimeSnapshot,
|
|
@@ -4214,12 +4183,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
4214
4183
|
const shouldRunFromWatchdog = runWatchdogUntilRef.current > Date.now();
|
|
4215
4184
|
const shouldShowRunning = shouldRunFromChat || shouldRunFromWatchdog;
|
|
4216
4185
|
|
|
4217
|
-
// Keep a light resume heartbeat even while idle so externally-started
|
|
4218
|
-
// turns are discovered quickly and can stream status/tool updates.
|
|
4219
|
-
ensureThreadResumeSubscription(selectedChatId, {
|
|
4220
|
-
force: shouldRunFromChat,
|
|
4221
|
-
});
|
|
4222
|
-
|
|
4223
4186
|
if (shouldShowRunning && !hasPendingApproval && !hasPendingUserInput) {
|
|
4224
4187
|
setActivity((prev) => {
|
|
4225
4188
|
// Only guard against watchdog-only bumps overriding a fresh
|
|
@@ -4304,7 +4267,6 @@ export const MainScreen = forwardRef<MainScreenHandle, MainScreenProps>(
|
|
|
4304
4267
|
pendingUserInputRequest?.id,
|
|
4305
4268
|
bumpRunWatchdog,
|
|
4306
4269
|
clearRunWatchdog,
|
|
4307
|
-
ensureThreadResumeSubscription,
|
|
4308
4270
|
]);
|
|
4309
4271
|
|
|
4310
4272
|
const handleResolveApproval = useCallback(
|
package/bin/clawdex.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const { spawnSync } = require("node:child_process");
|
|
5
5
|
const fs = require("node:fs");
|
|
6
6
|
const path = require("node:path");
|
|
7
|
+
const os = require("node:os");
|
|
7
8
|
|
|
8
9
|
function printUsage() {
|
|
9
10
|
console.log(`Usage: clawdex <command> [options]
|
|
@@ -17,30 +18,59 @@ Commands:
|
|
|
17
18
|
stop
|
|
18
19
|
Stop bridge + Expo services for this project.
|
|
19
20
|
|
|
21
|
+
upgrade [--version <latest|x.y.z>] [--restart]
|
|
22
|
+
update [--version <latest|x.y.z>] [--restart]
|
|
23
|
+
Upgrade clawdex-mobile globally.
|
|
24
|
+
--restart stops running services first, upgrades, then runs 'clawdex init'.
|
|
25
|
+
|
|
26
|
+
version
|
|
27
|
+
Print current CLI package version.
|
|
28
|
+
|
|
20
29
|
help
|
|
21
30
|
Show this help.
|
|
22
31
|
`);
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
function
|
|
26
|
-
const
|
|
27
|
-
if (!fs.existsSync(scriptPath)) {
|
|
28
|
-
console.error(`error: script not found at ${scriptPath}`);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const child = spawnSync(scriptPath, args, {
|
|
34
|
+
function runCommand(command, args = [], options = {}) {
|
|
35
|
+
const child = spawnSync(command, args, {
|
|
33
36
|
stdio: "inherit",
|
|
34
37
|
env: process.env,
|
|
35
38
|
cwd: process.cwd(),
|
|
39
|
+
...options,
|
|
36
40
|
});
|
|
37
41
|
|
|
38
42
|
if (child.error) {
|
|
39
|
-
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
status: child.status ?? 1,
|
|
46
|
+
error: child.error,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
ok: (child.status ?? 1) === 0,
|
|
52
|
+
status: child.status ?? 1,
|
|
53
|
+
error: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function runScript(scriptName, args = [], { exitOnComplete = true } = {}) {
|
|
58
|
+
const scriptPath = path.resolve(__dirname, "..", "scripts", scriptName);
|
|
59
|
+
if (!fs.existsSync(scriptPath)) {
|
|
60
|
+
console.error(`error: script not found at ${scriptPath}`);
|
|
40
61
|
process.exit(1);
|
|
41
62
|
}
|
|
42
63
|
|
|
43
|
-
|
|
64
|
+
const result = runCommand(scriptPath, args);
|
|
65
|
+
if (!result.ok && result.error) {
|
|
66
|
+
console.error(`error: failed to run ${scriptName}: ${result.error.message}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (exitOnComplete) {
|
|
70
|
+
process.exit(result.status);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
44
74
|
}
|
|
45
75
|
|
|
46
76
|
function runInit(args) {
|
|
@@ -51,6 +81,106 @@ function runStop(args) {
|
|
|
51
81
|
runScript("stop-services.sh", args);
|
|
52
82
|
}
|
|
53
83
|
|
|
84
|
+
function getCliVersion() {
|
|
85
|
+
const packageJsonPath = path.resolve(__dirname, "..", "package.json");
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
88
|
+
return parsed.version || "unknown";
|
|
89
|
+
} catch {
|
|
90
|
+
return "unknown";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseUpgradeArgs(args) {
|
|
95
|
+
let targetVersion = "latest";
|
|
96
|
+
let restart = false;
|
|
97
|
+
let noStop = false;
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
100
|
+
const value = args[i];
|
|
101
|
+
if (value === "--version") {
|
|
102
|
+
const candidate = args[i + 1];
|
|
103
|
+
if (!candidate || candidate.startsWith("-")) {
|
|
104
|
+
throw new Error("--version requires a value (for example: latest, 1.1.2)");
|
|
105
|
+
}
|
|
106
|
+
targetVersion = candidate;
|
|
107
|
+
i += 1;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (value === "--restart") {
|
|
112
|
+
restart = true;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (value === "--no-stop") {
|
|
117
|
+
noStop = true;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (value === "--help" || value === "-h") {
|
|
122
|
+
printUsage();
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error(`unknown option '${value}'`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { targetVersion, restart, noStop };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function runUpgrade(args) {
|
|
133
|
+
let options;
|
|
134
|
+
try {
|
|
135
|
+
options = parseUpgradeArgs(args);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(`error: ${error.message}`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const previousVersion = getCliVersion();
|
|
142
|
+
const packageSpecifier =
|
|
143
|
+
options.targetVersion === "latest"
|
|
144
|
+
? "clawdex-mobile@latest"
|
|
145
|
+
: `clawdex-mobile@${options.targetVersion}`;
|
|
146
|
+
|
|
147
|
+
console.log(`Current clawdex-mobile version: ${previousVersion}`);
|
|
148
|
+
if (!options.noStop) {
|
|
149
|
+
console.log("Stopping running bridge/Expo services before upgrade...");
|
|
150
|
+
const stopResult = runScript("stop-services.sh", [], { exitOnComplete: false });
|
|
151
|
+
if (!stopResult.ok) {
|
|
152
|
+
console.error("error: failed to stop services before upgrade.");
|
|
153
|
+
process.exit(stopResult.status);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log(`Upgrading via npm: ${packageSpecifier}`);
|
|
158
|
+
const installResult = runCommand("npm", ["install", "-g", packageSpecifier]);
|
|
159
|
+
if (!installResult.ok) {
|
|
160
|
+
const platformHint =
|
|
161
|
+
os.platform() === "win32"
|
|
162
|
+
? "Run terminal as Administrator and retry."
|
|
163
|
+
: "If this is a permissions error, retry with sudo or fix npm global prefix.";
|
|
164
|
+
console.error(`error: upgrade failed. ${platformHint}`);
|
|
165
|
+
process.exit(installResult.status);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log("Upgrade completed.");
|
|
169
|
+
if (options.restart) {
|
|
170
|
+
console.log("Restarting with updated setup: clawdex init");
|
|
171
|
+
const restartResult = runCommand("clawdex", ["init"]);
|
|
172
|
+
process.exit(restartResult.status);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log("Run 'clawdex init' to start services with the updated version.");
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function runVersion() {
|
|
180
|
+
console.log(getCliVersion());
|
|
181
|
+
process.exit(0);
|
|
182
|
+
}
|
|
183
|
+
|
|
54
184
|
const argv = process.argv.slice(2);
|
|
55
185
|
const command = argv[0];
|
|
56
186
|
|
|
@@ -67,6 +197,14 @@ if (command === "stop") {
|
|
|
67
197
|
runStop(argv.slice(1));
|
|
68
198
|
}
|
|
69
199
|
|
|
200
|
+
if (command === "upgrade" || command === "update") {
|
|
201
|
+
runUpgrade(argv.slice(1));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (command === "version" || command === "--version" || command === "-v") {
|
|
205
|
+
runVersion();
|
|
206
|
+
}
|
|
207
|
+
|
|
70
208
|
console.error(`error: unknown command '${command}'`);
|
|
71
209
|
printUsage();
|
|
72
210
|
process.exit(1);
|