@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 +26 -96
- package/dist/foundation/contracts.d.ts +1 -0
- package/dist/foundation/contracts.js +3 -0
- package/dist/foundation/index.d.ts +3 -0
- package/dist/foundation/index.js +7 -0
- package/dist/foundation/types.d.ts +1 -0
- package/dist/foundation/types.js +3 -0
- package/dist/index.d.ts +3 -33
- package/dist/index.js +5 -17
- package/package.json +28 -55
- package/shared/migrations/README.md +63 -0
- package/shared/migrations/outfitter-cli-0.2.0.md +150 -0
- package/shared/migrations/outfitter-config-0.2.0.md +59 -0
- package/shared/migrations/outfitter-contracts-0.2.0.md +200 -0
- package/shared/migrations/outfitter-daemon-0.2.0.md +11 -0
- package/shared/migrations/outfitter-file-ops-0.2.0.md +11 -0
- package/shared/migrations/outfitter-index-0.2.0.md +11 -0
- package/shared/migrations/outfitter-logging-0.2.0.md +66 -0
- package/shared/migrations/outfitter-mcp-0.2.0.md +180 -0
- package/shared/migrations/outfitter-state-0.2.0.md +11 -0
- package/shared/migrations/outfitter-testing-0.2.0.md +78 -0
- package/shared/migrations/outfitter-tooling-0.2.0.md +66 -0
- package/shared/migrations/outfitter-types-0.2.0.md +11 -0
- package/VERSIONS.md +0 -38
package/README.md
CHANGED
|
@@ -1,130 +1,60 @@
|
|
|
1
1
|
# @outfitter/kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Foundation facade for Outfitter.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`@outfitter/kit` provides a single foundation entrypoint over:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `@outfitter/contracts`
|
|
8
|
+
- `@outfitter/types`
|
|
8
9
|
|
|
9
|
-
|
|
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
|
-
##
|
|
18
|
+
## Root Facade
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
The root entrypoint re-exports the contracts surface and exposes types under a namespace.
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
3. **Checking version requirements** programmatically
|
|
22
|
+
```typescript
|
|
23
|
+
import { Result, ValidationError, Types } from "@outfitter/kit";
|
|
22
24
|
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
### STACK_VERSION
|
|
53
|
-
|
|
54
|
-
The current stack version (matches package.json).
|
|
32
|
+
### Contracts
|
|
55
33
|
|
|
56
34
|
```typescript
|
|
57
|
-
import {
|
|
58
|
-
|
|
59
|
-
console.log(`Using Outfitter Stack ${STACK_VERSION}`);
|
|
35
|
+
import { Result, createLoggerFactory } from "@outfitter/kit/foundation/contracts";
|
|
60
36
|
```
|
|
61
37
|
|
|
62
|
-
###
|
|
63
|
-
|
|
64
|
-
Minimum compatible versions for each package.
|
|
38
|
+
### Types
|
|
65
39
|
|
|
66
40
|
```typescript
|
|
67
|
-
import {
|
|
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
|
-
###
|
|
74
|
-
|
|
75
|
-
Type for valid package names in the stack.
|
|
44
|
+
### Aggregate Foundation
|
|
76
45
|
|
|
77
46
|
```typescript
|
|
78
|
-
import {
|
|
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
|
-
##
|
|
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
|
-
|
|
106
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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 @@
|
|
|
1
|
+
export * from "@outfitter/types";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,33 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* @outfitter/
|
|
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
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
18
|
-
MINIMUM_VERSIONS
|
|
6
|
+
Types
|
|
19
7
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outfitter/kit",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "0.2.
|
|
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
|
-
"
|
|
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
|
-
"./
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
"
|
|
64
|
-
"
|
|
25
|
+
"./foundation/types": {
|
|
26
|
+
"import": {
|
|
27
|
+
"types": "./dist/foundation/types.d.ts",
|
|
28
|
+
"default": "./dist/foundation/types.js"
|
|
29
|
+
}
|
|
65
30
|
},
|
|
66
|
-
"
|
|
67
|
-
"
|
|
31
|
+
"./foundation": {
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/foundation/index.d.ts",
|
|
34
|
+
"default": "./dist/foundation/index.js"
|
|
35
|
+
}
|
|
68
36
|
},
|
|
69
|
-
"
|
|
70
|
-
|
|
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
|
-
"
|
|
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,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,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`.
|
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
|