@edukors/ai-cli 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +162 -2
  3. package/dist/cli/main.d.ts +2 -0
  4. package/dist/cli/main.js +256 -0
  5. package/dist/cli/main.js.map +1 -0
  6. package/dist/constants.d.ts +2 -0
  7. package/dist/constants.js +3 -0
  8. package/dist/constants.js.map +1 -0
  9. package/dist/diagnostics.d.ts +28 -0
  10. package/dist/diagnostics.js +35 -0
  11. package/dist/diagnostics.js.map +1 -0
  12. package/dist/engine.d.ts +157 -0
  13. package/dist/engine.js +395 -0
  14. package/dist/engine.js.map +1 -0
  15. package/dist/errors.d.ts +27 -0
  16. package/dist/errors.js +59 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/events.d.ts +95 -0
  19. package/dist/events.js +8 -0
  20. package/dist/events.js.map +1 -0
  21. package/dist/host/main.d.ts +2 -0
  22. package/dist/host/main.js +30 -0
  23. package/dist/host/main.js.map +1 -0
  24. package/dist/host/stdio.d.ts +34 -0
  25. package/dist/host/stdio.js +254 -0
  26. package/dist/host/stdio.js.map +1 -0
  27. package/dist/index.d.ts +34 -0
  28. package/dist/index.js +21 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/mcp/config.d.ts +19 -0
  31. package/dist/mcp/config.js +63 -0
  32. package/dist/mcp/config.js.map +1 -0
  33. package/dist/mcp/external.d.ts +55 -0
  34. package/dist/mcp/external.js +129 -0
  35. package/dist/mcp/external.js.map +1 -0
  36. package/dist/mcp/toolServer.d.ts +30 -0
  37. package/dist/mcp/toolServer.js +102 -0
  38. package/dist/mcp/toolServer.js.map +1 -0
  39. package/dist/platform/discovery.d.ts +23 -0
  40. package/dist/platform/discovery.js +64 -0
  41. package/dist/platform/discovery.js.map +1 -0
  42. package/dist/platform/env.d.ts +12 -0
  43. package/dist/platform/env.js +104 -0
  44. package/dist/platform/env.js.map +1 -0
  45. package/dist/platform/login.d.ts +16 -0
  46. package/dist/platform/login.js +42 -0
  47. package/dist/platform/login.js.map +1 -0
  48. package/dist/platform/paths.d.ts +19 -0
  49. package/dist/platform/paths.js +46 -0
  50. package/dist/platform/paths.js.map +1 -0
  51. package/dist/platform/process.d.ts +55 -0
  52. package/dist/platform/process.js +186 -0
  53. package/dist/platform/process.js.map +1 -0
  54. package/dist/provider.d.ts +156 -0
  55. package/dist/provider.js +2 -0
  56. package/dist/provider.js.map +1 -0
  57. package/dist/providers/claude/adapter.d.ts +43 -0
  58. package/dist/providers/claude/adapter.js +398 -0
  59. package/dist/providers/claude/adapter.js.map +1 -0
  60. package/dist/providers/claude/events.d.ts +36 -0
  61. package/dist/providers/claude/events.js +90 -0
  62. package/dist/providers/claude/events.js.map +1 -0
  63. package/dist/providers/codex/adapter.d.ts +28 -0
  64. package/dist/providers/codex/adapter.js +497 -0
  65. package/dist/providers/codex/adapter.js.map +1 -0
  66. package/dist/providers/codex/rpc.d.ts +17 -0
  67. package/dist/providers/codex/rpc.js +75 -0
  68. package/dist/providers/codex/rpc.js.map +1 -0
  69. package/dist/providers.d.ts +9 -0
  70. package/dist/providers.js +15 -0
  71. package/dist/providers.js.map +1 -0
  72. package/dist/redact.d.ts +7 -0
  73. package/dist/redact.js +48 -0
  74. package/dist/redact.js.map +1 -0
  75. package/dist/registry/lock.d.ts +18 -0
  76. package/dist/registry/lock.js +83 -0
  77. package/dist/registry/lock.js.map +1 -0
  78. package/dist/registry/registry.d.ts +38 -0
  79. package/dist/registry/registry.js +119 -0
  80. package/dist/registry/registry.js.map +1 -0
  81. package/dist/session.d.ts +126 -0
  82. package/dist/session.js +333 -0
  83. package/dist/session.js.map +1 -0
  84. package/dist/settings.d.ts +8 -0
  85. package/dist/settings.js +7 -0
  86. package/dist/settings.js.map +1 -0
  87. package/dist/skills.d.ts +24 -0
  88. package/dist/skills.js +91 -0
  89. package/dist/skills.js.map +1 -0
  90. package/dist/testing/fakeProvider.d.ts +22 -0
  91. package/dist/testing/fakeProvider.js +266 -0
  92. package/dist/testing/fakeProvider.js.map +1 -0
  93. package/dist/testing/index.d.ts +2 -0
  94. package/dist/testing/index.js +2 -0
  95. package/dist/testing/index.js.map +1 -0
  96. package/dist/tools.d.ts +45 -0
  97. package/dist/tools.js +32 -0
  98. package/dist/tools.js.map +1 -0
  99. package/dist/version.d.ts +2 -0
  100. package/dist/version.js +3 -0
  101. package/dist/version.js.map +1 -0
  102. package/fixtures/fake-ai.mjs +230 -0
  103. package/fixtures/fake-claude.mjs +62 -0
  104. package/fixtures/fake-codex.mjs +281 -0
  105. package/fixtures/fake-mcp-server.mjs +14 -0
  106. package/package.json +74 -4
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Edukors.org - Maurício Garcia and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,163 @@
1
- # Temporary Holding Version
1
+ # edukors_ai_cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `@edukors/ai-cli` connects EDUKORS editors (Slides and Graph) to the AI provider CLIs installed on a user's computer. It gives both editors the same account and session behavior:
4
+
5
+ 1. Choose a provider.
6
+ 2. Connect an account.
7
+ 3. Select the account and start working.
8
+
9
+ The library handles CLI discovery, accounts, provider processes, sessions, interruption, tool routing, normalized events and redacted diagnostics. Each editor keeps its own document state, tools, validation, undo and UI.
10
+
11
+ > **Status: 0.1.0.** Shared core, Claude and Codex adapters, skills and the user's MCP servers, the stdio host and a deterministic fake provider. Both adapters are verified live (sign-in, isolation of two accounts, tools, questions, interruption, crash recovery); the Graph editor runs on the library. See [docs/compatibility.md](docs/compatibility.md) and [Roadmap](#roadmap).
12
+
13
+ ## Installing
14
+
15
+ ```sh
16
+ npm install @edukors/ai-cli@0.1.1
17
+ ```
18
+
19
+ Applications pin an exact version and commit their lockfile; a release of the library changes no installed application.
20
+
21
+ ## Requirements
22
+
23
+ - Node.js 22.12 or later.
24
+ - macOS is the tested platform. Linux and Windows code paths exist but have not been verified yet.
25
+
26
+ ## Try it without an editor
27
+
28
+ ```sh
29
+ npm install
30
+ npm test # the full suite, no accounts needed
31
+ npm run build
32
+
33
+ # Claude and Codex are always available (they need the user's own CLI installed).
34
+ # The fake provider is a real separate CLI process (fixtures/fake-ai.mjs).
35
+ alias ai="node dist/cli/main.js --fake --data-dir .sandbox"
36
+ ai providers
37
+ ai add fake Personal
38
+ ai connect Personal
39
+ ai status Personal
40
+ ai chat Personal --document lesson-1
41
+ ```
42
+
43
+ In `chat`, the fake provider responds to keywords: `tool append_paragraph {"text":"Hi"}`, `tool read_document`, `ask`, `slow` (press Ctrl+C to interrupt), `crash`, `rate-limit`, `env`. Anything else is echoed. The full list is at the top of `fixtures/fake-ai.mjs`.
44
+
45
+ Without `--data-dir`, the shared per-user directory is used: `~/Library/Application Support/EDUKORS` on macOS, `%LOCALAPPDATA%\EDUKORS` on Windows, `$XDG_DATA_HOME/edukors` on Linux. You can also set it with `EDUKORS_AI_DATA_DIR`.
46
+
47
+ ## Using the library
48
+
49
+ ```ts
50
+ import { createAiCli, defineTool } from "@edukors/ai-cli";
51
+ import { z } from "zod";
52
+
53
+ const ai = createAiCli({ appId: "graph", providers: [/* adapters */] });
54
+
55
+ const [detection] = await ai.detectAll(); // ready | missing | incompatible | error
56
+ const account = await ai.createAccount({ providerId: "claude", label: "Work" });
57
+ await ai.connectAccount(account.id); // the provider's own sign-in flow
58
+
59
+ const session = await ai.openSession({
60
+ accountId: account.id,
61
+ documentId: course.id,
62
+ instructions: "You edit the course on screen.",
63
+ tools: [
64
+ defineTool({
65
+ name: "set_title",
66
+ description: "Sets the course title.",
67
+ input: z.object({ title: z.string().min(1) }),
68
+ run: ({ title }, { signal }) => store.setTitle(title), // the editor validates and applies
69
+ }),
70
+ ],
71
+ });
72
+
73
+ session.on((event) => ui.handle(event)); // textDelta, activity, question, toolStarted, ...
74
+ const result = await session.send("Rename the course", { context: latestDocumentState });
75
+ await session.interrupt(); // committed edits stay; later output is dropped
76
+ ```
77
+
78
+ ### Skills and the user's MCP servers
79
+
80
+ ```ts
81
+ const session = await ai.openSession({
82
+ accountId, documentId, tools,
83
+ skillsDir: "/abs/path/to/skills", // <name>/SKILL.md; no other skill is enabled
84
+ mcpServers: { glossary: { command: "npx", args: ["glossary-mcp"] } }, // or { type: "http" | "sse", url }
85
+ authorize: async ({ server, tool, input }) => (await ui.confirm(`${server}: ${tool}`)) ? { allow: true } : { allow: false, message: "Declined." },
86
+ });
87
+ ```
88
+
89
+ Every editor's AI settings screen has the same layout (see section 6 of `edukors_ai_cli_plan.md`): **Accounts** at the top, and under **Advanced** always *Instructions for the agent*, *MCP servers* and *Skills*. `parseMcpConfig(text)` validates the MCP JSON (`{ "mcpServers": { ... } }` or the bare object, `timeout` in milliseconds) and returns every problem as a stable code; `listSkills(dir)` lists the skills folder for display.
90
+
91
+ The library connects to the user's servers itself and offers their tools to either provider. A provider is never handed a server directly: every call goes through `authorize`, and is reported as `toolStarted`/`toolCompleted` (`mcp__<server>__<tool>`). Without `authorize`, such calls are denied. Server status is reported once as `mcpServerStatus` events.
92
+
93
+ Claude Code loads the skills natively, through a local plugin. Codex would need shell commands to read them, so the library serves them through a `read_skill` tool confined to each skill's folder, and lists them in the session's developer instructions. In both cases the provider's own skills and the user's personal ones are switched off.
94
+
95
+ ### Guarantees
96
+
97
+ - **Scoped events.** Every event carries `appId`, `documentId`, `accountId`, `providerId` and `sessionId`. Events tied to a request also carry `requestId`.
98
+ - **No late output.** Once a request is interrupted, finished or replaced, any output the provider still sends is dropped. It never reaches the document, and no tool runs after cancellation. This is enforced by the library, not left to each adapter.
99
+ - **Recovery.** If a provider crashes, the request fails with `PROVIDER_CRASHED`. The next request restarts the provider and resumes the conversation when the provider supports it. A provider that ignores an interruption is shut down after a grace period.
100
+ - **Stable errors.** Every failure has a code from `ERROR_CODES` with structured metadata. Raw provider text goes only to diagnostics.
101
+ - **Honest capabilities.** Missing features (usage, models, logout, multiple accounts, ...) show up as capabilities and `CAPABILITY_UNSUPPORTED` errors. They are never simulated, and unknown usage is reported as unknown, not zero.
102
+ - **Isolated environment.** Provider processes get an allowlisted environment, so inherited credentials such as `ANTHROPIC_API_KEY` cannot override the selected account.
103
+
104
+ ### Accounts and the shared registry
105
+
106
+ Accounts live in `<data dir>/ai/registry.json` and are shared by every EDUKORS application of the same OS user. The registry holds only non-secret metadata: an immutable id, the provider, a label, and a reference to a managed directory. Credentials stay where the provider keeps them, inside that account's managed directory or the provider's own secure storage.
107
+
108
+ Writes are atomic (temporary file, flush, rename) and serialized across processes by a lock directory. The lock is refreshed while held and taken over if its owner dies. A library version never rewrites a registry whose `schemaVersion` it doesn't know, and preserves unknown fields when it does write.
109
+
110
+ Sessions are not shared. Their scratch space is under `ai/sessions/<appId>/<document hash>/<accountId>`.
111
+
112
+ Removing an account affects every editor on the computer. `removeAccount` removes the account from the registry. `logoutAccount` signs it out at the provider.
113
+
114
+ ## Application-host protocol
115
+
116
+ `edukors-ai-host --app-id graph` exposes the library over stdin/stdout, one JSON object per line. The Tauri editor runs it as a sidecar, and the Electron editor can run it in a worker process. The message shapes are documented at the top of `src/host/stdio.ts`. Tools are declared with JSON Schema in `session.open`, and the host calls back into the application with `tool.call`.
117
+
118
+ ```sh
119
+ printf '{"id":1,"method":"providers.detect"}\n' | node dist/host/main.js --app-id graph --fake --data-dir .sandbox
120
+ ```
121
+
122
+ ## Writing a provider adapter
123
+
124
+ Implement `ProviderAdapter` (see `src/provider.ts`). `src/testing/fakeProvider.ts` is a complete reference: short commands for detection, sign-in and status; a long-running process for the session; zod validation of everything read from the CLI; and `hooks.exited` for crashes. An adapter must:
125
+
126
+ - build its process environment with `buildEnv`, setting only that account's variables;
127
+ - use `ManagedProcess`/`runCommand`, never bare `spawn`, so timeouts, bounded output and process-tree cleanup apply;
128
+ - settle a pending `send` when `close()` is called or the process exits;
129
+ - report only the capabilities it has verified.
130
+
131
+ ## Layout
132
+
133
+ | Path | Contents |
134
+ | --- | --- |
135
+ | `src/engine.ts` | `AiCli`: providers, accounts, sessions, diagnostics |
136
+ | `src/session.ts` | Session lifecycle, late-event guard, tool routing, questions, recovery |
137
+ | `src/provider.ts` | The adapter contract |
138
+ | `src/events.ts`, `src/errors.ts` | Normalized events and stable error codes |
139
+ | `src/tools.ts` | Application tool definitions (`defineTool`) |
140
+ | `src/registry/` | Shared account registry and cross-process lock |
141
+ | `src/platform/` | Data paths, environment, CLI discovery, process management |
142
+ | `src/host/` | stdio application-host protocol and executable |
143
+ | `src/cli/` | `edukors-ai` terminal tool |
144
+ | `src/providers/claude/`, `src/providers/codex/` | Provider adapters |
145
+ | `src/mcp/` | MCP servers: the application's tools (in-process or local HTTP bridge) and the user's servers (client) |
146
+ | `src/skills.ts` | Skill folders: listing, confined reading, `read_skill` |
147
+ | `src/testing/`, `fixtures/` | Fake provider adapter and fake CLIs (`fake-ai`, `fake-claude`, `fake-codex`) |
148
+
149
+ ## Roadmap
150
+
151
+ Follows `edukors_ai_cli_plan.md`:
152
+
153
+ - [x] Phase 2: shared core, fake provider, contract tests, stdio host.
154
+ - [x] Phase 1 (offline part): compatibility matrix in `docs/compatibility.md`.
155
+ - [x] Phase 3 (offline part): Claude and Codex adapters, tested against fakes and against the real CLIs signed out.
156
+ - [x] Phases 1 and 3 (live part): sign-in, turns and isolation with two real accounts per provider.
157
+ - [x] Phase 4: Graph integration (on the Graph editor's `ai-cli-integration` branch).
158
+ - [ ] Phase 5: Slides integration.
159
+ - [ ] Phase 6: remaining providers, Windows/Linux verification, release.
160
+
161
+ ## License
162
+
163
+ MIT. See [LICENSE](LICENSE). Contributions: [CONTRIBUTING.md](CONTRIBUTING.md). Security reports: [SECURITY.md](SECURITY.md).
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,256 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `edukors-ai`: the library from a terminal, for trying it without either
4
+ * editor. It uses the same engine, registry and adapters the editors use.
5
+ */
6
+ import { createInterface } from "node:readline/promises";
7
+ import { parseArgs } from "node:util";
8
+ import { z } from "zod";
9
+ import { createAiCli } from "../engine.js";
10
+ import { isAiCliError } from "../errors.js";
11
+ import { bundledProviders } from "../providers.js";
12
+ import { defineTool } from "../tools.js";
13
+ const USAGE = `usage: edukors-ai [--data-dir <dir>] [--fake] <command>
14
+
15
+ providers installed providers and their capabilities
16
+ accounts accounts in the shared registry
17
+ add <provider> [label] register an account
18
+ rename <account> <label> change an account's label
19
+ remove <account> [--delete-data]
20
+ connect <account> sign in
21
+ status <account> sign-in state, without a model request
22
+ logout <account>
23
+ models <account>
24
+ chat <account> [--document <id>] [--model <id>]
25
+ diagnostics redacted diagnostic report (JSON)
26
+
27
+ <account> is an account id or label. --fake enables the test provider.
28
+ In chat, Ctrl+C stops the current request; Ctrl+D or /exit leaves.`;
29
+ const { values, positionals } = parseArgs({
30
+ allowPositionals: true,
31
+ options: {
32
+ "data-dir": { type: "string" },
33
+ "app-id": { type: "string", default: "cli" },
34
+ fake: { type: "boolean", default: false },
35
+ document: { type: "string", default: "scratch" },
36
+ model: { type: "string" },
37
+ "delete-data": { type: "boolean", default: false },
38
+ verbose: { type: "boolean", default: false },
39
+ help: { type: "boolean", short: "h", default: false },
40
+ },
41
+ });
42
+ const [command, ...args] = positionals;
43
+ if (!command || values.help) {
44
+ console.log(USAGE);
45
+ process.exit(command ? 0 : 2);
46
+ }
47
+ const ai = createAiCli({
48
+ appId: values["app-id"],
49
+ providers: bundledProviders({ fake: values.fake }),
50
+ ...(values["data-dir"] ? { dataDir: values["data-dir"] } : {}),
51
+ logSink: (e) => {
52
+ if (values.verbose)
53
+ process.stderr.write(`[${e.level}] ${e.scope}: ${e.message}\n`);
54
+ },
55
+ });
56
+ async function findAccount(ref) {
57
+ if (!ref)
58
+ throw new Error("an account is required");
59
+ const accounts = await ai.listAccounts();
60
+ const found = accounts.find((a) => a.id === ref) ?? accounts.filter((a) => a.label.toLowerCase() === ref.toLowerCase()).at(0);
61
+ if (!found)
62
+ throw new Error(`no account "${ref}"`);
63
+ return found;
64
+ }
65
+ const print = (value) => console.log(typeof value === "string" ? value : JSON.stringify(value, null, 2));
66
+ async function main() {
67
+ switch (command) {
68
+ case "providers": {
69
+ if (ai.providers().length === 0)
70
+ return print("No providers are available yet. Use --fake to try the test provider.");
71
+ for (const d of await ai.detectAll()) {
72
+ const caps = d.status === "ready" ? await ai.capabilities(d.providerId) : null;
73
+ print(`${d.providerId}\t${d.status}${d.version ? ` ${d.version}` : ""}${d.requiredVersion ? ` (needs ${d.requiredVersion})` : ""}`);
74
+ if (caps)
75
+ print(`\t${Object.entries(caps).filter(([, v]) => v === true).map(([k]) => k).join(", ")}; login: ${caps.login}`);
76
+ }
77
+ return;
78
+ }
79
+ case "accounts": {
80
+ const accounts = await ai.listAccounts();
81
+ if (accounts.length === 0)
82
+ return print("No accounts.");
83
+ for (const a of accounts)
84
+ print(`${a.id}\t${a.providerId}\t${a.label}${a.supported ? "" : "\t(provider not available here)"}`);
85
+ return;
86
+ }
87
+ case "add":
88
+ return print(await ai.createAccount({ providerId: args[0] ?? "", label: args.slice(1).join(" ") }));
89
+ case "rename":
90
+ return print(await ai.renameAccount((await findAccount(args[0])).id, args.slice(1).join(" ")));
91
+ case "remove":
92
+ await ai.removeAccount((await findAccount(args[0])).id, { deleteData: values["delete-data"] });
93
+ return print("Removed. Other EDUKORS applications on this computer no longer list it.");
94
+ case "connect":
95
+ return connect((await findAccount(args[0])).id);
96
+ case "status":
97
+ return print(await ai.accountStatus((await findAccount(args[0])).id));
98
+ case "logout":
99
+ await ai.logoutAccount((await findAccount(args[0])).id);
100
+ return print("Signed out.");
101
+ case "models":
102
+ return print(await ai.listModels((await findAccount(args[0])).id));
103
+ case "diagnostics":
104
+ return print(await ai.diagnosticReport());
105
+ case "chat":
106
+ return chat(ai, (await findAccount(args[0])).id);
107
+ default:
108
+ console.error(USAGE);
109
+ process.exitCode = 2;
110
+ }
111
+ }
112
+ /**
113
+ * Signs in. The browser normally finishes on its own; when it does not open,
114
+ * the address is shown here and, for providers that end with a code, the code
115
+ * typed (or piped) on the next line is passed on.
116
+ */
117
+ async function connect(accountId) {
118
+ let rl = null;
119
+ try {
120
+ const status = await ai.connectAccount(accountId, {
121
+ onLogin: ({ url, acceptsCode }) => {
122
+ console.error(`\nIf the browser did not open, sign in at:\n${url}\n`);
123
+ if (!acceptsCode)
124
+ return;
125
+ rl = createInterface({ input: process.stdin, output: process.stderr, terminal: process.stdin.isTTY });
126
+ rl.setPrompt("Paste the code shown after signing in (or finish in the browser): ");
127
+ rl.prompt();
128
+ rl.once("line", (line) => {
129
+ try {
130
+ if (line.trim())
131
+ ai.submitLoginCode(accountId, line);
132
+ }
133
+ catch (e) {
134
+ console.error(isAiCliError(e) ? `[${e.code}] ${e.message}` : String(e));
135
+ }
136
+ });
137
+ },
138
+ });
139
+ print(status);
140
+ }
141
+ finally {
142
+ rl?.close();
143
+ }
144
+ }
145
+ /** A small in-memory document, so tool calls can be tried from the terminal. */
146
+ function demoTools(paragraphs) {
147
+ return [
148
+ defineTool({
149
+ name: "read_document",
150
+ description: "Returns the document's paragraphs, numbered.",
151
+ input: z.object({}),
152
+ run: () => ({ content: paragraphs.map((p, i) => `${i + 1}. ${p}`).join("\n") || "(empty)" }),
153
+ }),
154
+ defineTool({
155
+ name: "append_paragraph",
156
+ description: "Adds a paragraph at the end of the document.",
157
+ input: z.object({ text: z.string().min(1) }),
158
+ run: ({ text }) => {
159
+ paragraphs.push(text);
160
+ return { content: `Added paragraph ${paragraphs.length}.` };
161
+ },
162
+ }),
163
+ ];
164
+ }
165
+ async function chat(ai, accountId) {
166
+ const paragraphs = [];
167
+ const session = await ai.openSession({
168
+ accountId,
169
+ documentId: values.document,
170
+ instructions: "You are helping edit a short document through the read_document and append_paragraph tools.",
171
+ tools: demoTools(paragraphs),
172
+ ...(values.model ? { options: { model: values.model } } : {}),
173
+ });
174
+ const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: process.stdin.isTTY });
175
+ let busy = false;
176
+ const questions = [];
177
+ /** Resolves when the current request ends or asks something. */
178
+ let wake = null;
179
+ session.on((e) => {
180
+ switch (e.type) {
181
+ case "textDelta":
182
+ process.stdout.write(e.text);
183
+ break;
184
+ case "activity":
185
+ process.stderr.write(`\x1b[2m[${e.phase}]\x1b[0m `);
186
+ break;
187
+ case "toolStarted":
188
+ process.stderr.write(`\x1b[2m[tool ${e.tool}]\x1b[0m `);
189
+ break;
190
+ case "toolCompleted":
191
+ if (!e.ok)
192
+ process.stderr.write(`\x1b[33m[${e.tool} failed: ${e.errorCode}]\x1b[0m `);
193
+ break;
194
+ case "question":
195
+ questions.push(e.questionId);
196
+ process.stdout.write(`\n? ${e.prompt}${e.options ? ` (${e.options.join(" / ")})` : ""}\n`);
197
+ wake?.();
198
+ break;
199
+ case "usageUpdated":
200
+ process.stderr.write(`\x1b[2m[tokens in ${e.usage.inputTokens ?? "?"}, out ${e.usage.outputTokens ?? "?"}]\x1b[0m`);
201
+ break;
202
+ case "error":
203
+ process.stderr.write(`\n\x1b[31m[${e.error.code}] ${e.error.message}\x1b[0m`);
204
+ break;
205
+ case "cancelled":
206
+ process.stderr.write("\n[stopped]");
207
+ break;
208
+ }
209
+ });
210
+ rl.on("SIGINT", () => {
211
+ if (busy)
212
+ void session.interrupt();
213
+ else
214
+ rl.close();
215
+ });
216
+ const prompt = () => {
217
+ rl.setPrompt(questions.length ? "answer> " : "\n> ");
218
+ rl.prompt();
219
+ };
220
+ print(`Session ${session.id} on document "${values.document}". Type /exit to leave.`);
221
+ prompt();
222
+ // Lines typed (or piped) while a request runs are buffered by the iterator.
223
+ for await (const raw of rl) {
224
+ const line = raw.trim();
225
+ if (line === "/exit")
226
+ break;
227
+ const question = questions.shift();
228
+ if (question)
229
+ session.answer(question, line);
230
+ else if (line) {
231
+ busy = true;
232
+ void session.send(line).finally(() => {
233
+ busy = false;
234
+ wake?.();
235
+ });
236
+ }
237
+ if (busy)
238
+ await new Promise((resolve) => (wake = resolve));
239
+ wake = null;
240
+ if (!busy)
241
+ process.stdout.write("\n");
242
+ prompt();
243
+ }
244
+ rl.close();
245
+ }
246
+ try {
247
+ await main();
248
+ }
249
+ catch (e) {
250
+ console.error(isAiCliError(e) ? `[${e.code}] ${e.message}` : e instanceof Error ? e.message : String(e));
251
+ process.exitCode = 1;
252
+ }
253
+ finally {
254
+ await ai.dispose();
255
+ }
256
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** The name of the application's own MCP server: tools reach the model as `mcp__edukors__<tool>`. */
2
+ export declare const TOOL_SERVER_NAME = "edukors";
@@ -0,0 +1,3 @@
1
+ /** The name of the application's own MCP server: tools reach the model as `mcp__edukors__<tool>`. */
2
+ export const TOOL_SERVER_NAME = "edukors";
3
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC"}
@@ -0,0 +1,28 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ export interface DiagnosticEntry {
3
+ at: string;
4
+ level: LogLevel;
5
+ scope: string;
6
+ message: string;
7
+ meta?: unknown;
8
+ }
9
+ export type LogSink = (entry: DiagnosticEntry) => void;
10
+ /**
11
+ * A bounded, redacted log. Everything recorded here is safe to export: the
12
+ * redaction happens on the way in, so a forgotten call site cannot leak.
13
+ */
14
+ export declare class Diagnostics {
15
+ private readonly capacity;
16
+ private readonly sink?;
17
+ private readonly entries;
18
+ constructor(capacity?: number, sink?: LogSink | undefined);
19
+ log(level: LogLevel, scope: string, message: string, meta?: unknown): void;
20
+ scoped(scope: string): ScopedLog;
21
+ snapshot(): DiagnosticEntry[];
22
+ }
23
+ export interface ScopedLog {
24
+ debug(message: string, meta?: unknown): void;
25
+ info(message: string, meta?: unknown): void;
26
+ warn(message: string, meta?: unknown): void;
27
+ error(message: string, meta?: unknown): void;
28
+ }
@@ -0,0 +1,35 @@
1
+ import { redactText, redactValue } from "./redact.js";
2
+ /**
3
+ * A bounded, redacted log. Everything recorded here is safe to export: the
4
+ * redaction happens on the way in, so a forgotten call site cannot leak.
5
+ */
6
+ export class Diagnostics {
7
+ capacity;
8
+ sink;
9
+ entries = [];
10
+ constructor(capacity = 500, sink) {
11
+ this.capacity = capacity;
12
+ this.sink = sink;
13
+ }
14
+ log(level, scope, message, meta) {
15
+ const entry = { at: new Date().toISOString(), level, scope, message: redactText(message) };
16
+ if (meta !== undefined)
17
+ entry.meta = redactValue(meta);
18
+ this.entries.push(entry);
19
+ if (this.entries.length > this.capacity)
20
+ this.entries.splice(0, this.entries.length - this.capacity);
21
+ this.sink?.(entry);
22
+ }
23
+ scoped(scope) {
24
+ return {
25
+ debug: (message, meta) => this.log("debug", scope, message, meta),
26
+ info: (message, meta) => this.log("info", scope, message, meta),
27
+ warn: (message, meta) => this.log("warn", scope, message, meta),
28
+ error: (message, meta) => this.log("error", scope, message, meta),
29
+ };
30
+ }
31
+ snapshot() {
32
+ return this.entries.slice();
33
+ }
34
+ }
35
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AActD;;;GAGG;AACH,MAAM,OAAO,WAAW;IAIH;IACA;IAJF,OAAO,GAAsB,EAAE,CAAC;IAEjD,YACmB,WAAW,GAAG,EACd,IAAc;QADd,aAAQ,GAAR,QAAQ,CAAM;QACd,SAAI,GAAJ,IAAI,CAAU;IAC9B,CAAC;IAEJ,GAAG,CAAC,KAAe,EAAE,KAAa,EAAE,OAAe,EAAE,IAAc;QACjE,MAAM,KAAK,GAAoB,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5G,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,OAAO;YACL,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;YACjE,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;YAC/D,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;YAC/D,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;SAClE,CAAC;IACJ,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;CACF"}