@creator-notes/cnotes 0.16.11

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 (158) hide show
  1. package/.claude-plugin/plugin.json +14 -0
  2. package/.mcp.json +12 -0
  3. package/LICENSE +21 -0
  4. package/README.md +303 -0
  5. package/dist/cn.d.ts +3 -0
  6. package/dist/cn.d.ts.map +1 -0
  7. package/dist/cn.js +124 -0
  8. package/dist/cn.js.map +1 -0
  9. package/dist/commands/auth.d.ts +10 -0
  10. package/dist/commands/auth.d.ts.map +1 -0
  11. package/dist/commands/auth.js +188 -0
  12. package/dist/commands/auth.js.map +1 -0
  13. package/dist/commands/canvas.d.ts +3 -0
  14. package/dist/commands/canvas.d.ts.map +1 -0
  15. package/dist/commands/canvas.js +1383 -0
  16. package/dist/commands/canvas.js.map +1 -0
  17. package/dist/commands/claude-hook.d.ts +28 -0
  18. package/dist/commands/claude-hook.d.ts.map +1 -0
  19. package/dist/commands/claude-hook.js +59 -0
  20. package/dist/commands/claude-hook.js.map +1 -0
  21. package/dist/commands/config.d.ts +3 -0
  22. package/dist/commands/config.d.ts.map +1 -0
  23. package/dist/commands/config.js +47 -0
  24. package/dist/commands/config.js.map +1 -0
  25. package/dist/commands/files.d.ts +3 -0
  26. package/dist/commands/files.d.ts.map +1 -0
  27. package/dist/commands/files.js +119 -0
  28. package/dist/commands/files.js.map +1 -0
  29. package/dist/commands/init.d.ts +3 -0
  30. package/dist/commands/init.d.ts.map +1 -0
  31. package/dist/commands/init.js +473 -0
  32. package/dist/commands/init.js.map +1 -0
  33. package/dist/commands/mcp.d.ts +15 -0
  34. package/dist/commands/mcp.d.ts.map +1 -0
  35. package/dist/commands/mcp.js +118 -0
  36. package/dist/commands/mcp.js.map +1 -0
  37. package/dist/commands/memory.d.ts +3 -0
  38. package/dist/commands/memory.d.ts.map +1 -0
  39. package/dist/commands/memory.js +150 -0
  40. package/dist/commands/memory.js.map +1 -0
  41. package/dist/commands/notes.d.ts +3 -0
  42. package/dist/commands/notes.d.ts.map +1 -0
  43. package/dist/commands/notes.js +706 -0
  44. package/dist/commands/notes.js.map +1 -0
  45. package/dist/commands/operations.d.ts +18 -0
  46. package/dist/commands/operations.d.ts.map +1 -0
  47. package/dist/commands/operations.js +231 -0
  48. package/dist/commands/operations.js.map +1 -0
  49. package/dist/commands/relationships.d.ts +3 -0
  50. package/dist/commands/relationships.d.ts.map +1 -0
  51. package/dist/commands/relationships.js +94 -0
  52. package/dist/commands/relationships.js.map +1 -0
  53. package/dist/commands/schema.d.ts +12 -0
  54. package/dist/commands/schema.d.ts.map +1 -0
  55. package/dist/commands/schema.js +85 -0
  56. package/dist/commands/schema.js.map +1 -0
  57. package/dist/commands/search.d.ts +3 -0
  58. package/dist/commands/search.d.ts.map +1 -0
  59. package/dist/commands/search.js +57 -0
  60. package/dist/commands/search.js.map +1 -0
  61. package/dist/commands/theme.d.ts +3 -0
  62. package/dist/commands/theme.d.ts.map +1 -0
  63. package/dist/commands/theme.js +184 -0
  64. package/dist/commands/theme.js.map +1 -0
  65. package/dist/commands/timeline.d.ts +3 -0
  66. package/dist/commands/timeline.d.ts.map +1 -0
  67. package/dist/commands/timeline.js +97 -0
  68. package/dist/commands/timeline.js.map +1 -0
  69. package/dist/commands/types.d.ts +3 -0
  70. package/dist/commands/types.d.ts.map +1 -0
  71. package/dist/commands/types.js +139 -0
  72. package/dist/commands/types.js.map +1 -0
  73. package/dist/commands/versions.d.ts +3 -0
  74. package/dist/commands/versions.d.ts.map +1 -0
  75. package/dist/commands/versions.js +120 -0
  76. package/dist/commands/versions.js.map +1 -0
  77. package/dist/commands/workspace.d.ts +13 -0
  78. package/dist/commands/workspace.d.ts.map +1 -0
  79. package/dist/commands/workspace.js +176 -0
  80. package/dist/commands/workspace.js.map +1 -0
  81. package/dist/lib/api-client.d.ts +45 -0
  82. package/dist/lib/api-client.d.ts.map +1 -0
  83. package/dist/lib/api-client.js +198 -0
  84. package/dist/lib/api-client.js.map +1 -0
  85. package/dist/lib/auth-store.d.ts +47 -0
  86. package/dist/lib/auth-store.d.ts.map +1 -0
  87. package/dist/lib/auth-store.js +116 -0
  88. package/dist/lib/auth-store.js.map +1 -0
  89. package/dist/lib/brand.d.ts +32 -0
  90. package/dist/lib/brand.d.ts.map +1 -0
  91. package/dist/lib/brand.js +32 -0
  92. package/dist/lib/brand.js.map +1 -0
  93. package/dist/lib/build-schema.d.ts +97 -0
  94. package/dist/lib/build-schema.d.ts.map +1 -0
  95. package/dist/lib/build-schema.js +139 -0
  96. package/dist/lib/build-schema.js.map +1 -0
  97. package/dist/lib/canvas-read.d.ts +54 -0
  98. package/dist/lib/canvas-read.d.ts.map +1 -0
  99. package/dist/lib/canvas-read.js +145 -0
  100. package/dist/lib/canvas-read.js.map +1 -0
  101. package/dist/lib/claude-session.d.ts +73 -0
  102. package/dist/lib/claude-session.d.ts.map +1 -0
  103. package/dist/lib/claude-session.js +104 -0
  104. package/dist/lib/claude-session.js.map +1 -0
  105. package/dist/lib/config.d.ts +28 -0
  106. package/dist/lib/config.d.ts.map +1 -0
  107. package/dist/lib/config.js +66 -0
  108. package/dist/lib/config.js.map +1 -0
  109. package/dist/lib/env.d.ts +14 -0
  110. package/dist/lib/env.d.ts.map +1 -0
  111. package/dist/lib/env.js +16 -0
  112. package/dist/lib/env.js.map +1 -0
  113. package/dist/lib/errors.d.ts +47 -0
  114. package/dist/lib/errors.d.ts.map +1 -0
  115. package/dist/lib/errors.js +194 -0
  116. package/dist/lib/errors.js.map +1 -0
  117. package/dist/lib/fs-utils.d.ts +2 -0
  118. package/dist/lib/fs-utils.d.ts.map +1 -0
  119. package/dist/lib/fs-utils.js +16 -0
  120. package/dist/lib/fs-utils.js.map +1 -0
  121. package/dist/lib/install-hook.d.ts +86 -0
  122. package/dist/lib/install-hook.d.ts.map +1 -0
  123. package/dist/lib/install-hook.js +168 -0
  124. package/dist/lib/install-hook.js.map +1 -0
  125. package/dist/lib/install-mcp.d.ts +21 -0
  126. package/dist/lib/install-mcp.d.ts.map +1 -0
  127. package/dist/lib/install-mcp.js +133 -0
  128. package/dist/lib/install-mcp.js.map +1 -0
  129. package/dist/lib/install-skill.d.ts +49 -0
  130. package/dist/lib/install-skill.d.ts.map +1 -0
  131. package/dist/lib/install-skill.js +113 -0
  132. package/dist/lib/install-skill.js.map +1 -0
  133. package/dist/lib/output.d.ts +29 -0
  134. package/dist/lib/output.d.ts.map +1 -0
  135. package/dist/lib/output.js +78 -0
  136. package/dist/lib/output.js.map +1 -0
  137. package/dist/lib/resolve-note.d.ts +7 -0
  138. package/dist/lib/resolve-note.d.ts.map +1 -0
  139. package/dist/lib/resolve-note.js +23 -0
  140. package/dist/lib/resolve-note.js.map +1 -0
  141. package/dist/lib/stdin.d.ts +5 -0
  142. package/dist/lib/stdin.d.ts.map +1 -0
  143. package/dist/lib/stdin.js +11 -0
  144. package/dist/lib/stdin.js.map +1 -0
  145. package/dist/lib/style.d.ts +10 -0
  146. package/dist/lib/style.d.ts.map +1 -0
  147. package/dist/lib/style.js +17 -0
  148. package/dist/lib/style.js.map +1 -0
  149. package/dist/lib/themes.d.ts +44 -0
  150. package/dist/lib/themes.d.ts.map +1 -0
  151. package/dist/lib/themes.js +168 -0
  152. package/dist/lib/themes.js.map +1 -0
  153. package/dist/mcp-server.d.ts +3 -0
  154. package/dist/mcp-server.d.ts.map +1 -0
  155. package/dist/mcp-server.js +782 -0
  156. package/dist/mcp-server.js.map +1 -0
  157. package/package.json +66 -0
  158. package/skills/cnotes/SKILL.md +680 -0
