-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathbuild.ts
More file actions
313 lines (287 loc) · 11.9 KB
/
Copy pathbuild.ts
File metadata and controls
313 lines (287 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/**
* Tau Build Script
*
* Uses Bun's bundler to compile the CLI from TypeScript source into a
* single distributable JS file that runs on Node.js >=20.
*/
import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import { isAbsolute, join, resolve } from 'path';
const pkg = JSON.parse(readFileSync('./package.json', 'utf8'));
// Generate a master shim for all missing internal/ant assets
if (!existsSync('./dist')) {
mkdirSync('./dist');
}
const shimPath = resolve(process.cwd(), 'dist/shim.js');
writeFileSync(shimPath, `
export const checkProtectedNamespace = () => false;
export const checkProtectedCluster = () => false;
export const checkManagedSettingsSecurity = () => {};
export const handleSecurityCheckResult = () => {};
export const TungstenTool = null;
export const SuggestBackgroundPRTool = null;
export const VerifyPlanExecutionTool = null;
export const isConnectorTextBlock = () => false;
export const AgentTool = null;
export const initBundledWorkflows = () => {};
export const WorkflowTool = null;
export const run = () => {};
export const DESCRIPTION = '';
export const PROMPT = '';
export const getToolUseSummary = () => '';
export const renderToolUseMessage = () => null;
export const renderToolUseRejectedMessage = () => null;
export const renderToolUseErrorMessage = () => null;
export const renderToolResultMessage = () => null;
export const createClaudeForChromeMcpServer = () => {};
export const BROWSER_TOOLS = [];
export const COMPUTER_USE_TOOLS = [];
export const DEFAULT_UPLOAD_CONCURRENCY = 1;
export const FILE_COUNT_LIMIT = 100;
export const OUTPUTS_SUBDIR = 'outputs';
export const buildComputerUseTools = () => [];
export const isCoordinatorMode = () => false;
export class SandboxManager {
constructor() {}
start() {}
stop() {}
isEnabled() { return false; }
getViolations() { return []; }
static isSupportedPlatform() { return false; }
static checkDependencies() { return { supported: false }; }
static wrapWithSandbox(command) { return command; }
static async initialize() {}
static updateConfig() {}
static reset() {}
static getFsReadConfig() { return {}; }
static getFsWriteConfig() { return {}; }
static getNetworkRestrictionConfig() { return {}; }
static getIgnoreViolations() { return false; }
static getAllowUnixSockets() { return true; }
static getAllowLocalBinding() { return true; }
static getEnableWeakerNestedSandbox() { return false; }
static getProxyPort() { return 0; }
static getSocksProxyPort() { return 0; }
static getLinuxHttpSocketPath() { return ''; }
static getLinuxSocksSocketPath() { return ''; }
static async waitForNetworkInitialization() {}
static getSandboxViolationStore() { return new SandboxViolationStore(); }
static annotateStderrWithSandboxFailures(stderr) { return stderr; }
static cleanupAfterCommand() {}
}
export class SandboxViolationStore { constructor() {} getViolations() { return []; } clear() {} }
export const SandboxRuntimeConfigSchema = { parse: (v) => v, safeParse: (v) => ({ success: true, data: v }) };
export const runChromeNativeHost = () => {};
export const runComputerUseMcpServer = () => {};
export const runDaemonWorker = () => {};
export const daemonMain = () => {};
export const templatesMain = () => {};
export const environmentRunnerMain = () => {};
export const selfHostedRunnerMain = () => {};
const proxy = new Proxy({}, { get: () => () => {} });
export default proxy;
`);
const result = await Bun.build({
entrypoints: ['./src/entrypoints/cli.tsx'],
outdir: './dist',
target: 'node',
format: 'esm',
minify: false,
sourcemap: 'linked',
splitting: false,
naming: 'cli.mjs',
// Externalize all node_modules — they'll be resolved at runtime from
// the npm install. Only bundle our own source.
packages: 'external',
define: {
// Build-time MACRO constants
'MACRO.VERSION': JSON.stringify(pkg.version),
'MACRO.PACKAGE_URL': JSON.stringify(pkg.name),
'MACRO.NATIVE_PACKAGE_URL': JSON.stringify(pkg.name),
'MACRO.BUILD_TIME': JSON.stringify(new Date().toISOString()),
'MACRO.FEEDBACK_CHANNEL': JSON.stringify('https://github.com/AbdoKnbGit/tau/issues'),
'MACRO.ISSUES_EXPLAINER': JSON.stringify('report the issue at https://github.com/AbdoKnbGit/tau/issues'),
'process.env.USER_TYPE': JSON.stringify('external'),
},
plugins: [
{
name: 'tau-build',
setup(build) {
// Shim bun:bundle — feature() returns false for all features
// in external builds (removes ant-internal code paths)
build.onResolve({ filter: /^bun:bundle$/ }, () => ({
path: 'bun:bundle',
namespace: 'bun-bundle-shim',
}));
build.onLoad(
{ filter: /.*/, namespace: 'bun-bundle-shim' },
() => ({
contents: `export function feature(_name) { return false; }`,
loader: 'js',
}),
);
// Load .md files as text (used by skills/bundled/verifyContent.ts etc.)
build.onLoad({ filter: /\.md$/ }, (args) => {
try {
const contents = readFileSync(args.path, 'utf8');
return { contents: `export default ${JSON.stringify(contents)};`, loader: 'js' };
} catch {
return { contents: `export default '';`, loader: 'js' };
}
});
// Universal resolver to handle .js → .ts/tsx mapping AND shimming missing files
build.onResolve({ filter: /.*/ }, (args) => {
if (
args.path.startsWith('node:') ||
args.namespace === 'bun-bundle-shim'
) return;
// Handle color-diff-napi shim first
if (args.path === 'color-diff-napi') {
return { path: resolve(process.cwd(), 'src/native-ts/color-diff/index.ts') };
}
// react/compiler-runtime is provided by React 19+ — let it resolve
// from node_modules as an external package.
if (args.path === 'react/compiler-runtime') {
return;
}
let absPath: string;
if (args.path.startsWith('src/')) {
absPath = resolve(process.cwd(), args.path);
} else if (args.path.startsWith('.') || isAbsolute(args.path)) {
absPath = resolve(args.resolveDir, args.path);
} else if (args.path.startsWith('@ant/') || args.path.startsWith('@anthropic-ai/sandbox')) {
return { path: shimPath };
} else {
return; // Likely a node_module or external
}
const possiblePaths = [
absPath,
absPath.replace(/\.js$/, '.ts'),
absPath.replace(/\.js$/, '.tsx'),
absPath.replace(/\.js$/, '.d.ts'),
absPath.replace(/\.mjs$/, '.ts'),
absPath.replace(/\.mjs$/, '.tsx'),
absPath + '.ts',
absPath + '.tsx',
join(absPath, 'index.ts'),
join(absPath, 'index.tsx'),
join(absPath, 'index.js'),
];
for (const p of possiblePaths) {
try {
if (existsSync(p) && !lstatSync(p).isDirectory()) {
return { path: p };
}
} catch { /* ignore */ }
}
// If it's a missing file within OUR source or assets, shim it
const root = process.cwd();
if (absPath.startsWith(root) && !absPath.includes('node_modules')) {
return { path: shimPath };
}
});
},
},
],
});
if (!result.success) {
console.error('Build failed:');
for (const log of result.logs) {
console.error(log);
}
process.exit(1);
}
// Prepend shebang so `tau` works as a direct executable
const outPath = './dist/cli.mjs';
const code = readFileSync(outPath, 'utf8');
if (!code.startsWith('#!')) {
// Patch jsonc-parser ESM imports to use the UMD (CJS) build instead,
// which doesn't have extensionless import issues in Node.js strict ESM.
let patched = code;
// Disable the config-reading guard — external builds don't need it
patched = patched.replace(
/!configReadingAllowed && true/g,
'false'
);
// Disable remote version check — Tau has its own versioning
patched = patched.replace(
/async function assertMinVersion\(\)\s*\{/,
'async function assertMinVersion() { return;'
);
// Fix jsonc-parser ESM extensionless import issue → use UMD build
patched = patched.replace(
/from\s+"jsonc-parser[^"]*"/g,
'from "jsonc-parser/lib/umd/main.js"'
);
// Fix CJS/ESM interop: convert named imports from npm packages to
// default import + destructure. Node.js strict ESM doesn't support
// named exports from CJS modules.
// e.g. import { foo } from "pkg" → import __pkg0 from "pkg"; const { foo } = __pkg0;
const builtins = new Set([
'crypto','fs','path','os','process','child_process','events','http',
'https','net','stream','tty','url','util','buffer','async_hooks',
'dns','readline','v8','zlib','assert','perf_hooks','worker_threads',
'string_decoder','tls','module','cluster','dgram','domain','punycode',
'querystring','timers','vm','wasi','inspector','diagnostics_channel',
'trace_events','console',
]);
let shimCounter = 0;
// Handle combined default + named imports: import Foo, { bar } from "pkg"
patched = patched.replace(
/import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*"([^"]+)"/g,
(_match: string, defName: string, names: string, mod: string) => {
if (mod.startsWith('node:') || mod.startsWith('./') || mod.startsWith('../')) return _match;
const pkgName = mod.startsWith('@') ? mod.split('/').slice(0,2).join('/') : mod.split('/')[0];
if (builtins.has(pkgName)) return _match;
const cjsPackages2 = new Set([
'ajv','semver','shell-quote','qrcode','asciichart',
'vscode-jsonrpc',
'react','react-reconciler',
]);
if (!cjsPackages2.has(pkgName)) return _match;
const fixedNames = names.replace(/\bas\b/g, ':');
return `import ${defName} from "${mod}"; const {${fixedNames}} = ${defName}`;
}
);
// Handle pure named imports: import { bar } from "pkg"
patched = patched.replace(
/import\s*\{([^}]+)\}\s*from\s*"([^"]+)"/g,
(_match: string, names: string, mod: string) => {
// Skip node builtins and pure ESM packages (they work fine with named imports)
if (mod.startsWith('node:') || mod.startsWith('./') || mod.startsWith('../')) return _match;
const pkgName = mod.startsWith('@') ? mod.split('/').slice(0,2).join('/') : mod.split('/')[0];
if (builtins.has(pkgName)) return _match;
// Only fix CJS packages — pure ESM packages support named exports
// CJS packages that lack proper dual ESM exports and need default-import shim.
// Packages with "exports" conditional maps (import/require) are excluded
// because Node resolves them to proper ESM when imported from ESM context.
const cjsPackages = new Set([
'ajv','semver','shell-quote','qrcode','asciichart',
'vscode-jsonrpc',
'react','react-reconciler',
]);
if (!cjsPackages.has(pkgName)) return _match;
// Convert to default import + destructure
// Also convert `x as y` → `x: y` for destructuring syntax
const varName = `__cjs${shimCounter++}`;
const fixedNames = names.replace(/\bas\b/g, ':');
return `import ${varName} from "${mod}"; const {${fixedNames}} = ${varName}`;
}
);
// Polyfill React.useEffectEvent — available in React canary/internal builds
// but not in stable React 19. Provides a stable function ref that always
// calls the latest callback (used by React Compiler output).
const useEffectEventPolyfill = `
import React from "react";
if (!React.useEffectEvent) {
React.useEffectEvent = function useEffectEvent(fn) {
const ref = React.useRef(fn);
ref.current = fn;
return React.useCallback(function () {
return ref.current.apply(void 0, arguments);
}, []);
};
}
`;
writeFileSync(outPath, `#!/usr/bin/env node\n${useEffectEventPolyfill}${patched}`);
}
console.log(`✓ Built dist/cli.mjs (${(result.outputs[0]?.size / 1024 / 1024).toFixed(1)} MB)`);