@interchained/portal-cli 0.1.1

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.
Files changed (81) hide show
  1. package/dist/commands/adapter.d.ts +5 -0
  2. package/dist/commands/adapter.d.ts.map +1 -0
  3. package/dist/commands/adapter.js +71 -0
  4. package/dist/commands/adapter.js.map +1 -0
  5. package/dist/commands/agent-cmd.d.ts +7 -0
  6. package/dist/commands/agent-cmd.d.ts.map +1 -0
  7. package/dist/commands/agent-cmd.js +162 -0
  8. package/dist/commands/agent-cmd.js.map +1 -0
  9. package/dist/commands/audit.d.ts +18 -0
  10. package/dist/commands/audit.d.ts.map +1 -0
  11. package/dist/commands/audit.js +80 -0
  12. package/dist/commands/audit.js.map +1 -0
  13. package/dist/commands/build.d.ts +10 -0
  14. package/dist/commands/build.d.ts.map +1 -0
  15. package/dist/commands/build.js +35 -0
  16. package/dist/commands/build.js.map +1 -0
  17. package/dist/commands/contract-cmd.d.ts +7 -0
  18. package/dist/commands/contract-cmd.d.ts.map +1 -0
  19. package/dist/commands/contract-cmd.js +222 -0
  20. package/dist/commands/contract-cmd.js.map +1 -0
  21. package/dist/commands/deploy.d.ts +13 -0
  22. package/dist/commands/deploy.d.ts.map +1 -0
  23. package/dist/commands/deploy.js +135 -0
  24. package/dist/commands/deploy.js.map +1 -0
  25. package/dist/commands/dev.d.ts +10 -0
  26. package/dist/commands/dev.d.ts.map +1 -0
  27. package/dist/commands/dev.js +37 -0
  28. package/dist/commands/dev.js.map +1 -0
  29. package/dist/commands/doctor.d.ts +6 -0
  30. package/dist/commands/doctor.d.ts.map +1 -0
  31. package/dist/commands/doctor.js +139 -0
  32. package/dist/commands/doctor.js.map +1 -0
  33. package/dist/commands/explain.d.ts +6 -0
  34. package/dist/commands/explain.d.ts.map +1 -0
  35. package/dist/commands/explain.js +75 -0
  36. package/dist/commands/explain.js.map +1 -0
  37. package/dist/commands/generate.d.ts +13 -0
  38. package/dist/commands/generate.d.ts.map +1 -0
  39. package/dist/commands/generate.js +222 -0
  40. package/dist/commands/generate.js.map +1 -0
  41. package/dist/commands/guard.d.ts +12 -0
  42. package/dist/commands/guard.d.ts.map +1 -0
  43. package/dist/commands/guard.js +71 -0
  44. package/dist/commands/guard.js.map +1 -0
  45. package/dist/commands/improve.d.ts +18 -0
  46. package/dist/commands/improve.d.ts.map +1 -0
  47. package/dist/commands/improve.js +157 -0
  48. package/dist/commands/improve.js.map +1 -0
  49. package/dist/commands/lint.d.ts +5 -0
  50. package/dist/commands/lint.d.ts.map +1 -0
  51. package/dist/commands/lint.js +87 -0
  52. package/dist/commands/lint.js.map +1 -0
  53. package/dist/commands/patch.d.ts +5 -0
  54. package/dist/commands/patch.d.ts.map +1 -0
  55. package/dist/commands/patch.js +78 -0
  56. package/dist/commands/patch.js.map +1 -0
  57. package/dist/commands/preview.d.ts +4 -0
  58. package/dist/commands/preview.d.ts.map +1 -0
  59. package/dist/commands/preview.js +26 -0
  60. package/dist/commands/preview.js.map +1 -0
  61. package/dist/commands/rollback.d.ts +8 -0
  62. package/dist/commands/rollback.d.ts.map +1 -0
  63. package/dist/commands/rollback.js +88 -0
  64. package/dist/commands/rollback.js.map +1 -0
  65. package/dist/commands/test.d.ts +7 -0
  66. package/dist/commands/test.d.ts.map +1 -0
  67. package/dist/commands/test.js +57 -0
  68. package/dist/commands/test.js.map +1 -0
  69. package/dist/index.d.ts +7 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +152 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/utils/contract.d.ts +14 -0
  74. package/dist/utils/contract.d.ts.map +1 -0
  75. package/dist/utils/contract.js +53 -0
  76. package/dist/utils/contract.js.map +1 -0
  77. package/dist/utils/print.d.ts +22 -0
  78. package/dist/utils/print.d.ts.map +1 -0
  79. package/dist/utils/print.js +47 -0
  80. package/dist/utils/print.js.map +1 -0
  81. package/package.json +44 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * portal contract validate — validate all contract files
