openpouch 0.2.2 → 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 +3 -3
- package/openpouch.js +59 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,12 +10,12 @@ 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.**
|
|
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
14
|
> ```bash
|
|
15
15
|
> npm run build
|
|
16
|
-
>
|
|
16
|
+
> npx openpouch deploy dist # Vite → dist/ · CRA → build/ · Next static export → out/
|
|
17
17
|
> ```
|
|
18
|
-
>
|
|
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
19
|
|
|
20
20
|
## Accounts (optional)
|
|
21
21
|
|
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,7 +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.**
|
|
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.",
|
|
5367
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`.",
|
|
5368
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.",
|
|
5369
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.",
|
|
@@ -5628,8 +5628,8 @@ async function initCommand(ctx, flags) {
|
|
|
5628
5628
|
|
|
5629
5629
|
// packages/cli/src/commands/instant.ts
|
|
5630
5630
|
import { spawn } from "node:child_process";
|
|
5631
|
-
import { readFile as readFile7 } from "node:fs/promises";
|
|
5632
|
-
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";
|
|
5633
5633
|
var TAR_EXCLUDES = [
|
|
5634
5634
|
"./node_modules",
|
|
5635
5635
|
"./.git",
|
|
@@ -5642,7 +5642,7 @@ var TAR_EXCLUDES = [
|
|
|
5642
5642
|
"./.openpouch"
|
|
5643
5643
|
];
|
|
5644
5644
|
function buildTarball(cwd) {
|
|
5645
|
-
return new Promise((
|
|
5645
|
+
return new Promise((resolve2, reject) => {
|
|
5646
5646
|
const args = ["-czf", "-", ...TAR_EXCLUDES.flatMap((e) => ["--exclude", e]), "-C", cwd, "."];
|
|
5647
5647
|
const tar = spawn("tar", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
5648
5648
|
const chunks = [];
|
|
@@ -5651,7 +5651,7 @@ function buildTarball(cwd) {
|
|
|
5651
5651
|
tar.stderr.on("data", (c) => stderr += String(c));
|
|
5652
5652
|
tar.on("error", reject);
|
|
5653
5653
|
tar.on("close", (code) => {
|
|
5654
|
-
if (code === 0)
|
|
5654
|
+
if (code === 0) resolve2(Buffer.concat(chunks));
|
|
5655
5655
|
else reject(new Error(`tar exited ${code}: ${stderr.trim().slice(0, 300)}`));
|
|
5656
5656
|
});
|
|
5657
5657
|
});
|
|
@@ -5664,7 +5664,49 @@ async function projectHint(cwd) {
|
|
|
5664
5664
|
}
|
|
5665
5665
|
return basename2(cwd) || "joey";
|
|
5666
5666
|
}
|
|
5667
|
-
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
|
+
}
|
|
5668
5710
|
const loaded = await loadManifest(ctx.cwd);
|
|
5669
5711
|
if (loaded.status === "ok") {
|
|
5670
5712
|
const envs = Object.values(loaded.manifest.environments ?? {});
|
|
@@ -5678,9 +5720,16 @@ async function instantCommand(ctx) {
|
|
|
5678
5720
|
);
|
|
5679
5721
|
}
|
|
5680
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
|
+
}
|
|
5681
5730
|
let tarball;
|
|
5682
5731
|
try {
|
|
5683
|
-
tarball = await buildTarball(
|
|
5732
|
+
tarball = await buildTarball(targetDir);
|
|
5684
5733
|
} catch (e) {
|
|
5685
5734
|
return errorResult(EXIT.UNEXPECTED, "provider", `could not package the project: ${e.message}`, "Ensure `tar` is available and the directory is readable.");
|
|
5686
5735
|
}
|
|
@@ -6223,7 +6272,7 @@ var USAGE = [
|
|
|
6223
6272
|
"usage: openpouch <command> [--json]",
|
|
6224
6273
|
"",
|
|
6225
6274
|
"commands:",
|
|
6226
|
-
" 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)",
|
|
6227
6276
|
" signup create an openpouch account: --email <addr> or --github (gives you an API key)",
|
|
6228
6277
|
" activate finish an email signup: --account <id> --token <token> (saves your API key)",
|
|
6229
6278
|
" whoami show the account behind your API key: tier + current usage",
|
|
@@ -6297,7 +6346,7 @@ async function run(argv, ctx) {
|
|
|
6297
6346
|
try {
|
|
6298
6347
|
switch (command) {
|
|
6299
6348
|
case "deploy":
|
|
6300
|
-
return render(await instantCommand(ctx), json);
|
|
6349
|
+
return render(await instantCommand(ctx, parsed.positionals[1]), json);
|
|
6301
6350
|
case "signup":
|
|
6302
6351
|
return render(await signupCommand(ctx, { email: parsed.values.email, github: parsed.values.github === true }), json);
|
|
6303
6352
|
case "activate":
|
package/package.json
CHANGED