orbitmap 0.3.0 → 0.4.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/README.md +546 -212
- package/dist/adapters/cloud.d.ts +367 -0
- package/dist/adapters/cloud.js +582 -0
- package/dist/adapters/cloud.js.map +1 -0
- package/dist/adapters/factory.d.ts +15 -0
- package/dist/adapters/factory.js +31 -0
- package/dist/adapters/factory.js.map +1 -0
- package/dist/adapters/local/adapter.d.ts +351 -0
- package/dist/adapters/local/adapter.js +346 -0
- package/dist/adapters/local/adapter.js.map +1 -0
- package/dist/adapters/local/context.d.ts +112 -0
- package/dist/adapters/local/context.js +137 -0
- package/dist/adapters/local/context.js.map +1 -0
- package/dist/adapters/local/entities/documents.d.ts +85 -0
- package/dist/adapters/local/entities/documents.js +251 -0
- package/dist/adapters/local/entities/documents.js.map +1 -0
- package/dist/adapters/local/entities/planning.d.ts +108 -0
- package/dist/adapters/local/entities/planning.js +540 -0
- package/dist/adapters/local/entities/planning.js.map +1 -0
- package/dist/adapters/local/entities/tasks.d.ts +95 -0
- package/dist/adapters/local/entities/tasks.js +442 -0
- package/dist/adapters/local/entities/tasks.js.map +1 -0
- package/dist/adapters/local/entities/work-items.d.ts +110 -0
- package/dist/adapters/local/entities/work-items.js +623 -0
- package/dist/adapters/local/entities/work-items.js.map +1 -0
- package/dist/adapters/local/rules.d.ts +172 -0
- package/dist/adapters/local/rules.js +319 -0
- package/dist/adapters/local/rules.js.map +1 -0
- package/dist/adapters/local/shapes.d.ts +209 -0
- package/dist/adapters/local/shapes.js +558 -0
- package/dist/adapters/local/shapes.js.map +1 -0
- package/dist/adapters/local/store.d.ts +200 -0
- package/dist/adapters/local/store.js +665 -0
- package/dist/adapters/local/store.js.map +1 -0
- package/dist/adapters/local/types.d.ts +226 -0
- package/dist/adapters/local/types.js +41 -0
- package/dist/adapters/local/types.js.map +1 -0
- package/dist/adapters/types.d.ts +332 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/agent-instructions.d.ts +25 -9
- package/dist/agent-instructions.js +285 -237
- package/dist/agent-instructions.js.map +1 -1
- package/dist/api-client.d.ts +8 -239
- package/dist/api-client.js +8 -403
- package/dist/api-client.js.map +1 -1
- package/dist/commands/agents.d.ts +1 -1
- package/dist/commands/agents.js +10 -10
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/areas.d.ts +3 -0
- package/dist/commands/areas.js +29 -0
- package/dist/commands/areas.js.map +1 -0
- package/dist/commands/assign.d.ts +3 -2
- package/dist/commands/assign.js +52 -15
- package/dist/commands/assign.js.map +1 -1
- package/dist/commands/context.d.ts +1 -1
- package/dist/commands/context.js +18 -12
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/create-area.d.ts +7 -0
- package/dist/commands/create-area.js +29 -0
- package/dist/commands/create-area.js.map +1 -0
- package/dist/commands/create.d.ts +3 -1
- package/dist/commands/create.js +5 -8
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/dep.d.ts +2 -2
- package/dist/commands/dep.js +3 -3
- package/dist/commands/dep.js.map +1 -1
- package/dist/commands/doc-import.d.ts +1 -1
- package/dist/commands/doc-import.js +2 -2
- package/dist/commands/doc-import.js.map +1 -1
- package/dist/commands/doc-patch.d.ts +1 -1
- package/dist/commands/doc-patch.js +2 -2
- package/dist/commands/doc-patch.js.map +1 -1
- package/dist/commands/doc-share.d.ts +6 -6
- package/dist/commands/doc-share.js +13 -13
- package/dist/commands/doc-share.js.map +1 -1
- package/dist/commands/doc-update.d.ts +1 -1
- package/dist/commands/doc-update.js +2 -2
- package/dist/commands/doc-update.js.map +1 -1
- package/dist/commands/doc.d.ts +1 -1
- package/dist/commands/doc.js +5 -4
- package/dist/commands/doc.js.map +1 -1
- package/dist/commands/docs-cache.d.ts +2 -2
- package/dist/commands/docs-cache.js +3 -3
- package/dist/commands/docs-cache.js.map +1 -1
- package/dist/commands/docs.d.ts +1 -1
- package/dist/commands/docs.js +2 -2
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/get.d.ts +1 -1
- package/dist/commands/get.js +43 -3
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/ideas.d.ts +4 -4
- package/dist/commands/ideas.js +6 -11
- package/dist/commands/ideas.js.map +1 -1
- package/dist/commands/init.d.ts +45 -3
- package/dist/commands/init.js +452 -104
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/intent.d.ts +41 -0
- package/dist/commands/intent.js +237 -0
- package/dist/commands/intent.js.map +1 -0
- package/dist/commands/issues.d.ts +6 -5
- package/dist/commands/issues.js +8 -12
- package/dist/commands/issues.js.map +1 -1
- package/dist/commands/log.d.ts +1 -1
- package/dist/commands/log.js +2 -2
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/mission.d.ts +42 -0
- package/dist/commands/mission.js +219 -0
- package/dist/commands/mission.js.map +1 -0
- package/dist/commands/orbit.d.ts +40 -3
- package/dist/commands/orbit.js +231 -58
- package/dist/commands/orbit.js.map +1 -1
- package/dist/commands/overview.d.ts +2 -2
- package/dist/commands/overview.js +25 -28
- package/dist/commands/overview.js.map +1 -1
- package/dist/commands/setup-agent.d.ts +27 -0
- package/dist/commands/setup-agent.js +85 -30
- package/dist/commands/setup-agent.js.map +1 -1
- package/dist/commands/setup-mcp.d.ts +1 -1
- package/dist/commands/setup-mcp.js +20 -49
- package/dist/commands/setup-mcp.js.map +1 -1
- package/dist/commands/start.d.ts +1 -1
- package/dist/commands/start.js +2 -2
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts +2 -1
- package/dist/commands/status.js +3 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/subtask.d.ts +1 -1
- package/dist/commands/subtask.js +2 -2
- package/dist/commands/subtask.js.map +1 -1
- package/dist/commands/task-edit-content.d.ts +1 -1
- package/dist/commands/task-edit-content.js +2 -2
- package/dist/commands/task-edit-content.js.map +1 -1
- package/dist/commands/task.d.ts +10 -3
- package/dist/commands/task.js +19 -21
- package/dist/commands/task.js.map +1 -1
- package/dist/commands/tasks.d.ts +1 -1
- package/dist/commands/tasks.js +2 -2
- package/dist/commands/tasks.js.map +1 -1
- package/dist/commands/vibes.d.ts +4 -4
- package/dist/commands/vibes.js +5 -5
- package/dist/commands/vibes.js.map +1 -1
- package/dist/config.d.ts +69 -9
- package/dist/config.js +206 -23
- package/dist/config.js.map +1 -1
- package/dist/doc-cache.d.ts +23 -3
- package/dist/doc-cache.js +72 -12
- package/dist/doc-cache.js.map +1 -1
- package/dist/errors.d.ts +19 -2
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -1
- package/dist/id-resolve.d.ts +61 -0
- package/dist/id-resolve.js +87 -0
- package/dist/id-resolve.js.map +1 -0
- package/dist/index.js +477 -104
- package/dist/index.js.map +1 -1
- package/dist/mcp-config.d.ts +36 -0
- package/dist/mcp-config.js +51 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/oauth.d.ts +8 -0
- package/dist/oauth.js +54 -15
- package/dist/oauth.js.map +1 -1
- package/dist/output.js +7 -2
- package/dist/output.js.map +1 -1
- package/dist/paths.d.ts +97 -0
- package/dist/paths.js +178 -0
- package/dist/paths.js.map +1 -0
- package/dist/project-config.d.ts +75 -0
- package/dist/project-config.js +55 -0
- package/dist/project-config.js.map +1 -0
- package/dist/workspace-resolve.d.ts +158 -0
- package/dist/workspace-resolve.js +284 -0
- package/dist/workspace-resolve.js.map +1 -0
- package/package.json +53 -50
package/dist/paths.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
/** Name of the per-project OrbitMap directory (`<project>/.orbitmap`). */
|
|
5
|
+
export const ORBITMAP_DIR = '.orbitmap';
|
|
6
|
+
/**
|
|
7
|
+
* Filename of *both* config files — `<project>/.orbitmap/config.json` (project-scoped,
|
|
8
|
+
* committable) and `~/.orbitmap/config.json` (machine-wide). Same name, different file:
|
|
9
|
+
* telling them apart is the job of {@link globalConfigPaths}, which the project walk-up
|
|
10
|
+
* below uses to skip the global one.
|
|
11
|
+
*/
|
|
12
|
+
export const CONFIG_FILENAME = 'config.json';
|
|
13
|
+
/** Filename of the machine-local secret store (`~/.orbitmap/credentials.json`). */
|
|
14
|
+
export const CREDENTIALS_FILENAME = 'credentials.json';
|
|
15
|
+
let homeCache;
|
|
16
|
+
/**
|
|
17
|
+
* The resolved OrbitMap home, memoised.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately a *function*, not a module-level constant: the CLI's own tests (and any
|
|
20
|
+
* embedder) set `ORBITMAP_CONFIG_HOME`/`XDG_CONFIG_HOME` after this module has been
|
|
21
|
+
* imported, and a constant captured at import time would ignore them — and would give
|
|
22
|
+
* `config.ts` and `oauth.ts` two independent, silently diverging copies. The memo is keyed
|
|
23
|
+
* on the inputs, so a later env change is picked up while repeat calls stay free.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveOrbitMapHome() {
|
|
26
|
+
const override = process.env['ORBITMAP_CONFIG_HOME'] ?? '';
|
|
27
|
+
const xdg = process.env['XDG_CONFIG_HOME'] ?? '';
|
|
28
|
+
const home = homedir();
|
|
29
|
+
const key = `${override}\u0000${xdg}\u0000${home}`;
|
|
30
|
+
if (homeCache?.key === key)
|
|
31
|
+
return homeCache.home;
|
|
32
|
+
const legacyDir = join(home, ORBITMAP_DIR);
|
|
33
|
+
const dir = override || (xdg ? join(xdg, 'orbitmap') : legacyDir);
|
|
34
|
+
const resolved = { dir, legacyDir };
|
|
35
|
+
homeCache = { key, home: resolved };
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Path to read `filename` from: the new `home.dir` location if the file exists there,
|
|
40
|
+
* otherwise the legacy `~/.orbitmap` location (which may or may not exist either — callers
|
|
41
|
+
* still need their own existence check). When `home.dir` and `home.legacyDir` are the same
|
|
42
|
+
* (the common case — neither `ORBITMAP_CONFIG_HOME` nor `XDG_CONFIG_HOME` set) this is a
|
|
43
|
+
* no-op and just returns the one path.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveReadPath(home, filename) {
|
|
46
|
+
const primary = join(home.dir, filename);
|
|
47
|
+
if (home.dir === home.legacyDir || existsSync(primary))
|
|
48
|
+
return primary;
|
|
49
|
+
const legacy = join(home.legacyDir, filename);
|
|
50
|
+
return existsSync(legacy) ? legacy : primary;
|
|
51
|
+
}
|
|
52
|
+
/** Path to write `filename` to: always the new `home.dir` location. */
|
|
53
|
+
export function resolveWritePath(home, filename) {
|
|
54
|
+
return join(home.dir, filename);
|
|
55
|
+
}
|
|
56
|
+
/** Absolute path the global config is read from — the relocated one, or the legacy
|
|
57
|
+
* `~/.orbitmap/config.json` when the relocated one does not exist yet. */
|
|
58
|
+
export function globalConfigReadPath() {
|
|
59
|
+
return resolveReadPath(resolveOrbitMapHome(), CONFIG_FILENAME);
|
|
60
|
+
}
|
|
61
|
+
/** Absolute path the global config is written to — always the current home, which is not
|
|
62
|
+
* necessarily where {@link globalConfigReadPath} read it from. */
|
|
63
|
+
export function globalConfigWritePath() {
|
|
64
|
+
return resolveWritePath(resolveOrbitMapHome(), CONFIG_FILENAME);
|
|
65
|
+
}
|
|
66
|
+
/** Absolute path of the machine-local credential store, wherever the home now is. */
|
|
67
|
+
export function credentialsPath() {
|
|
68
|
+
return resolveWritePath(resolveOrbitMapHome(), CREDENTIALS_FILENAME);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Every path that is a *global* `config.json` for this machine — the current home and the
|
|
72
|
+
* legacy `~/.orbitmap` one, which is still read as a fallback. The project-config walk-up
|
|
73
|
+
* skips exactly these: same filename, different file, and pulling the global one in as if
|
|
74
|
+
* it were a project's own is the cross-project leak ADR 0002 exists to prevent.
|
|
75
|
+
*/
|
|
76
|
+
export function globalConfigPaths() {
|
|
77
|
+
const home = resolveOrbitMapHome();
|
|
78
|
+
const paths = [join(home.dir, CONFIG_FILENAME)];
|
|
79
|
+
if (home.legacyDir !== home.dir)
|
|
80
|
+
paths.push(join(home.legacyDir, CONFIG_FILENAME));
|
|
81
|
+
return paths;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Canonical form of `path` for identity comparisons: symlinks resolved where the path
|
|
85
|
+
* exists, and lower-cased on Windows, whose filesystem is case-insensitive (`C:\Users\me`
|
|
86
|
+
* and `c:\users\me` are one directory). A plain `resolve()` string compare normalises
|
|
87
|
+
* neither, which is how the original `$HOME` walk-up guard silently failed.
|
|
88
|
+
*/
|
|
89
|
+
function canonical(path) {
|
|
90
|
+
let out = resolve(path);
|
|
91
|
+
try {
|
|
92
|
+
out = realpathSync.native(out);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Does not exist (yet) — the lexical form is the best we can do, and is enough:
|
|
96
|
+
// a path that does not exist cannot be a config file we would have read anyway.
|
|
97
|
+
}
|
|
98
|
+
return process.platform === 'win32' ? out.toLowerCase() : out;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* True when `orbitmapDir` is an OrbitMap *home* rather than a project's `.orbitmap/`.
|
|
102
|
+
*
|
|
103
|
+
* `credentials.json` is the machine-local secret store. The CLI only ever writes it into
|
|
104
|
+
* the resolved home ({@link resolveOrbitMapHome}) and never into a project directory, so
|
|
105
|
+
* finding one next to a `config.json` means that directory is a home — whatever the current
|
|
106
|
+
* `$HOME` happens to say.
|
|
107
|
+
*
|
|
108
|
+
* That distinction cannot be made from the path alone once `$HOME` is not what it was when
|
|
109
|
+
* the home was created: an overridden `HOME`/`USERPROFILE` (CI, `sudo`, a roaming profile,
|
|
110
|
+
* a test harness) leaves the real `~/.orbitmap/config.json` sitting on the walk-up path as
|
|
111
|
+
* an ordinary ancestor directory. Skipping it is always the safe direction — the worst case
|
|
112
|
+
* is that a rung falls through to the next one, never that one project's settings leak into
|
|
113
|
+
* another.
|
|
114
|
+
*/
|
|
115
|
+
function isOrbitMapHomeDir(orbitmapDir) {
|
|
116
|
+
return existsSync(join(orbitmapDir, CREDENTIALS_FILENAME));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Every existing `<dir>/.orbitmap/config.json` from `startDir` up to the user's home
|
|
120
|
+
* directory, **nearest first** — the same discovery behaviour as git looking for `.git`.
|
|
121
|
+
*
|
|
122
|
+
* This is the single implementation of the project-config walk-up; `project-config.ts`
|
|
123
|
+
* layers per-field resolution on top of it (ADR 0002 §2) and both `config.ts` and
|
|
124
|
+
* `workspace-resolve.ts` go through that, so a fix here applies to every ladder at once.
|
|
125
|
+
*
|
|
126
|
+
* Three invariants keep the global config out of the result:
|
|
127
|
+
*
|
|
128
|
+
* - **Any candidate equal to a {@link globalConfigPaths} entry is skipped.** That is the
|
|
129
|
+
* real invariant — it holds regardless of where the global config actually lives, so it
|
|
130
|
+
* also covers `ORBITMAP_CONFIG_HOME`/`XDG_CONFIG_HOME` relocating it somewhere in the
|
|
131
|
+
* middle of the walk.
|
|
132
|
+
* - **Any candidate sitting next to a `credentials.json` is skipped** — see
|
|
133
|
+
* {@link isOrbitMapHomeDir}, which catches a home the current `$HOME` no longer names.
|
|
134
|
+
* - **The walk stops at `$HOME`.** Nothing above a user's home is that user's project.
|
|
135
|
+
* Compared canonically ({@link canonical}) rather than as raw strings, so a symlinked
|
|
136
|
+
* `$HOME` (`/home/u` → `/data/home/u`) or a Windows case difference does not sail past it.
|
|
137
|
+
* The original guard was an exact `===` on `resolve()`d strings and therefore failed on
|
|
138
|
+
* both, silently handing the global config back as if it were a project's own.
|
|
139
|
+
*/
|
|
140
|
+
export function findProjectConfigFiles(startDir = process.cwd()) {
|
|
141
|
+
const found = [];
|
|
142
|
+
const globals = new Set(globalConfigPaths().map(canonical));
|
|
143
|
+
const homeStop = canonical(homedir());
|
|
144
|
+
let dir = resolve(startDir);
|
|
145
|
+
for (;;) {
|
|
146
|
+
const orbitmapDir = join(dir, ORBITMAP_DIR);
|
|
147
|
+
const candidate = join(orbitmapDir, CONFIG_FILENAME);
|
|
148
|
+
if (existsSync(candidate) &&
|
|
149
|
+
!globals.has(canonical(candidate)) &&
|
|
150
|
+
!isOrbitMapHomeDir(orbitmapDir)) {
|
|
151
|
+
found.push(candidate);
|
|
152
|
+
}
|
|
153
|
+
if (canonical(dir) === homeStop)
|
|
154
|
+
return found;
|
|
155
|
+
const parent = dirname(dir);
|
|
156
|
+
if (parent === dir)
|
|
157
|
+
return found;
|
|
158
|
+
dir = parent;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Per-field walk-up: hand each project config file, nearest first, to `read` and return the
|
|
163
|
+
* first defined value together with the file it came from.
|
|
164
|
+
*
|
|
165
|
+
* "Nearest file that *sets this field* wins" — not "nearest file wins for everything".
|
|
166
|
+
* A monorepo package can set `agent` in its own `.orbitmap/config.json` and still inherit
|
|
167
|
+
* `mode`/`area` from the repository root, which is the per-field layering ADR 0002 §2
|
|
168
|
+
* promises (the `npm`/`git config` model).
|
|
169
|
+
*/
|
|
170
|
+
export function resolveProjectField(startDir, read) {
|
|
171
|
+
for (const file of findProjectConfigFiles(startDir)) {
|
|
172
|
+
const value = read(file);
|
|
173
|
+
if (value !== undefined)
|
|
174
|
+
return { value, file };
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The config file schema and the per-field project walk-up, in one place.
|
|
3
|
+
*
|
|
4
|
+
* This lives apart from `config.ts` (which owns the *global* file: loading it, migrating
|
|
5
|
+
* it, resolving credentials from it) so that both it and `workspace-resolve.ts` can use the
|
|
6
|
+
* one implementation without `workspace-resolve.ts` having to depend on the global-config
|
|
7
|
+
* machinery for it. The discovery underneath — walking up, skipping the global config,
|
|
8
|
+
* stopping at `$HOME` — lives in `paths.ts` and is shared with everything else.
|
|
9
|
+
*
|
|
10
|
+
* See `docs/adr/0002-project-scoped-config.md`.
|
|
11
|
+
*/
|
|
12
|
+
/** Storage backend for domain data. Absent in a config file means `'cloud'`. */
|
|
13
|
+
export type OrbitMapMode = 'cloud' | 'local';
|
|
14
|
+
/**
|
|
15
|
+
* Shape shared by both config files: `<project>/.orbitmap/config.json` and
|
|
16
|
+
* `~/.orbitmap/config.json`.
|
|
17
|
+
*
|
|
18
|
+
* Per ADR 0002 a config file holds **no secrets**. The agent's API key lives in
|
|
19
|
+
* `~/.orbitmap/credentials.json` (see `oauth.ts`), keyed by `agent` — the project says
|
|
20
|
+
* *which* agent to use, the machine holds *that agent's* credential. `api_key` below is a
|
|
21
|
+
* read-only fallback for configs written before this change; `loadConfig()` migrates it out
|
|
22
|
+
* on first read so it never appears in a config the CLI itself wrote.
|
|
23
|
+
*
|
|
24
|
+
* The interface lists the fields the CLI *understands*; it is not the full set of keys a
|
|
25
|
+
* file may hold. Both save functions merge into whatever is already on disk, so a key
|
|
26
|
+
* written by a newer (or older) version survives a write from this one — a read must never
|
|
27
|
+
* be able to destroy data (see `mergeIntoFile` in `config.ts`).
|
|
28
|
+
*/
|
|
29
|
+
export interface OrbitMapConfig {
|
|
30
|
+
/** On-disk format version of *this* file. `0`/absent = pre-ADR-0002. */
|
|
31
|
+
schema_version?: number;
|
|
32
|
+
/** `'cloud'` (default when absent) or `'local'`. */
|
|
33
|
+
mode?: OrbitMapMode;
|
|
34
|
+
/**
|
|
35
|
+
* Default local workspace directory. Global config only — a project's own workspace is
|
|
36
|
+
* found by the `.orbitmap/workspace.yml` / `link.json` walk-up, never by this field.
|
|
37
|
+
* **Must be absolute**: a relative value would resolve against the current directory and
|
|
38
|
+
* therefore mean a different workspace per project, which is the same cross-project leak
|
|
39
|
+
* ADR 0002 removes elsewhere. A relative value is ignored with a warning.
|
|
40
|
+
*/
|
|
41
|
+
workspace_path?: string;
|
|
42
|
+
/** Name of the agent profile to use — looked up in `~/.orbitmap/credentials.json`. */
|
|
43
|
+
agent?: string;
|
|
44
|
+
/** Default area slug/id. */
|
|
45
|
+
area?: string;
|
|
46
|
+
/** @deprecated Legacy secret, read once for migration then dropped. Never written. */
|
|
47
|
+
api_key?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parse and validate a raw config object (either file) — mistyped fields drop out instead
|
|
51
|
+
* of propagating a garbage value into the resolution ladders. Unknown keys are not
|
|
52
|
+
* represented here but are never lost on write (see `mergeIntoFile` in `config.ts`).
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseConfig(raw: unknown): OrbitMapConfig;
|
|
55
|
+
/** Read and validate one project `.orbitmap/config.json`; `undefined` when it is missing or
|
|
56
|
+
* malformed — a broken file is treated as absent rather than throwing mid-ladder. */
|
|
57
|
+
export declare function readProjectConfigFile(file: string): OrbitMapConfig | undefined;
|
|
58
|
+
/** One field's value together with the project config file that supplied it. */
|
|
59
|
+
export interface ResolvedProjectField<T> {
|
|
60
|
+
value: T;
|
|
61
|
+
/** Absolute path of the `.orbitmap/config.json` the value came from. */
|
|
62
|
+
file: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve one field by walking up from `startDir`, **per field** (ADR 0002 §2): the nearest
|
|
66
|
+
* `.orbitmap/config.json` that actually *sets* `field` wins, not merely the nearest file.
|
|
67
|
+
*
|
|
68
|
+
* A monorepo package that pins only its own `agent` still inherits `mode` and `area` from
|
|
69
|
+
* the repository root — with "nearest file wins as a unit" the root's settings would vanish
|
|
70
|
+
* the moment a package added a config of its own.
|
|
71
|
+
*
|
|
72
|
+
* Sync (like `findLinkFile` in `workspace-resolve.ts`) so the synchronous resolution ladders
|
|
73
|
+
* can use it without threading promises through every rung.
|
|
74
|
+
*/
|
|
75
|
+
export declare function resolveProjectConfigField<K extends keyof OrbitMapConfig>(field: K, startDir?: string): ResolvedProjectField<NonNullable<OrbitMapConfig[K]>> | undefined;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolveProjectField } from './paths.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parse and validate a raw config object (either file) — mistyped fields drop out instead
|
|
5
|
+
* of propagating a garbage value into the resolution ladders. Unknown keys are not
|
|
6
|
+
* represented here but are never lost on write (see `mergeIntoFile` in `config.ts`).
|
|
7
|
+
*/
|
|
8
|
+
export function parseConfig(raw) {
|
|
9
|
+
if (typeof raw !== 'object' || raw === null)
|
|
10
|
+
return {};
|
|
11
|
+
const r = raw;
|
|
12
|
+
const config = {};
|
|
13
|
+
if (typeof r['schema_version'] === 'number')
|
|
14
|
+
config.schema_version = r['schema_version'];
|
|
15
|
+
if (r['mode'] === 'cloud' || r['mode'] === 'local')
|
|
16
|
+
config.mode = r['mode'];
|
|
17
|
+
if (typeof r['workspace_path'] === 'string' && r['workspace_path']) {
|
|
18
|
+
config.workspace_path = r['workspace_path'];
|
|
19
|
+
}
|
|
20
|
+
if (typeof r['agent'] === 'string' && r['agent'])
|
|
21
|
+
config.agent = r['agent'];
|
|
22
|
+
if (typeof r['area'] === 'string' && r['area'])
|
|
23
|
+
config.area = r['area'];
|
|
24
|
+
if (typeof r['api_key'] === 'string' && r['api_key'])
|
|
25
|
+
config.api_key = r['api_key'];
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
/** Read and validate one project `.orbitmap/config.json`; `undefined` when it is missing or
|
|
29
|
+
* malformed — a broken file is treated as absent rather than throwing mid-ladder. */
|
|
30
|
+
export function readProjectConfigFile(file) {
|
|
31
|
+
try {
|
|
32
|
+
return parseConfig(JSON.parse(readFileSync(file, 'utf-8')));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve one field by walking up from `startDir`, **per field** (ADR 0002 §2): the nearest
|
|
40
|
+
* `.orbitmap/config.json` that actually *sets* `field` wins, not merely the nearest file.
|
|
41
|
+
*
|
|
42
|
+
* A monorepo package that pins only its own `agent` still inherits `mode` and `area` from
|
|
43
|
+
* the repository root — with "nearest file wins as a unit" the root's settings would vanish
|
|
44
|
+
* the moment a package added a config of its own.
|
|
45
|
+
*
|
|
46
|
+
* Sync (like `findLinkFile` in `workspace-resolve.ts`) so the synchronous resolution ladders
|
|
47
|
+
* can use it without threading promises through every rung.
|
|
48
|
+
*/
|
|
49
|
+
export function resolveProjectConfigField(field, startDir = process.cwd()) {
|
|
50
|
+
const hit = resolveProjectField(startDir, (file) => readProjectConfigFile(file)?.[field]);
|
|
51
|
+
return hit
|
|
52
|
+
? { value: hit.value, file: hit.file }
|
|
53
|
+
: undefined;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=project-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-config.js","sourceRoot":"","sources":["../src/project-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAqDjD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACvD,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,IAAI,OAAO,CAAC,CAAC,gBAAgB,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACzF,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,OAAO;QAAE,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5E,IAAI,OAAO,CAAC,CAAC,gBAAgB,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACnE,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC;QAAE,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC5E,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC;QAAE,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,CAAC;QAAE,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IAEpF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;sFACsF;AACtF,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AASD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAQ,EACR,WAAmB,OAAO,CAAC,GAAG,EAAE;IAEhC,MAAM,GAAG,GAAG,mBAAmB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,OAAO,GAAG;QACR,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAuC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;QACxE,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { type OrbitMapConfig, type OrbitMapMode } from './config.js';
|
|
2
|
+
import { ORBITMAP_DIR } from './paths.js';
|
|
3
|
+
export type { OrbitMapMode };
|
|
4
|
+
/** Name of the per-project OrbitMap directory (`<project>/.orbitmap`). Defined in
|
|
5
|
+
* `paths.ts` (which owns the project-config walk-up) and re-exported here, where most
|
|
6
|
+
* callers already look for it. */
|
|
7
|
+
export { ORBITMAP_DIR };
|
|
8
|
+
/** Project-local pointer at a workspace living elsewhere on disk. */
|
|
9
|
+
export declare const LINK_FILE = "link.json";
|
|
10
|
+
/** Marker file that identifies a directory as a local workspace. */
|
|
11
|
+
export declare const WORKSPACE_FILE = "workspace.yml";
|
|
12
|
+
/** Contents of `<project>/.orbitmap/link.json`. */
|
|
13
|
+
export interface WorkspaceLink {
|
|
14
|
+
/** Absolute path, or a path relative to the link file itself. */
|
|
15
|
+
workspace?: string;
|
|
16
|
+
/** Area slug within that workspace. */
|
|
17
|
+
area?: string;
|
|
18
|
+
}
|
|
19
|
+
/** A `link.json` that was found on disk, with the file it came from. */
|
|
20
|
+
export interface FoundWorkspaceLink {
|
|
21
|
+
/** Absolute path of the link file. */
|
|
22
|
+
file: string;
|
|
23
|
+
link: WorkspaceLink;
|
|
24
|
+
}
|
|
25
|
+
export declare function setWorkspaceFlag(value?: string): void;
|
|
26
|
+
export declare function getWorkspaceFlag(): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Walk up from `startDir` to the filesystem root looking for `.orbitmap/link.json`
|
|
29
|
+
* (same discovery behaviour as git). Returns the nearest one, or `undefined`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function findLinkFile(startDir?: string): FoundWorkspaceLink | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Walk up from `startDir` to the filesystem root looking for a directory whose
|
|
34
|
+
* `.orbitmap/` holds a `workspace.yml` — i.e. a local workspace living inside the
|
|
35
|
+
* project. Returns the absolute path of that `.orbitmap` directory, or `undefined`.
|
|
36
|
+
*
|
|
37
|
+
* Same walk-up as {@link findLinkFile} so that a workspace discovered from a nested
|
|
38
|
+
* subdirectory is both what makes the mode local and what the path ladder returns.
|
|
39
|
+
*/
|
|
40
|
+
export declare function findWorkspaceDir(startDir?: string): string | undefined;
|
|
41
|
+
export interface ResolveOptions {
|
|
42
|
+
/** Explicit `--workspace <path>`; defaults to the captured global flag. */
|
|
43
|
+
workspace?: string;
|
|
44
|
+
/** Explicit `--area <slug>`. */
|
|
45
|
+
area?: string;
|
|
46
|
+
/** Directory the resolution starts from (defaults to `process.cwd()`). */
|
|
47
|
+
cwd?: string;
|
|
48
|
+
/** Global config; pass explicitly to avoid touching `~/.orbitmap`. */
|
|
49
|
+
config?: OrbitMapConfig;
|
|
50
|
+
/** Pre-discovered link file; when omitted it is looked up from `cwd`. */
|
|
51
|
+
link?: FoundWorkspaceLink | undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Mode resolution (ADR 0002, extending spec §3.3) — **per project first, global config
|
|
55
|
+
* only as a fallback**, first match wins:
|
|
56
|
+
*
|
|
57
|
+
* 1. `--workspace <path>` flag → local (explicit override, no further checks)
|
|
58
|
+
* 2. `ORBITMAP_MODE=local|cloud` → that mode, for this invocation
|
|
59
|
+
* 3. nearest `.orbitmap/config.json` **that sets `mode`** → that value **[ADR 0002]**
|
|
60
|
+
* 4. local auto-detect: nearest `.orbitmap/link.json` or `.orbitmap/workspace.yml`,
|
|
61
|
+
* walking up from cwd to the filesystem root (as git looks for `.git`) → local
|
|
62
|
+
* 5. global config `mode` (absent or unknown ⇒ `'cloud'`)
|
|
63
|
+
*
|
|
64
|
+
* Rung 3 is resolved **per field** (`resolveProjectConfigField`), not "nearest file wins":
|
|
65
|
+
* a `packages/api/.orbitmap/config.json` that only pins an `agent` does not shadow the
|
|
66
|
+
* repository root's `mode`. See ADR 0002 §2.
|
|
67
|
+
*
|
|
68
|
+
* Rung 3 exists because the whole per-project scoping mechanism (link.json,
|
|
69
|
+
* workspace.yml-based auto-detect) was originally built only for *local* mode — a cloud
|
|
70
|
+
* project had no file of its own to declare itself cloud in, so it depended entirely on
|
|
71
|
+
* rung 5 never being flipped by another project. `.orbitmap/config.json` gives cloud
|
|
72
|
+
* projects that same voice, and it outranks rung 4 on purpose: a project that explicitly
|
|
73
|
+
* declares `mode: "cloud"` must not be dragged back into local mode by a leftover
|
|
74
|
+
* `link.json`/`workspace.yml` in the same directory.
|
|
75
|
+
*
|
|
76
|
+
* Rung 4 is what keeps *un-declared* projects independent: a directory that ran
|
|
77
|
+
* `orbitmap init` → local is local from then on via its own marker file, and a directory
|
|
78
|
+
* that never did keeps resolving through its own config — one project's choice can never
|
|
79
|
+
* flip another's.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveMode(options?: ResolveOptions): OrbitMapMode;
|
|
82
|
+
/**
|
|
83
|
+
* Workspace directory resolution (§3.3), first match wins:
|
|
84
|
+
* 1. `--workspace <path>` flag
|
|
85
|
+
* 2. `ORBITMAP_WORKSPACE` env var
|
|
86
|
+
* 3. nearest `.orbitmap/link.json` (walking up from cwd) → its `workspace` field
|
|
87
|
+
* 4. nearest `.orbitmap/workspace.yml` (walking up from cwd) → that `.orbitmap`
|
|
88
|
+
* 5. the `.orbitmap/` directory of the nearest project config that sets `mode: "local"`,
|
|
89
|
+
* when that directory is itself a workspace **[ADR 0002]**
|
|
90
|
+
* 6. global config `workspace_path` — **must be absolute** (a relative value is ignored
|
|
91
|
+
* with a warning; see {@link OrbitMapConfig.workspace_path})
|
|
92
|
+
* 7. otherwise: `OrbitMapAPIError` with code `WORKSPACE_NOT_FOUND`
|
|
93
|
+
*
|
|
94
|
+
* Rung 5 is what makes a committed `{"mode": "local"}` usable on its own: without it, a
|
|
95
|
+
* project config that declares local mode has nowhere to point and every command fails with
|
|
96
|
+
* `WORKSPACE_NOT_FOUND`. It usually resolves to the same directory as rung 4 — the point is
|
|
97
|
+
* that it does not *depend* on the auto-detect walk finding the marker first, and that it
|
|
98
|
+
* anchors on the config file that made this project local rather than on the current
|
|
99
|
+
* directory.
|
|
100
|
+
*
|
|
101
|
+
* The returned path is absolute; its existence is not verified (except for rungs 4 and 5,
|
|
102
|
+
* which are defined by the marker file).
|
|
103
|
+
*/
|
|
104
|
+
export declare function resolveWorkspacePath(options?: ResolveOptions): string;
|
|
105
|
+
/**
|
|
106
|
+
* Which rung of the area ladder produced a slug.
|
|
107
|
+
*
|
|
108
|
+
* `flag`/`env`/`link`/`project-config` are **explicit**: the user, the project's own
|
|
109
|
+
* `link.json`, or the project's own `.orbitmap/config.json` named that area, so a slug that
|
|
110
|
+
* does not exist must fail loudly. `config` is the machine-wide default (the deprecated
|
|
111
|
+
* global `~/.orbitmap/config.json` `area` — ADR 0002) — the weakest rung, and the only one
|
|
112
|
+
* a local workspace is allowed to override or ignore (see `createLocalContext`).
|
|
113
|
+
*/
|
|
114
|
+
export type AreaSource = 'flag' | 'env' | 'link' | 'project-config' | 'config';
|
|
115
|
+
/** An area slug together with the rung it came from. */
|
|
116
|
+
export interface ResolvedAreaSlug {
|
|
117
|
+
area?: string;
|
|
118
|
+
source?: AreaSource;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Area resolution (ADR 0002, extending spec §3.3), explicit sources only:
|
|
122
|
+
* `--area` → `ORBITMAP_AREA` → `link.json.area` → nearest `.orbitmap/config.json`
|
|
123
|
+
* **that sets `area`** **[ADR 0002]** → global config `area` (deprecated).
|
|
124
|
+
*
|
|
125
|
+
* The project-config rung is per-field (`resolveProjectConfigField`): a nested config that
|
|
126
|
+
* sets only `agent` does not hide an `area` pinned by the repository root.
|
|
127
|
+
*
|
|
128
|
+
* The two remaining rungs — the workspace's own `workspace.yml` `default_area` (which
|
|
129
|
+
* sits *between* the project config and the global config) and "workspace has exactly one
|
|
130
|
+
* area → auto-select it" — require reading the workspace tree and therefore live in the
|
|
131
|
+
* local adapter (`createLocalContext`); this function stays synchronous and file-store-free
|
|
132
|
+
* so that cloud mode never touches a workspace file. The `source` lets the adapter tell an
|
|
133
|
+
* explicit request apart from the machine-wide default.
|
|
134
|
+
*/
|
|
135
|
+
export declare function resolveArea(options?: ResolveOptions): ResolvedAreaSlug;
|
|
136
|
+
/** {@link resolveArea} without the rung — the historical signature. */
|
|
137
|
+
export declare function resolveAreaSlug(options?: ResolveOptions): string | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* Assert that an area was resolved. Adapters call this after their own last-resort
|
|
140
|
+
* auto-selection; `availableAreas` (when known) is surfaced in the error details.
|
|
141
|
+
*/
|
|
142
|
+
export declare function requireArea(area: string | undefined, availableAreas?: string[]): string;
|
|
143
|
+
export interface ResolvedWorkspaceContext {
|
|
144
|
+
mode: OrbitMapMode;
|
|
145
|
+
/** Absolute workspace directory; only resolved in local mode. */
|
|
146
|
+
workspacePath?: string;
|
|
147
|
+
area?: string;
|
|
148
|
+
/** Which rung of the area ladder produced {@link ResolvedWorkspaceContext.area}. */
|
|
149
|
+
areaSource?: AreaSource;
|
|
150
|
+
link?: FoundWorkspaceLink;
|
|
151
|
+
config: OrbitMapConfig;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Full context resolution. Loads the global config when one is not injected.
|
|
155
|
+
* In cloud mode the workspace directory is not resolved (and never throws
|
|
156
|
+
* `WORKSPACE_NOT_FOUND`).
|
|
157
|
+
*/
|
|
158
|
+
export declare function resolveWorkspaceContext(options?: ResolveOptions): Promise<ResolvedWorkspaceContext>;
|