okno 1.0.0-alpha.16 → 1.0.0-alpha.17

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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { o as a } from "./plugin-DfOx2gkl.js";
1
+ import { o as a } from "./plugin-Cy62173B.js";
2
2
  export {
3
3
  a as okno
4
4
  };
package/dist/init.d.ts CHANGED
@@ -13,8 +13,25 @@ export declare function detect(cwd: string): Detected;
13
13
  * never reformat). Returns false (→ manual fallback) if there's no `plugins`
14
14
  * array to extend, e.g. a bare `defineConfig({})`. Idempotent. */
15
15
  export declare function addPlugin(configPath: string): boolean;
16
- /** Scaffold okno/schema.ts + a starter home page if there's no okno/ yet. */
17
- export declare function scaffold(cwd: string): boolean;
16
+ export type ScaffoldMode = "starter" | "empty";
17
+ /**
18
+ * Scaffold okno/ if there's no okno/ yet. Two modes:
19
+ * - "starter": the site-wide globals every site needs — Meta (SEO/OG), Navbar,
20
+ * Footer — plus a Home page and a `navlink` block the nav/footer reuse. Ships
21
+ * ready to edit so the editor isn't an empty shell on first run.
22
+ * - "empty": just a Home page with a single field — a blank slate to model from
23
+ * scratch.
24
+ * The `connect-okno` skill explains why those are globals and how to extend the
25
+ * model. Returns false if okno/ already exists (left untouched).
26
+ */
27
+ export declare function scaffold(cwd: string, mode?: ScaffoldMode): boolean;
28
+ /**
29
+ * Install the `connect-okno` skill into the project's `.claude/skills/` so the
30
+ * agent has the okno mental model (when to use collections vs blocks vs globals,
31
+ * the spread-to-edit pattern) on hand. Claude clients only. Returns the relative
32
+ * path written, or null if the bundled skill couldn't be found / already exists.
33
+ */
34
+ export declare function writeSkill(cwd: string): string | null;
18
35
  /** Register the okno MCP server for an AI client. */
19
36
  export declare function writeMcpConfig(cwd: string, client: "claude" | "cursor"): string;
20
37
  export declare function runInit(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAgBA,KAAK,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;AAEpE,UAAU,QAAQ;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,yEAAyE;IACzE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,oFAAoF;IACpF,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;CACzB;AAiBD,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CA0B5C;AAED;;;mEAGmE;AACnE,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CA8BrD;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAc7C;AAED,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAgB/E;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE7C"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAiBA,KAAK,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;AAEpE,UAAU,QAAQ;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,yEAAyE;IACzE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,oFAAoF;IACpF,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;CACzB;AAiBD,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CA0B5C;AAED;;;mEAGmE;AACnE,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CA8BrD;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,CAAA;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAAwB,GAAG,OAAO,CAmB7E;AA0GD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWrD;AAED,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAgB/E;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CA8F7C"}
