@milpa/comal 0.2.2 → 0.2.4
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 +1 -1
- package/backend/contracts/remote-commands-v1.json +0 -12
- package/backend/contracts/remote-device-v1.json +423 -0
- package/backend/contracts/remote-relay-answers-v1.json +209 -0
- package/package.json +4 -1
- package/skills/mv3/SKILL.md +44 -0
- package/skills/mv3/skill.json +4 -0
- package/src/agent.mjs +299 -32
- package/src/auto-guard.mjs +40 -3
- package/src/autocompact.mjs +233 -0
- package/src/bash-timeouts.mjs +29 -0
- package/src/child-env.mjs +23 -0
- package/src/cli.mjs +261 -62
- package/src/code-run-artifact.mjs +30 -0
- package/src/code-run-journal.mjs +135 -0
- package/src/code-run-session-proof.mjs +50 -0
- package/src/code-run-session.mjs +97 -0
- package/src/code-run-worker.mjs +20 -4
- package/src/code-run.mjs +49 -14
- package/src/codex-provider.mjs +4 -4
- package/src/compaction-notice.mjs +22 -0
- package/src/compaction.mjs +162 -23
- package/src/connection-settings.mjs +36 -4
- package/src/context-pressure.mjs +5 -4
- package/src/context.mjs +27 -22
- package/src/execution-metrics.mjs +36 -5
- package/src/file-recovery-proof.mjs +9 -1
- package/src/file-recovery.mjs +36 -3
- package/src/gemini-provider.mjs +5 -3
- package/src/git-integration-operations.mjs +2 -1
- package/src/git-plumbing.mjs +2 -1
- package/src/git-source.mjs +2 -1
- package/src/git-workspaces.mjs +2 -1
- package/src/house.mjs +13 -1
- package/src/i18n/cli-es.mjs +12 -1
- package/src/i18n/es.mjs +38 -1
- package/src/judges.mjs +2 -1
- package/src/mcp.mjs +2 -1
- package/src/model-controls.mjs +16 -2
- package/src/model-deadline.mjs +2 -2
- package/src/openai-provider.mjs +8 -4
- package/src/operations.mjs +17 -2
- package/src/package-identity.mjs +68 -0
- package/src/peer-probe.mjs +16 -0
- package/src/permissions.mjs +97 -4
- package/src/plugin-config.mjs +18 -1
- package/src/plugin-controls.mjs +31 -8
- package/src/plugin-trust.mjs +15 -6
- package/src/plugins/chrome-lab/bridge.mjs +19 -6
- package/src/plugins/chrome-lab/client.mjs +242 -12
- package/src/plugins/chrome-lab/index.mjs +106 -24
- package/src/plugins/chrome-lab/legacy-fill.mjs +25 -0
- package/src/plugins/chrome-lab/native-reply.mjs +31 -0
- package/src/plugins/open-relay/actions.mjs +60 -9
- package/src/plugins/open-relay/client.mjs +3 -3
- package/src/plugins/open-relay/decision.mjs +3 -2
- package/src/plugins/open-relay/index.mjs +17 -7
- package/src/plugins/open-relay/lookup.mjs +41 -4
- package/src/plugins/open-relay/notices.mjs +44 -3
- package/src/plugins/open-relay/panel.mjs +4 -1
- package/src/plugins/open-relay/watch.mjs +27 -8
- package/src/process-lock.mjs +20 -12
- package/src/provider-auth.mjs +6 -3
- package/src/provider-profiles.mjs +13 -3
- package/src/provider.mjs +175 -30
- package/src/qr-scan.mjs +240 -0
- package/src/read-only-check.mjs +6 -1
- package/src/relay/broker.mjs +173 -0
- package/src/relay/cards.mjs +702 -0
- package/src/relay/flow.mjs +886 -0
- package/src/relay/follow.mjs +119 -0
- package/src/relay/git.mjs +23 -0
- package/src/relay/hub-client.mjs +163 -0
- package/src/relay/state.mjs +55 -0
- package/src/remote-control.mjs +283 -15
- package/src/remote-device-card.mjs +111 -0
- package/src/remote-device.mjs +92 -0
- package/src/remote-permissions.mjs +159 -0
- package/src/remote-relay.mjs +468 -0
- package/src/remote-stats.mjs +205 -0
- package/src/session-bus.mjs +13 -3
- package/src/session-provider-settings.mjs +2 -2
- package/src/skill-runtime.mjs +8 -6
- package/src/source-ownership.mjs +3 -1
- package/src/tool-manifest.mjs +71 -0
- package/src/tool-packs.mjs +22 -6
- package/src/tool-schema.mjs +14 -2
- package/src/tools.mjs +96 -27
- package/src/tui/controller.mjs +4 -1
- package/src/tui/discovery.mjs +17 -7
- package/src/tui/inbound-blocks.mjs +5 -1
- package/src/tui/screen.mjs +53 -14
- package/src/tui/swarm-panel.mjs +19 -8
- package/src/turn-timing.mjs +82 -0
- package/src/usage-accounting.mjs +12 -1
- package/src/vision.mjs +6 -1
- package/src/visual/chrome.mjs +379 -0
- package/src/visual/fingerprint.mjs +30 -0
- package/src/visual/fixtures.mjs +201 -0
- package/src/visual/gate.mjs +92 -0
- package/src/visual/judge.mjs +114 -0
- package/src/visual/ledger.mjs +160 -0
- package/src/visual/measure.mjs +145 -0
- package/src/visual/names.mjs +7 -0
- package/src/visual/operations.mjs +211 -0
- package/src/visual/pixel-diff.mjs +96 -0
- package/src/visual/png.mjs +103 -0
- package/src/visual/registry.mjs +265 -0
- package/src/visual/report.mjs +64 -0
- package/src/visual/verify.mjs +292 -0
- package/src/work-assertions.mjs +15 -4
- package/src/work-plan.mjs +166 -30
- package/src/work-state.mjs +4 -4
- package/src/workflows/chrome-task-adoption.mjs +7 -3
- package/src/workspace-serve.mjs +59 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// House-managed static server for browser tests (chrome-devtools MCP, extension labs).
|
|
2
|
+
// It serves one workspace folder read-only on 127.0.0.1 and lives only as long as the
|
|
3
|
+
// Comal process: no background shell process to approve, track or leak.
|
|
4
|
+
import http from 'node:http';
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
import { confinedPath } from './visual/registry.mjs';
|
|
9
|
+
|
|
10
|
+
const TYPES = { '.html': 'text/html; charset=utf-8', '.htm': 'text/html; charset=utf-8', '.css': 'text/css; charset=utf-8', '.js': 'text/javascript; charset=utf-8',
|
|
11
|
+
'.mjs': 'text/javascript; charset=utf-8', '.json': 'application/json; charset=utf-8', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg',
|
|
12
|
+
'.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp', '.ico': 'image/x-icon', '.woff2': 'font/woff2', '.txt': 'text/plain; charset=utf-8' };
|
|
13
|
+
const MAX_SERVERS = 4;
|
|
14
|
+
const fail = message => Object.assign(new Error(message), { code: 'WORKSPACE_SERVE_INVALID' });
|
|
15
|
+
|
|
16
|
+
export function workspaceServeOperations({ cwd }) {
|
|
17
|
+
const servers = new Map();
|
|
18
|
+
async function start(directory) {
|
|
19
|
+
if (servers.size >= MAX_SERVERS) throw fail(`Ya hay ${MAX_SERVERS} servidores; detén uno con action stop.`);
|
|
20
|
+
const root = await confinedPath(cwd, directory, 'WorkspaceServe');
|
|
21
|
+
if (!(await fs.stat(root)).isDirectory()) throw fail(`WorkspaceServe: ${directory} no es una carpeta.`);
|
|
22
|
+
const server = http.createServer(async (request, response) => {
|
|
23
|
+
const reply = (status, body = '') => { response.writeHead(status, { 'content-type': 'text/plain; charset=utf-8', 'cache-control': 'no-store' }); response.end(body); };
|
|
24
|
+
if (!['GET', 'HEAD'].includes(request.method)) return reply(405, 'Solo lectura.');
|
|
25
|
+
try {
|
|
26
|
+
let relative = decodeURIComponent(new URL(request.url, 'http://127.0.0.1').pathname).replace(/^\/+/, '');
|
|
27
|
+
if (!relative || relative.endsWith('/')) relative += 'index.html';
|
|
28
|
+
// The real path must stay inside the served folder (no .., no symlink out, no protected state).
|
|
29
|
+
const file = await confinedPath(root, relative, 'archivo').catch(() => null);
|
|
30
|
+
if (!file || path.relative(root, file).startsWith('..') || !(await fs.stat(file)).isFile()) return reply(404, 'No existe.');
|
|
31
|
+
const body = await fs.readFile(file);
|
|
32
|
+
response.writeHead(200, { 'content-type': TYPES[path.extname(file).toLowerCase()] || 'application/octet-stream', 'content-length': body.length, 'cache-control': 'no-store' });
|
|
33
|
+
response.end(request.method === 'HEAD' ? undefined : body);
|
|
34
|
+
} catch { reply(404, 'No existe.'); }
|
|
35
|
+
});
|
|
36
|
+
await new Promise((resolve, reject) => { server.once('error', reject); server.listen(0, '127.0.0.1', resolve); });
|
|
37
|
+
server.unref(); // never keeps Comal alive; it closes with the process
|
|
38
|
+
const id = randomUUID(), entry = { server_id: id, directory: path.relative(await fs.realpath(cwd), root), url: `http://127.0.0.1:${server.address().port}/` };
|
|
39
|
+
servers.set(id, { ...entry, server });
|
|
40
|
+
return entry;
|
|
41
|
+
}
|
|
42
|
+
async function stop(id) {
|
|
43
|
+
const entry = servers.get(id); if (!entry) throw fail(`WorkspaceServe: no hay servidor con server_id ${id}.`);
|
|
44
|
+
servers.delete(id); entry.server.closeAllConnections?.();
|
|
45
|
+
await new Promise(resolve => entry.server.close(resolve));
|
|
46
|
+
return { stopped: true, server_id: id };
|
|
47
|
+
}
|
|
48
|
+
return [{
|
|
49
|
+
name: 'WorkspaceServe',
|
|
50
|
+
description: 'Serve one workspace folder read-only (GET/HEAD) on http://127.0.0.1:<port>/ for browser tests: pages a content script must match, fixtures for an extension lab suite, a page to open with chrome-devtools. Use it instead of starting a server with Bash. action start {directory} returns url and server_id; stop {server_id}; list. Servers close when the session process exits. Not the workspace root, never .comal/.harness/.git.',
|
|
51
|
+
effects: { workspace: 'read', external: 'none', process: 'none', authority: 'none' },
|
|
52
|
+
input_schema: { type: 'object', properties: { action: { enum: ['start', 'stop', 'list'] }, directory: { type: 'string', minLength: 1, maxLength: 500 }, server_id: { type: 'string', minLength: 1, maxLength: 64 } }, required: ['action'], additionalProperties: false },
|
|
53
|
+
run: async input => {
|
|
54
|
+
if (input.action === 'start') { if (!input.directory) throw fail('start requiere directory.'); return JSON.stringify(await start(input.directory)); }
|
|
55
|
+
if (input.action === 'stop') { if (!input.server_id) throw fail('stop requiere server_id.'); return JSON.stringify(await stop(input.server_id)); }
|
|
56
|
+
return JSON.stringify({ servers: [...servers.values()].map(({ server_id, directory, url }) => ({ server_id, directory, url })) });
|
|
57
|
+
},
|
|
58
|
+
}];
|
|
59
|
+
}
|