@poncho-ai/cli 0.38.1 → 0.40.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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +170 -0
- package/dist/{chunk-W7SQVUB4.js → chunk-KVGMTYDD.js} +1959 -66
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-interactive-ink-UKPUGCDW.js → run-interactive-ink-LJTKUUV4.js} +1 -1
- package/package.json +4 -4
- package/src/index.ts +366 -6
- package/src/init-onboarding.ts +8 -2
- package/src/scaffolding.ts +75 -13
- package/src/templates.ts +5 -1
- package/src/vfs-zip.ts +94 -0
- package/src/web-ui-client.ts +1022 -0
- package/src/web-ui-styles.ts +408 -1
- package/src/web-ui.ts +6 -0
package/src/scaffolding.ts
CHANGED
|
@@ -25,7 +25,8 @@ export const normalizeDeployTarget = (target: string): DeployScaffoldTarget => {
|
|
|
25
25
|
normalized === "vercel" ||
|
|
26
26
|
normalized === "docker" ||
|
|
27
27
|
normalized === "lambda" ||
|
|
28
|
-
normalized === "fly"
|
|
28
|
+
normalized === "fly" ||
|
|
29
|
+
normalized === "railway"
|
|
29
30
|
) {
|
|
30
31
|
return normalized;
|
|
31
32
|
}
|
|
@@ -223,6 +224,25 @@ const port = Number.parseInt(process.env.PORT ?? "3000", 10);
|
|
|
223
224
|
await startDevServer(Number.isNaN(port) ? 3000 : port, { workingDir: process.cwd() });
|
|
224
225
|
`;
|
|
225
226
|
|
|
227
|
+
let browserEnabled = false;
|
|
228
|
+
try {
|
|
229
|
+
const cfg = await loadPonchoConfig(projectDir);
|
|
230
|
+
browserEnabled = !!cfg?.browser;
|
|
231
|
+
} catch { /* best-effort */ }
|
|
232
|
+
|
|
233
|
+
// Chromium runtime libs for Playwright when `browser: true`. Built as a
|
|
234
|
+
// single apt-get layer so it can be inserted verbatim into Dockerfiles
|
|
235
|
+
// for docker/railway/fly targets and stripped out otherwise.
|
|
236
|
+
const chromiumLibsLayer = browserEnabled
|
|
237
|
+
? `RUN apt-get update && apt-get install -y --no-install-recommends \\
|
|
238
|
+
ca-certificates fonts-liberation libnss3 libatk1.0-0 libatk-bridge2.0-0 \\
|
|
239
|
+
libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \\
|
|
240
|
+
libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound2 \\
|
|
241
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
242
|
+
|
|
243
|
+
`
|
|
244
|
+
: "";
|
|
245
|
+
|
|
226
246
|
if (target === "vercel") {
|
|
227
247
|
// Build @vercel/nft trace hints for packages that are dynamically loaded
|
|
228
248
|
// at runtime. Bare `import("pkg")` with a string literal is enough for
|
|
@@ -231,12 +251,6 @@ await startDevServer(Number.isNaN(port) ? 3000 : port, { workingDir: process.cwd
|
|
|
231
251
|
// an optional package isn't installed.
|
|
232
252
|
const traceHints: string[] = [];
|
|
233
253
|
|
|
234
|
-
let browserEnabled = false;
|
|
235
|
-
try {
|
|
236
|
-
const cfg = await loadPonchoConfig(projectDir);
|
|
237
|
-
browserEnabled = !!cfg?.browser;
|
|
238
|
-
} catch { /* best-effort */ }
|
|
239
|
-
|
|
240
254
|
if (browserEnabled) {
|
|
241
255
|
traceHints.push(`import("@poncho-ai/browser").catch(() => {});`);
|
|
242
256
|
|
|
@@ -346,16 +360,19 @@ export default async function handler(req, res) {
|
|
|
346
360
|
const dockerfilePath = resolve(projectDir, "Dockerfile");
|
|
347
361
|
await writeScaffoldFile(
|
|
348
362
|
dockerfilePath,
|
|
349
|
-
`FROM node:
|
|
363
|
+
`FROM node:22-slim
|
|
350
364
|
WORKDIR /app
|
|
351
|
-
|
|
365
|
+
|
|
366
|
+
${chromiumLibsLayer}COPY package.json package.json
|
|
367
|
+
RUN npm install --omit=dev
|
|
368
|
+
|
|
352
369
|
COPY AGENT.md AGENT.md
|
|
353
370
|
COPY poncho.config.js poncho.config.js
|
|
354
371
|
COPY skills skills
|
|
355
372
|
COPY tests tests
|
|
356
373
|
COPY .env.example .env.example
|
|
357
|
-
RUN corepack enable && npm install -g @poncho-ai/cli@^${cliVersion}
|
|
358
374
|
COPY server.js server.js
|
|
375
|
+
|
|
359
376
|
EXPOSE 3000
|
|
360
377
|
CMD ["node","server.js"]
|
|
361
378
|
`,
|
|
@@ -389,6 +406,48 @@ export const handler = async (event = {}) => {
|
|
|
389
406
|
//
|
|
390
407
|
// Reminders: Create a CloudWatch Events rule that triggers GET /api/reminders/check
|
|
391
408
|
// every 10 minutes (or your preferred interval) with Authorization: Bearer <PONCHO_AUTH_TOKEN>.
|
|
409
|
+
`,
|
|
410
|
+
{ force: options?.force, writtenPaths, baseDir: projectDir },
|
|
411
|
+
);
|
|
412
|
+
} else if (target === "railway") {
|
|
413
|
+
await writeScaffoldFile(
|
|
414
|
+
resolve(projectDir, "Dockerfile"),
|
|
415
|
+
`FROM node:22-slim
|
|
416
|
+
WORKDIR /app
|
|
417
|
+
|
|
418
|
+
${chromiumLibsLayer}COPY package.json package.json
|
|
419
|
+
RUN npm install --omit=dev
|
|
420
|
+
|
|
421
|
+
COPY AGENT.md AGENT.md
|
|
422
|
+
COPY poncho.config.js poncho.config.js
|
|
423
|
+
COPY skills skills
|
|
424
|
+
COPY tests tests
|
|
425
|
+
COPY .env.example .env.example
|
|
426
|
+
COPY server.js server.js
|
|
427
|
+
|
|
428
|
+
EXPOSE 3000
|
|
429
|
+
CMD ["node","server.js"]
|
|
430
|
+
`,
|
|
431
|
+
{ force: options?.force, writtenPaths, baseDir: projectDir },
|
|
432
|
+
);
|
|
433
|
+
await writeScaffoldFile(resolve(projectDir, "server.js"), sharedServerEntrypoint, {
|
|
434
|
+
force: options?.force,
|
|
435
|
+
writtenPaths,
|
|
436
|
+
baseDir: projectDir,
|
|
437
|
+
});
|
|
438
|
+
// Pin Railway to the Dockerfile builder so it doesn't try Nixpacks (which
|
|
439
|
+
// misreads pnpm-workspace.yaml or missing lockfiles and fails the build
|
|
440
|
+
// before producing useful logs).
|
|
441
|
+
await writeScaffoldFile(
|
|
442
|
+
resolve(projectDir, "railway.toml"),
|
|
443
|
+
`[build]
|
|
444
|
+
builder = "dockerfile"
|
|
445
|
+
dockerfilePath = "Dockerfile"
|
|
446
|
+
|
|
447
|
+
[deploy]
|
|
448
|
+
startCommand = "node server.js"
|
|
449
|
+
restartPolicyType = "on_failure"
|
|
450
|
+
restartPolicyMaxRetries = 3
|
|
392
451
|
`,
|
|
393
452
|
{ force: options?.force, writtenPaths, baseDir: projectDir },
|
|
394
453
|
);
|
|
@@ -409,15 +468,18 @@ export const handler = async (event = {}) => {
|
|
|
409
468
|
);
|
|
410
469
|
await writeScaffoldFile(
|
|
411
470
|
resolve(projectDir, "Dockerfile"),
|
|
412
|
-
`FROM node:
|
|
471
|
+
`FROM node:22-slim
|
|
413
472
|
WORKDIR /app
|
|
414
|
-
|
|
473
|
+
|
|
474
|
+
${chromiumLibsLayer}COPY package.json package.json
|
|
475
|
+
RUN npm install --omit=dev
|
|
476
|
+
|
|
415
477
|
COPY AGENT.md AGENT.md
|
|
416
478
|
COPY poncho.config.js poncho.config.js
|
|
417
479
|
COPY skills skills
|
|
418
480
|
COPY tests tests
|
|
419
|
-
RUN npm install -g @poncho-ai/cli@^${cliVersion}
|
|
420
481
|
COPY server.js server.js
|
|
482
|
+
|
|
421
483
|
EXPOSE 3000
|
|
422
484
|
CMD ["node","server.js"]
|
|
423
485
|
`,
|
package/src/templates.ts
CHANGED
|
@@ -369,7 +369,7 @@ cron:
|
|
|
369
369
|
|
|
370
370
|
- \`poncho dev\`: jobs run via an in-process scheduler.
|
|
371
371
|
- \`poncho build vercel\`: generates \`vercel.json\` cron entries. Set \`CRON_SECRET\` to the same value as \`PONCHO_AUTH_TOKEN\` so Vercel can authenticate.
|
|
372
|
-
- Docker/Fly.io: scheduler runs automatically.
|
|
372
|
+
- Docker/Fly.io/Railway: scheduler runs automatically.
|
|
373
373
|
- Lambda: use AWS EventBridge to trigger \`GET /api/cron/<jobName>\` with \`Authorization: Bearer <token>\`.
|
|
374
374
|
- Trigger manually: \`curl http://localhost:3000/api/cron/daily-report\`
|
|
375
375
|
|
|
@@ -493,6 +493,10 @@ poncho build lambda
|
|
|
493
493
|
# Fly.io
|
|
494
494
|
poncho build fly
|
|
495
495
|
fly deploy
|
|
496
|
+
|
|
497
|
+
# Railway
|
|
498
|
+
poncho build railway
|
|
499
|
+
railway up
|
|
496
500
|
\`\`\`
|
|
497
501
|
|
|
498
502
|
Set environment variables on your deployment platform:
|
package/src/vfs-zip.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Minimal "store" (no-compression) zip writer. Used by the VFS folder-download
|
|
2
|
+
// endpoint. Avoids pulling in a zip dependency.
|
|
3
|
+
|
|
4
|
+
const CRC_TABLE: Uint32Array = (() => {
|
|
5
|
+
const table = new Uint32Array(256);
|
|
6
|
+
for (let i = 0; i < 256; i++) {
|
|
7
|
+
let c = i;
|
|
8
|
+
for (let k = 0; k < 8; k++) c = (c & 1) !== 0 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
9
|
+
table[i] = c >>> 0;
|
|
10
|
+
}
|
|
11
|
+
return table;
|
|
12
|
+
})();
|
|
13
|
+
|
|
14
|
+
const crc32 = (data: Uint8Array): number => {
|
|
15
|
+
let crc = 0xffffffff;
|
|
16
|
+
for (let i = 0; i < data.length; i++) crc = (CRC_TABLE[(crc ^ data[i]!) & 0xff]! ^ (crc >>> 8)) >>> 0;
|
|
17
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const dosDateTime = (date: Date): { time: number; day: number } => {
|
|
21
|
+
const time = ((date.getHours() & 0x1f) << 11) | ((date.getMinutes() & 0x3f) << 5) | (Math.floor(date.getSeconds() / 2) & 0x1f);
|
|
22
|
+
const year = Math.max(1980, date.getFullYear());
|
|
23
|
+
const day = (((year - 1980) & 0x7f) << 9) | (((date.getMonth() + 1) & 0x0f) << 5) | (date.getDate() & 0x1f);
|
|
24
|
+
return { time, day };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export interface ZipEntry {
|
|
28
|
+
/** POSIX-style relative path (forward slashes). */
|
|
29
|
+
name: string;
|
|
30
|
+
content: Uint8Array;
|
|
31
|
+
mtime?: Date;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const buildZip = (entries: ZipEntry[]): Buffer => {
|
|
35
|
+
const local: Buffer[] = [];
|
|
36
|
+
const central: Buffer[] = [];
|
|
37
|
+
let offset = 0;
|
|
38
|
+
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
const nameBuf = Buffer.from(entry.name, "utf8");
|
|
41
|
+
const data = Buffer.from(entry.content);
|
|
42
|
+
const crc = crc32(entry.content);
|
|
43
|
+
const { time, day } = dosDateTime(entry.mtime ?? new Date());
|
|
44
|
+
|
|
45
|
+
const lfh = Buffer.alloc(30);
|
|
46
|
+
lfh.writeUInt32LE(0x04034b50, 0);
|
|
47
|
+
lfh.writeUInt16LE(20, 4); // version needed
|
|
48
|
+
lfh.writeUInt16LE(0x0800, 6); // general purpose flags (bit 11 = UTF-8 name)
|
|
49
|
+
lfh.writeUInt16LE(0, 8); // compression method: store
|
|
50
|
+
lfh.writeUInt16LE(time, 10);
|
|
51
|
+
lfh.writeUInt16LE(day, 12);
|
|
52
|
+
lfh.writeUInt32LE(crc, 14);
|
|
53
|
+
lfh.writeUInt32LE(data.length, 18);
|
|
54
|
+
lfh.writeUInt32LE(data.length, 22);
|
|
55
|
+
lfh.writeUInt16LE(nameBuf.length, 26);
|
|
56
|
+
lfh.writeUInt16LE(0, 28);
|
|
57
|
+
local.push(lfh, nameBuf, data);
|
|
58
|
+
|
|
59
|
+
const cdh = Buffer.alloc(46);
|
|
60
|
+
cdh.writeUInt32LE(0x02014b50, 0);
|
|
61
|
+
cdh.writeUInt16LE(20, 4); // version made by
|
|
62
|
+
cdh.writeUInt16LE(20, 6); // version needed
|
|
63
|
+
cdh.writeUInt16LE(0x0800, 8); // flags
|
|
64
|
+
cdh.writeUInt16LE(0, 10); // compression
|
|
65
|
+
cdh.writeUInt16LE(time, 12);
|
|
66
|
+
cdh.writeUInt16LE(day, 14);
|
|
67
|
+
cdh.writeUInt32LE(crc, 16);
|
|
68
|
+
cdh.writeUInt32LE(data.length, 20);
|
|
69
|
+
cdh.writeUInt32LE(data.length, 24);
|
|
70
|
+
cdh.writeUInt16LE(nameBuf.length, 28);
|
|
71
|
+
cdh.writeUInt16LE(0, 30);
|
|
72
|
+
cdh.writeUInt16LE(0, 32);
|
|
73
|
+
cdh.writeUInt16LE(0, 34); // disk number
|
|
74
|
+
cdh.writeUInt16LE(0, 36); // internal attrs
|
|
75
|
+
cdh.writeUInt32LE(0, 38); // external attrs
|
|
76
|
+
cdh.writeUInt32LE(offset, 42);
|
|
77
|
+
central.push(cdh, nameBuf);
|
|
78
|
+
|
|
79
|
+
offset += lfh.length + nameBuf.length + data.length;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const centralBuf = Buffer.concat(central);
|
|
83
|
+
const eocd = Buffer.alloc(22);
|
|
84
|
+
eocd.writeUInt32LE(0x06054b50, 0);
|
|
85
|
+
eocd.writeUInt16LE(0, 4); // disk number
|
|
86
|
+
eocd.writeUInt16LE(0, 6); // disk where central dir starts
|
|
87
|
+
eocd.writeUInt16LE(entries.length, 8); // entries on this disk
|
|
88
|
+
eocd.writeUInt16LE(entries.length, 10); // total entries
|
|
89
|
+
eocd.writeUInt32LE(centralBuf.length, 12);
|
|
90
|
+
eocd.writeUInt32LE(offset, 16); // central dir offset
|
|
91
|
+
eocd.writeUInt16LE(0, 20); // comment length
|
|
92
|
+
|
|
93
|
+
return Buffer.concat([...local, centralBuf, eocd]);
|
|
94
|
+
};
|