@parlor/scaffold 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +11 -2
- package/dist/add/addon.d.ts +103 -0
- package/dist/add/addon.d.ts.map +1 -0
- package/dist/add/addon.js +12 -0
- package/dist/add/addon.js.map +1 -0
- package/dist/add/plan.d.ts +72 -0
- package/dist/add/plan.d.ts.map +1 -0
- package/dist/add/plan.js +237 -0
- package/dist/add/plan.js.map +1 -0
- package/dist/add/run.d.ts +92 -0
- package/dist/add/run.d.ts.map +1 -0
- package/dist/add/run.js +167 -0
- package/dist/add/run.js.map +1 -0
- package/dist/add/transaction.d.ts +67 -0
- package/dist/add/transaction.d.ts.map +1 -0
- package/dist/add/transaction.js +181 -0
- package/dist/add/transaction.js.map +1 -0
- package/dist/addons/agent.d.ts +58 -0
- package/dist/addons/agent.d.ts.map +1 -0
- package/dist/addons/agent.js +50 -0
- package/dist/addons/agent.js.map +1 -0
- package/dist/addons/auth.d.ts +103 -0
- package/dist/addons/auth.d.ts.map +1 -0
- package/dist/addons/auth.js +93 -0
- package/dist/addons/auth.js.map +1 -0
- package/dist/addons/index.d.ts +159 -0
- package/dist/addons/index.d.ts.map +1 -0
- package/dist/addons/index.js +8 -0
- package/dist/addons/index.js.map +1 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +23 -0
- package/dist/catalog.js.map +1 -0
- package/dist/create.d.ts +45 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +162 -0
- package/dist/create.js.map +1 -0
- package/dist/docs.d.ts +12 -0
- package/dist/docs.d.ts.map +1 -0
- package/dist/docs.js +70 -0
- package/dist/docs.js.map +1 -0
- package/dist/edit/inspect.d.ts +15 -0
- package/dist/edit/inspect.d.ts.map +1 -0
- package/dist/edit/inspect.js +73 -0
- package/dist/edit/inspect.js.map +1 -0
- package/dist/edit/ops.d.ts +92 -0
- package/dist/edit/ops.d.ts.map +1 -0
- package/dist/edit/ops.js +516 -0
- package/dist/edit/ops.js.map +1 -0
- package/dist/edit/source.d.ts +24 -0
- package/dist/edit/source.d.ts.map +1 -0
- package/dist/edit/source.js +36 -0
- package/dist/edit/source.js.map +1 -0
- package/dist/edit/syntax.d.ts +39 -0
- package/dist/edit/syntax.d.ts.map +1 -0
- package/dist/edit/syntax.js +129 -0
- package/dist/edit/syntax.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +5 -0
- package/dist/errors.js.map +1 -0
- package/dist/files.d.ts +15 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +65 -0
- package/dist/files.js.map +1 -0
- package/dist/fixtures.d.ts +28 -0
- package/dist/fixtures.d.ts.map +1 -0
- package/dist/fixtures.js +66 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/git.d.ts +22 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +56 -0
- package/dist/git.js.map +1 -0
- package/dist/identity.d.ts +9 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +23 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/package-manager.d.ts +49 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +118 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +9 -0
- package/dist/version.js.map +1 -0
- package/package.json +46 -3
- package/templates/auth/auth.ts +19 -0
- package/templates/auth/schema/auth.ts +1 -0
- package/templates/auth/src/auth/client.ts +3 -0
- package/templates/auth/src/auth/sign-in-gate.tsx +17 -0
- package/templates/auth/src/auth/sign-out-button.tsx +17 -0
- package/templates/auth/src/routes/link.tsx +92 -0
- package/templates/auth/src/routes/sign-in.tsx +117 -0
- package/templates/default/_gitignore +7 -0
- package/templates/default/actions/index.ts +58 -0
- package/templates/default/actions/todos.spec.ts +38 -0
- package/templates/default/index.html +13 -0
- package/templates/default/migrations/0000_init.sql +9 -0
- package/templates/default/migrations/meta/0000_snapshot.json +87 -0
- package/templates/default/migrations/meta/_journal.json +13 -0
- package/templates/default/package.json +44 -0
- package/templates/default/parlor.config.ts +12 -0
- package/templates/default/schema/index.ts +1 -0
- package/templates/default/schema/todos.ts +13 -0
- package/templates/default/server.ts +13 -0
- package/templates/default/src/agent/agent-button.tsx +120 -0
- package/templates/default/src/agent/agent-sidebar.tsx +828 -0
- package/templates/default/src/agent/agent.css +5 -0
- package/templates/default/src/agent/confirmation-card.tsx +42 -0
- package/templates/default/src/agent/sidebar-view.ts +36 -0
- package/templates/default/src/agent/views.ts +9 -0
- package/templates/default/src/app.css +1 -0
- package/templates/default/src/header-actions.tsx +9 -0
- package/templates/default/src/main.tsx +27 -0
- package/templates/default/src/parlor.d.ts +9 -0
- package/templates/default/src/routeTree.gen.ts +59 -0
- package/templates/default/src/routes/__root.tsx +29 -0
- package/templates/default/src/routes/index.tsx +141 -0
- package/templates/default/tsconfig.json +8 -0
- package/templates/default/vitest.config.ts +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { mkdir, readdir } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\n\nimport type { AddonName } from \"./addons/index.js\";\nimport { CATALOG } from \"./catalog.js\";\nimport { renderAgentsMd, renderReadme } from \"./docs.js\";\nimport { editSource, type Op } from \"./edit/ops.js\";\nimport { parseSource } from \"./edit/source.js\";\nimport { CreateError } from \"./errors.js\";\nimport { type TemplateFiles, templateFiles, writeFiles } from \"./files.js\";\nimport { type GitOutcome, initialCommit } from \"./git.js\";\nimport { type AppIdentity, identityFor } from \"./identity.js\";\nimport {\n commandsFor,\n execCommand,\n type InstallOutcome,\n type PackageManager,\n packageManagerField,\n packageManagerFiles,\n runInstall,\n} from \"./package-manager.js\";\nimport { FRAMEWORK_VERSION } from \"./version.js\";\n\nexport interface CreateOptions {\n readonly directory: string;\n readonly packageManager: PackageManager;\n readonly mode: \"apply\" | \"dry-run\";\n readonly install: boolean;\n readonly git: boolean;\n /** Run through the project's own CLI after a successful install, so create needs no toolchain. */\n readonly addons: readonly AddonName[];\n readonly log: (line: string) => void;\n}\n\nexport interface CreatedProject {\n readonly directory: string;\n readonly identity: AppIdentity;\n readonly packageManager: PackageManager;\n readonly files: readonly string[];\n readonly install: InstallOutcome | { readonly kind: \"skipped\" };\n readonly addons: {\n readonly applied: readonly AddonName[];\n /** Still to run as `<pm> exec parlor add <name>`; the next steps print the command. */\n readonly deferred: readonly AddonName[];\n };\n readonly git: GitOutcome | { readonly kind: \"disabled\" };\n}\n\nexport const CREATE_SAFE_ENTRIES: ReadonlySet<string> = new Set([\n \".git\",\n \".DS_Store\",\n \".idea\",\n \".vscode\",\n \".claude\",\n \".cursor\",\n \"LICENSE\",\n \"Thumbs.db\",\n]);\n\nconst DEFAULT_TEMPLATE = \"default\";\n\n/**\n * The default template's `parlor.config.ts` names itself; create renames it through the same\n * edit engine `parlor add` uses, so the template stays a plain project with no placeholders.\n */\nexport function identityOps(identity: AppIdentity): readonly Op[] {\n const call = { callee: \"defineConfig\", from: \"@parlor/config\" };\n return [\n {\n kind: \"set-property\",\n call,\n path: [\"app\", \"id\"],\n value: JSON.stringify(identity.appId),\n onConflict: \"replace\",\n },\n {\n kind: \"set-property\",\n call,\n path: [\"app\", \"name\"],\n value: JSON.stringify(identity.appName),\n onConflict: \"replace\",\n },\n ];\n}\n\nconst CONFIG_FILE = \"parlor.config.ts\";\n\nfunction renameApp(text: string, identity: AppIdentity): string {\n const outcome = editSource(parseSource(CONFIG_FILE, text), identityOps(identity));\n if (outcome.status === \"unsafe\") {\n throw new Error(\n `The default template's ${CONFIG_FILE} cannot be renamed: ${outcome.unsafe.map((entry) => entry.reason).join(\" \")}`,\n );\n }\n return outcome.status === \"edit\" ? outcome.text : text;\n}\n\nexport async function renderProject(\n identity: AppIdentity,\n packageManager: PackageManager,\n templates: TemplateFiles,\n version: string = FRAMEWORK_VERSION,\n): Promise<ReadonlyMap<string, string>> {\n const files = new Map<string, string>();\n for (const path of await templates.list(DEFAULT_TEMPLATE, \"\")) {\n const text = await templates.read(DEFAULT_TEMPLATE, path);\n files.set(\n path,\n path === \"package.json\"\n ? rewritePackageJson(text, identity, packageManager, version)\n : path === CONFIG_FILE\n ? renameApp(text, identity)\n : text,\n );\n }\n const docs = { identity, packageManager, version };\n files.set(\"README.md\", renderReadme(docs));\n files.set(\"AGENTS.md\", renderAgentsMd(docs));\n for (const [path, text] of packageManagerFiles(packageManager)) files.set(path, text);\n return new Map([...files].sort(([a], [b]) => a.localeCompare(b)));\n}\n\ninterface Manifest {\n readonly name?: string;\n readonly packageManager?: string;\n readonly dependencies?: Readonly<Record<string, string>>;\n readonly devDependencies?: Readonly<Record<string, string>>;\n readonly [key: string]: unknown;\n}\n\nconst UNINSTALLABLE = /^(?:workspace|catalog|link|file|portal):/;\n\n/** `catalog:` takes the range the framework was published with, so the project resolves one zod and one React. */\nexport function rewritePackageJson(\n text: string,\n identity: AppIdentity,\n packageManager: PackageManager,\n version: string,\n): string {\n const manifest = JSON.parse(text) as Manifest;\n const resolve = (dependencies: Readonly<Record<string, string>>) =>\n Object.fromEntries(\n Object.entries(dependencies).map(([name, range]) => {\n const resolved = range.startsWith(\"workspace:\")\n ? version\n : range === \"catalog:\"\n ? (CATALOG[name] ?? range)\n : range;\n if (UNINSTALLABLE.test(resolved)) {\n throw new Error(\n `${name}@${range} cannot be installed outside the Parlor repo.`,\n );\n }\n return [name, resolved];\n }),\n );\n const field = packageManagerField(packageManager);\n const { name: _name, packageManager: _manager, ...rest } = manifest;\n const rewritten: Manifest = {\n name: identity.packageName,\n ...rest,\n ...(field ? { packageManager: field } : {}),\n ...(manifest.dependencies ? { dependencies: resolve(manifest.dependencies) } : {}),\n ...(manifest.devDependencies\n ? { devDependencies: resolve(manifest.devDependencies) }\n : {}),\n };\n return `${JSON.stringify(rewritten, null, 2)}\\n`;\n}\n\nasync function checkTarget(directory: string): Promise<void> {\n const entries = await readdir(directory).catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return [];\n throw error;\n });\n const blocking = entries.filter((entry) => !CREATE_SAFE_ENTRIES.has(entry)).sort();\n if (blocking.length > 0) {\n throw new CreateError(\n `${basename(directory)} is not empty (${blocking.join(\", \")}). Pick a new folder name.`,\n );\n }\n}\n\n/** Install and git failures are reported, never thrown: the files are already a working project. */\nexport async function createProject(options: CreateOptions): Promise<CreatedProject> {\n const { directory, packageManager } = options;\n await checkTarget(directory);\n const identity = identityFor(basename(directory));\n const files = await renderProject(identity, packageManager, templateFiles());\n const result = {\n directory,\n identity,\n packageManager,\n files: [...files.keys()],\n install: { kind: \"skipped\" } as CreatedProject[\"install\"],\n addons: { applied: [], deferred: options.addons },\n git: { kind: \"disabled\" } as CreatedProject[\"git\"],\n };\n if (options.mode === \"dry-run\") return result;\n await mkdir(directory, { recursive: true });\n await writeFiles(directory, files);\n const install = options.install\n ? await runInstall(directory, commandsFor(packageManager).install, options.log)\n : result.install;\n const addons =\n install.kind === \"installed\" || install.kind === \"ignored-builds\"\n ? await applyAddons(directory, packageManager, options.addons)\n : result.addons;\n const git = options.git ? await initialCommit(directory) : result.git;\n return { ...result, install, addons, git };\n}\n\n/** `--no-git-check`: the files are about to be committed as one, so they are untracked now. */\nasync function applyAddons(\n directory: string,\n packageManager: PackageManager,\n addons: readonly AddonName[],\n): Promise<CreatedProject[\"addons\"]> {\n const applied: AddonName[] = [];\n const deferred: AddonName[] = [];\n for (const addon of addons) {\n const command = execCommand(packageManager, \"parlor\", [\n \"add\",\n addon,\n \"--no-git-check\",\n ]);\n const code = await new Promise<number | null>((resolve) => {\n const child = spawn(command.bin, command.args, {\n cwd: directory,\n stdio: \"inherit\",\n });\n child.once(\"error\", () => resolve(null));\n child.once(\"close\", resolve);\n });\n (code === 0 ? applied : deferred).push(addon);\n }\n return { applied, deferred };\n}\n"]}
|
package/dist/docs.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AppIdentity } from "./identity.js";
|
|
2
|
+
import { type PackageManager } from "./package-manager.js";
|
|
3
|
+
export interface ProjectDocsInput {
|
|
4
|
+
readonly identity: AppIdentity;
|
|
5
|
+
readonly packageManager: PackageManager;
|
|
6
|
+
readonly version: string;
|
|
7
|
+
}
|
|
8
|
+
/** Rendered per package manager, so every command in it runs as written. */
|
|
9
|
+
export declare function renderReadme({ identity, packageManager }: ProjectDocsInput): string;
|
|
10
|
+
/** Facts a coding agent cannot infer from the files, plus where the full docs are. */
|
|
11
|
+
export declare function renderAgentsMd({ packageManager, version }: ProjectDocsInput): string;
|
|
12
|
+
//# sourceMappingURL=docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../src/docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGxE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,gBAAgB,GAAG,MAAM,CAmCnF;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE,gBAAgB,GAAG,MAAM,CA4BpF"}
|
package/dist/docs.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { commandsFor } from "./package-manager.js";
|
|
2
|
+
import { DOCS_URL } from "./version.js";
|
|
3
|
+
/** Rendered per package manager, so every command in it runs as written. */
|
|
4
|
+
export function renderReadme({ identity, packageManager }) {
|
|
5
|
+
const pm = commandsFor(packageManager);
|
|
6
|
+
return `# ${identity.appName}
|
|
7
|
+
|
|
8
|
+
A [Parlor](${DOCS_URL}) app. Everything the UI does goes through actions, so your coding agent
|
|
9
|
+
can do it too: from the sidebar, over MCP, or over HTTP.
|
|
10
|
+
|
|
11
|
+
## Develop
|
|
12
|
+
|
|
13
|
+
\`\`\`sh
|
|
14
|
+
${pm.run("dev")}
|
|
15
|
+
\`\`\`
|
|
16
|
+
|
|
17
|
+
Open http://localhost:5173 and press **Agent** to chat with the coding agent on this computer
|
|
18
|
+
(Claude Code or Codex). Ask it to add a todo.
|
|
19
|
+
|
|
20
|
+
| Command | What it does |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| \`${pm.run("dev")}\` | App, API and agent host with hot reload |
|
|
23
|
+
| \`${pm.run("typecheck")}\` | Regenerate the route tree, then \`tsc\` |
|
|
24
|
+
| \`${pm.run("test")}\` | Vitest |
|
|
25
|
+
| \`${pm.run("db:generate")}\` | A SQL migration from \`schema/\` |
|
|
26
|
+
| \`${pm.run("build")}\` | Production build in \`.parlor/\` |
|
|
27
|
+
| \`${pm.exec("parlor", ["add", "auth"])}\` | Sign-in, so each user sees only their own data |
|
|
28
|
+
| \`${pm.exec("parlor", ["dev", "--target", "mac"])}\` | The same app as a macOS window |
|
|
29
|
+
|
|
30
|
+
## Layout
|
|
31
|
+
|
|
32
|
+
- \`actions/\`: every piece of business logic, as \`defineAction\`. The UI, agents, HTTP and MCP all call these.
|
|
33
|
+
- \`schema/\`: the Drizzle tables; \`migrations/\` is generated from them.
|
|
34
|
+
- \`src/routes/\`: pages. \`src/agent/\`: the agent sidebar, yours to change.
|
|
35
|
+
- \`parlor.config.ts\`: app name, id, ports, and Vite options under \`vite\`.
|
|
36
|
+
|
|
37
|
+
Learn more at ${DOCS_URL}/getting-started/.
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
/** Facts a coding agent cannot infer from the files, plus where the full docs are. */
|
|
41
|
+
export function renderAgentsMd({ packageManager, version }) {
|
|
42
|
+
const pm = commandsFor(packageManager);
|
|
43
|
+
return `# AGENTS.md
|
|
44
|
+
|
|
45
|
+
This is a Parlor ${version} app. Parlor changes faster than your training data: read
|
|
46
|
+
${DOCS_URL}/llms.txt (every page, as Markdown) before changing how the app is wired.
|
|
47
|
+
|
|
48
|
+
## Rules
|
|
49
|
+
|
|
50
|
+
- Business logic lives only in \`actions/\` as \`defineAction\`. The UI calls actions with
|
|
51
|
+
\`useActionQuery\` and \`useActionMutation\` from \`@parlor/client/react\`, never \`fetch\`.
|
|
52
|
+
A page loads its data in its route \`loader\` with \`ensureActionQueryData\` and reads it with
|
|
53
|
+
\`useActionSuspenseQuery\`.
|
|
54
|
+
- Every table has a \`scope\` column and every action filters by \`ctx.scope\`.
|
|
55
|
+
- An action that changes data declares \`writes\`; one that reads declares \`reads\`. That is how
|
|
56
|
+
pages refresh when an agent changes something.
|
|
57
|
+
- After changing \`schema/\`, run \`${pm.run("db:generate")}\` and commit the migration.
|
|
58
|
+
- \`.parlor/\` is generated. Never edit it. There is no \`vite.config.ts\`: Vite options go in the
|
|
59
|
+
\`vite\` field of \`parlor.config.ts\`.
|
|
60
|
+
- Add features with \`${pm.exec("parlor", ["add", "<auth|agent>"])}\` instead of wiring them by hand.
|
|
61
|
+
- Porting an existing app into this project? Follow ${DOCS_URL}/guides/migrating/ step by step,
|
|
62
|
+
and ask the person before working around anything it lists as not supported yet.
|
|
63
|
+
|
|
64
|
+
## Commands
|
|
65
|
+
|
|
66
|
+
- \`${pm.run("dev")}\`: runs until stopped; the app is on http://localhost:5173.
|
|
67
|
+
- \`${pm.run("typecheck")}\` and \`${pm.run("test")}\` must pass before you finish.
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=docs.js.map
|
package/dist/docs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.js","sourceRoot":"","sources":["../src/docs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAuB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAQxC,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAoB;IACzE,MAAM,EAAE,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IACvC,OAAO,KAAK,QAAQ,CAAC,OAAO;;aAEjB,QAAQ;;;;;;EAMnB,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;;;;;;;;MAQT,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;MACb,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC;MACnB,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;MACd,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC;MACrB,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;MACf,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;MAClC,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;;;;;;;;;gBASnC,QAAQ;CACvB,CAAC;AACF,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,cAAc,CAAC,EAAE,cAAc,EAAE,OAAO,EAAoB;IAC1E,MAAM,EAAE,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IACvC,OAAO;;mBAEU,OAAO;EACxB,QAAQ;;;;;;;;;;;sCAW4B,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC;;;wBAGnC,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;sDACZ,QAAQ;;;;;MAKxD,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;MACb,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;CAClD,CAAC;AACF,CAAC","sourcesContent":["import type { AppIdentity } from \"./identity.js\";\nimport { commandsFor, type PackageManager } from \"./package-manager.js\";\nimport { DOCS_URL } from \"./version.js\";\n\nexport interface ProjectDocsInput {\n readonly identity: AppIdentity;\n readonly packageManager: PackageManager;\n readonly version: string;\n}\n\n/** Rendered per package manager, so every command in it runs as written. */\nexport function renderReadme({ identity, packageManager }: ProjectDocsInput): string {\n const pm = commandsFor(packageManager);\n return `# ${identity.appName}\n\nA [Parlor](${DOCS_URL}) app. Everything the UI does goes through actions, so your coding agent\ncan do it too: from the sidebar, over MCP, or over HTTP.\n\n## Develop\n\n\\`\\`\\`sh\n${pm.run(\"dev\")}\n\\`\\`\\`\n\nOpen http://localhost:5173 and press **Agent** to chat with the coding agent on this computer\n(Claude Code or Codex). Ask it to add a todo.\n\n| Command | What it does |\n| --- | --- |\n| \\`${pm.run(\"dev\")}\\` | App, API and agent host with hot reload |\n| \\`${pm.run(\"typecheck\")}\\` | Regenerate the route tree, then \\`tsc\\` |\n| \\`${pm.run(\"test\")}\\` | Vitest |\n| \\`${pm.run(\"db:generate\")}\\` | A SQL migration from \\`schema/\\` |\n| \\`${pm.run(\"build\")}\\` | Production build in \\`.parlor/\\` |\n| \\`${pm.exec(\"parlor\", [\"add\", \"auth\"])}\\` | Sign-in, so each user sees only their own data |\n| \\`${pm.exec(\"parlor\", [\"dev\", \"--target\", \"mac\"])}\\` | The same app as a macOS window |\n\n## Layout\n\n- \\`actions/\\`: every piece of business logic, as \\`defineAction\\`. The UI, agents, HTTP and MCP all call these.\n- \\`schema/\\`: the Drizzle tables; \\`migrations/\\` is generated from them.\n- \\`src/routes/\\`: pages. \\`src/agent/\\`: the agent sidebar, yours to change.\n- \\`parlor.config.ts\\`: app name, id, ports, and Vite options under \\`vite\\`.\n\nLearn more at ${DOCS_URL}/getting-started/.\n`;\n}\n\n/** Facts a coding agent cannot infer from the files, plus where the full docs are. */\nexport function renderAgentsMd({ packageManager, version }: ProjectDocsInput): string {\n const pm = commandsFor(packageManager);\n return `# AGENTS.md\n\nThis is a Parlor ${version} app. Parlor changes faster than your training data: read\n${DOCS_URL}/llms.txt (every page, as Markdown) before changing how the app is wired.\n\n## Rules\n\n- Business logic lives only in \\`actions/\\` as \\`defineAction\\`. The UI calls actions with\n \\`useActionQuery\\` and \\`useActionMutation\\` from \\`@parlor/client/react\\`, never \\`fetch\\`.\n A page loads its data in its route \\`loader\\` with \\`ensureActionQueryData\\` and reads it with\n \\`useActionSuspenseQuery\\`.\n- Every table has a \\`scope\\` column and every action filters by \\`ctx.scope\\`.\n- An action that changes data declares \\`writes\\`; one that reads declares \\`reads\\`. That is how\n pages refresh when an agent changes something.\n- After changing \\`schema/\\`, run \\`${pm.run(\"db:generate\")}\\` and commit the migration.\n- \\`.parlor/\\` is generated. Never edit it. There is no \\`vite.config.ts\\`: Vite options go in the\n \\`vite\\` field of \\`parlor.config.ts\\`.\n- Add features with \\`${pm.exec(\"parlor\", [\"add\", \"<auth|agent>\"])}\\` instead of wiring them by hand.\n- Porting an existing app into this project? Follow ${DOCS_URL}/guides/migrating/ step by step,\n and ask the person before working around anything it lists as not supported yet.\n\n## Commands\n\n- \\`${pm.run(\"dev\")}\\`: runs until stopped; the app is on http://localhost:5173.\n- \\`${pm.run(\"typecheck\")}\\` and \\`${pm.run(\"test\")}\\` must pass before you finish.\n`;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type SourceFile } from "./source.js";
|
|
2
|
+
export type Presence = "installed" | "absent" | "unknown";
|
|
3
|
+
/**
|
|
4
|
+
* What the app's server entry passes to `createServer`, read from its syntax without running
|
|
5
|
+
* it. `unknown` when the shape hides it (options built elsewhere, spreads, a plugins variable),
|
|
6
|
+
* so every reader picks the behavior that is safe when it cannot tell.
|
|
7
|
+
*/
|
|
8
|
+
export interface ServerShape {
|
|
9
|
+
readonly auth: Presence;
|
|
10
|
+
readonly chat: Presence;
|
|
11
|
+
}
|
|
12
|
+
export declare const UNKNOWN_SERVER: ServerShape;
|
|
13
|
+
export declare function inspectServer(file: SourceFile): ServerShape;
|
|
14
|
+
export declare function inspectServerEntry(rootDir: string, entry: string): Promise<ServerShape>;
|
|
15
|
+
//# sourceMappingURL=inspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/edit/inspect.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAU3D,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED,eAAO,MAAM,cAAc,EAAE,WAAkD,CAAC;AA8ChF,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAa3D;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,CAAC,CAQtB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parseSource } from "./source.js";
|
|
4
|
+
import { findCall, importedName, objectArgument, propertyOf, valueOf, } from "./syntax.js";
|
|
5
|
+
export const UNKNOWN_SERVER = { auth: "unknown", chat: "unknown" };
|
|
6
|
+
const SERVER = { callee: "createServer", from: "@parlor/server" };
|
|
7
|
+
const CHAT = { callee: "chat", from: "@parlor/chat/server" };
|
|
8
|
+
/** A call, or a module-scope `const` bound once to a call; anything conditional is unknown. */
|
|
9
|
+
function authPresence(file, value) {
|
|
10
|
+
if (value.type === "Identifier" && value.name === "undefined")
|
|
11
|
+
return "absent";
|
|
12
|
+
const unwrapped = value.type === "AwaitExpression" ? value.argument : value;
|
|
13
|
+
if (unwrapped.type === "CallExpression" || unwrapped.type === "NewExpression") {
|
|
14
|
+
return "installed";
|
|
15
|
+
}
|
|
16
|
+
if (value.type !== "Identifier")
|
|
17
|
+
return "unknown";
|
|
18
|
+
const declarators = file.ast.program.body.flatMap((statement) => {
|
|
19
|
+
const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
|
|
20
|
+
return declaration?.type === "VariableDeclaration" && declaration.kind === "const"
|
|
21
|
+
? declaration.declarations.filter((declarator) => declarator.id.type === "Identifier" && declarator.id.name === value.name)
|
|
22
|
+
: [];
|
|
23
|
+
});
|
|
24
|
+
const init = declarators.length === 1 ? declarators[0]?.init : undefined;
|
|
25
|
+
const call = init?.type === "AwaitExpression" ? init.argument : init;
|
|
26
|
+
return call?.type === "CallExpression" || call?.type === "NewExpression"
|
|
27
|
+
? "installed"
|
|
28
|
+
: "unknown";
|
|
29
|
+
}
|
|
30
|
+
function chatPresence(file, plugins) {
|
|
31
|
+
if (plugins.type !== "ArrayExpression")
|
|
32
|
+
return "unknown";
|
|
33
|
+
if (plugins.elements.some((element) => element?.type === "SpreadElement"))
|
|
34
|
+
return "unknown";
|
|
35
|
+
const local = importedName(file, CHAT.callee, CHAT.from);
|
|
36
|
+
if (!local)
|
|
37
|
+
return "absent";
|
|
38
|
+
return plugins.elements.some((element) => element?.type === "CallExpression" &&
|
|
39
|
+
element.callee.type === "Identifier" &&
|
|
40
|
+
element.callee.name === local)
|
|
41
|
+
? "installed"
|
|
42
|
+
: "absent";
|
|
43
|
+
}
|
|
44
|
+
export function inspectServer(file) {
|
|
45
|
+
const call = findCall(file, SERVER);
|
|
46
|
+
if (!call.ok)
|
|
47
|
+
return UNKNOWN_SERVER;
|
|
48
|
+
const argument = objectArgument(file, SERVER, call.value);
|
|
49
|
+
if (!argument.ok)
|
|
50
|
+
return UNKNOWN_SERVER;
|
|
51
|
+
if (argument.value.kind === "none")
|
|
52
|
+
return { auth: "absent", chat: "absent" };
|
|
53
|
+
const auth = propertyOf(file, argument.value.node, "auth");
|
|
54
|
+
const plugins = propertyOf(file, argument.value.node, "plugins");
|
|
55
|
+
if (!auth.ok || !plugins.ok)
|
|
56
|
+
return UNKNOWN_SERVER;
|
|
57
|
+
return {
|
|
58
|
+
auth: auth.value ? authPresence(file, valueOf(auth.value)) : "absent",
|
|
59
|
+
chat: plugins.value ? chatPresence(file, valueOf(plugins.value)) : "absent",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export async function inspectServerEntry(rootDir, entry) {
|
|
63
|
+
const text = await readFile(join(rootDir, entry), "utf8").catch(() => undefined);
|
|
64
|
+
if (text === undefined)
|
|
65
|
+
return UNKNOWN_SERVER;
|
|
66
|
+
try {
|
|
67
|
+
return inspectServer(parseSource(entry, text));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return UNKNOWN_SERVER;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/edit/inspect.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport type { Expression } from \"@babel/types\";\n\nimport { parseSource, type SourceFile } from \"./source.js\";\nimport {\n type CallSite,\n findCall,\n importedName,\n objectArgument,\n propertyOf,\n valueOf,\n} from \"./syntax.js\";\n\nexport type Presence = \"installed\" | \"absent\" | \"unknown\";\n\n/**\n * What the app's server entry passes to `createServer`, read from its syntax without running\n * it. `unknown` when the shape hides it (options built elsewhere, spreads, a plugins variable),\n * so every reader picks the behavior that is safe when it cannot tell.\n */\nexport interface ServerShape {\n readonly auth: Presence;\n readonly chat: Presence;\n}\n\nexport const UNKNOWN_SERVER: ServerShape = { auth: \"unknown\", chat: \"unknown\" };\n\nconst SERVER: CallSite = { callee: \"createServer\", from: \"@parlor/server\" };\nconst CHAT: CallSite = { callee: \"chat\", from: \"@parlor/chat/server\" };\n\n/** A call, or a module-scope `const` bound once to a call; anything conditional is unknown. */\nfunction authPresence(file: SourceFile, value: Expression): Presence {\n if (value.type === \"Identifier\" && value.name === \"undefined\") return \"absent\";\n const unwrapped = value.type === \"AwaitExpression\" ? value.argument : value;\n if (unwrapped.type === \"CallExpression\" || unwrapped.type === \"NewExpression\") {\n return \"installed\";\n }\n if (value.type !== \"Identifier\") return \"unknown\";\n const declarators = file.ast.program.body.flatMap((statement) => {\n const declaration =\n statement.type === \"ExportNamedDeclaration\" ? statement.declaration : statement;\n return declaration?.type === \"VariableDeclaration\" && declaration.kind === \"const\"\n ? declaration.declarations.filter(\n (declarator) =>\n declarator.id.type === \"Identifier\" && declarator.id.name === value.name,\n )\n : [];\n });\n const init = declarators.length === 1 ? declarators[0]?.init : undefined;\n const call = init?.type === \"AwaitExpression\" ? init.argument : init;\n return call?.type === \"CallExpression\" || call?.type === \"NewExpression\"\n ? \"installed\"\n : \"unknown\";\n}\n\nfunction chatPresence(file: SourceFile, plugins: Expression): Presence {\n if (plugins.type !== \"ArrayExpression\") return \"unknown\";\n if (plugins.elements.some((element) => element?.type === \"SpreadElement\"))\n return \"unknown\";\n const local = importedName(file, CHAT.callee, CHAT.from);\n if (!local) return \"absent\";\n return plugins.elements.some(\n (element) =>\n element?.type === \"CallExpression\" &&\n element.callee.type === \"Identifier\" &&\n element.callee.name === local,\n )\n ? \"installed\"\n : \"absent\";\n}\n\nexport function inspectServer(file: SourceFile): ServerShape {\n const call = findCall(file, SERVER);\n if (!call.ok) return UNKNOWN_SERVER;\n const argument = objectArgument(file, SERVER, call.value);\n if (!argument.ok) return UNKNOWN_SERVER;\n if (argument.value.kind === \"none\") return { auth: \"absent\", chat: \"absent\" };\n const auth = propertyOf(file, argument.value.node, \"auth\");\n const plugins = propertyOf(file, argument.value.node, \"plugins\");\n if (!auth.ok || !plugins.ok) return UNKNOWN_SERVER;\n return {\n auth: auth.value ? authPresence(file, valueOf(auth.value)) : \"absent\",\n chat: plugins.value ? chatPresence(file, valueOf(plugins.value)) : \"absent\",\n };\n}\n\nexport async function inspectServerEntry(\n rootDir: string,\n entry: string,\n): Promise<ServerShape> {\n const text = await readFile(join(rootDir, entry), \"utf8\").catch(() => undefined);\n if (text === undefined) return UNKNOWN_SERVER;\n try {\n return inspectServer(parseSource(entry, text));\n } catch {\n return UNKNOWN_SERVER;\n }\n}\n"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type SourceFile, type Splice } from "./source.js";
|
|
2
|
+
import { type CallSite } from "./syntax.js";
|
|
3
|
+
export type { CallSite } from "./syntax.js";
|
|
4
|
+
/**
|
|
5
|
+
* The closed set of code edits. Each one knows how to tell that it is already done, how to
|
|
6
|
+
* make it, and when it is unsafe. Add a kind here, with its tests, instead of editing text
|
|
7
|
+
* anywhere else.
|
|
8
|
+
*/
|
|
9
|
+
export type Op =
|
|
10
|
+
/** Joins an existing value import from `from`, else a new line where oxfmt's sorted imports put it. */
|
|
11
|
+
{
|
|
12
|
+
readonly kind: "import";
|
|
13
|
+
readonly names: readonly string[];
|
|
14
|
+
readonly from: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: "export-all";
|
|
17
|
+
readonly from: string;
|
|
18
|
+
}
|
|
19
|
+
/** Present when an element starts with the same identifier: `chat()` is present when `chat(...)` is. */
|
|
20
|
+
| {
|
|
21
|
+
readonly kind: "append-element";
|
|
22
|
+
readonly call: CallSite;
|
|
23
|
+
readonly path: readonly [string, ...string[]];
|
|
24
|
+
readonly element: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* `$name` in `value` is replaced with the source text of the sibling property `name`, so
|
|
28
|
+
* `createAuth($database)` follows whatever the app passes.
|
|
29
|
+
*/
|
|
30
|
+
| {
|
|
31
|
+
readonly kind: "set-property";
|
|
32
|
+
readonly call: CallSite;
|
|
33
|
+
readonly path: readonly [string, ...string[]];
|
|
34
|
+
readonly value: string;
|
|
35
|
+
/** `unsafe` for add-ons, which never overwrite; `replace` for create's own template. */
|
|
36
|
+
readonly onConflict: "unsafe" | "replace";
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: "wrap-property";
|
|
39
|
+
readonly call: CallSite;
|
|
40
|
+
readonly path: readonly [string, ...string[]];
|
|
41
|
+
readonly wrapper: string;
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: "jsx-attribute";
|
|
44
|
+
readonly element: string;
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly value: string;
|
|
47
|
+
}
|
|
48
|
+
/** The component must return exactly one JSX element or fragment. */
|
|
49
|
+
| {
|
|
50
|
+
readonly kind: "jsx-child";
|
|
51
|
+
readonly component: string;
|
|
52
|
+
readonly element: string;
|
|
53
|
+
};
|
|
54
|
+
export type OpOutcome = {
|
|
55
|
+
readonly status: "done";
|
|
56
|
+
} | {
|
|
57
|
+
readonly status: "edit";
|
|
58
|
+
readonly splices: readonly Splice[];
|
|
59
|
+
} | {
|
|
60
|
+
readonly status: "unsafe";
|
|
61
|
+
readonly reason: string;
|
|
62
|
+
};
|
|
63
|
+
export declare function evaluateOp(file: SourceFile, op: Op): OpOutcome;
|
|
64
|
+
/** One short line for the printed plan, such as "auth: createAuth(database)"; none for an import. */
|
|
65
|
+
export declare function opSummary(file: SourceFile, op: Op): string | undefined;
|
|
66
|
+
/** The code to write by hand for `op`; a `$name` stands for the sibling the app passes. */
|
|
67
|
+
export declare function manualCode(op: Op): string;
|
|
68
|
+
export declare function indentLines(text: string, indent: string): string;
|
|
69
|
+
/** The change to make by hand when `op` is unsafe. */
|
|
70
|
+
export declare function manualChange(file: string, op: Op): string;
|
|
71
|
+
export type EditOutcome = {
|
|
72
|
+
readonly status: "done";
|
|
73
|
+
} | {
|
|
74
|
+
readonly status: "edit";
|
|
75
|
+
readonly text: string;
|
|
76
|
+
} | {
|
|
77
|
+
readonly status: "unsafe";
|
|
78
|
+
readonly unsafe: readonly UnsafeOp[];
|
|
79
|
+
};
|
|
80
|
+
export interface UnsafeOp {
|
|
81
|
+
readonly op: Op;
|
|
82
|
+
readonly reason: string;
|
|
83
|
+
}
|
|
84
|
+
export declare const UNCONFIRMED = "could not confirm the edit";
|
|
85
|
+
/**
|
|
86
|
+
* Applies `ops` in order, reparsing after each one, then proves the result: it must still
|
|
87
|
+
* parse and every op must now evaluate to `done`. A failed proof is `unsafe`, so a bug in an op
|
|
88
|
+
* can cost a manual step but never a broken or half-edited file, and a second run is a no-op
|
|
89
|
+
* by construction. Collects every unsafe op instead of stopping at the first.
|
|
90
|
+
*/
|
|
91
|
+
export declare function editSource(file: SourceFile, ops: readonly Op[]): EditOutcome;
|
|
92
|
+
//# sourceMappingURL=ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/edit/ops.ts"],"names":[],"mappings":"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"}
|