conductor-remote 1.57.4 → 1.58.1
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 +5 -5
- package/dist/assets/{index-CoOO4JDW.css → index-DT9enoqA.css} +1 -1
- package/dist/assets/{index-CSWnlNUe.js → index-DTYIH7h9.js} +30 -30
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-node/src/conductor.applescript +1 -1
- package/dist-node/src/firstprompt.js +14 -14
- package/dist-node/src/mcp-tools.js +16 -5
- package/dist-node/src/notify.js +1 -1
- package/dist-node/src/reads.js +11 -1
- package/dist-node/src/server.js +25 -9
- package/dist-node/src/writes.js +6 -5
- package/package.json +9 -20
package/dist/index.html
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<title>Conductor Remote</title>
|
|
14
14
|
<!-- Runs before the module bundle so it can catch a stale shell that fails to boot. -->
|
|
15
15
|
<script src="/self-heal.js"></script>
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-DTYIH7h9.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DT9enoqA.css">
|
|
18
18
|
<link rel="manifest" href="/manifest.webmanifest"></head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
package/dist/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let l={};const t=e=>i(e,o),c={module:{uri:o},exports:l,require:t};s[o]=Promise.all(n.map(e=>c[e]||t(e))).then(e=>(r(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";importScripts("/push-sw.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"self-heal.js",revision:"49bd63adb25a09341f8d2610e8bd3c76"},{url:"push-sw.js",revision:"e1e682e2e5e88fa03b7808ae9db8e098"},{url:"index.html",revision:"
|
|
1
|
+
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let l={};const t=e=>i(e,o),c={module:{uri:o},exports:l,require:t};s[o]=Promise.all(n.map(e=>c[e]||t(e))).then(e=>(r(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";importScripts("/push-sw.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"self-heal.js",revision:"49bd63adb25a09341f8d2610e8bd3c76"},{url:"push-sw.js",revision:"e1e682e2e5e88fa03b7808ae9db8e098"},{url:"index.html",revision:"65eae6f412bc584ef0604735364c56f5"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-DTYIH7h9.js",revision:null},{url:"assets/index-DT9enoqA.css",revision:null},{url:"apple-touch-icon.png",revision:"2b9301416b880d45d4bb655f2600d1f2"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]}))});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
handlers to run and hands the result to `osascript`. It lives in its own file
|
|
6
6
|
rather than a TypeScript template literal for three reasons: an editor can
|
|
7
7
|
highlight it, `yarn verify` can compile-check it (scripts/check-applescript.ts,
|
|
8
|
-
|
|
8
|
+
the repository validator for this language), and a backtick in a comment
|
|
9
9
|
no longer terminates the string it used to sit inside — so this sentence,
|
|
10
10
|
which contains `one`, is now harmless.
|
|
11
11
|
|
|
@@ -89,13 +89,13 @@ export class FirstPromptQueue {
|
|
|
89
89
|
* prompt lands (`null`) or is given up on (the failed entry) — awaited by API
|
|
90
90
|
* callers that asked to block, ignored by the phone.
|
|
91
91
|
*/
|
|
92
|
-
enqueue(workspaceId, text, sendImmediately = true, attachmentIds = [],
|
|
92
|
+
enqueue(workspaceId, text, sendImmediately = true, attachmentIds = [], agent) {
|
|
93
93
|
this.entries = [
|
|
94
94
|
...this.entries.filter(e => e.workspaceId !== workspaceId),
|
|
95
95
|
{
|
|
96
96
|
workspaceId,
|
|
97
97
|
text,
|
|
98
|
-
...(
|
|
98
|
+
...(agent && Object.keys(agent).length ? { agent } : {}),
|
|
99
99
|
...(attachmentIds.length ? { attachmentIds } : {}),
|
|
100
100
|
status: 'waiting',
|
|
101
101
|
attempts: 0,
|
|
@@ -187,7 +187,7 @@ export class FirstPromptQueue {
|
|
|
187
187
|
return;
|
|
188
188
|
// It already went — the user sent it from the Mac, where the deep link left it
|
|
189
189
|
// pre-filled in the composer. Sending again would double it, and changing the
|
|
190
|
-
//
|
|
190
|
+
// agent now would affect a later turn instead of the first one they configured.
|
|
191
191
|
if (target.alreadySent)
|
|
192
192
|
return this.delivered(entry);
|
|
193
193
|
// Before `ready`, a send is worth trying and not worth judging: Conductor may not
|
|
@@ -211,8 +211,9 @@ export class FirstPromptQueue {
|
|
|
211
211
|
else
|
|
212
212
|
entry.attempts += 1;
|
|
213
213
|
this.save();
|
|
214
|
-
const
|
|
215
|
-
|
|
214
|
+
const agent = entry.agent ?? (entry.model ? { model: entry.model } : undefined);
|
|
215
|
+
const result = agent
|
|
216
|
+
? await this.setAgent(entry, target.sessionId, agent)
|
|
216
217
|
: entry.text.trim()
|
|
217
218
|
? await this.deps.send(entry.workspaceId, target.sessionId, entry.text)
|
|
218
219
|
: { ok: true };
|
|
@@ -242,18 +243,17 @@ export class FirstPromptQueue {
|
|
|
242
243
|
this.save();
|
|
243
244
|
}
|
|
244
245
|
/**
|
|
245
|
-
* Keep
|
|
246
|
-
* change is persisted before the send starts, so a
|
|
247
|
-
*
|
|
246
|
+
* Keep agent choices in the same attempt as the prompt. A successful settings
|
|
247
|
+
* change is persisted before the send starts, so a retry cannot toggle controls
|
|
248
|
+
* back and forth. A workspace with no prompt settles after this step.
|
|
248
249
|
*/
|
|
249
|
-
async
|
|
250
|
-
if (!
|
|
251
|
-
return { ok:
|
|
252
|
-
|
|
253
|
-
return { ok: false, error: 'the relay cannot set a model for a new workspace' };
|
|
254
|
-
const result = await this.deps.setModel(entry.workspaceId, sessionId, entry.model);
|
|
250
|
+
async setAgent(entry, sessionId, agent) {
|
|
251
|
+
if (!this.deps.setAgent)
|
|
252
|
+
return { ok: false, error: 'the relay cannot configure a new workspace’s agent' };
|
|
253
|
+
const result = await this.deps.setAgent(entry.workspaceId, sessionId, agent);
|
|
255
254
|
if (!result.ok)
|
|
256
255
|
return result;
|
|
256
|
+
entry.agent = undefined;
|
|
257
257
|
entry.model = undefined;
|
|
258
258
|
this.save();
|
|
259
259
|
return entry.text.trim() ? this.deps.send(entry.workspaceId, sessionId, entry.text) : { ok: true };
|
|
@@ -31,7 +31,7 @@ import { HIT_CLOSE, HIT_OPEN, workspaceTitle } from "./shared.js";
|
|
|
31
31
|
/** Versions we know how to speak. The client's choice wins when we know it. */
|
|
32
32
|
export const PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'];
|
|
33
33
|
export const SERVER_INFO = { name: 'conductor-remote', version: '1' };
|
|
34
|
-
export const INSTRUCTIONS = 'Drives local Conductor agents through the conductor-remote relay. search_chats and read_chat reach archived workspaces, which is where most finished work lives. create_workspace opens its workspace link without direct UI control;
|
|
34
|
+
export const INSTRUCTIONS = 'Drives local Conductor agents through the conductor-remote relay. search_chats and read_chat reach archived workspaces, which is where most finished work lives. create_workspace opens its workspace link without direct UI control; requested agent settings and the first prompt are applied later through Conductor’s UI. dismiss_prompt, keep_awake and relay_logs touch no UI. send_prompt, split_chat, stop_turn, set_agent_options, a live list_models call and set_workspace_status drive the real Mac UI and steal focus for a few seconds — confirm with the user before using them on a chat they did not name.';
|
|
35
35
|
/** Reads are quick; a UI write is measured in tens of seconds (writes.ts ▸ SEND_ATTEMPT_MS). */
|
|
36
36
|
export const READ_TIMEOUT_MS = 10_000;
|
|
37
37
|
export const WRITE_TIMEOUT_MS = 75_000;
|
|
@@ -331,7 +331,7 @@ export function createTools(call) {
|
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
name: 'create_workspace',
|
|
334
|
-
description: 'Start a new Conductor workspace in a repo, optionally with a first prompt and
|
|
334
|
+
description: 'Start a new Conductor workspace in a repo, optionally with a first prompt and agent settings. The workspace starts from a Conductor deep link, so creation itself needs no Accessibility. The relay applies requested model, effort, plan, and fast settings through Conductor’s UI after it creates the first chat and before it delivers the prompt. Returns as soon as the workspace row exists (~2s), before the worktree is built.',
|
|
335
335
|
inputSchema: {
|
|
336
336
|
type: 'object',
|
|
337
337
|
properties: {
|
|
@@ -341,6 +341,13 @@ export function createTools(call) {
|
|
|
341
341
|
type: 'string',
|
|
342
342
|
description: 'Picker label from list_models with no session_id. The relay applies it before the first prompt, or configures an empty workspace once its chat exists.'
|
|
343
343
|
},
|
|
344
|
+
effort: {
|
|
345
|
+
type: 'string',
|
|
346
|
+
enum: ['low', 'medium', 'high', 'xhigh', 'max', 'ultracode'],
|
|
347
|
+
description: 'Reasoning effort applied before the first prompt.'
|
|
348
|
+
},
|
|
349
|
+
plan: { type: 'boolean', description: 'Start the first chat in Conductor’s Plan mode.' },
|
|
350
|
+
fast: { type: 'boolean', description: 'Set Fast mode before the first prompt.' },
|
|
344
351
|
wait_for_send: {
|
|
345
352
|
type: 'boolean',
|
|
346
353
|
description: 'Block until the first prompt is actually delivered (tens of seconds, and longer behind other queued sends). Default false.'
|
|
@@ -356,12 +363,16 @@ export function createTools(call) {
|
|
|
356
363
|
const repo = need(args, 'repo');
|
|
357
364
|
const prompt = str(args.prompt);
|
|
358
365
|
const model = str(args.model);
|
|
366
|
+
const effort = str(args.effort);
|
|
367
|
+
const plan = typeof args.plan === 'boolean' ? args.plan : undefined;
|
|
368
|
+
const fast = typeof args.fast === 'boolean' ? args.fast : undefined;
|
|
369
|
+
const configured = model !== undefined || effort !== undefined || plan !== undefined || fast !== undefined;
|
|
359
370
|
const send = args.wait_for_send === true;
|
|
360
371
|
// Default on, matching the relay: an omitted flag must never mean "wait".
|
|
361
372
|
const sendImmediately = args.send_immediately !== false;
|
|
362
373
|
const data = await call(routes.createWorkspace.path(), {
|
|
363
374
|
method: routes.createWorkspace.method,
|
|
364
|
-
body: { repo, prompt, model, send, sendImmediately },
|
|
375
|
+
body: { repo, prompt, model, effort, plan, fast, send, sendImmediately },
|
|
365
376
|
timeoutMs: send ? WRITE_TIMEOUT_MS : 30_000
|
|
366
377
|
});
|
|
367
378
|
const lines = [
|
|
@@ -374,8 +385,8 @@ export function createTools(call) {
|
|
|
374
385
|
lines.push('the first prompt is queued — the relay delivers it, so do not send it again');
|
|
375
386
|
else if (data.sent)
|
|
376
387
|
lines.push('the first prompt was delivered');
|
|
377
|
-
if (
|
|
378
|
-
lines.push(data.configured ?
|
|
388
|
+
if (configured)
|
|
389
|
+
lines.push(data.configured ? 'agent settings applied' : 'agent settings queued');
|
|
379
390
|
return lines.join('\n');
|
|
380
391
|
}
|
|
381
392
|
},
|
package/dist-node/src/notify.js
CHANGED
|
@@ -253,7 +253,7 @@ function turnEnded(status) {
|
|
|
253
253
|
}
|
|
254
254
|
/**
|
|
255
255
|
* The status state machine, kept apart from the store and the network so it can be
|
|
256
|
-
* driven a tick at a time by `
|
|
256
|
+
* driven a tick at a time by `tests/notify.test.ts`. Every rule in it is a rule
|
|
257
257
|
* about *not* notifying, and each one is a nuisance or a silence that nothing in the
|
|
258
258
|
* type system can catch.
|
|
259
259
|
*/
|
package/dist-node/src/reads.js
CHANGED
|
@@ -4,6 +4,14 @@ import path from 'node:path';
|
|
|
4
4
|
import { describeRepoIcon, resolveRepoIcon } from "./icons.js";
|
|
5
5
|
import { workspaceTitle } from "./shared.js";
|
|
6
6
|
import { parseMessage } from "./transcript.js";
|
|
7
|
+
/** Keep the stable wire field in sync with whichever provider owns the chat. */
|
|
8
|
+
function toSessionRow(row) {
|
|
9
|
+
const { codex_thinking_level, ...session } = row;
|
|
10
|
+
return {
|
|
11
|
+
...session,
|
|
12
|
+
claude_effort_level: row.agent_type === 'codex' ? codex_thinking_level : row.claude_effort_level
|
|
13
|
+
};
|
|
14
|
+
}
|
|
7
15
|
const worktreeCache = new Map();
|
|
8
16
|
/**
|
|
9
17
|
* Neutralize LIKE's own wildcards in a user's search word. `queryTokens` already
|
|
@@ -232,7 +240,8 @@ export class Reads {
|
|
|
232
240
|
// have `sent_at` NULL and are skipped, which is why a queued message can't blip the
|
|
233
241
|
// timer while the previous answer is still going. Served straight off
|
|
234
242
|
// idx_session_messages_sent_at(session_id, sent_at) — measured free at this poll rate.
|
|
235
|
-
|
|
243
|
+
const rows = this.db.query(`SELECT s.id, s.status, s.title, s.model, s.permission_mode,
|
|
244
|
+
s.claude_effort_level, s.codex_thinking_level, s.fast_mode, s.agent_type,
|
|
236
245
|
s.context_used_percent, s.unread_count,
|
|
237
246
|
s.created_at, s.updated_at, s.last_user_message_at,
|
|
238
247
|
(SELECT MAX(m.sent_at) FROM session_messages m
|
|
@@ -240,6 +249,7 @@ export class Reads {
|
|
|
240
249
|
FROM sessions s
|
|
241
250
|
WHERE s.workspace_id = ? AND COALESCE(s.is_hidden, 0) = 0
|
|
242
251
|
ORDER BY s.created_at ASC`, [workspaceId]);
|
|
252
|
+
return rows.map(toSessionRow);
|
|
243
253
|
}
|
|
244
254
|
/**
|
|
245
255
|
* Every live chat's status, across all workspaces — what the notifier watches for
|
package/dist-node/src/server.js
CHANGED
|
@@ -312,11 +312,11 @@ const firstPrompts = new FirstPromptQueue(path.join(stateDir(), 'first-prompts.j
|
|
|
312
312
|
const result = await deliverPrompt(ws, sessionId, text);
|
|
313
313
|
return { ok: result.ok, error: result.error, blocked: lockBlocked(result.error) };
|
|
314
314
|
}),
|
|
315
|
-
|
|
315
|
+
setAgent: (workspaceId, sessionId, agent) => withUiPriority('background', async () => {
|
|
316
316
|
const ws = reads.getWorkspace(workspaceId);
|
|
317
317
|
if (!ws)
|
|
318
318
|
return { ok: false, error: 'the workspace is gone' };
|
|
319
|
-
const result = await applyAgentPatch(ws, sessionId,
|
|
319
|
+
const result = await applyAgentPatch(ws, sessionId, agent);
|
|
320
320
|
return { ok: result.ok, error: result.error, blocked: lockBlocked(result.error) };
|
|
321
321
|
}),
|
|
322
322
|
materialize: async (_workspaceId, worktree, attachmentIds) => {
|
|
@@ -950,13 +950,29 @@ const server = http.createServer(async (req, res) => {
|
|
|
950
950
|
return json(req, res, discardStagedAttachment(STAGED_ATTACHMENTS_DIR, stagedAttachment) ? 200 : 404, {
|
|
951
951
|
ok: true
|
|
952
952
|
});
|
|
953
|
-
// POST /api/workspaces { repo, prompt,
|
|
953
|
+
// POST /api/workspaces { repo, prompt, model?, effort?, plan?, fast?, send? }
|
|
954
|
+
// — create a workspace via Conductor's deep link, then configure its first chat.
|
|
954
955
|
if (isRoute(routes.createWorkspace, req.method, pathname)) {
|
|
955
956
|
const body = JSON.parse((await readBody(req)) || '{}');
|
|
956
957
|
const attachmentIds = body.attachmentIds ?? [];
|
|
957
958
|
if (body.model !== undefined && typeof body.model !== 'string')
|
|
958
959
|
return json(req, res, 400, { error: 'model must be a picker label' });
|
|
959
|
-
|
|
960
|
+
if (body.effort !== undefined && typeof body.effort !== 'string')
|
|
961
|
+
return json(req, res, 400, { error: 'effort must be a string' });
|
|
962
|
+
const effort = body.effort?.trim() || undefined;
|
|
963
|
+
if (effort && !EFFORT_LABELS[effort])
|
|
964
|
+
return json(req, res, 400, { error: `effort must be one of ${Object.keys(EFFORT_LABELS).join(', ')}` });
|
|
965
|
+
if (body.plan !== undefined && typeof body.plan !== 'boolean')
|
|
966
|
+
return json(req, res, 400, { error: 'plan must be a boolean' });
|
|
967
|
+
if (body.fast !== undefined && typeof body.fast !== 'boolean')
|
|
968
|
+
return json(req, res, 400, { error: 'fast must be a boolean' });
|
|
969
|
+
const agent = {
|
|
970
|
+
model: body.model?.trim() || undefined,
|
|
971
|
+
effort,
|
|
972
|
+
plan: body.plan,
|
|
973
|
+
fast: body.fast
|
|
974
|
+
};
|
|
975
|
+
const configureAgent = Object.values(agent).some(value => value !== undefined);
|
|
960
976
|
if (!Array.isArray(attachmentIds) || attachmentIds.some(id => typeof id !== 'string'))
|
|
961
977
|
return json(req, res, 400, { error: 'attachment ids must be a list of strings' });
|
|
962
978
|
const attachments = stagedAttachments(STAGED_ATTACHMENTS_DIR, attachmentIds);
|
|
@@ -1000,8 +1016,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1000
1016
|
// its own schedule and the phone watches it in /api/state; `send:true` opts API
|
|
1001
1017
|
// callers into waiting.
|
|
1002
1018
|
// Whatever happens, the prompt is already pre-filled in Conductor's composer.
|
|
1003
|
-
const settled = prompt ||
|
|
1004
|
-
? firstPrompts.enqueue(created.id, prompt, body.sendImmediately !== false, attachmentIds,
|
|
1019
|
+
const settled = prompt || configureAgent
|
|
1020
|
+
? firstPrompts.enqueue(created.id, prompt, body.sendImmediately !== false, attachmentIds, configureAgent ? agent : undefined)
|
|
1005
1021
|
: null;
|
|
1006
1022
|
const failed = settled && body.send === true ? await settled : null;
|
|
1007
1023
|
settled?.catch(() => undefined); // fire-and-forget: it reports failure, it never rejects
|
|
@@ -1010,11 +1026,11 @@ const server = http.createServer(async (req, res) => {
|
|
|
1010
1026
|
workspaceId: created.id,
|
|
1011
1027
|
workspace: reads.getWorkspace(created.id) ?? created,
|
|
1012
1028
|
pendingPrompt: prompt || undefined,
|
|
1013
|
-
model,
|
|
1029
|
+
model: agent.model,
|
|
1014
1030
|
sent: body.send === true && !!prompt && !failed,
|
|
1015
|
-
configured: body.send === true &&
|
|
1031
|
+
configured: body.send === true && configureAgent && !failed,
|
|
1016
1032
|
warning: failed?.error &&
|
|
1017
|
-
`Workspace created; the initial ${
|
|
1033
|
+
`Workspace created; the initial ${configureAgent ? 'agent settings and prompt' : 'prompt'} didn’t finish (${failed.error}).`
|
|
1018
1034
|
});
|
|
1019
1035
|
}
|
|
1020
1036
|
// GET /api/repos/:name/icon — the repo's resolved sidebar icon (see src/icons.ts)
|
package/dist-node/src/writes.js
CHANGED
|
@@ -38,7 +38,7 @@ function pumpUi() {
|
|
|
38
38
|
next.start();
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* Take the lock, run `op`, release it. Exported for `
|
|
41
|
+
* Take the lock, run `op`, release it. Exported for `tests/ui-lock.test.ts`,
|
|
42
42
|
* which is the only way this queue's control flow gets read by anything.
|
|
43
43
|
*/
|
|
44
44
|
export function uiTurn(op) {
|
|
@@ -501,10 +501,11 @@ my joinInstantHotspot()`.trim();
|
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
503
|
/**
|
|
504
|
-
* Conductor stores the effort level
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
504
|
+
* Conductor stores the effort level in a provider-specific session column
|
|
505
|
+
* (`codex_thinking_level` or `claude_effort_level`), normalized by Reads onto the
|
|
506
|
+
* relay's stable wire field. The composer button is labelled with the human name
|
|
507
|
+
* and *cycles* through these values, so both directions are needed: the label to
|
|
508
|
+
* press toward, and the normalized DB value to confirm against.
|
|
508
509
|
*/
|
|
509
510
|
export const EFFORT_LABELS = {
|
|
510
511
|
low: 'Low',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor-remote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.58.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "yarn@4.15.0",
|
|
6
6
|
"description": "Phone control panel for local Conductor agents. Reads ride SQLite + git; prompts ride Conductor's own dispatch path.",
|
|
@@ -50,29 +50,16 @@
|
|
|
50
50
|
"typecheck": "tsc -p tsconfig.json",
|
|
51
51
|
"lint": "biome check .",
|
|
52
52
|
"fix": "biome check . --fix",
|
|
53
|
-
"
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:watch": "vitest",
|
|
55
|
+
"test:coverage": "vitest run --coverage",
|
|
56
|
+
"check:repo": "yarn check:imports && yarn check:applescript",
|
|
57
|
+
"verify": "yarn typecheck && yarn lint && yarn test && yarn check:repo",
|
|
54
58
|
"release": "semantic-release",
|
|
55
59
|
"prepack": "yarn build && yarn build:node",
|
|
56
60
|
"postinstall": "husky || true",
|
|
57
|
-
"check:attachments": "node scripts/check-attachments.ts",
|
|
58
61
|
"check:applescript": "node scripts/check-applescript.ts",
|
|
59
|
-
"check:
|
|
60
|
-
"check:utf8-target": "node scripts/check-utf8-target.ts",
|
|
61
|
-
"check:file-links": "node scripts/check-file-links.ts",
|
|
62
|
-
"check:firstprompt": "node scripts/check-firstprompt.ts",
|
|
63
|
-
"check:model-cache": "node scripts/check-model-cache.ts",
|
|
64
|
-
"check:mcp-chat-read": "node scripts/check-mcp-chat-read.ts",
|
|
65
|
-
"check:model-labels": "node scripts/check-model-labels.ts",
|
|
66
|
-
"check:transcript-details": "node scripts/check-transcript-details.ts",
|
|
67
|
-
"check:transcript-actions": "node scripts/check-transcript-actions.ts",
|
|
68
|
-
"check:sendonce": "node scripts/check-sendonce.ts",
|
|
69
|
-
"check:notify": "node scripts/check-notify.ts",
|
|
70
|
-
"check:online": "node scripts/check-online.ts",
|
|
71
|
-
"check:pr": "node scripts/check-pr.ts",
|
|
72
|
-
"check:imports": "node scripts/check-imports.ts",
|
|
73
|
-
"check:nosleep": "node scripts/check-nosleep.ts",
|
|
74
|
-
"check:routes": "node scripts/check-routes.ts",
|
|
75
|
-
"check:uilock": "node scripts/check-uilock.ts"
|
|
62
|
+
"check:imports": "node scripts/check-imports.ts"
|
|
76
63
|
},
|
|
77
64
|
"devDependencies": {
|
|
78
65
|
"@biomejs/biome": "^2.3.8",
|
|
@@ -85,6 +72,7 @@
|
|
|
85
72
|
"@types/react": "^19.2.10",
|
|
86
73
|
"@types/react-dom": "^19.2.3",
|
|
87
74
|
"@vitejs/plugin-react": "^5.0.4",
|
|
75
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
88
76
|
"clsx": "^2.1.1",
|
|
89
77
|
"husky": "^9.1.7",
|
|
90
78
|
"jsqr": "^1.4.0",
|
|
@@ -102,6 +90,7 @@
|
|
|
102
90
|
"typescript": "^5.9.3",
|
|
103
91
|
"vite": "^7.3.1",
|
|
104
92
|
"vite-plugin-pwa": "^1.2.0",
|
|
93
|
+
"vitest": "^4.1.11",
|
|
105
94
|
"zustand": "^5.0.12"
|
|
106
95
|
}
|
|
107
96
|
}
|