package/dist/init.js CHANGED
@@ -1,54 +1,55 @@
1
- import { existsSync as g, readFileSync as k, writeFileSync as m, mkdirSync as v } from "node:fs";
2
- import { join as r } from "node:path";
3
- const l = {
1
+ import { existsSync as f, readFileSync as h, writeFileSync as l, mkdirSync as g } from "node:fs";
2
+ import { join as s, dirname as v } from "node:path";
3
+ import { fileURLToPath as S } from "node:url";
4
+ const u = {
4
5
  astro: ["astro.config.mjs", "astro.config.ts", "astro.config.js"],
5
6
  sveltekit: ["vite.config.ts", "vite.config.js"],
6
7
  nuxt: ["nuxt.config.ts", "nuxt.config.js"],
7
8
  vite: ["vite.config.ts", "vite.config.js", "vite.config.mjs"]
8
9
  };
9
- function u(o, e) {
10
+ function p(n, e) {
10
11
  for (const t of e) {
11
- const n = r(o, t);
12
- if (g(n)) return n;
12
+ const o = s(n, t);
13
+ if (f(o)) return o;
13
14
  }
14
15
  return null;
15
16
  }
16
- function h(o) {
17
- const e = r(o, "package.json"), t = {};
18
- if (g(e))
17
+ function b(n) {
18
+ const e = s(n, "package.json"), t = {};
19
+ if (f(e))
19
20
  try {
20
- const i = JSON.parse(k(e, "utf-8"));
21
+ const i = JSON.parse(h(e, "utf-8"));
21
22
  Object.assign(t, i.dependencies, i.devDependencies);
22
23
  } catch {
23
24
  }
24
- const n = (i) => i in t;
25
- return n("astro") || u(o, l.astro) ? { framework: "astro", configPath: u(o, l.astro), pluginsAt: "vite" } : n("nuxt") ? { framework: "nuxt", configPath: u(o, l.nuxt), pluginsAt: "vite" } : n("@sveltejs/kit") ? { framework: "sveltekit", configPath: u(o, l.vite), pluginsAt: "top" } : n("vite") ? { framework: "vite", configPath: u(o, l.vite), pluginsAt: "top" } : { framework: "unknown", configPath: null, pluginsAt: "top" };
25
+ const o = (i) => i in t;
26
+ return o("astro") || p(n, u.astro) ? { framework: "astro", configPath: p(n, u.astro), pluginsAt: "vite" } : o("nuxt") ? { framework: "nuxt", configPath: p(n, u.nuxt), pluginsAt: "vite" } : o("@sveltejs/kit") ? { framework: "sveltekit", configPath: p(n, u.vite), pluginsAt: "top" } : o("vite") ? { framework: "vite", configPath: p(n, u.vite), pluginsAt: "top" } : { framework: "unknown", configPath: null, pluginsAt: "top" };
26
27
  }
27
- function S(o) {
28
- let e = k(o, "utf-8");
28
+ function x(n) {
29
+ let e = h(n, "utf-8");
29
30
  if (/from\s*["']okno\/vite["']/.test(e)) return !0;
30
31
  const t = e.match(/\bplugins\s*:\s*\[/);
31
32
  if (!t || t.index === void 0) return !1;
32
- const n = t.index + t[0].length, i = e.slice(n);
33
- let c;
34
- const s = i.match(/^[^\S\n]*\n(\s*)/);
35
- s ? c = `
36
- ${s[1]}okno(),` : i.trimStart().startsWith("]") ? c = "okno()" : c = "okno(), ", e = e.slice(0, n) + c + e.slice(n);
37
- const a = 'import { okno } from "okno/vite"', f = [...e.matchAll(/^import .*$/gm)];
38
- if (f.length) {
39
- const p = f[f.length - 1], d = p.index + p[0].length;
40
- e = e.slice(0, d) + `
41
- ` + a + e.slice(d);
33
+ const o = t.index + t[0].length, i = e.slice(o);
34
+ let m;
35
+ const a = i.match(/^[^\S\n]*\n(\s*)/);
36
+ a ? m = `
37
+ ${a[1]}okno(),` : i.trimStart().startsWith("]") ? m = "okno()" : m = "okno(), ", e = e.slice(0, o) + m + e.slice(o);
38
+ const d = 'import { okno } from "okno/vite"', r = [...e.matchAll(/^import .*$/gm)];
39
+ if (r.length) {
40
+ const c = r[r.length - 1], k = c.index + c[0].length;
41
+ e = e.slice(0, k) + `
42
+ ` + d + e.slice(k);
42
43
  } else
43
- e = a + `
44
+ e = d + `
44
45
  ` + e;
45
- return m(o, e), !0;
46
+ return l(n, e), !0;
46
47
  }
47
- function x(o) {
48
- const e = r(o, "okno"), t = r(e, "schema.ts");
49
- return g(t) ? !1 : (v(r(e, "pages"), { recursive: !0 }), m(
50
- t,
51
- `import type { Schema } from "okno"
48
+ function A(n, e = "starter") {
49
+ const t = s(n, "okno"), o = s(t, "schema.ts");
50
+ return f(o) ? !1 : (g(s(t, "pages"), { recursive: !0 }), e === "empty" ? (l(o, C), l(s(t, "pages", "home.ts"), j), !0) : (g(s(t, "globals"), { recursive: !0 }), l(o, E), l(s(t, "pages", "home.ts"), T), l(s(t, "globals", "meta.ts"), w), l(s(t, "globals", "navbar.ts"), M), l(s(t, "globals", "footer.ts"), P), !0));
51
+ }
52
+ const C = `import type { Schema } from "okno"
52
53
 
53
54
  export default {
54
55
  pages: {
@@ -57,35 +58,111 @@ export default {
57
58
  fields: {
58
59
  title: { type: "string" },
59
60
  },
61
+ url: "/",
60
62
  },
61
63
  },
62
64
  } satisfies Schema
63
- `
64
- ), m(
65
- r(e, "pages", "home.ts"),
66
- `export default {
65
+ `, j = `export default {
67
66
  title: "Hello from okno",
68
67
  }
69
- `
70
- ), !0);
68
+ `, E = `import type { Schema } from "okno"
69
+
70
+ export default {
71
+ pages: {
72
+ home: {
73
+ name: "Home",
74
+ fields: {
75
+ headline: { type: "string" },
76
+ subhead: { type: "string" },
77
+ body: { type: "richtext" },
78
+ image: { type: "media", accept: ["image"] },
79
+ },
80
+ url: "/",
81
+ },
82
+ },
83
+ globals: {
84
+ meta: {
85
+ name: "Meta",
86
+ fields: {
87
+ title: { type: "string" },
88
+ description: { type: "string" },
89
+ shareImage: { type: "media", accept: ["image"], label: "Share image" },
90
+ favicon: { type: "media", accept: ["image"] },
91
+ },
92
+ },
93
+ navbar: {
94
+ name: "Navbar",
95
+ fields: {
96
+ logo: { type: "string" },
97
+ links: { type: "block", block: "navlink", multiple: true },
98
+ cta: { type: "link", label: "Call to action" },
99
+ },
100
+ },
101
+ footer: {
102
+ name: "Footer",
103
+ fields: {
104
+ text: { type: "string" },
105
+ links: { type: "block", block: "navlink", multiple: true },
106
+ },
107
+ },
108
+ },
109
+ blocks: {
110
+ navlink: {
111
+ name: "Nav link",
112
+ fields: {
113
+ link: { type: "link" },
114
+ },
115
+ },
116
+ },
117
+ } satisfies Schema
118
+ `, T = `export default {
119
+ headline: "Hello from okno",
120
+ subhead: "Edit this on the page — press “e” or visit ?okno.",
121
+ body: "<p>This is your home page. Everything here is content in your repo.</p>",
122
+ image: null,
123
+ }
124
+ `, w = `export default {
125
+ title: "My okno site",
126
+ description: "Built with okno — a Git-backed CMS with live editing.",
127
+ shareImage: null,
128
+ favicon: null,
129
+ }
130
+ `, M = `export default {
131
+ logo: "okno",
132
+ links: [
133
+ { link: { text: "Home", url: "/", external: false } },
134
+ { link: { text: "About", url: "/about", external: false } },
135
+ ],
136
+ cta: { text: "Get started", url: "/", external: false },
137
+ }
138
+ `, P = `export default {
139
+ text: "© My okno site",
140
+ links: [{ link: { text: "Home", url: "/", external: false } }],
141
+ }
142
+ `;
143
+ function R(n) {
144
+ const e = v(S(import.meta.url)), t = s(e, "..", "skills", "connect-okno", "SKILL.md");
145
+ if (!f(t)) return null;
146
+ const o = s(".claude", "skills", "connect-okno", "SKILL.md"), i = s(n, o);
147
+ return f(i) ? null : (g(v(i), { recursive: !0 }), l(i, h(t, "utf-8")), o);
71
148
  }
72
- function j(o, e) {
73
- const t = e === "claude" ? ".mcp.json" : r(".cursor", "mcp.json"), n = r(o, t);
149
+ function H(n, e) {
150
+ const t = e === "claude" ? ".mcp.json" : s(".cursor", "mcp.json"), o = s(n, t);
74
151
  let i = { mcpServers: {} };
75
- if (g(n))
152
+ if (f(o))
76
153
  try {
77
- i = JSON.parse(k(n, "utf-8"));
154
+ i = JSON.parse(h(o, "utf-8"));
78
155
  } catch {
79
156
  }
80
- return i.mcpServers ??= {}, i.mcpServers.okno = { command: "npx", args: ["okno", "mcp"] }, v(r(n, ".."), { recursive: !0 }), m(n, JSON.stringify(i, null, 2) + `
157
+ return i.mcpServers ??= {}, i.mcpServers.okno = { command: "npx", args: ["okno", "mcp"] }, g(s(o, ".."), { recursive: !0 }), l(o, JSON.stringify(i, null, 2) + `
81
158
  `), t;
82
159
  }
83
- async function A() {
84
- const o = process.cwd(), e = await import("@clack/prompts");
160
+ async function _() {
161
+ const n = process.cwd(), e = await import("@clack/prompts");
85
162
  e.intro("okno init");
86
- let t = h(o);
163
+ let t = b(n);
87
164
  if (t.framework === "unknown") {
88
- const s = await e.select({
165
+ const r = await e.select({
89
166
  message: "Which framework is this project?",
90
167
  options: [
91
168
  { value: "astro", label: "Astro" },
@@ -94,11 +171,11 @@ async function A() {
94
171
  { value: "nuxt", label: "Nuxt" }
95
172
  ]
96
173
  });
97
- if (e.isCancel(s)) return e.cancel("Cancelled.");
98
- const a = s, f = a === "astro" || a === "nuxt" ? "vite" : "top", p = l[a] ?? l.vite;
99
- t = { framework: a, configPath: u(o, p), pluginsAt: f };
174
+ if (e.isCancel(r)) return e.cancel("Cancelled.");
175
+ const c = r, k = c === "astro" || c === "nuxt" ? "vite" : "top", y = u[c] ?? u.vite;
176
+ t = { framework: c, configPath: p(n, y), pluginsAt: k };
100
177
  }
101
- const n = await e.select({
178
+ const o = await e.select({
102
179
  message: "Set up the okno MCP server for your AI editor?",
103
180
  options: [
104
181
  { value: "claude", label: "Claude Code (.mcp.json)" },
@@ -107,31 +184,51 @@ async function A() {
107
184
  ],
108
185
  initialValue: "claude"
109
186
  });
110
- if (e.isCancel(n)) return e.cancel("Cancelled.");
111
- const i = [];
112
- let c = !1;
113
- if (t.configPath && (c = S(t.configPath)), c)
114
- i.push(`✓ Added okno() to ${t.configPath.replace(o + "/", "")}`);
187
+ if (e.isCancel(o)) return e.cancel("Cancelled.");
188
+ let i = "starter";
189
+ if (!f(s(n, "okno", "schema.ts"))) {
190
+ const r = await e.select({
191
+ message: "Scaffold a Starter, or an empty schema?",
192
+ options: [
193
+ { value: "starter", label: "Starter — Home + Meta/Navbar/Footer globals, ready to edit" },
194
+ { value: "empty", label: "Empty — just a Home page, model it yourself" }
195
+ ],
196
+ initialValue: "starter"
197
+ });
198
+ if (e.isCancel(r)) return e.cancel("Cancelled.");
199
+ i = r;
200
+ }
201
+ const a = [];
202
+ let d = !1;
203
+ if (t.configPath && (d = x(t.configPath)), d)
204
+ a.push(`✓ Added okno() to ${t.configPath.replace(n + "/", "")}`);
115
205
  else {
116
- const s = t.pluginsAt === "vite" ? `import { okno } from "okno/vite"
206
+ const r = t.pluginsAt === "vite" ? `import { okno } from "okno/vite"
117
207
  // inside defineConfig:
118
208
  // vite: { plugins: [okno()] }` : `import { okno } from "okno/vite"
119
209
  // inside defineConfig:
120
210
  // plugins: [okno()]`;
121
- i.push(`! Couldn't edit your config automatically — add okno() yourself:
122
- ${s}`);
211
+ a.push(`! Couldn't edit your config automatically — add okno() yourself:
212
+ ${r}`);
213
+ }
214
+ if (A(n, i) ? a.push(
215
+ i === "starter" ? "✓ Scaffolded the okno Starter (Home + Meta/Navbar/Footer globals)" : "✓ Scaffolded an empty okno/ (Home page only)"
216
+ ) : a.push("• okno/ already exists — left it alone"), o !== "skip") {
217
+ const r = H(n, o);
218
+ a.push(`✓ Registered the okno MCP server in ${r}`);
123
219
  }
124
- if (x(o) ? i.push("✓ Scaffolded okno/schema.ts + okno/pages/home.ts") : i.push("• okno/ already exists — left it alone"), n !== "skip") {
125
- const s = j(o, n);
126
- i.push(`✓ Registered the okno MCP server in ${s}`);
220
+ if (o === "claude") {
221
+ const r = R(n);
222
+ r && a.push(`✓ Installed the connect-okno skill in ${r}`);
127
223
  }
128
- e.note(i.join(`
224
+ e.note(a.join(`
129
225
  `), "Done"), e.outro("Run your dev server and press “e” (or visit ?okno) to open the editor.");
130
226
  }
131
227
  export {
132
- S as addPlugin,
133
- h as detect,
134
- A as runInit,
135
- x as scaffold,
136
- j as writeMcpConfig
228
+ x as addPlugin,
229
+ b as detect,
230
+ _ as runInit,
231
+ A as scaffold,
232
+ H as writeMcpConfig,
233
+ R as writeSkill
137
234
  };
package/dist/mcp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAwCA;kCACkC;AAClC,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAuJ5C"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAwCA;kCACkC;AAClC,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAmK5C"}
package/dist/mcp.js CHANGED
@@ -1,54 +1,59 @@
1
- import { existsSync as l, readdirSync as j, readFileSync as k, mkdirSync as D, writeFileSync as S, unlinkSync as N, realpathSync as T } from "node:fs";
2
- import { join as i, dirname as O, relative as C, sep as E, resolve as $ } from "node:path";
1
+ import { existsSync as l, readdirSync as j, readFileSync as y, mkdirSync as D, writeFileSync as S, unlinkSync as C, realpathSync as N } from "node:fs";
2
+ import { join as i, dirname as O, relative as L, sep as E, resolve as T } from "node:path";
3
3
  import { execFileSync as F } from "node:child_process";
4
- import { p as b, e as R, a as I } from "./content-encode-DoojdsVU.js";
5
- function M() {
4
+ import { p as b, e as M, a as $ } from "./content-encode-DoojdsVU.js";
5
+ function I() {
6
6
  const f = process.env.OKNO_DIR;
7
7
  if (f) {
8
- const o = $(process.cwd(), f);
8
+ const o = T(process.cwd(), f);
9
9
  return l(i(o, "schema.ts")) ? o : l(i(o, "okno", "schema.ts")) ? i(o, "okno") : o;
10
10
  }
11
11
  let h = process.cwd();
12
12
  for (let o = 0; o < 25; o++) {
13
13
  if (l(i(h, "okno", "schema.ts"))) return i(h, "okno");
14
- const r = O(h);
15
- if (r === h) break;
16
- h = r;
14
+ const s = O(h);
15
+ if (s === h) break;
16
+ h = s;
17
17
  }
18
18
  console.error("okno mcp: could not find an okno/ directory. Set OKNO_DIR to your project's okno/ path."), process.exit(1);
19
19
  }
20
- async function W() {
21
- const { McpServer: f } = await import("@modelcontextprotocol/sdk/server/mcp.js"), { StdioServerTransport: h } = await import("@modelcontextprotocol/sdk/server/stdio.js"), { z: o } = await import("zod"), r = M();
20
+ async function A() {
21
+ const { McpServer: f } = await import("@modelcontextprotocol/sdk/server/mcp.js"), { StdioServerTransport: h } = await import("@modelcontextprotocol/sdk/server/stdio.js"), { z: o } = await import("zod"), s = I();
22
22
  function g(e) {
23
23
  if (!e || e.includes("..") || e.includes("\0") || e.startsWith("/")) throw new Error(`Invalid path: ${e}`);
24
24
  if (!e.endsWith(".ts")) throw new Error(`Path must be a .ts file: ${e}`);
25
- const t = i(r, e);
26
- if (t !== r && !t.startsWith(r + E)) throw new Error(`Path escapes okno dir: ${e}`);
25
+ const t = i(s, e);
26
+ if (t !== s && !t.startsWith(s + E)) throw new Error(`Path escapes okno dir: ${e}`);
27
27
  return t;
28
28
  }
29
- const m = (e, t = r) => F("git", e, { cwd: t, encoding: "utf-8" }).trim();
30
- let p;
31
- const x = () => {
32
- if (p !== void 0) return p;
29
+ const m = (e, t = s) => F("git", e, { cwd: t, encoding: "utf-8" }).trim();
30
+ let u;
31
+ const _ = () => {
32
+ if (u !== void 0) return u;
33
33
  try {
34
- p = m(["config", "user.name"]) || "local";
34
+ u = m(["config", "user.name"]) || "local";
35
35
  } catch {
36
- p = "local";
36
+ u = "local";
37
37
  }
38
- return p;
38
+ return u;
39
39
  };
40
40
  function w() {
41
- const e = i(r, "schema.ts");
41
+ const e = i(s, "schema.ts");
42
42
  let t = `import type { Schema } from "okno"
43
43
 
44
- `, s = {};
44
+ `, r = {};
45
45
  if (l(e)) {
46
- const n = k(e, "utf-8"), d = n.indexOf("export default");
47
- d > 0 && (t = n.slice(0, d)), s = b(n) ?? {};
46
+ const n = y(e, "utf-8"), d = n.indexOf("export default");
47
+ d > 0 && (t = n.slice(0, d)), r = b(n) ?? {};
48
48
  }
49
- return { schema: s, header: t };
49
+ return { schema: r, header: t };
50
50
  }
51
- const c = (e) => ({ content: [{ type: "text", text: JSON.stringify(e, null, 2) }] }), a = new f({ name: "okno", version: "0.2.0" });
51
+ const c = (e) => ({ content: [{ type: "text", text: JSON.stringify(e, null, 2) }] }), a = new f(
52
+ { name: "okno", version: "0.2.0" },
53
+ {
54
+ instructions: "Okno is a Git-backed CMS: content is .ts files in the project's repo. Call get_schema first to learn the content model (pages, collections, globals, blocks). write_schema replaces the WHOLE schema — read it, merge, write it all back. Writes are drafts on the working branch; a human publishes — you cannot. For how to MODEL content (when to use a collection + reference vs a block vs a global, the spread-to-edit rendering pattern), use the `connect-okno` skill — it's installed at .claude/skills/connect-okno/SKILL.md (run `okno init` if missing)."
55
+ }
56
+ );
52
57
  a.tool(
53
58
  "get_schema",
54
59
  "Get the Okno project's schema — pages, collections (with field definitions), globals, blocks, locales. Call this first to learn the content model before reading or writing.",
@@ -59,10 +64,10 @@ async function W() {
59
64
  "List the entries in a collection. Returns each entry's slug and file path (relative to the okno dir).",
60
65
  { collection: o.string().describe("Collection slug, e.g. 'articles'") },
61
66
  async ({ collection: e }) => {
62
- const t = i(r, "collections", e);
67
+ const t = i(s, "collections", e);
63
68
  if (!l(t)) return c([]);
64
- const s = j(t, { withFileTypes: !0 }).filter((n) => n.isFile() && n.name.endsWith(".ts") && n.name !== "index.ts").map((n) => ({ slug: n.name.slice(0, -3), path: `collections/${e}/${n.name}` }));
65
- return c(s);
69
+ const r = j(t, { withFileTypes: !0 }).filter((n) => n.isFile() && n.name.endsWith(".ts") && n.name !== "index.ts").map((n) => ({ slug: n.name.slice(0, -3), path: `collections/${e}/${n.name}` }));
70
+ return c(r);
66
71
  }
67
72
  ), a.tool(
68
73
  "read_entry",
@@ -71,7 +76,7 @@ async function W() {
71
76
  async ({ path: e }) => {
72
77
  const t = g(e);
73
78
  if (!l(t)) throw new Error(`Not found: ${e}`);
74
- return c(b(k(t, "utf-8")));
79
+ return c(b(y(t, "utf-8")));
75
80
  }
76
81
  ), a.tool(
77
82
  "write_entry",
@@ -81,14 +86,14 @@ async function W() {
81
86
  content: o.record(o.unknown()).describe("Entry fields as an object, matching the schema")
82
87
  },
83
88
  async ({ path: e, content: t }) => {
84
- const s = g(e);
89
+ const r = g(e);
85
90
  let n;
86
- if (l(s)) {
87
- const u = b(k(s, "utf-8"));
88
- u.created?.date && (n = u.created);
91
+ if (l(r)) {
92
+ const p = b(y(r, "utf-8"));
93
+ p.created?.date && (n = p.created);
89
94
  }
90
- const d = R(t, { now: (/* @__PURE__ */ new Date()).toISOString(), author: x(), created: n });
91
- return D(O(s), { recursive: !0 }), S(s, d), c({ ok: !0, path: e });
95
+ const d = M(t, { now: (/* @__PURE__ */ new Date()).toISOString(), author: _(), created: n });
96
+ return D(O(r), { recursive: !0 }), S(r, d), c({ ok: !0, path: e });
92
97
  }
93
98
  ), a.tool(
94
99
  "delete_entry",
@@ -96,7 +101,7 @@ async function W() {
96
101
  { path: o.string().describe("Entry path relative to the okno dir") },
97
102
  async ({ path: e }) => {
98
103
  const t = g(e);
99
- return l(t) && N(t), c({ ok: !0, path: e });
104
+ return l(t) && C(t), c({ ok: !0, path: e });
100
105
  }
101
106
  ), a.tool(
102
107
  "write_schema",
@@ -104,32 +109,32 @@ async function W() {
104
109
  { schema: o.record(o.unknown()).describe("The complete schema object: { pages?, collections?, globals?, blocks?, locales? }") },
105
110
  async ({ schema: e }) => {
106
111
  const { header: t } = w();
107
- return S(i(r, "schema.ts"), I(e, t)), c({ ok: !0 });
112
+ return S(i(s, "schema.ts"), $(e, t)), c({ ok: !0 });
108
113
  }
109
114
  ), a.tool(
110
115
  "publish",
111
116
  "Commit and push the okno content changes. Stages ONLY the okno/ paths (never the project's code), commits, and pushes the current branch. No-op if there's nothing to commit.",
112
117
  { message: o.string().optional().describe("Optional commit message (default: 'okno: content')") },
113
118
  async ({ message: e }) => {
114
- const t = m(["rev-parse", "--show-toplevel"]), s = C(t, T(r)).split(E).join("/");
115
- m(["add", "-A", "--", s], t);
119
+ const t = m(["rev-parse", "--show-toplevel"]), r = L(t, N(s)).split(E).join("/");
120
+ m(["add", "-A", "--", r], t);
116
121
  const n = m(["diff", "--cached", "--name-only"], t);
117
122
  let d = !1;
118
123
  n && (m(["commit", "-m", e?.trim() || "okno: content"], t), d = !0);
119
- let u = !1, v = null;
124
+ let p = !1, v = null;
120
125
  try {
121
- m(["push"], t), u = !0;
122
- } catch (y) {
123
- v = y instanceof Error ? y.message.split(`
124
- `)[0] : String(y);
126
+ m(["push"], t), p = !0;
127
+ } catch (k) {
128
+ v = k instanceof Error ? k.message.split(`
129
+ `)[0] : String(k);
125
130
  }
126
- return c({ ok: !0, committed: d, pushed: u, pushError: v, files: n ? n.split(`
131
+ return c({ ok: !0, committed: d, pushed: p, pushError: v, files: n ? n.split(`
127
132
  `) : [] });
128
133
  }
129
134
  );
130
- const _ = new h();
131
- await a.connect(_), console.error(`okno mcp connected → ${r} (local filesystem)`);
135
+ const x = new h();
136
+ await a.connect(x), console.error(`okno mcp connected → ${s} (local filesystem)`);
132
137
  }
133
138
  export {
134
- W as runMcp
139
+ A as runMcp
135
140
  };