@weave_protocol/adapter-msaf 0.1.0

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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @weave_protocol/adapter-msaf — public API
3
+ *
4
+ * Primary export: WardMiddleware class.
5
+ * Plus: types, policy loader, evaluator.
6
+ */
7
+ export { WardMiddleware } from './middleware.js';
8
+ export { TOOL_MAPPINGS, WardDeniedError, } from './types.js';
9
+ export type { ToolMapping, MsafToolCall, MsafMiddlewareResult, MiddlewareOptions, } from './types.js';
10
+ export { resolveWardForCwd, loadWardFromSource, evaluateCall, } from './policy.js';
11
+ export type { ResolvedWard } from './policy.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @weave_protocol/adapter-msaf — public API
3
+ *
4
+ * Primary export: WardMiddleware class.
5
+ * Plus: types, policy loader, evaluator.
6
+ */
7
+ export { WardMiddleware } from './middleware.js';
8
+ export { TOOL_MAPPINGS, WardDeniedError, } from './types.js';
9
+ export { resolveWardForCwd, loadWardFromSource, evaluateCall, } from './policy.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAOpB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,GACb,MAAM,aAAa,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * WARD middleware for the Microsoft Agent Framework.
3
+ *
4
+ * MSAF exposes three middleware types; we provide adapters for two of them:
5
+ *
6
+ * 1. Function middleware — gates individual tool calls. This is the primary
7
+ * WARD enforcement layer. Use `.functionMiddleware()`.
8
+ *
9
+ * 2. Agent middleware — gates whole agent turns. Wraps the entire run.
10
+ * Use `.agentMiddleware()`. Less granular than function middleware but
11
+ * useful for behavioral-limit checks (max iterations, max cost) and
12
+ * for adding session-scoped logging.
13
+ *
14
+ * The user is responsible for registering the returned function with their
15
+ * MSAF agent / chat client. We don't reach into MSAF's internals.
16
+ *
17
+ * Why we don't ship a direct MSAF SDK dependency:
18
+ * MSAF's primary surface is .NET. The Node/TS bindings are evolving and
19
+ * we don't want to pin a specific 1.0.0-rc version. Instead, we expose
20
+ * middleware FUNCTIONS that match MSAF's documented `pre_invoke` and
21
+ * `agent_middleware` signatures. The user wires them in.
22
+ */
23
+ import { type WardPolicy } from '@weave_protocol/ward';
24
+ import { type MsafToolCall, type MsafMiddlewareResult, type MiddlewareOptions } from './types.js';
25
+ /**
26
+ * The primary entry point. Construct one, register the returned middleware
27
+ * functions with your MSAF agent.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * import { WardMiddleware } from '@weave_protocol/adapter-msaf';
32
+ *
33
+ * const ward = new WardMiddleware({ wardPath: './WARD.md' });
34
+ *
35
+ * // For per-tool gating (primary use):
36
+ * agent.useFunctionMiddleware(ward.functionMiddleware());
37
+ *
38
+ * // For turn-level gating (optional, complementary):
39
+ * agent.useAgentMiddleware(ward.agentMiddleware());
40
+ * ```
41
+ */
42
+ export declare class WardMiddleware {
43
+ private resolved;
44
+ private readonly failClosed;
45
+ private readonly toolMappings;
46
+ private readonly onAllow?;
47
+ private readonly onDeny?;
48
+ constructor(opts?: MiddlewareOptions);
49
+ /**
50
+ * Returns true if a WARD policy is loaded.
51
+ */
52
+ isLoaded(): boolean;
53
+ /**
54
+ * The active WARD policy source path (or '<inline>'), if loaded.
55
+ */
56
+ getPolicySource(): string | null;
57
+ /**
58
+ * The parsed WARD policy object, if loaded.
59
+ */
60
+ getPolicy(): WardPolicy | null;
61
+ /**
62
+ * Evaluate a tool call against the loaded policy. Pure function — does
63
+ * not throw. Useful for testing and for users who want to run the check
64
+ * manually without going through middleware.
65
+ */
66
+ evaluate(call: MsafToolCall): MsafMiddlewareResult;
67
+ /**
68
+ * Returns a function middleware compatible with MSAF's function-middleware
69
+ * pre_invoke shape. The returned function:
70
+ * - calls next() if the call is allowed
71
+ * - throws WardDeniedError if the call is denied or requires approval
72
+ *
73
+ * Usage:
74
+ * agent.useFunctionMiddleware(ward.functionMiddleware());
75
+ */
76
+ functionMiddleware(): (call: MsafToolCall, next: () => Promise<unknown>) => Promise<unknown>;
77
+ /**
78
+ * Returns an agent middleware compatible with MSAF's agent middleware
79
+ * shape. This fires once per turn before any LLM call.
80
+ *
81
+ * The agent middleware is informational only by default — it doesn't gate
82
+ * individual tool calls (that's what functionMiddleware is for). It exists
83
+ * so users who want a turn-level hook (for logging or session tracking)
84
+ * can register one. To enforce behavioral limits (cost, iterations) at the
85
+ * turn level, subclass or wrap this.
86
+ */
87
+ agentMiddleware(): (ctx: {
88
+ turnIndex?: number;
89
+ }, next: () => Promise<unknown>) => Promise<unknown>;
90
+ /**
91
+ * Backward-compatible: alias for functionMiddleware().
92
+ * MSAF's terminology evolved; we keep both spellings.
93
+ */
94
+ middleware(): ReturnType<WardMiddleware['functionMiddleware']>;
95
+ }
96
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EAGvB,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA8B;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA8B;gBAE1C,IAAI,GAAE,iBAAsB;IA6BxC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,SAAS,IAAI,UAAU,GAAG,IAAI;IAI9B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,oBAAoB;IAQlD;;;;;;;;OAQG;IACH,kBAAkB,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IA2B5F;;;;;;;;;OASG;IACH,eAAe,IAAI,CAAC,GAAG,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IAQlG;;;OAGG;IACH,UAAU,IAAI,UAAU,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;CAG/D"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * WARD middleware for the Microsoft Agent Framework.
3
+ *
4
+ * MSAF exposes three middleware types; we provide adapters for two of them:
5
+ *
6
+ * 1. Function middleware — gates individual tool calls. This is the primary
7
+ * WARD enforcement layer. Use `.functionMiddleware()`.
8
+ *
9
+ * 2. Agent middleware — gates whole agent turns. Wraps the entire run.
10
+ * Use `.agentMiddleware()`. Less granular than function middleware but
11
+ * useful for behavioral-limit checks (max iterations, max cost) and
12
+ * for adding session-scoped logging.
13
+ *
14
+ * The user is responsible for registering the returned function with their
15
+ * MSAF agent / chat client. We don't reach into MSAF's internals.
16
+ *
17
+ * Why we don't ship a direct MSAF SDK dependency:
18
+ * MSAF's primary surface is .NET. The Node/TS bindings are evolving and
19
+ * we don't want to pin a specific 1.0.0-rc version. Instead, we expose
20
+ * middleware FUNCTIONS that match MSAF's documented `pre_invoke` and
21
+ * `agent_middleware` signatures. The user wires them in.
22
+ */
23
+ import { readFileSync, existsSync } from 'node:fs';
24
+ import { WardDeniedError, } from './types.js';
25
+ import { resolveWardForCwd, loadWardFromSource, evaluateCall } from './policy.js';
26
+ // ============================================================================
27
+ // WardMiddleware class
28
+ // ============================================================================
29
+ /**
30
+ * The primary entry point. Construct one, register the returned middleware
31
+ * functions with your MSAF agent.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { WardMiddleware } from '@weave_protocol/adapter-msaf';
36
+ *
37
+ * const ward = new WardMiddleware({ wardPath: './WARD.md' });
38
+ *
39
+ * // For per-tool gating (primary use):
40
+ * agent.useFunctionMiddleware(ward.functionMiddleware());
41
+ *
42
+ * // For turn-level gating (optional, complementary):
43
+ * agent.useAgentMiddleware(ward.agentMiddleware());
44
+ * ```
45
+ */
46
+ export class WardMiddleware {
47
+ resolved;
48
+ failClosed;
49
+ toolMappings;
50
+ onAllow;
51
+ onDeny;
52
+ constructor(opts = {}) {
53
+ this.failClosed = opts.failMode === 'closed';
54
+ this.toolMappings = opts.toolMappings || {};
55
+ this.onAllow = opts.onAllow;
56
+ this.onDeny = opts.onDeny;
57
+ try {
58
+ if (opts.wardSource) {
59
+ this.resolved = loadWardFromSource(opts.wardSource, '<inline>');
60
+ }
61
+ else if (opts.wardPath) {
62
+ if (!existsSync(opts.wardPath)) {
63
+ throw new Error(`WARD.md not found at ${opts.wardPath}`);
64
+ }
65
+ const src = readFileSync(opts.wardPath, 'utf8');
66
+ this.resolved = loadWardFromSource(src, opts.wardPath);
67
+ }
68
+ else {
69
+ this.resolved = resolveWardForCwd();
70
+ }
71
+ }
72
+ catch (err) {
73
+ if (this.failClosed)
74
+ throw err;
75
+ // Fail-open: log and continue with no policy (every call allowed)
76
+ // eslint-disable-next-line no-console
77
+ console.warn(`[weave-msaf] WARD.md could not be loaded (${err instanceof Error ? err.message : String(err)}). Running in fail-open mode — no enforcement.`);
78
+ this.resolved = null;
79
+ }
80
+ }
81
+ /**
82
+ * Returns true if a WARD policy is loaded.
83
+ */
84
+ isLoaded() {
85
+ return this.resolved !== null;
86
+ }
87
+ /**
88
+ * The active WARD policy source path (or '<inline>'), if loaded.
89
+ */
90
+ getPolicySource() {
91
+ return this.resolved?.source ?? null;
92
+ }
93
+ /**
94
+ * The parsed WARD policy object, if loaded.
95
+ */
96
+ getPolicy() {
97
+ return this.resolved?.policy ?? null;
98
+ }
99
+ /**
100
+ * Evaluate a tool call against the loaded policy. Pure function — does
101
+ * not throw. Useful for testing and for users who want to run the check
102
+ * manually without going through middleware.
103
+ */
104
+ evaluate(call) {
105
+ if (!this.resolved) {
106
+ return { decision: 'allow', reasons: ['No WARD.md loaded'] };
107
+ }
108
+ const result = evaluateCall(this.resolved.policy, call, this.toolMappings);
109
+ return { ...result, policySource: this.resolved.source };
110
+ }
111
+ /**
112
+ * Returns a function middleware compatible with MSAF's function-middleware
113
+ * pre_invoke shape. The returned function:
114
+ * - calls next() if the call is allowed
115
+ * - throws WardDeniedError if the call is denied or requires approval
116
+ *
117
+ * Usage:
118
+ * agent.useFunctionMiddleware(ward.functionMiddleware());
119
+ */
120
+ functionMiddleware() {
121
+ return async (call, next) => {
122
+ const result = this.evaluate(call);
123
+ if (result.decision === 'allow') {
124
+ if (this.onAllow)
125
+ await this.onAllow(call, result);
126
+ return next();
127
+ }
128
+ // Denied or requires approval
129
+ if (this.onDeny) {
130
+ const override = await this.onDeny(call, result);
131
+ if (override === true) {
132
+ // User explicitly overrode the WARD decision
133
+ return next();
134
+ }
135
+ }
136
+ throw new WardDeniedError(result.decision === 'deny' ? 'deny' : 'require_approval', result.reasons, call.toolName, result.policySource);
137
+ };
138
+ }
139
+ /**
140
+ * Returns an agent middleware compatible with MSAF's agent middleware
141
+ * shape. This fires once per turn before any LLM call.
142
+ *
143
+ * The agent middleware is informational only by default — it doesn't gate
144
+ * individual tool calls (that's what functionMiddleware is for). It exists
145
+ * so users who want a turn-level hook (for logging or session tracking)
146
+ * can register one. To enforce behavioral limits (cost, iterations) at the
147
+ * turn level, subclass or wrap this.
148
+ */
149
+ agentMiddleware() {
150
+ return async (ctx, next) => {
151
+ // For now, agent middleware is pass-through; future versions can add
152
+ // iteration-counter / cost-tracking enforcement here.
153
+ return next();
154
+ };
155
+ }
156
+ /**
157
+ * Backward-compatible: alias for functionMiddleware().
158
+ * MSAF's terminology evolved; we keep both spellings.
159
+ */
160
+ middleware() {
161
+ return this.functionMiddleware();
162
+ }
163
+ }
164
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * WARD policy loading + evaluation for MSAF middleware.
3
+ *
4
+ * Unlike the Claude Code / Antigravity adapters which read WARD on every
5
+ * hook invocation (because they're spawned as subprocesses), MSAF middleware
6
+ * runs in-process. We load WARD once at middleware construction time and
7
+ * keep the parsed policy in memory for the lifetime of the agent run.
8
+ */
9
+ import { type WardPolicy } from '@weave_protocol/ward';
10
+ import { type ToolMapping, type MsafToolCall, type MsafMiddlewareResult } from './types.js';
11
+ export interface ResolvedWard {
12
+ policy: WardPolicy;
13
+ source: string;
14
+ }
15
+ /**
16
+ * Find a WARD.md by walking the resolution order:
17
+ * 1. $WEAVE_WARD_PATH if set
18
+ * 2. <cwd>/WARD.md
19
+ * 3. <cwd>/.weave/WARD.md
20
+ * 4. <cwd>/.msaf/WARD.md (MSAF convention if user puts config in .msaf/)
21
+ */
22
+ export declare function resolveWardForCwd(cwd?: string): ResolvedWard | null;
23
+ export declare function loadWardFromSource(source: string, label?: string): ResolvedWard;
24
+ export declare function evaluateCall(policy: WardPolicy, call: MsafToolCall, customMappings?: Record<string, ToolMapping>): MsafMiddlewareResult;
25
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,YAAY,GAAG,IAAI,CAmBlF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAa,GAAG,YAAY,CAEnF;AAMD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,YAAY,EAClB,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAM,GAC/C,oBAAoB,CA6DtB"}
package/dist/policy.js ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * WARD policy loading + evaluation for MSAF middleware.
3
+ *
4
+ * Unlike the Claude Code / Antigravity adapters which read WARD on every
5
+ * hook invocation (because they're spawned as subprocesses), MSAF middleware
6
+ * runs in-process. We load WARD once at middleware construction time and
7
+ * keep the parsed policy in memory for the lifetime of the agent run.
8
+ */
9
+ import { readFileSync, existsSync } from 'node:fs';
10
+ import { join, resolve } from 'node:path';
11
+ import { parseWard, checkCapability, checkFilesystem, checkNetwork, } from '@weave_protocol/ward';
12
+ import { TOOL_MAPPINGS, } from './types.js';
13
+ /**
14
+ * Find a WARD.md by walking the resolution order:
15
+ * 1. $WEAVE_WARD_PATH if set
16
+ * 2. <cwd>/WARD.md
17
+ * 3. <cwd>/.weave/WARD.md
18
+ * 4. <cwd>/.msaf/WARD.md (MSAF convention if user puts config in .msaf/)
19
+ */
20
+ export function resolveWardForCwd(cwd = process.cwd()) {
21
+ const candidates = [];
22
+ if (process.env.WEAVE_WARD_PATH)
23
+ candidates.push(process.env.WEAVE_WARD_PATH);
24
+ if (cwd) {
25
+ candidates.push(join(cwd, 'WARD.md'));
26
+ candidates.push(join(cwd, '.weave', 'WARD.md'));
27
+ candidates.push(join(cwd, '.msaf', 'WARD.md'));
28
+ }
29
+ for (const path of candidates) {
30
+ const resolved = resolve(path);
31
+ if (existsSync(resolved)) {
32
+ const source = readFileSync(resolved, 'utf8');
33
+ const policy = parseWard(source);
34
+ return { policy, source: resolved };
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+ export function loadWardFromSource(source, label = '<inline>') {
40
+ return { policy: parseWard(source), source: label };
41
+ }
42
+ // ============================================================================
43
+ // Evaluation
44
+ // ============================================================================
45
+ export function evaluateCall(policy, call, customMappings = {}) {
46
+ const reasons = [];
47
+ let decision = 'allow';
48
+ // Merge built-in + custom mappings; custom wins on conflict.
49
+ const mapping = customMappings[call.toolName] || TOOL_MAPPINGS[call.toolName] || { capability: call.toolName };
50
+ // 1. Capability check (mapped name + raw name, stricter explicit wins)
51
+ const capByMapping = checkCapability(policy, mapping.capability);
52
+ const capByRaw = checkCapability(policy, call.toolName);
53
+ const cap = mergeCapability(capByMapping, capByRaw);
54
+ if (cap.decision === 'deny') {
55
+ return { decision: 'deny', reasons: [cap.reason] };
56
+ }
57
+ if (cap.decision === 'require_approval') {
58
+ decision = 'require_approval';
59
+ reasons.push(cap.reason);
60
+ }
61
+ // 2. Filesystem check
62
+ if (mapping.pathField && call.args && typeof call.args[mapping.pathField] === 'string') {
63
+ const path = call.args[mapping.pathField];
64
+ const fs = checkFilesystem(policy, mapping.fsOp || 'read', path);
65
+ if (fs.decision === 'deny') {
66
+ return { decision: 'deny', reasons: [fs.reason] };
67
+ }
68
+ if (fs.decision === 'require_approval' && decision !== 'require_approval') {
69
+ decision = 'require_approval';
70
+ reasons.push(fs.reason);
71
+ }
72
+ }
73
+ // 3. Network check
74
+ if (mapping.urlField && call.args && typeof call.args[mapping.urlField] === 'string') {
75
+ const url = call.args[mapping.urlField];
76
+ const method = call.args.method || 'GET';
77
+ const net = checkNetwork(policy, url, method);
78
+ if (net.decision === 'deny') {
79
+ return { decision: 'deny', reasons: [net.reason] };
80
+ }
81
+ if (net.decision === 'require_approval' && decision !== 'require_approval') {
82
+ decision = 'require_approval';
83
+ reasons.push(net.reason);
84
+ }
85
+ }
86
+ // 4. Bash command heuristic
87
+ if (mapping.commandField && call.args && typeof call.args[mapping.commandField] === 'string') {
88
+ const command = call.args[mapping.commandField];
89
+ const bashCheck = scanBashCommand(policy, command);
90
+ if (bashCheck.decision === 'deny') {
91
+ return { decision: 'deny', reasons: [bashCheck.reason] };
92
+ }
93
+ if (bashCheck.decision === 'require_approval' && decision !== 'require_approval') {
94
+ decision = 'require_approval';
95
+ reasons.push(bashCheck.reason);
96
+ }
97
+ }
98
+ return { decision, reasons };
99
+ }
100
+ function isExplicit(reason) {
101
+ return (reason.includes('is in the allow list') ||
102
+ reason.includes('is in the deny list') ||
103
+ reason.includes('requires human approval'));
104
+ }
105
+ function mergeCapability(a, b) {
106
+ const aExp = isExplicit(a.reason);
107
+ const bExp = isExplicit(b.reason);
108
+ if (aExp && !bExp)
109
+ return a;
110
+ if (bExp && !aExp)
111
+ return b;
112
+ if (a.decision === 'deny' || b.decision === 'deny') {
113
+ return a.decision === 'deny' ? a : b;
114
+ }
115
+ if (a.decision === 'require_approval' || b.decision === 'require_approval') {
116
+ return a.decision === 'require_approval' ? a : b;
117
+ }
118
+ return a;
119
+ }
120
+ function scanBashCommand(policy, command) {
121
+ const urlMatch = command.match(/https?:\/\/[^\s'"`)]+/);
122
+ if (urlMatch) {
123
+ const net = checkNetwork(policy, urlMatch[0], 'GET');
124
+ if (net.decision === 'deny')
125
+ return { decision: 'deny', reason: `bash command targets ${urlMatch[0]}: ${net.reason}` };
126
+ if (net.decision === 'require_approval')
127
+ return { decision: 'require_approval', reason: `bash command targets ${urlMatch[0]}: ${net.reason}` };
128
+ }
129
+ const dangerousPaths = [
130
+ '~/.ssh',
131
+ '~/.aws',
132
+ '~/.config/gcloud',
133
+ '~/.azure', // Azure credentials (relevant for MSAF users)
134
+ '/etc/',
135
+ '/usr/',
136
+ '/.env',
137
+ ];
138
+ for (const danger of dangerousPaths) {
139
+ if (command.includes(danger)) {
140
+ let op = 'read';
141
+ if (/(?:^|[\s;|])rm\s/.test(command))
142
+ op = 'delete';
143
+ else if (/>|>>|tee|sed -i/.test(command))
144
+ op = 'write';
145
+ const fs = checkFilesystem(policy, op, danger + (danger.endsWith('/') ? '**' : ''));
146
+ if (fs.decision === 'deny')
147
+ return { decision: 'deny', reason: `bash touches ${danger}: ${fs.reason}` };
148
+ if (fs.decision === 'require_approval')
149
+ return { decision: 'require_approval', reason: `bash touches ${danger}: ${fs.reason}` };
150
+ }
151
+ }
152
+ return { decision: 'allow', reason: '' };
153
+ }
154
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Types for the Microsoft Agent Framework adapter.
3
+ *
4
+ * MSAF supports three middleware types (per the v1.0 docs):
5
+ * 1. Agent middleware — wraps full agent runs (once per turn)
6
+ * 2. Function middleware — wraps individual tool calls
7
+ * 3. Chat middleware — wraps raw model requests
8
+ *
9
+ * For WARD enforcement we primarily care about function middleware
10
+ * (since WARD gates tool calls), but we also expose an agent-middleware
11
+ * variant for users who want a turn-level gate.
12
+ */
13
+ /**
14
+ * A proposed function/tool call that MSAF is about to execute.
15
+ * Shape mirrors what MSAF's function middleware exposes via its context.
16
+ */
17
+ export interface MsafToolCall {
18
+ toolName: string;
19
+ args: Record<string, unknown>;
20
+ raw?: unknown;
21
+ }
22
+ /**
23
+ * Result of a WARD evaluation for an MSAF middleware.
24
+ */
25
+ export interface MsafMiddlewareResult {
26
+ decision: 'allow' | 'deny' | 'require_approval';
27
+ reasons: string[];
28
+ policySource?: string;
29
+ }
30
+ /**
31
+ * Standardized error thrown by the middleware when a call is denied.
32
+ * MSAF middleware short-circuits by throwing (or by not calling next()),
33
+ * so we provide a typed error so users can catch and handle it.
34
+ */
35
+ export declare class WardDeniedError extends Error {
36
+ readonly decision: 'deny' | 'require_approval';
37
+ readonly reasons: string[];
38
+ readonly policySource: string | undefined;
39
+ readonly toolName: string;
40
+ constructor(decision: 'deny' | 'require_approval', reasons: string[], toolName: string, policySource?: string);
41
+ }
42
+ /**
43
+ * Mapping from MSAF tool names to their nature.
44
+ *
45
+ * MSAF tools are user-defined, but several conventions are widely
46
+ * established (especially through the Copilot/Claude Code SDK harness
47
+ * integrations and the local agent runtime which exposes shell/file/
48
+ * messaging tools). The mappings below cover those well-known names.
49
+ *
50
+ * Users can also register custom mappings via MiddlewareOptions.toolMappings.
51
+ */
52
+ export interface ToolMapping {
53
+ capability: string;
54
+ pathField?: string;
55
+ fsOp?: 'read' | 'write' | 'execute' | 'delete' | 'list';
56
+ urlField?: string;
57
+ commandField?: string;
58
+ }
59
+ export declare const TOOL_MAPPINGS: Record<string, ToolMapping>;
60
+ /**
61
+ * Options when creating a WardMiddleware instance.
62
+ */
63
+ export interface MiddlewareOptions {
64
+ /**
65
+ * Explicit path to a WARD.md file. If omitted, resolves via:
66
+ * $WEAVE_WARD_PATH → <cwd>/WARD.md → <cwd>/.weave/WARD.md → <cwd>/.msaf/WARD.md
67
+ */
68
+ wardPath?: string;
69
+ /**
70
+ * Raw WARD.md content (alternative to wardPath). Useful for tests or
71
+ * embedding the policy in code.
72
+ */
73
+ wardSource?: string;
74
+ /**
75
+ * Custom tool name → capability mappings. Merged on top of the built-in
76
+ * TOOL_MAPPINGS so users can override or add.
77
+ */
78
+ toolMappings?: Record<string, ToolMapping>;
79
+ /**
80
+ * Fail mode:
81
+ * - 'open' (default): if WARD can't be loaded, allow the call and warn
82
+ * - 'closed': if WARD can't be loaded, deny the call
83
+ */
84
+ failMode?: 'open' | 'closed';
85
+ /**
86
+ * Optional callback when a call is allowed. Useful for logging/attestation.
87
+ */
88
+ onAllow?: (call: MsafToolCall, result: MsafMiddlewareResult) => void | Promise<void>;
89
+ /**
90
+ * Optional callback when a call is denied. Useful for alerting.
91
+ * If you return false, the call is allowed despite the WARD decision.
92
+ * (Generally don't do that — but it's available for emergency overrides.)
93
+ */
94
+ onDeny?: (call: MsafToolCall, result: MsafMiddlewareResult) => boolean | void | Promise<boolean | void>;
95
+ }
96
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,kBAAkB,CAAC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAgB,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACtD,SAAgB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClC,SAAgB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,SAAgB,QAAQ,EAAE,MAAM,CAAC;gBAG/B,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EACrC,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM;CAWxB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA4BrD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAE3C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErF;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,KAAK,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CACzG"}
package/dist/types.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Types for the Microsoft Agent Framework adapter.
3
+ *
4
+ * MSAF supports three middleware types (per the v1.0 docs):
5
+ * 1. Agent middleware — wraps full agent runs (once per turn)
6
+ * 2. Function middleware — wraps individual tool calls
7
+ * 3. Chat middleware — wraps raw model requests
8
+ *
9
+ * For WARD enforcement we primarily care about function middleware
10
+ * (since WARD gates tool calls), but we also expose an agent-middleware
11
+ * variant for users who want a turn-level gate.
12
+ */
13
+ /**
14
+ * Standardized error thrown by the middleware when a call is denied.
15
+ * MSAF middleware short-circuits by throwing (or by not calling next()),
16
+ * so we provide a typed error so users can catch and handle it.
17
+ */
18
+ export class WardDeniedError extends Error {
19
+ decision;
20
+ reasons;
21
+ policySource;
22
+ toolName;
23
+ constructor(decision, reasons, toolName, policySource) {
24
+ super(`WARD ${decision === 'deny' ? 'denied' : 'requires approval for'} tool '${toolName}': ${reasons.join(' | ')}`);
25
+ this.name = 'WardDeniedError';
26
+ this.decision = decision;
27
+ this.reasons = reasons;
28
+ this.policySource = policySource;
29
+ this.toolName = toolName;
30
+ }
31
+ }
32
+ export const TOOL_MAPPINGS = {
33
+ // MSAF local agent runtime tools
34
+ ShellExec: { capability: 'shell_exec', commandField: 'command' },
35
+ Bash: { capability: 'shell_exec', commandField: 'command' },
36
+ FileRead: { capability: 'file_read', pathField: 'path', fsOp: 'read' },
37
+ FileWrite: { capability: 'file_write', pathField: 'path', fsOp: 'write' },
38
+ FileEdit: { capability: 'file_write', pathField: 'path', fsOp: 'write' },
39
+ FileDelete: { capability: 'file_delete', pathField: 'path', fsOp: 'delete' },
40
+ ListDirectory: { capability: 'file_list', pathField: 'path', fsOp: 'list' },
41
+ HttpRequest: { capability: 'http_request', urlField: 'url' },
42
+ WebFetch: { capability: 'http_request', urlField: 'url' },
43
+ // Copilot SDK integration patterns
44
+ RunCommand: { capability: 'shell_exec', commandField: 'command' },
45
+ EditFile: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
46
+ ReadFile: { capability: 'file_read', pathField: 'file_path', fsOp: 'read' },
47
+ // Claude Code SDK integration (via MSAF) - share with adapter-claudecode names
48
+ Bash_via_claude: { capability: 'shell_exec', commandField: 'command' },
49
+ Edit: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
50
+ Write: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
51
+ Read: { capability: 'file_read', pathField: 'file_path', fsOp: 'read' },
52
+ // Common workflow/automation tools
53
+ SendEmail: { capability: 'send_email' },
54
+ PostMessage: { capability: 'send_message' },
55
+ CreateIssue: { capability: 'create_issue' },
56
+ Subagent: { capability: 'subagent' },
57
+ };
58
+ //# sourceMappingURL=types.js.map