@docyrus/docyrus 0.0.23 → 0.0.25

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/server-loader.js CHANGED
@@ -3092,6 +3092,85 @@ async function waitForIdle(session, timeoutMs = 3e4) {
3092
3092
  }
3093
3093
  });
3094
3094
  }
3095
+ function convertSessionEntriesToUIMessages(entries) {
3096
+ const messages = [];
3097
+ const toolResults = /* @__PURE__ */ new Map();
3098
+ for (const entry of entries) {
3099
+ const rec = entry;
3100
+ if (rec.type !== "message") {
3101
+ continue;
3102
+ }
3103
+ const msg = rec.message;
3104
+ if (!msg || msg.role !== "toolResult") {
3105
+ continue;
3106
+ }
3107
+ const toolCallId = msg.toolCallId;
3108
+ if (toolCallId) {
3109
+ const content = msg.content;
3110
+ const textParts = Array.isArray(content) ? content.filter((b) => b.type === "text").map((b) => b.text).join("\n") : typeof content === "string" ? content : "";
3111
+ toolResults.set(toolCallId, {
3112
+ output: textParts,
3113
+ isError: msg.isError ?? false
3114
+ });
3115
+ }
3116
+ }
3117
+ for (const entry of entries) {
3118
+ const rec = entry;
3119
+ if (rec.type !== "message") {
3120
+ continue;
3121
+ }
3122
+ const msg = rec.message;
3123
+ if (!msg) {
3124
+ continue;
3125
+ }
3126
+ const entryId = rec.id ?? `entry_${messages.length}`;
3127
+ if (msg.role === "user") {
3128
+ const content = msg.content;
3129
+ let text = "";
3130
+ if (typeof content === "string") {
3131
+ text = content;
3132
+ } else if (Array.isArray(content)) {
3133
+ text = content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
3134
+ }
3135
+ if (text) {
3136
+ messages.push({ id: entryId, role: "user", parts: [{ type: "text", text }] });
3137
+ }
3138
+ continue;
3139
+ }
3140
+ if (msg.role === "assistant") {
3141
+ const content = msg.content;
3142
+ if (!Array.isArray(content)) {
3143
+ continue;
3144
+ }
3145
+ const parts = [];
3146
+ for (const block of content) {
3147
+ if (block.type === "text" && typeof block.text === "string") {
3148
+ parts.push({ type: "text", text: block.text });
3149
+ } else if (block.type === "thinking" && typeof block.thinking === "string") {
3150
+ parts.push({ type: "reasoning", text: block.thinking, state: "complete" });
3151
+ } else if (block.type === "toolCall") {
3152
+ const toolCallId = block.id;
3153
+ const toolName = block.name;
3154
+ const input = block.arguments ?? {};
3155
+ const result = toolResults.get(toolCallId);
3156
+ parts.push({
3157
+ type: "dynamic-tool",
3158
+ toolCallId,
3159
+ toolName,
3160
+ input,
3161
+ state: result ? result.isError ? "output-error" : "output-available" : "input-available",
3162
+ ...result && !result.isError ? { output: result.output } : {},
3163
+ ...result && result.isError ? { errorText: String(result.output) } : {}
3164
+ });
3165
+ }
3166
+ }
3167
+ if (parts.length > 0) {
3168
+ messages.push({ id: entryId, role: "assistant", parts });
3169
+ }
3170
+ }
3171
+ }
3172
+ return messages;
3173
+ }
3095
3174
  var FS_IGNORE = /* @__PURE__ */ new Set([
3096
3175
  "node_modules",
3097
3176
  ".git",
@@ -3135,13 +3214,19 @@ async function buildTree(params) {
3135
3214
  entries.sort((a, b) => {
3136
3215
  const aIsDir = a.isDirectory();
3137
3216
  const bIsDir = b.isDirectory();
3138
- if (aIsDir !== bIsDir) return aIsDir ? -1 : 1;
3217
+ if (aIsDir !== bIsDir) {
3218
+ return aIsDir ? -1 : 1;
3219
+ }
3139
3220
  return a.name.localeCompare(b.name);
3140
3221
  });
3141
3222
  const result = [];
3142
3223
  for (const entry of entries) {
3143
- if (counter.value >= maxFiles) break;
3144
- if (ignore.has(entry.name)) continue;
3224
+ if (counter.value >= maxFiles) {
3225
+ break;
3226
+ }
3227
+ if (ignore.has(entry.name)) {
3228
+ continue;
3229
+ }
3145
3230
  const fullPath = (0, import_node_path2.join)(dir, entry.name);
3146
3231
  const relativePath = (0, import_node_path2.relative)(cwd, fullPath);
3147
3232
  if (entry.isDirectory()) {
@@ -3164,7 +3249,9 @@ async function buildTree(params) {
3164
3249
  }
3165
3250
  async function walkFiles(params) {
3166
3251
  const { dir, cwd, pattern, ignore, maxResults, results } = params;
3167
- if (results.length >= maxResults) return;
3252
+ if (results.length >= maxResults) {
3253
+ return;
3254
+ }
3168
3255
  let entries;
3169
3256
  try {
3170
3257
  entries = await (0, import_promises2.readdir)(dir, { withFileTypes: true });
@@ -3172,8 +3259,12 @@ async function walkFiles(params) {
3172
3259
  return;
3173
3260
  }
3174
3261
  for (const entry of entries) {
3175
- if (results.length >= maxResults) break;
3176
- if (ignore.has(entry.name)) continue;
3262
+ if (results.length >= maxResults) {
3263
+ break;
3264
+ }
3265
+ if (ignore.has(entry.name)) {
3266
+ continue;
3267
+ }
3177
3268
  const fullPath = (0, import_node_path2.join)(dir, entry.name);
3178
3269
  const relativePath = (0, import_node_path2.relative)(cwd, fullPath);
3179
3270
  if (entry.isDirectory()) {
@@ -3184,7 +3275,7 @@ async function walkFiles(params) {
3184
3275
  }
3185
3276
  }
3186
3277
  async function createAgentServer(params) {
3187
- const { port, sessionManager, modelRegistry, context, onResumeSession } = params;
3278
+ const { port, sessionManager, modelRegistry, context, onCreateSession, onResumeSession } = params;
3188
3279
  let activeSession = params.session;
3189
3280
  const app = new Hono2();
3190
3281
  app.use("/*", cors({ origin: "*" }));
@@ -3279,6 +3370,31 @@ async function createAgentServer(params) {
3279
3370
  return c.json({ error: message }, 500);
3280
3371
  }
3281
3372
  });
3373
+ app.post("/api/sessions", async (c) => {
3374
+ try {
3375
+ if (activeSession.isStreaming) {
3376
+ await activeSession.abort();
3377
+ await waitForIdle(activeSession);
3378
+ }
3379
+ activeSession = await onCreateSession();
3380
+ const sessionId = activeSession.id?.trim();
3381
+ if (!sessionId) {
3382
+ return c.json({ error: "Created session is missing an id" }, 500);
3383
+ }
3384
+ const sessions = await sessionManager.list();
3385
+ const match2 = sessions.find((session) => session.id === sessionId);
3386
+ return c.json({
3387
+ ok: true,
3388
+ sessionId,
3389
+ sessionName: match2?.name ?? null,
3390
+ cwd: match2?.cwd ?? context.cwd,
3391
+ model: activeSession.model ? { provider: activeSession.model.provider, id: activeSession.model.id } : null
3392
+ });
3393
+ } catch (error) {
3394
+ const message = error instanceof Error ? error.message : String(error);
3395
+ return c.json({ error: message }, 500);
3396
+ }
3397
+ });
3282
3398
  app.get("/api/sessions/:sessionId/messages", async (c) => {
3283
3399
  const sessionId = c.req.param("sessionId");
3284
3400
  try {
@@ -3289,14 +3405,15 @@ async function createAgentServer(params) {
3289
3405
  }
3290
3406
  const opened = sessionManager.open(match2.path);
3291
3407
  const sessionContext = opened.buildSessionContext();
3292
- const entries = opened.getBranch();
3408
+ const rawEntries = opened.getBranch();
3409
+ const messages = convertSessionEntriesToUIMessages(rawEntries);
3293
3410
  return c.json({
3294
3411
  sessionId: opened.getSessionId(),
3295
3412
  sessionName: opened.getSessionName() ?? null,
3296
3413
  cwd: opened.getCwd(),
3297
3414
  model: sessionContext.model ?? null,
3298
3415
  thinkingLevel: sessionContext.thinkingLevel ?? null,
3299
- entries
3416
+ messages
3300
3417
  });
3301
3418
  } catch (error) {
3302
3419
  const message = error instanceof Error ? error.message : String(error);
@@ -3466,6 +3583,42 @@ async function createAgentServer(params) {
3466
3583
  return c.json({ error: message }, status);
3467
3584
  }
3468
3585
  });
3586
+ const CLI_EXEC = process.env.DOCYRUS_CLI_EXECUTABLE || process.execPath;
3587
+ const CLI_ENTRY = process.env.DOCYRUS_CLI_ENTRY || (0, import_node_path2.resolve)(process.argv[1] ? (0, import_node_path2.join)(process.argv[1], "..") : __dirname, "main.js");
3588
+ const CLI_SCOPE = process.env.DOCYRUS_CLI_SCOPE;
3589
+ const CLI_TIMEOUT_MS = 3e4;
3590
+ function runCliCommand(args) {
3591
+ return new Promise((resolveResult) => {
3592
+ const scopeArgs = CLI_SCOPE ? ["--scope", CLI_SCOPE] : [];
3593
+ const proc = (0, import_node_child_process.spawn)(CLI_EXEC, [CLI_ENTRY, ...scopeArgs, ...args, "--json"], {
3594
+ cwd: context.cwd,
3595
+ stdio: ["ignore", "pipe", "pipe"],
3596
+ timeout: CLI_TIMEOUT_MS
3597
+ });
3598
+ let stdout = "";
3599
+ let stderr = "";
3600
+ proc.stdout?.on("data", (chunk) => {
3601
+ stdout += chunk.toString();
3602
+ });
3603
+ proc.stderr?.on("data", (chunk) => {
3604
+ stderr += chunk.toString();
3605
+ });
3606
+ proc.on("close", (code) => {
3607
+ if (code !== 0) {
3608
+ resolveResult({ ok: false, error: stderr.trim() || `exit code ${code}` });
3609
+ return;
3610
+ }
3611
+ try {
3612
+ resolveResult({ ok: true, data: JSON.parse(stdout) });
3613
+ } catch {
3614
+ resolveResult({ ok: true, data: stdout.trim() });
3615
+ }
3616
+ });
3617
+ proc.on("error", (err) => {
3618
+ resolveResult({ ok: false, error: err.message });
3619
+ });
3620
+ });
3621
+ }
3469
3622
  let devProcess = null;
3470
3623
  let devUrl = null;
3471
3624
  const DEV_URL_PATTERN = /https?:\/\/(?:localhost|127\.0\.0\.1):\d+/;
@@ -3479,13 +3632,104 @@ async function createAgentServer(params) {
3479
3632
  return null;
3480
3633
  }
3481
3634
  }
3635
+ async function detectDevPort(cwd) {
3636
+ try {
3637
+ const pkg = JSON.parse(await (0, import_promises2.readFile)((0, import_node_path2.join)(cwd, "package.json"), "utf-8"));
3638
+ const devScript = pkg.scripts?.dev;
3639
+ if (devScript) {
3640
+ const portFlag = devScript.match(/--port\s+(\d+)/);
3641
+ if (portFlag) {
3642
+ return Number(portFlag[1]);
3643
+ }
3644
+ const dashP = devScript.match(/(?:^|\s)-p\s+(\d+)/);
3645
+ if (dashP) {
3646
+ return Number(dashP[1]);
3647
+ }
3648
+ }
3649
+ } catch {
3650
+ }
3651
+ for (const name of ["vite.config.ts", "vite.config.mts", "vite.config.js"]) {
3652
+ try {
3653
+ const content = await (0, import_promises2.readFile)((0, import_node_path2.join)(cwd, name), "utf-8");
3654
+ const portMatch = content.match(/port\s*:\s*(\d+)/);
3655
+ if (portMatch) {
3656
+ return Number(portMatch[1]);
3657
+ }
3658
+ } catch {
3659
+ }
3660
+ }
3661
+ for (const name of ["next.config.ts", "next.config.mts", "next.config.js", "next.config.mjs"]) {
3662
+ try {
3663
+ await (0, import_promises2.stat)((0, import_node_path2.join)(cwd, name));
3664
+ return 3e3;
3665
+ } catch {
3666
+ }
3667
+ }
3668
+ try {
3669
+ await (0, import_promises2.stat)((0, import_node_path2.join)(cwd, "angular.json"));
3670
+ return 4200;
3671
+ } catch {
3672
+ }
3673
+ for (const name of ["nuxt.config.ts", "nuxt.config.js"]) {
3674
+ try {
3675
+ await (0, import_promises2.stat)((0, import_node_path2.join)(cwd, name));
3676
+ return 3e3;
3677
+ } catch {
3678
+ }
3679
+ }
3680
+ return null;
3681
+ }
3682
+ let cachedProjectInfo = null;
3683
+ async function getProjectInfo() {
3684
+ if (cachedProjectInfo) {
3685
+ return cachedProjectInfo;
3686
+ }
3687
+ const cwd = context.cwd;
3688
+ let repo = null;
3689
+ let packageName = null;
3690
+ let packageVersion = null;
3691
+ try {
3692
+ repo = await new Promise((res, rej) => {
3693
+ (0, import_node_child_process.execFile)("git", ["remote", "get-url", "origin"], { cwd }, (err, stdout) => {
3694
+ if (err) {
3695
+ return rej(err);
3696
+ }
3697
+ const url = stdout.trim();
3698
+ const match2 = url.match(/\/([^/]+?)(?:\.git)?$/);
3699
+ res(match2 ? match2[1] : url);
3700
+ });
3701
+ });
3702
+ } catch {
3703
+ }
3704
+ try {
3705
+ const pkg = JSON.parse(await (0, import_promises2.readFile)((0, import_node_path2.join)(cwd, "package.json"), "utf-8"));
3706
+ packageName = pkg.name ?? null;
3707
+ packageVersion = pkg.version ?? null;
3708
+ } catch {
3709
+ }
3710
+ cachedProjectInfo = {
3711
+ path: cwd,
3712
+ folder: (0, import_node_path2.basename)(cwd),
3713
+ repo,
3714
+ packageName,
3715
+ packageVersion
3716
+ };
3717
+ return cachedProjectInfo;
3718
+ }
3482
3719
  app.get("/api/env/status", async (c) => {
3720
+ const [authResult, project] = await Promise.all([
3721
+ runCliCommand(["auth", "who"]),
3722
+ getProjectInfo()
3723
+ ]);
3724
+ const env = authResult.ok ? authResult.data : null;
3483
3725
  if (devProcess && devProcess.exitCode === null && devUrl) {
3484
3726
  const httpStatus = await probeUrl(devUrl);
3485
3727
  return c.json({
3486
3728
  status: httpStatus !== null ? "running" : "starting",
3487
3729
  url: devUrl,
3488
3730
  managed: true,
3731
+ project,
3732
+ env,
3489
3733
  ...httpStatus !== null ? { httpStatus } : {}
3490
3734
  });
3491
3735
  }
@@ -3494,17 +3738,33 @@ async function createAgentServer(params) {
3494
3738
  devProcess = null;
3495
3739
  const stoppedUrl = devUrl;
3496
3740
  devUrl = null;
3497
- return c.json({ status: "stopped", url: stoppedUrl, exitCode, managed: true });
3741
+ return c.json({ status: "stopped", url: stoppedUrl, exitCode, managed: true, project, env });
3498
3742
  }
3499
- const commonPorts = [5173, 5174, 3e3, 3001, 4321, 8080, 8e3];
3500
- for (const devPort of commonPorts) {
3501
- const candidate = `http://localhost:${devPort}`;
3502
- const httpStatus = await probeUrl(candidate);
3503
- if (httpStatus !== null) {
3504
- return c.json({ status: "running", url: candidate, httpStatus, managed: false });
3743
+ const explicitUrl = c.req.query("url");
3744
+ const explicitPort = c.req.query("port");
3745
+ let probeTarget = null;
3746
+ if (explicitUrl) {
3747
+ probeTarget = explicitUrl;
3748
+ } else if (explicitPort) {
3749
+ probeTarget = `http://localhost:${explicitPort}`;
3750
+ } else {
3751
+ const detected = await detectDevPort(context.cwd);
3752
+ if (detected) {
3753
+ probeTarget = `http://localhost:${detected}`;
3505
3754
  }
3506
3755
  }
3507
- return c.json({ status: "stopped", url: null, managed: false });
3756
+ if (probeTarget) {
3757
+ const httpStatus = await probeUrl(probeTarget);
3758
+ return c.json({
3759
+ status: httpStatus !== null ? "running" : "stopped",
3760
+ url: probeTarget,
3761
+ httpStatus: httpStatus ?? void 0,
3762
+ managed: false,
3763
+ project,
3764
+ env
3765
+ });
3766
+ }
3767
+ return c.json({ status: "stopped", url: null, managed: false, project, env });
3508
3768
  });
3509
3769
  app.post("/api/env/serve", (c) => {
3510
3770
  if (devProcess && devProcess.exitCode === null) {
@@ -3521,7 +3781,9 @@ async function createAgentServer(params) {
3521
3781
  let stderr = "";
3522
3782
  let resolved = false;
3523
3783
  function settle(response) {
3524
- if (resolved) return;
3784
+ if (resolved) {
3785
+ return;
3786
+ }
3525
3787
  resolved = true;
3526
3788
  resolveResponse(response);
3527
3789
  }
@@ -3562,13 +3824,103 @@ async function createAgentServer(params) {
3562
3824
  devUrl = null;
3563
3825
  return c.json({ status: "stopped", url: stoppedUrl, pid });
3564
3826
  });
3827
+ const BOOLEAN_CLI_FLAGS = /* @__PURE__ */ new Set(["json", "verbose", "global", "noAuth", "expand", "i"]);
3828
+ function buildCliArgs(pathSegments, query, body) {
3829
+ const args = [...pathSegments, "--json"];
3830
+ for (const [key, value] of Object.entries(query)) {
3831
+ if (key === "json") {
3832
+ continue;
3833
+ }
3834
+ const flag = key.length === 1 ? `-${key}` : `--${key}`;
3835
+ if (BOOLEAN_CLI_FLAGS.has(key) || value === "" || value === "true") {
3836
+ args.push(flag);
3837
+ } else {
3838
+ args.push(flag, value);
3839
+ }
3840
+ }
3841
+ if (body) {
3842
+ if (body.data !== void 0) {
3843
+ args.push("--data", typeof body.data === "string" ? body.data : JSON.stringify(body.data));
3844
+ }
3845
+ if (typeof body.fromFile === "string") {
3846
+ args.push("--from-file", body.fromFile);
3847
+ }
3848
+ for (const [key, value] of Object.entries(body)) {
3849
+ if (key === "data" || key === "fromFile") {
3850
+ continue;
3851
+ }
3852
+ const flag = key.length === 1 ? `-${key}` : `--${key}`;
3853
+ if (typeof value === "boolean") {
3854
+ if (value) {
3855
+ args.push(flag);
3856
+ }
3857
+ } else if (value !== void 0 && value !== null) {
3858
+ args.push(flag, String(value));
3859
+ }
3860
+ }
3861
+ }
3862
+ return args;
3863
+ }
3864
+ app.all("/api/cli/*", async (c) => {
3865
+ const pathSegments = c.req.path.replace(/^\/api\/cli\/?/, "").split("/").filter(Boolean);
3866
+ if (pathSegments.length === 0) {
3867
+ return c.json({ error: "No command specified. Usage: /api/cli/<command>/[subcommand]/[args...]" }, 400);
3868
+ }
3869
+ const query = {};
3870
+ for (const [key, value] of Object.entries(c.req.query())) {
3871
+ if (typeof value === "string") {
3872
+ query[key] = value;
3873
+ }
3874
+ }
3875
+ let body;
3876
+ if (c.req.method === "POST" || c.req.method === "PUT") {
3877
+ try {
3878
+ body = await c.req.json();
3879
+ } catch {
3880
+ }
3881
+ }
3882
+ const cliArgs = buildCliArgs(pathSegments, query, body);
3883
+ return new Promise((resolveResponse) => {
3884
+ const scopeArgs = CLI_SCOPE ? ["--scope", CLI_SCOPE] : [];
3885
+ const proc = (0, import_node_child_process.spawn)(CLI_EXEC, [CLI_ENTRY, ...scopeArgs, ...cliArgs], {
3886
+ cwd: context.cwd,
3887
+ stdio: ["ignore", "pipe", "pipe"],
3888
+ timeout: CLI_TIMEOUT_MS
3889
+ });
3890
+ let stdout = "";
3891
+ let stderr = "";
3892
+ proc.stdout?.on("data", (chunk) => {
3893
+ stdout += chunk.toString();
3894
+ });
3895
+ proc.stderr?.on("data", (chunk) => {
3896
+ stderr += chunk.toString();
3897
+ });
3898
+ proc.on("close", (code) => {
3899
+ if (code !== 0) {
3900
+ resolveResponse(c.json({
3901
+ error: stderr.trim() || `Command exited with code ${code}`,
3902
+ command: `docyrus ${cliArgs.join(" ")}`,
3903
+ exitCode: code
3904
+ }, 500));
3905
+ return;
3906
+ }
3907
+ try {
3908
+ const parsed = JSON.parse(stdout);
3909
+ resolveResponse(c.json(parsed));
3910
+ } catch {
3911
+ resolveResponse(c.json({ output: stdout.trim(), command: `docyrus ${cliArgs.join(" ")}` }));
3912
+ }
3913
+ });
3914
+ proc.on("error", (err) => {
3915
+ resolveResponse(c.json({ error: err.message, command: `docyrus ${cliArgs.join(" ")}` }, 500));
3916
+ });
3917
+ });
3918
+ });
3565
3919
  const { serve: serve2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
3566
- serve2({
3567
- fetch: app.fetch,
3568
- port
3569
- }, (info) => {
3920
+ const MAX_PORT_RETRIES = 10;
3921
+ function printBanner(actualPort) {
3570
3922
  process.stderr.write(`
3571
- Agent server listening on http://localhost:${info.port}
3923
+ Agent server listening on http://localhost:${actualPort}
3572
3924
 
3573
3925
  `);
3574
3926
  process.stderr.write(` POST /api/chat \u2014 send chat messages (SSE UIMessage stream)
@@ -3578,6 +3930,8 @@ async function createAgentServer(params) {
3578
3930
  process.stderr.write(` GET /api/status \u2014 session status
3579
3931
  `);
3580
3932
  process.stderr.write(` GET /api/sessions \u2014 list sessions
3933
+ `);
3934
+ process.stderr.write(` POST /api/sessions \u2014 create a new session
3581
3935
  `);
3582
3936
  process.stderr.write(` GET /api/sessions/:sessionId/messages \u2014 session messages
3583
3937
  `);
@@ -3606,9 +3960,37 @@ async function createAgentServer(params) {
3606
3960
  process.stderr.write(` POST /api/env/serve \u2014 start dev server (pnpm dev)
3607
3961
  `);
3608
3962
  process.stderr.write(` POST /api/env/stop \u2014 stop dev server
3963
+ `);
3964
+ process.stderr.write(` * /api/cli/** \u2014 proxy any docyrus CLI command
3609
3965
 
3610
3966
  `);
3611
- });
3967
+ }
3968
+ for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {
3969
+ const candidatePort = port + attempt;
3970
+ try {
3971
+ await new Promise((resolveStart, rejectStart) => {
3972
+ const server = serve2({ fetch: app.fetch, port: candidatePort }, () => {
3973
+ printBanner(candidatePort);
3974
+ resolveStart();
3975
+ });
3976
+ server.on("error", (err) => {
3977
+ if (err.code === "EADDRINUSE") {
3978
+ process.stderr.write(` Port ${candidatePort} in use, trying ${candidatePort + 1}...
3979
+ `);
3980
+ rejectStart(err);
3981
+ } else {
3982
+ throw err;
3983
+ }
3984
+ });
3985
+ });
3986
+ return;
3987
+ } catch (err) {
3988
+ const isAddrInUse = err instanceof Error && "code" in err && err.code === "EADDRINUSE";
3989
+ if (!isAddrInUse || attempt === MAX_PORT_RETRIES - 1) {
3990
+ throw new Error(`All ports ${port}\u2013${port + MAX_PORT_RETRIES - 1} are in use`);
3991
+ }
3992
+ }
3993
+ }
3612
3994
  }
3613
3995
 
3614
3996
  // src/server/server-loader.ts
@@ -3808,6 +4190,21 @@ Or create ${modelsJsonPath}`
3808
4190
  sessionDir: request.sessionDir ?? null,
3809
4191
  thinkingLevel: request.thinking ?? null
3810
4192
  },
4193
+ onCreateSession: async () => {
4194
+ const { session: freshSession } = await pi.createAgentSession({
4195
+ cwd,
4196
+ agentDir,
4197
+ authStorage,
4198
+ modelRegistry,
4199
+ resourceLoader,
4200
+ settingsManager,
4201
+ sessionManager,
4202
+ tools: buildTools(request.profile, cwd, pi),
4203
+ model: requestedModel,
4204
+ thinkingLevel: request.thinking
4205
+ });
4206
+ return freshSession;
4207
+ },
3811
4208
  onResumeSession: async (sessionId) => {
3812
4209
  const sessions = await pi.SessionManager.list(cwd, request.sessionDir);
3813
4210
  const match2 = sessions.find((s) => s.id === sessionId);