auden 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/auden-paths.d.ts +8 -0
- package/dist/auden-paths.d.ts.map +1 -0
- package/dist/auden-paths.js +10 -0
- package/dist/auden-paths.js.map +1 -0
- package/dist/bin.d.ts +11 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +13 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk.d.ts +3 -0
- package/dist/chunk.d.ts.map +1 -0
- package/dist/chunk.js +13 -0
- package/dist/chunk.js.map +1 -0
- package/dist/commands/doctor.d.ts +13 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +125 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/eval/index.d.ts +2 -0
- package/dist/commands/eval/index.d.ts.map +1 -0
- package/dist/commands/eval/index.js +2 -0
- package/dist/commands/eval/index.js.map +1 -0
- package/dist/commands/eval/run.d.ts +38 -0
- package/dist/commands/eval/run.d.ts.map +1 -0
- package/dist/commands/eval/run.js +179 -0
- package/dist/commands/eval/run.js.map +1 -0
- package/dist/commands/guides/active.d.ts +2 -0
- package/dist/commands/guides/active.d.ts.map +1 -0
- package/dist/commands/guides/active.js +38 -0
- package/dist/commands/guides/active.js.map +1 -0
- package/dist/commands/guides/index.d.ts +2 -0
- package/dist/commands/guides/index.d.ts.map +1 -0
- package/dist/commands/guides/index.js +13 -0
- package/dist/commands/guides/index.js.map +1 -0
- package/dist/commands/guides/project.d.ts +13 -0
- package/dist/commands/guides/project.d.ts.map +1 -0
- package/dist/commands/guides/project.js +71 -0
- package/dist/commands/guides/project.js.map +1 -0
- package/dist/commands/guides/search.d.ts +8 -0
- package/dist/commands/guides/search.d.ts.map +1 -0
- package/dist/commands/guides/search.js +46 -0
- package/dist/commands/guides/search.js.map +1 -0
- package/dist/commands/init.d.ts +43 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +436 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp.d.ts +23 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +55 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/pull.d.ts +38 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +127 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/rules/export.d.ts +140 -0
- package/dist/commands/rules/export.d.ts.map +1 -0
- package/dist/commands/rules/export.js +635 -0
- package/dist/commands/rules/export.js.map +1 -0
- package/dist/commands/rules/import.d.ts +33 -0
- package/dist/commands/rules/import.d.ts.map +1 -0
- package/dist/commands/rules/import.js +122 -0
- package/dist/commands/rules/import.js.map +1 -0
- package/dist/commands/rules/index.d.ts +2 -0
- package/dist/commands/rules/index.d.ts.map +1 -0
- package/dist/commands/rules/index.js +13 -0
- package/dist/commands/rules/index.js.map +1 -0
- package/dist/commands/rules/watch.d.ts +43 -0
- package/dist/commands/rules/watch.d.ts.map +1 -0
- package/dist/commands/rules/watch.js +125 -0
- package/dist/commands/rules/watch.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +61 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/suggest.d.ts +8 -0
- package/dist/commands/suggest.d.ts.map +1 -0
- package/dist/commands/suggest.js +43 -0
- package/dist/commands/suggest.js.map +1 -0
- package/dist/commands/sync.d.ts +23 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +193 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/verdict/index.d.ts +2 -0
- package/dist/commands/verdict/index.d.ts.map +1 -0
- package/dist/commands/verdict/index.js +11 -0
- package/dist/commands/verdict/index.js.map +1 -0
- package/dist/commands/verdict/record.d.ts +18 -0
- package/dist/commands/verdict/record.d.ts.map +1 -0
- package/dist/commands/verdict/record.js +60 -0
- package/dist/commands/verdict/record.js.map +1 -0
- package/dist/config.d.ts +96 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +246 -0
- package/dist/config.js.map +1 -0
- package/dist/context/pull.d.ts +40 -0
- package/dist/context/pull.d.ts.map +1 -0
- package/dist/context/pull.js +46 -0
- package/dist/context/pull.js.map +1 -0
- package/dist/dashboard-health.d.ts +20 -0
- package/dist/dashboard-health.d.ts.map +1 -0
- package/dist/dashboard-health.js +24 -0
- package/dist/dashboard-health.js.map +1 -0
- package/dist/eval-provider.d.ts +30 -0
- package/dist/eval-provider.d.ts.map +1 -0
- package/dist/eval-provider.js +359 -0
- package/dist/eval-provider.js.map +1 -0
- package/dist/eval-summary.d.ts +24 -0
- package/dist/eval-summary.d.ts.map +1 -0
- package/dist/eval-summary.js +30 -0
- package/dist/eval-summary.js.map +1 -0
- package/dist/feedback/extract.d.ts +6 -0
- package/dist/feedback/extract.d.ts.map +1 -0
- package/dist/feedback/extract.js +580 -0
- package/dist/feedback/extract.js.map +1 -0
- package/dist/http-retry.d.ts +23 -0
- package/dist/http-retry.d.ts.map +1 -0
- package/dist/http-retry.js +54 -0
- package/dist/http-retry.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +70 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +121 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/scope.d.ts +30 -0
- package/dist/mcp/scope.d.ts.map +1 -0
- package/dist/mcp/scope.js +64 -0
- package/dist/mcp/scope.js.map +1 -0
- package/dist/mcp/server.d.ts +57 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +427 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/write-items.d.ts +34 -0
- package/dist/mcp/write-items.d.ts.map +1 -0
- package/dist/mcp/write-items.js +59 -0
- package/dist/mcp/write-items.js.map +1 -0
- package/dist/rules/deletions-client.d.ts +16 -0
- package/dist/rules/deletions-client.d.ts.map +1 -0
- package/dist/rules/deletions-client.js +40 -0
- package/dist/rules/deletions-client.js.map +1 -0
- package/dist/rules/diff.d.ts +19 -0
- package/dist/rules/diff.d.ts.map +1 -0
- package/dist/rules/diff.js +36 -0
- package/dist/rules/diff.js.map +1 -0
- package/dist/rules/discover.d.ts +81 -0
- package/dist/rules/discover.d.ts.map +1 -0
- package/dist/rules/discover.js +307 -0
- package/dist/rules/discover.js.map +1 -0
- package/dist/rules/file-origin.d.ts +16 -0
- package/dist/rules/file-origin.d.ts.map +1 -0
- package/dist/rules/file-origin.js +31 -0
- package/dist/rules/file-origin.js.map +1 -0
- package/dist/rules/global-flag.d.ts +12 -0
- package/dist/rules/global-flag.d.ts.map +1 -0
- package/dist/rules/global-flag.js +15 -0
- package/dist/rules/global-flag.js.map +1 -0
- package/dist/rules/import-client.d.ts +37 -0
- package/dist/rules/import-client.d.ts.map +1 -0
- package/dist/rules/import-client.js +98 -0
- package/dist/rules/import-client.js.map +1 -0
- package/dist/rules/init-pull.d.ts +34 -0
- package/dist/rules/init-pull.d.ts.map +1 -0
- package/dist/rules/init-pull.js +43 -0
- package/dist/rules/init-pull.js.map +1 -0
- package/dist/rules/member-files-client.d.ts +17 -0
- package/dist/rules/member-files-client.d.ts.map +1 -0
- package/dist/rules/member-files-client.js +29 -0
- package/dist/rules/member-files-client.js.map +1 -0
- package/dist/rules/path-contains.d.ts +9 -0
- package/dist/rules/path-contains.d.ts.map +1 -0
- package/dist/rules/path-contains.js +17 -0
- package/dist/rules/path-contains.js.map +1 -0
- package/dist/rules/payload.d.ts +13 -0
- package/dist/rules/payload.d.ts.map +1 -0
- package/dist/rules/payload.js +35 -0
- package/dist/rules/payload.js.map +1 -0
- package/dist/rules/pull-bundle.d.ts +13 -0
- package/dist/rules/pull-bundle.d.ts.map +1 -0
- package/dist/rules/pull-bundle.js +32 -0
- package/dist/rules/pull-bundle.js.map +1 -0
- package/dist/rules/watch.d.ts +121 -0
- package/dist/rules/watch.d.ts.map +1 -0
- package/dist/rules/watch.js +457 -0
- package/dist/rules/watch.js.map +1 -0
- package/dist/skill-template.d.ts +19 -0
- package/dist/skill-template.d.ts.map +1 -0
- package/dist/skill-template.js +174 -0
- package/dist/skill-template.js.map +1 -0
- package/dist/sync-batches.d.ts +37 -0
- package/dist/sync-batches.d.ts.map +1 -0
- package/dist/sync-batches.js +67 -0
- package/dist/sync-batches.js.map +1 -0
- package/dist/sync-client.d.ts +22 -0
- package/dist/sync-client.d.ts.map +1 -0
- package/dist/sync-client.js +38 -0
- package/dist/sync-client.js.map +1 -0
- package/dist/sync-response.d.ts +23 -0
- package/dist/sync-response.d.ts.map +1 -0
- package/dist/sync-response.js +22 -0
- package/dist/sync-response.js.map +1 -0
- package/dist/token-verify.d.ts +14 -0
- package/dist/token-verify.d.ts.map +1 -0
- package/dist/token-verify.js +30 -0
- package/dist/token-verify.js.map +1 -0
- package/dist/usage/extract.d.ts +31 -0
- package/dist/usage/extract.d.ts.map +1 -0
- package/dist/usage/extract.js +200 -0
- package/dist/usage/extract.js.map +1 -0
- package/dist/usage/providers.d.ts +8 -0
- package/dist/usage/providers.d.ts.map +1 -0
- package/dist/usage/providers.js +23 -0
- package/dist/usage/providers.js.map +1 -0
- package/dist/verdict-queue.d.ts +50 -0
- package/dist/verdict-queue.d.ts.map +1 -0
- package/dist/verdict-queue.js +131 -0
- package/dist/verdict-queue.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Auden MCP server. Exposes the context layer (`/api/v1/context/*`) to any
|
|
3
|
+
* agent as a small set of tools over stdio (`list_bundles`, `pull_context`,
|
|
4
|
+
* `push_context`, `list_inbox`, `pull_inbox`, `archive_inbox`), so an agent
|
|
5
|
+
* configures it once (in `.mcp.json` / Claude Code / Cursor) instead of wiring
|
|
6
|
+
* each source. The server name (`auden`) namespaces them, so tool names stay
|
|
7
|
+
* bare underscores — dots are outside the Anthropic/Claude Code tool-name charset.
|
|
8
|
+
*
|
|
9
|
+
* Every tool maps 1:1 to a REST route on the dashboard via `ContextClient`. The
|
|
10
|
+
* server acts as the user (it reuses the CLI token) and constrains exposure
|
|
11
|
+
* locally: `readOnly` refuses mutating tools, and `bundles` (an allowlist)
|
|
12
|
+
* limits which bundles are reachable — the "wire once, still scoped" answer.
|
|
13
|
+
*
|
|
14
|
+
* Argument validation is Valibot (never Zod) per repo convention; the low-level
|
|
15
|
+
* `Server` is used precisely so tool input schemas are plain JSON Schema and
|
|
16
|
+
* incoming arguments are validated by our own Valibot schemas rather than the
|
|
17
|
+
* SDK's Zod shapes.
|
|
18
|
+
*/
|
|
19
|
+
import { ContextItemTypeSchema, MAX_TRANSFORM_SOURCE_IDS, PushContentTypeSchema, SourceItemIdsSchema, } from '@auden.to/protocol';
|
|
20
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
21
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
22
|
+
import * as v from 'valibot';
|
|
23
|
+
import { isBundleAllowed, resolveSince } from './scope.js';
|
|
24
|
+
import { writeItemsToDir } from './write-items.js';
|
|
25
|
+
const SERVER_NAME = 'auden';
|
|
26
|
+
const SERVER_VERSION = '1';
|
|
27
|
+
function ok(data) {
|
|
28
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
29
|
+
}
|
|
30
|
+
function fail(message) {
|
|
31
|
+
return { content: [{ type: 'text', text: message }], isError: true };
|
|
32
|
+
}
|
|
33
|
+
function valiMessage(err) {
|
|
34
|
+
return err instanceof v.ValiError
|
|
35
|
+
? err.issues.map((issue) => issue.message).join('; ')
|
|
36
|
+
: 'invalid arguments';
|
|
37
|
+
}
|
|
38
|
+
// Arguments arrive as `request.params.arguments`, which the MCP spec allows to
|
|
39
|
+
// be omitted; treat a missing value as an empty object before validating.
|
|
40
|
+
function parseArgs(schema, args) {
|
|
41
|
+
return v.parse(schema, args ?? {});
|
|
42
|
+
}
|
|
43
|
+
const BundleArg = v.pipe(v.string(), v.minLength(1));
|
|
44
|
+
// Constrain `types` to the real item-type enum so a typo (e.g. "note") is
|
|
45
|
+
// rejected client-side instead of silently widening the result set — the REST
|
|
46
|
+
// endpoint drops unknown types and, when all are dropped, applies no filter.
|
|
47
|
+
const TypeArrayArg = v.array(ContextItemTypeSchema);
|
|
48
|
+
// Mirror the server's 200-char cap so oversized names fail with a clear
|
|
49
|
+
// client-side message rather than an opaque 400.
|
|
50
|
+
const NameArg = v.pipe(v.string(), v.minLength(1), v.maxLength(200));
|
|
51
|
+
// Mirror the REST endpoint's MAX_LIMIT so an over-large `limit` fails with a
|
|
52
|
+
// clear client-side message instead of being silently clamped server-side.
|
|
53
|
+
const MAX_LIMIT = 500;
|
|
54
|
+
const PullContextArgs = v.object({
|
|
55
|
+
bundle: BundleArg,
|
|
56
|
+
query: v.optional(v.string()),
|
|
57
|
+
types: v.optional(TypeArrayArg),
|
|
58
|
+
limit: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(MAX_LIMIT))),
|
|
59
|
+
writeToDir: v.optional(v.string()),
|
|
60
|
+
});
|
|
61
|
+
const PushContextArgs = v.object({
|
|
62
|
+
bundle: BundleArg,
|
|
63
|
+
name: NameArg,
|
|
64
|
+
contentType: v.optional(PushContentTypeSchema),
|
|
65
|
+
content: v.pipe(v.string(), v.minLength(1)),
|
|
66
|
+
// A present `itemId` routes to the update path — reject an empty string so a
|
|
67
|
+
// caller can't accidentally issue a PUT with a blank id.
|
|
68
|
+
itemId: v.optional(v.pipe(v.string(), v.minLength(1))),
|
|
69
|
+
origin: v.optional(v.string()),
|
|
70
|
+
// Optimistic-concurrency precondition on the update path: the `version` the
|
|
71
|
+
// agent last read. On mismatch the server returns 409 rather than clobbering a
|
|
72
|
+
// concurrent edit. Update only — ignored on create.
|
|
73
|
+
expectedVersion: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1))),
|
|
74
|
+
// The protocol's own schema, so an invalid citation list fails with a clear
|
|
75
|
+
// client-side message and can't drift from the server contract.
|
|
76
|
+
sourceItemIds: v.optional(SourceItemIdsSchema),
|
|
77
|
+
});
|
|
78
|
+
const ListInboxArgs = v.object({
|
|
79
|
+
since: v.optional(v.string()),
|
|
80
|
+
types: v.optional(TypeArrayArg),
|
|
81
|
+
});
|
|
82
|
+
const PullInboxArgs = v.object({
|
|
83
|
+
since: v.optional(v.string()),
|
|
84
|
+
types: v.optional(TypeArrayArg),
|
|
85
|
+
writeToDir: v.optional(v.string()),
|
|
86
|
+
});
|
|
87
|
+
const ArchiveInboxArgs = v.object({
|
|
88
|
+
ids: v.pipe(v.array(v.pipe(v.string(), v.minLength(1))), v.minLength(1)),
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Build the tool definitions (name, JSON-Schema input, handler). Exposed
|
|
92
|
+
* separately from `createMcpServer` so handlers unit-test directly against a
|
|
93
|
+
* mocked client without a transport.
|
|
94
|
+
*/
|
|
95
|
+
export function buildTools(deps) {
|
|
96
|
+
const now = deps.now ?? (() => new Date());
|
|
97
|
+
const denyBundle = (slug) => isBundleAllowed(slug, deps.bundles)
|
|
98
|
+
? null
|
|
99
|
+
: fail(`Bundle "${slug}" is not in this server's allowlist.`);
|
|
100
|
+
// read-only guards writes to the *context layer* (push/update/archive on the
|
|
101
|
+
// server). It does not gate a local `writeToDir` on a pull — that materializes
|
|
102
|
+
// already-readable context to a directory the caller named, not a server write.
|
|
103
|
+
const denyWrite = () => deps.readOnly
|
|
104
|
+
? fail('This Auden MCP server is read-only; context-layer writes are refused.')
|
|
105
|
+
: null;
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
name: 'list_bundles',
|
|
109
|
+
description: 'List the context bundles available to you (id, slug, name, kind). Use this to discover where to pull from or push to.',
|
|
110
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
111
|
+
async handler() {
|
|
112
|
+
try {
|
|
113
|
+
const { bundles } = await deps.client.listBundles();
|
|
114
|
+
const visible = bundles.filter((b) => isBundleAllowed(b.slug, deps.bundles));
|
|
115
|
+
return ok({ bundles: visible });
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'pull_context',
|
|
124
|
+
description: 'Pull scoped items from a bundle. Filter with `types` (guide|document|reference|asset), a `query` substring, and `limit` (default 100, max 500 — pass a higher `limit` to retrieve more). Pass `writeToDir` to also write each item to disk in the current environment.',
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
bundle: { type: 'string', description: 'Bundle slug to pull from.' },
|
|
129
|
+
query: { type: 'string', description: 'Substring filter over name + content.' },
|
|
130
|
+
types: {
|
|
131
|
+
type: 'array',
|
|
132
|
+
items: { type: 'string' },
|
|
133
|
+
description: 'Restrict to these item types.',
|
|
134
|
+
},
|
|
135
|
+
limit: {
|
|
136
|
+
type: 'integer',
|
|
137
|
+
minimum: 1,
|
|
138
|
+
maximum: MAX_LIMIT,
|
|
139
|
+
description: 'Max items to return (default 100, max 500).',
|
|
140
|
+
},
|
|
141
|
+
writeToDir: {
|
|
142
|
+
type: 'string',
|
|
143
|
+
description: 'If set, also write each item to this directory as Markdown.',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
required: ['bundle'],
|
|
147
|
+
additionalProperties: false,
|
|
148
|
+
},
|
|
149
|
+
async handler(rawArgs) {
|
|
150
|
+
let args;
|
|
151
|
+
try {
|
|
152
|
+
args = parseArgs(PullContextArgs, rawArgs);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
return fail(valiMessage(err));
|
|
156
|
+
}
|
|
157
|
+
const denied = denyBundle(args.bundle);
|
|
158
|
+
if (denied)
|
|
159
|
+
return denied;
|
|
160
|
+
try {
|
|
161
|
+
const { items } = await deps.client.pullContext({
|
|
162
|
+
bundle: args.bundle,
|
|
163
|
+
query: args.query,
|
|
164
|
+
types: args.types,
|
|
165
|
+
limit: args.limit,
|
|
166
|
+
});
|
|
167
|
+
if (args.writeToDir) {
|
|
168
|
+
const written = await writeItemsToDir(items, args.writeToDir, deps.writeDeps);
|
|
169
|
+
return ok({ items, written });
|
|
170
|
+
}
|
|
171
|
+
return ok({ items });
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'push_context',
|
|
180
|
+
description: 'Push a canonical item into a bundle. Omit `itemId` to create; pass `itemId` to update in place (the edit propagates to every bundle the item belongs to). On update only `name` and `content` change — `contentType` and `origin` are ignored. `contentType` defaults to "document". Optionally pass `expectedVersion` (the `version` you last read for the item) on an update: the server rejects the write with 409 if the item has changed since, so a stale edit surfaces as a conflict instead of silently clobbering a concurrent write. When creating a document produced from other context items (inbox captures, bundle items), cite their ids as `sourceItemIds` — if one of the user\'s guides covers the transform, Auden grades it against that guide\'s criteria and returns the verdict.',
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: 'object',
|
|
183
|
+
properties: {
|
|
184
|
+
bundle: { type: 'string', description: 'Bundle slug to push into.' },
|
|
185
|
+
name: { type: 'string', description: 'Human-readable item name.' },
|
|
186
|
+
contentType: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
enum: ['document', 'reference', 'asset'],
|
|
189
|
+
description: 'Item content type (default "document").',
|
|
190
|
+
},
|
|
191
|
+
content: { type: 'string', description: 'The item body (Markdown/text).' },
|
|
192
|
+
itemId: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
description: 'Existing item id to update in place; omit to create.',
|
|
195
|
+
},
|
|
196
|
+
origin: { type: 'string', description: 'Optional provenance string.' },
|
|
197
|
+
expectedVersion: {
|
|
198
|
+
type: 'integer',
|
|
199
|
+
minimum: 1,
|
|
200
|
+
description: 'Optimistic-concurrency precondition (update only): the version you last read. The server returns 409 if the item changed since, instead of clobbering a concurrent edit.',
|
|
201
|
+
},
|
|
202
|
+
sourceItemIds: {
|
|
203
|
+
type: 'array',
|
|
204
|
+
items: { type: 'string' },
|
|
205
|
+
minItems: 1,
|
|
206
|
+
maxItems: MAX_TRANSFORM_SOURCE_IDS,
|
|
207
|
+
description: "Ids of the context items this document was produced from (create only). Graded against the user's own guidance when a guide covers the transform; ungraded pushes are fine — the citation is optional provenance.",
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
required: ['bundle', 'name', 'content'],
|
|
211
|
+
additionalProperties: false,
|
|
212
|
+
},
|
|
213
|
+
async handler(rawArgs) {
|
|
214
|
+
const readOnly = denyWrite();
|
|
215
|
+
if (readOnly)
|
|
216
|
+
return readOnly;
|
|
217
|
+
let args;
|
|
218
|
+
try {
|
|
219
|
+
args = parseArgs(PushContextArgs, rawArgs);
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
return fail(valiMessage(err));
|
|
223
|
+
}
|
|
224
|
+
const denied = denyBundle(args.bundle);
|
|
225
|
+
if (denied)
|
|
226
|
+
return denied;
|
|
227
|
+
// Grading only applies to a create — the server rejects sourceItemIds
|
|
228
|
+
// on the update path, so fail fast with a clearer message here.
|
|
229
|
+
if (args.itemId && args.sourceItemIds) {
|
|
230
|
+
return fail('sourceItemIds applies to newly created items — omit itemId, or push without sourceItemIds.');
|
|
231
|
+
}
|
|
232
|
+
// Citations are NOT gated by the bundle allowlist: they return no item
|
|
233
|
+
// content to the agent (only a verdict), the server validates ownership,
|
|
234
|
+
// and the client cannot know which bundle an arbitrary id belongs to.
|
|
235
|
+
// The allowlist keeps governing what this server can pull and push.
|
|
236
|
+
try {
|
|
237
|
+
const result = await deps.client.pushContext({
|
|
238
|
+
bundle: args.bundle,
|
|
239
|
+
name: args.name,
|
|
240
|
+
contentType: args.contentType ?? 'document',
|
|
241
|
+
content: args.content,
|
|
242
|
+
itemId: args.itemId,
|
|
243
|
+
origin: args.origin,
|
|
244
|
+
expectedVersion: args.expectedVersion,
|
|
245
|
+
sourceItemIds: args.sourceItemIds,
|
|
246
|
+
});
|
|
247
|
+
return ok(result);
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: 'list_inbox',
|
|
256
|
+
description: 'List unarchived inbox items. `since` accepts an ISO timestamp or a relative window like "24h", "7d", or "30m".',
|
|
257
|
+
inputSchema: {
|
|
258
|
+
type: 'object',
|
|
259
|
+
properties: {
|
|
260
|
+
since: {
|
|
261
|
+
type: 'string',
|
|
262
|
+
description: 'ISO timestamp or relative window ("24h", "7d", "30m").',
|
|
263
|
+
},
|
|
264
|
+
types: {
|
|
265
|
+
type: 'array',
|
|
266
|
+
items: { type: 'string' },
|
|
267
|
+
description: 'Restrict to these item types.',
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
additionalProperties: false,
|
|
271
|
+
},
|
|
272
|
+
async handler(rawArgs) {
|
|
273
|
+
return listInbox(deps, now, rawArgs);
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'pull_inbox',
|
|
278
|
+
description: 'Pull recent inbox items for a round-trip (e.g. "notes from the last 24h"). Like list_inbox (supports `since` and `types`) but also supports `writeToDir` to materialize them to disk.',
|
|
279
|
+
inputSchema: {
|
|
280
|
+
type: 'object',
|
|
281
|
+
properties: {
|
|
282
|
+
since: {
|
|
283
|
+
type: 'string',
|
|
284
|
+
description: 'ISO timestamp or relative window ("24h", "7d", "30m").',
|
|
285
|
+
},
|
|
286
|
+
types: {
|
|
287
|
+
type: 'array',
|
|
288
|
+
items: { type: 'string' },
|
|
289
|
+
description: 'Restrict to these item types.',
|
|
290
|
+
},
|
|
291
|
+
writeToDir: {
|
|
292
|
+
type: 'string',
|
|
293
|
+
description: 'If set, also write each item to this directory as Markdown.',
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
additionalProperties: false,
|
|
297
|
+
},
|
|
298
|
+
async handler(rawArgs) {
|
|
299
|
+
return pullInbox(deps, now, rawArgs);
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'archive_inbox',
|
|
304
|
+
description: 'Archive inbox items by id once consumed, so they drop out of future inbox pulls. Reversible on the dashboard.',
|
|
305
|
+
inputSchema: {
|
|
306
|
+
type: 'object',
|
|
307
|
+
properties: {
|
|
308
|
+
ids: {
|
|
309
|
+
type: 'array',
|
|
310
|
+
items: { type: 'string' },
|
|
311
|
+
minItems: 1,
|
|
312
|
+
description: 'Inbox item ids to archive.',
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
required: ['ids'],
|
|
316
|
+
additionalProperties: false,
|
|
317
|
+
},
|
|
318
|
+
async handler(rawArgs) {
|
|
319
|
+
const readOnly = denyWrite();
|
|
320
|
+
if (readOnly)
|
|
321
|
+
return readOnly;
|
|
322
|
+
// Archive touches the reserved `inbox` bundle — honor the allowlist.
|
|
323
|
+
const denied = denyBundle('inbox');
|
|
324
|
+
if (denied)
|
|
325
|
+
return denied;
|
|
326
|
+
let args;
|
|
327
|
+
try {
|
|
328
|
+
args = parseArgs(ArchiveInboxArgs, rawArgs);
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
return fail(valiMessage(err));
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
return ok(await deps.client.archiveInbox(args.ids));
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
async function listInbox(deps, now, rawArgs) {
|
|
344
|
+
const denied = denyInbox(deps);
|
|
345
|
+
if (denied)
|
|
346
|
+
return denied;
|
|
347
|
+
let args;
|
|
348
|
+
try {
|
|
349
|
+
args = parseArgs(ListInboxArgs, rawArgs);
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
return fail(valiMessage(err));
|
|
353
|
+
}
|
|
354
|
+
let since;
|
|
355
|
+
try {
|
|
356
|
+
since = args.since ? resolveSince(args.since, now()) : undefined;
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
return ok(await deps.client.listInbox({ since, types: args.types }));
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async function pullInbox(deps, now, rawArgs) {
|
|
369
|
+
const denied = denyInbox(deps);
|
|
370
|
+
if (denied)
|
|
371
|
+
return denied;
|
|
372
|
+
let args;
|
|
373
|
+
try {
|
|
374
|
+
args = parseArgs(PullInboxArgs, rawArgs);
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
return fail(valiMessage(err));
|
|
378
|
+
}
|
|
379
|
+
let since;
|
|
380
|
+
try {
|
|
381
|
+
since = args.since ? resolveSince(args.since, now()) : undefined;
|
|
382
|
+
}
|
|
383
|
+
catch (err) {
|
|
384
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
const { items } = await deps.client.listInbox({ since, types: args.types });
|
|
388
|
+
if (args.writeToDir) {
|
|
389
|
+
const written = await writeItemsToDir(items, args.writeToDir, deps.writeDeps);
|
|
390
|
+
return ok({ items, written });
|
|
391
|
+
}
|
|
392
|
+
return ok({ items });
|
|
393
|
+
}
|
|
394
|
+
catch (err) {
|
|
395
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
function denyInbox(deps) {
|
|
399
|
+
return isBundleAllowed('inbox', deps.bundles)
|
|
400
|
+
? null
|
|
401
|
+
: fail("The inbox bundle is not in this server's allowlist.");
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Wire the tools into an MCP `Server` with stdio-ready request handlers. The
|
|
405
|
+
* caller connects a transport (`await server.connect(new StdioServerTransport())`).
|
|
406
|
+
*/
|
|
407
|
+
export function createMcpServer(deps) {
|
|
408
|
+
const tools = buildTools(deps);
|
|
409
|
+
const byName = new Map(tools.map((t) => [t.name, t]));
|
|
410
|
+
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, { capabilities: { tools: {} } });
|
|
411
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
412
|
+
tools: tools.map((t) => ({
|
|
413
|
+
name: t.name,
|
|
414
|
+
description: t.description,
|
|
415
|
+
inputSchema: t.inputSchema,
|
|
416
|
+
})),
|
|
417
|
+
}));
|
|
418
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
419
|
+
const tool = byName.get(request.params.name);
|
|
420
|
+
if (!tool) {
|
|
421
|
+
return fail(`Unknown tool: ${request.params.name}`);
|
|
422
|
+
}
|
|
423
|
+
return tool.handler(request.params.arguments);
|
|
424
|
+
});
|
|
425
|
+
return server;
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialize pulled context items to a local directory, mirroring the
|
|
3
|
+
* write-to-disk pattern in `rules/pull-bundle.ts`. Used by the `pull_context` /
|
|
4
|
+
* `pull_inbox` MCP tools when the agent passes a `writeToDir` -- it lets a coding
|
|
5
|
+
* agent drop scoped context straight into its working tree.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
8
|
+
type WritableItem = {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
content: string | null;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Turn an item's display name into a safe single-segment `.md` filename.
|
|
15
|
+
* Strips path separators and leading dots so a crafted item name cannot escape
|
|
16
|
+
* the target directory, replaces characters that are invalid in Windows
|
|
17
|
+
* filenames (`< > : " | ? *`) so writes don't fail on the cross-platform
|
|
18
|
+
* machines coding agents run on, and falls back to the item id when the name
|
|
19
|
+
* reduces to nothing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function safeItemFileName(name: string, id: string): string;
|
|
22
|
+
export type WriteItemsDeps = {
|
|
23
|
+
mkdirFn?: typeof mkdir;
|
|
24
|
+
writeFileFn?: typeof writeFile;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Write each item's `content` to `dir` as `<safe-name>.md`, creating the
|
|
28
|
+
* directory if needed. Items with `null` content (e.g. assets, whose bytes live
|
|
29
|
+
* in object storage) are skipped. Filename collisions are disambiguated by
|
|
30
|
+
* appending the item id. Returns the absolute-ish paths written, in order.
|
|
31
|
+
*/
|
|
32
|
+
export declare function writeItemsToDir(items: readonly WritableItem[], dir: string, deps?: WriteItemsDeps): Promise<string[]>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=write-items.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-items.d.ts","sourceRoot":"","sources":["../../src/mcp/write-items.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAGnD,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CASjE;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;IACtB,WAAW,CAAC,EAAE,OAAO,SAAS,CAAA;CAC/B,CAAA;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC,CA8BnB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialize pulled context items to a local directory, mirroring the
|
|
3
|
+
* write-to-disk pattern in `rules/pull-bundle.ts`. Used by the `pull_context` /
|
|
4
|
+
* `pull_inbox` MCP tools when the agent passes a `writeToDir` -- it lets a coding
|
|
5
|
+
* agent drop scoped context straight into its working tree.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
/**
|
|
10
|
+
* Turn an item's display name into a safe single-segment `.md` filename.
|
|
11
|
+
* Strips path separators and leading dots so a crafted item name cannot escape
|
|
12
|
+
* the target directory, replaces characters that are invalid in Windows
|
|
13
|
+
* filenames (`< > : " | ? *`) so writes don't fail on the cross-platform
|
|
14
|
+
* machines coding agents run on, and falls back to the item id when the name
|
|
15
|
+
* reduces to nothing.
|
|
16
|
+
*/
|
|
17
|
+
export function safeItemFileName(name, id) {
|
|
18
|
+
const base = name
|
|
19
|
+
.trim()
|
|
20
|
+
.replace(/[/\\]/g, '-') // no path separators: single segment, no traversal
|
|
21
|
+
.replace(/[<>:"|?*]/g, '-') // chars invalid in Windows filenames
|
|
22
|
+
.replace(/^[-.]+/, '') // no leading dots/dashes (., .., dotfiles-as-traversal)
|
|
23
|
+
.trim();
|
|
24
|
+
const cleaned = base || id;
|
|
25
|
+
return cleaned.toLowerCase().endsWith('.md') ? cleaned : `${cleaned}.md`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Write each item's `content` to `dir` as `<safe-name>.md`, creating the
|
|
29
|
+
* directory if needed. Items with `null` content (e.g. assets, whose bytes live
|
|
30
|
+
* in object storage) are skipped. Filename collisions are disambiguated by
|
|
31
|
+
* appending the item id. Returns the absolute-ish paths written, in order.
|
|
32
|
+
*/
|
|
33
|
+
export async function writeItemsToDir(items, dir, deps = {}) {
|
|
34
|
+
const mkdirFn = deps.mkdirFn ?? mkdir;
|
|
35
|
+
const writeFileFn = deps.writeFileFn ?? writeFile;
|
|
36
|
+
await mkdirFn(dir, { recursive: true });
|
|
37
|
+
// Track used names case-insensitively: coding agents commonly run on
|
|
38
|
+
// case-insensitive filesystems (macOS, Windows), where "README.md" and
|
|
39
|
+
// "readme.md" are the same file -- a case-sensitive Set would miss the
|
|
40
|
+
// collision and the second write would silently clobber the first.
|
|
41
|
+
const used = new Set();
|
|
42
|
+
const written = [];
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
if (item.content === null)
|
|
45
|
+
continue;
|
|
46
|
+
let fileName = safeItemFileName(item.name, item.id);
|
|
47
|
+
if (used.has(fileName.toLowerCase())) {
|
|
48
|
+
// Disambiguate a name collision with the stable item id.
|
|
49
|
+
fileName = safeItemFileName(`${item.name}-${item.id}`, item.id);
|
|
50
|
+
}
|
|
51
|
+
used.add(fileName.toLowerCase());
|
|
52
|
+
const path = join(dir, fileName);
|
|
53
|
+
const body = item.content.endsWith('\n') ? item.content : `${item.content}\n`;
|
|
54
|
+
await writeFileFn(path, body);
|
|
55
|
+
written.push(path);
|
|
56
|
+
}
|
|
57
|
+
return written;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=write-items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-items.js","sourceRoot":"","sources":["../../src/mcp/write-items.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQhC;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,EAAU;IACvD,MAAM,IAAI,GAAG,IAAI;SACd,IAAI,EAAE;SACN,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,mDAAmD;SAC1E,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,qCAAqC;SAChE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,wDAAwD;SAC9E,IAAI,EAAE,CAAA;IACT,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAA;IAC1B,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,CAAA;AAC1E,CAAC;AAOD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,KAA8B,EAC9B,GAAW,EACX,OAAuB,EAAE;IAEzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAA;IACrC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,SAAS,CAAA;IAEjD,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvC,qEAAqE;IACrE,uEAAuE;IACvE,uEAAuE;IACvE,mEAAmE;IACnE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,OAAO,GAAa,EAAE,CAAA;IAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI;YAAE,SAAQ;QAEnC,IAAI,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;QACnD,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACrC,yDAAyD;YACzD,QAAQ,GAAG,gBAAgB,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;QACjE,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;QAEhC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,CAAA;QAC7E,MAAM,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RawGuideFileDeletion, type RuleDeletionsResponse } from '@auden.to/protocol';
|
|
2
|
+
export type DeleteRulesOptions = {
|
|
3
|
+
dashboardUrl: string;
|
|
4
|
+
token: string;
|
|
5
|
+
deletions: RawGuideFileDeletion[];
|
|
6
|
+
/** Override fetch for tests. Defaults to globalThis.fetch. */
|
|
7
|
+
fetchImpl?: typeof fetch;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* POST deletions to the dashboard, chunked to stay under the server's
|
|
11
|
+
* `MAX_RULE_DELETIONS_BATCH` per-request cap, and sum the parsed results.
|
|
12
|
+
* Empty input is rejected so the CLI never sends a useless request. Throws on
|
|
13
|
+
* transport, non-2xx, or malformed response bodies.
|
|
14
|
+
*/
|
|
15
|
+
export declare function deleteRules(options: DeleteRulesOptions): Promise<RuleDeletionsResponse>;
|
|
16
|
+
//# sourceMappingURL=deletions-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deletions-client.d.ts","sourceRoot":"","sources":["../../src/rules/deletions-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAA;AAI3B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,oBAAoB,EAAE,CAAA;IACjC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,CAAA;AAMD;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,qBAAqB,CAAC,CAmChC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MAX_RULE_DELETIONS_BATCH, parseRuleDeletionsResponse, } from '@auden.to/protocol';
|
|
2
|
+
import { chunkArray } from '../chunk.js';
|
|
3
|
+
function trimTrailingSlashes(url) {
|
|
4
|
+
return url.replace(/\/+$/, '');
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* POST deletions to the dashboard, chunked to stay under the server's
|
|
8
|
+
* `MAX_RULE_DELETIONS_BATCH` per-request cap, and sum the parsed results.
|
|
9
|
+
* Empty input is rejected so the CLI never sends a useless request. Throws on
|
|
10
|
+
* transport, non-2xx, or malformed response bodies.
|
|
11
|
+
*/
|
|
12
|
+
export async function deleteRules(options) {
|
|
13
|
+
if (options.deletions.length === 0) {
|
|
14
|
+
throw new Error('deleteRules: deletions array must not be empty');
|
|
15
|
+
}
|
|
16
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
17
|
+
const url = `${trimTrailingSlashes(options.dashboardUrl)}/api/rules/deletions`;
|
|
18
|
+
let disabled = 0;
|
|
19
|
+
let skipped = 0;
|
|
20
|
+
for (const batch of chunkArray(options.deletions, MAX_RULE_DELETIONS_BATCH)) {
|
|
21
|
+
const response = await fetchImpl(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${options.token}`,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({ deletions: batch }),
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const text = await response.text().catch(() => '');
|
|
31
|
+
throw new Error(`Deletions failed with ${response.status}${text ? `: ${text}` : ''}`);
|
|
32
|
+
}
|
|
33
|
+
const json = (await response.json());
|
|
34
|
+
const result = parseRuleDeletionsResponse(json);
|
|
35
|
+
disabled += result.disabled;
|
|
36
|
+
skipped += result.skipped;
|
|
37
|
+
}
|
|
38
|
+
return { disabled, skipped };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=deletions-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deletions-client.js","sourceRoot":"","sources":["../../src/rules/deletions-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,GAG3B,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAUxC,SAAS,mBAAmB,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAChC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAA2B;IAE3B,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAA;IACnE,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAA;IAC5C,MAAM,GAAG,GAAG,GAAG,mBAAmB,CAAC,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAA;IAE9E,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,OAAO,GAAG,CAAC,CAAA;IAEf,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,wBAAwB,CAAC,EAAE,CAAC;QAC5E,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;gBACxC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;SAC3C,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;YAClD,MAAM,IAAI,KAAK,CACb,yBAAyB,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACrE,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAA;QAC/C,MAAM,MAAM,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAA;QAC/C,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAA;QAC3B,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;IAC3B,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;AAC9B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type FormatUnifiedDiffOptions = {
|
|
2
|
+
/** Number of unchanged context lines around each hunk. */
|
|
3
|
+
context?: number;
|
|
4
|
+
/** ANSI-colorize +/-/header lines. Defaults to false. */
|
|
5
|
+
color?: boolean;
|
|
6
|
+
/** Header label for the on-disk version. */
|
|
7
|
+
oldHeader?: string;
|
|
8
|
+
/** Header label for the incoming version. */
|
|
9
|
+
newHeader?: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Render a unified diff between `oldContent` and `newContent` for `filePath`.
|
|
13
|
+
*
|
|
14
|
+
* Wraps `diff.createTwoFilesPatch` and optionally applies ANSI colors so the
|
|
15
|
+
* output matches what users expect from `git diff`. Trailing blank lines from
|
|
16
|
+
* `createTwoFilesPatch` are trimmed so callers can append directly.
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatUnifiedDiff(oldContent: string, newContent: string, filePath: string, options?: FormatUnifiedDiffOptions): string;
|
|
19
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/rules/diff.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,wBAAwB,GAAG;IACrC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yDAAyD;IACzD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAcR"}
|