openpouch 0.2.1 → 0.2.3
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/openpouch.js +59 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,13 @@ npx openpouch deploy
|
|
|
10
10
|
|
|
11
11
|
You get a live `https://<slug>.openpouch.sh` URL plus a claim link. The agent deploys autonomously; a human claims it via the link to keep it. openpouch writes the deployment truth (`deploy.manifest.json`, `deploy.evidence.json`, `DEPLOYMENT.md`) back into your repo, so any agent can resume after context loss.
|
|
12
12
|
|
|
13
|
+
> **Framework frontends (React/Vite/Next/Svelte…): deploy the _built output_, not the source folder.** Build first, then point `deploy` at the build directory:
|
|
14
|
+
> ```bash
|
|
15
|
+
> npm run build
|
|
16
|
+
> npx openpouch deploy dist # Vite → dist/ · CRA → build/ · Next static export → out/
|
|
17
|
+
> ```
|
|
18
|
+
> If you run `openpouch deploy` in an unbuilt frontend root, it **stops and tells you which folder to deploy** instead of silently shipping source that won't run (use `openpouch deploy .` to force the current folder). Server-side build-on-deploy is on the roadmap.
|
|
19
|
+
|
|
13
20
|
## Accounts (optional)
|
|
14
21
|
|
|
15
22
|
Start anonymous, or create a free account for higher limits — entirely from the agent, no dashboard:
|
package/openpouch.js
CHANGED
|
@@ -5129,7 +5129,7 @@ async function approveCommand(ctx, requestId) {
|
|
|
5129
5129
|
}
|
|
5130
5130
|
|
|
5131
5131
|
// packages/cli/src/deploy-engine.ts
|
|
5132
|
-
var sleep = (ms) => new Promise((
|
|
5132
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
5133
5133
|
var TERMINAL = /* @__PURE__ */ new Set(["live", "failed", "canceled"]);
|
|
5134
5134
|
async function runSmokeChecks(url, healthcheck) {
|
|
5135
5135
|
const check = healthcheck ?? { path: "/", expectStatus: 200, timeoutMs: 1e4 };
|
|
@@ -5363,6 +5363,7 @@ function renderAgentsSection(projectName) {
|
|
|
5363
5363
|
"",
|
|
5364
5364
|
`${projectName} deploys via openpouch \u2014 an agent-native deployment control plane. This works the same from any agent harness.`,
|
|
5365
5365
|
"",
|
|
5366
|
+
"- **Framework frontends (React/Vite/Next/Svelte\u2026): deploy the _built output_, not the source folder.** Build first, then point deploy at the build directory: `npm run build`, then `openpouch deploy dist` (Vite\u2192`dist/`, CRA\u2192`build/`, Next static export\u2192`out/`). Running `openpouch deploy` in an unbuilt frontend root is refused with the right folder to use (`openpouch deploy .` forces the current folder); server-side build-on-deploy is on the roadmap.",
|
|
5366
5367
|
"- **Deployment truth** (what is live, where, which commit, rollback anchor): read `DEPLOYMENT.md` or `deploy.evidence.json`. Config lives in `deploy.manifest.json`, agent permissions in `deploy.policy.json`.",
|
|
5367
5368
|
"- **CLI:** `openpouch inspect` \xB7 `plan` \xB7 `preview` (autonomous if policy allows) \xB7 `prod` \xB7 `verify` \xB7 `logs` \xB7 `rollback`. Add `--json` for a single machine-readable JSON object; errors come as `{category, message, fix}` \u2014 act on the fix. Exit codes are documented API.",
|
|
5368
5369
|
"- **Relay the `summary` to your human:** every result (CLI `--json` and MCP) carries a top-level `summary` \u2014 plain-language, jargon-free text written for a non-technical operator. Pass it on verbatim: it says what happened, whether the app is live and healthy, the live link, and what (if anything) the human needs to do. The **live URL is the primary result** \u2014 on a successful deploy it's the top-level `url` field, ready to share.",
|
|
@@ -5627,8 +5628,8 @@ async function initCommand(ctx, flags) {
|
|
|
5627
5628
|
|
|
5628
5629
|
// packages/cli/src/commands/instant.ts
|
|
5629
5630
|
import { spawn } from "node:child_process";
|
|
5630
|
-
import { readFile as readFile7 } from "node:fs/promises";
|
|
5631
|
-
import { basename as basename2, join as join7 } from "node:path";
|
|
5631
|
+
import { readFile as readFile7, stat } from "node:fs/promises";
|
|
5632
|
+
import { basename as basename2, join as join7, resolve } from "node:path";
|
|
5632
5633
|
var TAR_EXCLUDES = [
|
|
5633
5634
|
"./node_modules",
|
|
5634
5635
|
"./.git",
|
|
@@ -5641,7 +5642,7 @@ var TAR_EXCLUDES = [
|
|
|
5641
5642
|
"./.openpouch"
|
|
5642
5643
|
];
|
|
5643
5644
|
function buildTarball(cwd) {
|
|
5644
|
-
return new Promise((
|
|
5645
|
+
return new Promise((resolve2, reject) => {
|
|
5645
5646
|
const args = ["-czf", "-", ...TAR_EXCLUDES.flatMap((e) => ["--exclude", e]), "-C", cwd, "."];
|
|
5646
5647
|
const tar = spawn("tar", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
5647
5648
|
const chunks = [];
|
|
@@ -5650,7 +5651,7 @@ function buildTarball(cwd) {
|
|
|
5650
5651
|
tar.stderr.on("data", (c) => stderr += String(c));
|
|
5651
5652
|
tar.on("error", reject);
|
|
5652
5653
|
tar.on("close", (code) => {
|
|
5653
|
-
if (code === 0)
|
|
5654
|
+
if (code === 0) resolve2(Buffer.concat(chunks));
|
|
5654
5655
|
else reject(new Error(`tar exited ${code}: ${stderr.trim().slice(0, 300)}`));
|
|
5655
5656
|
});
|
|
5656
5657
|
});
|
|
@@ -5663,7 +5664,49 @@ async function projectHint(cwd) {
|
|
|
5663
5664
|
}
|
|
5664
5665
|
return basename2(cwd) || "joey";
|
|
5665
5666
|
}
|
|
5666
|
-
async function
|
|
5667
|
+
async function unbuiltFrontendHint(dir) {
|
|
5668
|
+
const buildDirs = [];
|
|
5669
|
+
for (const c of ["dist", "build", "out"]) {
|
|
5670
|
+
try {
|
|
5671
|
+
if ((await stat(join7(dir, c))).isDirectory()) buildDirs.push(c);
|
|
5672
|
+
} catch {
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
let html;
|
|
5676
|
+
try {
|
|
5677
|
+
html = await readFile7(join7(dir, "index.html"), "utf8");
|
|
5678
|
+
} catch {
|
|
5679
|
+
html = void 0;
|
|
5680
|
+
}
|
|
5681
|
+
const devEntry = html !== void 0 && (/src=["']\/?src\//.test(html) || /\.(jsx|tsx|ts|vue|svelte)["']/.test(html));
|
|
5682
|
+
let noEntrySpa = false;
|
|
5683
|
+
if (html === void 0) {
|
|
5684
|
+
try {
|
|
5685
|
+
const pkg = JSON.parse(await readFile7(join7(dir, "package.json"), "utf8"));
|
|
5686
|
+
if (pkg.scripts?.["build"]) {
|
|
5687
|
+
try {
|
|
5688
|
+
noEntrySpa = (await stat(join7(dir, "src"))).isDirectory();
|
|
5689
|
+
} catch {
|
|
5690
|
+
noEntrySpa = false;
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5693
|
+
} catch {
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
return { buildDirs, isUnbuilt: devEntry || noEntrySpa };
|
|
5697
|
+
}
|
|
5698
|
+
async function instantCommand(ctx, dir) {
|
|
5699
|
+
const explicitDir = dir !== void 0 && dir !== "";
|
|
5700
|
+
const targetDir = explicitDir ? resolve(ctx.cwd, dir) : ctx.cwd;
|
|
5701
|
+
if (explicitDir) {
|
|
5702
|
+
try {
|
|
5703
|
+
if (!(await stat(targetDir)).isDirectory()) {
|
|
5704
|
+
return errorResult(EXIT.USAGE, "usage", `not a directory: ${dir}`, "Pass a folder to deploy, e.g. `openpouch deploy dist`.");
|
|
5705
|
+
}
|
|
5706
|
+
} catch {
|
|
5707
|
+
return errorResult(EXIT.USAGE, "usage", `folder not found: ${dir}`, "Pass an existing folder, e.g. `openpouch deploy dist`.");
|
|
5708
|
+
}
|
|
5709
|
+
}
|
|
5667
5710
|
const loaded = await loadManifest(ctx.cwd);
|
|
5668
5711
|
if (loaded.status === "ok") {
|
|
5669
5712
|
const envs = Object.values(loaded.manifest.environments ?? {});
|
|
@@ -5677,9 +5720,16 @@ async function instantCommand(ctx) {
|
|
|
5677
5720
|
);
|
|
5678
5721
|
}
|
|
5679
5722
|
}
|
|
5723
|
+
if (!explicitDir) {
|
|
5724
|
+
const { buildDirs, isUnbuilt } = await unbuiltFrontendHint(targetDir);
|
|
5725
|
+
if (isUnbuilt) {
|
|
5726
|
+
const fix = buildDirs.length > 0 ? `This looks like an unbuilt frontend. Deploy the build output instead: \`openpouch deploy ${buildDirs[0]}\` \u2014 or \`openpouch deploy .\` to ship this folder as-is.` : "This looks like an unbuilt frontend (index.html references source modules). Build first, then deploy the build folder: `npm run build`, then `openpouch deploy dist` \u2014 or `openpouch deploy .` to ship this folder as-is.";
|
|
5727
|
+
return errorResult(EXIT.USAGE, "usage", "refusing to deploy what looks like unbuilt frontend source", fix);
|
|
5728
|
+
}
|
|
5729
|
+
}
|
|
5680
5730
|
let tarball;
|
|
5681
5731
|
try {
|
|
5682
|
-
tarball = await buildTarball(
|
|
5732
|
+
tarball = await buildTarball(targetDir);
|
|
5683
5733
|
} catch (e) {
|
|
5684
5734
|
return errorResult(EXIT.UNEXPECTED, "provider", `could not package the project: ${e.message}`, "Ensure `tar` is available and the directory is readable.");
|
|
5685
5735
|
}
|
|
@@ -6222,7 +6272,7 @@ var USAGE = [
|
|
|
6222
6272
|
"usage: openpouch <command> [--json]",
|
|
6223
6273
|
"",
|
|
6224
6274
|
"commands:",
|
|
6225
|
-
" deploy
|
|
6275
|
+
" deploy [dir] zero-config instant preview on openpouch's own infra \u2014 deploys ./<dir> (e.g. `deploy dist`) or the current folder (anonymous, or under your account if a key is set)",
|
|
6226
6276
|
" signup create an openpouch account: --email <addr> or --github (gives you an API key)",
|
|
6227
6277
|
" activate finish an email signup: --account <id> --token <token> (saves your API key)",
|
|
6228
6278
|
" whoami show the account behind your API key: tier + current usage",
|
|
@@ -6296,7 +6346,7 @@ async function run(argv, ctx) {
|
|
|
6296
6346
|
try {
|
|
6297
6347
|
switch (command) {
|
|
6298
6348
|
case "deploy":
|
|
6299
|
-
return render(await instantCommand(ctx), json);
|
|
6349
|
+
return render(await instantCommand(ctx, parsed.positionals[1]), json);
|
|
6300
6350
|
case "signup":
|
|
6301
6351
|
return render(await signupCommand(ctx, { email: parsed.values.email, github: parsed.values.github === true }), json);
|
|
6302
6352
|
case "activate":
|
package/package.json
CHANGED