@docyrus/docyrus 0.0.26 → 0.0.28
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 +7 -0
- package/agent-loader.js +33 -3
- package/agent-loader.js.map +4 -4
- package/main.js +443 -108
- package/main.js.map +4 -4
- package/package.json +1 -1
- package/resources/pi-agent/skills/docyrus-platform/SKILL.md +1 -1
- package/resources/pi-agent/skills/docyrus-platform/references/developer-tools.md +1 -1
- package/resources/pi-agent/skills/docyrus-platform/references/docyrus-cli-usage.md +46 -0
- package/resources/pi-agent/skills/docyrus-platform/references/querying-and-data-operations.md +7 -0
- package/server-loader.js +234 -5
- package/server-loader.js.map +4 -4
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ For detailed specifications of each building block, see [references/core-buildin
|
|
|
24
24
|
|
|
25
25
|
### Querying & Data Operations
|
|
26
26
|
|
|
27
|
-
Unified query engine with column selection, 50+ filter operators, aggregations, formulas, pivots, child queries, and full-text search. Full CRUD with bulk operations.
|
|
27
|
+
Unified query engine with column selection, 50+ filter operators, aggregations, formulas, pivots, child queries, and full-text search. Full CRUD with bulk operations, record comments, and file attachments.
|
|
28
28
|
|
|
29
29
|
See [references/querying-and-data-operations.md](references/querying-and-data-operations.md).
|
|
30
30
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
## CLI
|
|
15
15
|
|
|
16
16
|
- Full-featured CLI (`@docyrus/docyrus`) for terminal and AI agent use
|
|
17
|
-
- Commands: environment management, authentication, data operations, schema management (studio), app management, API discovery, AI chat, and direct API requests
|
|
17
|
+
- Commands: environment management, authentication, data operations, record comments, record file attachments, schema management (studio), app management, API discovery, AI chat, and direct API requests
|
|
18
18
|
- Multi-account, multi-tenant session management
|
|
19
19
|
- OpenAPI discovery with caching and fallback generation
|
|
20
20
|
- Interactive TUI mode
|
|
@@ -251,6 +251,52 @@ Delete a data source item.
|
|
|
251
251
|
| `dataSourceSlug` | string | yes | Data source slug |
|
|
252
252
|
| `recordId` | string | yes | Record ID |
|
|
253
253
|
|
|
254
|
+
### `docyrus ds comments create <appSlug> <dataSourceSlug> <recordId>`
|
|
255
|
+
|
|
256
|
+
Create a record-scoped comment.
|
|
257
|
+
|
|
258
|
+
| Argument | Type | Required | Description |
|
|
259
|
+
|---|---|---|---|
|
|
260
|
+
| `appSlug` | string | yes | App slug |
|
|
261
|
+
| `dataSourceSlug` | string | yes | Data source slug |
|
|
262
|
+
| `recordId` | string | yes | Record ID |
|
|
263
|
+
|
|
264
|
+
| Option | Type | Description |
|
|
265
|
+
|---|---|---|
|
|
266
|
+
| `--message` | string | Comment message |
|
|
267
|
+
| `--data` | string | Full JSON payload for the comment DTO |
|
|
268
|
+
| `--fromFile` | string | Path to a JSON payload file |
|
|
269
|
+
| `--parentId` | string | Parent comment ID |
|
|
270
|
+
| `--assignedTo` | string | Assigned user ID |
|
|
271
|
+
| `--attachments` | string | JSON attachments payload |
|
|
272
|
+
| `--level` | number | Comment level |
|
|
273
|
+
| `--status` | number | Comment status |
|
|
274
|
+
| `--done` | boolean | Mark comment as done |
|
|
275
|
+
|
|
276
|
+
**Notes:**
|
|
277
|
+
- Use either `--message` or `--data` / `--fromFile`
|
|
278
|
+
- `--data` and `--fromFile` cannot be mixed with field-specific flags
|
|
279
|
+
|
|
280
|
+
### `docyrus ds files upload <appSlug> <dataSourceSlug> <recordId>`
|
|
281
|
+
|
|
282
|
+
Upload a record-scoped file attachment.
|
|
283
|
+
|
|
284
|
+
| Argument | Type | Required | Description |
|
|
285
|
+
|---|---|---|---|
|
|
286
|
+
| `appSlug` | string | yes | App slug |
|
|
287
|
+
| `dataSourceSlug` | string | yes | Data source slug |
|
|
288
|
+
| `recordId` | string | yes | Record ID |
|
|
289
|
+
|
|
290
|
+
| Option | Type | Description |
|
|
291
|
+
|---|---|---|
|
|
292
|
+
| `--file` | string | Path to the local file to upload |
|
|
293
|
+
| `--contentType` | string | Override the inferred MIME type |
|
|
294
|
+
| `--publicFile` | boolean | Store the file in the public tenant bucket |
|
|
295
|
+
|
|
296
|
+
**Notes:**
|
|
297
|
+
- Uploads use `multipart/form-data`
|
|
298
|
+
- Content type is inferred from the file extension when omitted
|
|
299
|
+
|
|
254
300
|
---
|
|
255
301
|
|
|
256
302
|
## discover — OpenAPI Discovery
|
package/resources/pi-agent/skills/docyrus-platform/references/querying-and-data-operations.md
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
- Bulk create, bulk update, bulk delete (batched for performance)
|
|
7
7
|
- Insert/update/delete with custom return value selection
|
|
8
8
|
|
|
9
|
+
## Record Comments & Files
|
|
10
|
+
|
|
11
|
+
- Record-scoped comments with create, list, fetch by ID, update, and delete operations
|
|
12
|
+
- Comment payloads can include threading (`parentId`), assignee targeting (`assignedTo`), attachments metadata, level, status, and done state
|
|
13
|
+
- Record-scoped file attachments with upload, list, fetch by ID, insert-without-upload, copy/move, and delete operations
|
|
14
|
+
- File uploads support multipart form data, public/private storage selection, and record association
|
|
15
|
+
|
|
9
16
|
## Query Engine
|
|
10
17
|
|
|
11
18
|
Every list/get call accepts a structured query payload:
|
package/server-loader.js
CHANGED
|
@@ -693,7 +693,7 @@ var init_dist = __esm({
|
|
|
693
693
|
var import_node_fs = require("node:fs");
|
|
694
694
|
var import_node_url = require("node:url");
|
|
695
695
|
var import_node_path4 = require("node:path");
|
|
696
|
-
var
|
|
696
|
+
var import_picocolors2 = __toESM(require_picocolors());
|
|
697
697
|
|
|
698
698
|
// src/agent/envStore.ts
|
|
699
699
|
var import_promises = require("node:fs/promises");
|
|
@@ -795,6 +795,7 @@ var AgentEnvStore = class {
|
|
|
795
795
|
|
|
796
796
|
// src/server/agentServer.ts
|
|
797
797
|
var import_node_child_process = require("node:child_process");
|
|
798
|
+
var import_node_crypto2 = require("node:crypto");
|
|
798
799
|
var import_promises3 = require("node:fs/promises");
|
|
799
800
|
var import_node_path3 = require("node:path");
|
|
800
801
|
|
|
@@ -4397,7 +4398,7 @@ async function walkFiles(params) {
|
|
|
4397
4398
|
}
|
|
4398
4399
|
}
|
|
4399
4400
|
async function createAgentServer(params) {
|
|
4400
|
-
const { port, sessionManager, modelRegistry, authRuntime, context, onCreateSession, onResumeSession } = params;
|
|
4401
|
+
const { port, sessionManager, modelRegistry, authRuntime, context, onCreateSession, onResumeSession, authToken } = params;
|
|
4401
4402
|
let activeSession = params.session;
|
|
4402
4403
|
const pendingAskUserRequests = /* @__PURE__ */ new Map();
|
|
4403
4404
|
const oauthFlowManager = new OAuthFlowManager();
|
|
@@ -4424,6 +4425,13 @@ async function createAgentServer(params) {
|
|
|
4424
4425
|
});
|
|
4425
4426
|
}
|
|
4426
4427
|
app.use("/*", cors({ origin: "*" }));
|
|
4428
|
+
app.use("/*", async (c, next) => {
|
|
4429
|
+
const unauthorizedResponse = authorizeServerRequest(c.req.raw, authToken);
|
|
4430
|
+
if (unauthorizedResponse) {
|
|
4431
|
+
return unauthorizedResponse;
|
|
4432
|
+
}
|
|
4433
|
+
await next();
|
|
4434
|
+
});
|
|
4427
4435
|
app.get("/api/health", (c) => {
|
|
4428
4436
|
return c.json({ ok: true });
|
|
4429
4437
|
});
|
|
@@ -5146,6 +5154,140 @@ async function createAgentServer(params) {
|
|
|
5146
5154
|
devUrl = null;
|
|
5147
5155
|
return c.json({ status: "stopped", url: stoppedUrl, pid });
|
|
5148
5156
|
});
|
|
5157
|
+
function gitExec(args, gitCwd) {
|
|
5158
|
+
return new Promise((res, rej) => {
|
|
5159
|
+
(0, import_node_child_process.execFile)("git", args, { cwd: gitCwd, maxBuffer: 50 * 1024 * 1024 }, (err, stdout) => {
|
|
5160
|
+
if (err) {
|
|
5161
|
+
return rej(err);
|
|
5162
|
+
}
|
|
5163
|
+
res(stdout);
|
|
5164
|
+
});
|
|
5165
|
+
});
|
|
5166
|
+
}
|
|
5167
|
+
app.get("/api/git/diff", async (c) => {
|
|
5168
|
+
const filterPath = c.req.query("path");
|
|
5169
|
+
const cwd = context.cwd;
|
|
5170
|
+
try {
|
|
5171
|
+
let branch;
|
|
5172
|
+
let hasHead = true;
|
|
5173
|
+
try {
|
|
5174
|
+
branch = (await gitExec(["rev-parse", "--abbrev-ref", "HEAD"], cwd)).trim() || void 0;
|
|
5175
|
+
} catch {
|
|
5176
|
+
hasHead = false;
|
|
5177
|
+
}
|
|
5178
|
+
const diffRef = hasHead ? ["diff", "HEAD"] : ["diff", "--cached"];
|
|
5179
|
+
const [nameStatusRaw, untrackedRaw, numstatRaw] = await Promise.all([
|
|
5180
|
+
gitExec([...diffRef, "--name-status"], cwd).catch(() => ""),
|
|
5181
|
+
gitExec(["ls-files", "--others", "--exclude-standard"], cwd).catch(() => ""),
|
|
5182
|
+
gitExec([...diffRef, "--numstat"], cwd).catch(() => "")
|
|
5183
|
+
]);
|
|
5184
|
+
const entries = [];
|
|
5185
|
+
for (const line of nameStatusRaw.split("\n").filter(Boolean)) {
|
|
5186
|
+
const parts = line.split(" ");
|
|
5187
|
+
const code = parts[0];
|
|
5188
|
+
if (code.startsWith("R")) {
|
|
5189
|
+
entries.push({ path: parts[2], status: "renamed", oldPath: parts[1] });
|
|
5190
|
+
} else if (code.startsWith("C")) {
|
|
5191
|
+
entries.push({ path: parts[2], status: "copied", oldPath: parts[1] });
|
|
5192
|
+
} else if (code.startsWith("M")) {
|
|
5193
|
+
entries.push({ path: parts[1], status: "modified" });
|
|
5194
|
+
} else if (code.startsWith("A")) {
|
|
5195
|
+
entries.push({ path: parts[1], status: "added" });
|
|
5196
|
+
} else if (code.startsWith("D")) {
|
|
5197
|
+
entries.push({ path: parts[1], status: "deleted" });
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
for (const filePath of untrackedRaw.split("\n").filter(Boolean)) {
|
|
5201
|
+
entries.push({ path: filePath, status: "untracked" });
|
|
5202
|
+
}
|
|
5203
|
+
const numstatMap = /* @__PURE__ */ new Map();
|
|
5204
|
+
for (const line of numstatRaw.split("\n").filter(Boolean)) {
|
|
5205
|
+
const match2 = line.match(/^(-|\d+)\t(-|\d+)\t(.+)$/);
|
|
5206
|
+
if (!match2) {
|
|
5207
|
+
continue;
|
|
5208
|
+
}
|
|
5209
|
+
const isBinary = match2[1] === "-" && match2[2] === "-";
|
|
5210
|
+
const additions = isBinary ? 0 : Number(match2[1]);
|
|
5211
|
+
const deletions = isBinary ? 0 : Number(match2[2]);
|
|
5212
|
+
let filePath = match2[3];
|
|
5213
|
+
const arrowIdx = filePath.indexOf(" => ");
|
|
5214
|
+
if (arrowIdx !== -1) {
|
|
5215
|
+
const braceStart = filePath.indexOf("{");
|
|
5216
|
+
if (braceStart !== -1 && braceStart < arrowIdx) {
|
|
5217
|
+
const braceEnd = filePath.indexOf("}", arrowIdx);
|
|
5218
|
+
if (braceEnd !== -1) {
|
|
5219
|
+
const prefix = filePath.slice(0, braceStart);
|
|
5220
|
+
const suffix = filePath.slice(braceEnd + 1);
|
|
5221
|
+
const newPart = filePath.slice(braceStart + 1, braceEnd).split(" => ")[1];
|
|
5222
|
+
filePath = prefix + newPart + suffix;
|
|
5223
|
+
}
|
|
5224
|
+
} else {
|
|
5225
|
+
filePath = filePath.slice(arrowIdx + 4);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
numstatMap.set(filePath, { additions, deletions, isBinary });
|
|
5229
|
+
}
|
|
5230
|
+
const filtered = filterPath ? entries.filter((e) => e.path === filterPath) : entries;
|
|
5231
|
+
const MAX_CONTENT_SIZE = 1e6;
|
|
5232
|
+
const fileResults = await Promise.all(filtered.map(async (entry) => {
|
|
5233
|
+
const stats = numstatMap.get(entry.path);
|
|
5234
|
+
if (stats?.isBinary) {
|
|
5235
|
+
return null;
|
|
5236
|
+
}
|
|
5237
|
+
let oldContent = "";
|
|
5238
|
+
let newContent = "";
|
|
5239
|
+
let truncated = false;
|
|
5240
|
+
if (hasHead && (entry.status === "modified" || entry.status === "deleted" || entry.status === "renamed" || entry.status === "copied")) {
|
|
5241
|
+
const showPath = entry.oldPath ?? entry.path;
|
|
5242
|
+
try {
|
|
5243
|
+
oldContent = await gitExec(["show", `HEAD:${showPath}`], cwd);
|
|
5244
|
+
if (oldContent.length > MAX_CONTENT_SIZE) {
|
|
5245
|
+
oldContent = oldContent.slice(0, MAX_CONTENT_SIZE);
|
|
5246
|
+
truncated = true;
|
|
5247
|
+
}
|
|
5248
|
+
} catch {
|
|
5249
|
+
}
|
|
5250
|
+
}
|
|
5251
|
+
if (entry.status !== "deleted") {
|
|
5252
|
+
try {
|
|
5253
|
+
const resolved = (0, import_node_path3.resolve)(cwd, entry.path);
|
|
5254
|
+
const buf = await (0, import_promises3.readFile)(resolved);
|
|
5255
|
+
if (buf.subarray(0, 8192).includes(0)) {
|
|
5256
|
+
return null;
|
|
5257
|
+
}
|
|
5258
|
+
newContent = buf.toString("utf-8");
|
|
5259
|
+
if (newContent.length > MAX_CONTENT_SIZE) {
|
|
5260
|
+
newContent = newContent.slice(0, MAX_CONTENT_SIZE);
|
|
5261
|
+
truncated = true;
|
|
5262
|
+
}
|
|
5263
|
+
} catch {
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
const additions = stats?.additions ?? (entry.status === "untracked" ? newContent.split("\n").length : 0);
|
|
5267
|
+
const deletions = stats?.deletions ?? 0;
|
|
5268
|
+
const file = {
|
|
5269
|
+
path: entry.path,
|
|
5270
|
+
status: entry.status,
|
|
5271
|
+
oldContent,
|
|
5272
|
+
newContent,
|
|
5273
|
+
additions,
|
|
5274
|
+
deletions
|
|
5275
|
+
};
|
|
5276
|
+
if (entry.oldPath) {
|
|
5277
|
+
file.oldPath = entry.oldPath;
|
|
5278
|
+
}
|
|
5279
|
+
if (truncated) {
|
|
5280
|
+
file.truncated = true;
|
|
5281
|
+
}
|
|
5282
|
+
return file;
|
|
5283
|
+
}));
|
|
5284
|
+
const files = fileResults.filter((f) => f !== null);
|
|
5285
|
+
return c.json({ files, ...branch ? { branch } : {} });
|
|
5286
|
+
} catch (error) {
|
|
5287
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5288
|
+
return c.json({ error: message }, 500);
|
|
5289
|
+
}
|
|
5290
|
+
});
|
|
5149
5291
|
const BOOLEAN_CLI_FLAGS = /* @__PURE__ */ new Set(["json", "verbose", "global", "noAuth", "expand", "i"]);
|
|
5150
5292
|
function buildCliArgs(pathSegments, query, body) {
|
|
5151
5293
|
const args = [...pathSegments, "--json"];
|
|
@@ -5294,6 +5436,8 @@ async function createAgentServer(params) {
|
|
|
5294
5436
|
process.stderr.write(` POST /api/env/serve \u2014 start dev server (pnpm dev)
|
|
5295
5437
|
`);
|
|
5296
5438
|
process.stderr.write(` POST /api/env/stop \u2014 stop dev server
|
|
5439
|
+
`);
|
|
5440
|
+
process.stderr.write(` GET /api/git/diff \u2014 uncommitted file diffs
|
|
5297
5441
|
`);
|
|
5298
5442
|
process.stderr.write(` * /api/cli/** \u2014 proxy any docyrus CLI command
|
|
5299
5443
|
|
|
@@ -5326,6 +5470,86 @@ async function createAgentServer(params) {
|
|
|
5326
5470
|
}
|
|
5327
5471
|
}
|
|
5328
5472
|
}
|
|
5473
|
+
function extractBearerToken(authorizationHeader) {
|
|
5474
|
+
if (!authorizationHeader) {
|
|
5475
|
+
return null;
|
|
5476
|
+
}
|
|
5477
|
+
const trimmed = authorizationHeader.trim();
|
|
5478
|
+
const firstSpaceIndex = trimmed.indexOf(" ");
|
|
5479
|
+
if (firstSpaceIndex <= 0) {
|
|
5480
|
+
return null;
|
|
5481
|
+
}
|
|
5482
|
+
const scheme = trimmed.slice(0, firstSpaceIndex);
|
|
5483
|
+
const token = trimmed.slice(firstSpaceIndex + 1).trim();
|
|
5484
|
+
if (scheme.toLowerCase() !== "bearer" || token.length === 0) {
|
|
5485
|
+
return null;
|
|
5486
|
+
}
|
|
5487
|
+
return token;
|
|
5488
|
+
}
|
|
5489
|
+
function hashToken(token) {
|
|
5490
|
+
return (0, import_node_crypto2.createHash)("sha256").update(token).digest();
|
|
5491
|
+
}
|
|
5492
|
+
function isBearerTokenAuthorized(actualToken, expectedToken) {
|
|
5493
|
+
if (!expectedToken) {
|
|
5494
|
+
return true;
|
|
5495
|
+
}
|
|
5496
|
+
if (!actualToken) {
|
|
5497
|
+
return false;
|
|
5498
|
+
}
|
|
5499
|
+
const actualHash = hashToken(actualToken);
|
|
5500
|
+
const expectedHash = hashToken(expectedToken);
|
|
5501
|
+
return (0, import_node_crypto2.timingSafeEqual)(actualHash, expectedHash);
|
|
5502
|
+
}
|
|
5503
|
+
function createUnauthorizedResponse() {
|
|
5504
|
+
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
5505
|
+
status: 401,
|
|
5506
|
+
headers: {
|
|
5507
|
+
"Content-Type": "application/json",
|
|
5508
|
+
"WWW-Authenticate": "Bearer"
|
|
5509
|
+
}
|
|
5510
|
+
});
|
|
5511
|
+
}
|
|
5512
|
+
function authorizeServerRequest(request, expectedToken) {
|
|
5513
|
+
if (!expectedToken || request.method === "OPTIONS") {
|
|
5514
|
+
return null;
|
|
5515
|
+
}
|
|
5516
|
+
const authorizationHeader = request.headers.get("Authorization");
|
|
5517
|
+
const token = extractBearerToken(authorizationHeader);
|
|
5518
|
+
if (!isBearerTokenAuthorized(token, expectedToken)) {
|
|
5519
|
+
return createUnauthorizedResponse();
|
|
5520
|
+
}
|
|
5521
|
+
return null;
|
|
5522
|
+
}
|
|
5523
|
+
|
|
5524
|
+
// src/server/loaderRequest.ts
|
|
5525
|
+
function parseServerLoaderRequest(payload) {
|
|
5526
|
+
return JSON.parse(payload);
|
|
5527
|
+
}
|
|
5528
|
+
|
|
5529
|
+
// src/services/spinner.ts
|
|
5530
|
+
var import_picocolors = __toESM(require_picocolors());
|
|
5531
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
5532
|
+
var SPINNER_INTERVAL_MS = 80;
|
|
5533
|
+
function createSpinner(message) {
|
|
5534
|
+
let frameIndex = 0;
|
|
5535
|
+
let currentMessage = message;
|
|
5536
|
+
const render = () => {
|
|
5537
|
+
const frame = import_picocolors.default.cyan(SPINNER_FRAMES[frameIndex]);
|
|
5538
|
+
process.stderr.write(`\r ${frame} ${import_picocolors.default.dim(currentMessage)}`);
|
|
5539
|
+
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
5540
|
+
};
|
|
5541
|
+
render();
|
|
5542
|
+
const interval = setInterval(render, SPINNER_INTERVAL_MS);
|
|
5543
|
+
return {
|
|
5544
|
+
update(newMessage) {
|
|
5545
|
+
currentMessage = newMessage;
|
|
5546
|
+
},
|
|
5547
|
+
stop() {
|
|
5548
|
+
clearInterval(interval);
|
|
5549
|
+
process.stderr.write(`\r${" ".repeat(currentMessage.length + 10)}\r`);
|
|
5550
|
+
}
|
|
5551
|
+
};
|
|
5552
|
+
}
|
|
5329
5553
|
|
|
5330
5554
|
// src/server/server-loader.ts
|
|
5331
5555
|
function readRequiredEnv(name) {
|
|
@@ -5336,7 +5560,7 @@ function readRequiredEnv(name) {
|
|
|
5336
5560
|
return value;
|
|
5337
5561
|
}
|
|
5338
5562
|
function readLoaderRequest() {
|
|
5339
|
-
return
|
|
5563
|
+
return parseServerLoaderRequest(readRequiredEnv("DOCYRUS_PI_REQUEST"));
|
|
5340
5564
|
}
|
|
5341
5565
|
async function loadPiExports() {
|
|
5342
5566
|
const piPackageDir = readRequiredEnv("PI_PACKAGE_DIR");
|
|
@@ -5425,8 +5649,8 @@ function resolveRequestedModel(params) {
|
|
|
5425
5649
|
function renderStartupSplash(version) {
|
|
5426
5650
|
process.stderr.write(
|
|
5427
5651
|
`
|
|
5428
|
-
${
|
|
5429
|
-
${
|
|
5652
|
+
${import_picocolors2.default.bold("DOCYRUS SERVER")} ${import_picocolors2.default.dim(`v${version}`)}
|
|
5653
|
+
${import_picocolors2.default.green("Starting agent server...")}
|
|
5430
5654
|
`
|
|
5431
5655
|
);
|
|
5432
5656
|
}
|
|
@@ -5496,6 +5720,7 @@ async function main() {
|
|
|
5496
5720
|
settingsManager.setLastChangelogVersion(version);
|
|
5497
5721
|
}
|
|
5498
5722
|
renderStartupSplash(version);
|
|
5723
|
+
const spinner = createSpinner("Loading agent...");
|
|
5499
5724
|
const requestedModel = resolveRequestedModel({
|
|
5500
5725
|
request,
|
|
5501
5726
|
modelRegistry
|
|
@@ -5508,6 +5733,7 @@ async function main() {
|
|
|
5508
5733
|
authStorage.setRuntimeApiKey(apiKeyProvider, request.apiKey);
|
|
5509
5734
|
}
|
|
5510
5735
|
const sessionManager = pi.SessionManager.create(cwd, request.sessionDir);
|
|
5736
|
+
spinner.update("Loading resources...");
|
|
5511
5737
|
const resourceLoader = new pi.DefaultResourceLoader({
|
|
5512
5738
|
cwd,
|
|
5513
5739
|
agentDir,
|
|
@@ -5520,6 +5746,7 @@ async function main() {
|
|
|
5520
5746
|
)
|
|
5521
5747
|
});
|
|
5522
5748
|
await resourceLoader.reload();
|
|
5749
|
+
spinner.update("Creating session...");
|
|
5523
5750
|
const { session, extensionsResult } = await pi.createAgentSession({
|
|
5524
5751
|
cwd,
|
|
5525
5752
|
agentDir,
|
|
@@ -5535,6 +5762,7 @@ async function main() {
|
|
|
5535
5762
|
if (hasPackagedMcpAdapter) {
|
|
5536
5763
|
extensionsResult.runtime.flagValues.set("mcp-config", mcpConfigPath);
|
|
5537
5764
|
}
|
|
5765
|
+
spinner.stop();
|
|
5538
5766
|
if (!session.model) {
|
|
5539
5767
|
throw new Error(
|
|
5540
5768
|
`No models available.
|
|
@@ -5547,6 +5775,7 @@ Or create ${modelsJsonPath}`
|
|
|
5547
5775
|
}
|
|
5548
5776
|
await createAgentServer({
|
|
5549
5777
|
session: createServerSessionAdapter({ session, extensionsResult }),
|
|
5778
|
+
authToken: request.auth,
|
|
5550
5779
|
port: request.port,
|
|
5551
5780
|
sessionManager: {
|
|
5552
5781
|
list: () => pi.SessionManager.list(cwd, request.sessionDir),
|