@stjbrown/agent-knowledge 0.1.0-beta.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 (38) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +44 -0
  3. package/README.md +212 -0
  4. package/dist/chunk-3XSOMUQQ.js +131 -0
  5. package/dist/chunk-3XSOMUQQ.js.map +1 -0
  6. package/dist/chunk-J4MELCGD.js +114 -0
  7. package/dist/chunk-J4MELCGD.js.map +1 -0
  8. package/dist/chunk-YIAVFL7A.js +1732 -0
  9. package/dist/chunk-YIAVFL7A.js.map +1 -0
  10. package/dist/headless.js +11 -0
  11. package/dist/headless.js.map +1 -0
  12. package/dist/index.js +16 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/main.js +373 -0
  15. package/dist/main.js.map +1 -0
  16. package/dist/tui-VZVO7UHV.js +521 -0
  17. package/dist/tui-VZVO7UHV.js.map +1 -0
  18. package/package.json +72 -0
  19. package/skills/kb/SKILL.md +54 -0
  20. package/skills/kb/example-bundle/concepts/customers.md +15 -0
  21. package/skills/kb/example-bundle/concepts/orders.md +19 -0
  22. package/skills/kb/example-bundle/index.md +20 -0
  23. package/skills/kb/example-bundle/log.md +6 -0
  24. package/skills/kb/example-bundle/spec/conventions.md +36 -0
  25. package/skills/kb/example-bundle/spec/types.md +23 -0
  26. package/skills/kb/references/SPEC.md +451 -0
  27. package/skills/kb/references/glossary.md +61 -0
  28. package/skills/kb/references/trust-model.md +79 -0
  29. package/skills/kb/templates/concept.md +22 -0
  30. package/skills/kb/templates/index.md +17 -0
  31. package/skills/kb/templates/log.md +13 -0
  32. package/skills/kb-ingest/SKILL.md +128 -0
  33. package/skills/kb-init/SKILL.md +79 -0
  34. package/skills/kb-lint/SKILL.md +77 -0
  35. package/skills/kb-lint/scripts/conformance.mjs +7537 -0
  36. package/skills/kb-query/SKILL.md +81 -0
  37. package/skills/kb-visualize/SKILL.md +72 -0
  38. package/skills/kb-visualize/scripts/graph.mjs +7520 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 stjbrown
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,44 @@
1
+ agent-knowledge
2
+ Copyright (c) 2026 stjbrown
3
+
4
+ This project is licensed under the MIT License (see LICENSE).
5
+
6
+ ------------------------------------------------------------------------
7
+ Third-party material
8
+ ------------------------------------------------------------------------
9
+
10
+ skills/kb/references/SPEC.md is a verbatim copy of the Open Knowledge Format
11
+ (OKF) v0.1 specification from:
12
+
13
+ https://github.com/GoogleCloudPlatform/knowledge-catalog (okf/SPEC.md)
14
+
15
+ That file is licensed under the Apache License, Version 2.0, and is included
16
+ and used under those terms.
17
+
18
+ ------------------------------------------------------------------------
19
+
20
+ Portions of packages/janet/src (the Amazon Bedrock gateway, and — when added —
21
+ the OAuth auth subsystem under src/auth) are adapted from MastraCode
22
+ (https://github.com/mastra-ai/mastra, the mastracode package), licensed under
23
+ the Apache License, Version 2.0. Adapted and used under those terms.
24
+
25
+ ------------------------------------------------------------------------
26
+
27
+ The generated conformance and graph tools bundle `yaml` by Eemeli Aro
28
+ (https://github.com/eemeli/yaml), licensed under the ISC License:
29
+
30
+ Copyright Eemeli Aro <eemeli@gmail.com>
31
+
32
+ Permission to use, copy, modify, and/or distribute this software for any
33
+ purpose with or without fee is hereby granted, provided that the above
34
+ copyright notice and this permission notice appear in all copies.
35
+
36
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
37
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
38
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
39
+ SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
41
+ OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
42
+ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43
+
44
+ All other files in this repository are MIT-licensed as described in LICENSE.
package/README.md ADDED
@@ -0,0 +1,212 @@
1
+ # agent-knowledge
2
+
3
+ **Agent Knowledge is a portable LLM wiki system for building and maintaining project knowledge in
4
+ plain Markdown using the Open Knowledge Format (OKF).**
5
+
6
+ It turns project documents, decisions, notes, and conversations into a connected knowledge base
7
+ that improves over time. Ask a question and get a cited answer. Add a source and the agent
8
+ integrates it with what the project already knows. Run a health check and it finds stale claims,
9
+ contradictions, and orphaned pages before the wiki quietly rots.
10
+
11
+ Everything remains plain Markdown: readable without special tooling, easy to diff and review, and
12
+ portable across agents.
13
+
14
+ ## From skills to Janet
15
+
16
+ Agent Knowledge began as a family of portable [Agent Skills](https://agentskills.io) called `kb-*`.
17
+ You could add them to Claude Code, Cursor, Codex, or another coding agent and teach the agent you
18
+ already use how to create, query, and maintain an OKF knowledge bundle.
19
+
20
+ Those skills are still the core of the project. Agent Knowledge has since evolved to include
21
+ **Janet**, a dedicated knowledge agent built around the same skills. Janet gives the workflow its
22
+ own CLI, interactive chat, model selection, authentication, and headless mode, while keeping the
23
+ knowledge itself open and independent of her runtime.
24
+
25
+ Janet is one way to use Agent Knowledge, not a requirement. You can:
26
+
27
+ **1. Add the skills to the agent you already use.** Install the `kb-*` skills in Claude Code,
28
+ Cursor, Codex, or one of 20+ other hosts. No new runtime is required.
29
+
30
+ **2. Run Janet directly (`npx @stjbrown/agent-knowledge@next`).** Chat with a self-contained
31
+ knowledge agent in any project, or drive her headlessly from scripts and CI. Bring your own model,
32
+ including Claude, Gemini, or GPT, through Google Vertex, Amazon Bedrock, API keys, or a Claude Max or
33
+ ChatGPT subscription.
34
+
35
+ **3. Call Janet as a subagent.** Delegate ingestion, research, queries, and knowledge maintenance to
36
+ a focused subagent while your primary agent stays on the larger task. The subagent can use Janet's
37
+ headless CLI or load the same `kb-*` skills directly.
38
+
39
+ Every mode is powered by the same `kb-*` skills. The standalone Janet CLI adds its own runtime,
40
+ model selection, and TUI around them.
41
+
42
+ ---
43
+
44
+ ## Janet
45
+
46
+ Janet (after *The Good Place*'s all-knowing repository-of-knowledge) is the standalone agent. She
47
+ operates on the **current directory**: run her in `~/project/` and the bundle is `~/project/knowledge/`,
48
+ with conversation history scoped to that project.
49
+
50
+ `--bundle <path>` may select a different bundle inside the project. Janet intentionally rejects
51
+ bundle paths outside the project workspace so its filesystem boundary remains meaningful.
52
+
53
+ ```bash
54
+ # Interactive preview (also installed as `ding`, because you summon Janet with a ding)
55
+ npx @stjbrown/agent-knowledge@next
56
+ # or, once installed globally:
57
+ janet
58
+ ```
59
+
60
+ First run walks you through picking a model from the providers you actually have configured. After
61
+ that:
62
+
63
+ ```bash
64
+ janet init # scaffold a knowledge/ bundle here
65
+ janet ingest ./notes/rfc-42.md # read a source and integrate it
66
+ janet query "how does auth work, and what supports it?"
67
+ janet lint # conformance + drift audit
68
+ janet viz # write an interactive graph (knowledge/graph.html)
69
+ ```
70
+
71
+ Add `-p` (or pipe/redirect) for **headless** one-shot mode — streams to stdout, exits on completion,
72
+ CI-friendly. Headless query/lint runs are read-only; init/ingest/viz may edit the workspace, while
73
+ shell commands and Git commits require explicit `--allow-exec`. `janet lint` runs a deterministic,
74
+ token-free OKF conformance check before the agent's drift audit, so it is usable as a CI gate.
75
+
76
+ **Inside the chat:**
77
+
78
+ | Command | |
79
+ |---|---|
80
+ | `/models` · `/model [id]` | pick a model from an arrow-key list, or switch by id |
81
+ | `/login <anthropic\|openai-codex> [browser\|device]` · `/logout` · `/auth` | subscription sign-in and status; device mode is available for remote OpenAI login |
82
+ | `/help` · `/quit` | help; exit (or double Ctrl+C) |
83
+
84
+ Just type to talk to Janet; ↑/↓ recalls previous prompts.
85
+
86
+ **Models & providers.** No default provider — you choose. Janet supports Google Vertex AI (Claude +
87
+ Gemini, via ADC/service account), Amazon Bedrock (AWS credential chain), Anthropic and OpenAI (API
88
+ key **or** subscription OAuth), and Google Gemini (API key). Set the choice once (`--model`,
89
+ `JANET_MODEL`, or the first-run picker) and it persists.
90
+
91
+ Janet is built on [Mastra](https://mastra.ai) and lives in
92
+ [`packages/janet`](https://github.com/stjbrown/agent-knowledge/tree/janet-agent/packages/janet)
93
+ (published as `@stjbrown/agent-knowledge`, bins `janet` + `ding`). She also reports lifecycle state
94
+ natively to [Herdr](https://herdr.dev) when run inside a Herdr pane.
95
+
96
+ ---
97
+
98
+ ## The skills
99
+
100
+ Install via [skills.sh](https://skills.sh) for Claude Code, Cursor, Codex, and 20+ other agents:
101
+
102
+ ```bash
103
+ npx skills@latest add stjbrown/agent-knowledge
104
+ ```
105
+
106
+ Or as a Claude Code plugin:
107
+
108
+ ```text
109
+ /plugin marketplace add stjbrown/agent-knowledge
110
+ /plugin install agent-knowledge
111
+ ```
112
+
113
+ Then start a knowledge base and use ordinary prompts:
114
+
115
+ ```text
116
+ /kb-init
117
+
118
+ Ingest this architecture decision: we chose Postgres because...
119
+ What do we know about authentication, and which sources support it?
120
+ What conflicts with our current deployment strategy?
121
+
122
+ /kb-lint # find broken links, stale claims, contradictions, and gaps
123
+ /kb-visualize # explore the bundle as an interactive graph
124
+ ```
125
+
126
+ ![Interactive knowledge graph showing concepts, implementations, operations, references, and OKF spec sections](https://raw.githubusercontent.com/stjbrown/agent-knowledge/janet-agent/assets/knowledge-graph.png)
127
+
128
+ The family splits on **who invokes them**. **Model-invoked** skills the agent reaches for on its own
129
+ when the task fits; **user-invoked** skills you trigger deliberately by name.
130
+
131
+ **Model-invoked**
132
+
133
+ - **`kb`** — the hub. Explains the format, holds the shared spec / glossary / trust model /
134
+ templates, and routes to the right skill. Other `kb-*` skills read its reference as their single
135
+ source of truth.
136
+ - **`kb-ingest`** — read a raw source once, extract its signal, and integrate it across the bundle
137
+ under the trust model. The heart of the system.
138
+ - **`kb-query`** — answer a question from the bundle (or surface relevant context for another task)
139
+ by progressive disclosure, cite the concepts used, and file valuable answers back so the base
140
+ compounds.
141
+
142
+ **User-invoked**
143
+
144
+ - **`kb-init`** — scaffold a new bundle (default `knowledge/`, custom path, multi-bundle aware) and
145
+ write its per-project schema layer (concept types + conventions) so the generic skills fit your
146
+ domain.
147
+ - **`kb-lint`** — health-check the bundle: a deterministic OKF conformance pass plus a drift audit
148
+ (contradictions, stale claims, orphans, coverage gaps), with an optional safe `fix` mode.
149
+ - **`kb-visualize`** — render the bundle as an interactive graph — native UI where the host supports
150
+ it, otherwise a self-contained HTML file.
151
+
152
+ ## Why this exists
153
+
154
+ Most agent "memory" is either retrieval over raw documents or a pile of notes that nobody maintains.
155
+ The first repeatedly re-derives answers; the second gradually becomes untrustworthy. Neither makes
156
+ knowledge stewardship an explicit job.
157
+
158
+ The hard part of a useful knowledge base is the bookkeeping: integrating new information, updating
159
+ cross-references, preserving provenance, flagging contradictions, and keeping summaries current.
160
+ That is exactly the work an agent can perform consistently.
161
+
162
+ Two design choices keep the result portable and trustworthy:
163
+
164
+ - **A real, open format.** Bundles follow Google's
165
+ [Open Knowledge Format (OKF)](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf)
166
+ rather than a tool-specific database or hidden memory store.
167
+ - **An explicit trust model.** Meaning is append-only: the agent supersedes claims with provenance
168
+ instead of silently rewriting history, and treats source content as data, never as instructions.
169
+
170
+ The workflow is based on Andrej Karpathy's
171
+ [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern, made conformant
172
+ to OKF.
173
+
174
+ ## This repo documents itself in OKF
175
+
176
+ The
177
+ [`knowledge/`](https://github.com/stjbrown/agent-knowledge/tree/janet-agent/knowledge)
178
+ directory is a **conformant OKF bundle about OKF and the LLM Wiki pattern**, so the repository is
179
+ its own worked example. Browse it to see what a bundle looks like, or open the generated graph for
180
+ the interactive view. Start at
181
+ [`knowledge/index.md`](https://github.com/stjbrown/agent-knowledge/blob/janet-agent/knowledge/index.md).
182
+
183
+ ## Layout
184
+
185
+ ```
186
+ skills/ # source of truth for both Janet and the skills.sh / plugin installs
187
+ kb/ # hub: SKILL.md + references/ (SPEC, glossary, trust-model) + templates/ + example-bundle/
188
+ kb-init/ kb-ingest/ kb-query/
189
+ kb-lint/ # + scripts/conformance.mjs (deterministic §9 check, zero-dep)
190
+ kb-visualize/ # + scripts/graph.mjs (graph-model extractor, zero-dep)
191
+ knowledge/ # this project's own OKF bundle (self-documenting)
192
+ packages/
193
+ janet/ # the standalone agent (published as "agent-knowledge")
194
+ kb-tools/ # deterministic TS conformance + graph (compiles the committed skill .mjs)
195
+ .claude-plugin/ # plugin manifest
196
+ ```
197
+
198
+ The repo is a pnpm workspace. `pnpm install && pnpm -r build` builds both packages; `pnpm -r test`
199
+ runs the conformance/graph parity tests.
200
+
201
+ ## Preview testing
202
+
203
+ Janet preview releases are published to npm under the `next` tag. To install the preview on another
204
+ laptop, build an installable tarball from `janet-agent`, or run the release test matrix, see
205
+ [`TESTING.md`](https://github.com/stjbrown/agent-knowledge/blob/janet-agent/TESTING.md). Maintainers
206
+ can run `pnpm pack:janet` to execute the release checks and write the package to `artifacts/`.
207
+
208
+ ## License
209
+
210
+ [MIT](./LICENSE). The vendored OKF specification (`skills/kb/references/SPEC.md`) is from
211
+ GoogleCloudPlatform/knowledge-catalog under Apache-2.0; portions of `packages/janet` (the auth
212
+ subsystem and Bedrock gateway) are adapted from MastraCode under Apache-2.0. See [NOTICE](./NOTICE).
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __janetCreateRequire } from "node:module";
3
+ const require = __janetCreateRequire(import.meta.url);
4
+ import {
5
+ appDataDir,
6
+ getAuthStorage,
7
+ hasAwsCredentials,
8
+ hasGoogleCredentials
9
+ } from "./chunk-YIAVFL7A.js";
10
+
11
+ // src/onboarding/settings.ts
12
+ import { mkdirSync, readFileSync, writeFileSync } from "fs";
13
+ import { dirname, join } from "path";
14
+ var ONBOARDING_VERSION = 1;
15
+ function settingsPath() {
16
+ return join(appDataDir(), "settings.json");
17
+ }
18
+ function loadSettings() {
19
+ try {
20
+ return JSON.parse(readFileSync(settingsPath(), "utf-8"));
21
+ } catch {
22
+ return {};
23
+ }
24
+ }
25
+ function saveSettings(settings) {
26
+ const p = settingsPath();
27
+ mkdirSync(dirname(p), { recursive: true });
28
+ writeFileSync(p, JSON.stringify(settings, null, 2) + "\n", "utf-8");
29
+ }
30
+ function completeOnboarding(modelId, stampedAt) {
31
+ const settings = loadSettings();
32
+ settings.defaultModelId = modelId;
33
+ settings.onboarding = { completedAt: stampedAt, version: ONBOARDING_VERSION };
34
+ saveSettings(settings);
35
+ }
36
+ function rememberModel(modelId) {
37
+ const id = modelId.trim();
38
+ if (!id) return;
39
+ const settings = loadSettings();
40
+ const rest = (settings.customModels ?? []).filter((m) => m !== id);
41
+ settings.customModels = [id, ...rest].slice(0, 20);
42
+ saveSettings(settings);
43
+ }
44
+
45
+ // src/onboarding/providers.ts
46
+ var CODEX_MODELS = [
47
+ { id: "gpt-5.6-sol", label: "GPT-5.6 Sol" },
48
+ { id: "gpt-5.6-terra", label: "GPT-5.6 Terra" },
49
+ { id: "gpt-5.6-luna", label: "GPT-5.6 Luna" },
50
+ { id: "gpt-5.5", label: "GPT-5.5" },
51
+ { id: "gpt-5.4", label: "GPT-5.4" },
52
+ { id: "gpt-5.4-mini", label: "GPT-5.4 Mini" }
53
+ ];
54
+ var LEGACY_CODEX_MODEL_IDS = {
55
+ "gpt-5.6-codex": "openai/gpt-5.6-sol",
56
+ "openai/gpt-5.6-codex": "openai/gpt-5.6-sol",
57
+ "gpt-5.5-codex": "openai/gpt-5.5",
58
+ "openai/gpt-5.5-codex": "openai/gpt-5.5"
59
+ };
60
+ function normalizeModelSelection(modelId, choices) {
61
+ const id = modelId.trim();
62
+ const legacy = LEGACY_CODEX_MODEL_IDS[id];
63
+ if (legacy) return legacy;
64
+ if (!id || id.includes("/")) return id;
65
+ const matches = choices.filter((choice) => choice.id.endsWith(`/${id}`));
66
+ return matches.length === 1 ? matches[0].id : id;
67
+ }
68
+ function hasOAuth(provider) {
69
+ try {
70
+ const s = getAuthStorage();
71
+ s.reload();
72
+ return s.get(provider)?.type === "oauth";
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+ function hasEnv(...vars) {
78
+ return vars.some((v) => !!process.env[v]);
79
+ }
80
+ function availableModels() {
81
+ const out = [];
82
+ if (hasGoogleCredentials()) {
83
+ const via = "Vertex AI (ADC)";
84
+ out.push(
85
+ { id: "vertex/claude-opus-4-8", label: "Claude Opus 4.8", via },
86
+ { id: "vertex/claude-sonnet-4-5", label: "Claude Sonnet 4.5", via },
87
+ { id: "vertex/gemini-2.5-pro", label: "Gemini 2.5 Pro", via }
88
+ );
89
+ }
90
+ if (hasEnv("ANTHROPIC_API_KEY") || hasOAuth("anthropic")) {
91
+ const via = hasOAuth("anthropic") ? "Anthropic (Claude Max)" : "Anthropic (API key)";
92
+ out.push(
93
+ { id: "anthropic/claude-opus-4-6", label: "Claude Opus 4.6", via },
94
+ { id: "anthropic/claude-sonnet-4-5", label: "Claude Sonnet 4.5", via }
95
+ );
96
+ }
97
+ if (hasOAuth("openai-codex")) {
98
+ const via = "OpenAI (ChatGPT/Codex)";
99
+ for (const m of CODEX_MODELS) out.push({ id: `openai/${m.id}`, label: m.label, via });
100
+ } else if (hasEnv("OPENAI_API_KEY")) {
101
+ out.push({ id: "openai/gpt-5.5", label: "GPT-5.5", via: "OpenAI (API key)" });
102
+ }
103
+ if (hasAwsCredentials()) {
104
+ const via = "Amazon Bedrock (AWS)";
105
+ out.push(
106
+ { id: "amazon-bedrock/anthropic.claude-opus-4-1-20250805-v1:0", label: "Claude Opus 4.1", via },
107
+ { id: "amazon-bedrock/anthropic.claude-sonnet-4-20250514-v1:0", label: "Claude Sonnet 4", via }
108
+ );
109
+ }
110
+ if (hasEnv("GOOGLE_GENERATIVE_AI_API_KEY")) {
111
+ out.push({ id: "google/gemini-2.5-pro", label: "Gemini 2.5 Pro", via: "Google (API key)" });
112
+ }
113
+ const known = new Set(out.map((m) => m.id));
114
+ for (const savedId of loadSettings().customModels ?? []) {
115
+ const id = normalizeModelSelection(savedId, out);
116
+ if (!known.has(id)) {
117
+ out.push({ id, label: id.split("/").pop() ?? id, via: "saved" });
118
+ known.add(id);
119
+ }
120
+ }
121
+ return out;
122
+ }
123
+
124
+ export {
125
+ loadSettings,
126
+ completeOnboarding,
127
+ rememberModel,
128
+ normalizeModelSelection,
129
+ availableModels
130
+ };
131
+ //# sourceMappingURL=chunk-3XSOMUQQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/onboarding/settings.ts","../src/onboarding/providers.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { appDataDir } from \"../agent/paths.js\";\n\n/** Global, machine-wide settings (model default + onboarding marker). */\nexport interface JanetSettings {\n onboarding?: { completedAt: string; version: number };\n /** The persisted default model id, applied when no --model / JANET_MODEL is given. */\n defaultModelId?: string;\n /** Model ids the user has used directly — surfaced in the picker afterward. */\n customModels?: string[];\n}\n\nexport const ONBOARDING_VERSION = 1;\n\nfunction settingsPath(): string {\n return join(appDataDir(), \"settings.json\");\n}\n\nexport function loadSettings(): JanetSettings {\n try {\n return JSON.parse(readFileSync(settingsPath(), \"utf-8\")) as JanetSettings;\n } catch {\n return {};\n }\n}\n\nexport function saveSettings(settings: JanetSettings): void {\n const p = settingsPath();\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(settings, null, 2) + \"\\n\", \"utf-8\");\n}\n\n/** Persist the chosen model and mark onboarding complete. */\nexport function completeOnboarding(modelId: string, stampedAt: string): void {\n const settings = loadSettings();\n settings.defaultModelId = modelId;\n settings.onboarding = { completedAt: stampedAt, version: ONBOARDING_VERSION };\n saveSettings(settings);\n}\n\nexport function hasOnboarded(): boolean {\n return loadSettings().onboarding !== undefined;\n}\n\n/**\n * Remember a model id the user selected directly so it appears in the picker on\n * later runs. Keeps the picker current without code changes as providers ship\n * new models. Most-recent-first, capped.\n */\nexport function rememberModel(modelId: string): void {\n const id = modelId.trim();\n if (!id) return;\n const settings = loadSettings();\n const rest = (settings.customModels ?? []).filter((m) => m !== id);\n settings.customModels = [id, ...rest].slice(0, 20);\n saveSettings(settings);\n}\n","import { hasGoogleCredentials } from \"../gateways/vertex.js\";\nimport { hasAwsCredentials } from \"../gateways/bedrock.js\";\nimport { getAuthStorage } from \"../gateways/oauth/claude-max.js\";\nimport { loadSettings } from \"./settings.js\";\n\nexport interface ModelChoice {\n /** Full model id, e.g. \"vertex/claude-opus-4-8\". */\n id: string;\n /** Short human label, e.g. \"Claude Opus 4.8\". */\n label: string;\n /** How this provider is reached, e.g. \"Vertex AI (ADC)\". */\n via: string;\n}\n\n/**\n * Models offered when signed in to a ChatGPT/Codex subscription (OAuth). The\n * Codex `responses` backend accepts the model id verbatim, so this is a\n * convenience lineup — ANY id also works via `/model openai/<id>`. Edit here as\n * OpenAI's Codex catalog changes.\n */\nexport const CODEX_MODELS: ReadonlyArray<{ id: string; label: string }> = [\n { id: \"gpt-5.6-sol\", label: \"GPT-5.6 Sol\" },\n { id: \"gpt-5.6-terra\", label: \"GPT-5.6 Terra\" },\n { id: \"gpt-5.6-luna\", label: \"GPT-5.6 Luna\" },\n { id: \"gpt-5.5\", label: \"GPT-5.5\" },\n { id: \"gpt-5.4\", label: \"GPT-5.4\" },\n { id: \"gpt-5.4-mini\", label: \"GPT-5.4 Mini\" },\n];\n\nconst LEGACY_CODEX_MODEL_IDS: Readonly<Record<string, string>> = {\n \"gpt-5.6-codex\": \"openai/gpt-5.6-sol\",\n \"openai/gpt-5.6-codex\": \"openai/gpt-5.6-sol\",\n \"gpt-5.5-codex\": \"openai/gpt-5.5\",\n \"openai/gpt-5.5-codex\": \"openai/gpt-5.5\",\n};\n\n/**\n * Resolve a hand-typed or previously persisted model name to Mastra's required\n * `provider/model` form when the active provider catalog makes it unambiguous.\n * Also migrates the invalid Codex aliases Janet advertised before v0.1.0.\n */\nexport function normalizeModelSelection(\n modelId: string,\n choices: ReadonlyArray<ModelChoice>,\n): string {\n const id = modelId.trim();\n const legacy = LEGACY_CODEX_MODEL_IDS[id];\n if (legacy) return legacy;\n if (!id || id.includes(\"/\")) return id;\n\n const matches = choices.filter((choice) => choice.id.endsWith(`/${id}`));\n return matches.length === 1 ? matches[0]!.id : id;\n}\n\nfunction hasOAuth(provider: string): boolean {\n try {\n const s = getAuthStorage();\n s.reload();\n return s.get(provider)?.type === \"oauth\";\n } catch {\n return false;\n }\n}\n\nfunction hasEnv(...vars: string[]): boolean {\n return vars.some((v) => !!process.env[v]);\n}\n\n/**\n * Enumerate concrete model choices from the providers that are actually\n * reachable on this machine right now (env keys, ADC, AWS chain, stored OAuth).\n * Ordered best-first. Empty when nothing is configured.\n */\nexport function availableModels(): ModelChoice[] {\n const out: ModelChoice[] = [];\n\n if (hasGoogleCredentials()) {\n const via = \"Vertex AI (ADC)\";\n out.push(\n { id: \"vertex/claude-opus-4-8\", label: \"Claude Opus 4.8\", via },\n { id: \"vertex/claude-sonnet-4-5\", label: \"Claude Sonnet 4.5\", via },\n { id: \"vertex/gemini-2.5-pro\", label: \"Gemini 2.5 Pro\", via },\n );\n }\n if (hasEnv(\"ANTHROPIC_API_KEY\") || hasOAuth(\"anthropic\")) {\n const via = hasOAuth(\"anthropic\") ? \"Anthropic (Claude Max)\" : \"Anthropic (API key)\";\n out.push(\n { id: \"anthropic/claude-opus-4-6\", label: \"Claude Opus 4.6\", via },\n { id: \"anthropic/claude-sonnet-4-5\", label: \"Claude Sonnet 4.5\", via },\n );\n }\n if (hasOAuth(\"openai-codex\")) {\n // Signed in to a ChatGPT/Codex subscription — offer the full Codex lineup.\n const via = \"OpenAI (ChatGPT/Codex)\";\n for (const m of CODEX_MODELS) out.push({ id: `openai/${m.id}`, label: m.label, via });\n } else if (hasEnv(\"OPENAI_API_KEY\")) {\n out.push({ id: \"openai/gpt-5.5\", label: \"GPT-5.5\", via: \"OpenAI (API key)\" });\n }\n if (hasAwsCredentials()) {\n const via = \"Amazon Bedrock (AWS)\";\n out.push(\n { id: \"amazon-bedrock/anthropic.claude-opus-4-1-20250805-v1:0\", label: \"Claude Opus 4.1\", via },\n { id: \"amazon-bedrock/anthropic.claude-sonnet-4-20250514-v1:0\", label: \"Claude Sonnet 4\", via },\n );\n }\n if (hasEnv(\"GOOGLE_GENERATIVE_AI_API_KEY\")) {\n out.push({ id: \"google/gemini-2.5-pro\", label: \"Gemini 2.5 Pro\", via: \"Google (API key)\" });\n }\n\n // Models the user has used directly (via /model or --model) that aren't\n // already listed — keeps the picker current as providers ship new models.\n const known = new Set(out.map((m) => m.id));\n for (const savedId of loadSettings().customModels ?? []) {\n const id = normalizeModelSelection(savedId, out);\n if (!known.has(id)) {\n out.push({ id, label: id.split(\"/\").pop() ?? id, via: \"saved\" });\n known.add(id);\n }\n }\n\n return out;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __janetCreateRequire } from "node:module";
3
+ const require = __janetCreateRequire(import.meta.url);
4
+ import {
5
+ bootJanet,
6
+ messageText
7
+ } from "./chunk-YIAVFL7A.js";
8
+
9
+ // src/headless/run.ts
10
+ async function runHeadless(opts) {
11
+ const { controller, session, herdrDetach } = await bootJanet({
12
+ dir: opts.dir,
13
+ bundle: opts.bundle,
14
+ interactive: false,
15
+ threadId: opts.threadId,
16
+ allowHeadlessEdits: opts.allowEdits,
17
+ allowHeadlessExec: opts.allowExec
18
+ });
19
+ const activeThreadId = session.thread.getId();
20
+ if (activeThreadId && process.env["JANET_PRINT_THREAD"]) {
21
+ process.stderr.write(`janet:thread ${activeThreadId}
22
+ `);
23
+ }
24
+ if (opts.modelId) {
25
+ await session.model.switch({ modelId: opts.modelId });
26
+ }
27
+ if (!session.model.hasSelection()) {
28
+ process.stderr.write(
29
+ "No model selected. Pass --model 'provider/model' or set JANET_MODEL, or run `janet` once to onboard. Checked: JANET_MODEL, and any persisted selection.\n"
30
+ );
31
+ herdrDetach();
32
+ await controller.destroy();
33
+ return { exitCode: 2, text: "" };
34
+ }
35
+ let finalText = "";
36
+ let lastStreamed = "";
37
+ let currentMessageId = "";
38
+ let exitCode = 0;
39
+ const debug = !!process.env["JANET_DEBUG"];
40
+ await new Promise((resolve) => {
41
+ const nonInteractiveNote = "\n\n(Non-interactive run: you cannot ask the user questions. Make reasonable assumptions from the workspace contents, state them briefly, and complete the task end-to-end in this single turn.)";
42
+ const unsubscribe = session.subscribe((event) => {
43
+ if (debug) {
44
+ const extra = event.type === "tool_start" ? ` ${event.toolName} ${JSON.stringify(event.args).slice(0, 100)}` : event.type === "tool_end" ? ` isError=${event.isError} ${String(event.result).slice(0, 80)}` : event.type === "message_end" && event.message.role === "assistant" ? ` toolCalls=${JSON.stringify(event.message.content.filter((c) => c.type === "tool_call").map((c) => c.name))}` : event.type === "agent_end" ? ` reason=${event.reason}` : event.type === "error" ? ` ${event.errorType} ${String(event.error?.message ?? "").slice(0, 120)}` : "";
45
+ process.stderr.write(`[dbg] ${event.type}${extra}
46
+ `);
47
+ }
48
+ switch (event.type) {
49
+ case "message_update":
50
+ case "message_end": {
51
+ if (event.message.role !== "assistant") break;
52
+ if (event.message.id !== currentMessageId) {
53
+ currentMessageId = event.message.id;
54
+ if (lastStreamed.length > 0) process.stdout.write("\n");
55
+ lastStreamed = "";
56
+ }
57
+ const text = messageText(event.message);
58
+ if (text.length > lastStreamed.length && text.startsWith(lastStreamed)) {
59
+ process.stdout.write(text.slice(lastStreamed.length));
60
+ lastStreamed = text;
61
+ }
62
+ if (event.type === "message_end" && text.length > 0) {
63
+ finalText = text;
64
+ }
65
+ break;
66
+ }
67
+ case "tool_approval_required":
68
+ void session.respondToToolApproval({ decision: "decline", toolCallId: event.toolCallId });
69
+ break;
70
+ case "tool_suspended": {
71
+ const payload = event.suspendPayload;
72
+ const resumeData = event.toolName === "ask_user" ? payload?.options?.length ? payload.options[0].label : "Proceed with reasonable defaults \u2014 this is a non-interactive run." : { action: "denied" };
73
+ void session.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData });
74
+ break;
75
+ }
76
+ case "error": {
77
+ const err = event.error;
78
+ const detail = [
79
+ err?.message,
80
+ err?.statusCode ? `HTTP ${err.statusCode}` : "",
81
+ err?.responseBody?.slice(0, 400) ?? ""
82
+ ].filter(Boolean).join(" \u2014 ");
83
+ process.stderr.write(`
84
+ Janet hit a snag: ${detail || "unknown error"}
85
+ `);
86
+ exitCode = 1;
87
+ break;
88
+ }
89
+ case "agent_end":
90
+ if (event.reason === "error" || event.reason === "aborted") exitCode = 1;
91
+ unsubscribe();
92
+ resolve();
93
+ break;
94
+ }
95
+ });
96
+ void session.sendMessage({ content: opts.message + nonInteractiveNote }).catch((err) => {
97
+ process.stderr.write(`
98
+ Janet hit a snag: ${err.message}
99
+ `);
100
+ exitCode = 1;
101
+ unsubscribe();
102
+ resolve();
103
+ });
104
+ });
105
+ process.stdout.write("\n");
106
+ herdrDetach();
107
+ await controller.destroy();
108
+ return { exitCode, text: finalText };
109
+ }
110
+
111
+ export {
112
+ runHeadless
113
+ };
114
+ //# sourceMappingURL=chunk-J4MELCGD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/headless/run.ts"],"sourcesContent":["import type { AgentControllerEvent } from \"@mastra/core/agent-controller\";\nimport { bootJanet } from \"../agent/controller.js\";\nimport { messageText } from \"./format.js\";\n\nexport interface HeadlessOptions {\n /** The directive/message to send to Janet. */\n message: string;\n dir?: string;\n bundle?: string;\n /** Model id to switch to before the turn (from --model / JANET_MODEL). */\n modelId?: string;\n /** Resume an existing thread. */\n threadId?: string;\n /** Allow workspace edits. Defaults to read-only. */\n allowEdits?: boolean;\n /** Allow shell execution. Defaults to false and should be an explicit user opt-in. */\n allowExec?: boolean;\n}\n\nexport interface HeadlessResult {\n exitCode: number;\n /** Final assistant text (also streamed to stdout as it arrives). */\n text: string;\n}\n\n/**\n * Headless one-shot: boot a fail-closed session, stream assistant text to\n * stdout, and resolve on `agent_end`. Pattern adapted from mastracode's\n * `sdk/src/headless/`.\n */\nexport async function runHeadless(opts: HeadlessOptions): Promise<HeadlessResult> {\n const { controller, session, herdrDetach } = await bootJanet({\n dir: opts.dir,\n bundle: opts.bundle,\n interactive: false,\n threadId: opts.threadId,\n allowHeadlessEdits: opts.allowEdits,\n allowHeadlessExec: opts.allowExec,\n });\n // Expose the active thread id so a supervisor (e.g. Herdr) can reattach with\n // `janet --thread <id>` after a restart.\n const activeThreadId = session.thread.getId();\n if (activeThreadId && process.env[\"JANET_PRINT_THREAD\"]) {\n process.stderr.write(`janet:thread ${activeThreadId}\\n`);\n }\n\n if (opts.modelId) {\n await session.model.switch({ modelId: opts.modelId });\n }\n if (!session.model.hasSelection()) {\n process.stderr.write(\n \"No model selected. Pass --model 'provider/model' or set JANET_MODEL, \" +\n \"or run `janet` once to onboard. Checked: JANET_MODEL, and any persisted selection.\\n\",\n );\n herdrDetach();\n await controller.destroy();\n return { exitCode: 2, text: \"\" };\n }\n\n let finalText = \"\";\n let lastStreamed = \"\";\n let currentMessageId = \"\";\n let exitCode = 0;\n\n const debug = !!process.env[\"JANET_DEBUG\"];\n await new Promise<void>((resolve) => {\n // Headless one-shots cannot answer questions: skills that would normally\n // ask the user (e.g. kb-init's domain questions) must proceed on their own.\n const nonInteractiveNote =\n \"\\n\\n(Non-interactive run: you cannot ask the user questions. Make reasonable \" +\n \"assumptions from the workspace contents, state them briefly, and complete the \" +\n \"task end-to-end in this single turn.)\";\n\n const unsubscribe = session.subscribe((event: AgentControllerEvent) => {\n if (debug) {\n const extra =\n event.type === \"tool_start\"\n ? ` ${event.toolName} ${JSON.stringify(event.args).slice(0, 100)}`\n : event.type === \"tool_end\"\n ? ` isError=${event.isError} ${String(event.result).slice(0, 80)}`\n : event.type === \"message_end\" && event.message.role === \"assistant\"\n ? ` toolCalls=${JSON.stringify(event.message.content.filter((c) => c.type === \"tool_call\").map((c) => (c as { name: string }).name))}`\n : event.type === \"agent_end\"\n ? ` reason=${event.reason}`\n : event.type === \"error\"\n ? ` ${event.errorType} ${String(event.error?.message ?? \"\").slice(0, 120)}`\n : \"\";\n process.stderr.write(`[dbg] ${event.type}${extra}\\n`);\n }\n switch (event.type) {\n case \"message_update\":\n case \"message_end\": {\n if (event.message.role !== \"assistant\") break;\n // Only reset the streamed-prefix tracker when a genuinely NEW message\n // starts (the same message keeps growing across tool calls).\n if (event.message.id !== currentMessageId) {\n currentMessageId = event.message.id;\n if (lastStreamed.length > 0) process.stdout.write(\"\\n\");\n lastStreamed = \"\";\n }\n const text = messageText(event.message);\n if (text.length > lastStreamed.length && text.startsWith(lastStreamed)) {\n process.stdout.write(text.slice(lastStreamed.length));\n lastStreamed = text;\n }\n if (event.type === \"message_end\" && text.length > 0) {\n finalText = text;\n }\n break;\n }\n case \"tool_approval_required\":\n // Explicit permission rules should normally resolve without a prompt.\n // If an unknown gate still reaches us, fail closed instead of hanging.\n void session.respondToToolApproval({ decision: \"decline\", toolCallId: event.toolCallId });\n break;\n case \"tool_suspended\": {\n // Headless can't prompt the user. For ask_user, tell Janet to proceed\n // with sensible defaults so the run completes; for a decision-style\n // suspension, approve. Prevents the turn hanging forever.\n const payload = event.suspendPayload as { options?: { label: string }[] } | undefined;\n const resumeData = event.toolName === \"ask_user\"\n ? payload?.options?.length\n ? payload.options[0]!.label\n : \"Proceed with reasonable defaults — this is a non-interactive run.\"\n : { action: \"denied\" };\n void session.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData });\n break;\n }\n case \"error\": {\n const err = event.error as Error & { statusCode?: number; responseBody?: string };\n const detail = [\n err?.message,\n err?.statusCode ? `HTTP ${err.statusCode}` : \"\",\n err?.responseBody?.slice(0, 400) ?? \"\",\n ]\n .filter(Boolean)\n .join(\" — \");\n process.stderr.write(`\\nJanet hit a snag: ${detail || \"unknown error\"}\\n`);\n exitCode = 1;\n break;\n }\n case \"agent_end\":\n if (event.reason === \"error\" || event.reason === \"aborted\") exitCode = 1;\n unsubscribe();\n resolve();\n break;\n }\n });\n\n void session.sendMessage({ content: opts.message + nonInteractiveNote }).catch((err: Error) => {\n process.stderr.write(`\\nJanet hit a snag: ${err.message}\\n`);\n exitCode = 1;\n unsubscribe();\n resolve();\n });\n });\n\n process.stdout.write(\"\\n\");\n herdrDetach();\n await controller.destroy();\n return { exitCode, text: finalText };\n}\n"],"mappings":"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","names":[]}