agentstuff 0.1.2 → 0.1.3
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 +1 -1
- package/dist/index.js +207 -55
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ bun add --global agentstuff
|
|
|
11
11
|
agentstuff setup
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Setup
|
|
14
|
+
Setup starts with two paths: a complete guided setup or a fast desktop repair. Complete setup walks through the iPhone, desktop integration, and terminal shortcut as separate numbered steps. Existing configuration is detected at every step, so you can show the current pairing code, rotate it, keep a healthy integration, or change the shortcut without redoing unrelated setup.
|
|
15
15
|
|
|
16
16
|
When run from an Agentstuff development checkout, the wizard can build and install the iOS development app with Xcode. A configured `AGENTSTUFF_MOBILE_INSTALL_URL` enables the public mobile-download option. Until a TestFlight or App Store build is configured, npm cannot install a signed iOS app by itself.
|
|
17
17
|
|
package/dist/index.js
CHANGED
|
@@ -39569,6 +39569,65 @@ var runWith2 = (command, config) => {
|
|
|
39569
39569
|
yield* provideContext2(program, services);
|
|
39570
39570
|
}, catchFilter2((error2) => isCliError(error2) && error2._tag === "ShowHelp" ? succeed2(error2) : fail2(error2), (error2) => andThen2(showHelp(command, error2), fail6(error2))), catchFilter2((e) => isQuitError(e) ? succeed2(e) : fail2(e), (_) => interrupt3));
|
|
39571
39571
|
};
|
|
39572
|
+
// package.json
|
|
39573
|
+
var package_default = {
|
|
39574
|
+
name: "agentstuff",
|
|
39575
|
+
version: "0.1.3",
|
|
39576
|
+
description: "Continue terminal agent sessions securely from your phone",
|
|
39577
|
+
license: "UNLICENSED",
|
|
39578
|
+
type: "module",
|
|
39579
|
+
os: ["darwin"],
|
|
39580
|
+
engines: {
|
|
39581
|
+
bun: ">=1.3.10"
|
|
39582
|
+
},
|
|
39583
|
+
files: [
|
|
39584
|
+
"dist",
|
|
39585
|
+
"README.md"
|
|
39586
|
+
],
|
|
39587
|
+
bin: {
|
|
39588
|
+
agentstuff: "dist/index.js"
|
|
39589
|
+
},
|
|
39590
|
+
repository: {
|
|
39591
|
+
type: "git",
|
|
39592
|
+
url: "git+https://github.com/swarajbachu/agent-stuff.git",
|
|
39593
|
+
directory: "apps/daemon"
|
|
39594
|
+
},
|
|
39595
|
+
homepage: "https://github.com/swarajbachu/agent-stuff#readme",
|
|
39596
|
+
bugs: "https://github.com/swarajbachu/agent-stuff/issues",
|
|
39597
|
+
keywords: [
|
|
39598
|
+
"ai",
|
|
39599
|
+
"agent",
|
|
39600
|
+
"mobile",
|
|
39601
|
+
"terminal",
|
|
39602
|
+
"bun"
|
|
39603
|
+
],
|
|
39604
|
+
scripts: {
|
|
39605
|
+
build: "bun build src/index.ts --outdir dist --target bun",
|
|
39606
|
+
dev: "bun --watch src/index.ts start",
|
|
39607
|
+
prepack: "bun run build",
|
|
39608
|
+
start: "bun src/index.ts start",
|
|
39609
|
+
"test:relay-client": "bun scripts/relay-client.ts",
|
|
39610
|
+
"spike:claude-resume": "bun scripts/claude-resume.ts",
|
|
39611
|
+
"spike:codex-app-server": "bun scripts/codex-app-server.ts",
|
|
39612
|
+
test: "bun test src",
|
|
39613
|
+
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
39614
|
+
},
|
|
39615
|
+
devDependencies: {
|
|
39616
|
+
"@agentstuff/crypto": "workspace:*",
|
|
39617
|
+
"@agentstuff/protocol": "workspace:*",
|
|
39618
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.0",
|
|
39619
|
+
"@effect/platform-bun": "4.0.0-beta.97",
|
|
39620
|
+
"@effect/sql-sqlite-bun": "4.0.0-beta.97",
|
|
39621
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
39622
|
+
chokidar: "^4.0.0",
|
|
39623
|
+
effect: "4.0.0-beta.97",
|
|
39624
|
+
"qrcode-terminal": "^0.12.0",
|
|
39625
|
+
zod: "4.4.3",
|
|
39626
|
+
"@types/bun": "^1.3.14",
|
|
39627
|
+
"@types/qrcode-terminal": "^0.12.2"
|
|
39628
|
+
}
|
|
39629
|
+
};
|
|
39630
|
+
|
|
39572
39631
|
// src/adapters/AdapterRegistry.ts
|
|
39573
39632
|
class AdapterNotFound extends TaggedErrorClass()("AdapterNotFound", {
|
|
39574
39633
|
provider: String4
|
|
@@ -82105,6 +82164,23 @@ var installedShellCommand = fn2("ShellIntegration.status")(function* (path5 = sh
|
|
|
82105
82164
|
});
|
|
82106
82165
|
|
|
82107
82166
|
// src/setup.ts
|
|
82167
|
+
var pairingActions = (hasExistingPairing) => hasExistingPairing ? ["show", "rotate", "keep"] : ["create"];
|
|
82168
|
+
var pairingPromptChoice = (action2, phoneConnected) => {
|
|
82169
|
+
switch (action2) {
|
|
82170
|
+
case "create":
|
|
82171
|
+
return { title: "Create a pairing code", value: action2, description: "Securely connect this Mac and iPhone" };
|
|
82172
|
+
case "show":
|
|
82173
|
+
return { title: "Show the current pairing code", value: action2, description: "Existing paired phones keep working" };
|
|
82174
|
+
case "rotate":
|
|
82175
|
+
return { title: "Generate a new pairing code", value: action2, description: "Revokes every previously shared code" };
|
|
82176
|
+
case "keep":
|
|
82177
|
+
return {
|
|
82178
|
+
title: "Keep the current pairing",
|
|
82179
|
+
value: action2,
|
|
82180
|
+
description: phoneConnected ? "An authenticated iPhone is connected" : "Skip showing a pairing code"
|
|
82181
|
+
};
|
|
82182
|
+
}
|
|
82183
|
+
};
|
|
82108
82184
|
var setupErrorMessage = (error52) => {
|
|
82109
82185
|
if (isObject(error52) && hasProperty(error52, "_tag") && error52._tag === "QuitError") {
|
|
82110
82186
|
return "Setup cancelled.";
|
|
@@ -82126,8 +82202,8 @@ var MobileInstallUrl = String4.pipe(check(makeFilter2((value2) => {
|
|
|
82126
82202
|
var decodeMobileInstallUrl = decodeUnknownOption2(MobileInstallUrl);
|
|
82127
82203
|
var setupSections = (mode) => ({
|
|
82128
82204
|
desktop: mode === "complete" || mode === "repair",
|
|
82129
|
-
shortcut: mode === "complete"
|
|
82130
|
-
phone: mode === "complete"
|
|
82205
|
+
shortcut: mode === "complete",
|
|
82206
|
+
phone: mode === "complete"
|
|
82131
82207
|
});
|
|
82132
82208
|
var findMobileProject = (start = process.cwd(), exists = existsSync3) => {
|
|
82133
82209
|
let directory4 = resolve6(start);
|
|
@@ -82149,10 +82225,8 @@ var selectMode = fn2("Setup.selectMode")(function* (yes) {
|
|
|
82149
82225
|
return yield* exports_Prompt.select({
|
|
82150
82226
|
message: "What would you like to set up?",
|
|
82151
82227
|
choices: [
|
|
82152
|
-
{ title: "Complete setup", value: "complete", description: "
|
|
82153
|
-
{ title: "Repair
|
|
82154
|
-
{ title: "Pair an iPhone", value: "pair", description: "Install or open the mobile app and show a pairing code" },
|
|
82155
|
-
{ title: "Configure terminal shortcut", value: "shortcut", description: "Choose the command used to start connected sessions" }
|
|
82228
|
+
{ title: "Complete setup", value: "complete", description: "Walk through iPhone, desktop, and terminal setup" },
|
|
82229
|
+
{ title: "Repair setup", value: "repair", description: "Reinstall the background service and live terminal integration" }
|
|
82156
82230
|
]
|
|
82157
82231
|
});
|
|
82158
82232
|
});
|
|
@@ -82165,10 +82239,27 @@ var runCommand = fn2("Setup.runCommand")(function* (executable2, arguments_, cwd
|
|
|
82165
82239
|
stderr: "inherit"
|
|
82166
82240
|
}));
|
|
82167
82241
|
});
|
|
82168
|
-
var configureShortcut = fn2("Setup.configureShortcut")(function* (options) {
|
|
82242
|
+
var configureShortcut = fn2("Setup.configureShortcut")(function* (options, existingCommand) {
|
|
82169
82243
|
if (options.noAlias)
|
|
82170
82244
|
return none2();
|
|
82171
82245
|
let commandName = getOrUndefined(options.alias);
|
|
82246
|
+
if (!options.yes && commandName === undefined && existingCommand !== undefined) {
|
|
82247
|
+
const action2 = yield* exports_Prompt.select({
|
|
82248
|
+
message: `Terminal shortcut \`${existingCommand}\` is already configured.`,
|
|
82249
|
+
choices: [
|
|
82250
|
+
{ title: `Keep ${existingCommand}`, value: "keep", description: "No shell changes needed" },
|
|
82251
|
+
{ title: "Choose a different shortcut", value: "change", description: "Replace the current Agentstuff shortcut" }
|
|
82252
|
+
]
|
|
82253
|
+
});
|
|
82254
|
+
if (action2 === "keep") {
|
|
82255
|
+
yield* log(`\u2713 Terminal shortcut: ${existingCommand}`);
|
|
82256
|
+
return some2(existingCommand);
|
|
82257
|
+
}
|
|
82258
|
+
commandName = yield* exports_Prompt.text({
|
|
82259
|
+
message: "New shortcut name",
|
|
82260
|
+
default: existingCommand === "agt" ? "astuff" : "agt"
|
|
82261
|
+
});
|
|
82262
|
+
}
|
|
82172
82263
|
if (!options.yes && commandName === undefined) {
|
|
82173
82264
|
const choice5 = yield* exports_Prompt.select({
|
|
82174
82265
|
message: "How should connected terminal sessions start?",
|
|
@@ -82259,69 +82350,130 @@ var runGuidedSetup = fn2("Setup.run")(function* (options) {
|
|
|
82259
82350
|
yield* log("");
|
|
82260
82351
|
const mode = yield* selectMode(options.yes);
|
|
82261
82352
|
const sections = setupSections(mode);
|
|
82262
|
-
if (
|
|
82353
|
+
if (mode === "repair" && !claudeFound) {
|
|
82263
82354
|
yield* error("Claude CLI is required for live terminal integration. Install it, then rerun setup.");
|
|
82264
82355
|
return;
|
|
82265
82356
|
}
|
|
82266
|
-
let rotate = options.reset;
|
|
82267
|
-
if (sections.phone && isSome2(existing) && !options.yes && !options.reset) {
|
|
82268
|
-
rotate = yield* exports_Prompt.select({
|
|
82269
|
-
message: "Which pairing credential should this phone use?",
|
|
82270
|
-
choices: [
|
|
82271
|
-
{ title: "Keep the current pairing", value: false, description: "Existing paired phones keep working" },
|
|
82272
|
-
{ title: "Rotate the pairing", value: true, description: "Revokes every previously shared pairing code" }
|
|
82273
|
-
]
|
|
82274
|
-
});
|
|
82275
|
-
}
|
|
82276
82357
|
const relayUrl = getOrUndefined(options.relay);
|
|
82358
|
+
const presencePath = join8(options.dataDirectory, "mobile-presence.json");
|
|
82359
|
+
let daemonRunning = daemon.installed;
|
|
82360
|
+
let integrationReady = integrationInstalled;
|
|
82361
|
+
let phoneConnected = yield* loadMobilePresence(presencePath).pipe(catch_2(() => succeed7(false)));
|
|
82277
82362
|
let configured = none2();
|
|
82278
|
-
|
|
82279
|
-
|
|
82363
|
+
const ensurePairing = fn2("Setup.ensurePairing")(function* (reset2) {
|
|
82364
|
+
const result3 = yield* configurePairing({
|
|
82280
82365
|
...relayUrl === undefined ? {} : { relayUrl },
|
|
82281
|
-
reset:
|
|
82282
|
-
})
|
|
82283
|
-
|
|
82284
|
-
|
|
82285
|
-
|
|
82286
|
-
|
|
82287
|
-
|
|
82288
|
-
|
|
82289
|
-
|
|
82290
|
-
|
|
82291
|
-
yield* log("\u2713 Background service");
|
|
82292
|
-
} else if (sections.phone && !daemon.installed) {
|
|
82293
|
-
yield* installDaemon({ dataDirectory: options.dataDirectory, load: true });
|
|
82294
|
-
yield* log("\u2713 Background service");
|
|
82295
|
-
}
|
|
82296
|
-
const shortcut = sections.shortcut ? yield* configureShortcut(options) : none2();
|
|
82297
|
-
let phoneConnected = false;
|
|
82298
|
-
if (sections.phone && !options.noPair && isSome2(configured) && (yield* prepareMobileApp(options.yes))) {
|
|
82366
|
+
reset: reset2
|
|
82367
|
+
});
|
|
82368
|
+
if (result3.changed) {
|
|
82369
|
+
phoneConnected = false;
|
|
82370
|
+
yield* saveMobilePresence(false, presencePath);
|
|
82371
|
+
}
|
|
82372
|
+
configured = some2(result3);
|
|
82373
|
+
return result3;
|
|
82374
|
+
});
|
|
82375
|
+
if (sections.phone) {
|
|
82299
82376
|
yield* log(`
|
|
82377
|
+
Step 1 of 3 \xB7 Connect your iPhone
|
|
82378
|
+
`);
|
|
82379
|
+
if (options.noPair) {
|
|
82380
|
+
yield* log("\xB7 Phone pairing skipped by --no-pair");
|
|
82381
|
+
} else {
|
|
82382
|
+
const hasExistingPairing = isSome2(existing);
|
|
82383
|
+
const pairingAction = options.reset ? "rotate" : options.yes ? hasExistingPairing ? "show" : "create" : hasExistingPairing ? yield* exports_Prompt.select({
|
|
82384
|
+
message: "Mobile pairing is already configured. What should we do?",
|
|
82385
|
+
choices: pairingActions(true).map((action2) => pairingPromptChoice(action2, phoneConnected))
|
|
82386
|
+
}) : "create";
|
|
82387
|
+
if (pairingAction === "keep") {
|
|
82388
|
+
yield* log(`\u2713 Current pairing kept${phoneConnected ? " \xB7 iPhone connected" : ""}`);
|
|
82389
|
+
} else {
|
|
82390
|
+
const pairing = yield* ensurePairing(pairingAction === "rotate");
|
|
82391
|
+
if (pairing.changed && daemonRunning)
|
|
82392
|
+
yield* restartDaemon();
|
|
82393
|
+
if (!daemonRunning) {
|
|
82394
|
+
yield* installDaemon({ dataDirectory: options.dataDirectory, load: true });
|
|
82395
|
+
daemonRunning = true;
|
|
82396
|
+
yield* log("\u2713 Background service started for pairing");
|
|
82397
|
+
}
|
|
82398
|
+
if (yield* prepareMobileApp(options.yes)) {
|
|
82399
|
+
yield* log(`
|
|
82300
82400
|
On your iPhone, open Agentstuff \u2192 Connect your Mac \u2192 Scan pairing code.
|
|
82301
82401
|
`);
|
|
82302
|
-
|
|
82303
|
-
|
|
82304
|
-
|
|
82305
|
-
|
|
82306
|
-
|
|
82307
|
-
|
|
82402
|
+
yield* renderQr(pairingUrl(pairing.pairing));
|
|
82403
|
+
yield* log("Waiting for an authenticated iPhone connection\u2026");
|
|
82404
|
+
phoneConnected = yield* waitForMobilePresence(presencePath, options.yes ? 10 : 60);
|
|
82405
|
+
while (!phoneConnected && !options.yes) {
|
|
82406
|
+
const action2 = yield* exports_Prompt.select({
|
|
82407
|
+
message: "The iPhone has not connected yet.",
|
|
82408
|
+
choices: [
|
|
82409
|
+
{ title: "Wait another 30 seconds", value: "retry", description: "Keep the app open after scanning" },
|
|
82410
|
+
{ title: "Continue setup and pair later", value: "later", description: "The pairing code remains ready" }
|
|
82411
|
+
]
|
|
82412
|
+
});
|
|
82413
|
+
if (action2 === "later")
|
|
82414
|
+
break;
|
|
82415
|
+
phoneConnected = yield* waitForMobilePresence(presencePath, 60);
|
|
82416
|
+
}
|
|
82417
|
+
yield* log(phoneConnected ? "\u2713 Authenticated iPhone connected" : "! Pairing is ready. Scan the code from Agentstuff when your phone is available.");
|
|
82418
|
+
}
|
|
82419
|
+
}
|
|
82420
|
+
}
|
|
82421
|
+
}
|
|
82422
|
+
if (sections.desktop) {
|
|
82423
|
+
yield* log(mode === "complete" ? `
|
|
82424
|
+
Step 2 of 3 \xB7 Configure terminal integration
|
|
82425
|
+
` : `
|
|
82426
|
+
Repairing desktop integration
|
|
82427
|
+
`);
|
|
82428
|
+
if (!claudeFound) {
|
|
82429
|
+
yield* log("! Terminal integration skipped because the required CLI is not installed.");
|
|
82430
|
+
yield* log(" Install it, then choose Repair setup.");
|
|
82431
|
+
} else {
|
|
82432
|
+
const healthy = integrationReady && daemonRunning;
|
|
82433
|
+
const desktopAction = mode === "repair" || options.yes ? "install" : healthy ? yield* exports_Prompt.select({
|
|
82434
|
+
message: "Terminal integration is already running.",
|
|
82308
82435
|
choices: [
|
|
82309
|
-
{ title: "
|
|
82310
|
-
{ title: "
|
|
82436
|
+
{ title: "Keep the current integration", value: "keep", description: "No changes needed" },
|
|
82437
|
+
{ title: "Reinstall the integration", value: "install", description: "Refresh the service and live terminal channel" }
|
|
82438
|
+
]
|
|
82439
|
+
}) : yield* exports_Prompt.select({
|
|
82440
|
+
message: "Terminal integration needs attention.",
|
|
82441
|
+
choices: [
|
|
82442
|
+
{
|
|
82443
|
+
title: "Configure it now",
|
|
82444
|
+
value: "install",
|
|
82445
|
+
description: integrationReady ? "Restart the background service" : "Install the live terminal channel and background service"
|
|
82446
|
+
},
|
|
82447
|
+
{ title: "Skip for now", value: "skip", description: "Finish from Repair setup later" }
|
|
82311
82448
|
]
|
|
82312
82449
|
});
|
|
82313
|
-
if (
|
|
82314
|
-
|
|
82315
|
-
|
|
82316
|
-
|
|
82317
|
-
|
|
82318
|
-
|
|
82450
|
+
if (desktopAction === "install") {
|
|
82451
|
+
if (isNone2(configured))
|
|
82452
|
+
yield* ensurePairing(options.reset && options.noPair);
|
|
82453
|
+
yield* installTerminalIntegration(undefined, true);
|
|
82454
|
+
integrationReady = true;
|
|
82455
|
+
yield* log("\u2713 Live terminal integration configured");
|
|
82456
|
+
yield* installDaemon({ dataDirectory: options.dataDirectory, load: true });
|
|
82457
|
+
daemonRunning = true;
|
|
82458
|
+
yield* log("\u2713 Background service running");
|
|
82459
|
+
} else if (desktopAction === "keep") {
|
|
82460
|
+
yield* log("\u2713 Current terminal integration kept");
|
|
82461
|
+
} else {
|
|
82462
|
+
yield* log("\xB7 Terminal integration skipped");
|
|
82463
|
+
}
|
|
82319
82464
|
}
|
|
82320
82465
|
}
|
|
82321
|
-
|
|
82466
|
+
let shortcut = none2();
|
|
82467
|
+
if (sections.shortcut) {
|
|
82468
|
+
yield* log(`
|
|
82469
|
+
Step 3 of 3 \xB7 Configure terminal shortcut
|
|
82470
|
+
`);
|
|
82471
|
+
shortcut = yield* configureShortcut(options, shellCommand);
|
|
82472
|
+
}
|
|
82473
|
+
const launchCommand = getOrElse(shortcut, () => shellCommand ?? "agentstuff claude");
|
|
82322
82474
|
yield* log(`
|
|
82323
82475
|
Ready.`);
|
|
82324
|
-
if (
|
|
82476
|
+
if (integrationReady && daemonRunning)
|
|
82325
82477
|
yield* log(" \u2713 Desktop integration running");
|
|
82326
82478
|
if (phoneConnected)
|
|
82327
82479
|
yield* log(" \u2713 iPhone connected");
|
|
@@ -85030,5 +85182,5 @@ if (rawCommand === "terminal" || rawCommand === "claude") {
|
|
|
85030
85182
|
process.exitCode = exitCode;
|
|
85031
85183
|
})), asVoid2, provide4(exports_BunServices.layer)));
|
|
85032
85184
|
} else {
|
|
85033
|
-
cli.pipe(exports_Command.run({ version:
|
|
85185
|
+
cli.pipe(exports_Command.run({ version: package_default.version }), provide4(exports_BunServices.layer), exports_BunRuntime.runMain);
|
|
85034
85186
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentstuff",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Continue terminal agent sessions securely from your phone",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"README.md"
|
|
14
14
|
],
|
|
15
15
|
"bin": {
|
|
16
|
-
"agentstuff": "
|
|
16
|
+
"agentstuff": "dist/index.js"
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@agentstuff/crypto": "
|
|
45
|
-
"@agentstuff/protocol": "
|
|
44
|
+
"@agentstuff/crypto": "workspace:*",
|
|
45
|
+
"@agentstuff/protocol": "workspace:*",
|
|
46
46
|
"@anthropic-ai/claude-agent-sdk": "^0.3.0",
|
|
47
47
|
"@effect/platform-bun": "4.0.0-beta.97",
|
|
48
48
|
"@effect/sql-sqlite-bun": "4.0.0-beta.97",
|