@crossdelta/pf-mcp 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.
- package/README.md +389 -0
- package/dist/cli.cjs +2348 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +2379 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +2489 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +722 -0
- package/dist/index.d.ts +722 -0
- package/dist/index.js +2460 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
import { PfEffect, PfPluginContext, PfWorkspaceContext } from '@crossdelta/platform-sdk/facade';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Effect Executor Types
|
|
5
|
+
*
|
|
6
|
+
* All type definitions for effect execution.
|
|
7
|
+
* Types first, following project conventions.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Error codes for structured error reporting
|
|
12
|
+
*/
|
|
13
|
+
declare const ErrorCodes: {
|
|
14
|
+
readonly PATH_OUTSIDE_ROOT: "PATH_OUTSIDE_ROOT";
|
|
15
|
+
readonly REQUIRES_ELICITATION: "REQUIRES_ELICITATION";
|
|
16
|
+
readonly UNSUPPORTED_EFFECT: "UNSUPPORTED_EFFECT";
|
|
17
|
+
readonly WRITE_FAILED: "WRITE_FAILED";
|
|
18
|
+
readonly ATOMIC_RENAME_FAILED: "ATOMIC_RENAME_FAILED";
|
|
19
|
+
readonly PLAN_HASH_MISMATCH: "PLAN_HASH_MISMATCH";
|
|
20
|
+
readonly REVIEW_REQUIRED: "REVIEW_REQUIRED";
|
|
21
|
+
readonly REVIEW_TOKEN_INVALID: "REVIEW_TOKEN_INVALID";
|
|
22
|
+
readonly REVIEW_TOKEN_MISMATCH: "REVIEW_TOKEN_MISMATCH";
|
|
23
|
+
readonly POLICY_VERSION_MISMATCH: "POLICY_VERSION_MISMATCH";
|
|
24
|
+
readonly POLICY_VIOLATION: "POLICY_VIOLATION";
|
|
25
|
+
readonly FORBIDDEN_DIR: "FORBIDDEN_DIR";
|
|
26
|
+
readonly CONSOLE_IN_DOMAIN: "CONSOLE_IN_DOMAIN";
|
|
27
|
+
readonly PROCESS_ENV_IN_DOMAIN: "PROCESS_ENV_IN_DOMAIN";
|
|
28
|
+
readonly FETCH_IN_DOMAIN: "FETCH_IN_DOMAIN";
|
|
29
|
+
};
|
|
30
|
+
type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
31
|
+
type EffectStatus = 'created' | 'updated' | 'skipped' | 'error' | 'would_create' | 'would_update' | 'would_skip';
|
|
32
|
+
interface PreviewInfo {
|
|
33
|
+
/** Existing file size in bytes */
|
|
34
|
+
oldBytes?: number;
|
|
35
|
+
/** New content size in bytes */
|
|
36
|
+
newBytes?: number;
|
|
37
|
+
/** SHA-256 hash of existing content */
|
|
38
|
+
oldHash?: string;
|
|
39
|
+
/** SHA-256 hash of new content */
|
|
40
|
+
newHash?: string;
|
|
41
|
+
/** Would overwrite existing file */
|
|
42
|
+
wouldOverwrite?: boolean;
|
|
43
|
+
/** @deprecated Use oldBytes/newBytes */
|
|
44
|
+
existingLength?: number;
|
|
45
|
+
/** @deprecated Use oldBytes/newBytes */
|
|
46
|
+
newLength?: number;
|
|
47
|
+
}
|
|
48
|
+
interface EffectExecutionResult {
|
|
49
|
+
/** Effect that was executed */
|
|
50
|
+
effect: PfEffect;
|
|
51
|
+
/** Whether execution succeeded (false for errors and dryRun) */
|
|
52
|
+
success: boolean;
|
|
53
|
+
/** Result status */
|
|
54
|
+
status: EffectStatus;
|
|
55
|
+
/** Human-readable message */
|
|
56
|
+
message: string;
|
|
57
|
+
/** Path affected (if applicable) */
|
|
58
|
+
path?: string;
|
|
59
|
+
/** Target identifier (file path, env key, etc.) */
|
|
60
|
+
target?: string;
|
|
61
|
+
/** Error code (if error) */
|
|
62
|
+
code?: ErrorCode;
|
|
63
|
+
/** Reason for skip/decision */
|
|
64
|
+
reason?: string;
|
|
65
|
+
/** Preview info for dryRun (rich artifacts) */
|
|
66
|
+
preview?: PreviewInfo;
|
|
67
|
+
}
|
|
68
|
+
interface EffectSummary {
|
|
69
|
+
/** Counts by effect kind */
|
|
70
|
+
byKind: Record<string, {
|
|
71
|
+
total: number;
|
|
72
|
+
created: number;
|
|
73
|
+
updated: number;
|
|
74
|
+
skipped: number;
|
|
75
|
+
error: number;
|
|
76
|
+
}>;
|
|
77
|
+
/** Total bytes that would be written */
|
|
78
|
+
totalNewBytes: number;
|
|
79
|
+
/** Total bytes that would be overwritten */
|
|
80
|
+
totalOldBytes: number;
|
|
81
|
+
}
|
|
82
|
+
interface EffectCounts {
|
|
83
|
+
created: number;
|
|
84
|
+
updated: number;
|
|
85
|
+
skipped: number;
|
|
86
|
+
error: number;
|
|
87
|
+
wouldCreate: number;
|
|
88
|
+
wouldUpdate: number;
|
|
89
|
+
wouldSkip: number;
|
|
90
|
+
}
|
|
91
|
+
interface PolicyViolationInfo {
|
|
92
|
+
code: string;
|
|
93
|
+
message: string;
|
|
94
|
+
path: string;
|
|
95
|
+
line?: number;
|
|
96
|
+
}
|
|
97
|
+
interface ApplyResult {
|
|
98
|
+
/** Overall success (all effects succeeded, or dryRun completed) */
|
|
99
|
+
ok: boolean;
|
|
100
|
+
/** Summary message */
|
|
101
|
+
summary: string;
|
|
102
|
+
/** Individual effect results */
|
|
103
|
+
results: EffectExecutionResult[];
|
|
104
|
+
/** Counts by status */
|
|
105
|
+
counts: EffectCounts;
|
|
106
|
+
/** Whether this was a dry run */
|
|
107
|
+
dryRun: boolean;
|
|
108
|
+
/** Error code (if top-level error) */
|
|
109
|
+
code?: ErrorCode;
|
|
110
|
+
/** Structured summary (M9: rich preview) */
|
|
111
|
+
structuredSummary?: EffectSummary;
|
|
112
|
+
/** Policy violations (if any) */
|
|
113
|
+
policyViolations?: PolicyViolationInfo[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Plan Types
|
|
118
|
+
*
|
|
119
|
+
* Types for the deterministic planning system.
|
|
120
|
+
* MCP = Planner (structure), AI = Code Generator (content)
|
|
121
|
+
*
|
|
122
|
+
* Flow:
|
|
123
|
+
* 1. AI/Copilot delivers Intent + Inputs
|
|
124
|
+
* 2. pf generates Plan + Preview (deterministic)
|
|
125
|
+
* 3. Optional: plan_review for validation
|
|
126
|
+
* 4. User OK Gate
|
|
127
|
+
* 5. apply_changes with expectedPlanHash (idempotent)
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
type PlanIssueSeverity = 'error' | 'warning' | 'info';
|
|
131
|
+
interface PlanIssue {
|
|
132
|
+
/** Issue severity */
|
|
133
|
+
severity: PlanIssueSeverity;
|
|
134
|
+
/** Error code for programmatic handling */
|
|
135
|
+
code: string;
|
|
136
|
+
/** Human-readable message */
|
|
137
|
+
message: string;
|
|
138
|
+
/** Affected path (if applicable) */
|
|
139
|
+
path?: string;
|
|
140
|
+
/** Line number (if applicable) */
|
|
141
|
+
line?: number;
|
|
142
|
+
}
|
|
143
|
+
interface PlanPreviewCounts {
|
|
144
|
+
/** Files that would be created */
|
|
145
|
+
wouldCreate: number;
|
|
146
|
+
/** Files that would be updated */
|
|
147
|
+
wouldUpdate: number;
|
|
148
|
+
/** Files that would be skipped (no changes) */
|
|
149
|
+
wouldSkip: number;
|
|
150
|
+
/** Effects with errors */
|
|
151
|
+
errors: number;
|
|
152
|
+
}
|
|
153
|
+
interface PlanPreview {
|
|
154
|
+
/** Counts by action type */
|
|
155
|
+
counts: PlanPreviewCounts;
|
|
156
|
+
/** Total bytes that would be written */
|
|
157
|
+
totalNewBytes: number;
|
|
158
|
+
/** Total bytes that would be overwritten */
|
|
159
|
+
totalOldBytes: number;
|
|
160
|
+
/** Files grouped by action */
|
|
161
|
+
files: {
|
|
162
|
+
create: string[];
|
|
163
|
+
update: string[];
|
|
164
|
+
skip: string[];
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
interface FilePlanEntry {
|
|
168
|
+
/** Absolute path where file should be created */
|
|
169
|
+
path: string;
|
|
170
|
+
/** Human-readable intent (what this file should do) */
|
|
171
|
+
intent: string;
|
|
172
|
+
/** Inputs for AI code generation */
|
|
173
|
+
inputs: Record<string, unknown>;
|
|
174
|
+
/** File layer for constraint enforcement */
|
|
175
|
+
layer?: 'domain' | 'useCase' | 'adapter' | 'infra' | 'config';
|
|
176
|
+
/** File kind for context */
|
|
177
|
+
kind?: 'handler' | 'adapter' | 'service' | 'useCase' | 'contract' | 'config' | 'test';
|
|
178
|
+
}
|
|
179
|
+
interface DependencyIntent {
|
|
180
|
+
/** Package name (e.g., '@pusher/push-notifications-server') */
|
|
181
|
+
name: string;
|
|
182
|
+
/** Version constraint (e.g., '^1.0.0', 'latest') */
|
|
183
|
+
version?: string;
|
|
184
|
+
/** Whether this is a dev dependency */
|
|
185
|
+
dev?: boolean;
|
|
186
|
+
/** Reason for adding this dependency */
|
|
187
|
+
reason?: string;
|
|
188
|
+
}
|
|
189
|
+
interface EnvVarIntent {
|
|
190
|
+
/** Environment variable key */
|
|
191
|
+
key: string;
|
|
192
|
+
/** Description for documentation */
|
|
193
|
+
description: string;
|
|
194
|
+
/** Whether this env var is required */
|
|
195
|
+
required: boolean;
|
|
196
|
+
/** Example value (for .env.example) */
|
|
197
|
+
example?: string;
|
|
198
|
+
}
|
|
199
|
+
interface GenerationPlanResult {
|
|
200
|
+
/** Whether plan generation succeeded */
|
|
201
|
+
ok: boolean;
|
|
202
|
+
/** Service name */
|
|
203
|
+
serviceName: string;
|
|
204
|
+
/** Service directory (relative to workspace) */
|
|
205
|
+
serviceDir: string;
|
|
206
|
+
/** Files to generate (paths/intent only - AI fills content) */
|
|
207
|
+
files: FilePlanEntry[];
|
|
208
|
+
/** Effects ready to apply (scaffold files with content) */
|
|
209
|
+
effects: PfEffect[];
|
|
210
|
+
/** Dependencies to add */
|
|
211
|
+
dependencies: DependencyIntent[];
|
|
212
|
+
/** Environment variables needed */
|
|
213
|
+
envVars: EnvVarIntent[];
|
|
214
|
+
/** Post-generation commands */
|
|
215
|
+
postCommands: string[];
|
|
216
|
+
/** SHA-256 hash of the plan for integrity verification */
|
|
217
|
+
planHash: string;
|
|
218
|
+
/** Preview of what would happen */
|
|
219
|
+
preview: PlanPreview;
|
|
220
|
+
/** Whether plan can be applied (no blocking errors) */
|
|
221
|
+
canApply: boolean;
|
|
222
|
+
/** Validation issues */
|
|
223
|
+
issues: PlanIssue[];
|
|
224
|
+
/** Metadata for debugging/logging */
|
|
225
|
+
metadata: Record<string, unknown>;
|
|
226
|
+
}
|
|
227
|
+
interface ApplyChangesInput {
|
|
228
|
+
/** Effects to apply (AI-generated content merged with plan) */
|
|
229
|
+
changes: PfEffect[];
|
|
230
|
+
/** Optional: Workspace root path */
|
|
231
|
+
workspaceRoot?: string;
|
|
232
|
+
/** Optional: Expected plan hash for drift detection */
|
|
233
|
+
expectedPlanHash?: string;
|
|
234
|
+
/** Optional: If true, requires a valid reviewToken */
|
|
235
|
+
requireReview?: boolean;
|
|
236
|
+
/** Optional: Review token from plan_review */
|
|
237
|
+
reviewToken?: string;
|
|
238
|
+
/** Optional: Expected policy version */
|
|
239
|
+
expectedPolicyVersion?: string;
|
|
240
|
+
}
|
|
241
|
+
interface DependencyPolicy {
|
|
242
|
+
/** Patterns to deny (e.g., file:, git+, https://) */
|
|
243
|
+
denyPatterns: string[];
|
|
244
|
+
/** Pinning strategy for new dependencies */
|
|
245
|
+
pinningStrategy: 'caret' | 'exact' | 'tilde';
|
|
246
|
+
/** Registry URL (optional, for private registries) */
|
|
247
|
+
registryUrl?: string;
|
|
248
|
+
}
|
|
249
|
+
declare const DEFAULT_DEPENDENCY_POLICY: DependencyPolicy;
|
|
250
|
+
declare const isFilePlanEntry: (value: unknown) => value is FilePlanEntry;
|
|
251
|
+
declare const isDependencyIntent: (value: unknown) => value is DependencyIntent;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Deps Add Executor
|
|
255
|
+
*
|
|
256
|
+
* Handles deps:add effects:
|
|
257
|
+
* - Adds dependency to package.json
|
|
258
|
+
* - Validates against DependencyPolicy (denyPatterns)
|
|
259
|
+
* - Idempotent: skips if dependency already exists with compatible version
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
interface DepsAddEffect {
|
|
263
|
+
readonly kind: 'deps:add';
|
|
264
|
+
/** Package name */
|
|
265
|
+
readonly name: string;
|
|
266
|
+
/** Version constraint (e.g., '^1.0.0', 'latest') */
|
|
267
|
+
readonly version?: string;
|
|
268
|
+
/** Whether this is a dev dependency */
|
|
269
|
+
readonly dev?: boolean;
|
|
270
|
+
/** Target service directory (relative to workspace root) */
|
|
271
|
+
readonly targetDir?: string;
|
|
272
|
+
}
|
|
273
|
+
declare const isDepsAddEffect: (effect: unknown) => effect is DepsAddEffect;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Audit Module
|
|
277
|
+
*
|
|
278
|
+
* Writes audit artifacts for apply_changes operations.
|
|
279
|
+
* Provides traceability for what was applied, when, and by whom.
|
|
280
|
+
*
|
|
281
|
+
* Audit artifacts are stored in: .pf/audit/<planHash>-<timestamp>.json
|
|
282
|
+
*
|
|
283
|
+
* Format:
|
|
284
|
+
* {
|
|
285
|
+
* planHash: string,
|
|
286
|
+
* reviewToken?: string,
|
|
287
|
+
* policyVersion: string,
|
|
288
|
+
* appliedAt: string (ISO),
|
|
289
|
+
* reviewedAt?: string (ISO),
|
|
290
|
+
* dryRun: boolean,
|
|
291
|
+
* summary: string,
|
|
292
|
+
* counts: {...},
|
|
293
|
+
* effects: PfEffect[],
|
|
294
|
+
* results: EffectExecutionResult[]
|
|
295
|
+
* }
|
|
296
|
+
*/
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Audit artifact data
|
|
300
|
+
*/
|
|
301
|
+
interface AuditArtifact {
|
|
302
|
+
/** Plan hash (SHA-256) */
|
|
303
|
+
planHash: string;
|
|
304
|
+
/** Review token used (if any) */
|
|
305
|
+
reviewToken?: string;
|
|
306
|
+
/** Policy version */
|
|
307
|
+
policyVersion: string;
|
|
308
|
+
/** ISO timestamp when apply was executed */
|
|
309
|
+
appliedAt: string;
|
|
310
|
+
/** ISO timestamp when plan was reviewed (from review token) */
|
|
311
|
+
reviewedAt?: string;
|
|
312
|
+
/** Whether this was a dry run */
|
|
313
|
+
dryRun: boolean;
|
|
314
|
+
/** Summary message */
|
|
315
|
+
summary: string;
|
|
316
|
+
/** Execution counts */
|
|
317
|
+
counts: ApplyResult['counts'];
|
|
318
|
+
/** Effects that were applied */
|
|
319
|
+
effects: readonly PfEffect[];
|
|
320
|
+
/** Individual execution results */
|
|
321
|
+
results: readonly EffectExecutionResult[];
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Audit directory name (relative to workspace root)
|
|
325
|
+
*/
|
|
326
|
+
declare const AUDIT_DIR = ".pf/audit";
|
|
327
|
+
/**
|
|
328
|
+
* Generate audit artifact filename
|
|
329
|
+
*
|
|
330
|
+
* Format: <planHash>-<timestamp>.json
|
|
331
|
+
* Timestamp is ISO format with colons replaced by dashes for filesystem safety
|
|
332
|
+
*/
|
|
333
|
+
declare const generateAuditFilename: (planHash: string, appliedAt: string) => string;
|
|
334
|
+
/**
|
|
335
|
+
* Write audit artifact to filesystem
|
|
336
|
+
*
|
|
337
|
+
* @param audit - Audit artifact data
|
|
338
|
+
* @param workspaceRoot - Workspace root path
|
|
339
|
+
* @returns Absolute path to written audit file
|
|
340
|
+
*/
|
|
341
|
+
declare const writeAuditArtifact: (audit: AuditArtifact, workspaceRoot: string) => string;
|
|
342
|
+
/**
|
|
343
|
+
* Create audit artifact from apply result
|
|
344
|
+
*/
|
|
345
|
+
declare const createAuditArtifact: (planHash: string, policyVersion: string, effects: readonly PfEffect[], result: ApplyResult, options?: {
|
|
346
|
+
reviewToken?: string;
|
|
347
|
+
reviewedAt?: string;
|
|
348
|
+
}) => AuditArtifact;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Plan Cache Module
|
|
352
|
+
*
|
|
353
|
+
* In-memory cache for plans and reviews.
|
|
354
|
+
* Used by MCP resources to retrieve plan/review data by hash.
|
|
355
|
+
*
|
|
356
|
+
* Cache Keys:
|
|
357
|
+
* - plan:<hash> → Plan data (effects array, metadata)
|
|
358
|
+
* - review:<hash> → Review result (from plan_review)
|
|
359
|
+
*
|
|
360
|
+
* Cache is scoped to the MCP server process lifetime.
|
|
361
|
+
* No persistence - restart clears cache.
|
|
362
|
+
*/
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Cached plan entry
|
|
366
|
+
*/
|
|
367
|
+
interface CachedPlan {
|
|
368
|
+
/** Plan hash (SHA-256) */
|
|
369
|
+
planHash: string;
|
|
370
|
+
/** Effects array */
|
|
371
|
+
effects: readonly PfEffect[];
|
|
372
|
+
/** ISO timestamp when plan was created/cached */
|
|
373
|
+
createdAt: string;
|
|
374
|
+
/** Source operation (generate_service, etc.) */
|
|
375
|
+
source: string;
|
|
376
|
+
/** Optional metadata */
|
|
377
|
+
metadata?: Record<string, unknown>;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Cached review entry
|
|
381
|
+
*/
|
|
382
|
+
interface CachedReview {
|
|
383
|
+
/** Plan hash this review is for */
|
|
384
|
+
planHash: string;
|
|
385
|
+
/** Policy version at review time */
|
|
386
|
+
policyVersion: string;
|
|
387
|
+
/** Review token (planHash.policyVersion) */
|
|
388
|
+
reviewToken: string;
|
|
389
|
+
/** ISO timestamp when review was performed */
|
|
390
|
+
reviewedAt: string;
|
|
391
|
+
/** Whether the plan passed review */
|
|
392
|
+
valid: boolean;
|
|
393
|
+
/** Whether the plan can be applied */
|
|
394
|
+
canApply: boolean;
|
|
395
|
+
/** Preview counts */
|
|
396
|
+
preview: {
|
|
397
|
+
wouldCreate: number;
|
|
398
|
+
wouldUpdate: number;
|
|
399
|
+
wouldSkip: number;
|
|
400
|
+
errors: number;
|
|
401
|
+
};
|
|
402
|
+
/** Issues found during review */
|
|
403
|
+
issues: ReadonlyArray<{
|
|
404
|
+
severity: 'error' | 'warning' | 'info';
|
|
405
|
+
code: string;
|
|
406
|
+
message: string;
|
|
407
|
+
target?: string;
|
|
408
|
+
}>;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get a cached plan by hash
|
|
412
|
+
*/
|
|
413
|
+
declare const getPlan: (planHash: string) => CachedPlan | undefined;
|
|
414
|
+
/**
|
|
415
|
+
* Get a cached review by plan hash
|
|
416
|
+
*/
|
|
417
|
+
declare const getReview: (planHash: string) => CachedReview | undefined;
|
|
418
|
+
/**
|
|
419
|
+
* Store a plan in the cache
|
|
420
|
+
*/
|
|
421
|
+
declare const cachePlan: (plan: CachedPlan) => void;
|
|
422
|
+
/**
|
|
423
|
+
* Store a review in the cache
|
|
424
|
+
*/
|
|
425
|
+
declare const cacheReview: (review: CachedReview) => void;
|
|
426
|
+
/**
|
|
427
|
+
* Check if a plan exists in the cache
|
|
428
|
+
*/
|
|
429
|
+
declare const hasPlan: (planHash: string) => boolean;
|
|
430
|
+
/**
|
|
431
|
+
* Check if a review exists in the cache
|
|
432
|
+
*/
|
|
433
|
+
declare const hasReview: (planHash: string) => boolean;
|
|
434
|
+
/**
|
|
435
|
+
* Get all cached plan hashes
|
|
436
|
+
*/
|
|
437
|
+
declare const listPlanHashes: () => string[];
|
|
438
|
+
/**
|
|
439
|
+
* Get all cached review hashes
|
|
440
|
+
*/
|
|
441
|
+
declare const listReviewHashes: () => string[];
|
|
442
|
+
/**
|
|
443
|
+
* Clear all caches (for testing)
|
|
444
|
+
*/
|
|
445
|
+
declare const clearCache: () => void;
|
|
446
|
+
/**
|
|
447
|
+
* Get cache statistics
|
|
448
|
+
*/
|
|
449
|
+
declare const getCacheStats: () => {
|
|
450
|
+
planCount: number;
|
|
451
|
+
reviewCount: number;
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Plan Hash Module
|
|
456
|
+
*
|
|
457
|
+
* Provides deterministic hashing for effect plans.
|
|
458
|
+
* Used for integrity verification between generate→review→apply flow.
|
|
459
|
+
*
|
|
460
|
+
* Key Features:
|
|
461
|
+
* - stableStringify: Deterministic JSON serialization (sorted keys)
|
|
462
|
+
* - computePlanHash: SHA-256 hex hash of normalized plan
|
|
463
|
+
* - computeContentHash: SHA-256 hex hash of file content
|
|
464
|
+
*/
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Stable JSON stringify with deterministic key ordering
|
|
468
|
+
*
|
|
469
|
+
* Ensures identical plans always produce identical strings,
|
|
470
|
+
* regardless of object key insertion order.
|
|
471
|
+
*
|
|
472
|
+
* @param value - Any JSON-serializable value
|
|
473
|
+
* @returns Deterministic JSON string
|
|
474
|
+
*/
|
|
475
|
+
declare const stableStringify: (value: unknown) => string;
|
|
476
|
+
/**
|
|
477
|
+
* Compute SHA-256 hash of a plan (effects array)
|
|
478
|
+
*
|
|
479
|
+
* Uses stableStringify for deterministic serialization.
|
|
480
|
+
* Returns lowercase hex string.
|
|
481
|
+
*
|
|
482
|
+
* @param changes - Array of effects to hash
|
|
483
|
+
* @returns SHA-256 hex hash (64 characters)
|
|
484
|
+
*/
|
|
485
|
+
declare const computePlanHash: (changes: readonly PfEffect[]) => string;
|
|
486
|
+
/**
|
|
487
|
+
* Compute SHA-256 hash of file content
|
|
488
|
+
*
|
|
489
|
+
* Uses UTF-8 encoding. Returns lowercase hex string.
|
|
490
|
+
*
|
|
491
|
+
* @param content - File content string
|
|
492
|
+
* @returns SHA-256 hex hash (64 characters)
|
|
493
|
+
*/
|
|
494
|
+
declare const computeContentHash: (content: string) => string;
|
|
495
|
+
/**
|
|
496
|
+
* Verify plan hash matches expected value
|
|
497
|
+
*
|
|
498
|
+
* @param changes - Current effects array
|
|
499
|
+
* @param expectedHash - Expected hash to verify against
|
|
500
|
+
* @returns true if hashes match, false otherwise
|
|
501
|
+
*/
|
|
502
|
+
declare const verifyPlanHash: (changes: readonly PfEffect[], expectedHash: string) => boolean;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Policy Module
|
|
506
|
+
*
|
|
507
|
+
* Manages policy versioning and review tokens for the MCP apply flow.
|
|
508
|
+
*
|
|
509
|
+
* Key Concepts:
|
|
510
|
+
* - POLICY_VERSION: Current version of apply policies (semantic versioning)
|
|
511
|
+
* - Review Token: Binds planHash + policyVersion for tamper-evident verification
|
|
512
|
+
*
|
|
513
|
+
* Flow:
|
|
514
|
+
* 1. generate_service → planHash
|
|
515
|
+
* 2. plan_review → reviewToken (planHash + policyVersion)
|
|
516
|
+
* 3. apply_changes → verify reviewToken OR skip if requireReview=false
|
|
517
|
+
*
|
|
518
|
+
* Upgrade Path:
|
|
519
|
+
* - Current: Simple concatenation (planHash.policyVersion)
|
|
520
|
+
* - Future: HMAC-based tokens for cryptographic binding (see docs)
|
|
521
|
+
*/
|
|
522
|
+
/**
|
|
523
|
+
* Current policy version
|
|
524
|
+
*
|
|
525
|
+
* Bump this when apply policies change (new validations, behavior changes).
|
|
526
|
+
* Format: YYYY-MM-DD (date-based versioning)
|
|
527
|
+
*
|
|
528
|
+
* History:
|
|
529
|
+
* - 2025-01-03: Initial policy version (M10)
|
|
530
|
+
*/
|
|
531
|
+
declare const POLICY_VERSION = "2025-01-03";
|
|
532
|
+
/**
|
|
533
|
+
* Review token format: `${planHash}.${policyVersion}`
|
|
534
|
+
*
|
|
535
|
+
* Simple format for initial implementation.
|
|
536
|
+
* Future: HMAC-based `${planHash}.${policyVersion}.${signature}`
|
|
537
|
+
*/
|
|
538
|
+
type ReviewToken = string;
|
|
539
|
+
/**
|
|
540
|
+
* Generate a review token from planHash and policyVersion
|
|
541
|
+
*
|
|
542
|
+
* @param planHash - SHA-256 hash of the plan (from computePlanHash)
|
|
543
|
+
* @param policyVersion - Policy version (defaults to POLICY_VERSION)
|
|
544
|
+
* @returns Review token in format `${planHash}.${policyVersion}`
|
|
545
|
+
*/
|
|
546
|
+
declare const generateReviewToken: (planHash: string, policyVersion?: string) => ReviewToken;
|
|
547
|
+
/**
|
|
548
|
+
* Parse a review token into its components
|
|
549
|
+
*
|
|
550
|
+
* @param token - Review token to parse
|
|
551
|
+
* @returns Parsed components or null if invalid format
|
|
552
|
+
*/
|
|
553
|
+
declare const parseReviewToken: (token: string) => {
|
|
554
|
+
planHash: string;
|
|
555
|
+
policyVersion: string;
|
|
556
|
+
} | null;
|
|
557
|
+
/**
|
|
558
|
+
* Validation result for review tokens
|
|
559
|
+
*/
|
|
560
|
+
interface ReviewTokenValidation {
|
|
561
|
+
valid: boolean;
|
|
562
|
+
code?: 'REVIEW_TOKEN_INVALID' | 'REVIEW_TOKEN_MISMATCH' | 'POLICY_VERSION_MISMATCH';
|
|
563
|
+
message?: string;
|
|
564
|
+
parsed?: {
|
|
565
|
+
planHash: string;
|
|
566
|
+
policyVersion: string;
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Validate a review token against expected planHash and policyVersion
|
|
571
|
+
*
|
|
572
|
+
* @param token - Review token to validate
|
|
573
|
+
* @param expectedPlanHash - Expected plan hash
|
|
574
|
+
* @param expectedPolicyVersion - Expected policy version (defaults to POLICY_VERSION)
|
|
575
|
+
* @returns Validation result with code and message if invalid
|
|
576
|
+
*/
|
|
577
|
+
declare const validateReviewToken: (token: string, expectedPlanHash: string, expectedPolicyVersion?: string) => ReviewTokenValidation;
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* MCP Resource Types
|
|
581
|
+
*
|
|
582
|
+
* Types for pf-mcp resources.
|
|
583
|
+
*
|
|
584
|
+
* @module resources/types
|
|
585
|
+
*/
|
|
586
|
+
/**
|
|
587
|
+
* MCP Resource definition (matches SDK's Resource type)
|
|
588
|
+
*/
|
|
589
|
+
interface McpResource {
|
|
590
|
+
/** Unique URI for the resource */
|
|
591
|
+
uri: string;
|
|
592
|
+
/** Human-readable name */
|
|
593
|
+
name: string;
|
|
594
|
+
/** Optional description */
|
|
595
|
+
description?: string;
|
|
596
|
+
/** MIME type of the resource content */
|
|
597
|
+
mimeType?: string;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Resource content returned by read
|
|
601
|
+
*/
|
|
602
|
+
interface McpResourceContent {
|
|
603
|
+
/** URI of the resource */
|
|
604
|
+
uri: string;
|
|
605
|
+
/** MIME type */
|
|
606
|
+
mimeType?: string;
|
|
607
|
+
/** Text content (for text resources) */
|
|
608
|
+
text?: string;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Resource reader function type
|
|
612
|
+
*/
|
|
613
|
+
type ResourceReader = (uri: string) => Promise<McpResourceContent>;
|
|
614
|
+
/**
|
|
615
|
+
* Resource definition with reader
|
|
616
|
+
*/
|
|
617
|
+
interface ResourceDefinition {
|
|
618
|
+
/** Static resource metadata */
|
|
619
|
+
resource: McpResource;
|
|
620
|
+
/** Function to read the resource content */
|
|
621
|
+
read: ResourceReader;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Generator Documentation Resources
|
|
626
|
+
*
|
|
627
|
+
* Exposes generator guidelines (service.md, etc.) as MCP resources
|
|
628
|
+
* for AI to read on-demand.
|
|
629
|
+
*
|
|
630
|
+
* @module resources/generator-docs
|
|
631
|
+
*/
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Create a resource for a specific generator doc
|
|
635
|
+
*/
|
|
636
|
+
declare const createGeneratorDocResource: (docName: string) => ResourceDefinition;
|
|
637
|
+
/**
|
|
638
|
+
* Create a discovery resource listing all available generator docs
|
|
639
|
+
*/
|
|
640
|
+
declare const createGeneratorDocsListResource: () => ResourceDefinition;
|
|
641
|
+
/**
|
|
642
|
+
* Create all generator doc resources (individual docs + list)
|
|
643
|
+
*/
|
|
644
|
+
declare const createAllGeneratorDocResources: () => Promise<ResourceDefinition[]>;
|
|
645
|
+
|
|
646
|
+
declare const readTemplateFile: (templateName: string, filePath: string) => Promise<string>;
|
|
647
|
+
declare const createTemplatesListResource: () => ResourceDefinition;
|
|
648
|
+
declare const createTemplateResource: (templateName: string) => ResourceDefinition;
|
|
649
|
+
declare const createTemplateFileResourceTemplate: () => {
|
|
650
|
+
uriTemplate: string;
|
|
651
|
+
name: string;
|
|
652
|
+
description: string;
|
|
653
|
+
mimeType: string;
|
|
654
|
+
};
|
|
655
|
+
declare const createAllTemplateResources: () => Promise<ResourceDefinition[]>;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* MCP Server Implementation
|
|
659
|
+
*
|
|
660
|
+
* Thin adapter between MCP SDK and Platform SDK facade.
|
|
661
|
+
* Uses execute() dispatch for tool calls (plan-only by default).
|
|
662
|
+
*
|
|
663
|
+
* Handles elicitation effects from tools:
|
|
664
|
+
* - Detects elicit:input effects in tool results
|
|
665
|
+
* - Returns structured error with missing fields (MCP elicitation not yet supported by VS Code)
|
|
666
|
+
* - Future: Use server.elicitInput() when client declares elicitation capability
|
|
667
|
+
*
|
|
668
|
+
* @module server
|
|
669
|
+
*/
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* MCP Server configuration
|
|
673
|
+
*/
|
|
674
|
+
interface McpServerOptions {
|
|
675
|
+
/** Server name (shown in MCP clients) */
|
|
676
|
+
name: string;
|
|
677
|
+
/** Server version */
|
|
678
|
+
version: string;
|
|
679
|
+
/** Workspace context */
|
|
680
|
+
workspace: PfWorkspaceContext;
|
|
681
|
+
/** Plugin modules to load */
|
|
682
|
+
plugins: string[];
|
|
683
|
+
/** Optional logger */
|
|
684
|
+
logger?: PfPluginContext['logger'];
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* MCP Server configuration with auto-discovery
|
|
688
|
+
*/
|
|
689
|
+
interface McpServerAutoOptions {
|
|
690
|
+
/** Server name (shown in MCP clients) */
|
|
691
|
+
name: string;
|
|
692
|
+
/** Server version */
|
|
693
|
+
version: string;
|
|
694
|
+
/** Optional workspace root (auto-discovered if omitted) */
|
|
695
|
+
workspaceRoot?: string;
|
|
696
|
+
/** Plugin modules to load */
|
|
697
|
+
plugins: string[];
|
|
698
|
+
/** Optional logger */
|
|
699
|
+
logger?: PfPluginContext['logger'];
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Create and start an MCP server
|
|
703
|
+
*
|
|
704
|
+
* Uses execute() dispatch for all tool calls.
|
|
705
|
+
* Built-in tools (services.generate) are always included.
|
|
706
|
+
* Plugin-based tools are loaded from specified modules.
|
|
707
|
+
*
|
|
708
|
+
* @param options - Server configuration
|
|
709
|
+
* @returns Promise that resolves when server is ready
|
|
710
|
+
*/
|
|
711
|
+
declare const createMcpServer: (options: McpServerOptions) => Promise<void>;
|
|
712
|
+
/**
|
|
713
|
+
* Create and start MCP server with auto-discovered workspace
|
|
714
|
+
*
|
|
715
|
+
* Automatically discovers workspace configuration from package.json and filesystem.
|
|
716
|
+
* This is the recommended way to start the server.
|
|
717
|
+
*
|
|
718
|
+
* @param options - Server options (workspace auto-discovered)
|
|
719
|
+
*/
|
|
720
|
+
declare const createMcpServerFromWorkspace: (options: McpServerAutoOptions) => Promise<void>;
|
|
721
|
+
|
|
722
|
+
export { AUDIT_DIR, type ApplyChangesInput, type AuditArtifact, type CachedPlan, type CachedReview, DEFAULT_DEPENDENCY_POLICY, type DependencyIntent, type DependencyPolicy, type DepsAddEffect, type EnvVarIntent, type FilePlanEntry, type GenerationPlanResult, type McpServerAutoOptions, type McpServerOptions, POLICY_VERSION, type PlanIssue, type PlanIssueSeverity, type PlanPreview, type PlanPreviewCounts, type ReviewToken, type ReviewTokenValidation, cachePlan, cacheReview, clearCache, computeContentHash, computePlanHash, createAllGeneratorDocResources, createAllTemplateResources, createAuditArtifact, createGeneratorDocResource, createGeneratorDocsListResource, createMcpServer, createMcpServerFromWorkspace, createTemplateFileResourceTemplate, createTemplateResource, createTemplatesListResource, generateAuditFilename, generateReviewToken, getCacheStats, getPlan, getReview, hasPlan, hasReview, isDependencyIntent, isDepsAddEffect, isFilePlanEntry, listPlanHashes, listReviewHashes, parseReviewToken, readTemplateFile, stableStringify, validateReviewToken, verifyPlanHash, writeAuditArtifact };
|