@agentproto/cli 0.9.0 → 0.10.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 +1 -1
- package/dist/cli.mjs +318 -74
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +308 -67
- package/dist/index.mjs.map +1 -1
- package/dist/registry/builtins.mjs +1 -1
- package/dist/registry/manifest.mjs +1 -1
- package/dist/registry/plugins.mjs +1 -1
- package/dist/registry/runtime.mjs +1 -1
- package/dist/util/credentials.mjs +1 -1
- package/package.json +16 -16
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { rm, readFile, mkdir, writeFile, readdir, mkdtemp, chmod, stat, cp, unli
|
|
|
6
6
|
import { homedir, tmpdir, userInfo, hostname, platform } from 'os';
|
|
7
7
|
import { isAbsolute, join, dirname, resolve, delimiter, basename, normalize, relative } from 'path';
|
|
8
8
|
import { promisify, parseArgs } from 'util';
|
|
9
|
-
import { createReadStream, promises, constants, readFileSync, existsSync, chmodSync, mkdirSync, writeFileSync, accessSync, readdirSync, renameSync, createWriteStream, statSync, openSync, closeSync } from 'fs';
|
|
9
|
+
import { createReadStream, promises, constants, readFileSync, existsSync, chmodSync, mkdirSync, writeFileSync, accessSync, readdirSync, renameSync, createWriteStream, statSync, realpathSync, openSync, closeSync } from 'fs';
|
|
10
10
|
import { createRequire as createRequire$1 } from 'module';
|
|
11
11
|
import { pathToFileURL, fileURLToPath } from 'url';
|
|
12
12
|
import { collectAgentprotoNamespaceRoots, makeAdapterResolver, makeSetupLedger, makeAdapterLister, makeAdapterWizard, discoverAdapterPackages, makeCredsStore, makeListTool, makeSetupTool, computeStatus } from '@agentproto/provider-kit';
|
|
@@ -39,7 +39,7 @@ import { stdout, stdin } from 'process';
|
|
|
39
39
|
import { getBrowserAdapter, browserAdapters } from '@agentproto/adapter-browser';
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* @agentproto/cli v0.
|
|
42
|
+
* @agentproto/cli v0.10.0
|
|
43
43
|
* The `agentproto` binary — install / run / serve AIP-45 agent CLIs.
|
|
44
44
|
*/
|
|
45
45
|
// Provide a real `require` in the ESM bundle. Some bundled deps (e.g.
|
|
@@ -15035,9 +15035,18 @@ function isWorkflowHandle(v2) {
|
|
|
15035
15035
|
}
|
|
15036
15036
|
async function importEntryHandle(workflowMdPath, entry) {
|
|
15037
15037
|
const abs = isAbsolute(entry) ? entry : join(dirname(workflowMdPath), entry);
|
|
15038
|
+
let href = pathToFileURL(abs).href;
|
|
15039
|
+
if (!process.env.VITEST) {
|
|
15040
|
+
try {
|
|
15041
|
+
const url = pathToFileURL(abs);
|
|
15042
|
+
url.searchParams.set("v", String((await stat(abs)).mtimeMs));
|
|
15043
|
+
href = url.href;
|
|
15044
|
+
} catch {
|
|
15045
|
+
}
|
|
15046
|
+
}
|
|
15038
15047
|
let mod;
|
|
15039
15048
|
try {
|
|
15040
|
-
mod = await import(
|
|
15049
|
+
mod = await import(href);
|
|
15041
15050
|
} catch (err) {
|
|
15042
15051
|
throw new WorkflowLoadError(
|
|
15043
15052
|
`cannot import entry '${entry}': ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -17350,9 +17359,19 @@ function setActiveWorkspace(config, slug) {
|
|
|
17350
17359
|
function findWorkspace(config, slug) {
|
|
17351
17360
|
return config.workspaces.find((w) => w.slug === sanitizeSlug(slug));
|
|
17352
17361
|
}
|
|
17362
|
+
function canonical(p2) {
|
|
17363
|
+
try {
|
|
17364
|
+
return realpathSync(resolve(p2));
|
|
17365
|
+
} catch {
|
|
17366
|
+
return resolve(p2);
|
|
17367
|
+
}
|
|
17368
|
+
}
|
|
17353
17369
|
function findWorkspaceByPath(config, dir) {
|
|
17354
|
-
const resolved =
|
|
17355
|
-
const candidates2 = config.workspaces.filter((w) =>
|
|
17370
|
+
const resolved = canonical(dir);
|
|
17371
|
+
const candidates2 = config.workspaces.filter((w) => {
|
|
17372
|
+
const wPath = canonical(w.path);
|
|
17373
|
+
return resolved.startsWith(wPath + "/") || resolved === wPath;
|
|
17374
|
+
}).sort((a, b2) => b2.path.length - a.path.length);
|
|
17356
17375
|
return candidates2[0];
|
|
17357
17376
|
}
|
|
17358
17377
|
function getActiveWorkspace(config) {
|
|
@@ -17438,6 +17457,76 @@ async function loadConfig(path) {
|
|
|
17438
17457
|
return {};
|
|
17439
17458
|
}
|
|
17440
17459
|
}
|
|
17460
|
+
var markerSchema = z.object({ worktreeId: z.string() });
|
|
17461
|
+
function statOrUndefined(path) {
|
|
17462
|
+
try {
|
|
17463
|
+
return statSync(path);
|
|
17464
|
+
} catch {
|
|
17465
|
+
return void 0;
|
|
17466
|
+
}
|
|
17467
|
+
}
|
|
17468
|
+
function readWorktreeGitDir(dir) {
|
|
17469
|
+
const link = (() => {
|
|
17470
|
+
try {
|
|
17471
|
+
return readFileSync(join(dir, ".git"), "utf8");
|
|
17472
|
+
} catch {
|
|
17473
|
+
return void 0;
|
|
17474
|
+
}
|
|
17475
|
+
})();
|
|
17476
|
+
if (link === void 0) return void 0;
|
|
17477
|
+
const target = /^gitdir:\s*(.+)$/m.exec(link)?.[1]?.trim();
|
|
17478
|
+
if (!target) return void 0;
|
|
17479
|
+
const gitDir = isAbsolute(target) ? target : resolve(dir, target);
|
|
17480
|
+
return statOrUndefined(join(gitDir, "gitdir"))?.isFile() === true ? gitDir : void 0;
|
|
17481
|
+
}
|
|
17482
|
+
function readMainRepoPath(gitDir) {
|
|
17483
|
+
let raw;
|
|
17484
|
+
try {
|
|
17485
|
+
raw = readFileSync(join(gitDir, "commondir"), "utf8").trim();
|
|
17486
|
+
} catch {
|
|
17487
|
+
return void 0;
|
|
17488
|
+
}
|
|
17489
|
+
if (!raw) return void 0;
|
|
17490
|
+
const commonGitDir = isAbsolute(raw) ? raw : resolve(gitDir, raw);
|
|
17491
|
+
return dirname(commonGitDir);
|
|
17492
|
+
}
|
|
17493
|
+
function readWorktreeId(gitDir) {
|
|
17494
|
+
let raw;
|
|
17495
|
+
try {
|
|
17496
|
+
raw = readFileSync(join(gitDir, "agentproto-worktree.json"), "utf8");
|
|
17497
|
+
} catch {
|
|
17498
|
+
return void 0;
|
|
17499
|
+
}
|
|
17500
|
+
let parsed;
|
|
17501
|
+
try {
|
|
17502
|
+
parsed = JSON.parse(raw);
|
|
17503
|
+
} catch {
|
|
17504
|
+
return void 0;
|
|
17505
|
+
}
|
|
17506
|
+
const result = markerSchema.safeParse(parsed);
|
|
17507
|
+
return result.success ? result.data.worktreeId : void 0;
|
|
17508
|
+
}
|
|
17509
|
+
function resolveWorktreeIdentity(cwd) {
|
|
17510
|
+
let dir = resolve(cwd);
|
|
17511
|
+
for (; ; ) {
|
|
17512
|
+
const dotGit = statOrUndefined(join(dir, ".git"));
|
|
17513
|
+
if (dotGit) {
|
|
17514
|
+
if (!dotGit.isFile()) return void 0;
|
|
17515
|
+
const gitDir = readWorktreeGitDir(dir);
|
|
17516
|
+
if (gitDir === void 0) return void 0;
|
|
17517
|
+
const worktreeId = readWorktreeId(gitDir);
|
|
17518
|
+
const mainRepoPath = readMainRepoPath(gitDir);
|
|
17519
|
+
return {
|
|
17520
|
+
worktreePath: dir,
|
|
17521
|
+
...worktreeId === void 0 ? {} : { worktreeId },
|
|
17522
|
+
...mainRepoPath === void 0 ? {} : { mainRepoPath }
|
|
17523
|
+
};
|
|
17524
|
+
}
|
|
17525
|
+
const parent = dirname(dir);
|
|
17526
|
+
if (parent === dir) return void 0;
|
|
17527
|
+
dir = parent;
|
|
17528
|
+
}
|
|
17529
|
+
}
|
|
17441
17530
|
var providers_store_exports = {};
|
|
17442
17531
|
__reExport(providers_store_exports, dist_exports);
|
|
17443
17532
|
function resolveSpawnDefaults(defaults, adapterSlug, input2) {
|
|
@@ -17988,15 +18077,38 @@ async function spawnAgentSession(deps2, input2) {
|
|
|
17988
18077
|
try {
|
|
17989
18078
|
const config = await loadWorkspacesConfig();
|
|
17990
18079
|
if (!cwd) {
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
18080
|
+
if (input2.workspaceSlug) {
|
|
18081
|
+
const ws = findWorkspace(config, input2.workspaceSlug);
|
|
18082
|
+
if (ws) {
|
|
18083
|
+
cwd = ws.path;
|
|
18084
|
+
resolvedSlug = ws.slug;
|
|
18085
|
+
}
|
|
18086
|
+
} else if (callerScope) {
|
|
18087
|
+
const parentCwd = callerScope.ownerSessionId ? registry.get(callerScope.ownerSessionId)?.cwd : void 0;
|
|
18088
|
+
if (parentCwd) {
|
|
18089
|
+
cwd = parentCwd;
|
|
18090
|
+
const ws = findWorkspaceByPath(config, parentCwd);
|
|
18091
|
+
if (ws) {
|
|
18092
|
+
resolvedSlug = ws.slug;
|
|
18093
|
+
}
|
|
18094
|
+
}
|
|
18095
|
+
} else {
|
|
18096
|
+
const ws = getActiveWorkspace(config);
|
|
18097
|
+
if (ws) {
|
|
18098
|
+
cwd = ws.path;
|
|
18099
|
+
resolvedSlug = ws.slug;
|
|
18100
|
+
}
|
|
17995
18101
|
}
|
|
17996
18102
|
} else if (!resolvedSlug) {
|
|
17997
18103
|
const ws = findWorkspaceByPath(config, cwd);
|
|
17998
18104
|
if (ws) {
|
|
17999
18105
|
resolvedSlug = ws.slug;
|
|
18106
|
+
} else {
|
|
18107
|
+
const identity = resolveWorktreeIdentity(cwd);
|
|
18108
|
+
if (identity?.mainRepoPath) {
|
|
18109
|
+
const baseWs = findWorkspaceByPath(config, identity.mainRepoPath);
|
|
18110
|
+
if (baseWs) resolvedSlug = baseWs.slug;
|
|
18111
|
+
}
|
|
18000
18112
|
}
|
|
18001
18113
|
}
|
|
18002
18114
|
} catch {
|
|
@@ -18202,7 +18314,8 @@ async function spawnAgentSession(deps2, input2) {
|
|
|
18202
18314
|
const effectivePrompt = input2.prompt ? `${composeRoleContext(role, input2.promptAppend, roleRegistry)}
|
|
18203
18315
|
|
|
18204
18316
|
${input2.prompt}` : input2.prompt;
|
|
18205
|
-
const
|
|
18317
|
+
const explicitTitle = input2.title?.trim() ? input2.title.trim() : void 0;
|
|
18318
|
+
const initialTitle = explicitTitle ?? (input2.prompt ? deriveSessionTitle(input2.prompt) : void 0);
|
|
18206
18319
|
let settleClaim;
|
|
18207
18320
|
if (input2.idempotencyKey) {
|
|
18208
18321
|
const claims = claimsFor(registry);
|
|
@@ -21013,6 +21126,90 @@ function registerSessionTools(rawServer, opts) {
|
|
|
21013
21126
|
}
|
|
21014
21127
|
}
|
|
21015
21128
|
);
|
|
21129
|
+
server.tool(
|
|
21130
|
+
"session_rename",
|
|
21131
|
+
"Set or clear a session's user-facing name \u2014 the label the sessions tree, transcript header, and tab show. `label` out-ranks `title` in that display chain, so a user rename should write `label` (the default a UI picks) to be sure it shows; `title` is the auto-derived first-sentence fallback. For EACH of `title`/`label`: a non-empty string sets it (trimmed + length-capped), an empty string clears it (reverting to the derived title / a friendly `adapter \xB7 id` fallback), and omitting it leaves that field untouched. Persists across daemon restarts. Does NOT rename the adapter-native session or touch the running agent.",
|
|
21132
|
+
{
|
|
21133
|
+
idOrName: z.string().min(1).describe("Session id or name to rename \u2014 from `session_list`."),
|
|
21134
|
+
label: z.string().optional().describe(
|
|
21135
|
+
"New label (the winning display field). Empty string clears it. Omit to leave the label untouched."
|
|
21136
|
+
),
|
|
21137
|
+
title: z.string().optional().describe(
|
|
21138
|
+
"New title (the auto-derived fallback slot). Empty string clears it, reverting to the first-sentence derivation. Omit to leave it untouched."
|
|
21139
|
+
)
|
|
21140
|
+
},
|
|
21141
|
+
async (input2) => {
|
|
21142
|
+
const prev = registry.findByIdOrName(input2.idOrName);
|
|
21143
|
+
if (!prev) {
|
|
21144
|
+
return {
|
|
21145
|
+
content: [
|
|
21146
|
+
{
|
|
21147
|
+
type: "text",
|
|
21148
|
+
text: JSON.stringify({ error: `no session "${input2.idOrName}" found` })
|
|
21149
|
+
}
|
|
21150
|
+
],
|
|
21151
|
+
isError: true
|
|
21152
|
+
};
|
|
21153
|
+
}
|
|
21154
|
+
if (callerScope) {
|
|
21155
|
+
const subtree = collectSubtree(
|
|
21156
|
+
callerScope.ownerSessionId,
|
|
21157
|
+
registry.list({ includeArchived: true })
|
|
21158
|
+
);
|
|
21159
|
+
if (!subtree.has(prev.id)) {
|
|
21160
|
+
return {
|
|
21161
|
+
content: [
|
|
21162
|
+
{
|
|
21163
|
+
type: "text",
|
|
21164
|
+
text: JSON.stringify({
|
|
21165
|
+
error: "orchestrator_session_out_of_scope",
|
|
21166
|
+
message: `session_rename: session "${prev.id}" is not in your subtree \u2014 a scoped orchestrator can only rename sessions it (transitively) spawned.`,
|
|
21167
|
+
ok: false,
|
|
21168
|
+
sessionId: prev.id
|
|
21169
|
+
})
|
|
21170
|
+
}
|
|
21171
|
+
],
|
|
21172
|
+
isError: true
|
|
21173
|
+
};
|
|
21174
|
+
}
|
|
21175
|
+
}
|
|
21176
|
+
if (input2.title === void 0 && input2.label === void 0) {
|
|
21177
|
+
return {
|
|
21178
|
+
content: [
|
|
21179
|
+
{
|
|
21180
|
+
type: "text",
|
|
21181
|
+
text: JSON.stringify({
|
|
21182
|
+
error: "nothing_to_rename",
|
|
21183
|
+
message: "session_rename: supply at least one of `title` or `label`.",
|
|
21184
|
+
ok: false,
|
|
21185
|
+
sessionId: prev.id
|
|
21186
|
+
})
|
|
21187
|
+
}
|
|
21188
|
+
],
|
|
21189
|
+
isError: true
|
|
21190
|
+
};
|
|
21191
|
+
}
|
|
21192
|
+
try {
|
|
21193
|
+
const desc = registry.renameSession(prev.id, {
|
|
21194
|
+
...input2.title !== void 0 ? { title: input2.title } : {},
|
|
21195
|
+
...input2.label !== void 0 ? { label: input2.label } : {}
|
|
21196
|
+
});
|
|
21197
|
+
return {
|
|
21198
|
+
content: [{ type: "text", text: JSON.stringify(desc, null, 2) }]
|
|
21199
|
+
};
|
|
21200
|
+
} catch (err) {
|
|
21201
|
+
return {
|
|
21202
|
+
content: [
|
|
21203
|
+
{
|
|
21204
|
+
type: "text",
|
|
21205
|
+
text: `session_rename: ${err instanceof Error ? err.message : String(err)}`
|
|
21206
|
+
}
|
|
21207
|
+
],
|
|
21208
|
+
isError: true
|
|
21209
|
+
};
|
|
21210
|
+
}
|
|
21211
|
+
}
|
|
21212
|
+
);
|
|
21016
21213
|
server.tool(
|
|
21017
21214
|
"terminal_start",
|
|
21018
21215
|
"Spawn a process under a real PTY (node-pty) on the host. Bytes (including ANSI escapes, alt-screen sequences) flow through the daemon's byte ring buffer; subscribers attach via the WS at /sessions/:id/pty. Use for interactive TUIs (claude, vim, htop) or to orchestrate shells from another agent. Returns the session descriptor.",
|
|
@@ -24221,60 +24418,6 @@ function createTerminalTranscriptWriter(opts) {
|
|
|
24221
24418
|
}
|
|
24222
24419
|
};
|
|
24223
24420
|
}
|
|
24224
|
-
var markerSchema = z.object({ worktreeId: z.string() });
|
|
24225
|
-
function statOrUndefined(path) {
|
|
24226
|
-
try {
|
|
24227
|
-
return statSync(path);
|
|
24228
|
-
} catch {
|
|
24229
|
-
return void 0;
|
|
24230
|
-
}
|
|
24231
|
-
}
|
|
24232
|
-
function readWorktreeGitDir(dir) {
|
|
24233
|
-
const link = (() => {
|
|
24234
|
-
try {
|
|
24235
|
-
return readFileSync(join(dir, ".git"), "utf8");
|
|
24236
|
-
} catch {
|
|
24237
|
-
return void 0;
|
|
24238
|
-
}
|
|
24239
|
-
})();
|
|
24240
|
-
if (link === void 0) return void 0;
|
|
24241
|
-
const target = /^gitdir:\s*(.+)$/m.exec(link)?.[1]?.trim();
|
|
24242
|
-
if (!target) return void 0;
|
|
24243
|
-
const gitDir = isAbsolute(target) ? target : resolve(dir, target);
|
|
24244
|
-
return statOrUndefined(join(gitDir, "gitdir"))?.isFile() === true ? gitDir : void 0;
|
|
24245
|
-
}
|
|
24246
|
-
function readWorktreeId(gitDir) {
|
|
24247
|
-
let raw;
|
|
24248
|
-
try {
|
|
24249
|
-
raw = readFileSync(join(gitDir, "agentproto-worktree.json"), "utf8");
|
|
24250
|
-
} catch {
|
|
24251
|
-
return void 0;
|
|
24252
|
-
}
|
|
24253
|
-
let parsed;
|
|
24254
|
-
try {
|
|
24255
|
-
parsed = JSON.parse(raw);
|
|
24256
|
-
} catch {
|
|
24257
|
-
return void 0;
|
|
24258
|
-
}
|
|
24259
|
-
const result = markerSchema.safeParse(parsed);
|
|
24260
|
-
return result.success ? result.data.worktreeId : void 0;
|
|
24261
|
-
}
|
|
24262
|
-
function resolveWorktreeIdentity(cwd) {
|
|
24263
|
-
let dir = resolve(cwd);
|
|
24264
|
-
for (; ; ) {
|
|
24265
|
-
const dotGit = statOrUndefined(join(dir, ".git"));
|
|
24266
|
-
if (dotGit) {
|
|
24267
|
-
if (!dotGit.isFile()) return void 0;
|
|
24268
|
-
const gitDir = readWorktreeGitDir(dir);
|
|
24269
|
-
if (gitDir === void 0) return void 0;
|
|
24270
|
-
const worktreeId = readWorktreeId(gitDir);
|
|
24271
|
-
return worktreeId === void 0 ? { worktreePath: dir } : { worktreePath: dir, worktreeId };
|
|
24272
|
-
}
|
|
24273
|
-
const parent = dirname(dir);
|
|
24274
|
-
if (parent === dir) return void 0;
|
|
24275
|
-
dir = parent;
|
|
24276
|
-
}
|
|
24277
|
-
}
|
|
24278
24421
|
function normalizeAgentPromptOptions(raw) {
|
|
24279
24422
|
if (!Array.isArray(raw)) return void 0;
|
|
24280
24423
|
const labels = raw.map((o) => {
|
|
@@ -25810,6 +25953,33 @@ function createSessionsRegistry(opts) {
|
|
|
25810
25953
|
stampProcessAlive(rt.desc);
|
|
25811
25954
|
return rt.desc;
|
|
25812
25955
|
},
|
|
25956
|
+
renameSession(id, patch) {
|
|
25957
|
+
const rt = sessions.get(id);
|
|
25958
|
+
if (!rt) throw new Error(`renameSession: no session "${id}"`);
|
|
25959
|
+
const apply = (field) => {
|
|
25960
|
+
const raw = patch[field];
|
|
25961
|
+
if (raw === void 0) return;
|
|
25962
|
+
const trimmed = raw === null ? "" : raw.trim();
|
|
25963
|
+
if (trimmed === "") {
|
|
25964
|
+
rt.desc[field] = void 0;
|
|
25965
|
+
return;
|
|
25966
|
+
}
|
|
25967
|
+
const points = Array.from(trimmed);
|
|
25968
|
+
rt.desc[field] = points.length > MAX_LENGTH ? points.slice(0, MAX_LENGTH).join("") : trimmed;
|
|
25969
|
+
};
|
|
25970
|
+
apply("title");
|
|
25971
|
+
apply("label");
|
|
25972
|
+
schedulePersist();
|
|
25973
|
+
sessionEvents?.emit({
|
|
25974
|
+
type: "session:renamed",
|
|
25975
|
+
sessionId: id,
|
|
25976
|
+
...rt.desc.title !== void 0 ? { title: rt.desc.title } : {},
|
|
25977
|
+
...rt.desc.label !== void 0 ? { label: rt.desc.label } : {},
|
|
25978
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
25979
|
+
});
|
|
25980
|
+
stampProcessAlive(rt.desc);
|
|
25981
|
+
return rt.desc;
|
|
25982
|
+
},
|
|
25813
25983
|
listPendingPermissions(filter) {
|
|
25814
25984
|
const all = Array.from(pendingPermissions.values());
|
|
25815
25985
|
const scoped = filter?.sessionId ? all.filter((p2) => p2.sessionId === filter.sessionId) : all;
|
|
@@ -28942,6 +29112,9 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
28942
29112
|
})() : {},
|
|
28943
29113
|
...typeof b2.prompt === "string" ? { prompt: b2.prompt } : {},
|
|
28944
29114
|
...typeof b2.label === "string" ? { label: b2.label } : {},
|
|
29115
|
+
// Explicit title override (SPEC-3 FIX C, `--title`) — wins over the
|
|
29116
|
+
// first-sentence derivation from the prompt (see session-spawn.ts).
|
|
29117
|
+
...typeof b2.title === "string" ? { title: b2.title } : {},
|
|
28945
29118
|
...typeof b2.idempotencyKey === "string" && b2.idempotencyKey.length > 0 ? { idempotencyKey: b2.idempotencyKey } : {},
|
|
28946
29119
|
...typeof b2.role === "string" && b2.role.length > 0 ? { role: b2.role } : {},
|
|
28947
29120
|
...typeof b2.promptAppend === "string" ? { promptAppend: b2.promptAppend } : {},
|
|
@@ -29198,6 +29371,49 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
29198
29371
|
}
|
|
29199
29372
|
return true;
|
|
29200
29373
|
}
|
|
29374
|
+
const terminalInputMatch = path.match(/^\/sessions\/([^/]+)\/terminal\/input$/);
|
|
29375
|
+
if (terminalInputMatch && req.method === "POST") {
|
|
29376
|
+
const id2 = terminalInputMatch[1];
|
|
29377
|
+
if (!id2) return false;
|
|
29378
|
+
if (!ptyEnabled) {
|
|
29379
|
+
json(501, {
|
|
29380
|
+
error: "pty_not_configured",
|
|
29381
|
+
message: "POST /sessions/:id/terminal/input needs the host to inject `spawnPty` into createGateway (node-pty optional dep \u2014 install in @agentproto/cli)."
|
|
29382
|
+
});
|
|
29383
|
+
return true;
|
|
29384
|
+
}
|
|
29385
|
+
const desc = registry.get(id2);
|
|
29386
|
+
if (!desc) {
|
|
29387
|
+
json(404, { error: "no_session", message: `no session "${id2}"` });
|
|
29388
|
+
return true;
|
|
29389
|
+
}
|
|
29390
|
+
const body = await readJsonBody(req);
|
|
29391
|
+
const text6 = body?.text;
|
|
29392
|
+
if (typeof text6 !== "string") {
|
|
29393
|
+
json(400, { error: "missing_text", message: "Body `text` must be a string." });
|
|
29394
|
+
return true;
|
|
29395
|
+
}
|
|
29396
|
+
if (desc.kind !== "terminal" || desc.pty !== true) {
|
|
29397
|
+
json(400, {
|
|
29398
|
+
error: "not_a_pty",
|
|
29399
|
+
message: `session "${id2}" is not a live PTY (kind=${desc.kind})`
|
|
29400
|
+
});
|
|
29401
|
+
return true;
|
|
29402
|
+
}
|
|
29403
|
+
const enter = body?.enter !== false;
|
|
29404
|
+
let ok = true;
|
|
29405
|
+
if (text6.length > 0) ok = registry.writeTerminalInput(id2, text6) && ok;
|
|
29406
|
+
if (enter) ok = registry.writeTerminalInput(id2, "\r") && ok;
|
|
29407
|
+
if (!ok) {
|
|
29408
|
+
json(400, {
|
|
29409
|
+
error: "not_a_pty",
|
|
29410
|
+
message: `session "${id2}" has no live PTY to write to`
|
|
29411
|
+
});
|
|
29412
|
+
return true;
|
|
29413
|
+
}
|
|
29414
|
+
json(200, { ok: true });
|
|
29415
|
+
return true;
|
|
29416
|
+
}
|
|
29201
29417
|
const modelMatch = path.match(/^\/sessions\/([^/]+)\/model$/);
|
|
29202
29418
|
if (modelMatch && req.method === "POST") {
|
|
29203
29419
|
const id2 = modelMatch[1];
|
|
@@ -29321,6 +29537,31 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
29321
29537
|
}
|
|
29322
29538
|
return true;
|
|
29323
29539
|
}
|
|
29540
|
+
const renameMatch = path.match(/^\/sessions\/([^/]+)$/);
|
|
29541
|
+
if (renameMatch && req.method === "PATCH") {
|
|
29542
|
+
const rawIdOrName2 = renameMatch[1];
|
|
29543
|
+
if (!rawIdOrName2) return false;
|
|
29544
|
+
const resolved = registry.findByIdOrName(rawIdOrName2);
|
|
29545
|
+
if (!resolved) {
|
|
29546
|
+
json(404, { error: "session_not_found", id: rawIdOrName2 });
|
|
29547
|
+
return true;
|
|
29548
|
+
}
|
|
29549
|
+
const body = await readJsonBody(req);
|
|
29550
|
+
const b2 = body && typeof body === "object" ? body : {};
|
|
29551
|
+
const field = (v2) => typeof v2 === "string" ? v2 : v2 === null ? null : void 0;
|
|
29552
|
+
const patch = {
|
|
29553
|
+
..."title" in b2 ? { title: field(b2.title) } : {},
|
|
29554
|
+
..."label" in b2 ? { label: field(b2.label) } : {}
|
|
29555
|
+
};
|
|
29556
|
+
try {
|
|
29557
|
+
const desc = registry.renameSession(resolved.id, patch);
|
|
29558
|
+
json(200, desc);
|
|
29559
|
+
} catch (err) {
|
|
29560
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
29561
|
+
json(msg.includes("no session") ? 404 : 500, { error: "rename_failed", message: msg });
|
|
29562
|
+
}
|
|
29563
|
+
return true;
|
|
29564
|
+
}
|
|
29324
29565
|
if (path === "/sessions" && req.method === "POST") {
|
|
29325
29566
|
const body = await readJsonBody(req);
|
|
29326
29567
|
if (!body || typeof body !== "object") {
|
|
@@ -39173,8 +39414,8 @@ async function runServe(args) {
|
|
|
39173
39414
|
values.workspace ?? cfgDaemon.workspace ?? process.cwd()
|
|
39174
39415
|
);
|
|
39175
39416
|
try {
|
|
39176
|
-
const
|
|
39177
|
-
if (!
|
|
39417
|
+
const stat8 = await promises.stat(workspace);
|
|
39418
|
+
if (!stat8.isDirectory()) {
|
|
39178
39419
|
process.stderr.write(
|
|
39179
39420
|
`agentproto serve: --workspace "${workspace}" is not a directory.
|
|
39180
39421
|
`
|
|
@@ -39581,7 +39822,7 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
39581
39822
|
async function runOneTunnel(opts, gateway, announcedTools, spawnPty, signal, reconnectState) {
|
|
39582
39823
|
if (!opts.connect) throw new Error("runOneTunnel: --connect not set");
|
|
39583
39824
|
const headers = {
|
|
39584
|
-
"user-agent": `agentproto/${"0.
|
|
39825
|
+
"user-agent": `agentproto/${"0.10.0"}`
|
|
39585
39826
|
};
|
|
39586
39827
|
if (opts.token) headers.authorization = `Bearer ${opts.token}`;
|
|
39587
39828
|
const ws = new WebSocket2(opts.connect, { headers });
|