Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions apps/web/scripts/install-preview.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ await mkdir(home, { recursive: true }); await mkdir(artifacts, { recursive: true
const tarballs = [];
const packages = [];
const shared = await sharedProfileFeatures();
for (const directory of ['../../packages/providers/identity-local', '../../packages/providers/browser-session', '../../packages/plugins/audit', '../../packages/plugins/access', ...shared.features.map(feature => feature.directory), '../../packages/plugins/activity', '../../packages/bundle']) {
// The shared plan addresses features from the repository root; every other entry
// here is relative to this app, so qualify the plan entries the same way.
for (const directory of ['../../packages/providers/identity-local', '../../packages/providers/browser-session', '../../packages/plugins/audit', '../../packages/plugins/access', ...shared.features.map(feature => `../../${feature.directory}`), '../../packages/plugins/activity', '../../packages/bundle']) {
const manifest = JSON.parse(await readFile(join(root, directory, 'package.json'), 'utf8'));
await access(join(root, directory, manifest.exports['.'].default));
await run('pnpm/bin/pnpm.cjs', ['--filter', manifest.name, 'pack', '--pack-destination', artifacts]);
Expand All @@ -52,13 +54,13 @@ for (const directory of ['../../packages/providers/identity-local', '../../packa
packages.push({ directory, manifest });
}
let initialized = false;
try { await access(join(home, '../../profiles/preview/package.json')); initialized = true; }
try { await access(join(home, 'profiles/preview/package.json')); initialized = true; }
catch (error) { if (error.code !== 'ENOENT') throw error; }
if (!initialized) await run('@deepseek-ai/dsh/lib/bin.js', ['--profile', 'preview', '--from-default-profile', 'web', '--dump-config']);
// Experts already contributes the official Team service, tools and Web action.
// The standalone Team profile adds the same loader ids again and can be toggled
// on from the upstream plugin gallery. Keep this preview's bundle list singular.
const previewManifestPath = join(home, '../../profiles/preview/package.json');
const previewManifestPath = join(home, 'profiles/preview/package.json');
const previewManifest = JSON.parse(await readFile(previewManifestPath, 'utf8'));
const normalizedManifest = withoutRedundantAgentTeamProfile(previewManifest);
if (normalizedManifest) {
Expand All @@ -83,15 +85,15 @@ if (!layersMatch) {
// Profiles disable automatic peer installation. The platform account adapter
// also needs its declared native account peer in this standalone runtime.
const installedVersion = async (name) => {
try { return JSON.parse(await readFile(join(home, '../../profiles/preview/node_modules/@deepseek-ai', name, 'package.json'), 'utf8')).version; }
try { return JSON.parse(await readFile(join(home, 'profiles/preview/node_modules/@deepseek-ai', name, 'package.json'), 'utf8')).version; }
catch (error) { if (error.code === 'ENOENT') return undefined; throw error; }
};
if (await installedVersion('dsh') !== cliVersion || await installedVersion('dsh-deepseek-account') !== cliVersion || await installedVersion('cordis-plugin-group') !== '1.0.4') {
await run('pnpm/bin/pnpm.cjs', ['--dir', join(home, '../../profiles/preview'), 'add', '--save-exact', `@deepseek-ai/dsh@${cliVersion}`, `@deepseek-ai/dsh-deepseek-account@${cliVersion}`, '@deepseek-ai/cordis-plugin-group@1.0.4']);
await run('pnpm/bin/pnpm.cjs', ['--dir', join(home, 'profiles/preview'), 'add', '--save-exact', `@deepseek-ai/dsh@${cliVersion}`, `@deepseek-ai/dsh-deepseek-account@${cliVersion}`, '@deepseek-ai/cordis-plugin-group@1.0.4']);
}
// DSH Profiles disable automatic peer installation. A fresh preview must
// install and upgrade the same official runtime peer closure as the release installer.
const profile = join(home, '../../profiles/preview');
const profile = join(home, 'profiles/preview');
const officialScope = join(profile, 'node_modules/@deepseek-ai');
for (let pass = 0; pass < 9; pass++) {
const missing = new Map();
Expand Down Expand Up @@ -139,16 +141,16 @@ if ((await officialResolutionDrift()).length) {
const drift = await officialResolutionDrift();
if (drift.length) throw new Error(`Official preview dependency resolution mismatch: ${drift.join('; ')}`);
}
const installedBase = JSON.parse(await readFile(join(home, '../../profiles/preview/node_modules/@deepseek-ai/dsh-base/package.json'), 'utf8'));
const installedBase = JSON.parse(await readFile(join(home, 'profiles/preview/node_modules/@deepseek-ai/dsh-base/package.json'), 'utf8'));
if (installedBase.version !== baseVersion) throw new Error(`Installed @deepseek-ai/dsh-base ${installedBase.version} does not match pinned ${baseVersion}.`);
const installedWebApp = JSON.parse(await readFile(join(home, '../../profiles/preview/node_modules/@deepseek-ai/dsh-web-app/package.json'), 'utf8'));
const installedWebApp = JSON.parse(await readFile(join(home, 'profiles/preview/node_modules/@deepseek-ai/dsh-web-app/package.json'), 'utf8'));
if (installedWebApp.version !== webAppVersion) throw new Error(`Installed @deepseek-ai/dsh-web-app ${installedWebApp.version} does not match pinned ${webAppVersion}.`);
// DSH scopes are module-instance local. Installing only the Web bundle
// beside a CLI-provided Base bundle can load two physical dsh-scope copies: the
// Agent consumers must resolve one shared scope module; otherwise new
// session fails as an "unscoped context". Resolve both consumers from the
// Profile and fail installation unless they share the exact same module file.
const profileRequire = createRequire(join(home, '../../profiles/preview/package.json'));
const profileRequire = createRequire(join(home, 'profiles/preview/package.json'));
const resolveProfileDependency = async (consumer, dependency) => {
const consumerManifest = profileRequire.resolve(`${consumer}/package.json`);
const consumerRequire = createRequire(consumerManifest);
Expand All @@ -165,7 +167,7 @@ for (const { directory, manifest } of packages) {
const entry = manifest.exports[face]?.default;
if (!entry) continue;
const expected = await readFile(join(root, directory, entry));
const installed = await readFile(join(home, '../../profiles/preview/node_modules', manifest.name, entry));
const installed = await readFile(join(home, 'profiles/preview/node_modules', manifest.name, entry));
if (!expected.equals(installed)) throw new Error(`Installed ${manifest.name} ${face} differs from the current build; refusing to report a successful preview update.`);
}
}
Expand Down
12 changes: 6 additions & 6 deletions apps/web/scripts/install-project-release.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ if (actualHarness !== expectedHarness) {
throw new Error(`WorkDSH ${manifest.version} requires dsh ${expectedHarness}; found ${actualHarness || 'unknown'}. Pass --dsh /absolute/path/to/a-compatible-dsh.`);
}

const profileManifest = join(dshHome, '../../profiles', profile, 'package.json');
const profileManifest = join(dshHome, 'profiles', profile, 'package.json');
if (existsSync(profileManifest)) {
console.log(`Existing profile ${profile} detected; preserving its configuration and stored data.`);
execute(['--profile', profile, '--dump-config']);
Expand All @@ -101,7 +101,7 @@ if (!dryRun && existsSync(profileManifest) && /^pnpm@\d+\.\d+\.\d+$/.test(manife
writeFileSync(profileManifest, JSON.stringify(profilePackage, null, 2) + '\n');
}

const workspaceFile = join(dshHome, '../../profiles', profile, 'pnpm-workspace.yaml');
const workspaceFile = join(dshHome, 'profiles', profile, 'pnpm-workspace.yaml');
if (!dryRun && existsSync(workspaceFile)) {
let current = readFileSync(workspaceFile, 'utf8');
// Native helpers are required by the official runtime; the other two scripts
Expand Down Expand Up @@ -157,7 +157,7 @@ for (const name of installOrder) {
}

// Keep CLI and ConfigEditor in the same Profile dependency graph (0.1.7).
const runtimeArgs = ['pnpm', '--dir', join(dshHome, '../../profiles', profile), 'add', '--save-exact', `@deepseek-ai/dsh@${expectedHarness}`, `@deepseek-ai/dsh-deepseek-account@${expectedHarness}`, '@deepseek-ai/cordis-plugin-group@1.0.4'];
const runtimeArgs = ['pnpm', '--dir', join(dshHome, 'profiles', profile), 'add', '--save-exact', `@deepseek-ai/dsh@${expectedHarness}`, `@deepseek-ai/dsh-deepseek-account@${expectedHarness}`, '@deepseek-ai/cordis-plugin-group@1.0.4'];
console.log(`> ${corepack} ${runtimeArgs.join(' ')}`);
if (!dryRun) {
const result = spawnSync(corepack, runtimeArgs, { stdio: 'inherit' });
Expand All @@ -168,7 +168,7 @@ if (!dryRun) {
// are bundled and not published to npm. Install the official runtime peer closure
// explicitly so a clean Profile can boot without relying on the developer repo.
if (!dryRun) {
const scope = join(dshHome, '../../profiles', profile, 'node_modules', '@deepseek-ai');
const scope = join(dshHome, 'profiles', profile, 'node_modules', '@deepseek-ai');
for (let pass = 0; existsSync(scope); pass++) {
const missing = new Map();
for (const entry of readdirSync(scope)) {
Expand All @@ -184,11 +184,11 @@ if (!dryRun) {
}
if (!missing.size) break;
if (pass >= 8) throw new Error('Official runtime peer dependencies did not converge.');
const result = spawnSync(corepack, ['pnpm', '--dir', join(dshHome, '../../profiles', profile), 'add', '--save-exact', ...missing.values()], { stdio: 'inherit' });
const result = spawnSync(corepack, ['pnpm', '--dir', join(dshHome, 'profiles', profile), 'add', '--save-exact', ...missing.values()], { stdio: 'inherit' });
if (result.error) throw result.error;
if (result.status !== 0) process.exit(result.status ?? 1);
}
}
const profileCli = join(dshHome, '../../profiles', profile, 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js');
const profileCli = join(dshHome, 'profiles', profile, 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js');
console.log(`\nWorkDSH ${manifest.version} ${dryRun ? 'installation plan verified' : 'is installed'} in profile ${profile}.`);
console.log(`Start it with: node ${JSON.stringify(profileCli)} --profile ${JSON.stringify(profile)}`);
4 changes: 2 additions & 2 deletions apps/web/scripts/probe-activity.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ await mkdir(cwd,{recursive:true});await mkdir(join(home,'storages'),{recursive:t
await writeFile(join(home,'storages/workspace.json'),JSON.stringify({unit:{name:'workspace',version:2},global:{initialized:true,workspaceIds:[workspaceId],archivedSessionIds:[]},tables:{workspaces:{[workspaceId]:{path:cwd,title:'Activity fixture',sessionIds:[id],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}}}}));
const dir=join(home,'sessions','--'+cwd.replaceAll('/','-').replace(/^-+/, '')+'--',id);await mkdir(dir,{recursive:true});
const disabled=process.argv.includes('--disabled');
await writeFile(join(home,'../../profiles/preview/cordis.patch.yml'),disabled ? '- id: workdsh-activity\n disabled: true\n' : '[]\n');
await writeFile(join(home,'profiles/preview/cordis.patch.yml'),disabled ? '- id: workdsh-activity\n disabled: true\n' : '[]\n');
const now=Date.now();const rows=[{type:'session',version:3,id,createdAt:now,cwd,isSeeded:false,delegationDepth:0,agentPreset:'dsh-base'},
{type:'turn/start',seq:0,time:now,data:{turn:1}},
{type:'user/message',seq:1,time:now,data:{role:'user',id:'fixture-user',source:{kind:'user'},content:[{type:'text',text:'Activity plugin verification'}]},surfaceOp:'append'},
Expand Down Expand Up @@ -44,4 +44,4 @@ assert.ok((await page.locator('body').innerText()).includes('Native conversation
await mkdir(join(root,'.artifacts/activity'),{recursive:true});await page.screenshot({path:join(root,'.artifacts/activity/browser.png')});
console.log('PASS: official Profile/Client load; one 46px bar; native body retained; animation off persists; system reduced-motion; Escape; no browser errors.');
}
}finally{await browser?.close();if(server.exitCode===null){const closed=new Promise(r=>server.once('close',r));server.kill('SIGTERM');const timer=setTimeout(()=>server.kill('SIGKILL'),5000);await closed;clearTimeout(timer);}await writeFile(join(home,'../../profiles/preview/cordis.patch.yml'),'[]\n');}
}finally{await browser?.close();if(server.exitCode===null){const closed=new Promise(r=>server.once('close',r));server.kill('SIGTERM');const timer=setTimeout(()=>server.kill('SIGKILL'),5000);await closed;clearTimeout(timer);}await writeFile(join(home,'profiles/preview/cordis.patch.yml'),'[]\n');}
2 changes: 1 addition & 1 deletion apps/web/scripts/probe-connectors-personal-browser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { chromium, expect } from '@playwright/test';
const root = new URL('../', import.meta.url).pathname;
const home = await realpath(process.argv[2]);
assert.match(home, /^\/private\/tmp\/workdsh-experts-package-[\w-]+$/);
const profile = join(home, '../../profiles/experts');
const profile = join(home, 'profiles/experts');
const manifest = JSON.parse(await readFile(join(profile, 'package.json'), 'utf8'));
assert.ok(!JSON.stringify(manifest).includes('enterprise'));
const artifacts = join(root, '.artifacts/connectors-personal-browser');
Expand Down
2 changes: 1 addition & 1 deletion apps/web/scripts/probe-native-team-web.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ try {
await command(pnpm, ['pack', '--pack-destination', artifacts], fixture); tarballs.push(join(artifacts, 'workdsh-native-team-probe-0.0.0.tgz'));
await command(dsh, ['--profile', 'native-team', '--from-default-profile', 'web', '--dump-config']);
await command(dsh, ['plugin', '--profile', 'native-team', 'add', `@deepseek-ai/dsh-base@${dshVersion}`, `@deepseek-ai/dsh-web-app@${dshVersion}`, ...tarballs, '--prefer-offline']);
const profilePatch = join(home, '../../profiles/native-team/cordis.patch.yml');
const profilePatch = join(home, 'profiles/native-team/cordis.patch.yml');
const browserOverride = '- id: browser-use-playwright-mcp\n disabled: true\n';
await writeFile(profilePatch, browserOverride);
pass('seven-independent-packages-installed-via-official-cli');
Expand Down
2 changes: 1 addition & 1 deletion apps/web/scripts/probe-office-live.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ export function apply(ctx){ctx.effect(()=>ctx.connection.fetch.register({path:'/
"web",
"--dump-config",
);
const profileManifest=join(home,'../../profiles/office/package.json');
const profileManifest=join(home,'profiles/office/package.json');
const profileJson=JSON.parse(await readFile(profileManifest,'utf8'));profileJson.packageManager='pnpm@10.34.5';await writeFile(profileManifest,JSON.stringify(profileJson,null,2)+'\n');
for(let i=0;i<tarballs.length;i++){
const digest=createHash('sha256').update(await readFile(tarballs[i])).digest('hex');
Expand Down
4 changes: 2 additions & 2 deletions apps/web/scripts/probe-personal-default-install.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ try{
await writeFile(join(assets,'release-manifest.json'),JSON.stringify({version:'unreleased-default-probe',harness:project.devDependencies['@deepseek-ai/dsh'],packageManager:project.packageManager,runtimeOverrides:Object.fromEntries(Object.entries(project.pnpm.overrides).filter(([name])=>name.startsWith('@deepseek-ai/'))),packages,installation:{defaultPackages:packages.map(p=>p.name)}}));
const wrapper=join(home,'dsh');await writeFile(wrapper,`#!/bin/sh\nexec '${process.execPath}' '${cli}' "$@"\n`,{mode:0o700});
await run(process.execPath,[join(root,'scripts/install-project-release.mjs'),'--directory',assets,'--profile','personal','--dsh',wrapper]);
const profile=JSON.parse(await readFile(join(home,'../../profiles/personal/package.json'),'utf8'));
const profile=JSON.parse(await readFile(join(home,'profiles/personal/package.json'),'utf8'));
for(const name of packages.map(p=>p.name))assert.ok(profile.dependencies[name],name);
for(const name of ['workdsh-plugin-office','workdsh-plugin-projects','workdsh-plugin-activity','workdsh-provider-identity-enterprise','workdsh-plugin-enterprise-collaboration'])assert.ok(!profile.dependencies[name],name);
pass('Actual source installer creates a fresh personal Profile with only the default owned package set');
server=spawn(process.execPath,[join(home,'../../profiles/personal/node_modules/@deepseek-ai/dsh/lib/bin.js'),'--profile','personal','--host','127.0.0.1','--port','0','--no-open'],{cwd:home,env,stdio:['ignore','pipe','pipe']});
server=spawn(process.execPath,[join(home,'profiles/personal/node_modules/@deepseek-ai/dsh/lib/bin.js'),'--profile','personal','--host','127.0.0.1','--port','0','--no-open'],{cwd:home,env,stdio:['ignore','pipe','pipe']});
server.stdout.on('data',b=>{log+=b;});server.stderr.on('data',b=>{log+=b;});
let host;
for(let until=Date.now()+45000;Date.now()<until;){
Expand Down
4 changes: 2 additions & 2 deletions apps/web/scripts/probe-personal-default-objects.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { spawn } from 'node:child_process';
const root=new URL('../',import.meta.url).pathname,evidence=join(root,'.artifacts/plugin-delivery');
const baseline=JSON.parse(await readFile(join(evidence,'personal-default-runtime.json'),'utf8'));
const home=await realpath(baseline.home);assert.match(home,/\/T\/workdsh-personal-default-[\w-]+$/);
const profile=JSON.parse(await readFile(join(home,'../../profiles/personal/package.json'),'utf8'));assert.ok(!JSON.stringify(profile).includes('enterprise'));
const profile=JSON.parse(await readFile(join(home,'profiles/personal/package.json'),'utf8'));assert.ok(!JSON.stringify(profile).includes('enterprise'));
const env={PATH:`${root}/node_modules/.bin:${dirname(process.execPath)}:/usr/bin:/bin`,HOME:process.env.HOME,DSH_HOME:home,DSH_AGENTS_HOME:join(home,'agents')};
let server,host;const checks=[];
async function stop(){if(!server||server.exitCode!==null||server.signalCode!==null)return;const closed=new Promise(r=>server.once('close',r));server.kill('SIGTERM');const timer=setTimeout(()=>server.kill('SIGKILL'),3000);await closed;clearTimeout(timer);}
async function start(){let log='';server=spawn(process.execPath,[join(home,'../../profiles/personal/node_modules/@deepseek-ai/dsh/lib/bin.js'),'--profile','personal','--host','127.0.0.1','--port','0','--no-open'],{cwd:home,env,stdio:['ignore','pipe','pipe']});server.stdout.on('data',b=>{log+=b;});server.stderr.on('data',b=>{log+=b;});
async function start(){let log='';server=spawn(process.execPath,[join(home,'profiles/personal/node_modules/@deepseek-ai/dsh/lib/bin.js'),'--profile','personal','--host','127.0.0.1','--port','0','--no-open'],{cwd:home,env,stdio:['ignore','pipe','pipe']});server.stdout.on('data',b=>{log+=b;});server.stderr.on('data',b=>{log+=b;});
for(let until=Date.now()+45000;Date.now()<until;){const match=log.match(/http:\/\/127\.0\.0\.1:\d+\/\?token=[\w-]+/);if(match)try{const response=await fetch(match[0],{redirect:'manual',signal:AbortSignal.timeout(1500)}),cookie=response.headers.getSetCookie().map(x=>x.split(';')[0]).join('; ');if(cookie){host={address:new URL(match[0]).origin,cookie};return;}}catch{}if(server.exitCode!==null)break;await new Promise(r=>setTimeout(r,100));}throw new Error('Owned personal Host startup failed');}
async function api(domain,endpoint,payload={}){const response=await fetch(host.address+'/api/workdsh-'+domain,{method:'POST',headers:{cookie:host.cookie,'content-type':'application/json'},body:JSON.stringify({endpoint,payload}),signal:AbortSignal.timeout(15000)});assert.equal(response.status,200);const result=await response.json();assert.equal(result.ok,true,JSON.stringify(result.error));return result.value;}
const pass=text=>{checks.push(text);console.log('PASS: '+text);};
Expand Down
4 changes: 2 additions & 2 deletions apps/web/scripts/probe-personal-project-lifecycle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ const root=new URL('../',import.meta.url).pathname,evidence=join(root,'.artifact
const baseline=JSON.parse(await readFile(join(evidence,'personal-default-runtime.json'),'utf8'));
const home=await realpath(baseline.home);
assert.match(home,/\/T\/workdsh-personal-default-[\w-]+$/);
const manifestPath=join(home,'../../profiles/personal/package.json');
const manifestPath=join(home,'profiles/personal/package.json');
const before=JSON.parse(await readFile(manifestPath,'utf8'));assert.ok(!before.dependencies['workdsh-plugin-projects']);
const env={PATH:`${root}/node_modules/.bin:${dirname(process.execPath)}:/usr/bin:/bin`,HOME:process.env.HOME,DSH_HOME:home,DSH_AGENTS_HOME:join(home,'agents'),npm_config_offline:'true'};
const cli=join(home,'../../profiles/personal/node_modules/@deepseek-ai/dsh/lib/bin.js'),exec=promisify(execFile);
const cli=join(home,'profiles/personal/node_modules/@deepseek-ai/dsh/lib/bin.js'),exec=promisify(execFile);
const run=async(args)=>exec(process.execPath,[cli,...args],{cwd:home,env,timeout:120000,maxBuffer:8*1024*1024});
const checks=[];let server,browser,log='';
async function stop(){await browser?.close();browser=undefined;if(!server||server.exitCode!==null||server.signalCode!==null)return;const done=new Promise(r=>server.once('close',r));server.kill('SIGTERM');const timer=setTimeout(()=>server.kill('SIGKILL'),3000);await done;clearTimeout(timer);}
Expand Down
Loading