@outfitter/kit 0.2.0 → 0.2.2

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 CHANGED
@@ -1,130 +1,60 @@
1
1
  # @outfitter/kit
2
2
 
3
- Version coordination meta-package for Outfitter.
3
+ Foundation facade for Outfitter.
4
4
 
5
- ## Purpose
5
+ `@outfitter/kit` provides a single foundation entrypoint over:
6
6
 
7
- This package ensures compatible versions across all `@outfitter/*` packages. Install it alongside specific packages to get coordinated version constraints via `peerDependencies`.
7
+ - `@outfitter/contracts`
8
+ - `@outfitter/types`
8
9
 
9
- ## Installation
10
+ Runtime and transport packages (`@outfitter/cli`, `@outfitter/mcp`, etc.) remain explicit dependencies.
11
+
12
+ ## Install
10
13
 
11
14
  ```bash
12
15
  bun add @outfitter/kit
13
16
  ```
14
17
 
15
- ## When to Use
18
+ ## Root Facade
16
19
 
17
- Use `@outfitter/kit` when:
20
+ The root entrypoint re-exports the contracts surface and exposes types under a namespace.
18
21
 
19
- 1. **Building applications** that use multiple Outfitter packages
20
- 2. **Ensuring compatibility** between package versions
21
- 3. **Checking version requirements** programmatically
22
+ ```typescript
23
+ import { Result, ValidationError, Types } from "@outfitter/kit";
22
24
 
23
- ```bash
24
- # Install stack alongside the packages you need
25
- bun add @outfitter/kit @outfitter/cli @outfitter/logging @outfitter/config
25
+ const value = Result.ok({ id: Types.shortId() });
26
26
  ```
27
27
 
28
- The stack's `peerDependencies` will warn if you have incompatible versions installed.
29
-
30
- ## Version Matrix
31
-
32
- See [VERSIONS.md](./VERSIONS.md) for the complete compatibility matrix.
33
-
34
- ### Current Release (0.1.0-rc.1)
28
+ ## Foundation Subpaths
35
29
 
36
- | Package | Minimum Version |
37
- |---------|-----------------|
38
- | @outfitter/contracts | 0.1.0-rc.1 |
39
- | @outfitter/types | 0.1.0-rc.1 |
40
- | @outfitter/cli | 0.1.0-rc.1 |
41
- | @outfitter/config | 0.1.0-rc.1 |
42
- | @outfitter/logging | 0.1.0-rc.1 |
43
- | @outfitter/file-ops | 0.1.0-rc.1 |
44
- | @outfitter/state | 0.1.0-rc.1 |
45
- | @outfitter/mcp | 0.1.0-rc.1 |
46
- | @outfitter/index | 0.1.0-rc.1 |
47
- | @outfitter/daemon | 0.1.0-rc.1 |
48
- | @outfitter/testing | 0.1.0-rc.1 |
30
+ Use subpaths when you want explicit import intent.
49
31
 
50
- ## Exports
51
-
52
- ### STACK_VERSION
53
-
54
- The current stack version (matches package.json).
32
+ ### Contracts
55
33
 
56
34
  ```typescript
57
- import { STACK_VERSION } from "@outfitter/kit";
58
-
59
- console.log(`Using Outfitter Stack ${STACK_VERSION}`);
35
+ import { Result, createLoggerFactory } from "@outfitter/kit/foundation/contracts";
60
36
  ```
61
37
 
62
- ### MINIMUM_VERSIONS
63
-
64
- Minimum compatible versions for each package.
38
+ ### Types
65
39
 
66
40
  ```typescript
67
- import { MINIMUM_VERSIONS } from "@outfitter/kit";
68
-
69
- // Check if a package meets the minimum version
70
- const cliMinimum = MINIMUM_VERSIONS["@outfitter/cli"]; // "0.1.0-rc.0"
41
+ import { shortId, isDefined } from "@outfitter/kit/foundation/types";
71
42
  ```
72
43
 
73
- ### OutfitterPackage
74
-
75
- Type for valid package names in the stack.
44
+ ### Aggregate Foundation
76
45
 
77
46
  ```typescript
