@fusion.dev/cortex-cli 0.0.0-dev

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 (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/bin.mjs +204 -0
  4. package/package.json +46 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fusion Development Group
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/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # @fusion.dev/cortex-cli
2
+
3
+ The Cortex command line. Records your notes, distills them into facts, answers
4
+ questions from the facts, and traces each answer back to the notes it came
5
+ from. The memory is a SQLite file on your machine, and the models run in Ollama
6
+ by default.
7
+
8
+ ```sh
9
+ npm install --global @fusion.dev/cortex-cli
10
+ ```
11
+
12
+ The command is a native binary, and npm installs the build for your machine
13
+ beside this package: macOS and Linux on Arm and x86-64, and Windows on x86-64.
14
+ An install that skips optional dependencies skips it too. `cortex` then runs a
15
+ `cortex` on your `PATH` whose `cortex --version --json` names this package, and
16
+ otherwise names the package that is missing.
17
+
18
+ ```sh
19
+ cortex ingest notes/monday.md
20
+ cortex consolidate
21
+ cortex ask "When does the release ship?"
22
+ cortex why
23
+ ```
24
+
25
+ | Verb | What it does |
26
+ |---|---|
27
+ | `ingest` | Records each paragraph of a file, or standard input, as an episode |
28
+ | `consolidate` | Asks the chat model for the facts the new episodes state, and gives each fact a vector |
29
+ | `ask` | Answers a question from the facts that score highest for it, and records the answer |
30
+ | `why` | Prints how an answer was derived: the facts it was given, why, and the notes under each |
31
+ | `forget` | Removes an episode, or every episode from a file, with everything derived from it |
32
+ | `replay` | Asks another model the same question with the same facts, and compares the answers |
33
+
34
+ `--json` is on every verb. [The quickstart](https://github.com/project-fusion/fusion/blob/main/cortex/docs/content/quickstart.mdx)
35
+ runs a session from install to `forget`, and
36
+ [the command page](https://github.com/project-fusion/fusion/blob/main/cortex/docs/content/command.mdx)
37
+ walks through a week of notes.
package/bin.mjs ADDED
@@ -0,0 +1,204 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `cortex` for a caller that installed it through npm.
4
+ *
5
+ * **A near-copy of `helix/cli/npm/bin.mjs`, deliberately.** Sharing it would
6
+ * put a file in the helix domain on the publish path of a cortex package, and
7
+ * per-domain lockstep exists so a release of either does not wait on the other.
8
+ *
9
+ * **Resolution order.** `CORTEX_BIN` first, because a caller that knows better
10
+ * should not have to argue. Then, in a checkout, the newest build in the cargo
11
+ * target directory, honoring `CARGO_TARGET_DIR`. Then the binary npm installed
12
+ * beside this, which is what a consumer has. Then a `cortex` on `PATH` whose
13
+ * `cortex --version --json` names this package, since another program can
14
+ * share the name. Then, in a checkout with cargo, one build. Otherwise it says
15
+ * what is missing.
16
+ */
17
+ import { spawnSync } from 'node:child_process'
18
+ import { existsSync, realpathSync, statSync } from 'node:fs'
19
+ import { createRequire } from 'node:module'
20
+ import { delimiter, dirname, join, resolve } from 'node:path'
21
+ import { fileURLToPath } from 'node:url'
22
+
23
+ const HERE = dirname(fileURLToPath(import.meta.url))
24
+ const CRATE = resolve(HERE, '..')
25
+ const WORKSPACE = resolve(CRATE, '../..')
26
+ const NAME = process.platform === 'win32' ? 'cortex.exe' : 'cortex'
27
+ const PACKAGE = '@fusion.dev/cortex-cli'
28
+
29
+ const target = process.env.CARGO_TARGET_DIR
30
+ ? resolve(process.env.CARGO_TARGET_DIR)
31
+ : join(WORKSPACE, 'target')
32
+
33
+ /**
34
+ * The most recently built binary, or undefined. By modification time, so a
35
+ * release build from last week does not shadow the debug build from a minute
36
+ * ago: `helix/cli/npm/bin.mjs` measured that trap.
37
+ */
38
+ const built = () =>
39
+ [join(target, 'release', NAME), join(target, 'debug', NAME)]
40
+ .filter((path) => existsSync(path))
41
+ .sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs)
42
+ .at(0)
43
+
44
+ /** The platform package for this machine, named as they are published. */
45
+ const PLATFORM = `${PACKAGE}-${process.platform}-${process.arch}`
46
+
47
+ /**
48
+ * The binary in this machine's platform package, or undefined. npm installs
49
+ * only the optional dependency whose `os` and `cpu` match, and it is resolved
50
+ * as a module so it is found wherever the package manager put it.
51
+ */
52
+ const packaged = () => {
53
+ let manifest
54
+ try {
55
+ manifest = createRequire(import.meta.url).resolve(`${PLATFORM}/package.json`)
56
+ } catch {
57
+ return undefined
58
+ }
59
+ const binary = join(dirname(manifest), NAME)
60
+ return existsSync(binary) ? binary : undefined
61
+ }
62
+
63
+ /** Whether this is the repository's own copy, where there is a crate to build. */
64
+ const checkout = existsSync(join(CRATE, 'Cargo.toml'))
65
+
66
+ /** Whether cargo is on the path. */
67
+ const hasCargo = () => spawnSync('cargo', ['--version'], { stdio: 'ignore' }).status === 0
68
+
69
+ /** This file, resolved, which a `PATH` entry must not be. */
70
+ const SELF = realpathSync(fileURLToPath(import.meta.url))
71
+
72
+ /**
73
+ * Each `cortex` on `PATH`, in order, resolved through its symlinks.
74
+ *
75
+ * **Walked and never spawned by name.** `node_modules/.bin/cortex` is a
76
+ * symlink to this file, so asking `PATH` to run `cortex` can run this shim
77
+ * again, which asks again: `helix/cli/npm/bin.mjs` measured 4,871 processes
78
+ * before the machine stopped forking.
79
+ */
80
+ function* onPath() {
81
+ const extensions = process.platform === 'win32' ? ['', '.exe', '.cmd', '.bat'] : ['']
82
+ const seen = new Set()
83
+ for (const directory of (process.env.PATH ?? '').split(delimiter)) {
84
+ if (directory === '') {
85
+ continue
86
+ }
87
+ for (const extension of extensions) {
88
+ const candidate = join(directory, NAME + extension)
89
+ if (!existsSync(candidate)) {
90
+ continue
91
+ }
92
+ let real
93
+ try {
94
+ real = realpathSync(candidate)
95
+ } catch {
96
+ continue
97
+ }
98
+ if (real === SELF || seen.has(real)) {
99
+ continue
100
+ }
101
+ seen.add(real)
102
+ yield real
103
+ }
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Set while this shim asks a `PATH` entry for `--version --json`, so a copy of
109
+ * this shim asked that way never searches `PATH` itself.
110
+ */
111
+ const PROBE = 'CORTEX_SHIM_PROBE'
112
+
113
+ /**
114
+ * Whether `binary` is this command line: its `--version --json` names this
115
+ * package. Another program named `cortex` exits with an error or prints
116
+ * something else.
117
+ */
118
+ const ours = (binary) => {
119
+ const asked = spawnSync(binary, ['--version', '--json'], {
120
+ encoding: 'utf8',
121
+ env: { ...process.env, [PROBE]: '1' },
122
+ stdio: ['ignore', 'pipe', 'ignore'],
123
+ timeout: 2_000,
124
+ })
125
+ try {
126
+ return JSON.parse(asked.stdout ?? '').package === PACKAGE
127
+ } catch {
128
+ return false
129
+ }
130
+ }
131
+
132
+ const run = (binary) => {
133
+ const { status, error } = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' })
134
+ /* A status means it ran. Bun sets `error` on any exit but zero, so asking
135
+ `error` alone would report every failed command as one that did not
136
+ start. */
137
+ if (error && status === null) {
138
+ console.error(`cortex: could not run \`${binary}\`: ${error.message}`)
139
+ process.exit(70)
140
+ }
141
+ process.exit(status ?? 70)
142
+ }
143
+
144
+ const found = process.env.CORTEX_BIN ?? (checkout ? built() : undefined) ?? packaged()
145
+ if (found && existsSync(found)) {
146
+ run(found)
147
+ }
148
+
149
+ const skipped = []
150
+ for (const candidate of process.env[PROBE] === undefined ? onPath() : []) {
151
+ if (ours(candidate)) {
152
+ run(candidate)
153
+ }
154
+ skipped.push(candidate)
155
+ }
156
+
157
+ /** The `cortex` binaries on `PATH` that are some other program, named. */
158
+ const foreign = () =>
159
+ skipped.length === 0
160
+ ? ''
161
+ : `\n\n Not run, from PATH: ${skipped.map((path) => `\`${path}\``).join(', ')}.\n` +
162
+ ` Its \`--version --json\` does not name \`${PACKAGE}\`, so it is another program.`
163
+
164
+ if (!checkout) {
165
+ console.error(
166
+ `cortex: no binary for ${process.platform} ${process.arch}.\n\n` +
167
+ ` It comes in \`${PLATFORM}\`, an optional dependency of\n` +
168
+ ` \`${PACKAGE}\`, and it is not installed. Either this machine is not\n` +
169
+ ' one there is a build for, or the install skipped optional dependencies\n' +
170
+ ' (`--omit=optional`, `--no-optional`), in which case install again without it.\n' +
171
+ ` \`CORTEX_BIN\` names a binary to run instead.${foreign()}`,
172
+ )
173
+ process.exit(69)
174
+ }
175
+
176
+ if (!hasCargo()) {
177
+ console.error(
178
+ 'cortex: no binary and no cargo.\n\n' +
179
+ ` Looked at: $CORTEX_BIN, ${join(target, 'release', NAME)},\n` +
180
+ ` ${join(target, 'debug', NAME)}, and \`${NAME}\` on PATH.\n\n` +
181
+ ' Either point `CORTEX_BIN` at a binary, or install a Rust toolchain so\n' +
182
+ ` this can build it.${foreign()}`,
183
+ )
184
+ process.exit(69)
185
+ }
186
+
187
+ console.error('cortex: no binary yet, building it once (cargo build -p fusion-cortex-cli)')
188
+ const build = spawnSync('cargo', ['build', '-p', 'fusion-cortex-cli'], {
189
+ cwd: WORKSPACE,
190
+ stdio: 'inherit',
191
+ })
192
+ if (build.status !== 0) {
193
+ console.error('cortex: the build failed, so there is nothing to run.')
194
+ process.exit(build.status ?? 70)
195
+ }
196
+ const after = built()
197
+ if (!after) {
198
+ console.error(
199
+ `cortex: cargo reported success and produced no \`${NAME}\` under ${target}.\n` +
200
+ ' That usually means a different target directory. Try `CARGO_TARGET_DIR`.',
201
+ )
202
+ process.exit(70)
203
+ }
204
+ run(after)
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@fusion.dev/cortex-cli",
3
+ "description": "The Cortex command line: record notes, distill them into facts, answer questions from the facts, and trace each answer to its sources.",
4
+ "version": "0.0.0-dev",
5
+ "license": "MIT",
6
+ "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
+ "repository": {
8
+ "directory": "cortex/cli/npm",
9
+ "type": "git",
10
+ "url": "git+https://github.com/project-fusion/fusion.git"
11
+ },
12
+ "type": "module",
13
+ "exports": {
14
+ "./bin.mjs": "./bin.mjs",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "bin.mjs"
19
+ ],
20
+ "bin": {
21
+ "cortex": "./bin.mjs"
22
+ },
23
+ "scripts": {
24
+ "test": "bun test"
25
+ },
26
+ "bugs": "https://github.com/project-fusion/fusion/issues",
27
+ "homepage": "https://fusion.dev",
28
+ "keywords": [
29
+ "cortex",
30
+ "cli",
31
+ "memory",
32
+ "provenance",
33
+ "ollama",
34
+ "local-first"
35
+ ],
36
+ "optionalDependencies": {
37
+ "@fusion.dev/cortex-cli-darwin-arm64": "0.1.2",
38
+ "@fusion.dev/cortex-cli-darwin-x64": "0.1.2",
39
+ "@fusion.dev/cortex-cli-linux-arm64": "0.1.2",
40
+ "@fusion.dev/cortex-cli-linux-x64": "0.1.2",
41
+ "@fusion.dev/cortex-cli-win32-x64": "0.1.2"
42
+ },
43
+ "publishConfig": {
44
+ "access": "restricted"
45
+ }
46
+ }