pinomad 0.5.0 → 0.7.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 +2 -2
- package/dist/{chunk-f0v3sht0.js → chunk-07769pqx.js} +10 -8
- package/dist/{chunk-ebfaf3k2.js → chunk-0xh6cy9v.js} +1 -1
- package/dist/{chunk-aqj4wg33.js → chunk-12kaxggg.js} +29 -12
- package/dist/{chunk-d4wdt5qs.js → chunk-1nyzr0mg.js} +2282 -1027
- package/dist/chunk-1t58fh0k.js +16 -0
- package/dist/{chunk-4by4x5c4.js → chunk-6ysezfy5.js} +44 -14
- package/dist/{chunk-kmbh44dt.js → chunk-7qb9tq54.js} +42 -6
- package/dist/{chunk-gqr7ahv4.js → chunk-8yme2wep.js} +2 -2
- package/dist/chunk-b1h374jr.js +159 -0
- package/dist/{chunk-hsp12cjt.js → chunk-e4ahjbmz.js} +212 -50
- package/dist/{chunk-9d59jjmt.js → chunk-fbkd73zr.js} +36 -10
- package/dist/chunk-kzbzacz9.js +12 -0
- package/dist/{chunk-zttf1hvh.js → chunk-m4c5gvce.js} +4 -3
- package/dist/{chunk-cjfmfyjb.js → chunk-ngf1zatm.js} +7 -6
- package/dist/{chunk-1d9sppj0.js → chunk-rtwxjb90.js} +1 -1
- package/dist/{chunk-m4q9wafw.js → chunk-sj7rnvh4.js} +118 -6
- package/dist/chunk-sz3rzk55.js +79 -0
- package/dist/{chunk-26d04z02.js → chunk-ywmm63ks.js} +7 -3
- package/dist/chunk-znhn8af7.js +33 -0
- package/dist/pinomad.js +36 -12
- package/package.json +1 -1
- package/web/assets/index-C0rwAo0H.css +1 -0
- package/web/assets/index-DGee2kNU.js +394 -0
- package/web/index.html +2 -2
- package/dist/chunk-5ng86fmy.js +0 -14
- package/dist/chunk-crv3dqzp.js +0 -63
- package/web/assets/index-BkF0-im5.css +0 -1
- package/web/assets/index-D4lgm3Y4.js +0 -383
- package/web/assets/montserrat-latin-ext-wght-normal-BsZE-iaG.woff2 +0 -0
- package/web/assets/montserrat-latin-wght-normal-l_AIctKy.woff2 +0 -0
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
followUpMode: true,
|
|
7
|
-
acceptAccountDevices: true
|
|
8
|
-
};
|
|
9
|
-
var HOST_SETTING_KEYS = Object.keys(HOST_SETTING_KEY_SET);
|
|
10
|
-
var THINKING_LEVEL_KEYS = { off: true, minimal: true, low: true, medium: true, high: true, xhigh: true, max: true };
|
|
11
|
-
var THINKING_LEVELS = Object.keys(THINKING_LEVEL_KEYS);
|
|
12
|
-
var isThinkingLevel = (value) => typeof value === "string" && Object.prototype.hasOwnProperty.call(THINKING_LEVEL_KEYS, value);
|
|
13
|
-
var isQueueMode = (value) => value === "all" || value === "one-at-a-time";
|
|
1
|
+
import {
|
|
2
|
+
HOST_SETTING_KEYS,
|
|
3
|
+
isQueueMode,
|
|
4
|
+
isThinkingLevel
|
|
5
|
+
} from "./chunk-znhn8af7.js";
|
|
14
6
|
|
|
15
7
|
// packages/protocol/src/frames.ts
|
|
16
8
|
var HOST_STREAMS = { conversations: 0, index: 0, devices: 0, mcp: 0, models: 1, auth: 1, settings: 2, agents: 6 };
|
|
@@ -22,22 +14,55 @@ var conversationStream = (id) => `conversation:${id}`;
|
|
|
22
14
|
var docStream = (kind, id) => `doc:${kind}:${id}`;
|
|
23
15
|
var UNAUTHORIZED_CLOSE_CODE = 4401;
|
|
24
16
|
var INVALID_FRAME_CLOSE_CODE = 4400;
|
|
25
|
-
var PROTOCOL = { major: 5, minor:
|
|
17
|
+
var PROTOCOL = { major: 5, minor: 19 };
|
|
26
18
|
var CALL_SINCE = {
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
addProject: 0,
|
|
20
|
+
removeProject: 0,
|
|
29
21
|
listFolders: 3,
|
|
22
|
+
listFiles: 10,
|
|
23
|
+
listSkills: 13,
|
|
24
|
+
listCommands: 17,
|
|
25
|
+
createConversation: 0,
|
|
26
|
+
archive: 0,
|
|
30
27
|
renameConversation: 4,
|
|
28
|
+
submit: 0,
|
|
29
|
+
withdrawQueued: 14,
|
|
30
|
+
steerQueued: 14,
|
|
31
|
+
abort: 0,
|
|
32
|
+
compact: 0,
|
|
33
|
+
runCommand: 17,
|
|
34
|
+
setModel: 0,
|
|
35
|
+
setThinkingLevel: 0,
|
|
36
|
+
setAgent: 18,
|
|
37
|
+
fork: 0,
|
|
38
|
+
answer: 0,
|
|
39
|
+
changes: 0,
|
|
40
|
+
createPairing: 0,
|
|
41
|
+
revokeDevice: 0,
|
|
42
|
+
logout: 1,
|
|
43
|
+
updateSettings: 2,
|
|
31
44
|
createAgent: 6,
|
|
32
45
|
updateAgent: 6,
|
|
33
46
|
deleteAgent: 6,
|
|
34
47
|
setPushToken: 7,
|
|
35
|
-
|
|
48
|
+
image: 15,
|
|
49
|
+
beginAttachment: 19,
|
|
50
|
+
appendAttachment: 19
|
|
36
51
|
};
|
|
37
52
|
function hostSupportsCall(hostMinor, method) {
|
|
38
|
-
return hostMinor >=
|
|
53
|
+
return hostMinor >= CALL_SINCE[method];
|
|
39
54
|
}
|
|
40
|
-
var FEATURE_SINCE = {
|
|
55
|
+
var FEATURE_SINCE = {
|
|
56
|
+
images: 5,
|
|
57
|
+
acceptAccountDevices: 8,
|
|
58
|
+
apnsPush: 9,
|
|
59
|
+
agentConversations: 10,
|
|
60
|
+
liveBranch: 11,
|
|
61
|
+
hostName: 12,
|
|
62
|
+
imageRefs: 15,
|
|
63
|
+
boundSkills: 16,
|
|
64
|
+
attachments: 19
|
|
65
|
+
};
|
|
41
66
|
function hostSupportsFeature(hostMinor, feature) {
|
|
42
67
|
return hostMinor >= FEATURE_SINCE[feature];
|
|
43
68
|
}
|
|
@@ -49,7 +74,8 @@ function parseClientFrame(value) {
|
|
|
49
74
|
if (typeof stream !== "string")
|
|
50
75
|
return { kind: "malformed" };
|
|
51
76
|
if (isStreamName(stream)) {
|
|
52
|
-
|
|
77
|
+
const refs = value.type === "subscribe" && value.images === "ref";
|
|
78
|
+
return { kind: "frame", frame: refs ? { type: "subscribe", stream, images: "ref" } : { type: value.type, stream } };
|
|
53
79
|
}
|
|
54
80
|
const prefix = stream.slice(0, stream.indexOf(":") === -1 ? undefined : stream.indexOf(":"));
|
|
55
81
|
if (STREAM_KINDS.has(prefix))
|
|
@@ -71,51 +97,40 @@ function isStreamName(stream) {
|
|
|
71
97
|
return stream === "tasks" || HOST_STREAM_NAMES.includes(stream) || /^(?:conversation:|doc:.+:)[1-9]\d*$/.test(stream);
|
|
72
98
|
}
|
|
73
99
|
var isCallMethod = (method) => CALL_METHODS.includes(method);
|
|
74
|
-
var CALL_METHODS =
|
|
75
|
-
"addProject",
|
|
76
|
-
"removeProject",
|
|
77
|
-
"listFolders",
|
|
78
|
-
"createConversation",
|
|
79
|
-
"archive",
|
|
80
|
-
"renameConversation",
|
|
81
|
-
"submit",
|
|
82
|
-
"abort",
|
|
83
|
-
"compact",
|
|
84
|
-
"setModel",
|
|
85
|
-
"setThinkingLevel",
|
|
86
|
-
"fork",
|
|
87
|
-
"answer",
|
|
88
|
-
"changes",
|
|
89
|
-
"createPairing",
|
|
90
|
-
"revokeDevice",
|
|
91
|
-
"logout",
|
|
92
|
-
"updateSettings",
|
|
93
|
-
"createAgent",
|
|
94
|
-
"updateAgent",
|
|
95
|
-
"deleteAgent",
|
|
96
|
-
"setPushToken",
|
|
97
|
-
"listFiles"
|
|
98
|
-
];
|
|
100
|
+
var CALL_METHODS = Object.keys(CALL_SINCE);
|
|
99
101
|
var SETTING_VALIDATORS = {
|
|
100
102
|
defaultModel: (value) => value === null || record(value) && nonempty(value.provider) && nonempty(value.modelId),
|
|
101
103
|
defaultThinkingLevel: (value) => value === null || isThinkingLevel(value),
|
|
102
104
|
steeringMode: (value) => value === null || isQueueMode(value),
|
|
103
105
|
followUpMode: (value) => value === null || isQueueMode(value),
|
|
104
|
-
acceptAccountDevices: (value) => value === null || typeof value === "boolean"
|
|
106
|
+
acceptAccountDevices: (value) => value === null || typeof value === "boolean",
|
|
107
|
+
hostName: (value) => value === null || typeof value === "string"
|
|
105
108
|
};
|
|
106
109
|
function validCallArgs(method, args) {
|
|
107
110
|
const conversationId = () => typeof args.conversationId === "number" && Number.isSafeInteger(args.conversationId) && args.conversationId >= 1;
|
|
108
|
-
const
|
|
111
|
+
const submissionId = () => typeof args.submissionId === "number" && Number.isSafeInteger(args.submissionId) && args.submissionId >= 1;
|
|
112
|
+
const images = () => args.images === undefined || Array.isArray(args.images) && args.images.every((image) => record(image) && ("data" in image ? typeof image.data === "string" && typeof image.mimeType === "string" : nonempty(image.ref)));
|
|
113
|
+
const skills = () => args.skills === undefined || Array.isArray(args.skills) && args.skills.every(nonempty);
|
|
114
|
+
const attachments = () => args.attachments === undefined || Array.isArray(args.attachments) && args.attachments.every(nonempty);
|
|
109
115
|
const role = () => record(args.role) && typeof args.role.name === "string" && typeof args.role.description === "string" && typeof args.role.prompt === "string" && (args.role.model === undefined || typeof args.role.model === "string") && (args.role.thinkingLevel === undefined || typeof args.role.thinkingLevel === "string");
|
|
110
116
|
switch (method) {
|
|
111
117
|
case "submit":
|
|
112
|
-
return conversationId() && typeof args.text === "string" && (args.whenBusy === "steer" || args.whenBusy === "followUp") && nonempty(args.requestId) && images();
|
|
118
|
+
return conversationId() && typeof args.text === "string" && (args.whenBusy === "steer" || args.whenBusy === "followUp") && nonempty(args.requestId) && images() && skills() && attachments();
|
|
119
|
+
case "withdrawQueued":
|
|
120
|
+
case "steerQueued":
|
|
121
|
+
return conversationId() && submissionId();
|
|
113
122
|
case "abort":
|
|
114
123
|
return conversationId();
|
|
115
124
|
case "setThinkingLevel":
|
|
116
125
|
return conversationId() && nonempty(args.level);
|
|
126
|
+
case "setAgent":
|
|
127
|
+
return conversationId() && (args.agent === null || nonempty(args.agent));
|
|
117
128
|
case "compact":
|
|
118
129
|
return conversationId() && (args.instructions === undefined || typeof args.instructions === "string");
|
|
130
|
+
case "listCommands":
|
|
131
|
+
return conversationId();
|
|
132
|
+
case "runCommand":
|
|
133
|
+
return conversationId() && nonempty(args.name) && (args.args === undefined || typeof args.args === "string");
|
|
119
134
|
case "setModel":
|
|
120
135
|
return conversationId() && record(args.model) && nonempty(args.model.provider) && nonempty(args.model.modelId);
|
|
121
136
|
case "fork":
|
|
@@ -124,15 +139,23 @@ function validCallArgs(method, args) {
|
|
|
124
139
|
return conversationId() && nonempty(args.kind) && nonempty(args.requestId) && Array.isArray(args.answers) && args.answers.every((answer) => record(answer) && Array.isArray(answer.selected) && answer.selected.every((l) => typeof l === "string") && (answer.other === undefined || typeof answer.other === "string"));
|
|
125
140
|
case "changes":
|
|
126
141
|
return conversationId();
|
|
142
|
+
case "image":
|
|
143
|
+
return nonempty(args.ref);
|
|
144
|
+
case "beginAttachment":
|
|
145
|
+
return nonempty(args.name) && typeof args.size === "number" && Number.isSafeInteger(args.size) && args.size >= 0;
|
|
146
|
+
case "appendAttachment":
|
|
147
|
+
return nonempty(args.attachmentId) && typeof args.offset === "number" && Number.isSafeInteger(args.offset) && args.offset >= 0 && typeof args.data === "string";
|
|
127
148
|
case "addProject":
|
|
128
149
|
case "removeProject":
|
|
129
150
|
return nonempty(args.path);
|
|
130
151
|
case "listFolders":
|
|
131
152
|
return args.path === undefined || nonempty(args.path);
|
|
132
153
|
case "createConversation":
|
|
133
|
-
return record(args.home) && (args.home.kind === "chat" || args.home.kind === "project" && nonempty(args.home.path)) && typeof args.text === "string" && (nonempty(args.text) || Array.isArray(args.images) && args.images.length > 0) && nonempty(args.requestId) && images() && (args.checkout === undefined || args.checkout === "worktree" || args.checkout === "project") && (args.model === undefined || record(args.model) && nonempty(args.model.provider) && nonempty(args.model.modelId)) && (args.thinkingLevel === undefined || nonempty(args.thinkingLevel)) && (args.agent === undefined || nonempty(args.agent));
|
|
154
|
+
return record(args.home) && (args.home.kind === "chat" || args.home.kind === "project" && nonempty(args.home.path)) && typeof args.text === "string" && (nonempty(args.text) || Array.isArray(args.images) && args.images.length > 0 || Array.isArray(args.attachments) && args.attachments.length > 0) && nonempty(args.requestId) && images() && skills() && attachments() && (args.checkout === undefined || args.checkout === "worktree" || args.checkout === "project") && (args.model === undefined || record(args.model) && nonempty(args.model.provider) && nonempty(args.model.modelId)) && (args.thinkingLevel === undefined || nonempty(args.thinkingLevel)) && (args.agent === undefined || nonempty(args.agent));
|
|
134
155
|
case "listFiles":
|
|
135
156
|
return typeof args.query === "string" && record(args.scope) && (args.scope.kind === "conversation" && typeof args.scope.conversationId === "number" && Number.isSafeInteger(args.scope.conversationId) && args.scope.conversationId >= 1 || args.scope.kind === "project" && nonempty(args.scope.path) && (args.scope.checkout === "worktree" || args.scope.checkout === "project"));
|
|
157
|
+
case "listSkills":
|
|
158
|
+
return record(args.scope) && (args.scope.kind === "conversation" && typeof args.scope.conversationId === "number" && Number.isSafeInteger(args.scope.conversationId) && args.scope.conversationId >= 1 || args.scope.kind === "project" && nonempty(args.scope.path) && (args.scope.checkout === "worktree" || args.scope.checkout === "project") || args.scope.kind === "chat");
|
|
136
159
|
case "archive":
|
|
137
160
|
return conversationId() && typeof args.archived === "boolean";
|
|
138
161
|
case "renameConversation":
|
|
@@ -161,6 +184,145 @@ function nonempty(value) {
|
|
|
161
184
|
return typeof value === "string" && value.length > 0;
|
|
162
185
|
}
|
|
163
186
|
|
|
187
|
+
// packages/protocol/src/attachments.ts
|
|
188
|
+
var MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
|
|
189
|
+
var MAX_ATTACHMENTS_PER_MESSAGE = 10;
|
|
190
|
+
var ATTACHMENT_CHUNK_BYTES = 512 * 1024;
|
|
191
|
+
var MAX_PENDING_ATTACHMENTS = 20;
|
|
192
|
+
var MAX_PENDING_ATTACHMENT_BYTES = 200 * 1024 * 1024;
|
|
193
|
+
var ATTACHMENT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
194
|
+
var MAX_ATTACHMENT_NAME_LENGTH = 255;
|
|
195
|
+
var ATTACHMENT_ID_PATTERN = /^[A-Za-z0-9_-]{22}$/;
|
|
196
|
+
function isAttachmentId(value) {
|
|
197
|
+
return ATTACHMENT_ID_PATTERN.test(value);
|
|
198
|
+
}
|
|
199
|
+
var ATTACHMENTS_OPEN = '<attachments v="1">';
|
|
200
|
+
var ATTACHMENTS_INSTRUCTION = "The user attached these files. They are read-only originals on this machine: read them with your tools when relevant, and copy one into the working directory before changing it.";
|
|
201
|
+
var ATTACHMENTS_CLOSE = "</attachments>";
|
|
202
|
+
var BASE64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
203
|
+
function base64DecodedLength(data) {
|
|
204
|
+
if (data.length % 4 !== 0 || !BASE64.test(data))
|
|
205
|
+
return;
|
|
206
|
+
const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
|
|
207
|
+
return data.length * 3 / 4 - padding;
|
|
208
|
+
}
|
|
209
|
+
function attachmentBeginProblem(name, size) {
|
|
210
|
+
if (name.trim() === "")
|
|
211
|
+
return "Attachment name cannot be empty";
|
|
212
|
+
if (!Number.isSafeInteger(size) || size < 0)
|
|
213
|
+
return "Attachment size must be a non-negative integer";
|
|
214
|
+
if (size > MAX_ATTACHMENT_BYTES)
|
|
215
|
+
return `Attachment is larger than ${MAX_ATTACHMENT_BYTES / (1024 * 1024)} MB`;
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
function attachmentChunkProblem(data) {
|
|
219
|
+
const size = base64DecodedLength(data);
|
|
220
|
+
if (size === undefined)
|
|
221
|
+
return "Attachment chunk is not valid base64";
|
|
222
|
+
if (size > ATTACHMENT_CHUNK_BYTES)
|
|
223
|
+
return `Attachment chunk is larger than ${ATTACHMENT_CHUNK_BYTES / 1024} KiB`;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
function xmlAttribute(value) {
|
|
227
|
+
let out = "";
|
|
228
|
+
for (let i = 0;i < value.length; i++) {
|
|
229
|
+
const unit = value.charCodeAt(i);
|
|
230
|
+
if (unit === 38)
|
|
231
|
+
out += "&";
|
|
232
|
+
else if (unit === 60)
|
|
233
|
+
out += "<";
|
|
234
|
+
else if (unit === 62)
|
|
235
|
+
out += ">";
|
|
236
|
+
else if (unit === 34)
|
|
237
|
+
out += """;
|
|
238
|
+
else if (unit < 32 || unit === 127)
|
|
239
|
+
out += `&#x${unit.toString(16)};`;
|
|
240
|
+
else
|
|
241
|
+
out += value[i];
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
function attachmentBlock(files) {
|
|
246
|
+
const lines = [
|
|
247
|
+
ATTACHMENTS_OPEN,
|
|
248
|
+
ATTACHMENTS_INSTRUCTION,
|
|
249
|
+
...files.map((file) => `<file id="${xmlAttribute(file.id)}" name="${xmlAttribute(file.name)}" path="${xmlAttribute(file.path)}" size="${file.size}"/>`),
|
|
250
|
+
ATTACHMENTS_CLOSE
|
|
251
|
+
];
|
|
252
|
+
return lines.join(`
|
|
253
|
+
`);
|
|
254
|
+
}
|
|
255
|
+
var FILE_OPEN = '<file id="';
|
|
256
|
+
var FILE_NAME = '" name="';
|
|
257
|
+
var FILE_PATH = '" path="';
|
|
258
|
+
var FILE_SIZE = '" size="';
|
|
259
|
+
var FILE_END = '"/>';
|
|
260
|
+
var SIZE = /^(?:0|[1-9][0-9]*)$/;
|
|
261
|
+
function decodeXmlAttribute(value) {
|
|
262
|
+
return value.replace(/&(amp|lt|gt|quot|apos|#x[0-9A-Fa-f]+|#[0-9]+);/g, (entity, body) => {
|
|
263
|
+
if (body === "amp")
|
|
264
|
+
return "&";
|
|
265
|
+
if (body === "lt")
|
|
266
|
+
return "<";
|
|
267
|
+
if (body === "gt")
|
|
268
|
+
return ">";
|
|
269
|
+
if (body === "quot")
|
|
270
|
+
return '"';
|
|
271
|
+
if (body === "apos")
|
|
272
|
+
return "'";
|
|
273
|
+
const code = body.startsWith("#x") ? parseInt(body.slice(2), 16) : parseInt(body.slice(1), 10);
|
|
274
|
+
return code >= 0 && code <= 1114111 ? String.fromCodePoint(code) : entity;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function quoted(text, at, marker) {
|
|
278
|
+
if (!text.startsWith(marker, at))
|
|
279
|
+
return;
|
|
280
|
+
const start = at + marker.length;
|
|
281
|
+
const end = text.indexOf('"', start);
|
|
282
|
+
if (end === -1)
|
|
283
|
+
return;
|
|
284
|
+
return { value: text.slice(start, end), next: end };
|
|
285
|
+
}
|
|
286
|
+
function parseFileLine(line) {
|
|
287
|
+
const id = quoted(line, 0, FILE_OPEN);
|
|
288
|
+
if (id === undefined)
|
|
289
|
+
return;
|
|
290
|
+
const name = quoted(line, id.next, FILE_NAME);
|
|
291
|
+
if (name === undefined)
|
|
292
|
+
return;
|
|
293
|
+
const path = quoted(line, name.next, FILE_PATH);
|
|
294
|
+
if (path === undefined)
|
|
295
|
+
return;
|
|
296
|
+
const size = quoted(line, path.next, FILE_SIZE);
|
|
297
|
+
if (size === undefined || !line.startsWith(FILE_END, size.next) || size.next + FILE_END.length !== line.length) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (!isAttachmentId(id.value) || !SIZE.test(size.value))
|
|
301
|
+
return;
|
|
302
|
+
const bytes = Number(size.value);
|
|
303
|
+
if (!Number.isSafeInteger(bytes))
|
|
304
|
+
return;
|
|
305
|
+
return { id: id.value, name: decodeXmlAttribute(name.value), size: bytes };
|
|
306
|
+
}
|
|
307
|
+
function parseAttachmentBlock(text) {
|
|
308
|
+
if (!text.startsWith(ATTACHMENTS_OPEN + `
|
|
309
|
+
`) || !text.endsWith(`
|
|
310
|
+
` + ATTACHMENTS_CLOSE))
|
|
311
|
+
return;
|
|
312
|
+
const lines = text.slice(ATTACHMENTS_OPEN.length + 1, -(ATTACHMENTS_CLOSE.length + 1)).split(`
|
|
313
|
+
`);
|
|
314
|
+
if (lines[0] !== ATTACHMENTS_INSTRUCTION || lines.length < 2)
|
|
315
|
+
return;
|
|
316
|
+
const files = [];
|
|
317
|
+
for (const line of lines.slice(1)) {
|
|
318
|
+
const file = parseFileLine(line);
|
|
319
|
+
if (file === undefined)
|
|
320
|
+
return;
|
|
321
|
+
files.push(file);
|
|
322
|
+
}
|
|
323
|
+
return files;
|
|
324
|
+
}
|
|
325
|
+
|
|
164
326
|
// packages/protocol/src/organization.ts
|
|
165
327
|
function organize(index, summaries) {
|
|
166
328
|
const summaryById = new Map(summaries.map((summary) => [summary.id, summary]));
|
|
@@ -254,4 +416,4 @@ function homeOf(index, summaries, id) {
|
|
|
254
416
|
return;
|
|
255
417
|
}
|
|
256
418
|
|
|
257
|
-
export {
|
|
419
|
+
export { HOST_STREAM_NAMES, hostStreams, conversationStream, docStream, UNAUTHORIZED_CLOSE_CODE, INVALID_FRAME_CLOSE_CODE, PROTOCOL, hostSupportsCall, hostSupportsFeature, parseClientFrame, MAX_ATTACHMENTS_PER_MESSAGE, MAX_PENDING_ATTACHMENTS, MAX_PENDING_ATTACHMENT_BYTES, ATTACHMENT_TTL_MS, MAX_ATTACHMENT_NAME_LENGTH, isAttachmentId, base64DecodedLength, attachmentBeginProblem, attachmentChunkProblem, attachmentBlock, parseAttachmentBlock, organize, checkoutOf, homeOf };
|
|
@@ -3,43 +3,55 @@ import {
|
|
|
3
3
|
assertSecureServerOrigin,
|
|
4
4
|
probeServerAccounts,
|
|
5
5
|
runServerOperation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ywmm63ks.js";
|
|
7
|
+
import {
|
|
8
|
+
constantValue,
|
|
9
|
+
openHostSettings
|
|
10
|
+
} from "./chunk-b1h374jr.js";
|
|
7
11
|
import {
|
|
8
12
|
loadHostKey,
|
|
9
13
|
loadRelayKey,
|
|
10
14
|
writeServerConfig
|
|
11
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-0xh6cy9v.js";
|
|
12
16
|
import {
|
|
13
17
|
relayHostId
|
|
14
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-7qb9tq54.js";
|
|
15
19
|
import {
|
|
16
20
|
argValue,
|
|
17
21
|
installSpec,
|
|
18
22
|
restartService,
|
|
19
23
|
serviceManager,
|
|
20
24
|
withoutRelayArgs
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-12kaxggg.js";
|
|
26
|
+
import"./chunk-kzbzacz9.js";
|
|
22
27
|
import {
|
|
23
28
|
commandHint,
|
|
24
29
|
hostEntry
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import"./chunk-
|
|
27
|
-
import"./chunk-
|
|
30
|
+
} from "./chunk-rtwxjb90.js";
|
|
31
|
+
import"./chunk-sj7rnvh4.js";
|
|
32
|
+
import"./chunk-e4ahjbmz.js";
|
|
33
|
+
import {
|
|
34
|
+
cleanHostName,
|
|
35
|
+
normalizeHostName
|
|
36
|
+
} from "./chunk-znhn8af7.js";
|
|
28
37
|
import {
|
|
29
38
|
DEFAULT_DATA_DIR
|
|
30
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-ngf1zatm.js";
|
|
31
40
|
import"./chunk-df32avw6.js";
|
|
32
41
|
|
|
33
42
|
// apps/host/src/cli/join.ts
|
|
34
43
|
import { mkdir } from "node:fs/promises";
|
|
35
44
|
import { homedir, hostname } from "node:os";
|
|
36
|
-
import { resolve } from "node:path";
|
|
45
|
+
import { join, resolve } from "node:path";
|
|
37
46
|
import { parseArgs } from "node:util";
|
|
38
47
|
var message = (error) => error instanceof Error ? error.message : String(error);
|
|
39
48
|
async function joinServer(args, deps) {
|
|
40
49
|
const origin = args.origin.replace(/\/+$/, "");
|
|
41
50
|
const dataDir = resolve(args.dataDir);
|
|
42
51
|
assertSecureServerOrigin(origin);
|
|
52
|
+
if (args.name !== undefined && cleanHostName(args.name) === "") {
|
|
53
|
+
throw new Error(`Invalid host name: ${JSON.stringify(args.name)}`);
|
|
54
|
+
}
|
|
43
55
|
await mkdir(dataDir, { recursive: true });
|
|
44
56
|
const signingKey = await loadRelayKey(dataDir);
|
|
45
57
|
const hostKey = await loadHostKey(dataDir);
|
|
@@ -56,13 +68,25 @@ async function joinServer(args, deps) {
|
|
|
56
68
|
if (probe === "disabled") {
|
|
57
69
|
throw new Error(`${origin} does not run server accounts — the server is too old or was started without a data dir`);
|
|
58
70
|
}
|
|
71
|
+
const settings = await openHostSettings({
|
|
72
|
+
path: join(dataDir, "settings.json"),
|
|
73
|
+
fallback: {
|
|
74
|
+
defaultModel: () => null,
|
|
75
|
+
defaultThinkingLevel: () => null,
|
|
76
|
+
steeringMode: () => "one-at-a-time",
|
|
77
|
+
followUpMode: () => "one-at-a-time"
|
|
78
|
+
},
|
|
79
|
+
models: constantValue([])
|
|
80
|
+
});
|
|
81
|
+
const current = settings.value;
|
|
82
|
+
const storedName = current.custom.includes("hostName") ? current.hostName : undefined;
|
|
59
83
|
const reply = await runServerOperation({
|
|
60
84
|
origin,
|
|
61
85
|
signingKey,
|
|
62
86
|
noisePublicKey: hostKey.publicKey,
|
|
63
87
|
op: "join",
|
|
64
88
|
joinToken: args.token,
|
|
65
|
-
name: args.name ?? deps?.hostname ?? hostname()
|
|
89
|
+
name: normalizeHostName(args.name ?? storedName ?? deps?.hostname ?? hostname())
|
|
66
90
|
});
|
|
67
91
|
if (reply.t === "refused") {
|
|
68
92
|
throw new Error(reply.reason === "expired_token" ? "the join token expired — generate a fresh one" : reply.reason === "invalid_token" ? "the join token is invalid or already spent — generate a fresh one" : `the server refused the join: ${reply.reason}`);
|
|
@@ -73,6 +97,8 @@ async function joinServer(args, deps) {
|
|
|
73
97
|
let service;
|
|
74
98
|
try {
|
|
75
99
|
await writeServerConfig(dataDir, { origin });
|
|
100
|
+
if (args.name !== undefined)
|
|
101
|
+
await settings.update({ hostName: args.name });
|
|
76
102
|
const freshSpec = installSpec(["--data-dir", dataDir], {
|
|
77
103
|
execPath: process.execPath,
|
|
78
104
|
env: process.env,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// apps/host/src/cli/args.ts
|
|
2
|
+
function isParseArgsError(error) {
|
|
3
|
+
const code = error.code;
|
|
4
|
+
return typeof code === "string" && code.startsWith("ERR_PARSE_ARGS_");
|
|
5
|
+
}
|
|
6
|
+
function reportParseArgsError(command, error) {
|
|
7
|
+
console.error(`${command}: ${error instanceof Error ? error.message : String(error)}`);
|
|
8
|
+
console.error(`run "${command} --help" for usage`);
|
|
9
|
+
process.exitCode = 2;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { isParseArgsError, reportParseArgsError };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connectRemoteDurable
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import"./chunk-
|
|
3
|
+
} from "./chunk-sj7rnvh4.js";
|
|
4
|
+
import"./chunk-e4ahjbmz.js";
|
|
5
|
+
import"./chunk-znhn8af7.js";
|
|
5
6
|
import {
|
|
6
7
|
hostAddress
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ngf1zatm.js";
|
|
8
9
|
import"./chunk-df32avw6.js";
|
|
9
10
|
|
|
10
11
|
// apps/host/src/cli/pair.ts
|
|
@@ -4,18 +4,19 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
6
6
|
var DEFAULT_DATA_DIR = process.env.PINOMAD_DATA_DIR ?? join(homedir(), ".pinomad");
|
|
7
|
+
var hostAddressOptions = {
|
|
8
|
+
"data-dir": { type: "string" },
|
|
9
|
+
url: { type: "string", default: "ws://127.0.0.1:7420" },
|
|
10
|
+
token: { type: "string" }
|
|
11
|
+
};
|
|
7
12
|
async function hostAddress(argv) {
|
|
8
13
|
const { values } = parseArgs({
|
|
9
14
|
args: [...argv],
|
|
10
|
-
options:
|
|
11
|
-
"data-dir": { type: "string" },
|
|
12
|
-
url: { type: "string", default: "ws://127.0.0.1:7420" },
|
|
13
|
-
token: { type: "string" }
|
|
14
|
-
}
|
|
15
|
+
options: hostAddressOptions
|
|
15
16
|
});
|
|
16
17
|
const dataDir = resolve(values["data-dir"] ?? DEFAULT_DATA_DIR);
|
|
17
18
|
const token = values.token ?? (await readFile(join(dataDir, "token"), "utf8")).trim();
|
|
18
19
|
return { url: values.url, token, dataDir };
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export { DEFAULT_DATA_DIR, hostAddress };
|
|
22
|
+
export { DEFAULT_DATA_DIR, hostAddressOptions, hostAddress };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// apps/host/src/distribution.ts
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
var packagedVersion = "0.
|
|
3
|
+
var packagedVersion = "0.7.0";
|
|
4
4
|
var webRoot = fileURLToPath(new URL(packagedVersion === undefined ? "../../web/dist" : "../web/", import.meta.url));
|
|
5
5
|
var hostEntry = packagedVersion === undefined ? { script: fileURLToPath(new URL("./main.ts", import.meta.url)), args: [] } : { script: fileURLToPath(new URL("./pinomad.js", import.meta.url)), args: ["host"] };
|
|
6
6
|
var commandHint = (name) => packagedVersion === undefined ? `bun run ${name}` : `pinomad ${name}`;
|