@@ -0,0 +1,104 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join, relative, isAbsolute } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { BRAND } from "./brand.js";
5
+ import { cnotesEnv } from "./env.js";
6
+ /**
7
+ * Where `cnotes claude-hook` (a Claude Code SessionStart hook) persists the
8
+ * current session id. A single "latest" file — simple and correct for the
9
+ * common one-session-per-machine case. Concurrent Claude Code sessions on the
10
+ * same machine would clobber it; set CNOTES_AGENT_SESSION_ID to disambiguate.
11
+ */
12
+ export const CLAUDE_SESSION_FILE = join(homedir(), BRAND.configDir, "claude-session.json");
13
+ /**
14
+ * How long a hook-captured session stays trustworthy as "the agent driving
15
+ * this cnotes run". The SessionStart hook stamps `updatedAt` when the session is
16
+ * (re)opened, but there's no heartbeat — so this is age-since-opened, not
17
+ * since-last-activity. A generous window keeps long-running sessions valid
18
+ * while stopping a file left behind by a session that ended days ago from
19
+ * stamping a later, unrelated run.
20
+ */
21
+ export const SESSION_FILE_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24h
22
+ /**
23
+ * Decide whether a stored hook session is still a trustworthy stand-in for
24
+ * "the agent driving THIS cnotes run". Pure (takes `now` + `cwd` rather than
25
+ * reading them) so the rules stay easy to reason about:
26
+ *
27
+ * - Must carry an `id` — the only thing we can actually resume.
28
+ * - Not older than {@link SESSION_FILE_MAX_AGE_MS} — a stale file left after
29
+ * a session ended must not stamp a later run as if that chat drove it.
30
+ * - If the file recorded the session's `cwd`, the current directory must sit
31
+ * inside that subtree — a cnotes run in a *different* project isn't this
32
+ * session's work. (No recorded cwd → can't scope, so we don't reject on
33
+ * that basis.)
34
+ *
35
+ * Erring toward rejection is the safe bias here: a false negative just drops
36
+ * the (optional) resume affordance, whereas a false positive mislabels the
37
+ * run's provenance and offers a resume to the wrong chat.
38
+ */
39
+ export function isStoredSessionUsable(stored, ctx) {
40
+ if (!stored.id)
41
+ return false;
42
+ if (typeof stored.updatedAt === "number" &&
43
+ ctx.now - stored.updatedAt > SESSION_FILE_MAX_AGE_MS) {
44
+ return false;
45
+ }
46
+ if (stored.cwd && !isWithin(ctx.cwd, stored.cwd))
47
+ return false;
48
+ return true;
49
+ }
50
+ /** True when `child` is `parent` or nested beneath it. */
51
+ function isWithin(child, parent) {
52
+ const rel = relative(parent, child);
53
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
54
+ }
55
+ /**
56
+ * Resolve the agent conversation/session driving the current cnotes run, so
57
+ * `cnotes operations begin` can stamp it on the operation row (making the run
58
+ * traceable + resumable from the timeline). Resolution order, most explicit
59
+ * first:
60
+ *
61
+ * 1. CN_AGENT_SESSION_ID (+ optional CN_AGENT_SESSION_KIND) — explicit
62
+ * override, wins everything. Lets any agent runtime opt in by hand.
63
+ * 2. The SessionStart-hook file written by `cnotes claude-hook`, when it's still
64
+ * fresh + scoped to this directory (see {@link isStoredSessionUsable}).
65
+ * This is the Claude Code TOP-LEVEL session id, captured once when the
66
+ * session starts — the most correct value to resume (a subagent's own
67
+ * bash would otherwise report the subagent's id via the env var below).
68
+ * 3. CLAUDE_CODE_SESSION_ID — Claude Code's per-process env var. Zero-config
69
+ * but undocumented; best-effort fallback when no hook is installed. It's
70
+ * the live process's own env, so no staleness check applies.
71
+ *
72
+ * Returns null when nothing is known (e.g. cnotes run outside any agent), in which
73
+ * case the run simply isn't session-stamped — no error.
74
+ */
75
+ export function resolveAgentSession() {
76
+ const overrideId = cnotesEnv("AGENT_SESSION_ID")?.trim();
77
+ if (overrideId) {
78
+ return {
79
+ kind: cnotesEnv("AGENT_SESSION_KIND")?.trim() || "claude-code",
80
+ id: overrideId,
81
+ };
82
+ }
83
+ const fromFile = readSessionFile(Date.now(), process.cwd());
84
+ if (fromFile)
85
+ return fromFile;
86
+ const envId = process.env.CLAUDE_CODE_SESSION_ID?.trim();
87
+ if (envId)
88
+ return { kind: "claude-code", id: envId };
89
+ return null;
90
+ }
91
+ function readSessionFile(now, cwd) {
92
+ try {
93
+ const raw = readFileSync(CLAUDE_SESSION_FILE, "utf-8");
94
+ const parsed = JSON.parse(raw);
95
+ if (isStoredSessionUsable(parsed, { now, cwd })) {
96
+ return { kind: parsed.kind || "claude-code", id: parsed.id };
97
+ }
98
+ }
99
+ catch {
100
+ // No hook file / unreadable / malformed → fall through to env.
101
+ }
102
+ return null;
103
+ }
104
+ //# sourceMappingURL=claude-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-session.js","sourceRoot":"","sources":["../../src/lib/claude-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAUrC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CACrC,OAAO,EAAE,EACT,KAAK,CAAC,SAAS,EACf,qBAAqB,CACtB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM;AASlE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAqB,EACrB,GAAiC;IAEjC,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IAC7B,IACE,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;QACpC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,SAAS,GAAG,uBAAuB,EACpD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0DAA0D;AAC1D,SAAS,QAAQ,CAAC,KAAa,EAAE,MAAc;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,UAAU,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC;IACzD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,SAAS,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,aAAa;YAC9D,EAAE,EAAE,UAAU;SACf,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5D,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC;IACzD,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IAErD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,GAAW,EAAE,GAAW;IAC/C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;QAChD,IAAI,qBAAqB,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,aAAa,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;QAC/D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;IACjE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface ResolvedConfig {
2
+ serverUrl: string;
3
+ token: string;
4
+ workspaceId: string;
5
+ json: boolean;
6
+ quiet: boolean;
7
+ fields?: string[];
8
+ }
9
+ interface GlobalOpts {
10
+ server?: string;
11
+ workspace?: string;
12
+ json?: boolean;
13
+ quiet?: boolean;
14
+ fields?: string;
15
+ }
16
+ /**
17
+ * Resolve server URL, token, and workspace from env vars, flags, and config file.
18
+ * Priority: flags > env vars > config file.
19
+ */
20
+ export declare function resolveConfig(opts: GlobalOpts): ResolvedConfig;
21
+ /**
22
+ * Resolve config without requiring workspace (for auth/config/workspace commands).
23
+ */
24
+ export declare function resolveBaseConfig(opts: GlobalOpts): Omit<ResolvedConfig, "workspaceId"> & {
25
+ workspaceId?: string;
26
+ };
27
+ export {};
28
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,UAAU,UAAU;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAqC9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAmBlH"}
@@ -0,0 +1,66 @@
1
+ import { loadConfig, getServerConfig } from "./auth-store.js";
2
+ import { AuthError, ValidationError } from "./errors.js";
3
+ import { cnotesEnv } from "./env.js";
4
+ /**
5
+ * Parse a `--fields a,b,c` option into a trimmed list, or undefined when unset.
6
+ */
7
+ function parseFields(fields) {
8
+ if (!fields)
9
+ return undefined;
10
+ const list = fields.split(",").map((f) => f.trim()).filter(Boolean);
11
+ return list.length > 0 ? list : undefined;
12
+ }
13
+ /**
14
+ * Resolve server URL, token, and workspace from env vars, flags, and config file.
15
+ * Priority: flags > env vars > config file.
16
+ */
17
+ export function resolveConfig(opts) {
18
+ const config = loadConfig();
19
+ // Server URL
20
+ const serverUrl = opts.server || cnotesEnv("SERVER") || config.currentServer;
21
+ // Token
22
+ const envToken = cnotesEnv("TOKEN");
23
+ const configToken = getServerConfig(config, serverUrl)?.token;
24
+ const token = envToken || configToken;
25
+ if (!token) {
26
+ throw new AuthError();
27
+ }
28
+ // Workspace ID
29
+ const envWorkspace = cnotesEnv("WORKSPACE");
30
+ const configWorkspace = getServerConfig(config, serverUrl)?.workspaceId;
31
+ const workspaceId = opts.workspace || envWorkspace || configWorkspace;
32
+ if (!workspaceId) {
33
+ throw new ValidationError("No workspace selected. Run `cnotes workspace select` or pass --workspace <id>");
34
+ }
35
+ // Output format
36
+ const json = opts.json || cnotesEnv("JSON") === "1" || !process.stdout.isTTY;
37
+ return {
38
+ serverUrl,
39
+ token,
40
+ workspaceId,
41
+ json: json ?? false,
42
+ quiet: opts.quiet ?? false,
43
+ fields: parseFields(opts.fields),
44
+ };
45
+ }
46
+ /**
47
+ * Resolve config without requiring workspace (for auth/config/workspace commands).
48
+ */
49
+ export function resolveBaseConfig(opts) {
50
+ const config = loadConfig();
51
+ const serverUrl = opts.server || cnotesEnv("SERVER") || config.currentServer;
52
+ const envToken = cnotesEnv("TOKEN");
53
+ const configToken = getServerConfig(config, serverUrl)?.token;
54
+ const token = envToken || configToken || "";
55
+ const configWorkspace = getServerConfig(config, serverUrl)?.workspaceId;
56
+ const json = opts.json || cnotesEnv("JSON") === "1" || !process.stdout.isTTY;
57
+ return {
58
+ serverUrl,
59
+ token,
60
+ workspaceId: opts.workspace || cnotesEnv("WORKSPACE") || configWorkspace,
61
+ json: json ?? false,
62
+ quiet: opts.quiet ?? false,
63
+ fields: parseFields(opts.fields),
64
+ };
65
+ }
66
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Read a cnotes environment variable, honoring the pre-rename `CN_` prefix as a
3
+ * fallback.
4
+ *
5
+ * The cn→cnotes rename moved the env contract from `CN_*` to `CNOTES_*`. New
6
+ * config (`.mcp.json`, the Claude Desktop / Codex install templates) writes the
7
+ * `CNOTES_*` form, but MCP configs written before the rename still carry `CN_*`
8
+ * — so we read `CNOTES_<suffix>` first and fall back to `CN_<suffix>` until the
9
+ * user re-runs `cnotes mcp setup-*` (which rewrites the config to the new form).
10
+ *
11
+ * Pass the suffix only, e.g. `cnotesEnv("SERVER")` for CNOTES_SERVER/CN_SERVER.
12
+ */
13
+ export declare function cnotesEnv(suffix: string): string | undefined;
14
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5D"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Read a cnotes environment variable, honoring the pre-rename `CN_` prefix as a
3
+ * fallback.
4
+ *
5
+ * The cn→cnotes rename moved the env contract from `CN_*` to `CNOTES_*`. New
6
+ * config (`.mcp.json`, the Claude Desktop / Codex install templates) writes the
7
+ * `CNOTES_*` form, but MCP configs written before the rename still carry `CN_*`
8
+ * — so we read `CNOTES_<suffix>` first and fall back to `CN_<suffix>` until the
9
+ * user re-runs `cnotes mcp setup-*` (which rewrites the config to the new form).
10
+ *
11
+ * Pass the suffix only, e.g. `cnotesEnv("SERVER")` for CNOTES_SERVER/CN_SERVER.
12
+ */
13
+ export function cnotesEnv(suffix) {
14
+ return process.env[`CNOTES_${suffix}`] ?? process.env[`CN_${suffix}`];
15
+ }
16
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,EAAE,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Exit codes are part of the CLI's contract with agents. Branching on the
3
+ * exit code is cheaper and more reliable than parsing stderr prose.
4
+ *
5
+ * 0 ok
6
+ * 1 generic error
7
+ * 2 auth required
8
+ * 3 validation (bad input)
9
+ * 4 not found
10
+ * 5 conflict (already exists / state collision)
11
+ * 6 rate-limited
12
+ * 7 permission denied
13
+ */
14
+ export declare const EXIT_CODES: {
15
+ readonly OK: 0;
16
+ readonly GENERIC: 1;
17
+ readonly AUTH: 2;
18
+ readonly VALIDATION: 3;
19
+ readonly NOT_FOUND: 4;
20
+ readonly CONFLICT: 5;
21
+ readonly RATE_LIMIT: 6;
22
+ readonly PERMISSION: 7;
23
+ };
24
+ export declare class CliError extends Error {
25
+ exitCode: number;
26
+ hint?: string;
27
+ constructor(message: string, exitCode?: number, hint?: string);
28
+ }
29
+ export declare class AuthError extends CliError {
30
+ constructor(message?: string, hint?: string);
31
+ }
32
+ export declare class ValidationError extends CliError {
33
+ constructor(message: string, hint?: string);
34
+ }
35
+ export declare class NotFoundError extends CliError {
36
+ constructor(message: string, hint?: string);
37
+ }
38
+ export declare class ApiError extends CliError {
39
+ status: number;
40
+ body: Record<string, unknown>;
41
+ constructor(status: number, body: Record<string, unknown>);
42
+ }
43
+ /**
44
+ * Handle errors from CLI commands uniformly.
45
+ */
46
+ export declare function handleError(error: unknown, json: boolean): never;
47
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU;;;;;;;;;CASb,CAAC;AAEX,qBAAa,QAAS,SAAQ,KAAK;IAKxB,QAAQ,EAAE,MAAM;IAJzB,IAAI,CAAC,EAAE,MAAM,CAAC;gBAGZ,OAAO,EAAE,MAAM,EACR,QAAQ,GAAE,MAA2B,EAC5C,IAAI,CAAC,EAAE,MAAM;CAMhB;AAED,qBAAa,SAAU,SAAQ,QAAQ;gBAEnC,OAAO,GAAE,MAAmC,EAC5C,IAAI,GAAE,MAAmD;CAK5D;AAED,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAI3C;AAED,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAI3C;AAED,qBAAa,QAAS,SAAQ,QAAQ;IAE3B,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAD7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAgBvC;AA4FD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,KAAK,CA8BhE"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Exit codes are part of the CLI's contract with agents. Branching on the
3
+ * exit code is cheaper and more reliable than parsing stderr prose.
4
+ *
5
+ * 0 ok
6
+ * 1 generic error
7
+ * 2 auth required
8
+ * 3 validation (bad input)
9
+ * 4 not found
10
+ * 5 conflict (already exists / state collision)
11
+ * 6 rate-limited
12
+ * 7 permission denied
13
+ */
14
+ export const EXIT_CODES = {
15
+ OK: 0,
16
+ GENERIC: 1,
17
+ AUTH: 2,
18
+ VALIDATION: 3,
19
+ NOT_FOUND: 4,
20
+ CONFLICT: 5,
21
+ RATE_LIMIT: 6,
22
+ PERMISSION: 7,
23
+ };
24
+ export class CliError extends Error {
25
+ exitCode;
26
+ hint;
27
+ constructor(message, exitCode = EXIT_CODES.GENERIC, hint) {
28
+ super(message);
29
+ this.exitCode = exitCode;
30
+ this.name = "CliError";
31
+ if (hint)
32
+ this.hint = hint;
33
+ }
34
+ }
35
+ export class AuthError extends CliError {
36
+ constructor(message = "Authentication required.", hint = "Run `cnotes auth login` to authenticate.") {
37
+ super(message, EXIT_CODES.AUTH, hint);
38
+ this.name = "AuthError";
39
+ }
40
+ }
41
+ export class ValidationError extends CliError {
42
+ constructor(message, hint) {
43
+ super(message, EXIT_CODES.VALIDATION, hint);
44
+ this.name = "ValidationError";
45
+ }
46
+ }
47
+ export class NotFoundError extends CliError {
48
+ constructor(message, hint) {
49
+ super(message, EXIT_CODES.NOT_FOUND, hint);
50
+ this.name = "NotFoundError";
51
+ }
52
+ }
53
+ export class ApiError extends CliError {
54
+ status;
55
+ body;
56
+ constructor(status, body) {
57
+ const baseMsg = body.error || `API error: HTTP ${status}`;
58
+ const fieldLines = formatFieldErrors(body.details);
59
+ const msg = fieldLines.length > 0
60
+ ? `${baseMsg}\n${fieldLines.map((l) => ` - ${l}`).join("\n")}`
61
+ : baseMsg;
62
+ const exitCode = exitCodeForStatus(status);
63
+ const resource = typeof body.resource === "string" ? body.resource : undefined;
64
+ const hint = typeof body.hint === "string"
65
+ ? body.hint
66
+ : hintForStatus(status, baseMsg, resource);
67
+ super(msg, exitCode, hint);
68
+ this.status = status;
69
+ this.body = body;
70
+ this.name = "ApiError";
71
+ }
72
+ }
73
+ function exitCodeForStatus(status) {
74
+ if (status === 401)
75
+ return EXIT_CODES.AUTH;
76
+ if (status === 403)
77
+ return EXIT_CODES.PERMISSION;
78
+ if (status === 404)
79
+ return EXIT_CODES.NOT_FOUND;
80
+ if (status === 409)
81
+ return EXIT_CODES.CONFLICT;
82
+ if (status === 422)
83
+ return EXIT_CODES.VALIDATION;
84
+ if (status === 429)
85
+ return EXIT_CODES.RATE_LIMIT;
86
+ if (status >= 400 && status < 500)
87
+ return EXIT_CODES.VALIDATION;
88
+ return EXIT_CODES.GENERIC;
89
+ }
90
+ function hintForStatus(status, message, resource) {
91
+ if (status === 401)
92
+ return "Run `cnotes auth login` to authenticate.";
93
+ if (status === 403)
94
+ return "Check workspace membership with `cnotes workspace current`.";
95
+ if (status === 404) {
96
+ // Prefer a server-provided `resource` field; fall back to regex on the
97
+ // error message. Regex is best-effort because server messages vary.
98
+ const r = (resource ?? "").toLowerCase();
99
+ if (r === "workspace" || (!r && /workspace/i.test(message))) {
100
+ return "Run `cnotes workspace list` to see available workspaces.";
101
+ }
102
+ if (r === "note" || (!r && /note/i.test(message))) {
103
+ return "Run `cnotes notes list` to see valid display IDs.";
104
+ }
105
+ if (r === "canvas" || (!r && /canvas/i.test(message))) {
106
+ return "Run `cnotes canvas list` to see available canvases.";
107
+ }
108
+ return "Run `cnotes schema` to see valid resource identifiers.";
109
+ }
110
+ if (status === 429)
111
+ return "Slow down requests or retry with backoff.";
112
+ if (status === 409)
113
+ return "Re-fetch current state and retry; another writer may have modified the resource.";
114
+ return undefined;
115
+ }
116
+ function isBatchItem(v) {
117
+ return (!!v &&
118
+ typeof v === "object" &&
119
+ typeof v.index === "number" &&
120
+ typeof v.field === "string" &&
121
+ typeof v.message === "string");
122
+ }
123
+ /**
124
+ * Extract human-readable lines from a server `details` payload. Recognises:
125
+ * - `{ items: [{ index, key?, field, message }, ...] }` — `cnotes notes create` per-item errors
126
+ * - Zod `.flatten()` shape `{ fieldErrors, formErrors }` — generic validation
127
+ */
128
+ function formatFieldErrors(details) {
129
+ if (!details || typeof details !== "object")
130
+ return [];
131
+ const d = details;
132
+ const lines = [];
133
+ if (Array.isArray(d.items)) {
134
+ for (const raw of d.items) {
135
+ if (!isBatchItem(raw))
136
+ continue;
137
+ const keyLabel = raw.key ? `(${raw.key})` : "(?)";
138
+ lines.push(`item ${raw.index} ${keyLabel}: ${raw.field}: ${raw.message}`);
139
+ }
140
+ if (lines.length > 0)
141
+ return lines;
142
+ }
143
+ if (d.fieldErrors) {
144
+ for (const [field, errs] of Object.entries(d.fieldErrors)) {
145
+ if (!errs || errs.length === 0)
146
+ continue;
147
+ for (const err of errs)
148
+ lines.push(`${field}: ${err}`);
149
+ }
150
+ }
151
+ if (lines.length === 0 && Array.isArray(d.formErrors)) {
152
+ for (const err of d.formErrors)
153
+ lines.push(err);
154
+ }
155
+ return lines;
156
+ }
157
+ /**
158
+ * Handle errors from CLI commands uniformly.
159
+ */
160
+ export function handleError(error, json) {
161
+ if (error instanceof CliError) {
162
+ if (json) {
163
+ const payload = {
164
+ error: error.message,
165
+ code: error.name,
166
+ exitCode: error.exitCode,
167
+ };
168
+ if (error.hint)
169
+ payload.hint = error.hint;
170
+ if (error instanceof ApiError) {
171
+ payload.status = error.status;
172
+ if (error.body && typeof error.body === "object" && "details" in error.body) {
173
+ payload.details = error.body.details;
174
+ }
175
+ }
176
+ console.error(JSON.stringify(payload));
177
+ }
178
+ else {
179
+ console.error(`Error: ${error.message}`);
180
+ if (error.hint)
181
+ console.error(` hint: ${error.hint}`);
182
+ }
183
+ process.exit(error.exitCode);
184
+ }
185
+ const message = error instanceof Error ? error.message : String(error);
186
+ if (json) {
187
+ console.error(JSON.stringify({ error: message, code: "unknown_error", exitCode: EXIT_CODES.GENERIC }));
188
+ }
189
+ else {
190
+ console.error(`Error: ${message}`);
191
+ }
192
+ process.exit(EXIT_CODES.GENERIC);
193
+ }
194
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function readFileSafe(path: string): string;
2
+ //# sourceMappingURL=fs-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-utils.d.ts","sourceRoot":"","sources":["../../src/lib/fs-utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD"}
@@ -0,0 +1,16 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { CliError, ValidationError } from "./errors.js";
3
+ export function readFileSafe(path) {
4
+ try {
5
+ return readFileSync(path, "utf-8");
6
+ }
7
+ catch (err) {
8
+ const nodeErr = err;
9
+ if (nodeErr.code === "ENOENT")
10
+ throw new ValidationError(`File not found: ${path}`);
11
+ if (nodeErr.code === "EACCES")
12
+ throw new ValidationError(`Permission denied: ${path}`);
13
+ throw new CliError(`Failed to read file: ${path} — ${nodeErr.message}`);
14
+ }
15
+ }
16
+ //# sourceMappingURL=fs-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-utils.js","sourceRoot":"","sources":["../../src/lib/fs-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAA4B,CAAC;QAC7C,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,eAAe,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;QACpF,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,eAAe,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACvF,MAAM,IAAI,QAAQ,CAAC,wBAAwB,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Install a Claude Code SessionStart hook that captures the session id.
3
+ *
4
+ * The hook runs `cnotes claude-hook` at session start, which writes the current
5
+ * session id to a file (see lib/claude-session.ts). `cnotes operations begin` then
6
+ * stamps it on the operation row, so an agent run on the timeline can be traced
7
+ * back to — and resumed from — the conversation that produced it.
8
+ *
9
+ * Target: the USER-GLOBAL ~/.claude/settings.json (so capture works in every
10
+ * repo, not just one). We preserve all existing settings + other hooks, back up
11
+ * the file before writing, and are idempotent (a second install is a no-op).
12
+ *
13
+ * Unlike the MCP installer, a parse failure here ABORTS rather than starting
14
+ * fresh: settings.json holds the user's entire Claude Code config, so silently
15
+ * overwriting it would be destructive.
16
+ */
17
+ /** The user-global Claude Code settings file. */
18
+ export declare const CLAUDE_SETTINGS_PATH: string;
19
+ /** The command the hook runs when `cnotes` is on PATH (a global install). */
20
+ export declare const SESSION_HOOK_COMMAND = "cnotes claude-hook";
21
+ /**
22
+ * Fallback command for when `cnotes` won't be on PATH — e.g. the user ran
23
+ * `npx @creator-notes/cnotes init` without installing globally. Resolving the hook
24
+ * through npx keeps it working instead of failing `command not found` on every
25
+ * session start. Costs npx resolution latency per session, so we only use it
26
+ * when `cnotes` genuinely isn't available. `npx cnotes` does NOT resolve (the published
27
+ * package is @creator-notes/cnotes); detection tolerates this form for idempotency.
28
+ */
29
+ export declare const SESSION_HOOK_COMMAND_NPX = "npx @creator-notes/cnotes claude-hook";
30
+ export interface HookInstallResult {
31
+ configPath: string;
32
+ /** created → new file; installed → merged into existing; already-present →
33
+ * a claude-hook SessionStart entry was already there (no write). */
34
+ status: "created" | "installed" | "already-present";
35
+ backedUp?: string;
36
+ }
37
+ interface HookEntry {
38
+ type?: string;
39
+ command?: string;
40
+ }
41
+ interface HookGroup {
42
+ matcher?: string;
43
+ hooks?: HookEntry[];
44
+ }
45
+ interface ClaudeSettings {
46
+ hooks?: Record<string, HookGroup[]>;
47
+ [key: string]: unknown;
48
+ }
49
+ /**
50
+ * A plain JSON object — the only shape a Claude Code settings.json can validly
51
+ * take. Arrays, `null`, and primitives parse as valid JSON but aren't a config
52
+ * we can safely merge into, so callers treat them like a parse failure rather
53
+ * than silently clobbering the file. Exported for direct unit testing.
54
+ */
55
+ export declare function isPlainSettingsObject(value: unknown): value is ClaudeSettings;
56
+ /**
57
+ * Identify our entry by the `claude-hook` command (tolerates both the `cnotes` and
58
+ * `npx …` forms). Exported for direct unit testing.
59
+ */
60
+ export declare function groupHasSessionHook(group: HookGroup): boolean;
61
+ /** True when any SessionStart group already carries our hook. Exported for tests. */
62
+ export declare function settingsHaveSessionHook(settings: ClaudeSettings): boolean;
63
+ /**
64
+ * Rewrite any SessionStart hook that targets our `claude-hook` subcommand but
65
+ * isn't the command we're installing — e.g. a pre-rename `cn claude-hook` entry
66
+ * left dead once the `cn` binary was dropped — to `command`, in place. Returns
67
+ * true if anything changed. Exported for direct unit testing.
68
+ */
69
+ export declare function upgradeStaleSessionHooks(settings: ClaudeSettings, command: string): boolean;
70
+ /**
71
+ * True when a `cnotes claude-hook` SessionStart entry already exists. Read-only —
72
+ * lets callers skip prompting on re-runs without mutating anything. Returns
73
+ * false (rather than throwing) when the file is missing or unreadable.
74
+ */
75
+ export declare function isClaudeSessionHookInstalled(): boolean;
76
+ /**
77
+ * Idempotently add the SessionStart hook to ~/.claude/settings.json.
78
+ * Preserves existing settings + hooks, backs up an existing file first.
79
+ *
80
+ * @throws if an existing settings.json is present but not valid JSON — we will
81
+ * not overwrite the user's whole config; the caller should surface the manual
82
+ * install instructions instead.
83
+ */
84
+ export declare function installClaudeSessionHook(command?: string): HookInstallResult;
85
+ export {};
86
+ //# sourceMappingURL=install-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/lib/install-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAaH,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,QAAiD,CAAC;AAEnF,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,0CAA0C,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB;yEACqE;IACrE,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,iBAAiB,CAAC;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,SAAS;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AACD,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAE7E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAO7D;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAGzE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,GACd,OAAO,CAqBT;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAStD;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,MAA6B,GACrC,iBAAiB,CAsEnB"}