@outfitter/kit 0.2.0 → 0.2.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/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- // src/index.ts
1
+ // @bun
2
+ // packages/kit/src/index.ts
2
3
  var STACK_VERSION = "0.1.0-rc.1";
3
4
  var MINIMUM_VERSIONS = {
4
5
  "@outfitter/cli": "0.1.0-rc.1",
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@outfitter/kit",
3
3
  "description": "Version coordination meta-package for Outfitter",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
8
- "VERSIONS.md"
8
+ "VERSIONS.md",
9
+ "shared/migrations"
9
10
  ],
10
11
  "module": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts",
@@ -71,8 +72,10 @@
71
72
  }
72
73
  },
73
74
  "scripts": {
74
- "build": "bunup --filter @outfitter/kit",
75
- "typecheck": "tsc --noEmit"
75
+ "build": "bun run sync:migrations && bunup --filter @outfitter/kit",
76
+ "typecheck": "tsc --noEmit",
77
+ "sync:migrations": "bun run ../../scripts/sync-migrations.ts",
78
+ "prepack": "bun run sync:migrations"
76
79
  },
77
80
  "devDependencies": {
78
81
  "@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.