@enfyra/mcp-server 0.2.51 → 0.2.52
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 +4 -1
- package/dist/lib/config-local-adapters.d.ts +11 -1
- package/dist/lib/config-local-adapters.js +5 -3
- package/dist/lib/config-local-adapters.js.map +1 -1
- package/dist/lib/config-local-types.d.ts +1 -0
- package/dist/lib/config-local.js +2 -2
- package/dist/lib/config-local.js.map +1 -1
- package/dist/lib/enfyra-mcp-server.js +3 -0
- package/dist/lib/enfyra-mcp-server.js.map +1 -1
- package/dist/lib/mcp-instructions.js +1 -0
- package/dist/lib/mcp-instructions.js.map +1 -1
- package/dist/lib/required-knowledge.js +11 -0
- package/dist/lib/required-knowledge.js.map +1 -1
- package/dist/lib/script-workspace.d.ts +2 -0
- package/dist/lib/script-workspace.js +116 -0
- package/dist/lib/script-workspace.js.map +1 -0
- package/dist/lib/source-artifacts.d.ts +1 -0
- package/dist/lib/source-artifacts.js +24 -9
- package/dist/lib/source-artifacts.js.map +1 -1
- package/dist/lib/tool-catalog.d.ts +1 -1
- package/dist/lib/tool-catalog.js +8 -27
- package/dist/lib/tool-catalog.js.map +1 -1
- package/dist/lib/tool-contracts.js +3 -0
- package/dist/lib/tool-contracts.js.map +1 -1
- package/dist/lib/tool-execution.d.ts +2 -0
- package/dist/lib/tool-execution.js +30 -0
- package/dist/lib/tool-execution.js.map +1 -0
- package/dist/lib/tool-output-contracts.js +2 -0
- package/dist/lib/tool-output-contracts.js.map +1 -1
- package/dist/lib/toolset-filter.d.ts +1 -1
- package/dist/lib/toolset-filter.js +4 -0
- package/dist/lib/toolset-filter.js.map +1 -1
- package/dist/lib/types.d.ts +1 -0
- package/dist/lib/workflow-definitions.d.ts +21 -1
- package/dist/lib/workflow-definitions.js +21 -4
- package/dist/lib/workflow-definitions.js.map +1 -1
- package/dist/lib/workflow-planner.js +9 -0
- package/dist/lib/workflow-planner.js.map +1 -1
- package/dist/lib/workflow-types.d.ts +1 -1
- package/dist/lib/workspace-files.d.ts +9 -0
- package/dist/lib/workspace-files.js +160 -0
- package/dist/lib/workspace-files.js.map +1 -0
- package/dist/lib/workspace-push.d.ts +44 -0
- package/dist/lib/workspace-push.js +79 -0
- package/dist/lib/workspace-push.js.map +1 -0
- package/dist/lib/workspace-remote.d.ts +3 -0
- package/dist/lib/workspace-remote.js +52 -0
- package/dist/lib/workspace-remote.js.map +1 -0
- package/dist/lib/workspace-state.d.ts +35 -0
- package/dist/lib/workspace-state.js +89 -0
- package/dist/lib/workspace-state.js.map +1 -0
- package/dist/lib/workspace-tools.d.ts +2 -0
- package/dist/lib/workspace-tools.js +40 -0
- package/dist/lib/workspace-tools.js.map +1 -0
- package/dist/lib/workspace-types.d.ts +83 -0
- package/dist/lib/workspace-types.js +2 -0
- package/dist/lib/workspace-types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { constants, lstatSync, mkdirSync, openSync, closeSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
5
|
+
export function sourceHash(source) {
|
|
6
|
+
return createHash('sha256').update(source, 'utf8').digest('hex');
|
|
7
|
+
}
|
|
8
|
+
export function workspaceTarget(value) {
|
|
9
|
+
const url = new URL(value);
|
|
10
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
11
|
+
throw new Error('Workspace target must be an HTTP API URL without credentials, query or fragment.');
|
|
12
|
+
return url.href.replace(/\/$/, '');
|
|
13
|
+
}
|
|
14
|
+
export function safeWorkspacePath(root, name) {
|
|
15
|
+
try {
|
|
16
|
+
if (lstatSync(root).isSymbolicLink())
|
|
17
|
+
throw new Error(`Workspace symlink is not allowed: ${root}`);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error.code !== 'ENOENT')
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
if (!name || isAbsolute(name) || name.includes('\\') || name.split('/').some((part) => part === '..' || part === '.' || !part))
|
|
24
|
+
throw new Error('Workspace path must be a relative path without traversal.');
|
|
25
|
+
const target = resolve(root, name);
|
|
26
|
+
if (!target.startsWith(`${root}${sep}`))
|
|
27
|
+
throw new Error('Workspace path is outside the project.');
|
|
28
|
+
let current = root;
|
|
29
|
+
for (const part of relative(root, target).split(sep)) {
|
|
30
|
+
current = join(current, part);
|
|
31
|
+
try {
|
|
32
|
+
const stat = lstatSync(current);
|
|
33
|
+
if (stat.isSymbolicLink())
|
|
34
|
+
throw new Error(`Workspace symlink is not allowed: ${current}`);
|
|
35
|
+
if (current !== target && !stat.isDirectory())
|
|
36
|
+
throw new Error(`Workspace parent is not a directory: ${current}`);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error.code !== 'ENOENT')
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return target;
|
|
44
|
+
}
|
|
45
|
+
export function readWorkspaceFile(root, name) {
|
|
46
|
+
const file = safeWorkspacePath(root, name);
|
|
47
|
+
let fd;
|
|
48
|
+
try {
|
|
49
|
+
fd = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error.code === 'ENOENT')
|
|
53
|
+
return null;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return readFileSync(fd, 'utf8');
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
closeSync(fd);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function writeWorkspaceFile(root, name, content, expected) {
|
|
64
|
+
const file = safeWorkspacePath(root, name);
|
|
65
|
+
mkdirSync(dirname(file), { recursive: true, mode: 0o700 });
|
|
66
|
+
safeWorkspacePath(root, name);
|
|
67
|
+
if (expected !== undefined && readWorkspaceFile(root, name) !== expected)
|
|
68
|
+
throw new Error(`Local file changed while synchronizing: ${name}`);
|
|
69
|
+
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
70
|
+
let mode = 0o600;
|
|
71
|
+
try {
|
|
72
|
+
mode = lstatSync(file).mode & 0o777;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error.code !== 'ENOENT')
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
const fd = openSync(temporary, 'wx', mode);
|
|
79
|
+
try {
|
|
80
|
+
writeFileSync(fd, content);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
safeWorkspacePath(root, name);
|
|
87
|
+
if (expected !== undefined && readWorkspaceFile(root, name) !== expected)
|
|
88
|
+
throw new Error(`Local file changed while synchronizing: ${name}`);
|
|
89
|
+
renameSync(temporary, file);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
rmSync(temporary, { force: true });
|
|
93
|
+
}
|
|
94
|
+
return file;
|
|
95
|
+
}
|
|
96
|
+
export function workspacePaths(projectRoot, target) {
|
|
97
|
+
if (!isAbsolute(projectRoot))
|
|
98
|
+
throw new Error('projectRoot must be an absolute project directory.');
|
|
99
|
+
const root = realpathSync(projectRoot);
|
|
100
|
+
if (!lstatSync(root).isDirectory())
|
|
101
|
+
throw new Error('projectRoot must be a directory.');
|
|
102
|
+
return {
|
|
103
|
+
projectRoot: root,
|
|
104
|
+
workspaceRoot: safeWorkspacePath(root, 'enfyra'),
|
|
105
|
+
tempRoot: safeWorkspacePath(root, `.tmp/enfyra/${sourceHash(target).slice(0, 16)}/${process.pid}`),
|
|
106
|
+
target,
|
|
107
|
+
manifestPath: 'enfyra/.state/sync.json',
|
|
108
|
+
planPath: 'enfyra/.state/push-plan.json',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export function ensureWorkspaceIgnored(paths) {
|
|
112
|
+
const root = paths.projectRoot;
|
|
113
|
+
const patterns = ['/enfyra/', '/.tmp/enfyra/'];
|
|
114
|
+
let isRepository = false;
|
|
115
|
+
try {
|
|
116
|
+
execFileSync('git', ['-C', root, 'rev-parse', '--show-toplevel'], { stdio: 'pipe' });
|
|
117
|
+
isRepository = true;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (!error.stderr?.toString().includes('not a git repository'))
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
if (isRepository) {
|
|
124
|
+
const tracked = execFileSync('git', ['-C', root, 'ls-files', '--', 'enfyra', '.tmp/enfyra'], { encoding: 'utf8' });
|
|
125
|
+
if (tracked.trim())
|
|
126
|
+
throw new Error('Workspace paths are already tracked by Git. Untrack them explicitly before preparing the workspace.');
|
|
127
|
+
}
|
|
128
|
+
const original = readWorkspaceFile(root, '.gitignore');
|
|
129
|
+
const lines = (original ?? '').split(/\r?\n/);
|
|
130
|
+
const missing = patterns.filter((pattern) => !lines.includes(pattern));
|
|
131
|
+
if (missing.length)
|
|
132
|
+
writeWorkspaceFile(root, '.gitignore', `${original ?? ''}${original && !original.endsWith('\n') ? '\n' : ''}${missing.join('\n')}\n`, original);
|
|
133
|
+
if (isRepository) {
|
|
134
|
+
for (const path of ['enfyra/project.json', '.tmp/enfyra/source.js'])
|
|
135
|
+
execFileSync('git', ['-C', root, 'check-ignore', '-q', '--', path], { stdio: 'pipe' });
|
|
136
|
+
}
|
|
137
|
+
return isRepository;
|
|
138
|
+
}
|
|
139
|
+
export async function withWorkspaceLock(paths, run) {
|
|
140
|
+
const lock = safeWorkspacePath(paths.projectRoot, 'enfyra/.state/workspace.lock');
|
|
141
|
+
mkdirSync(dirname(lock), { recursive: true, mode: 0o700 });
|
|
142
|
+
let fd;
|
|
143
|
+
try {
|
|
144
|
+
fd = openSync(lock, 'wx', 0o600);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (error.code === 'EEXIST')
|
|
148
|
+
throw new Error('Workspace is locked by another operation. Retry when it finishes; inspect an abandoned lock before removing it.');
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
writeFileSync(fd, JSON.stringify({ pid: process.pid }));
|
|
152
|
+
try {
|
|
153
|
+
return await run();
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
closeSync(fd);
|
|
157
|
+
rmSync(lock, { force: true });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=workspace-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-files.js","sourceRoot":"","sources":["../../src/lib/workspace-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { WorkspaceDependencies, WorkspaceManifest, WorkspacePaths, WorkspacePushInput } from './workspace-types.js';
|
|
2
|
+
export declare function pushWorkspace(paths: WorkspacePaths, manifest: WorkspaceManifest, dependencies: WorkspaceDependencies, input: WorkspacePushInput): Promise<{
|
|
3
|
+
action: string;
|
|
4
|
+
complete: boolean;
|
|
5
|
+
artifacts: {
|
|
6
|
+
key: string;
|
|
7
|
+
status: import("./workspace-types.js").WorkspaceSourceStatus;
|
|
8
|
+
language: string;
|
|
9
|
+
sourceField: string;
|
|
10
|
+
localFile: string;
|
|
11
|
+
remoteFile: string;
|
|
12
|
+
localHash: string;
|
|
13
|
+
remoteHash: string;
|
|
14
|
+
baselineHash: string;
|
|
15
|
+
}[];
|
|
16
|
+
guidance: string;
|
|
17
|
+
planId?: undefined;
|
|
18
|
+
protection?: undefined;
|
|
19
|
+
remainingKeys?: undefined;
|
|
20
|
+
} | {
|
|
21
|
+
action: string;
|
|
22
|
+
complete: boolean;
|
|
23
|
+
planId: string;
|
|
24
|
+
artifacts: any[];
|
|
25
|
+
protection: string;
|
|
26
|
+
guidance: string;
|
|
27
|
+
remainingKeys?: undefined;
|
|
28
|
+
} | {
|
|
29
|
+
action: string;
|
|
30
|
+
complete: boolean;
|
|
31
|
+
artifacts: Record<string, unknown>[];
|
|
32
|
+
remainingKeys: string[];
|
|
33
|
+
guidance: string;
|
|
34
|
+
planId?: undefined;
|
|
35
|
+
protection?: undefined;
|
|
36
|
+
} | {
|
|
37
|
+
action: string;
|
|
38
|
+
complete: boolean;
|
|
39
|
+
artifacts: Record<string, unknown>[];
|
|
40
|
+
guidance?: undefined;
|
|
41
|
+
planId?: undefined;
|
|
42
|
+
protection?: undefined;
|
|
43
|
+
remainingKeys?: undefined;
|
|
44
|
+
}>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { writeSourceArtifact } from './source-artifacts.js';
|
|
4
|
+
import { sourceHash, readWorkspaceFile, writeWorkspaceFile } from './workspace-files.js';
|
|
5
|
+
import { observeArtifact, observationSummary, saveWorkspace, selectArtifacts } from './workspace-state.js';
|
|
6
|
+
const planSchema = z.object({ id: z.string().uuid(), target: z.string(), projectRoot: z.string(), consumed: z.boolean(), items: z.array(z.object({ key: z.string(), localRevision: z.string(), remoteRevision: z.string(), sourceHash: z.string() }).strict()).max(500) }).strict();
|
|
7
|
+
function savePlan(paths, plan) {
|
|
8
|
+
writeWorkspaceFile(paths.projectRoot, paths.planPath, `${JSON.stringify(plan, null, 2)}\n`);
|
|
9
|
+
}
|
|
10
|
+
function diffArtifact(observation) {
|
|
11
|
+
const remote = (observation.remote?.source ?? '').split('\n');
|
|
12
|
+
const local = (observation.localSource ?? '').split('\n');
|
|
13
|
+
const diff = [`--- live/${observation.artifact.path}`, `+++ local/${observation.artifact.path}`, `@@ -1,${remote.length} +1,${local.length} @@`, ...remote.map((line) => `-${line}`), ...local.map((line) => `+${line}`)].join('\n');
|
|
14
|
+
return writeSourceArtifact({ tableName: observation.artifact.tableName, id: observation.artifact.id, fieldName: 'diff', source: diff });
|
|
15
|
+
}
|
|
16
|
+
export async function pushWorkspace(paths, manifest, dependencies, input) {
|
|
17
|
+
if (!input.apply) {
|
|
18
|
+
if (input.planId)
|
|
19
|
+
throw new Error('planId is only accepted when apply=true.');
|
|
20
|
+
const observations = [];
|
|
21
|
+
for (const artifact of selectArtifacts(manifest, input.keys))
|
|
22
|
+
observations.push(await observeArtifact(paths, artifact, dependencies));
|
|
23
|
+
const blocked = observations.filter((item) => !['synced', 'local_changed'].includes(item.status));
|
|
24
|
+
if (blocked.length)
|
|
25
|
+
return { action: 'enfyra_workspace_push_blocked', complete: false, artifacts: observations.map(observationSummary), guidance: 'Pull remote-only or aligned changes first; resolve conflicts without overwriting local edits.' };
|
|
26
|
+
const changes = observations.filter((item) => item.status === 'local_changed');
|
|
27
|
+
const artifacts = [];
|
|
28
|
+
for (const change of changes) {
|
|
29
|
+
const sourceArtifact = writeSourceArtifact({ tableName: change.artifact.tableName, id: change.artifact.id, fieldName: change.artifact.sourceField, source: change.localSource });
|
|
30
|
+
await dependencies.validate(change.artifact, change.localSource);
|
|
31
|
+
artifacts.push({ ...observationSummary(change), sourceFile: sourceArtifact.tmpFile, diff: diffArtifact(change) });
|
|
32
|
+
}
|
|
33
|
+
const plan = { id: randomUUID(), target: paths.target, projectRoot: paths.projectRoot, consumed: false, items: changes.map((item) => ({ key: item.artifact.key, localRevision: item.localRevision, remoteRevision: item.remoteRevision, sourceHash: sourceHash(item.localSource) })) };
|
|
34
|
+
savePlan(paths, plan);
|
|
35
|
+
return { action: 'enfyra_workspace_push_previewed', complete: changes.length === 0, planId: plan.id, artifacts, protection: 'optimistic-source-check', guidance: 'Review the diffs, then call push_enfyra_sources with apply=true and this planId. External writers are not locked; each write rechecks and verifies the live source.' };
|
|
36
|
+
}
|
|
37
|
+
if (!input.planId)
|
|
38
|
+
throw new Error('A reviewed planId is required when apply=true.');
|
|
39
|
+
if (input.keys)
|
|
40
|
+
throw new Error('Apply uses the reviewed plan scope; omit keys.');
|
|
41
|
+
const raw = readWorkspaceFile(paths.projectRoot, paths.planPath);
|
|
42
|
+
const plan = raw ? planSchema.parse(JSON.parse(raw)) : null;
|
|
43
|
+
if (!plan || plan.id !== input.planId || plan.consumed || plan.target !== paths.target || plan.projectRoot !== paths.projectRoot)
|
|
44
|
+
throw new Error('Push plan is missing, consumed, stale or belongs to another target. Preview again.');
|
|
45
|
+
const changes = [];
|
|
46
|
+
for (const item of plan.items) {
|
|
47
|
+
const artifact = selectArtifacts(manifest, [item.key])[0];
|
|
48
|
+
const observation = await observeArtifact(paths, artifact, dependencies);
|
|
49
|
+
if (observation.status !== 'local_changed' || observation.localRevision !== item.localRevision || observation.remoteRevision !== item.remoteRevision || sourceHash(observation.localSource) !== item.sourceHash)
|
|
50
|
+
throw new Error(`Source changed after preview: ${item.key}. Inspect and preview again.`);
|
|
51
|
+
await dependencies.validate(artifact, observation.localSource);
|
|
52
|
+
changes.push(observation);
|
|
53
|
+
}
|
|
54
|
+
plan.consumed = true;
|
|
55
|
+
savePlan(paths, plan);
|
|
56
|
+
const results = [];
|
|
57
|
+
for (const change of changes) {
|
|
58
|
+
try {
|
|
59
|
+
const current = await observeArtifact(paths, change.artifact, dependencies);
|
|
60
|
+
if (current.localRevision !== change.localRevision || current.remoteRevision !== change.remoteRevision)
|
|
61
|
+
throw new Error('Source changed before write; preview again.');
|
|
62
|
+
const source = current.localSource;
|
|
63
|
+
const staged = writeSourceArtifact({ tableName: current.artifact.tableName, id: current.artifact.id, fieldName: current.artifact.sourceField, source });
|
|
64
|
+
await dependencies.write(current.artifact, source, sourceHash(current.remote.source), staged.tmpFile);
|
|
65
|
+
const saved = await observeArtifact(paths, current.artifact, dependencies);
|
|
66
|
+
if (saved.remoteRevision !== current.localRevision)
|
|
67
|
+
throw new Error('Saved source does not match the reviewed source. Inspect live state before retrying.');
|
|
68
|
+
current.artifact.baseline = saved.remoteRevision;
|
|
69
|
+
saveWorkspace(paths, manifest);
|
|
70
|
+
results.push({ key: current.artifact.key, status: 'pushed', sourceSha256: sourceHash(source), verified: true, localChangedDuringPush: saved.localRevision !== current.localRevision });
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
results.push({ key: change.artifact.key, status: 'failed', error: error instanceof Error ? error.message : String(error) });
|
|
74
|
+
return { action: 'enfyra_workspace_push_incomplete', complete: false, artifacts: results, remainingKeys: changes.slice(results.length).map((item) => item.artifact.key), guidance: 'Some writes may have completed. Inspect live state and create a fresh preview before retrying.' };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { action: 'enfyra_workspace_pushed', complete: true, artifacts: results };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=workspace-push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-push.js","sourceRoot":"","sources":["../../src/lib/workspace-push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ToolsetRegistrationState } from './types.js';
|
|
2
|
+
import type { WorkspaceDependencies } from './workspace-types.js';
|
|
3
|
+
export declare function createWorkspaceRemote(apiUrl: string, state: ToolsetRegistrationState): Pick<WorkspaceDependencies, 'read' | 'validate' | 'write'>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { fetchAPI } from './fetch.js';
|
|
2
|
+
import { fetchTableMetadata } from './metadata-client.js';
|
|
3
|
+
import { validateDynamicScript, validateExtensionCode } from './platform-extension-source.js';
|
|
4
|
+
import { assertDynamicCodeKnowledgeAck, assertExtensionKnowledgeAck, assertGlobalRulesAck } from './required-knowledge.js';
|
|
5
|
+
import { executeToolDefinition } from './tool-execution.js';
|
|
6
|
+
import { resolveCatalogToolAvailability } from './tool-permission-profile.js';
|
|
7
|
+
import { getPrimaryFieldName } from './tool-record-operations.js';
|
|
8
|
+
export function createWorkspaceRemote(apiUrl, state) {
|
|
9
|
+
return {
|
|
10
|
+
read: async (artifact) => {
|
|
11
|
+
const table = await fetchTableMetadata(apiUrl, artifact.tableName);
|
|
12
|
+
const columns = (table.columns ?? []);
|
|
13
|
+
const primaryKey = await getPrimaryFieldName(artifact.tableName, table);
|
|
14
|
+
const sourceField = artifact.tableName === 'enfyra_extension' ? 'code' : 'sourceCode';
|
|
15
|
+
if (!columns.some((column) => column.name === sourceField))
|
|
16
|
+
throw new Error(`${artifact.tableName} does not expose an editable ${sourceField} field.`);
|
|
17
|
+
const languageField = ['scriptLanguage', 'language'].find((name) => columns.some((column) => column.name === name));
|
|
18
|
+
const fields = [primaryKey, sourceField, ...(languageField ? [languageField] : [])];
|
|
19
|
+
const query = new URLSearchParams({ filter: JSON.stringify({ [primaryKey]: { _eq: artifact.id } }), limit: '1', fields: fields.join(',') });
|
|
20
|
+
const result = await fetchAPI(apiUrl, `/${artifact.tableName}?${query}`);
|
|
21
|
+
const record = Array.isArray(result?.data) ? result.data[0] : Array.isArray(result) ? result[0] : null;
|
|
22
|
+
if (!record)
|
|
23
|
+
return null;
|
|
24
|
+
if (String(record[primaryKey]) !== artifact.id || typeof record[sourceField] !== 'string')
|
|
25
|
+
throw new Error('Workspace source response did not match the requested artifact or expose readable source.');
|
|
26
|
+
return { source: record[sourceField], sourceField, language: languageField ? String(record[languageField] ?? 'javascript') : 'javascript' };
|
|
27
|
+
},
|
|
28
|
+
validate: async (artifact, source) => {
|
|
29
|
+
assertGlobalRulesAck(undefined);
|
|
30
|
+
if (artifact.tableName === 'enfyra_extension') {
|
|
31
|
+
assertExtensionKnowledgeAck(undefined);
|
|
32
|
+
return validateExtensionCode(apiUrl, source, artifact.id);
|
|
33
|
+
}
|
|
34
|
+
assertDynamicCodeKnowledgeAck(undefined);
|
|
35
|
+
return validateDynamicScript(apiUrl, source, artifact.language);
|
|
36
|
+
},
|
|
37
|
+
write: async (artifact, _source, expectedHash, sourceFile) => {
|
|
38
|
+
const name = artifact.tableName === 'enfyra_extension' ? 'update_extension_code' : 'update_script_source';
|
|
39
|
+
const tool = state.getTool(name);
|
|
40
|
+
if (!tool)
|
|
41
|
+
throw new Error(`Workspace writer is not registered: ${name}`);
|
|
42
|
+
const args = artifact.tableName === 'enfyra_extension'
|
|
43
|
+
? { id: artifact.id, sourceFile, expectedSha256: expectedHash }
|
|
44
|
+
: { tableName: artifact.tableName, id: artifact.id, sourceFile, expectedSourceSha256: expectedHash, scriptLanguage: artifact.language };
|
|
45
|
+
const result = await executeToolDefinition(tool, args, undefined, resolveCatalogToolAvailability);
|
|
46
|
+
if (result?.isError)
|
|
47
|
+
throw new Error(result.content?.find((item) => item.type === 'text')?.text ?? `${name} failed.`);
|
|
48
|
+
return result;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=workspace-remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-remote.js","sourceRoot":"","sources":["../../src/lib/workspace-remote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { WorkspaceArtifact, WorkspaceArtifactRef, WorkspaceDependencies, WorkspaceManifest, WorkspaceObservation, WorkspacePaths, WorkspaceRemoteSource, WorkspaceSourceStatus } from './workspace-types.js';
|
|
3
|
+
export declare const WORKSPACE_TABLES: readonly ["enfyra_route_handler", "enfyra_pre_hook", "enfyra_post_hook", "enfyra_flow_step", "enfyra_websocket_event", "enfyra_websocket", "enfyra_oauth_config", "enfyra_bootstrap_script", "enfyra_extension"];
|
|
4
|
+
export declare const workspaceArtifactSchema: z.ZodObject<{
|
|
5
|
+
tableName: z.ZodEnum<["enfyra_route_handler", "enfyra_pre_hook", "enfyra_post_hook", "enfyra_flow_step", "enfyra_websocket_event", "enfyra_websocket", "enfyra_oauth_config", "enfyra_bootstrap_script", "enfyra_extension"]>;
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
path: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, "strict", z.ZodTypeAny, {
|
|
9
|
+
path?: string;
|
|
10
|
+
tableName?: "enfyra_extension" | "enfyra_route_handler" | "enfyra_pre_hook" | "enfyra_post_hook" | "enfyra_flow_step" | "enfyra_websocket_event" | "enfyra_websocket" | "enfyra_oauth_config" | "enfyra_bootstrap_script";
|
|
11
|
+
id?: string;
|
|
12
|
+
}, {
|
|
13
|
+
path?: string;
|
|
14
|
+
tableName?: "enfyra_extension" | "enfyra_route_handler" | "enfyra_pre_hook" | "enfyra_post_hook" | "enfyra_flow_step" | "enfyra_websocket_event" | "enfyra_websocket" | "enfyra_oauth_config" | "enfyra_bootstrap_script";
|
|
15
|
+
id?: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare function sourceRevision(remote: WorkspaceRemoteSource): string;
|
|
18
|
+
export declare function artifactKey(ref: WorkspaceArtifactRef): string;
|
|
19
|
+
export declare function artifactPath(ref: WorkspaceArtifactRef, source: WorkspaceRemoteSource): string;
|
|
20
|
+
export declare function loadWorkspace(paths: WorkspacePaths): WorkspaceManifest;
|
|
21
|
+
export declare function saveWorkspace(paths: WorkspacePaths, manifest: WorkspaceManifest): void;
|
|
22
|
+
export declare function selectArtifacts(manifest: WorkspaceManifest, keys?: string[]): WorkspaceArtifact[];
|
|
23
|
+
export declare function observeArtifact(paths: WorkspacePaths, artifact: WorkspaceArtifact, dependencies: WorkspaceDependencies): Promise<WorkspaceObservation>;
|
|
24
|
+
export declare function observationSummary(observation: WorkspaceObservation): {
|
|
25
|
+
key: string;
|
|
26
|
+
status: WorkspaceSourceStatus;
|
|
27
|
+
language: string;
|
|
28
|
+
sourceField: string;
|
|
29
|
+
localFile: string;
|
|
30
|
+
remoteFile: string;
|
|
31
|
+
localHash: string;
|
|
32
|
+
remoteHash: string;
|
|
33
|
+
baselineHash: string;
|
|
34
|
+
};
|
|
35
|
+
export declare function updateFromRemote(paths: WorkspacePaths, observation: WorkspaceObservation): void;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { relative } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { readWorkspaceFile, safeWorkspacePath, sourceHash, writeWorkspaceFile } from './workspace-files.js';
|
|
4
|
+
import { writeSourceArtifact } from './source-artifacts.js';
|
|
5
|
+
export const WORKSPACE_TABLES = ['enfyra_route_handler', 'enfyra_pre_hook', 'enfyra_post_hook', 'enfyra_flow_step', 'enfyra_websocket_event', 'enfyra_websocket', 'enfyra_oauth_config', 'enfyra_bootstrap_script', 'enfyra_extension'];
|
|
6
|
+
export const workspaceArtifactSchema = z.object({ tableName: z.enum(WORKSPACE_TABLES), id: z.string().min(1).max(200), path: z.string().optional() }).strict();
|
|
7
|
+
const savedArtifactSchema = workspaceArtifactSchema.extend({ key: z.string(), path: z.string(), sourceField: z.string(), language: z.string(), baseline: z.string() });
|
|
8
|
+
const manifestSchema = z.object({ target: z.string(), artifacts: z.array(savedArtifactSchema).max(500) }).strict();
|
|
9
|
+
export function sourceRevision(remote) {
|
|
10
|
+
return sourceHash(JSON.stringify([remote.source, remote.sourceField, remote.language]));
|
|
11
|
+
}
|
|
12
|
+
export function artifactKey(ref) {
|
|
13
|
+
return `${ref.tableName}:${ref.id}`;
|
|
14
|
+
}
|
|
15
|
+
export function artifactPath(ref, source) {
|
|
16
|
+
const kind = ref.tableName.replace(/^enfyra_/, '').replace(/_/g, '-');
|
|
17
|
+
const id = ref.id.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 60);
|
|
18
|
+
const extension = source.sourceField === 'code' ? 'vue' : source.language === 'typescript' ? 'ts' : 'js';
|
|
19
|
+
const path = ref.path ?? `${kind}/${id}-${sourceHash(ref.id).slice(0, 8)}.${extension}`;
|
|
20
|
+
if (path.startsWith('.') || path === 'project.json' || path.split('/').some((part) => part.startsWith('.')))
|
|
21
|
+
throw new Error('Artifact path cannot use workspace configuration or state directories.');
|
|
22
|
+
return path;
|
|
23
|
+
}
|
|
24
|
+
export function loadWorkspace(paths) {
|
|
25
|
+
const raw = readWorkspaceFile(paths.projectRoot, paths.manifestPath);
|
|
26
|
+
if (!raw)
|
|
27
|
+
throw new Error('Workspace is not prepared. Call prepare_enfyra_workspace with projectRoot and exact artifact references.');
|
|
28
|
+
const manifest = manifestSchema.parse(JSON.parse(raw));
|
|
29
|
+
if (manifest.target !== paths.target)
|
|
30
|
+
throw new Error('Workspace target differs from the connected Enfyra instance. Use a separate project workspace.');
|
|
31
|
+
const keys = new Set();
|
|
32
|
+
const files = new Set();
|
|
33
|
+
for (const artifact of manifest.artifacts) {
|
|
34
|
+
if (artifact.key !== artifactKey(artifact) || keys.has(artifact.key) || files.has(artifact.path))
|
|
35
|
+
throw new Error('Workspace manifest has invalid or duplicate artifact mappings.');
|
|
36
|
+
artifactPath(artifact, { source: '', sourceField: artifact.sourceField, language: artifact.language });
|
|
37
|
+
safeWorkspacePath(paths.workspaceRoot, artifact.path);
|
|
38
|
+
keys.add(artifact.key);
|
|
39
|
+
files.add(artifact.path);
|
|
40
|
+
}
|
|
41
|
+
return manifest;
|
|
42
|
+
}
|
|
43
|
+
export function saveWorkspace(paths, manifest) {
|
|
44
|
+
writeWorkspaceFile(paths.projectRoot, paths.manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
45
|
+
}
|
|
46
|
+
export function selectArtifacts(manifest, keys) {
|
|
47
|
+
if (!keys)
|
|
48
|
+
return manifest.artifacts;
|
|
49
|
+
if (!keys.length || new Set(keys).size !== keys.length)
|
|
50
|
+
throw new Error('Select a non-empty list of unique artifact keys.');
|
|
51
|
+
return keys.map((key) => {
|
|
52
|
+
const artifact = manifest.artifacts.find((item) => item.key === key);
|
|
53
|
+
if (!artifact)
|
|
54
|
+
throw new Error(`Artifact is not in this workspace: ${key}`);
|
|
55
|
+
return artifact;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export async function observeArtifact(paths, artifact, dependencies) {
|
|
59
|
+
const localFile = safeWorkspacePath(paths.workspaceRoot, artifact.path);
|
|
60
|
+
const localSource = readWorkspaceFile(paths.workspaceRoot, artifact.path);
|
|
61
|
+
const remote = await dependencies.read(artifact);
|
|
62
|
+
const remoteRevision = remote ? sourceRevision(remote) : null;
|
|
63
|
+
const localRevision = localSource === null ? null : sourceRevision({ source: localSource, sourceField: artifact.sourceField, language: artifact.language });
|
|
64
|
+
let status;
|
|
65
|
+
if (!remote)
|
|
66
|
+
status = 'remote_missing';
|
|
67
|
+
else if (localSource === null)
|
|
68
|
+
status = 'local_missing';
|
|
69
|
+
else if (localRevision === remoteRevision)
|
|
70
|
+
status = remoteRevision === artifact.baseline ? 'synced' : 'aligned';
|
|
71
|
+
else if (localRevision === artifact.baseline)
|
|
72
|
+
status = 'remote_changed';
|
|
73
|
+
else if (remoteRevision === artifact.baseline)
|
|
74
|
+
status = 'local_changed';
|
|
75
|
+
else
|
|
76
|
+
status = 'conflict';
|
|
77
|
+
const remoteFile = remote ? writeSourceArtifact({ tableName: artifact.tableName, id: artifact.id, fieldName: remote.sourceField, source: remote.source }).tmpFile : null;
|
|
78
|
+
return { artifact, localSource, remote, localRevision, remoteRevision, status, localFile, remoteFile };
|
|
79
|
+
}
|
|
80
|
+
export function observationSummary(observation) {
|
|
81
|
+
return { key: observation.artifact.key, status: observation.status, language: observation.artifact.language, sourceField: observation.artifact.sourceField, localFile: observation.localFile, remoteFile: observation.remoteFile, localHash: observation.localRevision, remoteHash: observation.remoteRevision, baselineHash: observation.artifact.baseline };
|
|
82
|
+
}
|
|
83
|
+
export function updateFromRemote(paths, observation) {
|
|
84
|
+
if (!observation.remote)
|
|
85
|
+
throw new Error('Cannot pull a deleted remote artifact.');
|
|
86
|
+
writeWorkspaceFile(paths.projectRoot, relative(paths.projectRoot, observation.localFile), observation.remote.source, observation.localSource);
|
|
87
|
+
Object.assign(observation.artifact, { baseline: observation.remoteRevision, language: observation.remote.language, sourceField: observation.remote.sourceField });
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=workspace-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-state.js","sourceRoot":"","sources":["../../src/lib/workspace-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { createScriptWorkspace } from './script-workspace.js';
|
|
4
|
+
import { createWorkspaceRemote } from './workspace-remote.js';
|
|
5
|
+
import { workspaceArtifactSchema } from './workspace-state.js';
|
|
6
|
+
import { jsonContent } from './response-format.js';
|
|
7
|
+
export function registerWorkspaceTools(server, state, apiUrl, projectRoot) {
|
|
8
|
+
const workspace = createScriptWorkspace({
|
|
9
|
+
apiUrl,
|
|
10
|
+
projectRoot,
|
|
11
|
+
roots: async () => {
|
|
12
|
+
if (!server.server.getClientCapabilities()?.roots)
|
|
13
|
+
return [];
|
|
14
|
+
const result = await server.server.listRoots();
|
|
15
|
+
return result.roots.map((root) => fileURLToPath(root.uri));
|
|
16
|
+
},
|
|
17
|
+
...createWorkspaceRemote(apiUrl, state),
|
|
18
|
+
});
|
|
19
|
+
const scope = {
|
|
20
|
+
projectRoot: z.string().optional().describe('Absolute client project directory. Defaults to the selected workspace, configured ENFYRA_MCP_PROJECT_ROOT or one client-provided root; never guesses cwd.'),
|
|
21
|
+
keys: z.array(z.string()).min(1).max(100).optional().describe('Exact workspace artifact keys. Omit to select the prepared inventory.'),
|
|
22
|
+
};
|
|
23
|
+
server.tool('prepare_enfyra_workspace', 'Prepare an ignored project-local enfyra/ source worktree. Adds /enfyra/ and /.tmp/enfyra/ to Git ignore before any source write. Bootstrap with explicit artifact references from discovery; existing workspaces preserve local edits and target binding. Does not create a Git branch or clone the whole instance.', {
|
|
24
|
+
...scope,
|
|
25
|
+
artifacts: z.array(workspaceArtifactSchema).max(100).optional().describe('Located live records to add. Optional path is relative to enfyra/. Required for a new workspace; use [] before creating new source, or omit to reopen.'),
|
|
26
|
+
}, async (input) => jsonContent(await workspace.prepare(input), { columnar: false }));
|
|
27
|
+
server.tool('inspect_enfyra_workspace', 'Inspect local, last-synced and freshly read live source hashes. Returns synced/local_changed/remote_changed/conflict or missing states, local file paths and project-local .tmp snapshots. Does not overwrite working sources.', scope, async (input) => jsonContent(await workspace.inspect(input), { columnar: false }));
|
|
28
|
+
server.tool('pull_enfyra_sources', 'Refresh missing or unchanged local workspace files from live source. Keeps local edits, conflicts and remotely deleted files intact; never infers server deletion from local deletion. Use inspect_enfyra_workspace to review returned states.', scope, async (input) => jsonContent(await workspace.pull(input), { columnar: false }));
|
|
29
|
+
server.tool('push_enfyra_sources', 'Preview and validate edited workspace sources, then apply the reviewed planId. Requires target confirmation and domain knowledge. Rechecks local/live hashes, uses canonical source writers and verifies each saved source. The plan is consumed before writes; partial failure requires fresh inspection and preview. External writers are not atomically locked.', {
|
|
30
|
+
...scope,
|
|
31
|
+
apply: z.boolean().optional().default(false),
|
|
32
|
+
planId: z.string().uuid().optional().describe('Required with apply=true; use the current reviewed preview plan and omit keys.'),
|
|
33
|
+
}, async (input) => {
|
|
34
|
+
const result = await workspace.push(input);
|
|
35
|
+
const content = jsonContent(result, { columnar: false });
|
|
36
|
+
return input.apply && !result.complete ? { ...content, isError: true } : content;
|
|
37
|
+
});
|
|
38
|
+
return workspace;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=workspace-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-tools.js","sourceRoot":"","sources":["../../src/lib/workspace-tools.ts"],"names":[],"mappings":"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"}
|