3
+ * portal contract init — scaffold default contracts for existing apps
4
+ */
5
+ import { writeFile, access } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ import pc from "picocolors";
8
+ import prompts from "prompts";
9
+ import { validateContract } from "@interchained/portal-contract";
10
+ import { banner, header, success, fail, warn, info, blank } from "../utils/print.js";
11
+ import { loadContract, findContractPath } from "../utils/contract.js";
12
+ async function exists(p) {
13
+ try {
14
+ await access(p);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ // ── portal contract validate ──────────────────────────────────────────────────
22
+ export async function contractValidateCommand() {
23
+ banner();
24
+ header("Contract Validation");
25
+ blank();
26
+ const root = process.cwd();
27
+ let failed = false;
28
+ // Find and load contract
29
+ const contractPath = await findContractPath(root);
30
+ if (!contractPath) {
31
+ fail("No app.contract.ts found — run: portal contract init");
32
+ process.exit(1);
33
+ }
34
+ let contract;
35
+ try {
36
+ contract = await loadContract(root);
37
+ validateContract(contract);
38
+ success("Contract schema valid");
39
+ }
40
+ catch (err) {
41
+ fail(`Contract schema invalid: ${err.message}`);
42
+ failed = true;
43
+ }
44
+ if (!failed) {
45
+ // Unreplaced template tokens
46
+ const contractStr = JSON.stringify(contract);
47
+ const tokens = contractStr.match(/\{\{[A-Z_]+\}\}/g);
48
+ if (tokens) {
49
+ const unique = [...new Set(tokens)];
50
+ for (const tok of unique) {
51
+ fail(`Unreplaced token: ${tok}`);
52
+ }
53
+ failed = true;
54
+ }
55
+ else {
56
+ success("No unreplaced template tokens");
57
+ }
58
+ // Required fields
59
+ if (!contract.name?.trim()) {
60
+ fail("contract.name is empty");
61
+ failed = true;
62
+ }
63
+ else {
64
+ success(`name: "${contract.name}"`);
65
+ }
66
+ if (!contract.goals?.length) {
67
+ fail("contract.goals is empty");
68
+ failed = true;
69
+ }
70
+ else {
71
+ success(`goals: ${contract.goals.length} defined`);
72
+ }
73
+ // Pages
74
+ const pages = contract.pages ?? [];
75
+ let pageIssues = 0;
76
+ for (const page of pages) {
77
+ if (!page.purpose?.trim()) {
78
+ warn(`Page "${page.route}" has no purpose`);
79
+ pageIssues++;
80
+ }
81
+ if (!page.primaryAction?.trim()) {
82
+ warn(`Page "${page.route}" has no primaryAction`);
83
+ }
84
+ }
85
+ if (pages.length === 0) {
86
+ warn("No pages declared in contract (optional but recommended)");
87
+ }
88
+ else if (pageIssues === 0) {
89
+ success(`pages: ${pages.length} declared, all have purpose`);
90
+ }
91
+ // Data files
92
+ const data = contract.data ?? {};
93
+ let missingData = 0;
94
+ for (const [name, filePath] of Object.entries(data)) {
95
+ const full = join(root, filePath);
96
+ if (!(await exists(full))) {
97
+ warn(`data.${name}: file missing (${filePath})`);
98
+ missingData++;
99
+ }
100
+ else {
101
+ success(`data.${name}: found`);
102
+ }
103
+ }
104
+ }
105
+ blank();
106
+ if (failed) {
107
+ fail("Contract validation failed — fix the issues above");
108
+ process.exit(1);
109
+ }
110
+ else {
111
+ success("Contract is valid and ready for agent operations");
112
+ blank();
113
+ }
114
+ }
115
+ // ── portal contract init ──────────────────────────────────────────────────────
116
+ const DEFAULT_CONTRACT = (name, description) => `import { defineApp } from "@interchained/portal-contract";
117
+
118
+ export default defineApp({
119
+ name: "${name}",
120
+ version: "1.1.0",
121
+
122
+ description: "${description}",
123
+
124
+ goals: [
125
+ "Describe the first thing this app is trying to accomplish",
126
+ "And the second",
127
+ ],
128
+
129
+ brand: {
130
+ voice: "clear, direct, professional",
131
+ colors: ["#0f172a", "#6366f1", "#f8fafc"],
132
+ forbiddenPhrases: ["world-class", "best-in-class", "game-changer"],
133
+ },
134
+
135
+ policies: {
136
+ publishing: "human_review",
137
+ accessibility: "basic",
138
+ forbiddenClaims: [],
139
+ },
140
+
141
+ qualityGates: {
142
+ requireMetaTitle: true,
143
+ requireMetaDescription: true,
144
+ requireH1: true,
145
+ requirePrimaryCTA: true,
146
+ forbidPlaceholderCopy: true,
147
+ },
148
+
149
+ pages: [],
150
+ });
151
+ `;
152
+ const DEFAULT_AGENT_CONFIG = `import { defineAgent } from "@interchained/portal-contract";
153
+
154
+ // Add your agents here — run with: portal agent run <name>
155
+
156
+ export const seoAgent = defineAgent({
157
+ name: "seo-reviewer",
158
+ model: "fast",
159
+ sentinel: "smart",
160
+ task: "Review page for SEO gaps and suggest improvements",
161
+ canPatch: true,
162
+ requiresApproval: true,
163
+ });
164
+ `;
165
+ export async function contractInitCommand() {
166
+ banner();
167
+ const root = process.cwd();
168
+ // Check existing
169
+ const existing = await findContractPath(root);
170
+ if (existing) {
171
+ info(`Contract already exists: ${existing}`);
172
+ const { overwrite } = await prompts({
173
+ type: "confirm",
174
+ name: "overwrite",
175
+ message: "Overwrite it?",
176
+ initial: false,
177
+ });
178
+ if (!overwrite) {
179
+ blank();
180
+ return;
181
+ }
182
+ }
183
+ const { appName } = await prompts({
184
+ type: "text",
185
+ name: "appName",
186
+ message: "App name:",
187
+ initial: root.split("/").pop() ?? "my-portal",
188
+ });
189
+ const { description } = await prompts({
190
+ type: "text",
191
+ name: "description",
192
+ message: "One-line description:",
193
+ initial: "A Portal web application",
194
+ });
195
+ if (!appName) {
196
+ blank();
197
+ return;
198
+ }
199
+ // Write app.contract.ts
200
+ await writeFile(join(root, "app.contract.ts"), DEFAULT_CONTRACT(appName, description || "A Portal web application"), "utf-8");
201
+ success("Created: app.contract.ts");
202
+ // Write agent.config.ts if it doesn't exist
203
+ const agentConfigPath = join(root, "agent.config.ts");
204
+ if (!(await exists(agentConfigPath))) {
205
+ await writeFile(agentConfigPath, DEFAULT_AGENT_CONFIG, "utf-8");
206
+ success("Created: agent.config.ts");
207
+ }
208
+ // Create agents/ dir
209
+ const agentsDir = join(root, "agents");
210
+ if (!(await exists(agentsDir))) {
211
+ const { mkdir } = await import("node:fs/promises");
212
+ await mkdir(agentsDir, { recursive: true });
213
+ success("Created: agents/");
214
+ }
215
+ blank();
216
+ info("Next steps:");
217
+ console.log(pc.dim(" 1. Edit app.contract.ts — define your goals, brand, and policies"));
218
+ console.log(pc.dim(" 2. portal contract validate — verify it's correct"));
219
+ console.log(pc.dim(" 3. portal audit — run your first audit"));
220
+ blank();
221
+ }
222
+ //# sourceMappingURL=contract-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-cmd.js","sourceRoot":"","sources":["../../src/commands/contract-cmd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * portal deploy — build and prepare deployment artifacts.
3
+ *
4
+ * Adapters: static | node | docker
5
+ */
6
+ export type DeployAdapter = "static" | "node" | "docker";
7
+ export interface DeployOptions {
8
+ adapter?: DeployAdapter;
9
+ outDir?: string;
10
+ tag?: string;
11
+ }
12
+ export declare function deployCommand(opts?: DeployOptions): Promise<void>;
13
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA0CD,wBAAsB,aAAa,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiF3E"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * portal deploy — build and prepare deployment artifacts.
3
+ *
4
+ * Adapters: static | node | docker
5
+ */
6
+ import { writeFile, access } from "node:fs/promises";
7
+ import { join } from "node:path";
8
+ import pc from "picocolors";
9
+ import { execa } from "execa";
10
+ import prompts from "prompts";
11
+ import { banner, header, success, fail, info, step, blank } from "../utils/print.js";
12
+ const DOCKERFILE = `FROM node:20-alpine AS builder
13
+ WORKDIR /app
14
+ COPY package*.json ./
15
+ RUN npm ci
16
+ COPY . .
17
+ RUN npx vite build
18
+
19
+ FROM node:20-alpine
20
+ WORKDIR /app
21
+ COPY --from=builder /app/dist ./dist
22
+ COPY --from=builder /app/package*.json ./
23
+ RUN npm ci --production
24
+ EXPOSE 3000
25
+ CMD ["node", "dist/server.js"]
26
+ `;
27
+ const SERVER_ENTRY = `import express from "express";
28
+ import { createServer } from "node:http";
29
+ import { fileURLToPath } from "node:url";
30
+ import { dirname, join } from "node:path";
31
+ import { existsSync } from "node:fs";
32
+
33
+ const __dirname = dirname(fileURLToPath(import.meta.url));
34
+ const app = express();
35
+ const PORT = process.env.PORT ?? 3000;
36
+
37
+ app.use(express.static(join(__dirname, ".")));
38
+ app.get("*", (_req, res) => {
39
+ res.sendFile(join(__dirname, "index.html"));
40
+ });
41
+
42
+ createServer(app).listen(PORT, () => {
43
+ console.log(\`Portal app running on port \${PORT}\`);
44
+ });
45
+ `;
46
+ async function exists(p) {
47
+ try {
48
+ await access(p);
49
+ return true;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ export async function deployCommand(opts = {}) {
56
+ banner();
57
+ const root = process.cwd();
58
+ let adapter = opts.adapter;
59
+ if (!adapter) {
60
+ const { chosen } = await prompts({
61
+ type: "select",
62
+ name: "chosen",
63
+ message: "Choose deployment adapter:",
64
+ choices: [
65
+ { title: `${pc.bold("static")} ${pc.dim("— CDN / Netlify / Vercel / S3")}`, value: "static" },
66
+ { title: `${pc.bold("node")} ${pc.dim("— Node.js server (Express)")}`, value: "node" },
67
+ { title: `${pc.bold("docker")} ${pc.dim("— Docker container (self-hosted)")}`, value: "docker" },
68
+ ],
69
+ });
70
+ adapter = chosen;
71
+ }
72
+ if (!adapter) {
73
+ blank();
74
+ return;
75
+ }
76
+ header(`Deploying: ${pc.bold(adapter)}`);
77
+ blank();
78
+ // Always build first
79
+ step("Building production bundle…");
80
+ try {
81
+ await execa("npx", ["vite", "build", "--outDir", opts.outDir ?? "dist"], {
82
+ cwd: root,
83
+ stdio: "inherit",
84
+ env: { ...process.env, FORCE_COLOR: "1" },
85
+ });
86
+ success("Build complete");
87
+ }
88
+ catch {
89
+ fail("Build failed — fix errors before deploying");
90
+ process.exit(1);
91
+ }
92
+ blank();
93
+ if (adapter === "static") {
94
+ success("Static build ready in dist/");
95
+ info("Deploy dist/ to any static host: Netlify, Vercel, S3, Cloudflare Pages, or rsync.");
96
+ }
97
+ else if (adapter === "node") {
98
+ // Write server entry if missing
99
+ const serverPath = join(root, "dist", "server.js");
100
+ if (!(await exists(serverPath))) {
101
+ step("Writing Node.js server entry (dist/server.js)…");
102
+ await writeFile(serverPath, SERVER_ENTRY, "utf-8");
103
+ success("dist/server.js written");
104
+ }
105
+ info("Run: node dist/server.js");
106
+ info("Set PORT env var to choose the port (default 3000).");
107
+ }
108
+ else if (adapter === "docker") {
109
+ const dockerfilePath = join(root, "Dockerfile");
110
+ if (!(await exists(dockerfilePath))) {
111
+ step("Writing Dockerfile…");
112
+ await writeFile(dockerfilePath, DOCKERFILE, "utf-8");
113
+ success("Dockerfile written");
114
+ }
115
+ else {
116
+ info("Dockerfile already exists — using existing one");
117
+ }
118
+ const tag = opts.tag ?? "portal-app:latest";
119
+ step(`Building Docker image: ${tag}…`);
120
+ try {
121
+ await execa("docker", ["build", "-t", tag, "."], {
122
+ cwd: root,
123
+ stdio: "inherit",
124
+ });
125
+ success(`Docker image built: ${tag}`);
126
+ info(`Run: docker run -p 3000:3000 ${tag}`);
127
+ }
128
+ catch {
129
+ console.log(pc.yellow("⚠ Docker build failed — make sure Docker is running"));
130
+ info("Dockerfile written to project root — build manually when ready.");
131
+ }
132
+ }
133
+ blank();
134
+ }
135
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * portal dev — starts the Vite dev server with Portal plugin.
3
+ */
4
+ export interface DevOptions {
5
+ port?: number;
6
+ host?: boolean;
7
+ open?: boolean;
8
+ }
9
+ export declare function devCommand(opts?: DevOptions): Promise<void>;
10
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BrE"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * portal dev — starts the Vite dev server with Portal plugin.
3
+ */
4
+ import { join } from "node:path";
5
+ import { execa } from "execa";
6
+ import pc from "picocolors";
7
+ import { banner, step } from "../utils/print.js";
8
+ export async function devCommand(opts = {}) {
9
+ banner();
10
+ const root = process.cwd();
11
+ const viteConfig = join(root, "vite.config.ts");
12
+ step(`Starting dev server${opts.port ? ` on port ${opts.port}` : ""}…`);
13
+ console.log(pc.dim(` root: ${root}`));
14
+ console.log();
15
+ const args = ["vite", "--config", viteConfig];
16
+ if (opts.port)
17
+ args.push("--port", String(opts.port));
18
+ if (opts.host)
19
+ args.push("--host");
20
+ if (opts.open)
21
+ args.push("--open");
22
+ try {
23
+ await execa("npx", args, {
24
+ stdio: "inherit",
25
+ cwd: root,
26
+ env: { ...process.env, FORCE_COLOR: "1" },
27
+ });
28
+ }
29
+ catch (err) {
30
+ // Vite exits non-zero on SIGINT — that's fine
31
+ const code = err.exitCode;
32
+ if (code !== 0 && code !== null && code !== undefined) {
33
+ process.exit(code);
34
+ }
35
+ }
36
+ }
37
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAQ,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAQvD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAmB,EAAE;IACpD,MAAM,EAAE,CAAC;IAET,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAEhD,IAAI,CAAC,sBAAsB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE;YACvB,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,IAAI;YACT,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE;SAC1C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,8CAA8C;QAC9C,MAAM,IAAI,GAAI,GAA6B,CAAC,QAAQ,CAAC;QACrD,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * portal doctor — environment + project health check.
3
+ * Runs before you let agents near your code.
4
+ */
5
+ export declare function doctorCommand(): Promise<void>;
6
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkBH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAgInD"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * portal doctor — environment + project health check.
3
+ * Runs before you let agents near your code.
4
+ */
5
+ import { access, readdir } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ import pc from "picocolors";
8
+ import { banner, header, success, warn, fail, blank } from "../utils/print.js";
9
+ import { loadContract, findContractPath } from "../utils/contract.js";
10
+ async function exists(p) {
11
+ try {
12
+ await access(p);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ export async function doctorCommand() {
20
+ banner();
21
+ header("Portal Doctor");
22
+ const root = process.cwd();
23
+ const checks = [];
24
+ // Node version
25
+ const nodeVer = process.version;
26
+ const nodeMaj = parseInt(nodeVer.slice(1), 10);
27
+ checks.push({
28
+ label: `Node.js ${nodeVer}`,
29
+ status: nodeMaj >= 18 ? "ok" : "fail",
30
+ detail: nodeMaj < 18 ? "Portal requires Node.js 18 or newer" : undefined,
31
+ });
32
+ // vite.config.ts / portal.config.ts
33
+ const hasViteConfig = (await exists(join(root, "vite.config.ts"))) ||
34
+ (await exists(join(root, "vite.config.js"))) ||
35
+ (await exists(join(root, "portal.config.ts")));
36
+ checks.push({
37
+ label: "vite.config.ts",
38
+ status: hasViteConfig ? "ok" : "warn",
39
+ detail: !hasViteConfig ? "No Vite config found — run: npm create portal-app" : undefined,
40
+ });
41
+ // app.contract.ts
42
+ const contractPath = await findContractPath(root);
43
+ checks.push({
44
+ label: "app.contract.ts",
45
+ status: contractPath ? "ok" : "warn",
46
+ detail: !contractPath
47
+ ? "No contract found — run: portal contract init"
48
+ : undefined,
49
+ });
50
+ // routes/ directory
51
+ const routesDir = join(root, "routes");
52
+ const hasRoutes = await exists(routesDir);
53
+ let routeCount = 0;
54
+ if (hasRoutes) {
55
+ try {
56
+ const entries = await readdir(routesDir, { recursive: true });
57
+ routeCount = entries.filter((e) => e.endsWith(".page.tsx") || e.endsWith(".page.jsx")).length;
58
+ }
59
+ catch { /* */ }
60
+ }
61
+ checks.push({
62
+ label: `routes/ (${routeCount} page${routeCount !== 1 ? "s" : ""})`,
63
+ status: hasRoutes && routeCount > 0 ? "ok" : "warn",
64
+ detail: !hasRoutes
65
+ ? "No routes/ directory found"
66
+ : routeCount === 0
67
+ ? "routes/ exists but has no *.page.tsx files"
68
+ : undefined,
69
+ });
70
+ // package.json
71
+ const hasPkg = await exists(join(root, "package.json"));
72
+ checks.push({
73
+ label: "package.json",
74
+ status: hasPkg ? "ok" : "fail",
75
+ detail: !hasPkg ? "No package.json — are you in the right directory?" : undefined,
76
+ });
77
+ // AI API key
78
+ const hasApiKey = !!process.env["AIASSIST_API_KEY"] || !!process.env["VITE_AIAS_API_KEY"];
79
+ checks.push({
80
+ label: "AIASSIST_API_KEY",
81
+ status: hasApiKey ? "ok" : "warn",
82
+ detail: !hasApiKey
83
+ ? "Not set — portal audit --ai, portal improve, and portal generate require this"
84
+ : undefined,
85
+ });
86
+ // Data files referenced in contract
87
+ if (contractPath) {
88
+ const contract = await loadContract(root);
89
+ for (const [name, filePath] of Object.entries(contract.data ?? {})) {
90
+ const fullPath = join(root, filePath);
91
+ const fileExists = await exists(fullPath);
92
+ checks.push({
93
+ label: `data.${name} (${filePath})`,
94
+ status: fileExists ? "ok" : "warn",
95
+ detail: !fileExists ? `Data file missing: ${filePath}` : undefined,
96
+ });
97
+ }
98
+ // Check for unreplaced tokens in contract name
99
+ if (contract.name.includes("{{")) {
100
+ checks.push({
101
+ label: "contract.name",
102
+ status: "fail",
103
+ detail: `Contract name contains unreplaced token: "${contract.name}"`,
104
+ });
105
+ }
106
+ }
107
+ // Print results
108
+ blank();
109
+ for (const check of checks) {
110
+ if (check.status === "ok") {
111
+ success(check.label);
112
+ }
113
+ else if (check.status === "warn") {
114
+ warn(check.label);
115
+ if (check.detail)
116
+ console.log(pc.dim(` ${check.detail}`));
117
+ }
118
+ else {
119
+ fail(check.label);
120
+ if (check.detail)
121
+ console.log(pc.red(` ${check.detail}`));
122
+ }
123
+ }
124
+ blank();
125
+ const failCount = checks.filter((c) => c.status === "fail").length;
126
+ const warnCount = checks.filter((c) => c.status === "warn").length;
127
+ if (failCount > 0) {
128
+ fail(`${failCount} critical issue${failCount !== 1 ? "s" : ""} found — fix before proceeding`);
129
+ process.exit(1);
130
+ }
131
+ else if (warnCount > 0) {
132
+ warn(`${warnCount} warning${warnCount !== 1 ? "s" : ""} — not blocking, but worth fixing`);
133
+ }
134
+ else {
135
+ success("All checks passed — project looks healthy");
136
+ }
137
+ blank();
138
+ }
139
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * portal explain <file> — explain a route, component, contract, or project
3
+ * structure in plain English using AI.
4
+ */
5
+ export declare function explainCommand(target: string): Promise<void>;
6
+ //# sourceMappingURL=explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../src/commands/explain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsElE"}