78
- import { type OutfitterPackage, MINIMUM_VERSIONS } from "@outfitter/kit";
79
-
80
- function getMinVersion(pkg: OutfitterPackage): string {
81
- return MINIMUM_VERSIONS[pkg];
82
- }
83
-
84
- getMinVersion("@outfitter/cli"); // "0.1.0-rc.0"
85
- getMinVersion("@outfitter/invalid"); // TypeScript error
47
+ import { Result, Types } from "@outfitter/kit/foundation";
86
48
  ```
87
49
 
88
- ## API Reference
89
-
90
- | Export | Type | Description |
91
- |--------|------|-------------|
92
- | `STACK_VERSION` | `string` | Current stack version |
93
- | `MINIMUM_VERSIONS` | `Record<OutfitterPackage, string>` | Minimum versions for all packages |
94
- | `OutfitterPackage` | `type` | Union type of valid package names |
95
-
96
- ## Dependency Tiers
97
-
98
- Packages are organized into tiers based on stability:
99
-
100
- ### Foundation (cold)
101
- Stable APIs, rarely change:
102
- - `@outfitter/contracts` - Result/Error patterns
103
- - `@outfitter/types` - Branded types
50
+ ## What Kit Does Not Hide
104
51
 
105
- ### Runtime (warm)
106
- Expected to evolve:
107
- - `@outfitter/cli` - CLI framework (includes terminal rendering)
108
- - `@outfitter/config` - Configuration
109
- - `@outfitter/logging` - Structured logging
110
- - `@outfitter/file-ops` - File operations
111
- - `@outfitter/state` - State management
112
- - `@outfitter/mcp` - MCP server framework
113
- - `@outfitter/index` - SQLite FTS5 indexing
114
- - `@outfitter/daemon` - Daemon lifecycle
52
+ `@outfitter/kit` does not implicitly install or expose runtime transports.
53
+ Keep transport dependencies explicit in your app:
115
54
 
116
- ### Tooling (lukewarm)
117
- Workflow-focused:
118
- - `@outfitter/testing` - Test harnesses
119
-
120
- ## Related Packages
121
-
122
- All `@outfitter/*` packages are designed to work together. See individual package documentation:
123
-
124
- - [@outfitter/contracts](../contracts/README.md) - Result types and error patterns
125
- - [@outfitter/cli](../cli/README.md) - CLI framework
126
- - [@outfitter/daemon](../daemon/README.md) - Daemon lifecycle management
127
- - [@outfitter/testing](../testing/README.md) - Test harnesses
55
+ ```bash
56
+ bun add @outfitter/kit @outfitter/cli @outfitter/mcp
57
+ ```
128
58
 
129
59
  ## License
130
60
 
@@ -0,0 +1 @@
1
+ export * from "@outfitter/contracts";
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ // packages/kit/src/foundation/contracts.ts
3
+ export * from "@outfitter/contracts";
@@ -0,0 +1,3 @@
1
+ export * from "@outfitter/contracts";
2
+ import * as Types from "@outfitter/types";
3
+ export { Types };
@@ -0,0 +1,7 @@
1
+ // @bun
2
+ // packages/kit/src/foundation/index.ts
3
+ export * from "@outfitter/contracts";
4
+ import * as Types from "@outfitter/types";
5
+ export {
6
+ Types
7
+ };
@@ -0,0 +1 @@
1
+ export * from "@outfitter/types";
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ // packages/kit/src/foundation/types.ts
3
+ export * from "@outfitter/types";
package/dist/index.d.ts CHANGED
@@ -1,33 +1,3 @@
1
- /**
2
- * @outfitter/kit - Version coordination meta-package
3
- *
4
- * This package coordinates versions across all @outfitter packages.
5
- * Install it alongside specific packages to ensure compatible versions.
6
- *
7
- * @packageDocumentation
8
- */
9
- /**
10
- * Stack version - matches package.json version
11
- */
12
- declare const STACK_VERSION = "0.1.0-rc.1";
13
- /**
14
- * Minimum compatible versions for each package
15
- */
16
- declare const MINIMUM_VERSIONS: {
17
- readonly "@outfitter/cli": "0.1.0-rc.1";
18
- readonly "@outfitter/config": "0.1.0-rc.1";
19
- readonly "@outfitter/contracts": "0.1.0-rc.1";
20
- readonly "@outfitter/daemon": "0.1.0-rc.1";
21
- readonly "@outfitter/file-ops": "0.1.0-rc.1";
22
- readonly "@outfitter/index": "0.1.0-rc.1";
23
- readonly "@outfitter/logging": "0.1.0-rc.1";
24
- readonly "@outfitter/mcp": "0.1.0-rc.1";
25
- readonly "@outfitter/state": "0.1.0-rc.1";
26
- readonly "@outfitter/testing": "0.1.0-rc.1";
27
- readonly "@outfitter/types": "0.1.0-rc.1";
28
- };
29
- /**
30
- * Type for package names in the stack
31
- */
32
- type OutfitterPackage = keyof typeof MINIMUM_VERSIONS;
33
- export { STACK_VERSION, OutfitterPackage, MINIMUM_VERSIONS };
1
+ export * from "@outfitter/contracts";
2
+ import * as Types from "@outfitter/types";
3
+ export { Types };
package/dist/index.js CHANGED
@@ -1,19 +1,7 @@
1
- // src/index.ts
2
- var STACK_VERSION = "0.1.0-rc.1";
3
- var MINIMUM_VERSIONS = {
4
- "@outfitter/cli": "0.1.0-rc.1",
5
- "@outfitter/config": "0.1.0-rc.1",
6
- "@outfitter/contracts": "0.1.0-rc.1",
7
- "@outfitter/daemon": "0.1.0-rc.1",
8
- "@outfitter/file-ops": "0.1.0-rc.1",
9
- "@outfitter/index": "0.1.0-rc.1",
10
- "@outfitter/logging": "0.1.0-rc.1",
11
- "@outfitter/mcp": "0.1.0-rc.1",
12
- "@outfitter/state": "0.1.0-rc.1",
13
- "@outfitter/testing": "0.1.0-rc.1",
14
- "@outfitter/types": "0.1.0-rc.1"
15
- };
1
+ // @bun
2
+ // packages/kit/src/index.ts
3
+ export * from "@outfitter/contracts";
4
+ import * as Types from "@outfitter/types";
16
5
  export {
17
- STACK_VERSION,
18
- MINIMUM_VERSIONS
6
+ Types
19
7
  };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@outfitter/kit",
3
- "description": "Version coordination meta-package for Outfitter",
4
- "version": "0.2.0",
3
+ "description": "Foundation facade for Outfitter contracts and types",
4
+ "version": "0.2.2",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
8
- "VERSIONS.md"
8
+ "shared/migrations"
9
9
  ],
10
10
  "module": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts",
@@ -16,63 +16,36 @@
16
16
  "default": "./dist/index.js"
17
17
  }
18
18
  },
