@markbrutx/promptbook-viewer 0.1.0 → 0.3.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.
Files changed (42) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/server/api.d.ts +4 -5
  4. package/dist/server/api.d.ts.map +1 -1
  5. package/dist/server/api.js +49 -12
  6. package/dist/server/api.js.map +1 -1
  7. package/dist/server/book-source.d.ts +24 -0
  8. package/dist/server/book-source.d.ts.map +1 -1
  9. package/dist/server/book-source.js +39 -0
  10. package/dist/server/book-source.js.map +1 -1
  11. package/dist/server/server.d.ts +1 -1
  12. package/dist/server/server.d.ts.map +1 -1
  13. package/dist/server/server.js +21 -8
  14. package/dist/server/server.js.map +1 -1
  15. package/dist/server/workspace.d.ts +13 -0
  16. package/dist/server/workspace.d.ts.map +1 -0
  17. package/dist/server/workspace.js +55 -0
  18. package/dist/server/workspace.js.map +1 -0
  19. package/dist/shared/types.d.ts +9 -0
  20. package/dist/shared/types.d.ts.map +1 -1
  21. package/dist/web/assets/index-BCBuW76o.css +1 -0
  22. package/dist/web/assets/index-BwIAKPNq.js +51 -0
  23. package/dist/web/favicon.png +0 -0
  24. package/dist/web/index.html +3 -2
  25. package/dist/web/promptbook-logo.png +0 -0
  26. package/package.json +19 -2
  27. package/src/index.ts +2 -0
  28. package/src/server/api.ts +57 -18
  29. package/src/server/book-source.ts +67 -0
  30. package/src/server/server.ts +22 -9
  31. package/src/server/workspace.ts +64 -0
  32. package/src/shared/types.ts +11 -0
  33. package/src/web/App.tsx +91 -28
  34. package/src/web/api.ts +26 -10
  35. package/src/web/components/Sidebar.tsx +37 -0
  36. package/src/web/index.html +1 -0
  37. package/src/web/public/favicon.png +0 -0
  38. package/src/web/public/promptbook-logo.png +0 -0
  39. package/src/web/styles.css +35 -0
  40. package/src/web/types.ts +2 -0
  41. package/dist/web/assets/index-B2Wxtb-f.css +0 -1
  42. package/dist/web/assets/index-C8f_6lr_.js +0 -51
package/dist/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export type { AnnotateInput, AnnotationStore } from "./server/annotations.js";
2
2
  export { createAnnotationStore } from "./server/annotations.js";
3
3
  export type { Viewer, ViewerOptions } from "./server/server.js";
4
4
  export { startViewer } from "./server/server.js";
5
- export type { AnnotateRequest, Annotation, AnnotationsResponse, BookResponse, CompositionSummary, FragmentSummary, LintResponse, ResolveResponse, RuleSummary, Segment, UsedInReference, UsedInResponse, VariantSummary, } from "./shared/types.js";
5
+ export type { AnnotateRequest, Annotation, AnnotationsResponse, BookResponse, BooksResponse, CompositionSummary, FragmentSummary, LintResponse, ResolveResponse, RuleSummary, Segment, UsedInReference, UsedInResponse, VariantSummary, WorkspaceBook, } from "./shared/types.js";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EACV,eAAe,EACf,UAAU,EACV,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,eAAe,EACf,WAAW,EACX,OAAO,EACP,eAAe,EACf,cAAc,EACd,cAAc,GACf,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EACV,eAAe,EACf,UAAU,EACV,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,eAAe,EACf,WAAW,EACX,OAAO,EACP,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC"}
@@ -1,16 +1,15 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
- import type { BookSource } from "./book-source.js";
2
+ import type { WorkspaceSource } from "./book-source.js";
3
3
  export interface RequestHandlerOptions {
4
- source: BookSource;
5
- promptsDir: string;
4
+ workspace: WorkspaceSource;
6
5
  /** Directory of the built web bundle (dist/web). */
7
6
  webRoot: string;
8
7
  }
9
8
  /** A request handler plus the hook the folder watcher uses to push reloads. */
10
9
  export interface RequestHandler {
11
10
  handle(req: IncomingMessage, res: ServerResponse): void;
12
- /** Invalidate the cached book and notify connected clients to refetch. */
13
- notifyReload(): void;
11
+ /** Invalidate a changed book (or all) and notify clients to refetch. */
12
+ notifyReload(book?: string): void;
14
13
  }
