@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.
- package/LICENSE +9 -0
- package/README.md +162 -2
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +256 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +3 -0
- package/dist/constants.js.map +1 -0
- package/dist/diagnostics.d.ts +28 -0
- package/dist/diagnostics.js +35 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/engine.d.ts +157 -0
- package/dist/engine.js +395 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +95 -0
- package/dist/events.js +8 -0
- package/dist/events.js.map +1 -0
- package/dist/host/main.d.ts +2 -0
- package/dist/host/main.js +30 -0
- package/dist/host/main.js.map +1 -0
- package/dist/host/stdio.d.ts +34 -0
- package/dist/host/stdio.js +254 -0
- package/dist/host/stdio.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/config.d.ts +19 -0
- package/dist/mcp/config.js +63 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/external.d.ts +55 -0
- package/dist/mcp/external.js +129 -0
- package/dist/mcp/external.js.map +1 -0
- package/dist/mcp/toolServer.d.ts +30 -0
- package/dist/mcp/toolServer.js +102 -0
- package/dist/mcp/toolServer.js.map +1 -0
- package/dist/platform/discovery.d.ts +23 -0
- package/dist/platform/discovery.js +64 -0
- package/dist/platform/discovery.js.map +1 -0
- package/dist/platform/env.d.ts +12 -0
- package/dist/platform/env.js +104 -0
- package/dist/platform/env.js.map +1 -0
- package/dist/platform/login.d.ts +16 -0
- package/dist/platform/login.js +42 -0
- package/dist/platform/login.js.map +1 -0
- package/dist/platform/paths.d.ts +19 -0
- package/dist/platform/paths.js +46 -0
- package/dist/platform/paths.js.map +1 -0
- package/dist/platform/process.d.ts +55 -0
- package/dist/platform/process.js +186 -0
- package/dist/platform/process.js.map +1 -0
- package/dist/provider.d.ts +156 -0
- package/dist/provider.js +2 -0
- package/dist/provider.js.map +1 -0
- package/dist/providers/claude/adapter.d.ts +43 -0
- package/dist/providers/claude/adapter.js +398 -0
- package/dist/providers/claude/adapter.js.map +1 -0
- package/dist/providers/claude/events.d.ts +36 -0
- package/dist/providers/claude/events.js +90 -0
- package/dist/providers/claude/events.js.map +1 -0
- package/dist/providers/codex/adapter.d.ts +28 -0
- package/dist/providers/codex/adapter.js +497 -0
- package/dist/providers/codex/adapter.js.map +1 -0
- package/dist/providers/codex/rpc.d.ts +17 -0
- package/dist/providers/codex/rpc.js +75 -0
- package/dist/providers/codex/rpc.js.map +1 -0
- package/dist/providers.d.ts +9 -0
- package/dist/providers.js +15 -0
- package/dist/providers.js.map +1 -0
- package/dist/redact.d.ts +7 -0
- package/dist/redact.js +48 -0
- package/dist/redact.js.map +1 -0
- package/dist/registry/lock.d.ts +18 -0
- package/dist/registry/lock.js +83 -0
- package/dist/registry/lock.js.map +1 -0
- package/dist/registry/registry.d.ts +38 -0
- package/dist/registry/registry.js +119 -0
- package/dist/registry/registry.js.map +1 -0
- package/dist/session.d.ts +126 -0
- package/dist/session.js +333 -0
- package/dist/session.js.map +1 -0
- package/dist/settings.d.ts +8 -0
- package/dist/settings.js +7 -0
- package/dist/settings.js.map +1 -0
- package/dist/skills.d.ts +24 -0
- package/dist/skills.js +91 -0
- package/dist/skills.js.map +1 -0
- package/dist/testing/fakeProvider.d.ts +22 -0
- package/dist/testing/fakeProvider.js +266 -0
- package/dist/testing/fakeProvider.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tools.d.ts +45 -0
- package/dist/tools.js +32 -0
- package/dist/tools.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/fixtures/fake-ai.mjs +230 -0
- package/fixtures/fake-claude.mjs +62 -0
- package/fixtures/fake-codex.mjs +281 -0
- package/fixtures/fake-mcp-server.mjs +14 -0
- 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
|
-
#
|
|
1
|
+
# edukors_ai_cli
|
|
2
2
|
|
|
3
|
-
|
|
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).
|
package/dist/cli/main.js
ADDED
|
@@ -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 @@
|
|
|
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"}
|