19
- "./package.json": "./package.json"
20
- },
21
- "peerDependencies": {
22
- "@outfitter/cli": ">=0.1.0",
23
- "@outfitter/config": ">=0.1.0",
24
- "@outfitter/contracts": ">=0.1.0",
25
- "@outfitter/daemon": ">=0.1.0",
26
- "@outfitter/file-ops": ">=0.1.0",
27
- "@outfitter/index": ">=0.1.0",
28
- "@outfitter/logging": ">=0.1.0",
29
- "@outfitter/mcp": ">=0.1.0",
30
- "@outfitter/state": ">=0.1.0",
31
- "@outfitter/testing": ">=0.1.0",
32
- "@outfitter/types": ">=0.1.0",
33
- "@outfitter/ui": ">=0.1.0-rc.1"
34
- },
35
- "peerDependenciesMeta": {
36
- "@outfitter/cli": {
37
- "optional": true
38
- },
39
- "@outfitter/config": {
40
- "optional": true
41
- },
42
- "@outfitter/contracts": {
43
- "optional": true
44
- },
45
- "@outfitter/daemon": {
46
- "optional": true
47
- },
48
- "@outfitter/file-ops": {
49
- "optional": true
50
- },
51
- "@outfitter/index": {
52
- "optional": true
53
- },
54
- "@outfitter/logging": {
55
- "optional": true
56
- },
57
- "@outfitter/mcp": {
58
- "optional": true
59
- },
60
- "@outfitter/state": {
61
- "optional": true
19
+ "./foundation/contracts": {
20
+ "import": {
21
+ "types": "./dist/foundation/contracts.d.ts",
22
+ "default": "./dist/foundation/contracts.js"
23
+ }
62
24
  },
63
- "@outfitter/testing": {
64
- "optional": true
25
+ "./foundation/types": {
26
+ "import": {
27
+ "types": "./dist/foundation/types.d.ts",
28
+ "default": "./dist/foundation/types.js"
29
+ }
65
30
  },
66
- "@outfitter/types": {
67
- "optional": true
31
+ "./foundation": {
32
+ "import": {
33
+ "types": "./dist/foundation/index.d.ts",
34
+ "default": "./dist/foundation/index.js"
35
+ }
68
36
  },
69
- "@outfitter/ui": {
70
- "optional": true
71
- }
37
+ "./package.json": "./package.json"
38
+ },
39
+ "dependencies": {
40
+ "@outfitter/contracts": "0.2.0",
41
+ "@outfitter/types": "0.2.0"
72
42
  },
73
43
  "scripts": {
74
- "build": "bunup --filter @outfitter/kit",
75
- "typecheck": "tsc --noEmit"
44
+ "build": "bun run sync:migrations && cd ../.. && bunup --filter @outfitter/kit",
45
+ "test": "bun test",
46
+ "typecheck": "tsc --noEmit",
47
+ "sync:migrations": "bun run ../../scripts/sync-migrations.ts",
48
+ "prepack": "bun run sync:migrations"
76
49
  },
77
50
  "devDependencies": {
78
51
  "@types/bun": "latest",
@@ -0,0 +1,63 @@
1
+ # Migration Docs
2
+
3
+ Versioned migration guides for `@outfitter/*` packages. Used by the `outfitter-check` skill and `outfitter update` CLI command to compose upgrade guidance.
4
+
5
+ ## Naming Convention
6
+
7
+ ```
8
+ outfitter-<package>-<version>.md
9
+ ```
10
+
11
+ Examples:
12
+ - `outfitter-contracts-0.2.0.md`
13
+ - `outfitter-cli-0.2.0.md`
14
+
15
+ ## Ordering
16
+
17
+ Migration docs are applied sequentially by version (semver ascending). Within a version, packages are ordered by dependency tier:
18
+
19
+ 1. **Foundation**: contracts, types
20
+ 2. **Runtime**: cli, mcp, config, logging, file-ops, state, index, daemon, testing
21
+ 3. **Tooling**: outfitter (umbrella CLI)
22
+
23
+ ## Template
24
+
25
+ ```markdown
26
+ ---
27
+ package: @outfitter/<name>
28
+ version: 0.2.0
29
+ breaking: false
30
+ ---
31
+
32
+ # @outfitter/<name> → 0.2.0
33
+
34
+ ## New APIs
35
+
36
+ <what's available now, with code examples>
37
+
38
+ ## Migration Steps
39
+
40
+ <specific things to change, with before/after>
41
+
42
+ ## No Action Required
43
+
44
+ <things that just work after bumping>
45
+ ```
46
+
47
+ ### Frontmatter Fields
48
+
49
+ | Field | Type | Description |
50
+ |-------|------|-------------|
51
+ | `package` | string | Full package name (`@outfitter/contracts`) |
52
+ | `version` | string | Target version |
53
+ | `breaking` | boolean | Whether this version has breaking changes |
54
+
55
+ ## Adding New Migration Docs
56
+
57
+ When releasing a new version:
58
+
59
+ 1. Create `outfitter-<package>-<version>.md` for each package with changes
60
+ 2. Follow the template above
61
+ 3. Include before/after code examples for any API changes
62
+ 4. Mark `breaking: true` if there are breaking changes
63
+ 5. Omit packages that only received dependency bumps (no API changes)
@@ -0,0 +1,150 @@
1
+ ---
2
+ package: "@outfitter/cli"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/cli → 0.2.0
8
+
9
+ ## New APIs
10
+
11
+ ### Portable `createCLI` from `@outfitter/cli/command`
12
+
13
+ `createCLI` and `command` are now available from the `@outfitter/cli/command` subpath export. This is the recommended import path for building CLIs.
14
+
15
+ ```typescript
16
+ import { createCLI, command } from "@outfitter/cli/command";
17
+
18
+ const cli = createCLI({
19
+ name: "my-tool",
20
+ version: "1.0.0",
21
+ description: "My CLI tool",
22
+ });
23
+
24
+ cli.register(
25
+ command("hello <name>")
26
+ .description("Greet someone")
27
+ .action(async (name) => {
28
+ console.log(`Hello, ${name}!`);
29
+ })
30
+ );
31
+
32
+ await cli.parse(process.argv);
33
+ ```
34
+
35
+ ### Command Normalization
36
+
37
+ Command specs now separate the command name from argument syntax. The CLI framework handles parsing `"get <id>"` into a command named `get` with argument `<id>`.
38
+
39
+ ```typescript
40
+ // Arguments are separated from the command name during registration
41
+ command("get <id>") // name: "get", args: ["<id>"]
42
+ command("[directory]") // name: undefined, args: ["[directory]"]
43
+ command("add <block>") // name: "add", args: ["<block>"]
44
+ ```
45
+
46
+ ### `--json` Output Mode
47
+
48
+ Commands can support structured JSON output via the `--json` flag:
49
+
50
+ ```typescript
51
+ import { output } from "@outfitter/cli/output";
52
+
53
+ // Human-readable (default)
54
+ await output(["Line 1", "Line 2"]);
55
+
56
+ // JSON mode (via --json flag or OUTFITTER_JSON=1)
57
+ await output({ users: [...] }, { mode: "json" });
58
+
59
+ // JSONL mode (for streaming)
60
+ await output(record, { mode: "jsonl" });
61
+ ```
62
+
63
+ Mode is auto-detected:
64
+ 1. Explicit `mode` option
65
+ 2. `OUTFITTER_JSONL=1` env var → jsonl
66
+ 3. `OUTFITTER_JSON=1` env var → json
67
+ 4. TTY → human, non-TTY → json
68
+
69
+ ### `pageSize` Prompt Option
70
+
71
+ Select and multi-select prompts now accept a `pageSize` option to control visible items:
72
+
73
+ ```typescript
74
+ import { promptSelect, promptMultiSelect } from "@outfitter/cli/prompt";
75
+
76
+ const choice = await promptSelect({
77
+ message: "Pick a template",
78
+ options: [...],
79
+ pageSize: 8, // Show 8 items at a time
80
+ });
81
+
82
+ const choices = await promptMultiSelect({
83
+ message: "Select features",
84
+ options: [...],
85
+ pageSize: 6,
86
+ });
87
+ ```
88
+
89
+ ### `ANSI.inverse` + Theme Support
90
+
91
+ The `ANSI` constant now includes `inverse` for swapping foreground/background colors. Themes expose it as a function:
92
+
93
+ ```typescript
94
+ import { ANSI } from "@outfitter/cli";
95
+
96
+ // Raw escape code
97
+ console.log(`${ANSI.inverse}Highlighted${ANSI.reset}`);
98
+
99
+ // Via theme
100
+ import { createTheme } from "@outfitter/cli";
101
+ const theme = createTheme();
102
+ console.log(theme.inverse("Highlighted"));
103
+ ```
104
+
105
+ New theme semantic colors:
106
+ - `theme.accent(text)` — Cyan for interactive elements
107
+ - `theme.highlight(text)` — Bold for strong emphasis
108
+ - `theme.link(text)` — Cyan + underline for URLs
109
+ - `theme.destructive(text)` — Bright red for dangerous actions
110
+ - `theme.subtle(text)` — Dim gray for less prominent text
111
+
112
+ ### `getSeverityIndicator()`
113
+
114
+ Severity-level indicator function for compliance and diagnostic output:
115
+
116
+ ```typescript
117
+ import { getSeverityIndicator } from "@outfitter/cli/render";
118
+
119
+ getSeverityIndicator("minor"); // "◇"
120
+ getSeverityIndicator("moderate"); // "◆"
121
+ getSeverityIndicator("severe"); // "◈"
122
+
123
+ // Fallback for terminals without unicode
124
+ getSeverityIndicator("minor", false); // "◊"
125
+ getSeverityIndicator("moderate", false); // "♦"
126
+ getSeverityIndicator("severe", false); // "♦♦"
127
+ ```
128
+
129
+ ## Migration Steps
130
+
131
+ ### Import `createCLI` from the command subpath
132
+
133
+ **Before:**
134
+ ```typescript
135
+ import { createCLI } from "@outfitter/cli/cli";
136
+ ```
137
+
138
+ **After:**
139
+ ```typescript
140
+ import { createCLI, command } from "@outfitter/cli/command";
141
+ ```
142
+
143
+ Both paths work, but `@outfitter/cli/command` is the canonical entry point.
144
+
145
+ ## No Action Required
146
+
147
+ - Existing `output()` calls work unchanged — JSON mode is opt-in
148
+ - Theme color functions are backward-compatible (new colors are additive)
149
+ - `ANSI` constant additions don't affect existing usage
150
+ - Prompt APIs are backward-compatible (`pageSize` is optional)
@@ -0,0 +1,59 @@
1
+ ---
2
+ package: "@outfitter/config"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/config → 0.2.0
8
+
9
+ ## New APIs
10
+
11
+ ### JSONC Parsing
12
+
13
+ Config files with `.jsonc` or `.json5` extensions are now parsed with comment support via JSON5:
14
+
15
+ ```typescript
16
+ import { loadConfig } from "@outfitter/config";
17
+
18
+ // config.jsonc is now a valid config file
19
+ const result = loadConfig("my-app", schema);
20
+ ```
21
+
22
+ Supported config formats:
23
+ - `.json` — Strict JSON (no comments)
24
+ - `.jsonc` / `.json5` — JSON with comments and trailing commas
25
+ - `.toml` — TOML format
26
+ - `.yaml` / `.yml` — YAML with merge key support
27
+
28
+ ### MCP Resource Handlers
29
+
30
+ Config loading now integrates with MCP resource handlers, allowing config values to be exposed as MCP resources.
31
+
32
+ ## Migration Steps
33
+
34
+ ### Use `.jsonc` for configs that need comments
35
+
36
+ **Before** (workaround with `.json`):
37
+ ```json
38
+ {
39
+ "debug": true
40
+ }
41
+ ```
42
+
43
+ **After** (`.jsonc` with comments):
44
+ ```jsonc
45
+ {
46
+ // Enable debug mode for development
47
+ "debug": true,
48
+
49
+ // API endpoint — override in production
50
+ "apiUrl": "http://localhost:3000",
51
+ }
52
+ ```
53
+
54
+ ## No Action Required
55
+
56
+ - Existing `.json`, `.toml`, `.yaml` configs work unchanged
57
+ - `loadConfig()` signature unchanged
58
+ - XDG directory resolution unchanged
59
+ - `extends` support unchanged
@@ -0,0 +1,200 @@
1
+ ---
2
+ package: "@outfitter/contracts"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/contracts → 0.2.0
8
+
9
+ ## New APIs
10
+
11
+ ### `create()` Static Factories
12
+
13
+ All error classes now have a `create()` static method that auto-generates messages from structured inputs. This is the preferred way to construct errors.
14
+
15
+ ```typescript
16
+ import {
17
+ ValidationError,
18
+ NotFoundError,
19
+ AmbiguousError,
20
+ ConflictError,
21
+ PermissionError,
22
+ TimeoutError,
23
+ RateLimitError,
24
+ NetworkError,
25
+ InternalError,
26
+ AuthError,
27
+ CancelledError,
28
+ } from "@outfitter/contracts";
29
+
30
+ // ValidationError — field + reason
31
+ ValidationError.create("email", "format invalid");
32
+ // → message: "email: format invalid", field: "email"
33
+
34
+ // NotFoundError — resourceType + resourceId
35
+ NotFoundError.create("user", "user-123");
36
+ // → message: "user not found: user-123", resourceType: "user", resourceId: "user-123"
37
+
38
+ // AmbiguousError — what + candidates
39
+ AmbiguousError.create("heading", ["Introduction", "Intro to APIs"]);
40
+ // → message: "Ambiguous heading: 2 matches found", candidates: [...]
41
+
42
+ // ConflictError — message
43
+ ConflictError.create("User already exists");
44
+
45
+ // PermissionError — message
46
+ PermissionError.create("Cannot delete admin users");
47
+
48
+ // TimeoutError — operation + timeoutMs
49
+ TimeoutError.create("database query", 5000);
50
+ // → message: "database query timed out after 5000ms"
51
+
52
+ // RateLimitError — message + optional retryAfterSeconds
53
+ RateLimitError.create("API rate limit exceeded", 30);
54
+
55
+ // NetworkError — message
56
+ NetworkError.create("Failed to connect to API");
57
+
58
+ // InternalError — message
59
+ InternalError.create("Unexpected failure");
60
+
61
+ // AuthError — message + optional reason
62
+ AuthError.create("Invalid API key", "invalid");
63
+
64
+ // CancelledError — message
65
+ CancelledError.create("Operation cancelled by user");
66
+ ```
67
+
68
+ All `create()` methods accept an optional `context` parameter:
69
+
70
+ ```typescript
71
+ ValidationError.create("email", "format invalid", { received: "not-an-email" });
72
+ NotFoundError.create("user", "user-123", { searchedIn: "active_users" });
73
+ ```
74
+
75
+ ### `context` Field
76
+
77
+ All error classes now support an optional `context` field for attaching structured metadata without overloading the message string:
78
+
79
+ ```typescript
80
+ new NotFoundError({
81
+ message: "Heading not found",
82
+ resourceType: "heading",
83
+ resourceId: "h:Intro",
84
+ context: { availableHeadings: ["Introduction", "Getting Started"] },
85
+ });
86
+
87
+ new ValidationError({
88
+ message: "Value out of range",
89
+ field: "age",
90
+ context: { min: 0, max: 150, received: -1 },
91
+ });
92
+
93
+ new InternalError({
94
+ message: "Failed to add block",
95
+ context: { action: "add", blockName: "scaffolding" },
96
+ });
97
+ ```
98
+
99
+ ### `AmbiguousError`
100
+
101
+ New error class for disambiguation scenarios. Uses `validation` category (exit 1, HTTP 400).
102
+
103
+ ```typescript
104
+ import { AmbiguousError } from "@outfitter/contracts";
105
+
106
+ // When a search matches multiple candidates
107
+ const error = new AmbiguousError({
108
+ message: "Multiple headings match 'Intro'",
109
+ candidates: ["Introduction", "Intro to APIs"],
110
+ });
111
+
112
+ // Or use the factory
113
+ const error = AmbiguousError.create("heading", ["Introduction", "Intro to APIs"]);
114
+
115
+ // Access candidates for disambiguation UI
116
+ error.candidates; // ["Introduction", "Intro to APIs"]
117
+ error.category; // "validation"
118
+ error.exitCode(); // 1
119
+ ```
120
+
121
+ ### `AssertionError`
122
+
123
+ New error class for invariant violations. Uses `internal` category (exit 8, HTTP 500).
124
+
125
+ ```typescript
126
+ import { AssertionError } from "@outfitter/contracts";
127
+
128
+ // Used by assertion utilities that return Result instead of throwing
129
+ const error = new AssertionError({
130
+ message: "Cache should always have value after init",
131
+ });
132
+ ```
133
+
134
+ ### `expect()` Result Boundary Helper
135
+
136
+ Unwraps a `Result` or throws with a contextual message. Use at system boundaries where you need to exit the Result railway.
137
+
138
+ ```typescript
139
+ import { expect } from "@outfitter/contracts";
140
+
141
+ // Unwraps Ok, throws on Err
142
+ const config = expect(loadConfig(), "Failed to load config");
143
+
144
+ // Throws: Error("Failed to load config: <original error>")
145
+ ```
146
+
147
+ ## Migration Steps
148
+
149
+ ### Use `create()` factories instead of manual construction
150
+
151
+ **Before:**
152
+ ```typescript
153
+ new ValidationError({ message: "email: format invalid", field: "email" });
154
+ new NotFoundError({ message: "user not found: user-123", resourceType: "user", resourceId: "user-123" });
155
+ ```
156
+
157
+ **After:**
158
+ ```typescript
159
+ ValidationError.create("email", "format invalid");
160
+ NotFoundError.create("user", "user-123");
161
+ ```
162
+
163
+ ### Use `context` instead of `details`
164
+
165
+ The `context` field replaces ad-hoc `details` patterns:
166
+
167
+ **Before:**
168
+ ```typescript
169
+ new InternalError("Unexpected error", { cause: error });
170
+ ```
171
+
172
+ **After:**
173
+ ```typescript
174
+ new InternalError({ message: "Unexpected error", context: { cause: error } });
175
+ // Or with factory:
176
+ InternalError.create("Unexpected error", { cause: error });
177
+ ```
178
+
179
+ ### Use `AmbiguousError` for multi-match scenarios
180
+
181
+ **Before:**
182
+ ```typescript
183
+ new ValidationError({
184
+ message: `Multiple matches found for '${query}'`,
185
+ field: "query",
186
+ });
187
+ ```
188
+
189
+ **After:**
190
+ ```typescript
191
+ AmbiguousError.create(query, matchedCandidates);
192
+ // Carries the candidate list for transport layers to use
193
+ ```
194
+
195
+ ## No Action Required
196
+
197
+ - Existing error constructors still work — `create()` is additive
198
+ - `exitCode()` and `statusCode()` methods unchanged
199
+ - `_tag` discriminators unchanged
200
+ - Pattern matching with `_tag` works the same way
@@ -0,0 +1,11 @@
1
+ ---
2
+ package: "@outfitter/daemon"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/daemon → 0.2.0
8
+
9
+ ## No Action Required
10
+
11
+ Version alignment release. No API changes — bump your dependency version and continue.
@@ -0,0 +1,11 @@
1
+ ---
2
+ package: "@outfitter/file-ops"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/file-ops → 0.2.0
8
+
9
+ ## No Action Required
10
+
11
+ Version alignment release. No API changes — bump your dependency version and continue.
@@ -0,0 +1,11 @@
1
+ ---
2
+ package: "@outfitter/index"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/index → 0.2.0
8
+
9
+ ## No Action Required
10
+
11
+ Version alignment release. No API changes — bump your dependency version and continue.
@@ -0,0 +1,66 @@
1
+ ---
2
+ package: "@outfitter/logging"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/logging → 0.2.0
8
+
9
+ ## New APIs
10
+
11
+ ### Console Sink Fallback
12
+
13
+ `createConsoleSink()` provides a ready-to-use sink that routes log messages to the appropriate console method based on severity:
14
+
15
+ ```typescript
16
+ import { createConsoleSink } from "@outfitter/logging";
17
+
18
+ const sink = createConsoleSink({ colors: true });
19
+
20
+ // Routing:
21
+ // fatal, error → console.error()
22
+ // warn → console.warn()
23
+ // debug, trace → console.debug()
24
+ // info → console.info()
25
+ ```
26
+
27
+ Color support is auto-detected from `process.stdout.isTTY` if not explicitly set.
28
+
29
+ ### Logger Method Overloads
30
+
31
+ Logger methods now accept both string and structured log arguments:
32
+
33
+ ```typescript
34
+ // String message
35
+ logger.info("User logged in");
36
+
37
+ // Structured with context
38
+ logger.info("User logged in", { userId: "123", method: "oauth" });
39
+ ```
40
+
41
+ ## Migration Steps
42
+
43
+ ### Remove top-level `node:*` imports
44
+
45
+ If you were importing Node.js built-in modules at the top level alongside `@outfitter/logging`, the package no longer relies on top-level `node:*` imports. This improves compatibility with edge runtimes.
46
+
47
+ **Before:**
48
+ ```typescript
49
+ import { createConsoleSink } from "@outfitter/logging";
50
+ // Package internally used: import { Console } from "node:console";
51
+ ```
52
+
53
+ **After:**
54
+ ```typescript
55
+ import { createConsoleSink } from "@outfitter/logging";
56
+ // Package uses runtime-safe console access
57
+ ```
58
+
59
+ This change is transparent — your code doesn't need modification unless you were relying on side effects from the package importing `node:*` modules.
60
+
61
+ ## No Action Required
62
+
63
+ - Existing logger setup works unchanged
64
+ - Redaction patterns (`DEFAULT_PATTERNS`) unchanged
65
+ - Sensitive key detection unchanged
66
+ - LogTape integration unchanged
@@ -0,0 +1,180 @@
1
+ ---
2
+ package: "@outfitter/mcp"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/mcp → 0.2.0
8
+
9
+ ## New APIs
10
+
11
+ ### Tool Annotations
12
+
13
+ Tools can now declare behavioral hints for clients via `annotations`:
14
+
15
+ ```typescript
16
+ import { defineTool } from "@outfitter/mcp";
17
+
18
+ const listUsers = defineTool({
19
+ name: "list-users",
20
+ description: "List all users",
21
+ inputSchema: z.object({ limit: z.number().optional() }),
22
+ annotations: {
23
+ readOnlyHint: true, // Does not modify state
24
+ destructiveHint: false, // Not destructive
25
+ idempotentHint: true, // Same input → same result
26
+ openWorldHint: false, // Operates on closed dataset
27
+ },
28
+ handler: async (input, ctx) => { /* ... */ },
29
+ });
30
+ ```
31
+
32
+ Annotation hints help clients make decisions about confirmation dialogs, caching, and retry behavior.
33
+
34
+ ### Resource Read Handlers
35
+
36
+ Resources can now include inline read handlers instead of relying on external dispatch:
37
+
38
+ ```typescript
39
+ import type { ResourceDefinition } from "@outfitter/mcp";
40
+
41
+ const configResource: ResourceDefinition = {
42
+ uri: "config:///app",
43
+ name: "App Configuration",
44
+ description: "Current application configuration",
45
+ mimeType: "application/json",
46
+ handler: async (uri, ctx) => {
47
+ const config = await loadConfig();
48
+ return Result.ok([{ uri, text: JSON.stringify(config) }]);
49
+ },
50
+ };
51
+ ```
52
+
53
+ ### Resource Templates
54
+
55
+ URI-templated resources with variable completion:
56
+
57
+ ```typescript
58
+ import type { ResourceTemplateDefinition } from "@outfitter/mcp";
59
+
60
+ const userProfile: ResourceTemplateDefinition = {
61
+ uriTemplate: "db:///users/{userId}/profile",
62
+ name: "User Profile",
63
+ description: "Profile for a specific user",
64
+ handler: async (uri, variables, ctx) => {
65
+ const user = await getUser(variables.userId);
66
+ return Result.ok([{
67
+ uri,
68
+ text: JSON.stringify(user),
69
+ mimeType: "application/json",
70
+ }]);
71
+ },
72
+ complete: {
73
+ userId: async (partial) => {
74
+ const users = await searchUsers(partial);
75
+ return { values: users.map((u) => u.id) };
76
+ },
77
+ },
78
+ };
79
+ ```
80
+
81
+ ### Prompt System
82
+
83
+ Define reusable prompt templates for MCP clients:
84
+
85
+ ```typescript
86
+ import type { PromptDefinition } from "@outfitter/mcp";
87
+
88
+ const codeReview: PromptDefinition = {
89
+ name: "code-review",
90
+ description: "Review code changes",
91
+ arguments: [
92
+ { name: "file", description: "File to review", required: true },
93
+ { name: "focus", description: "Review focus area", required: false },
94
+ ],
95
+ handler: async (args, ctx) => {
96
+ return {
97
+ messages: [
98
+ {
99
+ role: "user",
100
+ content: {
101
+ type: "text",
102
+ text: `Review ${args.file} focusing on ${args.focus ?? "general quality"}`,
103
+ },
104
+ },
105
+ ],
106
+ };
107
+ },
108
+ };
109
+ ```
110
+
111
+ ### Content Annotations
112
+
113
+ Annotate content with audience and priority hints:
114
+
115
+ ```typescript
116
+ {
117
+ type: "text",
118
+ text: "Debug trace information",
119
+ annotations: {
120
+ audience: ["assistant"], // Not shown to user
121
+ priority: 0.2, // Low priority
122
+ },
123
+ }
124
+ ```
125
+
126
+ ### Completions, Logging, Notifications, Progress
127
+
128
+ - **Completions**: Resource template variables and prompt arguments support auto-completion handlers
129
+ - **Logging**: Structured logging via `ctx.logger` with severity levels
130
+ - **Notifications**: Server-to-client notifications for resource changes
131
+ - **Progress**: Long-running operations can report progress via `ctx.progress(current, total)`
132
+
133
+ ## Migration Steps
134
+
135
+ ### Add annotations to existing tools
136
+
137
+ **Before:**
138
+ ```typescript
139
+ const tool = defineTool({
140
+ name: "delete-user",
141
+ description: "Delete a user",
142
+ inputSchema: z.object({ id: z.string() }),
143
+ handler: deleteUserHandler,
144
+ });
145
+ ```
146
+
147
+ **After:**
148
+ ```typescript
149
+ const tool = defineTool({
150
+ name: "delete-user",
151
+ description: "Delete a user",
152
+ inputSchema: z.object({ id: z.string() }),
153
+ annotations: {
154
+ readOnlyHint: false,
155
+ destructiveHint: true,
156
+ },
157
+ handler: deleteUserHandler,
158
+ });
159
+ ```
160
+
161
+ ### Add `.describe()` to Zod schemas for MCP tools
162
+
163
+ MCP clients use schema descriptions for tool documentation:
164
+
165
+ ```typescript
166
+ // Before
167
+ z.object({ limit: z.number().optional() })
168
+
169
+ // After
170
+ z.object({
171
+ limit: z.number().optional().describe("Maximum number of results to return"),
172
+ })
173
+ ```
174
+
175
+ ## No Action Required
176
+
177
+ - Existing tool definitions work without annotations
178
+ - `deferLoading` defaults to `true` (unchanged)
179
+ - Handler signatures are backward-compatible
180
+ - Resource and prompt systems are additive
@@ -0,0 +1,11 @@
1
+ ---
2
+ package: "@outfitter/state"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/state → 0.2.0
8
+
9
+ ## No Action Required
10
+
11
+ Version alignment release. No API changes — bump your dependency version and continue.
@@ -0,0 +1,78 @@
1
+ ---
2
+ package: "@outfitter/testing"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/testing → 0.2.0
8
+
9
+ ## New APIs
10
+
11
+ ### Type Re-exports
12
+
13
+ All harness and factory types are now re-exported from the package root for convenient access:
14
+
15
+ ```typescript
16
+ import {
17
+ // Fixtures
18
+ createFixture,
19
+ loadFixture,
20
+ withEnv,
21
+ withTempDir,
22
+
23
+ // CLI Harness
24
+ createCliHarness,
25
+ captureCLI,
26
+ mockStdin,
27
+ type CliHarness,
28
+ type CliResult,
29
+ type CliTestResult,
30
+
31
+ // MCP Harness
32
+ createMcpHarness,
33
+ createMcpTestHarness,
34
+ type McpHarness,
35
+ type McpTestHarnessOptions,
36
+ type McpToolResponse,
37
+
38
+ // Mock Factories
39
+ createTestConfig,
40
+ createTestContext,
41
+ createTestLogger,
42
+ type LogEntry,
43
+ type TestLogger,
44
+ } from "@outfitter/testing";
45
+ ```
46
+
47
+ ## Migration Steps
48
+
49
+ ### Remove top-level `node:*` imports
50
+
51
+ Like `@outfitter/logging`, the testing package no longer uses top-level `node:*` imports. This is transparent to consumers.
52
+
53
+ ### Import types from the root
54
+
55
+ **Before** (importing from submodules):
56
+ ```typescript
57
+ import { createCliHarness } from "@outfitter/testing/cli-harness";
58
+ import { createMcpHarness } from "@outfitter/testing/mcp-harness";
59
+ import type { CliHarness } from "@outfitter/testing/cli-harness";
60
+ ```
61
+
62
+ **After** (import from root):
63
+ ```typescript
64
+ import {
65
+ createCliHarness,
66
+ createMcpHarness,
67
+ type CliHarness,
68
+ } from "@outfitter/testing";
69
+ ```
70
+
71
+ Both paths work, but the root import is preferred.
72
+
73
+ ## No Action Required
74
+
75
+ - Existing test harness usage works unchanged
76
+ - Fixture utilities unchanged
77
+ - Mock factory APIs unchanged
78
+ - Submodule imports still work (root is additive)
@@ -0,0 +1,66 @@
1
+ ---
2
+ package: "@outfitter/tooling"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/tooling → 0.2.0
8
+
9
+ ## New (First npm Publish)
10
+
11
+ This is the first npm-published release of `@outfitter/tooling`. It provides dev tooling presets and a CLI for Outfitter projects.
12
+
13
+ ### Biome Preset
14
+
15
+ Shared Biome configuration with Outfitter-specific rules:
16
+
17
+ ```json
18
+ {
19
+ "extends": ["@outfitter/tooling/biome"]
20
+ }
21
+ ```
22
+
23
+ ### TypeScript Presets
24
+
25
+ Strict TypeScript configurations:
26
+
27
+ ```json
28
+ // tsconfig.json — strict base
29
+ { "extends": "@outfitter/tooling/tsconfig" }
30
+
31
+ // tsconfig.json — Bun variant
32
+ { "extends": "@outfitter/tooling/tsconfig-bun" }
33
+ ```
34
+
35
+ ### Lefthook Git Hooks
36
+
37
+ Pre-configured git hooks for pre-commit (format, lint, typecheck) and pre-push (build, test):
38
+
39
+ ```yaml
40
+ # lefthook.yml
41
+ extends:
42
+ - "@outfitter/tooling/lefthook"
43
+ ```
44
+
45
+ ### CLI Commands
46
+
47
+ ```bash
48
+ # Initialize tooling in a project
49
+ bunx @outfitter/tooling init
50
+
51
+ # Check formatting and linting
52
+ bunx @outfitter/tooling check
53
+
54
+ # Auto-fix issues
55
+ bunx @outfitter/tooling fix
56
+
57
+ # Upgrade Bun version across the repo
58
+ bunx @outfitter/tooling upgrade-bun [version]
59
+
60
+ # TDD-aware pre-push hook
61
+ bunx @outfitter/tooling pre-push
62
+ ```
63
+
64
+ ## No Action Required
65
+
66
+ If you were previously using `@outfitter/tooling` from the monorepo workspace, no changes needed — just ensure your dependency points to `^0.2.0`.
@@ -0,0 +1,11 @@
1
+ ---
2
+ package: "@outfitter/types"
3
+ version: 0.2.0
4
+ breaking: false
5
+ ---
6
+
7
+ # @outfitter/types → 0.2.0
8
+
9
+ ## No Action Required
10
+
11
+ Version alignment release. No API changes — bump your dependency version and continue.
package/VERSIONS.md DELETED
@@ -1,38 +0,0 @@
1
- # Version Compatibility Matrix
2
-
3
- This document tracks version compatibility across @outfitter packages.
4
-
5
- ## Current Release
6
-
7
- | Package | Version | Status |
8
- |---------|---------|--------|
9
- | @outfitter/contracts | 0.1.0-rc.0 | RC |
10
- | @outfitter/types | 0.1.0-rc.0 | RC |
11
- | @outfitter/cli | 0.1.0-rc.0 | RC |
12
- | @outfitter/config | 0.1.0-rc.0 | RC |
13
- | @outfitter/logging | 0.1.0-rc.0 | RC |
14
- | @outfitter/file-ops | 0.1.0-rc.0 | RC |
15
- | @outfitter/state | 0.1.0-rc.0 | RC |
16
- | @outfitter/mcp | 0.1.0-rc.0 | RC |
17
- | @outfitter/index | 0.1.0-rc.0 | RC |
18
- | @outfitter/daemon | 0.1.0-rc.0 | RC |
19
- | @outfitter/testing | 0.1.0-rc.0 | RC |
20
-
21
- ## Dependency Tiers
22
-
23
- ### Foundation (cold)
24
- - `@outfitter/contracts` - Result/Error patterns
25
- - `@outfitter/types` - Branded types
26
-
27
- ### Runtime (warm)
28
- - `@outfitter/cli` - CLI framework (includes terminal rendering)
29
- - `@outfitter/config` - Configuration
30
- - `@outfitter/logging` - Structured logging
31
- - `@outfitter/file-ops` - File operations
32
- - `@outfitter/state` - State management
33
- - `@outfitter/mcp` - MCP server framework
34
- - `@outfitter/index` - SQLite FTS5 indexing
35
- - `@outfitter/daemon` - Daemon lifecycle
36
-
37
- ### Tooling (lukewarm)
38
- - `@outfitter/testing` - Test harnesses