dev-flow-deepseek 0.1.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/proxy.js DELETED
@@ -1,87 +0,0 @@
1
- #!/usr/bin/env node
2
- import { APPROVED_RAW_TOOLS, MAX_ADAPTER_DIAGNOSTIC_BYTES, PACKAGE_NAME, PACKAGE_VERSION, STARTUP_EXIT_CODE } from "./compatibility.js";
3
- import { BackendClient, BackendStartupError } from "./backend-client.js";
4
- import { readBackendConfiguration } from "./environment.js";
5
- import { createAdapterErrorResult, projectBackendResult } from "./result-envelope.js";
6
- import process from "node:process";
7
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
10
-
11
- //#region src/proxy.ts
12
- function isApprovedTool(name) {
13
- return APPROVED_RAW_TOOLS.includes(name);
14
- }
15
- function startupDiagnostic(code) {
16
- const text = `dsh-dev-flow projection proxy startup failed (${code}).`;
17
- if (Buffer.byteLength(text, "utf8") > 4096) return "dsh-dev-flow projection proxy startup failed.";
18
- return text;
19
- }
20
- async function startProxy() {
21
- let backend;
22
- try {
23
- backend = await BackendClient.connect(readBackendConfiguration());
24
- } catch (error) {
25
- const code = error instanceof BackendStartupError ? error.code : "BACKEND_START_FAILED";
26
- process.stderr.write(`${startupDiagnostic(code)}\n`);
27
- process.exitCode = 2;
28
- return;
29
- }
30
- const server = new Server({
31
- name: PACKAGE_NAME,
32
- version: PACKAGE_VERSION
33
- }, { capabilities: { tools: {} } });
34
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [...backend.tools] }));
35
- server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
36
- const name = request.params.name;
37
- if (!isApprovedTool(name)) throw new TypeError("Requested tool is not exposed by this proxy.");
38
- let upstream;
39
- try {
40
- upstream = await backend.call(name, request.params.arguments ?? {}, extra.signal);
41
- } catch {
42
- const code = extra.signal.aborted ? "REQUEST_CANCELLED" : "UPSTREAM_CALL_FAILED";
43
- return createAdapterErrorResult(name, code);
44
- }
45
- try {
46
- return projectBackendResult(name, upstream);
47
- } catch {
48
- return createAdapterErrorResult(name, "UPSTREAM_RESULT_INVALID");
49
- }
50
- });
51
- const outwardTransport = new StdioServerTransport();
52
- let shuttingDown = false;
53
- const shutdown = async (exitCode) => {
54
- if (shuttingDown) return;
55
- shuttingDown = true;
56
- if (exitCode !== 0) process.exitCode = exitCode;
57
- await Promise.allSettled([server.close(), backend.close()]);
58
- };
59
- process.once("SIGINT", () => {
60
- shutdown(0);
61
- });
62
- process.once("SIGTERM", () => {
63
- shutdown(0);
64
- });
65
- backend.closed.then(() => {
66
- if (!shuttingDown) shutdown(1);
67
- });
68
- try {
69
- await server.connect(outwardTransport);
70
- } catch {
71
- process.stderr.write(`${startupDiagnostic("BACKEND_INITIALIZE_FAILED")}\n`);
72
- await shutdown(2);
73
- return;
74
- }
75
- const protocolClose = outwardTransport.onclose;
76
- outwardTransport.onclose = () => {
77
- protocolClose?.();
78
- if (!shuttingDown) shutdown(0);
79
- };
80
- }
81
- startProxy().catch(() => {
82
- process.stderr.write(`${startupDiagnostic("BACKEND_INITIALIZE_FAILED")}\n`);
83
- process.exitCode = 2;
84
- });
85
-
86
- //#endregion
87
- export { };
@@ -1,105 +0,0 @@
1
- import { ADAPTER_ERROR_CODES, ADAPTER_ERROR_SCHEMA, APPROVED_RAW_TOOLS, DEV_FLOW_RESULT_SCHEMA, MAX_ADAPTER_DIAGNOSTIC_BYTES } from "./compatibility.js";
2
- import { canonicalJson } from "./canonical-json.js";
3
-
4
- //#region src/result-envelope.ts
5
- const REQUEST_ID_PATTERN = /^mcp-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
6
- const ADAPTER_MESSAGES = Object.freeze({
7
- BACKEND_START_FAILED: "The Dev Flow backend could not be started.",
8
- BACKEND_INITIALIZE_FAILED: "The Dev Flow backend could not be initialized.",
9
- BACKEND_CATALOG_INVALID: "The Dev Flow backend tool catalog is invalid.",
10
- UPSTREAM_CALL_FAILED: "The Dev Flow backend call did not return a valid result.",
11
- UPSTREAM_RESULT_INVALID: "The Dev Flow backend returned an invalid result.",
12
- REQUEST_CANCELLED: "The Dev Flow backend call was cancelled before a valid result was received."
13
- });
14
- function isPlainObject(value) {
15
- if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
16
- const prototype = Object.getPrototypeOf(value);
17
- return prototype === Object.prototype || prototype === null;
18
- }
19
- function hasExactKeys(value, expected) {
20
- const actual = Object.keys(value).sort();
21
- const sortedExpected = [...expected].sort();
22
- return actual.length === sortedExpected.length && actual.every((key, index) => key === sortedExpected[index]);
23
- }
24
- function invalid(reason) {
25
- throw new TypeError(`Invalid Dev Flow result envelope: ${reason}.`);
26
- }
27
- function validateDevFlowEnvelope(value, invokedTool) {
28
- if (!APPROVED_RAW_TOOLS.includes(invokedTool)) invalid("invoked tool is not approved");
29
- if (!isPlainObject(value)) invalid("structuredContent is not a plain object");
30
- if (!hasExactKeys(value, [
31
- "schema",
32
- "ok",
33
- "tool",
34
- "request_id",
35
- "result",
36
- "error"
37
- ])) invalid("top-level fields do not match the closed envelope");
38
- if (value.schema !== "dev-flow-mcp-result/1.0.0") invalid("schema identity does not match");
39
- if (value.tool !== invokedTool) invalid("tool identity does not match the invoked tool");
40
- if (typeof value.request_id !== "string" || !REQUEST_ID_PATTERN.test(value.request_id)) invalid("request_id does not match the pinned grammar");
41
- if (typeof value.ok !== "boolean") invalid("ok is not boolean");
42
- if (value.ok) {
43
- if (value.error !== null) invalid("successful envelope error is not null");
44
- } else {
45
- if (value.result !== null) invalid("error envelope result is not null");
46
- if (!isPlainObject(value.error)) invalid("error is not a plain object");
47
- if (!hasExactKeys(value.error, [
48
- "code",
49
- "message",
50
- "details",
51
- "recovery"
52
- ])) invalid("error fields do not match the closed union");
53
- if (typeof value.error.code !== "string" || value.error.code.length === 0) invalid("error code is not a non-empty string");
54
- if (typeof value.error.message !== "string" || value.error.message.length === 0) invalid("error message is not a non-empty string");
55
- if (!isPlainObject(value.error.details)) invalid("error details is not a plain object");
56
- if (value.error.recovery !== null && !isPlainObject(value.error.recovery)) invalid("error recovery is neither a plain object nor null");
57
- }
58
- canonicalJson(value);
59
- return value;
60
- }
61
- function projectBackendResult(invokedTool, upstream) {
62
- const envelope = validateDevFlowEnvelope(upstream.structuredContent, invokedTool);
63
- return {
64
- ...upstream,
65
- content: [{
66
- type: "text",
67
- text: canonicalJson(envelope)
68
- }]
69
- };
70
- }
71
- function recoveryFor(tool) {
72
- if (tool === "dev_flow_start_task") return Object.freeze(["dev_flow_find_tasks_for_path"]);
73
- if (tool === "dev_flow_apply_action") return Object.freeze(["dev_flow_get_task", "dev_flow_get_next_action"]);
74
- return Object.freeze([tool]);
75
- }
76
- function createAdapterErrorEnvelope(tool, code) {
77
- if (!APPROVED_RAW_TOOLS.includes(tool)) throw new TypeError("Adapter error tool is not approved.");
78
- if (!ADAPTER_ERROR_CODES.includes(code)) throw new TypeError("Adapter error code is not approved.");
79
- const message = ADAPTER_MESSAGES[code];
80
- if (Buffer.byteLength(message, "utf8") > 4096) throw new TypeError("Adapter diagnostic exceeds its fixed byte limit.");
81
- return Object.freeze({
82
- schema: ADAPTER_ERROR_SCHEMA,
83
- ok: false,
84
- tool,
85
- error: Object.freeze({
86
- code,
87
- message,
88
- mutation_uncertain: tool === "dev_flow_start_task" || tool === "dev_flow_apply_action",
89
- recovery: recoveryFor(tool)
90
- })
91
- });
92
- }
93
- function createAdapterErrorResult(tool, code) {
94
- const envelope = createAdapterErrorEnvelope(tool, code);
95
- return {
96
- content: [{
97
- type: "text",
98
- text: canonicalJson(envelope)
99
- }],
100
- isError: true
101
- };
102
- }
103
-
104
- //#endregion
105
- export { createAdapterErrorEnvelope, createAdapterErrorResult, projectBackendResult, validateDevFlowEnvelope };
@@ -1,89 +0,0 @@
1
- # Activation and routing
2
-
3
- These rules refine explicit `/dev-flow` task selection and recovery. They do
4
- not define Controller actions, payload schemas, transitions, or terminal
5
- criteria.
6
-
7
- ## Complete-result rule
8
-
9
- Treat tool text as authority only when it is the complete canonical JSON
10
- result. If any result mentions `spill`, `truncated`, `pruned`, `preview`, or
11
- `Full formatted result stored at`, use a normal DSH file-reading tool to read
12
- the complete saved text before parsing it. If the complete text cannot be
13
- read, stop. Never infer an action, binding, payload schema, repository set,
14
- recovery operation, or terminal result from a preview.
15
-
16
- ## Select or start
17
-
18
- 1. Call `mcp__dev-flow__dev_flow_find_tasks_for_path` with the exact current
19
- canonical Git root. Inventory must be authoritative; stop if it is
20
- unavailable or inconsistent.
21
- 2. Discovery does not prove complete repository membership. For every
22
- candidate that might be selected, call
23
- `mcp__dev-flow__dev_flow_get_next_action` and use its fresh authority.
24
- 3. Canonicalize every returned `repository_set.repositories[].path`. A
25
- candidate is compatible only when its workflow is exactly `lite`, its
26
- repository array has cardinality one, and that one canonical path equals
27
- the current root. Reject subsets, supersets, different members,
28
- multi-repository tasks, unrelated paths, and non-`lite` workflows.
29
- 4. Resume one compatible active task when the result is unambiguous. If more
30
- than one is compatible, present their bounded identities and ask the user
31
- to choose; never select by recency. If discovery returns only incompatible
32
- tasks, report the conflict and ask the user to resolve it outside this MVP.
33
- 5. When authoritative discovery returns no candidate and the request is
34
- substantive, call `mcp__dev-flow__dev_flow_start_task` with only the user
35
- requirement, workflow `lite`, and a one-element repositories array holding
36
- the current root. Omit custom task ID and contract fields.
37
-
38
- Never merge candidates, convert workflows, cancel tasks, revise contracts, or
39
- use an unexposed inventory or governance operation.
40
-
41
- ## Drive current authority
42
-
43
- For each nonterminal result:
44
-
45
- 1. Reconfirm exact one-root repository equality.
46
- 2. Read the fresh action ID, objective, guidance, allowed effects, required
47
- evidence, closed payload schema, and complete binding.
48
- 3. Perform only that action in the current repository with normal DSH tools.
49
- 4. Build a payload containing exactly the schema-declared fields.
50
- 5. Call `mcp__dev-flow__dev_flow_apply_action` with the exact task ID, action
51
- ID, payload, and unmodified current binding.
52
- 6. Continue only from the fresh action returned by a successful mutation or a
53
- new `mcp__dev-flow__dev_flow_get_next_action` read. Never reuse an old
54
- binding.
55
-
56
- When the Controller returns a terminal result, report its Delivery Dossier.
57
- Do not announce completion before that authority exists.
58
-
59
- ## Errors and mutation uncertainty
60
-
61
- A valid `dev-flow-mcp-result/1.0.0` envelope with `ok: false` remains a
62
- Controller domain error. Follow its recovery only when the named operation is
63
- one of the six exposed tools. If it requires a hidden governance,
64
- cancellation, finding, listing, or contract operation, report that the task is
65
- outside this MVP and stop.
66
-
67
- An adapter envelope with schema `dsh-dev-flow-proxy-error/1.0.0` is not a
68
- Controller result. For a failed read, wait until the six-tool surface is
69
- healthy and repeat that read at most once. Never reinterpret an adapter error
70
- as task state.
71
-
72
- If `mcp__dev-flow__dev_flow_start_task` loses or corrupts its response, assume
73
- neither success nor failure. Rediscover tasks for the current root and inspect
74
- fresh compatible authority before considering another start. Do not create a
75
- replacement for a task that may already exist.
76
-
77
- If `mcp__dev-flow__dev_flow_apply_action` loses or corrupts its response,
78
- assume neither success nor failure. First call
79
- `mcp__dev-flow__dev_flow_get_task`, then
80
- `mcp__dev-flow__dev_flow_get_next_action`, and compare the fresh revision,
81
- action, and binding. Retry only when that authority proves the mutation did not
82
- commit and the current binding still authorizes it. Never blindly replay a
83
- mutation.
84
-
85
- ## Repository and product boundary
86
-
87
- Keep the repository set fixed at the one current user-prepared worktree. Do not
88
- manage Git topology or publishing. Do not install a runtime, add a UI, expose
89
- another MCP tool, use remote transport, or store adapter-owned task state.