@volter/supercode-teams 0.2.146 → 0.2.148
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/connector/index.mjs +10 -1
- package/machine.mjs +12 -1
- package/package.json +1 -1
- package/server/continuations.mjs +1 -1
- package/server/harness-routes.mjs +10 -7
- package/server/storage-report.mjs +1 -1
- package/server/store-core.mjs +1 -1
package/connector/index.mjs
CHANGED
|
@@ -765,8 +765,17 @@ export class TeamsConnector {
|
|
|
765
765
|
this.state.native_transfer??={sent_bytes:0,reused_bytes:0,chunks:0};
|
|
766
766
|
this.state.native_transfer[reused?'reused_bytes':'sent_bytes']+=Buffer.byteLength(chunk.bytes_base64,'base64');
|
|
767
767
|
this.state.native_transfer.chunks++;
|
|
768
|
+
const key=`${item.begin.harness}:${item.begin.native_session_id}`;
|
|
769
|
+
const transfers=this.state.native_transfers??={};
|
|
770
|
+
const transfer=transfers[key]??={since:this.clock.nowMs(),sent_bytes:0,reused_bytes:0,chunks:0,captures:0};
|
|
771
|
+
transfer[reused?'reused_bytes':'sent_bytes']+=Buffer.byteLength(chunk.bytes_base64,'base64');
|
|
772
|
+
transfer.chunks++;transfer.at=this.clock.nowMs();
|
|
773
|
+
for(const expired of Object.keys(transfers).sort((a,b)=>transfers[b].at-transfers[a].at).slice(128))delete transfers[expired];
|
|
768
774
|
}
|
|
769
|
-
|
|
775
|
+
const receipt=await this.request('POST',`/sources/${this.sourceId}/captures/${item.begin.capture_id}/commit`,item.commit);
|
|
776
|
+
const transfer=this.state.native_transfers?.[`${item.begin.harness}:${item.begin.native_session_id}`];
|
|
777
|
+
if(transfer&&item.artifacts?.length){transfer.captures++;transfer.last_bundle_bytes=item.commit.artifacts.reduce((sum,a)=>sum+a.byte_length,0);}
|
|
778
|
+
return receipt;}
|
|
770
779
|
// True when the server refused a queued capture because its sync rule was removed, paused or revised since it
|
|
771
780
|
// was queued: the capture can never be accepted, so it must not hold every later capture behind it. The
|
|
772
781
|
// refusal is confirmed against a fresh configuration; any other refusal (a revoked credential, a paused
|
package/machine.mjs
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// It decides nothing on anyone's behalf. Every act is logged.
|
|
27
27
|
import { spawn, spawnSync } from 'node:child_process';
|
|
28
28
|
import { EventEmitter } from 'node:events';
|
|
29
|
-
import { appendFileSync, readFileSync, writeFileSync, writeSync, statSync, readdirSync, mkdirSync, renameSync, rmSync, existsSync, openSync, readSync, closeSync } from 'node:fs';
|
|
29
|
+
import { appendFileSync, readFileSync, writeFileSync, writeSync, statSync, readdirSync, mkdirSync, renameSync, rmSync, existsSync, openSync, readSync, closeSync, accessSync, constants } from 'node:fs';
|
|
30
30
|
import { join, resolve, dirname } from 'node:path';
|
|
31
31
|
import { fileURLToPath } from 'node:url';
|
|
32
32
|
import { homedir, hostname } from 'node:os';
|
|
@@ -619,6 +619,9 @@ export class TeamsMachine extends MachineCore {
|
|
|
619
619
|
*/
|
|
620
620
|
#paneEnv(contextKey, requested) {
|
|
621
621
|
const env = { ...(requested ?? {}) };
|
|
622
|
+
// A long-lived tmux server can predate a consolidated installation.
|
|
623
|
+
// New panes inherit this daemon's selected tools, not that stale PATH.
|
|
624
|
+
env.PATH ??= this.env.PATH;
|
|
622
625
|
const inherited = env.NODE_OPTIONS ?? this.env.NODE_OPTIONS ?? '';
|
|
623
626
|
// Quoted: NODE_OPTIONS splits on spaces, and a home path may hold one (Windows user folders often do).
|
|
624
627
|
env.NODE_OPTIONS = `${inherited} --require ${JSON.stringify(PORTHOLE_HOOK)}`.trim();
|
|
@@ -1409,6 +1412,14 @@ export class TeamsMachine extends MachineCore {
|
|
|
1409
1412
|
let session;
|
|
1410
1413
|
let nativeInput;
|
|
1411
1414
|
try {
|
|
1415
|
+
if (process.platform !== 'win32' && !String(params.program).includes('/')) {
|
|
1416
|
+
const search = params.env?.PATH ?? this.env.PATH ?? '';
|
|
1417
|
+
const program = search.split(':').map(dir => resolve(dir || params.cwd || process.cwd(), params.program)).find(path => {
|
|
1418
|
+
try { accessSync(path, constants.X_OK); return statSync(path).isFile(); } catch { return false; }
|
|
1419
|
+
});
|
|
1420
|
+
if (!program) throw new Error(`program ${params.program} is absent from this machine's launch PATH`);
|
|
1421
|
+
params = { ...params, program };
|
|
1422
|
+
}
|
|
1412
1423
|
if (params.kind === 'codex') params = { ...params, arguments: canonicalCodexFolderTrust(params.cwd, params.arguments) };
|
|
1413
1424
|
session = await this.host.createSession({
|
|
1414
1425
|
command: this.#nativeQuestionCommand(params, contextKey, by, (value) => { nativeInput = value; }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.148",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A machine daemon serving this machine's doors, and a local or remote Teams server for shared session discovery, OpenTelemetry ingestion and access to enrolled machines.",
|
|
6
6
|
"license": "MIT",
|
package/server/continuations.mjs
CHANGED
|
@@ -53,4 +53,4 @@ async function authorizedRemote(api,auth,machineId,effectId,incarnation,routeFai
|
|
|
53
53
|
|
|
54
54
|
export async function remoteContinuationRoute({api,req,res,auth,machineId,effectId,requestId,fail,send,result}){const {value}=await authorizedRemote(api,auth,machineId,effectId,req.headers['x-teams-incarnation'],fail);const ticket={kind:'remote_launch',continuation_id:value.id,operation_id:value.operation_id,harness:value.harness,fidelity:value.fidelity,artifact:value.artifact,destination:value.destination,expires_at:Math.min(value.expires_at,value.destination_authorization.expires_at)};return send(res,200,result(api,auth,ticket),requestId);}
|
|
55
55
|
|
|
56
|
-
export async function remoteContinuationArtifactRoute({api,req,res,auth,machineId,effectId,uploadId,requestId,fail}){const {value}=await authorizedRemote(api,auth,machineId,effectId,req.headers['x-teams-incarnation'],fail);const file=value.artifact.files.find(item=>item.upload_id===uploadId);if(!file)fail(404,'not_found','artifact is not in the continuation bundle');const rows=await api.store.query('SELECT bytes FROM
|
|
56
|
+
export async function remoteContinuationArtifactRoute({api,req,res,auth,machineId,effectId,uploadId,requestId,fail}){const {value}=await authorizedRemote(api,auth,machineId,effectId,req.headers['x-teams-incarnation'],fail);const file=value.artifact.files.find(item=>item.upload_id===uploadId);if(!file)fail(404,'not_found','artifact is not in the continuation bundle');const rows=await api.store.query('SELECT chunk_index,bytes FROM artifact_chunks WHERE team_id=? AND upload_id=? UNION ALL SELECT r.chunk_index,b.bytes FROM artifact_chunk_refs r JOIN artifact_blobs b ON b.team_id=r.team_id AND b.sha256=r.sha256 WHERE r.team_id=? AND r.upload_id=? ORDER BY chunk_index',[auth.team_id,uploadId,auth.team_id,uploadId]),bytes=Buffer.concat(rows.map(row=>row.bytes));if(bytes.length!==file.byte_length||createHash('sha256').update(bytes).digest('hex')!==file.sha256)fail(409,'conflict','artifact bytes changed');let start=0,end=bytes.length-1,status=200;const range=req.headers.range;if(range!==undefined){const match=/^bytes=(\d*)-(\d*)$/.exec(range);if(!match||(!match[1]&&!match[2]))fail(416,'invalid_request','invalid artifact range');if(match[1]){start=Number(match[1]);end=match[2]?Number(match[2]):end;}else{const suffix=Number(match[2]);start=Math.max(0,bytes.length-suffix);}if(!Number.isSafeInteger(start)||!Number.isSafeInteger(end)||start<0||end<start||start>=bytes.length)fail(416,'invalid_request','artifact range is unsatisfiable');end=Math.min(end,bytes.length-1);status=206;}const body=bytes.subarray(start,end+1);res.writeHead(status,{'Content-Type':file.media_type,'Content-Length':String(body.length),'Accept-Ranges':'bytes','Cache-Control':'no-store','X-Request-ID':requestId,...(status===206?{'Content-Range':`bytes ${start}-${end}/${bytes.length}`}:{})});res.end(body);}
|
|
@@ -285,15 +285,18 @@ async function artifactChunk(api,req,res,auth,sourceId,uploadId,index,requestId)
|
|
|
285
285
|
const upload=await api.store.one('SELECT * FROM uploads WHERE team_id=? AND id=?',[auth.team_id,uploadId]);
|
|
286
286
|
if(await expireStaging(api,auth.team_id,sourceId,uploadId,'uploads',upload))fail(409,'resync_required','upload reservation expired');
|
|
287
287
|
if(upload&&upload.source_id!==sourceId)fail(409,'capture_conflict','upload belongs to another source');
|
|
288
|
-
const old=await api.store.one('SELECT sha256 FROM
|
|
288
|
+
const old=await api.store.one('SELECT sha256 FROM artifact_chunks WHERE team_id=? AND upload_id=? AND chunk_index=? UNION ALL SELECT sha256 FROM artifact_chunk_refs WHERE team_id=? AND upload_id=? AND chunk_index=?',[auth.team_id,uploadId,index,auth.team_id,uploadId,index]);
|
|
289
289
|
if(old){if(old.sha256!==b.sha256)fail(409,'capture_conflict','artifact chunk replay differs');return send(res,200,result(api,auth,{index,sha256:b.sha256}),requestId);}
|
|
290
290
|
let bytes;
|
|
291
291
|
if (b.reuse === true) {
|
|
292
292
|
// A source may reuse only bytes it already uploaded. Knowing another
|
|
293
293
|
// source's content hash never grants read access to its native history.
|
|
294
|
-
const held = await api.store.one(`SELECT
|
|
295
|
-
JOIN uploads u ON u.team_id=
|
|
296
|
-
|
|
294
|
+
const held = await api.store.one(`SELECT b.bytes FROM artifact_blobs b WHERE b.team_id=? AND b.sha256=?
|
|
295
|
+
AND EXISTS (SELECT 1 FROM artifact_chunk_refs r JOIN uploads u ON u.team_id=r.team_id AND u.id=r.upload_id
|
|
296
|
+
WHERE r.team_id=b.team_id AND r.sha256=b.sha256 AND u.source_id=?)
|
|
297
|
+
UNION ALL SELECT c.bytes FROM artifact_chunks c WHERE c.team_id=? AND c.sha256=?
|
|
298
|
+
AND EXISTS (SELECT 1 FROM uploads u WHERE u.team_id=c.team_id AND u.id=c.upload_id AND u.source_id=?) LIMIT 1`,
|
|
299
|
+
[auth.team_id,b.sha256,sourceId,auth.team_id,b.sha256,sourceId]);
|
|
297
300
|
if (!held) fail(404,'chunk_missing','this source has no retained chunk with that digest');
|
|
298
301
|
bytes = Buffer.from(held.bytes);
|
|
299
302
|
} else {
|
|
@@ -311,8 +314,8 @@ async function artifactChunk(api,req,res,auth,sourceId,uploadId,index,requestId)
|
|
|
311
314
|
}
|
|
312
315
|
const now=api.clock.nowMs(),response=result(api,auth,{index,sha256:b.sha256,reused:b.reuse===true,stored_bytes:blob?0:bytes.length});
|
|
313
316
|
const guards=[
|
|
314
|
-
{sql:"SELECT 1 ok WHERE EXISTS (SELECT 1 FROM credentials c JOIN sources s ON s.team_id=c.team_id AND s.id=c.source_id WHERE c.id=? AND c.source_id=? AND c.revoked_at IS NULL AND (c.expires_at IS NULL OR c.expires_at>?) AND s.state='active') AND NOT EXISTS (SELECT 1 FROM capture_expiries WHERE team_id=? AND source_id=? AND id=?) AND NOT EXISTS (SELECT 1 FROM uploads WHERE team_id=? AND id=? AND source_id<>?) AND COALESCE((SELECT committed FROM uploads WHERE team_id=? AND id=?),0)=0 AND COALESCE((SELECT created_at+86400000>? FROM uploads WHERE team_id=? AND id=?),1) AND (SELECT count(*) FROM
|
|
315
|
-
{sql:'SELECT 1 ok WHERE COALESCE((SELECT sum(length(bytes)) FROM
|
|
317
|
+
{sql:"SELECT 1 ok WHERE EXISTS (SELECT 1 FROM credentials c JOIN sources s ON s.team_id=c.team_id AND s.id=c.source_id WHERE c.id=? AND c.source_id=? AND c.revoked_at IS NULL AND (c.expires_at IS NULL OR c.expires_at>?) AND s.state='active') AND NOT EXISTS (SELECT 1 FROM capture_expiries WHERE team_id=? AND source_id=? AND id=?) AND NOT EXISTS (SELECT 1 FROM uploads WHERE team_id=? AND id=? AND source_id<>?) AND COALESCE((SELECT committed FROM uploads WHERE team_id=? AND id=?),0)=0 AND COALESCE((SELECT created_at+86400000>? FROM uploads WHERE team_id=? AND id=?),1) AND ((SELECT count(*) FROM artifact_chunks WHERE team_id=? AND upload_id=?)+(SELECT count(*) FROM artifact_chunk_refs WHERE team_id=? AND upload_id=?))=?",params:[auth.credential_id,sourceId,now,auth.team_id,sourceId,uploadId,auth.team_id,uploadId,sourceId,auth.team_id,uploadId,now,auth.team_id,uploadId,auth.team_id,uploadId,auth.team_id,uploadId,index],code:'batch_gap',status:409,message:'upload authorization, expiry, or sequence changed'},
|
|
318
|
+
{sql:'SELECT 1 ok WHERE COALESCE((SELECT sum(length(bytes)) FROM artifact_chunks WHERE team_id=? AND upload_id=?),0)+COALESCE((SELECT sum(length(b.bytes)) FROM artifact_chunk_refs r JOIN artifact_blobs b ON b.team_id=r.team_id AND b.sha256=r.sha256 WHERE r.team_id=? AND r.upload_id=?),0)+?<=?',params:[auth.team_id,uploadId,auth.team_id,uploadId,bytes.length,api.uploadLimitBytes],code:'request_too_large',status:413,message:'artifact exceeds configured upload cap'}
|
|
316
319
|
];
|
|
317
320
|
await guardedMutation(api,res,auth,guards,[
|
|
318
321
|
{sql:'INSERT OR IGNORE INTO uploads(team_id,id,source_id,created_at) VALUES (?,?,?,?)',params:[auth.team_id,uploadId,sourceId,now]},
|
|
@@ -322,7 +325,7 @@ async function artifactChunk(api,req,res,auth,sourceId,uploadId,index,requestId)
|
|
|
322
325
|
send(res,200,response,requestId);
|
|
323
326
|
}
|
|
324
327
|
async function captureCommit(api,req,res,auth,sourceId,captureId,requestId){const source=await sourceAuth(api,auth,sourceId);const commit=await parseJson(req);exact(commit,['capture_id','parts','digest','title','repository','reported_user','recorded_activity_at','parent_native_id','coverage','artifacts','native_bundle']);if(commit.capture_id!==captureId||!Number.isSafeInteger(commit.parts)||commit.parts<1)fail(400,'invalid_request','invalid commit');const cap=await api.store.one('SELECT * FROM captures WHERE team_id=? AND id=? AND source_id=?',[auth.team_id,captureId,sourceId]);if(await expireStaging(api,auth.team_id,sourceId,captureId,'captures',cap))fail(409,'resync_required','capture reservation expired');if(!cap)fail(404,'not_found','capture not found');if(cap.state==='committed'){const receipt=JSON.parse(cap.receipt_json);if(receipt.digest!==commit.digest)fail(409,'capture_conflict','commit replay differs');receipt.duplicate=true;return send(res,200,result(api,auth,receipt),requestId);}const rows=await api.store.query('SELECT * FROM capture_parts WHERE team_id=? AND capture_id=? ORDER BY part_index',[auth.team_id,captureId]);if(rows.length!==commit.parts)fail(409,'batch_gap','capture parts incomplete');const begin=JSON.parse(cap.begin_json);if(source.kind==='connector'){const rule=await api.store.one('SELECT * FROM sync_rules WHERE team_id=? AND id=? AND source_id=? AND machine_id=?',[auth.team_id,begin.rule_id,sourceId,auth.machine_id]);if(!rule||rule.state!=='active'||rule.revision!==begin.rule_revision||rule.visibility!==begin.visibility)fail(rule?.state==='paused'?409:403,rule?.state==='paused'?'source_paused':'forbidden','sync rule changed before commit');}const parts=rows.map(x=>JSON.parse(x.payload_json));if(captureDigest(begin,parts,commit)!==commit.digest)fail(409,'capture_conflict','capture digest differs');let messages=captureMessages(parts);if(messages.length>100000)fail(413,'request_too_large','capture contains too many messages');
|
|
325
|
-
for(const manifest of commit.artifacts){validateArtifactName(manifest.relative_name);const upload=await api.store.one('SELECT source_id FROM uploads WHERE team_id=? AND id=?',[auth.team_id,manifest.upload_id]);if(!upload||upload.source_id!==sourceId)fail(409,'capture_conflict','artifact upload belongs to another source');const chunks=await api.store.query('SELECT
|
|
328
|
+
for(const manifest of commit.artifacts){validateArtifactName(manifest.relative_name);const upload=await api.store.one('SELECT source_id FROM uploads WHERE team_id=? AND id=?',[auth.team_id,manifest.upload_id]);if(!upload||upload.source_id!==sourceId)fail(409,'capture_conflict','artifact upload belongs to another source');const chunks=await api.store.query('SELECT chunk_index,bytes FROM artifact_chunks WHERE team_id=? AND upload_id=? UNION ALL SELECT r.chunk_index,b.bytes FROM artifact_chunk_refs r JOIN artifact_blobs b ON b.team_id=r.team_id AND b.sha256=r.sha256 WHERE r.team_id=? AND r.upload_id=? ORDER BY chunk_index',[auth.team_id,manifest.upload_id,auth.team_id,manifest.upload_id]);const bytes=Buffer.concat(chunks.map(x=>x.bytes));if(chunks.length!==manifest.chunks||bytes.length!==manifest.byte_length||sha256(bytes)!==manifest.sha256)fail(409,'capture_conflict','artifact manifest does not match staged chunks');}
|
|
326
329
|
if(commit.native_bundle!=null){const bundle=commit.native_bundle;exact(bundle,['id','harness','fidelity','residue','files'],'native_bundle');if(typeof bundle.id!=='string'||bundle.harness!==cap.harness||!['byte_lossless','value_lossless','semantic'].includes(bundle.fidelity)||!Array.isArray(bundle.residue)||!bundle.residue.every(x=>typeof x==='string')||!Array.isArray(bundle.files))fail(400,'invalid_request','invalid native bundle');const artifactIds=new Set(commit.artifacts.map(x=>x.upload_id)),seen=new Set();for(const file of bundle.files){exact(file,['upload_id','role'],'native_bundle file');if(!artifactIds.has(file.upload_id)||seen.has(file.upload_id)||!['primary','subagent','bundle','source_recovery'].includes(file.role))fail(400,'invalid_request','native bundle files must uniquely reference captured artifacts');seen.add(file.upload_id);}if(seen.size!==artifactIds.size||bundle.files.filter(x=>x.role==='primary').length!==1||new Set(commit.artifacts.map(x=>x.relative_name)).size!==commit.artifacts.length)fail(400,'invalid_request','native bundle must describe every unique artifact and one primary');}
|
|
327
330
|
let origin=await api.store.one('SELECT * FROM origins WHERE team_id=? AND source_id=? AND harness=? AND native_id=?',[auth.team_id,sourceId,cap.harness,cap.native_id]);
|
|
328
331
|
// A capture that carries (schema 9's wire half) names its first carry.count messages by digest instead of sending
|
|
@@ -20,7 +20,7 @@ export async function storageReport({ api, res, auth, url, requestId }) {
|
|
|
20
20
|
p.native_id,p.harness,p.captured_at,
|
|
21
21
|
json_extract(u.manifest_json,'$.role') role,json_extract(u.manifest_json,'$.media_type') media_type,
|
|
22
22
|
json_extract(u.manifest_json,'$.sha256') sha256,
|
|
23
|
-
(SELECT COALESCE(SUM(length(bytes)),0) FROM
|
|
23
|
+
((SELECT COALESCE(SUM(length(bytes)),0) FROM artifact_chunks c WHERE c.team_id=u.team_id AND c.upload_id=u.id) + (SELECT COALESCE(SUM(length(b.bytes)),0) FROM artifact_chunk_refs r JOIN artifact_blobs b ON b.team_id=r.team_id AND b.sha256=r.sha256 WHERE r.team_id=u.team_id AND r.upload_id=u.id)) bytes,
|
|
24
24
|
EXISTS (SELECT 1 FROM session_artifacts a WHERE a.team_id=u.team_id AND a.upload_id=u.id) version_referenced,
|
|
25
25
|
EXISTS (SELECT 1 FROM continuations c WHERE c.team_id=u.team_id AND instr(c.value_json,u.id)>0) continuation_referenced,
|
|
26
26
|
EXISTS (SELECT 1 FROM captures c WHERE c.team_id=u.team_id AND c.state='staging' AND instr(c.begin_json,u.id)>0) staging_referenced
|
package/server/store-core.mjs
CHANGED
|
@@ -111,7 +111,7 @@ export function createStoreHandlers({ all, get, run, tx }) {
|
|
|
111
111
|
const upload=get(`SELECT u.manifest_json FROM session_artifacts a JOIN uploads u ON u.team_id=a.team_id AND u.id=a.upload_id
|
|
112
112
|
WHERE a.team_id=? AND a.session_id=? AND a.upload_id=? AND u.committed=1`,[args.teamId,session.id,args.uploadId]);
|
|
113
113
|
if(!upload)domainError(404,'not_found','artifact not found');
|
|
114
|
-
const chunks=all('SELECT bytes FROM
|
|
114
|
+
const chunks=all('SELECT chunk_index,bytes FROM artifact_chunks WHERE team_id=? AND upload_id=? UNION ALL SELECT r.chunk_index,b.bytes FROM artifact_chunk_refs r JOIN artifact_blobs b ON b.team_id=r.team_id AND b.sha256=r.sha256 WHERE r.team_id=? AND r.upload_id=? ORDER BY chunk_index',[args.teamId,args.uploadId,args.teamId,args.uploadId]);
|
|
115
115
|
return {manifest:JSON.parse(upload.manifest_json),bytes:Buffer.concat(chunks.map(row=>row.bytes))};
|
|
116
116
|
});
|
|
117
117
|
return {
|