conductor-remote 1.55.1 → 1.56.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/dist/assets/{index-DJ35BMTb.css → index-C2BviSOi.css} +1 -1
- package/dist/assets/{index-DVIyfOd7.js → index-CxgN1roC.js} +32 -32
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-node/src/file-preview.js +6 -44
- package/dist-node/src/pr.js +28 -2
- package/dist-node/src/server.js +6 -3
- package/dist-node/src/shared.js +40 -0
- package/package.json +4 -2
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-CxgN1roC.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C2BviSOi.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
|
|
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:"45b48aad06a99f1da7ee2c21dbaf2c2e"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-CxgN1roC.js",revision:null},{url:"assets/index-C2BviSOi.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\//]}))});
|
|
@@ -1,46 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
|
|
3
|
-
'.bash',
|
|
4
|
-
'.c',
|
|
5
|
-
'.cc',
|
|
6
|
-
'.cpp',
|
|
7
|
-
'.css',
|
|
8
|
-
'.go',
|
|
9
|
-
'.h',
|
|
10
|
-
'.hpp',
|
|
11
|
-
'.html',
|
|
12
|
-
'.java',
|
|
13
|
-
'.js',
|
|
14
|
-
'.json',
|
|
15
|
-
'.jsx',
|
|
16
|
-
'.md',
|
|
17
|
-
'.mjs',
|
|
18
|
-
'.mts',
|
|
19
|
-
'.php',
|
|
20
|
-
'.py',
|
|
21
|
-
'.rb',
|
|
22
|
-
'.rs',
|
|
23
|
-
'.scss',
|
|
24
|
-
'.sh',
|
|
25
|
-
'.sql',
|
|
26
|
-
'.svg',
|
|
27
|
-
'.swift',
|
|
28
|
-
'.toml',
|
|
29
|
-
'.ts',
|
|
30
|
-
'.tsx',
|
|
31
|
-
'.txt',
|
|
32
|
-
'.yaml',
|
|
33
|
-
'.yml'
|
|
34
|
-
]);
|
|
35
|
-
function sourceExtension(filePath) {
|
|
36
|
-
const name = filePath.slice(filePath.lastIndexOf('/') + 1);
|
|
37
|
-
const dot = name.lastIndexOf('.');
|
|
38
|
-
return dot === -1 ? '' : name.slice(dot).toLowerCase();
|
|
39
|
-
}
|
|
40
|
-
/** True when a file is a text source format this viewer is allowed to expose. */
|
|
41
|
-
export function isPreviewableSource(filePath) {
|
|
42
|
-
return SOURCE_EXTENSIONS.has(sourceExtension(filePath));
|
|
43
|
-
}
|
|
2
|
+
import { isPreviewableSource } from "./shared.js";
|
|
44
3
|
/** True only for a descendant. A prefix test would let `/workspaces-old` escape `/workspaces`. */
|
|
45
4
|
function insideDirectory(filePath, root) {
|
|
46
5
|
const relative = path.relative(root, filePath);
|
|
@@ -54,8 +13,11 @@ function insideDirectory(filePath, root) {
|
|
|
54
13
|
* Call this only with real paths. That ensures a symlink cannot point outside
|
|
55
14
|
* an allowed directory after this check.
|
|
56
15
|
*/
|
|
57
|
-
export function isAllowedPreviewPath(filePath, workspaceRoot, homeRoot, exposeMode) {
|
|
58
|
-
return insideDirectory(filePath, workspaceRoot) ||
|
|
16
|
+
export function isAllowedPreviewPath(filePath, workspaceRoot, homeRoot, exposeMode, bundledSkillsRoot = null) {
|
|
17
|
+
return (insideDirectory(filePath, workspaceRoot) ||
|
|
18
|
+
(exposeMode === 'tailnet' &&
|
|
19
|
+
(insideDirectory(filePath, homeRoot) ||
|
|
20
|
+
(bundledSkillsRoot !== null && insideDirectory(filePath, bundledSkillsRoot)))));
|
|
59
21
|
}
|
|
60
22
|
/**
|
|
61
23
|
* Parse a source link without treating ordinary PWA routes as file references.
|
package/dist-node/src/pr.js
CHANGED
|
@@ -37,7 +37,7 @@ export function attachPrStatus(workspaces) {
|
|
|
37
37
|
else {
|
|
38
38
|
const c = w.worktree ? conflictCache.get(w.worktree) : undefined;
|
|
39
39
|
// Optimistically green until the local merge check says otherwise (self-corrects within CONFLICT_TTL).
|
|
40
|
-
w.pr_status = c?.conflicts ? 'conflicts' : 'mergeable';
|
|
40
|
+
w.pr_status = c?.conflicts ? 'conflicts' : hasFailedChecks(pr.statusCheckRollup) ? 'checks_failed' : 'mergeable';
|
|
41
41
|
if (w.worktree && (!c || now - c.at > CONFLICT_TTL))
|
|
42
42
|
refreshConflict(w.worktree, w.baseBranch);
|
|
43
43
|
}
|
|
@@ -61,7 +61,16 @@ function refreshRepo(root) {
|
|
|
61
61
|
/** One `gh` call per repo → its PRs keyed by head branch. Never rejects. */
|
|
62
62
|
async function fetchRepoPRs(root) {
|
|
63
63
|
try {
|
|
64
|
-
const { stdout } = await exec('gh', [
|
|
64
|
+
const { stdout } = await exec('gh', [
|
|
65
|
+
'pr',
|
|
66
|
+
'list',
|
|
67
|
+
'--state',
|
|
68
|
+
'all',
|
|
69
|
+
'--limit',
|
|
70
|
+
'100',
|
|
71
|
+
'--json',
|
|
72
|
+
'headRefName,number,url,state,isDraft,updatedAt,statusCheckRollup'
|
|
73
|
+
], { cwd: root, encoding: 'utf8', timeout: 15_000 });
|
|
65
74
|
const list = JSON.parse(stdout);
|
|
66
75
|
// Oldest first so the newest PR wins when a branch has been reused across PRs.
|
|
67
76
|
list.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt));
|
|
@@ -74,6 +83,23 @@ async function fetchRepoPRs(root) {
|
|
|
74
83
|
return null;
|
|
75
84
|
}
|
|
76
85
|
}
|
|
86
|
+
const FAILED_CHECK_CONCLUSIONS = new Set([
|
|
87
|
+
'ACTION_REQUIRED',
|
|
88
|
+
'CANCELLED',
|
|
89
|
+
'FAILURE',
|
|
90
|
+
'STALE',
|
|
91
|
+
'STARTUP_FAILURE',
|
|
92
|
+
'TIMED_OUT'
|
|
93
|
+
]);
|
|
94
|
+
const FAILED_CHECK_STATES = new Set(['ERROR', 'FAILURE']);
|
|
95
|
+
/**
|
|
96
|
+
* Check runs carry their terminal result in `conclusion`; legacy status contexts
|
|
97
|
+
* use `state`. Pending checks remain green because this marker calls out failures.
|
|
98
|
+
*/
|
|
99
|
+
export function hasFailedChecks(checks) {
|
|
100
|
+
return !!checks?.some(check => (check.conclusion && FAILED_CHECK_CONCLUSIONS.has(check.conclusion)) ||
|
|
101
|
+
(check.state && FAILED_CHECK_STATES.has(check.state)));
|
|
102
|
+
}
|
|
77
103
|
function refreshConflict(worktree, base) {
|
|
78
104
|
if (conflictInflight.has(worktree))
|
|
79
105
|
return;
|
package/dist-node/src/server.js
CHANGED
|
@@ -468,6 +468,7 @@ async function serveLocalImage(req, res, requestedPath) {
|
|
|
468
468
|
const FILE_PREVIEW_MAX_BYTES = 512 * 1024;
|
|
469
469
|
const FILE_PREVIEW_CONTEXT_LINES = 100;
|
|
470
470
|
const FILE_PREVIEW_FIRST_LINES = 500;
|
|
471
|
+
const BUNDLED_SKILLS_ROOT = '/Applications/Conductor.app/Contents/Resources/conductor-skill/skills';
|
|
471
472
|
/**
|
|
472
473
|
* Serve source that an agent linked in its Markdown. The link format comes from
|
|
473
474
|
* coding-agent file references, but its path still arrives from a remote client.
|
|
@@ -481,15 +482,17 @@ async function serveFilePreview(req, res, reference) {
|
|
|
481
482
|
let filePath;
|
|
482
483
|
let workspaceRoot;
|
|
483
484
|
let homeRoot;
|
|
485
|
+
let bundledSkillsRoot;
|
|
484
486
|
let size;
|
|
485
487
|
try {
|
|
486
488
|
;
|
|
487
|
-
[filePath, workspaceRoot, homeRoot] = await Promise.all([
|
|
489
|
+
[filePath, workspaceRoot, homeRoot, bundledSkillsRoot] = await Promise.all([
|
|
488
490
|
fs.promises.realpath(target.path),
|
|
489
491
|
fs.promises.realpath(cfg.workspacesRoot),
|
|
490
|
-
fs.promises.realpath(os.homedir())
|
|
492
|
+
fs.promises.realpath(os.homedir()),
|
|
493
|
+
fs.promises.realpath(BUNDLED_SKILLS_ROOT).catch(() => null)
|
|
491
494
|
]);
|
|
492
|
-
if (!isAllowedPreviewPath(filePath, workspaceRoot, homeRoot, readExposeMode())) {
|
|
495
|
+
if (!isAllowedPreviewPath(filePath, workspaceRoot, homeRoot, readExposeMode(), bundledSkillsRoot)) {
|
|
493
496
|
return json(req, res, 404, { error: 'source file not found' });
|
|
494
497
|
}
|
|
495
498
|
const info = await fs.promises.stat(filePath);
|
package/dist-node/src/shared.js
CHANGED
|
@@ -162,3 +162,43 @@ export function attachmentTokens(text) {
|
|
|
162
162
|
}
|
|
163
163
|
return tokens;
|
|
164
164
|
}
|
|
165
|
+
/** Text source formats the relay may return to the phone's source preview. */
|
|
166
|
+
const SOURCE_EXTENSIONS = new Set([
|
|
167
|
+
'.bash',
|
|
168
|
+
'.c',
|
|
169
|
+
'.cc',
|
|
170
|
+
'.cpp',
|
|
171
|
+
'.css',
|
|
172
|
+
'.go',
|
|
173
|
+
'.h',
|
|
174
|
+
'.hpp',
|
|
175
|
+
'.html',
|
|
176
|
+
'.java',
|
|
177
|
+
'.js',
|
|
178
|
+
'.json',
|
|
179
|
+
'.jsx',
|
|
180
|
+
'.md',
|
|
181
|
+
'.mjs',
|
|
182
|
+
'.mts',
|
|
183
|
+
'.php',
|
|
184
|
+
'.py',
|
|
185
|
+
'.rb',
|
|
186
|
+
'.rs',
|
|
187
|
+
'.scss',
|
|
188
|
+
'.sh',
|
|
189
|
+
'.sql',
|
|
190
|
+
'.svg',
|
|
191
|
+
'.swift',
|
|
192
|
+
'.toml',
|
|
193
|
+
'.ts',
|
|
194
|
+
'.tsx',
|
|
195
|
+
'.txt',
|
|
196
|
+
'.yaml',
|
|
197
|
+
'.yml'
|
|
198
|
+
]);
|
|
199
|
+
/** True for a file extension the relay's source preview accepts. */
|
|
200
|
+
export function isPreviewableSource(filePath) {
|
|
201
|
+
const name = filePath.slice(filePath.lastIndexOf('/') + 1);
|
|
202
|
+
const dot = name.lastIndexOf('.');
|
|
203
|
+
return dot !== -1 && SOURCE_EXTENSIONS.has(name.slice(dot).toLowerCase());
|
|
204
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor-remote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.56.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,7 +50,7 @@
|
|
|
50
50
|
"typecheck": "tsc -p tsconfig.json",
|
|
51
51
|
"lint": "biome check .",
|
|
52
52
|
"fix": "biome check . --fix",
|
|
53
|
-
"verify": "yarn typecheck && yarn lint && yarn check:imports && yarn check:routes && yarn check:attachments && yarn check:applescript && yarn check:config && yarn check:utf8-target && yarn check:file-links && yarn check:model-cache && yarn check:model-labels && yarn check:nosleep && yarn check:uilock && yarn check:firstprompt && yarn check:sendonce && yarn check:notify && yarn check:online",
|
|
53
|
+
"verify": "yarn typecheck && yarn lint && yarn check:pr && yarn check:imports && yarn check:routes && yarn check:attachments && yarn check:applescript && yarn check:config && yarn check:utf8-target && yarn check:file-links && yarn check:model-cache && yarn check:model-labels && yarn check:transcript-actions && yarn check:nosleep && yarn check:uilock && yarn check:firstprompt && yarn check:sendonce && yarn check:notify && yarn check:online",
|
|
54
54
|
"release": "semantic-release",
|
|
55
55
|
"prepack": "yarn build && yarn build:node",
|
|
56
56
|
"postinstall": "husky || true",
|
|
@@ -62,9 +62,11 @@
|
|
|
62
62
|
"check:firstprompt": "node scripts/check-firstprompt.ts",
|
|
63
63
|
"check:model-cache": "node scripts/check-model-cache.ts",
|
|
64
64
|
"check:model-labels": "node scripts/check-model-labels.ts",
|
|
65
|
+
"check:transcript-actions": "node scripts/check-transcript-actions.ts",
|
|
65
66
|
"check:sendonce": "node scripts/check-sendonce.ts",
|
|
66
67
|
"check:notify": "node scripts/check-notify.ts",
|
|
67
68
|
"check:online": "node scripts/check-online.ts",
|
|
69
|
+
"check:pr": "node scripts/check-pr.ts",
|
|
68
70
|
"check:imports": "node scripts/check-imports.ts",
|
|
69
71
|
"check:nosleep": "node scripts/check-nosleep.ts",
|
|
70
72
|
"check:routes": "node scripts/check-routes.ts",
|