@devmarketplacenpm/devmp 0.1.1-beta.5
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 +208 -0
- package/bin/devmp.js +245 -0
- package/lib/api.js +231 -0
- package/lib/browser.js +21 -0
- package/lib/checkpoints.js +292 -0
- package/lib/command-runner.js +368 -0
- package/lib/commands.js +597 -0
- package/lib/completion.js +190 -0
- package/lib/config.js +172 -0
- package/lib/diff.js +216 -0
- package/lib/executor.js +208 -0
- package/lib/git.js +39 -0
- package/lib/instructions.js +69 -0
- package/lib/interactive-tunnel.js +420 -0
- package/lib/interactive.js +1269 -0
- package/lib/markdown.js +201 -0
- package/lib/mentions.js +68 -0
- package/lib/prompt.js +140 -0
- package/lib/routes.js +27 -0
- package/lib/session.js +107 -0
- package/lib/status.js +249 -0
- package/lib/tty/ansi.js +171 -0
- package/lib/tty/composer.js +680 -0
- package/lib/tty/screen.js +167 -0
- package/lib/ui.js +174 -0
- package/lib/version.js +134 -0
- package/lib/workspace.js +608 -0
- package/lib/ws-run.js +142 -0
- package/package.json +40 -0
package/lib/ws-run.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createExecutor } = require('./executor');
|
|
4
|
+
const { createCommandRunner } = require('./command-runner');
|
|
5
|
+
const { agentWsUrl: wsUrl } = require('./routes');
|
|
6
|
+
const { record: recordClientVersion } = require('./version');
|
|
7
|
+
const { readProjectInstructions } = require('./instructions');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Run the agent over the live WebSocket tunnel. The server drives; this client
|
|
11
|
+
* answers on-demand file ops against local disk (via the executor) and forwards
|
|
12
|
+
* text/done/error to `onEvent`. Resolves when the socket closes.
|
|
13
|
+
*/
|
|
14
|
+
async function runOverWs({ session, rootDir, prompt, provider, model, maxFiles, yes, allowCommands, onEvent }) {
|
|
15
|
+
// Read before the socket opens: the handshake carries them, and a run that
|
|
16
|
+
// ignored the project's own conventions would have to be corrected by hand.
|
|
17
|
+
const instructions = await readProjectInstructions(rootDir).catch(() => null);
|
|
18
|
+
if (instructions) {
|
|
19
|
+
onEvent({ type: 'instructions', source: instructions.source, truncated: instructions.truncated });
|
|
20
|
+
}
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const url = wsUrl(session.apiBaseUrl);
|
|
23
|
+
let ws;
|
|
24
|
+
try {
|
|
25
|
+
ws = new WebSocket(url);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
reject(new Error(`Could not open ${url}: ${error.message}`));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const executor = createExecutor({
|
|
32
|
+
rootDir,
|
|
33
|
+
yes,
|
|
34
|
+
onFile: (path, outcome) => onEvent({ type: 'file-local', path, outcome }),
|
|
35
|
+
});
|
|
36
|
+
const commandRunner = createCommandRunner({ rootDir, allowCommands });
|
|
37
|
+
|
|
38
|
+
let settled = false;
|
|
39
|
+
const done = (fn, arg) => {
|
|
40
|
+
if (settled) return;
|
|
41
|
+
settled = true;
|
|
42
|
+
process.off('SIGINT', onSigint);
|
|
43
|
+
fn(arg);
|
|
44
|
+
};
|
|
45
|
+
const onSigint = () => {
|
|
46
|
+
try {
|
|
47
|
+
ws.send(JSON.stringify({ type: 'cancel' }));
|
|
48
|
+
} catch {
|
|
49
|
+
/* socket already gone */
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
process.on('SIGINT', onSigint);
|
|
53
|
+
|
|
54
|
+
ws.onopen = () => {
|
|
55
|
+
ws.send(
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
type: 'start',
|
|
58
|
+
token: session.accessToken,
|
|
59
|
+
prompt,
|
|
60
|
+
...(provider ? { provider } : {}),
|
|
61
|
+
...(model ? { model } : {}),
|
|
62
|
+
...(maxFiles ? { maxFiles } : {}),
|
|
63
|
+
...(instructions
|
|
64
|
+
? {
|
|
65
|
+
instructions: instructions.text,
|
|
66
|
+
instructionsSource: instructions.source,
|
|
67
|
+
}
|
|
68
|
+
: {}),
|
|
69
|
+
}),
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
ws.onmessage = async (event) => {
|
|
74
|
+
let msg;
|
|
75
|
+
try {
|
|
76
|
+
const raw =
|
|
77
|
+
typeof event.data === 'string' ? event.data : event.data.toString();
|
|
78
|
+
msg = JSON.parse(raw);
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Additive and transport-agnostic: whichever frame the server chooses
|
|
84
|
+
// to carry version info on, the client picks it up.
|
|
85
|
+
recordClientVersion(msg.client);
|
|
86
|
+
|
|
87
|
+
if (msg.type === 'fs') {
|
|
88
|
+
try {
|
|
89
|
+
const payload = await executor.handle(msg.op, msg.args || {});
|
|
90
|
+
ws.send(JSON.stringify({ type: 'fsResult', id: msg.id, ok: true, ...payload }));
|
|
91
|
+
} catch (error) {
|
|
92
|
+
ws.send(
|
|
93
|
+
JSON.stringify({
|
|
94
|
+
type: 'fsResult',
|
|
95
|
+
id: msg.id,
|
|
96
|
+
ok: false,
|
|
97
|
+
message: error.message,
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (msg.type === 'cmd') {
|
|
105
|
+
try {
|
|
106
|
+
const payload = await commandRunner.handle(
|
|
107
|
+
String(msg.command || ''),
|
|
108
|
+
msg.id,
|
|
109
|
+
);
|
|
110
|
+
ws.send(JSON.stringify({ type: 'cmdResult', id: msg.id, ok: true, ...payload }));
|
|
111
|
+
} catch (error) {
|
|
112
|
+
ws.send(
|
|
113
|
+
JSON.stringify({
|
|
114
|
+
type: 'cmdResult',
|
|
115
|
+
id: msg.id,
|
|
116
|
+
ok: false,
|
|
117
|
+
message: error.message,
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (msg.type === 'cmdCancel') {
|
|
125
|
+
commandRunner.cancel(msg.id);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
onEvent(msg); // text | done | error
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
ws.onerror = (event) => {
|
|
133
|
+
const message =
|
|
134
|
+
(event && (event.message || (event.error && event.error.message))) ||
|
|
135
|
+
'connection failed';
|
|
136
|
+
done(reject, new Error(`Could not reach the agent tunnel at ${url} (${message}).`));
|
|
137
|
+
};
|
|
138
|
+
ws.onclose = () => done(resolve);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = { runOverWs };
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devmarketplacenpm/devmp",
|
|
3
|
+
"version": "0.1.1-beta.5",
|
|
4
|
+
"description": "DevMarketplace CLI — a terminal coding agent. The agent runs on the server; the files land on your machine.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"coding-agent",
|
|
8
|
+
"ai",
|
|
9
|
+
"terminal",
|
|
10
|
+
"devmarketplace"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/gentez/devmarketplace-cli#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/gentez/devmarketplace-cli/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/gentez/devmarketplace-cli.git"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"devmp": "bin/devmp.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin",
|
|
25
|
+
"lib",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"type": "commonjs",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"devmp": "node bin/devmp.js",
|
|
34
|
+
"test": "node --test test/*.test.js"
|
|
35
|
+
},
|
|
36
|
+
"license": "UNLICENSED",
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
}
|
|
40
|
+
}
|