taskdex 0.1.3 → 0.1.5
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 +5 -0
- package/package.json +1 -1
- package/scripts/taskdex.mjs +86 -1
package/README.md
CHANGED
|
@@ -38,6 +38,11 @@ This will clone the repo and immediately run interactive terminal setup.
|
|
|
38
38
|
Setup now defaults to `dev-client` runtime, can build the native app (`expo run:ios` / `expo run:android`), and then starts Expo in `--dev-client` mode.
|
|
39
39
|
For iOS builds, setup asks whether to run on a real iPhone or Simulator, and supports choosing a specific iPhone device name.
|
|
40
40
|
When a `pnpm-lock.yaml` is present in `mobile`, the CLI installs mobile dependencies with pnpm automatically.
|
|
41
|
+
Setup writes runtime bridge env values into `mobile/.env.local`, sets `CODEX_CWD` for bridge agent workspace, and can pass `OPENAI_API_KEY` if provided.
|
|
42
|
+
Setup also includes Convex mode selection:
|
|
43
|
+
- `new` runs `convex dev --once` automatically
|
|
44
|
+
- `existing` prompts for Convex env values and writes them
|
|
45
|
+
- `skip` leaves Convex untouched (bridge/local state still works, cloud persistence may be limited)
|
|
41
46
|
|
|
42
47
|
For an already-cloned repo:
|
|
43
48
|
|
package/package.json
CHANGED
package/scripts/taskdex.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import crypto from 'node:crypto';
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
5
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import os from 'node:os';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import process from 'node:process';
|
|
@@ -174,6 +174,34 @@ function parseInstallChoice(input) {
|
|
|
174
174
|
throw new Error('Install choice must be Y or N.');
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
function parseConvexMode(input) {
|
|
178
|
+
const normalized = input.trim().toLowerCase() || 'new';
|
|
179
|
+
if (['new', 'setup', 'create'].includes(normalized)) return 'new';
|
|
180
|
+
if (['existing', 'manual'].includes(normalized)) return 'existing';
|
|
181
|
+
if (['skip', 'none'].includes(normalized)) return 'skip';
|
|
182
|
+
throw new Error('Convex setup mode must be "new", "existing", or "skip".');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function upsertEnvVars(envFilePath, values) {
|
|
186
|
+
const keys = Object.keys(values);
|
|
187
|
+
const original = existsSync(envFilePath) ? readFileSync(envFilePath, 'utf8') : '';
|
|
188
|
+
const lines = original ? original.split(/\r?\n/) : [];
|
|
189
|
+
const seen = new Set();
|
|
190
|
+
const updated = lines.map((line) => {
|
|
191
|
+
const match = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=/);
|
|
192
|
+
if (!match) return line;
|
|
193
|
+
const key = match[1];
|
|
194
|
+
if (!keys.includes(key)) return line;
|
|
195
|
+
seen.add(key);
|
|
196
|
+
return `${key}=${values[key]}`;
|
|
197
|
+
});
|
|
198
|
+
for (const key of keys) {
|
|
199
|
+
if (!seen.has(key)) updated.push(`${key}=${values[key]}`);
|
|
200
|
+
}
|
|
201
|
+
const nextContent = `${updated.filter((line) => line !== '').join('\n')}\n`;
|
|
202
|
+
writeFileSync(envFilePath, nextContent, 'utf8');
|
|
203
|
+
}
|
|
204
|
+
|
|
177
205
|
function wait(ms) {
|
|
178
206
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
179
207
|
}
|
|
@@ -188,10 +216,22 @@ async function readSetupConfig() {
|
|
|
188
216
|
const runtimeInput = await rl.question('App runtime (dev-client/expo-go) [dev-client]: ');
|
|
189
217
|
const installInput = await rl.question('Install npm dependencies first? [Y/n]: ');
|
|
190
218
|
const runtime = parseRuntime(runtimeInput);
|
|
219
|
+
const convexModeInput = await rl.question('Convex setup (new/existing/skip) [new]: ');
|
|
220
|
+
const convexMode = parseConvexMode(convexModeInput);
|
|
221
|
+
let convexUrlInput = '';
|
|
222
|
+
let convexDeploymentInput = '';
|
|
223
|
+
let convexSiteUrlInput = '';
|
|
224
|
+
if (convexMode === 'existing') {
|
|
225
|
+
convexUrlInput = (await rl.question('EXPO_PUBLIC_CONVEX_URL: ')).trim();
|
|
226
|
+
convexDeploymentInput = (await rl.question('CONVEX_DEPLOYMENT (optional): ')).trim();
|
|
227
|
+
convexSiteUrlInput = (await rl.question('EXPO_PUBLIC_CONVEX_SITE_URL (optional): ')).trim();
|
|
228
|
+
}
|
|
191
229
|
let buildDevClient = false;
|
|
192
230
|
let buildPlatform = process.platform === 'darwin' ? 'ios' : 'android';
|
|
193
231
|
let iosTarget = 'iphone';
|
|
194
232
|
let iosDeviceName = '';
|
|
233
|
+
const openAiApiKey = (await rl.question('OPENAI_API_KEY (optional, Enter to use current shell/Codex login): ')).trim();
|
|
234
|
+
const workspaceInput = (await rl.question('Agent workspace path [repo root]: ')).trim();
|
|
195
235
|
if (runtime === 'dev-client') {
|
|
196
236
|
const buildInput = await rl.question('Build native development client now? [Y/n]: ');
|
|
197
237
|
buildDevClient = parseInstallChoice(buildInput);
|
|
@@ -213,10 +253,16 @@ async function readSetupConfig() {
|
|
|
213
253
|
apiKey: apiKeyInput.trim() || crypto.randomBytes(24).toString('hex'),
|
|
214
254
|
expoMode: parseExpoMode(expoModeInput),
|
|
215
255
|
runtime,
|
|
256
|
+
convexMode,
|
|
257
|
+
convexUrlInput,
|
|
258
|
+
convexDeploymentInput,
|
|
259
|
+
convexSiteUrlInput,
|
|
216
260
|
buildDevClient,
|
|
217
261
|
buildPlatform,
|
|
218
262
|
iosTarget,
|
|
219
263
|
iosDeviceName,
|
|
264
|
+
openAiApiKey,
|
|
265
|
+
workspaceInput,
|
|
220
266
|
installDeps: parseInstallChoice(installInput),
|
|
221
267
|
};
|
|
222
268
|
} finally {
|
|
@@ -236,16 +282,31 @@ async function runInteractiveSetup(rootDir) {
|
|
|
236
282
|
apiKey,
|
|
237
283
|
expoMode,
|
|
238
284
|
runtime,
|
|
285
|
+
convexMode,
|
|
286
|
+
convexUrlInput,
|
|
287
|
+
convexDeploymentInput,
|
|
288
|
+
convexSiteUrlInput,
|
|
239
289
|
buildDevClient,
|
|
240
290
|
buildPlatform,
|
|
241
291
|
iosTarget,
|
|
242
292
|
iosDeviceName,
|
|
293
|
+
openAiApiKey,
|
|
294
|
+
workspaceInput,
|
|
243
295
|
installDeps,
|
|
244
296
|
} = await readSetupConfig();
|
|
245
297
|
const bridgeUrl = `ws://${getLocalIPv4()}:${port}`;
|
|
298
|
+
const workspacePath = workspaceInput ? path.resolve(workspaceInput) : rootDir;
|
|
299
|
+
|
|
300
|
+
if (!existsSync(workspacePath)) {
|
|
301
|
+
throw new Error(`Workspace path does not exist: ${workspacePath}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const envFilePath = path.join(mobileDir, '.env.local');
|
|
246
305
|
|
|
247
306
|
console.log(`\nBridge URL: ${bridgeUrl}`);
|
|
248
307
|
console.log(`Bridge API key: ${apiKey}`);
|
|
308
|
+
console.log(`Agent workspace: ${workspacePath}`);
|
|
309
|
+
console.log(`Convex mode: ${convexMode}`);
|
|
249
310
|
console.log(`Expo mode: ${expoMode}\n`);
|
|
250
311
|
|
|
251
312
|
if (installDeps) {
|
|
@@ -257,6 +318,28 @@ async function runInteractiveSetup(rootDir) {
|
|
|
257
318
|
await installMobileDependencies(mobileDir);
|
|
258
319
|
}
|
|
259
320
|
|
|
321
|
+
if (convexMode === 'new') {
|
|
322
|
+
console.log('\nSetting up Convex deployment...\n');
|
|
323
|
+
await runCommand(npxCmd, ['-y', 'convex', 'dev', '--once'], { cwd: mobileDir });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (convexMode === 'existing') {
|
|
327
|
+
if (!convexUrlInput) {
|
|
328
|
+
throw new Error('EXPO_PUBLIC_CONVEX_URL is required when Convex mode is "existing".');
|
|
329
|
+
}
|
|
330
|
+
const convexValues = {
|
|
331
|
+
EXPO_PUBLIC_CONVEX_URL: convexUrlInput,
|
|
332
|
+
...(convexDeploymentInput ? { CONVEX_DEPLOYMENT: convexDeploymentInput } : {}),
|
|
333
|
+
...(convexSiteUrlInput ? { EXPO_PUBLIC_CONVEX_SITE_URL: convexSiteUrlInput } : {}),
|
|
334
|
+
};
|
|
335
|
+
upsertEnvVars(envFilePath, convexValues);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
upsertEnvVars(envFilePath, {
|
|
339
|
+
EXPO_PUBLIC_BRIDGE_URL: bridgeUrl,
|
|
340
|
+
EXPO_PUBLIC_BRIDGE_API_KEY: apiKey,
|
|
341
|
+
});
|
|
342
|
+
|
|
260
343
|
console.log('\nStarting bridge server...\n');
|
|
261
344
|
const bridgeProcess = spawn(npmCmd, ['run', 'dev'], {
|
|
262
345
|
cwd: bridgeDir,
|
|
@@ -265,6 +348,8 @@ async function runInteractiveSetup(rootDir) {
|
|
|
265
348
|
...process.env,
|
|
266
349
|
PORT: String(port),
|
|
267
350
|
API_KEY: apiKey,
|
|
351
|
+
CODEX_CWD: workspacePath,
|
|
352
|
+
...(openAiApiKey ? { OPENAI_API_KEY: openAiApiKey } : {}),
|
|
268
353
|
},
|
|
269
354
|
});
|
|
270
355
|
|