15
14
  export declare function createRequestHandler(options: RequestHandlerOptions): RequestHandler;
16
15
  //# sourceMappingURL=api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/server/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASnD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IACxD,0EAA0E;IAC1E,YAAY,IAAI,IAAI,CAAC;CACtB;AAyDD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CAiFnF"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/server/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,OAAO,KAAK,EAAgB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAStE,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,eAAe,CAAC;IAC3B,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IACxD,wEAAwE;IACxE,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AA2DD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CAuHnF"}
@@ -52,46 +52,82 @@ function asAnnotateRequest(body) {
52
52
  }
53
53
  return input;
54
54
  }
55
+ const EMPTY_BOOK = { compositions: [], codePrompts: [], fragments: [], warnings: [] };
55
56
  export function createRequestHandler(options) {
56
- const { source, promptsDir, webRoot } = options;
57
+ const { workspace, webRoot } = options;
57
58
  const sseClients = new Set();
58
- const annotations = createAnnotationStore(promptsDir);
59
+ const annotationStores = new Map();
60
+ /** Per-book annotation queue, keyed by directory; bookless roots write at root. */
61
+ const annotationsFor = async (bookName) => {
62
+ const resolved = await workspace.resolve(bookName);
63
+ const dir = resolved?.book.dir ?? workspace.root;
64
+ let store = annotationStores.get(dir);
65
+ if (store === undefined) {
66
+ store = createAnnotationStore(dir);
67
+ annotationStores.set(dir, store);
68
+ }
69
+ return store;
70
+ };
71
+ /** Resolve the active book or throw a 400-worthy error when the workspace is empty. */
72
+ const requireBook = async (bookName) => {
73
+ const resolved = await workspace.resolve(bookName);
74
+ if (resolved === undefined) {
75
+ throw new Error("no book found in the workspace");
76
+ }
77
+ return resolved;
78
+ };
59
79
  const handle = async (req, res) => {
60
80
  const url = new URL(req.url ?? "/", "http://localhost");
61
81
  const path = url.pathname;
62
82
  const method = req.method ?? "GET";
83
+ const bookName = url.searchParams.get("book") ?? undefined;
63
84
  try {
85
+ if (path === "/api/books" && method === "GET") {
86
+ sendJson(res, 200, { books: await workspace.books() });
87
+ return;
88
+ }
64
89
  if (path === "/api/book" && method === "GET") {
65
- sendJson(res, 200, buildBookResponse(await source.get(), promptsDir));
90
+ const resolved = await workspace.resolve(bookName);
91
+ if (resolved === undefined) {
92
+ sendJson(res, 200, EMPTY_BOOK);
93
+ return;
94
+ }
95
+ sendJson(res, 200, buildBookResponse(resolved.folder, resolved.book.dir));
66
96
  return;
67
97
  }
68
98
  if (path === "/api/resolve" && method === "POST") {
69
99
  const { prompt, context } = asResolveRequest(await readJsonBody(req));
70
- sendJson(res, 200, buildResolveResponse(await source.get(), prompt, context));
100
+ const { folder } = await requireBook(bookName);
101
+ sendJson(res, 200, buildResolveResponse(folder, prompt, context));
71
102
  return;
72
103
  }
73
104
  if (path === "/api/lint" && method === "POST") {
74
105
  const { prompt, context } = asResolveRequest(await readJsonBody(req));
75
- sendJson(res, 200, buildLintResponse(await source.get(), prompt, context));
106
+ const { folder } = await requireBook(bookName);
107
+ sendJson(res, 200, buildLintResponse(folder, prompt, context));
76
108
  return;
77
109
  }
78
110
  if (path.startsWith("/api/used-in/") && method === "GET") {
79
111
  const id = decodeURIComponent(path.slice("/api/used-in/".length));
80
- sendJson(res, 200, buildUsedInResponse(await source.get(), id));
112
+ const { folder } = await requireBook(bookName);
113
+ sendJson(res, 200, buildUsedInResponse(folder, id));
81
114
  return;
82
115
  }
83
116
  if (path === "/api/annotate" && method === "POST") {
84
- const annotation = await annotations.append(asAnnotateRequest(await readJsonBody(req)));
117
+ const store = await annotationsFor(bookName);
118
+ const annotation = await store.append(asAnnotateRequest(await readJsonBody(req)));
85
119
  sendJson(res, 200, annotation);
86
120
  return;
87
121
  }
88
122
  if (path === "/api/annotations" && method === "GET") {
89
- sendJson(res, 200, { annotations: await annotations.list() });
123
+ const store = await annotationsFor(bookName);
124
+ sendJson(res, 200, { annotations: await store.list() });
90
125
  return;
91
126
  }
92
127
  if (path.startsWith("/api/annotations/") && method === "DELETE") {
93
128
  const id = decodeURIComponent(path.slice("/api/annotations/".length));
94
- const removed = await annotations.remove(id);
129
+ const store = await annotationsFor(bookName);
130
+ const removed = await store.remove(id);
95
131
  sendJson(res, removed ? 200 : 404, { id, removed });
96
132
  return;
97
133
  }
@@ -123,10 +159,11 @@ export function createRequestHandler(options) {
123
159
  handle(req, res) {
124
160
  void handle(req, res);
125
161
  },
126
- notifyReload() {
127
- source.invalidate();
162
+ notifyReload(book) {
163
+ workspace.invalidate(book);
164
+ const data = book !== undefined ? JSON.stringify({ book }) : "{}";
128
165
  for (const client of sseClients) {
129
- client.write("event: reload\ndata: {}\n\n");
166
+ client.write(`event: reload\ndata: ${data}\n\n`);
130
167
  }
131
168
  },
132
169
  };
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/server/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/server/api.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Fixture, FsAdapter, PromptBook } from "@markbrutx/promptbook-core";
2
+ import { type Book } from "./workspace.js";
2
3
  /** A loaded prompts folder plus the fixtures that supply named variants. */
3
4
  export interface LoadedFolder {
4
5
  book: PromptBook;
@@ -17,4 +18,27 @@ export interface BookSource {
17
18
  invalidate(): void;
18
19
  }
19
20
  export declare function createBookSource(promptsDir: string, fs?: FsAdapter): BookSource;
21
+ /** A book resolved for a request: its identity plus its loaded folder. */
22
+ export interface ResolvedBook {
23
+ book: Book;
24
+ folder: LoadedFolder;
25
+ }
26
+ /**
27
+ * Caches a {@link BookSource} per book across a whole workspace, discovering the
28
+ * books under the root lazily. One viewer serves every book through a single
29
+ * switcher: `books()` lists them, `resolve(name)` loads one (defaulting to the
30
+ * first), and `invalidate(name)` drops one book's cache while always re-scanning
31
+ * the book set (so a new folder appears without a restart).
32
+ */
33
+ export interface WorkspaceSource {
34
+ /** Root the workspace was discovered from (annotation fallback when bookless). */
35
+ root: string;
36
+ /** Discovered books (name + dir), re-scanned after {@link invalidate}. */
37
+ books(): Promise<Book[]>;
38
+ /** Load a book by name, or the first book when the name is missing/unknown. */
39
+ resolve(name?: string): Promise<ResolvedBook | undefined>;
40
+ /** Drop one book's cache (or none) and re-scan the book set. */
41
+ invalidate(name?: string): void;
42
+ }
43
+ export declare function createWorkspaceSource(root: string, fs?: FsAdapter): WorkspaceSource;
20
44
  //# sourceMappingURL=book-source.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"book-source.d.ts","sourceRoot":"","sources":["../../src/server/book-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAGjF,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7B,oEAAoE;IACpE,UAAU,IAAI,IAAI,CAAC;CACpB;AAWD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,SAAS,GAAG,UAAU,CAsB/E"}
1
+ {"version":3,"file":"book-source.d.ts","sourceRoot":"","sources":["../../src/server/book-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAEjF,OAAO,EAAE,KAAK,IAAI,EAAsB,MAAM,gBAAgB,CAAC;AAE/D,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7B,oEAAoE;IACpE,UAAU,IAAI,IAAI,CAAC;CACpB;AAWD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,SAAS,GAAG,UAAU,CAsB/E;AAED,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACzB,+EAA+E;IAC/E,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IAC1D,gEAAgE;IAChE,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,SAAS,GAAG,eAAe,CAwCnF"}
@@ -1,4 +1,5 @@
1
1
  import { loadFixtures, loadPrompts } from "@markbrutx/promptbook-core";
2
+ import { loadWorkspaceBooks } from "./workspace.js";
2
3
  /** Fixtures are optional: a folder without a `fixtures/` dir simply has none. */
3
4
  async function safeLoadFixtures(promptsDir, fs) {
4
5
  try {
@@ -29,4 +30,42 @@ export function createBookSource(promptsDir, fs) {
29
30
  },
30
31
  };
31
32
  }
33
+ export function createWorkspaceSource(root, fs) {
34
+ let bookList;
35
+ const sources = new Map();
36
+ const discover = () => {
37
+ if (bookList === undefined) {
38
+ bookList = loadWorkspaceBooks(root, fs);
39
+ }
40
+ return bookList;
41
+ };
42
+ const sourceFor = (book) => {
43
+ let source = sources.get(book.name);
44
+ if (source === undefined) {
45
+ source = createBookSource(book.dir, fs);
46
+ sources.set(book.name, source);
47
+ }
48
+ return source;
49
+ };
50
+ return {
51
+ root,
52
+ books() {
53
+ return discover();
54
+ },
55
+ async resolve(name) {
56
+ const books = await discover();
57
+ if (books.length === 0) {
58
+ return undefined;
59
+ }
60
+ const book = books.find((b) => b.name === name) ?? books[0];
61
+ return { book, folder: await sourceFor(book).get() };
62
+ },
63
+ invalidate(name) {
64
+ bookList = undefined;
65
+ if (name !== undefined) {
66
+ sources.get(name)?.invalidate();
67
+ }
68
+ },
69
+ };
70
+ }
32
71
  //# sourceMappingURL=book-source.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"book-source.js","sourceRoot":"","sources":["../../src/server/book-source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAqBvE,iFAAiF;AACjF,KAAK,UAAU,gBAAgB,CAAC,UAAkB,EAAE,EAAc;IAChE,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,EAAc;IACjE,IAAI,MAAyC,CAAC;IAE9C,MAAM,IAAI,GAAG,KAAK,IAA2B,EAAE;QAC7C,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACzC,WAAW,CAAC,UAAU,EAAE,EAAE,CAAC;YAC3B,gBAAgB,CAAC,UAAU,EAAE,EAAE,CAAC;SACjC,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC;IAEF,OAAO;QACL,GAAG;YACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM,GAAG,IAAI,EAAE,CAAC;YAClB,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,UAAU;YACR,MAAM,GAAG,SAAS,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"book-source.js","sourceRoot":"","sources":["../../src/server/book-source.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { FsAdapter } from "@markbrutx/promptbook-core";
2
2
  export interface ViewerOptions {
3
- /** Folder containing `fragments/`, `rules/` and optional `fixtures/`. */
3
+ /** Workspace root (a single book, or a folder of sibling books). */
4
4
  promptsDir: string;
5
5
  /** Port to listen on; 0 (default) picks a free port. */
6
6
  port?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAI5D,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6EAA6E;IAC7E,EAAE,CAAC,EAAE,SAAS,CAAC;CAChB;AAED,sEAAsE;AACtE,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAoCD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BzE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAI5D,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6EAA6E;IAC7E,EAAE,CAAC,EAAE,SAAS,CAAC;CAChB;AAED,sEAAsE;AACtE,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAgDD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BzE"}
@@ -1,9 +1,10 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { watch } from "node:fs";
3
3
  import { createServer } from "node:http";
4
+ import { sep } from "node:path";
4
5
  import { fileURLToPath } from "node:url";
5
6
  import { createRequestHandler } from "./api.js";
6
- import { createBookSource } from "./book-source.js";
7
+ import { createWorkspaceSource } from "./book-source.js";
7
8
  /** Best-effort: open `url` in the OS default browser; never throws. */
8
9
  function openBrowser(url) {
9
10
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -20,15 +21,27 @@ function openBrowser(url) {
20
21
  // opening a browser is a convenience, not a requirement
21
22
  }
22
23
  }
23
- /** Watch the prompts folder and call `onChange` (debounced) on any edit. */
24
- function watchFolder(promptsDir, onChange) {
24
+ /**
25
+ * Watch the workspace root and call `onChange` (debounced) with the changed
26
+ * book. A change path's first segment names its top-level book; when several
27
+ * books or unknown paths change in one window, `undefined` is passed so the
28
+ * client refetches the active book regardless.
29
+ */
30
+ function watchFolder(rootDir, onChange) {
25
31
  try {
26
32
  let timer;
27
- const watcher = watch(promptsDir, { recursive: true }, () => {
33
+ let changed = new Set();
34
+ const watcher = watch(rootDir, { recursive: true }, (_event, filename) => {
35
+ const name = typeof filename === "string" && filename.length > 0 ? filename : undefined;
36
+ changed.add(name === undefined ? undefined : name.split(sep)[0]);
28
37
  if (timer !== undefined) {
29
38
  clearTimeout(timer);
30
39
  }
31
- timer = setTimeout(onChange, 50);
40
+ timer = setTimeout(() => {
41
+ const books = [...changed];
42
+ changed = new Set();
43
+ onChange(books.length === 1 ? books[0] : undefined);
44
+ }, 50);
32
45
  });
33
46
  watcher.on("error", () => { });
34
47
  return watcher;
@@ -45,8 +58,8 @@ function watchFolder(promptsDir, onChange) {
45
58
  export async function startViewer(options) {
46
59
  const { promptsDir, port = 0, open = false, fs } = options;
47
60
  const webRoot = fileURLToPath(new URL("../web", import.meta.url));
48
- const source = createBookSource(promptsDir, fs);
49
- const handler = createRequestHandler({ source, promptsDir, webRoot });
61
+ const workspace = createWorkspaceSource(promptsDir, fs);
62
+ const handler = createRequestHandler({ workspace, webRoot });
50
63
  const server = createServer((req, res) => handler.handle(req, res));
51
64
  await new Promise((resolve, reject) => {
52
65
  server.once("error", reject);
@@ -55,7 +68,7 @@ export async function startViewer(options) {
55
68
  const address = server.address();
56
69
  const boundPort = typeof address === "object" && address !== null ? address.port : port;
57
70
  const url = `http://localhost:${boundPort}`;
58
- const watcher = watchFolder(promptsDir, () => handler.notifyReload());
71
+ const watcher = watchFolder(promptsDir, (book) => handler.notifyReload(book));
59
72
  if (open) {
60
73
  openBrowser(url);
61
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { FsAdapter } from "@markbrutx/promptbook-core";
2
+ /** A discovered prompts book: its folder name and absolute directory. */
3
+ export interface Book {
4
+ name: string;
5
+ dir: string;
6
+ }
7
+ /**
8
+ * Read a workspace from `rootDir`. When the root is itself a book it is the only
9
+ * book (back-compat single-book view, named after the folder); otherwise the
10
+ * root is a workspace of its sub-books.
11
+ */
12
+ export declare function loadWorkspaceBooks(rootDir: string, fs?: FsAdapter): Promise<Book[]>;
13
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAG5D,yEAAyE;AACzE,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AA6CD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,SAAoB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAKnG"}
@@ -0,0 +1,55 @@
1
+ import { basename, join } from "node:path";
2
+ import { nodeFs } from "@markbrutx/promptbook-core";
3
+ /** Folder names that are book internals or noise, never workspace sub-books. */
4
+ const NON_BOOK_DIRS = new Set(["node_modules", "fragments", "rules", "code-prompts"]);
5
+ /** Markers that make a folder a loadable book (a config or a loadable form). */
6
+ const BOOK_MARKERS = ["promptbook.json", "rules", "code-prompts"];
7
+ /** True when `dir` looks like a prompts book (has a config or a loadable form). */
8
+ async function isBook(fs, dir) {
9
+ let entries;
10
+ try {
11
+ entries = await fs.readDir(dir);
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ return BOOK_MARKERS.some((marker) => entries.includes(marker));
17
+ }
18
+ /**
19
+ * Find the books directly under `rootDir`: each non-internal subfolder that is
20
+ * itself a book. One level deep, sorted by name. This mirrors the CLI's
21
+ * discovery (kept as a server-local copy so the viewer never depends on the
22
+ * CLI), so `view` and `ls --all` see the same workspace.
23
+ */
24
+ async function discoverBooks(rootDir, fs = nodeFs()) {
25
+ let entries;
26
+ try {
27
+ entries = await fs.readDir(rootDir);
28
+ }
29
+ catch {
30
+ return [];
31
+ }
32
+ const books = [];
33
+ for (const name of [...entries].sort()) {
34
+ if (name.startsWith(".") || name.startsWith("_") || NON_BOOK_DIRS.has(name)) {
35
+ continue;
36
+ }
37
+ const dir = join(rootDir, name);
38
+ if (await isBook(fs, dir)) {
39
+ books.push({ name, dir });
40
+ }
41
+ }
42
+ return books;
43
+ }
44
+ /**
45
+ * Read a workspace from `rootDir`. When the root is itself a book it is the only
46
+ * book (back-compat single-book view, named after the folder); otherwise the
47
+ * root is a workspace of its sub-books.
48
+ */
49
+ export async function loadWorkspaceBooks(rootDir, fs = nodeFs()) {
50
+ if (await isBook(fs, rootDir)) {
51
+ return [{ name: basename(rootDir), dir: rootDir }];
52
+ }
53
+ return discoverBooks(rootDir, fs);
54
+ }
55
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAQpD,gFAAgF;AAChF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;AAEtF,gFAAgF;AAChF,MAAM,YAAY,GAAG,CAAC,iBAAiB,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;AAElE,mFAAmF;AACnF,KAAK,UAAU,MAAM,CAAC,EAAa,EAAE,GAAW;IAC9C,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,EAAE,GAAc,MAAM,EAAE;IACpE,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5E,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAChC,IAAI,MAAM,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAe,EAAE,EAAE,GAAc,MAAM,EAAE;IAChF,IAAI,MAAM,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC"}
@@ -52,6 +52,15 @@ export interface CodePromptSummary {
52
52
  samples: CodePromptSampleSummary[];
53
53
  sourceFile: string;
54
54
  }
55
+ /** One book in the workspace, as `GET /api/books` lists it. */
56
+ export interface WorkspaceBook {
57
+ name: string;
58
+ dir: string;
59
+ }
60
+ /** Response of `GET /api/books`: the switcher menu. */
61
+ export interface BooksResponse {
62
+ books: WorkspaceBook[];
63
+ }
55
64
  /** Response of `GET /api/book`. */
56
65
  export interface BookResponse {
57
66
  compositions: CompositionSummary[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ :root{--bg: #fff;--panel: #f6f8fa;--border: #e1e4e8;--text: #1f2328;--muted: #6e7781;--accent: #4f46e5;--warn: #b35900;font-family:system-ui,-apple-system,Segoe UI,sans-serif;font-size:14px;color:var(--text)}*{box-sizing:border-box}body{margin:0;background:var(--bg)}.layout{display:grid;grid-template-columns:260px minmax(0,1fr) 380px;height:100vh}.sidebar{border-right:1px solid var(--border);overflow-y:auto;padding:12px;background:var(--panel)}.sidebar-brand{display:flex;flex-direction:column;gap:10px;padding:4px 4px 12px;border-bottom:1px solid var(--border);margin-bottom:4px}.sidebar-logo{width:168px;max-width:80%;height:auto;display:block;margin:8px auto 4px}.book-switcher{display:flex;align-items:center;gap:6px}.book-switcher-label{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}.sidebar-title{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin:16px 0 6px}.tree{list-style:none;margin:0;padding-left:12px}.tree-folder,.tree-composition{cursor:pointer;font-weight:600;padding:2px 0}.tree-item,.link{display:inline-flex;align-items:center;gap:6px;width:100%;text-align:left;background:none;border:none;padding:3px 6px;border-radius:5px;color:var(--text);cursor:pointer;font:inherit}.tree-item:hover{background:#eaeef2}.tree-item.active{background:var(--accent);color:#fff}.link{width:auto;color:var(--accent);padding:0;text-decoration:underline}.swatch{width:10px;height:10px;border-radius:2px;flex:none}.canvas{overflow-y:auto;padding:20px 24px}.canvas-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:12px}.canvas-title{font-size:18px;margin:0;display:flex;align-items:center;gap:8px}.legend{list-style:none;display:flex;flex-wrap:wrap;gap:10px;padding:0;margin:0 0 14px;font-size:12px;color:var(--muted)}.legend li{display:inline-flex;align-items:center;gap:5px}.prompt{display:flex;flex-direction:column;gap:14px}.segment{position:relative;margin:0;padding:16px 12px 12px;border-radius:6px;border:1px solid var(--border);white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:13px;line-height:1.5}.segment-tag{position:absolute;top:0;right:0;font-size:10px;padding:1px 6px;background:#0000000f;border-bottom-left-radius:6px;font-family:system-ui,sans-serif;color:var(--muted)}.rail{border-left:1px solid var(--border);overflow-y:auto;padding:16px;background:var(--panel)}.rail section,.addons section{margin-bottom:18px}.rail h3,.addons h3{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin:0 0 8px}.rail h4{margin:12px 0 4px;font-size:12px}select,input{width:100%;padding:4px 6px;border:1px solid var(--border);border-radius:5px;font:inherit;background:#fff}.book-switcher select{flex:1;width:auto}.control-row{display:grid;grid-template-columns:90px 1fr;align-items:center;gap:8px;margin-bottom:6px}.control-key{font-family:ui-monospace,monospace;font-size:12px;color:var(--muted)}.control-add{display:grid;grid-template-columns:1fr auto;gap:6px;margin-top:6px}.control-add button{border:1px solid var(--border);border-radius:5px;background:#fff;cursor:pointer;padding:0 10px}.rules,.findings,.warnings,.used-list{list-style:none;margin:0;padding:0}.rules li{padding:4px 0;border-bottom:1px solid var(--border);font-size:12px}.rules li.skipped{color:var(--muted)}.rule-mark{margin-right:6px}.rule-action{font-weight:600;margin-right:6px}.rule-effect{font-family:ui-monospace,monospace;margin-top:2px}.rule-reason{color:var(--muted);margin-top:2px}.order{font-family:ui-monospace,monospace;font-size:12px;word-break:break-word}.finding{display:flex;flex-wrap:wrap;gap:6px;align-items:baseline;padding:5px 0;border-bottom:1px solid var(--border);font-size:12px}.finding-sev{text-transform:uppercase;font-size:10px;font-weight:700;padding:1px 5px;border-radius:4px;background:#eaeef2}.finding.error .finding-sev{background:#ffd7d5;color:#a40e26}.finding.warning .finding-sev{background:#fff1c2;color:var(--warn)}.finding-rule{font-family:ui-monospace,monospace;color:var(--muted)}.diff-body{margin:8px 0 0;font-family:ui-monospace,monospace;font-size:12px;border:1px solid var(--border);border-radius:6px;overflow-x:auto;background:#fff}.diff-row{padding:0 8px;white-space:pre-wrap}.diff-row.add{background:#e6ffec}.diff-row.remove{background:#ffebe9}.diff-mark{display:inline-block;width:12px;color:var(--muted)}.annot-mark{background:#fff3b0;border-bottom:2px solid var(--warn);border-radius:2px;padding:0 1px}.annot-popover{position:fixed;z-index:20;width:280px;padding:10px;background:#fff;border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #00000029}.annot-popover textarea{width:100%;min-height:64px;resize:vertical;margin:6px 0}.annot-actions{display:flex;justify-content:flex-end;gap:10px;align-items:center}.annot-actions button[type=button]:last-child{border:1px solid var(--border);border-radius:5px;background:var(--accent);color:#fff;padding:4px 12px;cursor:pointer}.annot-actions button[disabled]{opacity:.5;cursor:default}.annot-quote{margin:0;font-style:italic;color:var(--muted);font-size:12px;word-break:break-word}.annot-list{list-style:none;margin:0;padding:0}.annot-list li{padding:8px 0;border-bottom:1px solid var(--border)}.annot-comment{margin:4px 0;font-size:13px;word-break:break-word}.annot-meta{display:flex;justify-content:space-between;align-items:center;gap:8px;font-size:12px}.badge{font-size:12px;padding:2px 8px;border-radius:999px;background:#eaeef2;white-space:nowrap}.badge-code{font-size:10px;text-transform:uppercase;letter-spacing:.06em;background:#2b2b40;color:#fff}.code-tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}.code-tab{font:inherit;font-size:12px;padding:3px 10px;border-radius:999px;border:1px solid var(--border);background:var(--panel);color:var(--text);cursor:pointer}.code-tab.active{background:var(--accent);border-color:var(--accent)}.code-diff{margin-top:18px}.tokens{font-size:20px;font-weight:600;margin:0}.muted{color:var(--muted)}.warn{color:var(--warn)}.used-list li{padding:3px 0}