Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f76f34049 | |||
| 7c5cd693ce | |||
| c9ed5e41b1 | |||
| 8ae5b56b5b | |||
| 1b265f343f | |||
| fd5c103f99 | |||
| cdc602edd7 | |||
| 782bb4e4bd | |||
| 94f9480a3a | |||
| 9364dd8a49 | |||
| 6d48a12efe | |||
| beab7cc053 | |||
| 6cade3eaec | |||
| c8d18eb2ac |
@@ -2,7 +2,7 @@
|
||||
"experimental": {
|
||||
"extensionReloading": true,
|
||||
"modelSteering": true,
|
||||
"memoryManager": true,
|
||||
"memoryManager": false,
|
||||
"topicUpdateNarration": true
|
||||
},
|
||||
"general": {
|
||||
|
||||
@@ -346,9 +346,11 @@ npm run lint
|
||||
|
||||
- Please adhere to the coding style, patterns, and conventions used throughout
|
||||
the existing codebase.
|
||||
- Consult [GEMINI.md](../GEMINI.md) (typically found in the project root) for
|
||||
specific instructions related to AI-assisted development, including
|
||||
conventions for React, comments, and Git usage.
|
||||
- Consult
|
||||
[GEMINI.md](https://github.com/google-gemini/gemini-cli/blob/main/GEMINI.md)
|
||||
(typically found in the project root) for specific instructions related to
|
||||
AI-assisted development, including conventions for React, comments, and Git
|
||||
usage.
|
||||
- **Imports:** Pay special attention to import paths. The project uses ESLint to
|
||||
enforce restrictions on relative imports between packages.
|
||||
|
||||
@@ -505,8 +507,9 @@ code.
|
||||
|
||||
### Documentation structure
|
||||
|
||||
Our documentation is organized using [sidebar.json](/docs/sidebar.json) as the
|
||||
table of contents. When adding new documentation:
|
||||
Our documentation is organized using
|
||||
[sidebar.json](https://github.com/google-gemini/gemini-cli/blob/main/docs/sidebar.json)
|
||||
as the table of contents. When adding new documentation:
|
||||
|
||||
1. Create your markdown file **in the appropriate directory** under `/docs`.
|
||||
2. Add an entry to `sidebar.json` in the relevant section.
|
||||
|
||||
|
After Width: | Height: | Size: 54 KiB |
@@ -19,6 +19,7 @@ using the `/theme` command within Gemini CLI:
|
||||
- `Holiday`
|
||||
- `Shades Of Purple`
|
||||
- `Solarized Dark`
|
||||
- `Tokyo Night`
|
||||
- **Light themes:**
|
||||
- `ANSI Light`
|
||||
- `Ayu Light`
|
||||
@@ -252,6 +253,10 @@ identify their source, for example: `shades-of-green (green-extension)`.
|
||||
|
||||
<img src="/docs/assets/theme-solarized-dark.png" alt="Solarized Dark theme" width="600">
|
||||
|
||||
### Tokyo Night
|
||||
|
||||
<img src="/docs/assets/theme-tokyonight-dark.png" alt="Tokyo Night theme" width="600">
|
||||
|
||||
## Light themes
|
||||
|
||||
### ANSI Light
|
||||
|
||||
@@ -1647,7 +1647,7 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
|
||||
- **`experimental.jitContext`** (boolean):
|
||||
- **Description:** Enable Just-In-Time (JIT) context loading.
|
||||
- **Default:** `true`
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.useOSC52Paste`** (boolean):
|
||||
|
||||
@@ -419,20 +419,6 @@ decision = "ask_user"
|
||||
priority = 10
|
||||
```
|
||||
|
||||
**4. Targeting a tool name across all servers**
|
||||
|
||||
Use `mcpName = "*"` with a specific `toolName` to target that operation
|
||||
regardless of which server provides it.
|
||||
|
||||
```toml
|
||||
# Allow the `search` tool across all connected MCP servers
|
||||
[[rule]]
|
||||
mcpName = "*"
|
||||
toolName = "search"
|
||||
decision = "allow"
|
||||
priority = 50
|
||||
```
|
||||
|
||||
## Default policies
|
||||
|
||||
The Gemini CLI ships with a set of default policies to provide a safe
|
||||
|
||||
@@ -283,4 +283,47 @@ describe('plan_mode', () => {
|
||||
assertModelHasOutput(result);
|
||||
},
|
||||
});
|
||||
|
||||
evalTest('ALWAYS_PASSES', {
|
||||
name: 'should transition from plan mode to normal execution and create a plan file from scratch',
|
||||
params: {
|
||||
settings,
|
||||
},
|
||||
prompt:
|
||||
'Enter plan mode and plan to create a new module called foo. The plan should be saved as foo-plan.md. Then, exit plan mode.',
|
||||
assert: async (rig, result) => {
|
||||
const enterPlanCalled = await rig.waitForToolCall('enter_plan_mode');
|
||||
expect(
|
||||
enterPlanCalled,
|
||||
'Expected enter_plan_mode tool to be called',
|
||||
).toBe(true);
|
||||
|
||||
const exitPlanCalled = await rig.waitForToolCall('exit_plan_mode');
|
||||
expect(exitPlanCalled, 'Expected exit_plan_mode tool to be called').toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
await rig.waitForTelemetryReady();
|
||||
const toolLogs = rig.readToolLogs();
|
||||
|
||||
// Check if the plan file was written successfully
|
||||
const planWrite = toolLogs.find(
|
||||
(log) =>
|
||||
log.toolRequest.name === 'write_file' &&
|
||||
log.toolRequest.args.includes('foo-plan.md'),
|
||||
);
|
||||
|
||||
expect(
|
||||
planWrite,
|
||||
'Expected write_file to be called for foo-plan.md',
|
||||
).toBeDefined();
|
||||
|
||||
expect(
|
||||
planWrite?.toolRequest.success,
|
||||
`Expected write_file to succeed, but got error: ${planWrite?.toolRequest.error}`,
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,8 +10,13 @@ import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'node:fs';
|
||||
import { env } from 'node:process';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
|
||||
// Browser agent Chrome DevTools MCP connection is flaky in Docker sandbox.
|
||||
// See: https://github.com/google-gemini/gemini-cli/issues/24382
|
||||
const isDockerSandbox = env['GEMINI_SANDBOX'] === 'docker';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
@@ -59,122 +64,128 @@ describe.skipIf(!chromeAvailable)('browser-policy', () => {
|
||||
await rig.cleanup();
|
||||
});
|
||||
|
||||
it('should skip confirmation when "Allow all server tools for this session" is chosen', async () => {
|
||||
rig.setup('browser-policy-skip-confirmation', {
|
||||
fakeResponsesPath: join(__dirname, 'browser-policy.responses'),
|
||||
settings: {
|
||||
agents: {
|
||||
overrides: {
|
||||
browser_agent: {
|
||||
enabled: true,
|
||||
it.skipIf(isDockerSandbox)(
|
||||
'should skip confirmation when "Allow all server tools for this session" is chosen',
|
||||
async () => {
|
||||
rig.setup('browser-policy-skip-confirmation', {
|
||||
fakeResponsesPath: join(__dirname, 'browser-policy.responses'),
|
||||
settings: {
|
||||
agents: {
|
||||
overrides: {
|
||||
browser_agent: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
browser: {
|
||||
headless: true,
|
||||
sessionMode: 'isolated',
|
||||
allowedDomains: ['example.com'],
|
||||
},
|
||||
},
|
||||
browser: {
|
||||
headless: true,
|
||||
sessionMode: 'isolated',
|
||||
allowedDomains: ['example.com'],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Manually trust the folder to avoid the dialog and enable option 3
|
||||
const geminiDir = join(rig.homeDir!, '.gemini');
|
||||
mkdirSync(geminiDir, { recursive: true });
|
||||
// Manually trust the folder to avoid the dialog and enable option 3
|
||||
const geminiDir = join(rig.homeDir!, '.gemini');
|
||||
mkdirSync(geminiDir, { recursive: true });
|
||||
|
||||
// Write to trustedFolders.json
|
||||
const trustedFoldersPath = join(geminiDir, 'trustedFolders.json');
|
||||
const trustedFolders = {
|
||||
[rig.testDir!]: 'TRUST_FOLDER',
|
||||
};
|
||||
writeFileSync(trustedFoldersPath, JSON.stringify(trustedFolders, null, 2));
|
||||
// Write to trustedFolders.json
|
||||
const trustedFoldersPath = join(geminiDir, 'trustedFolders.json');
|
||||
const trustedFolders = {
|
||||
[rig.testDir!]: 'TRUST_FOLDER',
|
||||
};
|
||||
writeFileSync(
|
||||
trustedFoldersPath,
|
||||
JSON.stringify(trustedFolders, null, 2),
|
||||
);
|
||||
|
||||
// Force confirmation for browser agent.
|
||||
// NOTE: We don't force confirm browser tools here because "Allow all server tools"
|
||||
// adds a rule with ALWAYS_ALLOW_PRIORITY (3.9x) which would be overshadowed by
|
||||
// a rule in the user tier (4.x) like the one from this TOML.
|
||||
// By removing the explicit mcp rule, the first MCP tool will still prompt
|
||||
// due to default approvalMode = 'default', and then "Allow all" will correctly
|
||||
// bypass subsequent tools.
|
||||
const policyFile = join(rig.testDir!, 'force-confirm.toml');
|
||||
writeFileSync(
|
||||
policyFile,
|
||||
`
|
||||
// Force confirmation for browser agent.
|
||||
// NOTE: We don't force confirm browser tools here because "Allow all server tools"
|
||||
// adds a rule with ALWAYS_ALLOW_PRIORITY (3.9x) which would be overshadowed by
|
||||
// a rule in the user tier (4.x) like the one from this TOML.
|
||||
// By removing the explicit mcp rule, the first MCP tool will still prompt
|
||||
// due to default approvalMode = 'default', and then "Allow all" will correctly
|
||||
// bypass subsequent tools.
|
||||
const policyFile = join(rig.testDir!, 'force-confirm.toml');
|
||||
writeFileSync(
|
||||
policyFile,
|
||||
`
|
||||
[[rule]]
|
||||
name = "Force confirm browser_agent"
|
||||
toolName = "browser_agent"
|
||||
decision = "ask_user"
|
||||
priority = 200
|
||||
`,
|
||||
);
|
||||
);
|
||||
|
||||
// Update settings.json in both project and home directories to point to the policy file
|
||||
for (const baseDir of [rig.testDir!, rig.homeDir!]) {
|
||||
const settingsPath = join(baseDir, '.gemini', 'settings.json');
|
||||
if (existsSync(settingsPath)) {
|
||||
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
settings.policyPaths = [policyFile];
|
||||
// Ensure folder trust is enabled
|
||||
settings.security = settings.security || {};
|
||||
settings.security.folderTrust = settings.security.folderTrust || {};
|
||||
settings.security.folderTrust.enabled = true;
|
||||
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
||||
// Update settings.json in both project and home directories to point to the policy file
|
||||
for (const baseDir of [rig.testDir!, rig.homeDir!]) {
|
||||
const settingsPath = join(baseDir, '.gemini', 'settings.json');
|
||||
if (existsSync(settingsPath)) {
|
||||
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
settings.policyPaths = [policyFile];
|
||||
// Ensure folder trust is enabled
|
||||
settings.security = settings.security || {};
|
||||
settings.security.folderTrust = settings.security.folderTrust || {};
|
||||
settings.security.folderTrust.enabled = true;
|
||||
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const run = await rig.runInteractive({
|
||||
approvalMode: 'default',
|
||||
env: {
|
||||
GEMINI_CLI_INTEGRATION_TEST: 'true',
|
||||
},
|
||||
});
|
||||
const run = await rig.runInteractive({
|
||||
approvalMode: 'default',
|
||||
env: {
|
||||
GEMINI_CLI_INTEGRATION_TEST: 'true',
|
||||
},
|
||||
});
|
||||
|
||||
await run.sendKeys(
|
||||
'Open https://example.com and check if there is a heading\r',
|
||||
);
|
||||
await run.sendKeys('\r');
|
||||
await run.sendKeys(
|
||||
'Open https://example.com and check if there is a heading\r',
|
||||
);
|
||||
await run.sendKeys('\r');
|
||||
|
||||
// Handle confirmations.
|
||||
// 1. Initial browser_agent delegation (likely only 3 options, so use option 1: Allow once)
|
||||
await poll(
|
||||
() => stripAnsi(run.output).toLowerCase().includes('action required'),
|
||||
60000,
|
||||
1000,
|
||||
);
|
||||
await run.sendKeys('1\r');
|
||||
await new Promise((r) => setTimeout(r, 2000));
|
||||
// Handle confirmations.
|
||||
// 1. Initial browser_agent delegation (likely only 3 options, so use option 1: Allow once)
|
||||
await poll(
|
||||
() => stripAnsi(run.output).toLowerCase().includes('action required'),
|
||||
60000,
|
||||
1000,
|
||||
);
|
||||
await run.sendKeys('1\r');
|
||||
await new Promise((r) => setTimeout(r, 2000));
|
||||
|
||||
// Handle privacy notice
|
||||
await poll(
|
||||
() => stripAnsi(run.output).toLowerCase().includes('privacy notice'),
|
||||
5000,
|
||||
100,
|
||||
);
|
||||
await run.sendKeys('1\r');
|
||||
await new Promise((r) => setTimeout(r, 5000));
|
||||
// Handle privacy notice
|
||||
await poll(
|
||||
() => stripAnsi(run.output).toLowerCase().includes('privacy notice'),
|
||||
5000,
|
||||
100,
|
||||
);
|
||||
await run.sendKeys('1\r');
|
||||
await new Promise((r) => setTimeout(r, 5000));
|
||||
|
||||
// new_page (MCP tool, should have 4 options, use option 3: Allow all server tools)
|
||||
await poll(
|
||||
() => {
|
||||
const stripped = stripAnsi(run.output).toLowerCase();
|
||||
return (
|
||||
stripped.includes('new_page') &&
|
||||
stripped.includes('allow all server tools for this session')
|
||||
);
|
||||
},
|
||||
60000,
|
||||
1000,
|
||||
);
|
||||
// new_page (MCP tool, should have 4 options, use option 3: Allow all server tools)
|
||||
await poll(
|
||||
() => {
|
||||
const stripped = stripAnsi(run.output).toLowerCase();
|
||||
return (
|
||||
stripped.includes('new_page') &&
|
||||
stripped.includes('allow all server tools for this session')
|
||||
);
|
||||
},
|
||||
60000,
|
||||
1000,
|
||||
);
|
||||
|
||||
// Select "Allow all server tools for this session" (option 3)
|
||||
await run.sendKeys('3\r');
|
||||
await new Promise((r) => setTimeout(r, 30000));
|
||||
// Select "Allow all server tools for this session" (option 3)
|
||||
await run.sendKeys('3\r');
|
||||
await new Promise((r) => setTimeout(r, 30000));
|
||||
|
||||
const output = stripAnsi(run.output).toLowerCase();
|
||||
const output = stripAnsi(run.output).toLowerCase();
|
||||
|
||||
expect(output).toContain('browser_agent');
|
||||
expect(output).toContain('completed successfully');
|
||||
});
|
||||
expect(output).toContain('browser_agent');
|
||||
expect(output).toContain('completed successfully');
|
||||
},
|
||||
);
|
||||
|
||||
it('should show the visible warning when browser agent starts in existing session mode', async () => {
|
||||
rig.setup('browser-session-warning', {
|
||||
|
||||
@@ -121,6 +121,7 @@ describe('file-system', () => {
|
||||
|
||||
const result = await rig.run({
|
||||
args: `write "hello" to "${fileName}" and then stop. Do not perform any other actions.`,
|
||||
timeout: 600000, // 10 min — real LLM can be slow in Docker sandbox
|
||||
});
|
||||
|
||||
const foundToolCall = await rig.waitForToolCall('write_file');
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"ink": "npm:@jrichman/ink@6.5.0",
|
||||
"ink": "npm:@jrichman/ink@6.6.3",
|
||||
"latest-version": "^9.0.0",
|
||||
"node-fetch-native": "^1.6.7",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
@@ -92,46 +92,6 @@
|
||||
"zod": "^3.25.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alcalzone/ansi-tokenize": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.2.2.tgz",
|
||||
"integrity": "sha512-mkOh+Wwawzuf5wa30bvc4nA+Qb6DIrGWgBhRR/Pw4T9nsgYait8izvXkNyU78D6Wcu3Z+KUdwCmLCxlWjEotYA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"is-fullwidth-code-point": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@alcalzone/ansi-tokenize/node_modules/is-fullwidth-code-point": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
|
||||
"integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
@@ -10089,14 +10049,13 @@
|
||||
},
|
||||
"node_modules/ink": {
|
||||
"name": "@jrichman/ink",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.5.0.tgz",
|
||||
"integrity": "sha512-S4g/ng7fPZmFwclO82iWkOce8vDLy/FIDgHIfkCWGOehqHe6dexHsmq3kNQD21okh198pA5SAQTCqNQJb/svRQ==",
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.6.3.tgz",
|
||||
"integrity": "sha512-0v4S7TbbF2tpQrfqH1btwLgTgH+K0vY2BJbokTE5Lk1KBr4TqZ+Pyo+geSD5F+zytX6G2ajGHBQyHk8yGK4C7A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alcalzone/ansi-tokenize": "^0.2.1",
|
||||
"ansi-escapes": "^7.0.0",
|
||||
"ansi-styles": "^6.2.1",
|
||||
"ansi-styles": "^6.2.3",
|
||||
"auto-bind": "^5.0.1",
|
||||
"chalk": "^5.6.0",
|
||||
"cli-boxes": "^3.0.0",
|
||||
@@ -10105,6 +10064,7 @@
|
||||
"code-excerpt": "^4.0.0",
|
||||
"es-toolkit": "^1.39.10",
|
||||
"indent-string": "^5.0.0",
|
||||
"is-fullwidth-code-point": "^5.0.0",
|
||||
"is-in-ci": "^2.0.0",
|
||||
"mnemonist": "^0.40.3",
|
||||
"patch-console": "^2.0.0",
|
||||
@@ -10174,9 +10134,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ink/node_modules/ansi-styles": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -10197,6 +10157,21 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ink/node_modules/is-fullwidth-code-point": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
|
||||
"integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ink/node_modules/is-in-ci": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-2.0.0.tgz",
|
||||
@@ -17551,7 +17526,7 @@
|
||||
"fzf": "^0.5.2",
|
||||
"glob": "^12.0.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"ink": "npm:@jrichman/ink@6.5.0",
|
||||
"ink": "npm:@jrichman/ink@6.6.3",
|
||||
"ink-gradient": "^3.0.0",
|
||||
"ink-spinner": "^5.0.0",
|
||||
"latest-version": "^9.0.0",
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"pre-commit": "node scripts/pre-commit.js"
|
||||
},
|
||||
"overrides": {
|
||||
"ink": "npm:@jrichman/ink@6.5.0",
|
||||
"ink": "npm:@jrichman/ink@6.6.3",
|
||||
"wrap-ansi": "9.0.2",
|
||||
"cliui": {
|
||||
"wrap-ansi": "7.0.0"
|
||||
@@ -136,7 +136,7 @@
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ink": "npm:@jrichman/ink@6.5.0",
|
||||
"ink": "npm:@jrichman/ink@6.6.3",
|
||||
"latest-version": "^9.0.0",
|
||||
"node-fetch-native": "^1.6.7",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"fzf": "^0.5.2",
|
||||
"glob": "^12.0.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"ink": "npm:@jrichman/ink@6.5.0",
|
||||
"ink": "npm:@jrichman/ink@6.6.3",
|
||||
"ink-gradient": "^3.0.0",
|
||||
"ink-spinner": "^5.0.0",
|
||||
"latest-version": "^9.0.0",
|
||||
|
||||
@@ -2056,7 +2056,7 @@ const SETTINGS_SCHEMA = {
|
||||
label: 'JIT Context Loading',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: true,
|
||||
default: false,
|
||||
description: 'Enable Just-In-Time (JIT) context loading.',
|
||||
showInDialog: false,
|
||||
},
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
type OverflowState,
|
||||
} from '../ui/contexts/OverflowContext.js';
|
||||
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { type Config } from '@google/gemini-cli-core';
|
||||
import { FakePersistentState } from './persistentStateFake.js';
|
||||
import { AppContext, type AppState } from '../ui/contexts/AppContext.js';
|
||||
@@ -51,7 +52,6 @@ import { themeManager, DEFAULT_THEME } from '../ui/themes/theme-manager.js';
|
||||
import { DefaultLight } from '../ui/themes/builtin/light/default-light.js';
|
||||
import { pickDefaultThemeName } from '../ui/themes/theme.js';
|
||||
import { generateSvgForTerminal } from './svg.js';
|
||||
import { loadCliConfig, type CliArgs } from '../config/config.js';
|
||||
|
||||
export const persistentStateMock = new FakePersistentState();
|
||||
|
||||
@@ -666,12 +666,11 @@ export const renderWithProviders = async (
|
||||
const terminalWidth = width ?? baseState.terminalWidth;
|
||||
|
||||
if (!config) {
|
||||
config = await loadCliConfig(
|
||||
settings.merged,
|
||||
'random-session-id',
|
||||
{} as unknown as CliArgs,
|
||||
{ cwd: '/' },
|
||||
);
|
||||
config = makeFakeConfig({
|
||||
useAlternateBuffer: settings.merged.ui?.useAlternateBuffer,
|
||||
showMemoryUsage: settings.merged.ui?.showMemoryUsage,
|
||||
accessibility: settings.merged.ui?.accessibility,
|
||||
});
|
||||
}
|
||||
|
||||
const mainAreaWidth = providedUiState?.mainAreaWidth ?? terminalWidth;
|
||||
|
||||
@@ -441,6 +441,7 @@ describe('<Footer />', () => {
|
||||
|
||||
it('renders footer with all optional sections hidden (minimal footer)', async () => {
|
||||
const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
|
||||
config: mockConfig,
|
||||
width: 120,
|
||||
uiState: { sessionStats: mockSessionStats },
|
||||
settings: createMockSettings({
|
||||
@@ -558,6 +559,7 @@ describe('<Footer />', () => {
|
||||
describe('Footer Token Formatting', () => {
|
||||
const renderWithTokens = async (tokens: number) => {
|
||||
const result = await renderWithProviders(<Footer />, {
|
||||
config: mockConfig,
|
||||
width: 120,
|
||||
uiState: {
|
||||
sessionStats: {
|
||||
@@ -810,6 +812,7 @@ describe('<Footer />', () => {
|
||||
|
||||
it('handles empty items array', async () => {
|
||||
const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
|
||||
config: mockConfig,
|
||||
width: 120,
|
||||
uiState: { sessionStats: mockSessionStats },
|
||||
settings: createMockSettings({
|
||||
|
||||
@@ -17,6 +17,7 @@ import { ToolGroupMessage } from './messages/ToolGroupMessage.js';
|
||||
import { GeminiMessageContent } from './messages/GeminiMessageContent.js';
|
||||
import { CompressionMessage } from './messages/CompressionMessage.js';
|
||||
import { WarningMessage } from './messages/WarningMessage.js';
|
||||
import { SubagentHistoryMessage } from './messages/SubagentHistoryMessage.js';
|
||||
import { Box } from 'ink';
|
||||
import { AboutBox } from './AboutBox.js';
|
||||
import { StatsDisplay } from './StatsDisplay.js';
|
||||
@@ -215,6 +216,12 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
|
||||
isExpandable={isExpandable}
|
||||
/>
|
||||
)}
|
||||
{itemForDisplay.type === 'subagent' && (
|
||||
<SubagentHistoryMessage
|
||||
item={itemForDisplay}
|
||||
terminalWidth={terminalWidth}
|
||||
/>
|
||||
)}
|
||||
{itemForDisplay.type === 'compression' && (
|
||||
<CompressionMessage compression={itemForDisplay.compression} />
|
||||
)}
|
||||
|
||||
@@ -2222,85 +2222,67 @@ describe('InputPrompt', () => {
|
||||
name: 'mid-word',
|
||||
text: 'hello world',
|
||||
visualCursor: [0, 3],
|
||||
expected: `hel${chalk.inverse('l')}o world`,
|
||||
},
|
||||
{
|
||||
name: 'at the beginning of the line',
|
||||
text: 'hello',
|
||||
visualCursor: [0, 0],
|
||||
expected: `${chalk.inverse('h')}ello`,
|
||||
},
|
||||
{
|
||||
name: 'at the end of the line',
|
||||
text: 'hello',
|
||||
visualCursor: [0, 5],
|
||||
expected: `hello${chalk.inverse(' ')}`,
|
||||
},
|
||||
{
|
||||
name: 'on a highlighted token',
|
||||
text: 'run @path/to/file',
|
||||
visualCursor: [0, 9],
|
||||
expected: `@path/${chalk.inverse('t')}o/file`,
|
||||
},
|
||||
{
|
||||
name: 'for multi-byte unicode characters',
|
||||
text: 'hello 👍 world',
|
||||
visualCursor: [0, 6],
|
||||
expected: `hello ${chalk.inverse('👍')} world`,
|
||||
},
|
||||
{
|
||||
name: 'after multi-byte unicode characters',
|
||||
text: '👍A',
|
||||
visualCursor: [0, 1],
|
||||
expected: `👍${chalk.inverse('A')}`,
|
||||
},
|
||||
{
|
||||
name: 'at the end of a line with unicode characters',
|
||||
text: 'hello 👍',
|
||||
visualCursor: [0, 8],
|
||||
expected: `hello 👍`, // skip checking inverse ansi due to ink truncation bug
|
||||
},
|
||||
{
|
||||
name: 'at the end of a short line with unicode characters',
|
||||
text: '👍',
|
||||
visualCursor: [0, 1],
|
||||
expected: `👍${chalk.inverse(' ')}`,
|
||||
},
|
||||
{
|
||||
name: 'on an empty line',
|
||||
text: '',
|
||||
visualCursor: [0, 0],
|
||||
expected: chalk.inverse(' '),
|
||||
},
|
||||
{
|
||||
name: 'on a space between words',
|
||||
text: 'hello world',
|
||||
visualCursor: [0, 5],
|
||||
expected: `hello${chalk.inverse(' ')}world`,
|
||||
},
|
||||
])(
|
||||
'should display cursor correctly $name',
|
||||
async ({ name, text, visualCursor, expected }) => {
|
||||
async ({ text, visualCursor }) => {
|
||||
mockBuffer.text = text;
|
||||
mockBuffer.lines = [text];
|
||||
mockBuffer.viewportVisualLines = [text];
|
||||
mockBuffer.visualCursor = visualCursor as [number, number];
|
||||
props.config.getUseBackgroundColor = () => false;
|
||||
|
||||
const { stdout, unmount } = await renderWithProviders(
|
||||
const renderResult = await renderWithProviders(
|
||||
<InputPrompt {...props} />,
|
||||
);
|
||||
await waitFor(() => {
|
||||
const frame = stdout.lastFrameRaw();
|
||||
expect(stripAnsi(frame)).toContain(stripAnsi(expected));
|
||||
if (
|
||||
name !== 'at the end of a line with unicode characters' &&
|
||||
name !== 'on a highlighted token'
|
||||
) {
|
||||
expect(frame).toContain('\u001b[7m');
|
||||
}
|
||||
});
|
||||
unmount();
|
||||
await renderResult.waitUntilReady();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -2316,7 +2298,6 @@ describe('InputPrompt', () => {
|
||||
[1, 0],
|
||||
[2, 0],
|
||||
],
|
||||
expected: `sec${chalk.inverse('o')}nd line`,
|
||||
},
|
||||
{
|
||||
name: 'at the beginning of a line',
|
||||
@@ -2326,7 +2307,6 @@ describe('InputPrompt', () => {
|
||||
[0, 0],
|
||||
[1, 0],
|
||||
],
|
||||
expected: `${chalk.inverse('s')}econd line`,
|
||||
},
|
||||
{
|
||||
name: 'at the end of a line',
|
||||
@@ -2336,11 +2316,10 @@ describe('InputPrompt', () => {
|
||||
[0, 0],
|
||||
[1, 0],
|
||||
],
|
||||
expected: `first line${chalk.inverse(' ')}`,
|
||||
},
|
||||
])(
|
||||
'should display cursor correctly $name in a multiline block',
|
||||
async ({ name, text, visualCursor, expected, visualToLogicalMap }) => {
|
||||
async ({ text, visualCursor, visualToLogicalMap }) => {
|
||||
mockBuffer.text = text;
|
||||
mockBuffer.lines = text.split('\n');
|
||||
mockBuffer.viewportVisualLines = text.split('\n');
|
||||
@@ -2350,20 +2329,12 @@ describe('InputPrompt', () => {
|
||||
>;
|
||||
props.config.getUseBackgroundColor = () => false;
|
||||
|
||||
const { stdout, unmount } = await renderWithProviders(
|
||||
const renderResult = await renderWithProviders(
|
||||
<InputPrompt {...props} />,
|
||||
);
|
||||
await waitFor(() => {
|
||||
const frame = stdout.lastFrameRaw();
|
||||
expect(stripAnsi(frame)).toContain(stripAnsi(expected));
|
||||
if (
|
||||
name !== 'at the end of a line with unicode characters' &&
|
||||
name !== 'on a highlighted token'
|
||||
) {
|
||||
expect(frame).toContain('\u001b[7m');
|
||||
}
|
||||
});
|
||||
unmount();
|
||||
await renderResult.waitUntilReady();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2380,18 +2351,12 @@ describe('InputPrompt', () => {
|
||||
];
|
||||
props.config.getUseBackgroundColor = () => false;
|
||||
|
||||
const { stdout, unmount } = await renderWithProviders(
|
||||
const renderResult = await renderWithProviders(
|
||||
<InputPrompt {...props} />,
|
||||
);
|
||||
await waitFor(() => {
|
||||
const frame = stdout.lastFrameRaw();
|
||||
const lines = frame.split('\n');
|
||||
// The line with the cursor should just be an inverted space inside the box border
|
||||
expect(
|
||||
lines.find((l) => l.includes(chalk.inverse(' '))),
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
unmount();
|
||||
await renderResult.waitUntilReady();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2412,22 +2377,14 @@ describe('InputPrompt', () => {
|
||||
];
|
||||
props.config.getUseBackgroundColor = () => false;
|
||||
|
||||
const { stdout, unmount } = await renderWithProviders(
|
||||
const renderResult = await renderWithProviders(
|
||||
<InputPrompt {...props} />,
|
||||
);
|
||||
await waitFor(() => {
|
||||
const frame = stdout.lastFrameRaw();
|
||||
// Check that all lines, including the empty one, are rendered.
|
||||
// This implicitly tests that the Box wrapper provides height for the empty line.
|
||||
expect(frame).toContain('hello');
|
||||
expect(frame).toContain('world');
|
||||
expect(frame).toContain(chalk.inverse(' '));
|
||||
|
||||
const outputLines = frame.trim().split('\n');
|
||||
// The number of lines should be 2 for the border plus 3 for the content.
|
||||
expect(outputLines.length).toBe(5);
|
||||
});
|
||||
unmount();
|
||||
await renderResult.waitUntilReady();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
|
||||
renderResult.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4088,14 +4045,12 @@ describe('InputPrompt', () => {
|
||||
it('should not show inverted cursor when shell is focused', async () => {
|
||||
props.isEmbeddedShellFocused = true;
|
||||
props.focus = false;
|
||||
const { stdout, unmount } = await renderWithProviders(
|
||||
const renderResult = await renderWithProviders(
|
||||
<InputPrompt {...props} />,
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(stdout.lastFrame()).not.toContain(`{chalk.inverse(' ')}`);
|
||||
});
|
||||
expect(stdout.lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
await renderResult.waitUntilReady();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ import {
|
||||
} from '../hooks/useConfirmingTool.js';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('ink-spinner', () => ({
|
||||
default: () => <Text>⠋</Text>,
|
||||
}));
|
||||
|
||||
const mockUseSettings = vi.fn().mockReturnValue({
|
||||
merged: {
|
||||
ui: {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="88" viewBox="0 0 920 88">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="88" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">first line</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<rect x="36" y="34" width="9" height="17" fill="#ffffff" />
|
||||
<text x="36" y="36" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">s</text>
|
||||
<text x="45" y="36" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">econd line</text>
|
||||
<text x="891" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="88" viewBox="0 0 920 88">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="88" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">first line</text>
|
||||
<rect x="126" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="36" y="36" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">second line</text>
|
||||
<text x="891" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="105" viewBox="0 0 920 105">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="105" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">first line</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="36" y="36" fill="#ffffff" textLength="27" lengthAdjust="spacingAndGlyphs">sec</text>
|
||||
<rect x="63" y="34" width="9" height="17" fill="#ffffff" />
|
||||
<text x="63" y="36" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">o</text>
|
||||
<text x="72" y="36" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">nd line</text>
|
||||
<text x="891" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="36" y="53" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">third line</text>
|
||||
<text x="891" y="53" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="70" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="105" viewBox="0 0 920 105">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="105" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">first line</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<rect x="36" y="34" width="9" height="17" fill="#ffffff" />
|
||||
<text x="891" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="36" y="53" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">third line</text>
|
||||
<text x="891" y="53" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="70" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">👍</text>
|
||||
<rect x="45" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="45" y="19" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">A</text>
|
||||
<text x="882" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<rect x="36" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="36" y="19" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">h</text>
|
||||
<text x="45" y="19" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">ello</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">hello 👍</text>
|
||||
<text x="882" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">👍</text>
|
||||
<rect x="45" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="882" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">hello</text>
|
||||
<rect x="81" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">hello </text>
|
||||
<rect x="90" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="90" y="19" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">👍</text>
|
||||
<text x="99" y="19" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs"> world</text>
|
||||
<text x="882" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="27" lengthAdjust="spacingAndGlyphs">hel</text>
|
||||
<rect x="63" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="63" y="19" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">l</text>
|
||||
<text x="72" y="19" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">o world</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">run </text>
|
||||
<text x="72" y="19" fill="#d7afff" textLength="45" lengthAdjust="spacingAndGlyphs">@path</text>
|
||||
<rect x="117" y="17" width="9" height="17" fill="#d7afff" />
|
||||
<text x="117" y="19" fill="#000000" textLength="9" lengthAdjust="spacingAndGlyphs">/</text>
|
||||
<text x="126" y="19" fill="#d7afff" textLength="63" lengthAdjust="spacingAndGlyphs">to/file</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">hello</text>
|
||||
<rect x="81" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="90" y="19" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">world</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<rect x="36" y="17" width="9" height="17" fill="#ffffff" />
|
||||
<text x="45" y="19" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs"> Type your message or @path/to/file</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="105" viewBox="0 0 920 105">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="105" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
<text x="0" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<text x="36" y="19" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">hello</text>
|
||||
<text x="891" y="19" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="36" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="36" y="53" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">world</text>
|
||||
<rect x="81" y="51" width="9" height="17" fill="#ffffff" />
|
||||
<text x="891" y="53" fill="#00cd00" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="70" fill="#00cd00" textLength="900" lengthAdjust="spacingAndGlyphs">────────────────────────────────────────────────────────────────────────────────────────────────────</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="71" viewBox="0 0 920 71">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="71" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<rect x="0" y="0" width="900" height="17" fill="#1f1f1f" />
|
||||
<text x="0" y="2" fill="#000000" textLength="900" lengthAdjust="spacingAndGlyphs">▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀</text>
|
||||
<rect x="0" y="17" width="9" height="17" fill="#1f1f1f" />
|
||||
<rect x="9" y="17" width="18" height="17" fill="#1f1f1f" />
|
||||
<text x="9" y="19" fill="#d7afff" textLength="18" lengthAdjust="spacingAndGlyphs">> </text>
|
||||
<rect x="27" y="17" width="324" height="17" fill="#1f1f1f" />
|
||||
<text x="27" y="19" fill="#afafaf" textLength="324" lengthAdjust="spacingAndGlyphs"> Type your message or @path/to/file</text>
|
||||
<rect x="351" y="17" width="549" height="17" fill="#1f1f1f" />
|
||||
<rect x="0" y="34" width="900" height="17" fill="#1f1f1f" />
|
||||
<text x="0" y="36" fill="#000000" textLength="900" lengthAdjust="spacingAndGlyphs">▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,5 +1,95 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > multi-line scenarios > should display cursor correctly 'at the beginning of a line' in a multiline block 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > first line │
|
||||
│ second line │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > multi-line scenarios > should display cursor correctly 'at the end of a line' in a multiline block 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > first line │
|
||||
│ second line │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > multi-line scenarios > should display cursor correctly 'in the middle of a line' in a multiline block 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > first line │
|
||||
│ second line │
|
||||
│ third line │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > multi-line scenarios > should display cursor on a blank line in a multiline block 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > first line │
|
||||
│ │
|
||||
│ third line │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'after multi-byte unicode characters' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > 👍A │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'at the beginning of the line' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'at the end of a line with unicode cha…' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello 👍 │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'at the end of a short line with unico…' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > 👍 │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'at the end of the line' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'for multi-byte unicode characters' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello 👍 world │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'mid-word' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello world │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'on a highlighted token' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > run @path/to/file │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'on a space between words' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello world │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios > should display cursor correctly 'on an empty line' 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > Type your message or @path/to/file │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > History Navigation and Completion Suppression > should not render suggestions during history navigation 1`] = `
|
||||
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> second message
|
||||
@@ -78,11 +168,18 @@ exports[`InputPrompt > mouse interaction > should toggle paste expansion on doub
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > multiline rendering > should correctly render multiline input including blank lines 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
│ > hello │
|
||||
│ │
|
||||
│ world │
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > snapshots > should not show inverted cursor when shell is focused 1`] = `
|
||||
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> Type your message or @path/to/file
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
"
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄"
|
||||
`;
|
||||
|
||||
exports[`InputPrompt > snapshots > should render correctly in shell mode 1`] = `
|
||||
|
||||
@@ -4,7 +4,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Focuse
|
||||
"ScrollableList
|
||||
AppHeader(full)
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ ⠋ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ Line 11 │
|
||||
│ Line 12 │
|
||||
@@ -24,7 +24,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Unfocu
|
||||
"ScrollableList
|
||||
AppHeader(full)
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ ⠋ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ Line 11 │
|
||||
│ Line 12 │
|
||||
@@ -43,7 +43,7 @@ AppHeader(full)
|
||||
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Constrained height' 1`] = `
|
||||
"AppHeader(full)
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ ⠋ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ ... first 11 lines hidden (Ctrl+O to show) ... │
|
||||
│ Line 12 │
|
||||
@@ -62,7 +62,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Con
|
||||
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unconstrained height' 1`] = `
|
||||
"AppHeader(full)
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ ⠋ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ Line 1 │
|
||||
│ Line 2 │
|
||||
|
||||
@@ -14,9 +14,9 @@ exports[`Initial Theme Selection > should default to a dark theme when terminal
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Ayu Light │ │ │
|
||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -64,9 +64,9 @@ exports[`Initial Theme Selection > should use the theme from settings even if te
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Ayu Light │ │ │
|
||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -103,9 +103,9 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Ayu Light │ │ │
|
||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -128,9 +128,9 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Ayu Light │ │ │
|
||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ╭─────────────────────────────────────────────────╮ │
|
||||
│ │ DEVELOPER TOOLS (Not visible to users) │ │
|
||||
|
||||
@@ -8,7 +8,7 @@ import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { SubagentGroupDisplay } from './SubagentGroupDisplay.js';
|
||||
import { Kind, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { vi } from 'vitest';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { Text } from 'ink';
|
||||
|
||||
vi.mock('../../utils/MarkdownDisplay.js', () => ({
|
||||
|
||||
@@ -191,8 +191,9 @@ export const SubagentGroupDisplay: React.FC<SubagentGroupDisplayProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
const history = toolCall.subagentHistory ?? progress.recentActivity;
|
||||
const lastActivity: SubagentActivityItem | undefined =
|
||||
progress.recentActivity[progress.recentActivity.length - 1];
|
||||
history[history.length - 1];
|
||||
|
||||
// Collapsed View: Show single compact line per agent
|
||||
if (!isExpanded) {
|
||||
@@ -260,6 +261,7 @@ export const SubagentGroupDisplay: React.FC<SubagentGroupDisplayProps> = ({
|
||||
<SubagentProgressDisplay
|
||||
progress={progress}
|
||||
terminalWidth={terminalWidth}
|
||||
historyOverrides={toolCall.subagentHistory}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { SubagentHistoryMessage } from './SubagentHistoryMessage.js';
|
||||
import type { HistoryItemSubagent } from '../../types.js';
|
||||
|
||||
describe('SubagentHistoryMessage', () => {
|
||||
const mockItem: HistoryItemSubagent = {
|
||||
type: 'subagent',
|
||||
agentName: 'research',
|
||||
history: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'thought',
|
||||
content: 'Thinking about the problem',
|
||||
status: 'completed',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'tool_call',
|
||||
content: 'Calling search_web',
|
||||
status: 'running',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'tool_call',
|
||||
content: 'Calling read_file fail',
|
||||
status: 'error',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('renders header with agent name and item count', async () => {
|
||||
const renderResult = await renderWithProviders(
|
||||
<SubagentHistoryMessage item={mockItem} terminalWidth={80} />,
|
||||
);
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain('research Trace (3 items)');
|
||||
expect(output).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('renders thought activities with brain icon', async () => {
|
||||
const renderResult = await renderWithProviders(
|
||||
<SubagentHistoryMessage item={mockItem} terminalWidth={80} />,
|
||||
);
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain('🧠 Thinking about the problem');
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('renders tool call activities with tool icon', async () => {
|
||||
const renderResult = await renderWithProviders(
|
||||
<SubagentHistoryMessage item={mockItem} terminalWidth={80} />,
|
||||
);
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain('🛠️ Calling search_web');
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('renders status indicators correctly', async () => {
|
||||
const renderResult = await renderWithProviders(
|
||||
<SubagentHistoryMessage item={mockItem} terminalWidth={80} />,
|
||||
);
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain('Calling search_web (Running...)');
|
||||
expect(output).toContain('Thinking about the problem ✅');
|
||||
expect(output).toContain('Calling read_file fail ❌');
|
||||
renderResult.unmount();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import type { HistoryItemSubagent } from '../../types.js';
|
||||
|
||||
interface SubagentHistoryMessageProps {
|
||||
item: HistoryItemSubagent;
|
||||
terminalWidth: number;
|
||||
}
|
||||
|
||||
export const SubagentHistoryMessage: React.FC<SubagentHistoryMessageProps> = ({
|
||||
item,
|
||||
terminalWidth,
|
||||
}) => (
|
||||
<Box flexDirection="column" width={terminalWidth} marginBottom={1}>
|
||||
<Box marginBottom={1}>
|
||||
<Text bold color="cyan">
|
||||
🤖 {item.agentName} Trace ({item.history.length} items)
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{item.history.map((activity) => (
|
||||
<Box key={activity.id} marginLeft={2} marginBottom={0}>
|
||||
<Text color={activity.type === 'thought' ? 'gray' : 'white'}>
|
||||
{activity.type === 'thought' ? '🧠' : '🛠️'} {activity.content}
|
||||
{activity.status === 'running' && ' (Running...)'}
|
||||
{activity.status === 'completed' && ' ✅'}
|
||||
{activity.status === 'error' && ' ❌'}
|
||||
</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
@@ -20,6 +20,7 @@ import { safeJsonToMarkdown } from '@google/gemini-cli-core';
|
||||
export interface SubagentProgressDisplayProps {
|
||||
progress: SubagentProgress;
|
||||
terminalWidth: number;
|
||||
historyOverrides?: SubagentActivityItem[];
|
||||
}
|
||||
|
||||
export const formatToolArgs = (args?: string): string => {
|
||||
@@ -57,7 +58,7 @@ export const formatToolArgs = (args?: string): string => {
|
||||
|
||||
export const SubagentProgressDisplay: React.FC<
|
||||
SubagentProgressDisplayProps
|
||||
> = ({ progress, terminalWidth }) => {
|
||||
> = ({ progress, terminalWidth, historyOverrides }) => {
|
||||
let headerText: string | undefined;
|
||||
let headerColor = theme.text.secondary;
|
||||
|
||||
@@ -85,72 +86,77 @@ export const SubagentProgressDisplay: React.FC<
|
||||
</Box>
|
||||
)}
|
||||
<Box flexDirection="column" marginLeft={0} gap={0}>
|
||||
{progress.recentActivity.map((item: SubagentActivityItem) => {
|
||||
if (item.type === 'thought') {
|
||||
const isCancellation = item.content === 'Request cancelled.';
|
||||
const icon = isCancellation ? 'ℹ ' : '💭';
|
||||
const color = isCancellation
|
||||
? theme.status.warning
|
||||
: theme.text.secondary;
|
||||
{(historyOverrides ?? progress.recentActivity).map(
|
||||
(item: SubagentActivityItem) => {
|
||||
if (item.type === 'thought') {
|
||||
const isCancellation = item.content === 'Request cancelled.';
|
||||
const icon = isCancellation ? 'ℹ ' : '💭';
|
||||
const color = isCancellation
|
||||
? theme.status.warning
|
||||
: theme.text.secondary;
|
||||
|
||||
return (
|
||||
<Box key={item.id} flexDirection="row">
|
||||
<Box minWidth={STATUS_INDICATOR_WIDTH}>
|
||||
<Text color={color}>{icon}</Text>
|
||||
return (
|
||||
<Box key={item.id} flexDirection="row">
|
||||
<Box minWidth={STATUS_INDICATOR_WIDTH}>
|
||||
<Text color={color}>{icon}</Text>
|
||||
</Box>
|
||||
<Box flexGrow={1}>
|
||||
<Text color={color}>{item.content}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box flexGrow={1}>
|
||||
<Text color={color}>{item.content}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
} else if (item.type === 'tool_call') {
|
||||
const statusSymbol =
|
||||
item.status === 'running' ? (
|
||||
<Spinner type="dots" />
|
||||
) : item.status === 'completed' ? (
|
||||
<Text color={theme.status.success}>{TOOL_STATUS.SUCCESS}</Text>
|
||||
) : item.status === 'cancelled' ? (
|
||||
<Text color={theme.status.warning} bold>
|
||||
{TOOL_STATUS.CANCELED}
|
||||
</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>{TOOL_STATUS.ERROR}</Text>
|
||||
);
|
||||
|
||||
const formattedArgs = item.description || formatToolArgs(item.args);
|
||||
const displayArgs =
|
||||
formattedArgs.length > 60
|
||||
? formattedArgs.slice(0, 60) + '...'
|
||||
: formattedArgs;
|
||||
|
||||
return (
|
||||
<Box key={item.id} flexDirection="row">
|
||||
<Box minWidth={STATUS_INDICATOR_WIDTH}>{statusSymbol}</Box>
|
||||
<Box flexDirection="row" flexGrow={1} flexWrap="wrap">
|
||||
<Text
|
||||
bold
|
||||
color={theme.text.primary}
|
||||
strikethrough={item.status === 'cancelled'}
|
||||
>
|
||||
{item.displayName || item.content}
|
||||
} else if (item.type === 'tool_call') {
|
||||
const statusSymbol =
|
||||
item.status === 'running' ? (
|
||||
<Spinner type="dots" />
|
||||
) : item.status === 'completed' ? (
|
||||
<Text color={theme.status.success}>
|
||||
{TOOL_STATUS.SUCCESS}
|
||||
</Text>
|
||||
{displayArgs && (
|
||||
<Box marginLeft={1}>
|
||||
<Text
|
||||
color={theme.text.secondary}
|
||||
wrap="truncate"
|
||||
strikethrough={item.status === 'cancelled'}
|
||||
>
|
||||
{displayArgs}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
) : item.status === 'cancelled' ? (
|
||||
<Text color={theme.status.warning} bold>
|
||||
{TOOL_STATUS.CANCELED}
|
||||
</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>{TOOL_STATUS.ERROR}</Text>
|
||||
);
|
||||
|
||||
const formattedArgs =
|
||||
item.description || formatToolArgs(item.args);
|
||||
const displayArgs =
|
||||
formattedArgs.length > 60
|
||||
? formattedArgs.slice(0, 60) + '...'
|
||||
: formattedArgs;
|
||||
|
||||
return (
|
||||
<Box key={item.id} flexDirection="row">
|
||||
<Box minWidth={STATUS_INDICATOR_WIDTH}>{statusSymbol}</Box>
|
||||
<Box flexDirection="row" flexGrow={1} flexWrap="wrap">
|
||||
<Text
|
||||
bold
|
||||
color={theme.text.primary}
|
||||
strikethrough={item.status === 'cancelled'}
|
||||
>
|
||||
{item.displayName || item.content}
|
||||
</Text>
|
||||
{displayArgs && (
|
||||
<Box marginLeft={1}>
|
||||
<Text
|
||||
color={theme.text.secondary}
|
||||
wrap="truncate"
|
||||
strikethrough={item.status === 'cancelled'}
|
||||
>
|
||||
{displayArgs}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{progress.result && (
|
||||
|
||||
@@ -279,8 +279,8 @@ describe('<ToolGroupMessage />', () => {
|
||||
);
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('Testing Topic');
|
||||
expect(output).toContain('— This is the description');
|
||||
expect(output).toContain('Testing Topic: ');
|
||||
expect(output).toContain('This is the description');
|
||||
expect(output).toMatchSnapshot('update_topic_tool');
|
||||
unmount();
|
||||
});
|
||||
@@ -307,8 +307,8 @@ describe('<ToolGroupMessage />', () => {
|
||||
);
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('Testing Topic');
|
||||
expect(output).toContain('— This is the summary');
|
||||
expect(output).toContain('Testing Topic: ');
|
||||
expect(output).toContain('This is the summary');
|
||||
unmount();
|
||||
});
|
||||
|
||||
|
||||
@@ -31,11 +31,16 @@ export const TopicMessage: React.FC<TopicMessageProps> = ({ args }) => {
|
||||
const intent = typeof rawIntent === 'string' ? rawIntent : undefined;
|
||||
|
||||
return (
|
||||
<Box flexDirection="row" marginLeft={2}>
|
||||
<Text color={theme.text.primary} bold>
|
||||
<Box flexDirection="row" marginLeft={2} flexWrap="wrap">
|
||||
<Text color={theme.text.primary} bold wrap="truncate-end">
|
||||
{title || 'Topic'}
|
||||
{intent && <Text>: </Text>}
|
||||
</Text>
|
||||
{intent && <Text color={theme.text.secondary}> — {intent}</Text>}
|
||||
{intent && (
|
||||
<Text color={theme.text.secondary} wrap="wrap">
|
||||
{intent}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="105" viewBox="0 0 920 105">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="105" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#00cdcd" textLength="234" lengthAdjust="spacingAndGlyphs" font-weight="bold">🤖 research Trace (3 items)</text>
|
||||
<text x="18" y="36" fill="#7f7f7f" textLength="270" lengthAdjust="spacingAndGlyphs">🧠 Thinking about the problem ✅</text>
|
||||
<text x="18" y="53" fill="#e5e5e5" textLength="297" lengthAdjust="spacingAndGlyphs">🛠️ Calling search_web (Running...)</text>
|
||||
<text x="18" y="70" fill="#e5e5e5" textLength="234" lengthAdjust="spacingAndGlyphs">🛠️ Calling read_file fail ❌</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 881 B |
@@ -0,0 +1,19 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`SubagentHistoryMessage > renders header with agent name and item count 1`] = `
|
||||
"🤖 research Trace (3 items)
|
||||
|
||||
🧠 Thinking about the problem ✅
|
||||
🛠️ Calling search_web (Running...)
|
||||
🛠️ Calling read_file fail ❌
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`SubagentHistoryMessage > renders header with agent name and item count 2`] = `
|
||||
"🤖 research Trace (3 items)
|
||||
|
||||
🧠 Thinking about the problem ✅
|
||||
🛠️ Calling search_web (Running...)
|
||||
🛠️ Calling read_file fail ❌
|
||||
"
|
||||
`;
|
||||
@@ -77,7 +77,7 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders header when scrolled
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders mixed tool calls including update_topic 1`] = `
|
||||
" Testing Topic — This is the description
|
||||
" Testing Topic: This is the description
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ read_file Read a file │
|
||||
│ │
|
||||
@@ -141,7 +141,7 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders two tool groups where
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders update_topic tool call using TopicMessage > update_topic_tool 1`] = `
|
||||
" Testing Topic — This is the description
|
||||
" Testing Topic: This is the description
|
||||
"
|
||||
`;
|
||||
|
||||
|
||||
@@ -10,12 +10,19 @@ import {
|
||||
type ToolResultDisplay,
|
||||
debugLogger,
|
||||
CoreToolCallStatus,
|
||||
type SubagentActivityItem,
|
||||
} from '@google/gemini-cli-core';
|
||||
import {
|
||||
type HistoryItemToolGroup,
|
||||
type IndividualToolCallDisplay,
|
||||
} from '../types.js';
|
||||
|
||||
function hasSubagentHistory(
|
||||
call: ToolCall,
|
||||
): call is ToolCall & { subagentHistory: SubagentActivityItem[] } {
|
||||
return 'subagentHistory' in call && call.subagentHistory !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms `ToolCall` objects into `HistoryItemToolGroup` objects for UI
|
||||
* display. This is a pure projection layer and does not track interaction
|
||||
@@ -115,6 +122,9 @@ export function mapToDisplay(
|
||||
progressTotal,
|
||||
approvalMode: call.approvalMode,
|
||||
originalRequestName: call.request.originalRequestName,
|
||||
subagentHistory: hasSubagentHistory(call)
|
||||
? call.subagentHistory
|
||||
: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -163,7 +163,6 @@ describe('useToolScheduler', () => {
|
||||
},
|
||||
};
|
||||
|
||||
// 1. Initial success
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
@@ -172,7 +171,6 @@ describe('useToolScheduler', () => {
|
||||
} as ToolCallsUpdateMessage);
|
||||
});
|
||||
|
||||
// 2. Mark as submitted
|
||||
act(() => {
|
||||
const [, , markAsSubmitted] = result.current;
|
||||
markAsSubmitted(['call-1']);
|
||||
@@ -180,7 +178,7 @@ describe('useToolScheduler', () => {
|
||||
|
||||
expect(result.current[0][0].responseSubmittedToGemini).toBe(true);
|
||||
|
||||
// 3. Receive another update (should preserve the true flag)
|
||||
// Verify flag is preserved across updates
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
@@ -348,7 +346,6 @@ describe('useToolScheduler', () => {
|
||||
confirmationDetails: { type: 'info', title: 'Confirm', prompt: 'Yes?' },
|
||||
};
|
||||
|
||||
// 1. Populate state with multiple schedulers
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
@@ -372,7 +369,6 @@ describe('useToolScheduler', () => {
|
||||
toolCalls.find((t) => t.request.callId === 'call-sub'),
|
||||
).toBeDefined();
|
||||
|
||||
// 2. Call setToolCallsForDisplay (e.g., simulate a manual update or clear)
|
||||
act(() => {
|
||||
const [, , , setToolCalls] = result.current;
|
||||
setToolCalls((prev) =>
|
||||
@@ -380,7 +376,6 @@ describe('useToolScheduler', () => {
|
||||
);
|
||||
});
|
||||
|
||||
// 3. Verify that tools are still present and maintain their scheduler IDs
|
||||
const [toolCalls2] = result.current;
|
||||
expect(toolCalls2).toHaveLength(2);
|
||||
expect(toolCalls2.every((t) => t.responseSubmittedToGemini)).toBe(true);
|
||||
@@ -482,7 +477,6 @@ describe('useToolScheduler', () => {
|
||||
confirmationDetails: { type: 'info', title: 'Confirm', prompt: 'Yes?' },
|
||||
} as WaitingToolCall;
|
||||
|
||||
// 1. Initial approval request
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
@@ -493,7 +487,6 @@ describe('useToolScheduler', () => {
|
||||
|
||||
expect(result.current[0]).toHaveLength(1);
|
||||
|
||||
// 2. Approved and executing
|
||||
const approvedCall = {
|
||||
...subagentCall,
|
||||
status: CoreToolCallStatus.Executing as const,
|
||||
@@ -510,7 +503,7 @@ describe('useToolScheduler', () => {
|
||||
expect(result.current[0]).toHaveLength(1);
|
||||
expect(result.current[0][0].status).toBe(CoreToolCallStatus.Executing);
|
||||
|
||||
// 3. New turn with a background tool (should NOT be shown)
|
||||
// Background tool should not be shown
|
||||
const backgroundTool = {
|
||||
status: CoreToolCallStatus.Executing as const,
|
||||
request: {
|
||||
@@ -595,4 +588,144 @@ describe('useToolScheduler', () => {
|
||||
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('accumulates SUBAGENT_ACTIVITY events and attaches them to toolCalls', async () => {
|
||||
const { result } = await renderHook(() =>
|
||||
useToolScheduler(
|
||||
vi.fn().mockResolvedValue(undefined),
|
||||
mockConfig,
|
||||
() => undefined,
|
||||
),
|
||||
);
|
||||
|
||||
const mockToolCall = {
|
||||
status: CoreToolCallStatus.Executing as const,
|
||||
request: {
|
||||
callId: 'call-1',
|
||||
name: 'research',
|
||||
args: {},
|
||||
isClientInitiated: false,
|
||||
prompt_id: 'p1',
|
||||
},
|
||||
tool: createMockTool({ name: 'research' }),
|
||||
invocation: createMockInvocation(),
|
||||
} as ExecutingToolCall;
|
||||
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
toolCalls: [mockToolCall],
|
||||
schedulerId: ROOT_SCHEDULER_ID,
|
||||
} as ToolCallsUpdateMessage);
|
||||
});
|
||||
|
||||
expect(result.current[0]).toHaveLength(1);
|
||||
expect(result.current[0][0].subagentHistory).toBeUndefined();
|
||||
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: 'research',
|
||||
activity: {
|
||||
id: '1',
|
||||
type: 'thought',
|
||||
content: 'Thinking...',
|
||||
status: 'running',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current[0][0].subagentHistory).toHaveLength(1);
|
||||
expect(result.current[0][0].subagentHistory![0].content).toBe(
|
||||
'Thinking...',
|
||||
);
|
||||
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: 'research',
|
||||
activity: {
|
||||
id: '2',
|
||||
type: 'tool_call',
|
||||
content: 'Calling tool',
|
||||
status: 'completed',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current[0][0].subagentHistory).toHaveLength(2);
|
||||
expect(result.current[0][0].subagentHistory![1].content).toBe(
|
||||
'Calling tool',
|
||||
);
|
||||
});
|
||||
|
||||
it('replaces SUBAGENT_ACTIVITY events by ID instead of appending', async () => {
|
||||
const { result } = await renderHook(() =>
|
||||
useToolScheduler(
|
||||
vi.fn().mockResolvedValue(undefined),
|
||||
mockConfig,
|
||||
() => undefined,
|
||||
),
|
||||
);
|
||||
|
||||
const mockToolCall = {
|
||||
status: CoreToolCallStatus.Executing as const,
|
||||
request: {
|
||||
callId: 'call-1',
|
||||
name: 'research',
|
||||
args: {},
|
||||
isClientInitiated: false,
|
||||
prompt_id: 'p1',
|
||||
},
|
||||
tool: createMockTool({ name: 'research' }),
|
||||
invocation: createMockInvocation(),
|
||||
};
|
||||
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
toolCalls: [mockToolCall],
|
||||
schedulerId: ROOT_SCHEDULER_ID,
|
||||
});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: 'research',
|
||||
activity: {
|
||||
id: '1',
|
||||
type: 'thought',
|
||||
content: 'Thinking...',
|
||||
status: 'running',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current[0][0].subagentHistory).toHaveLength(1);
|
||||
expect(result.current[0][0].subagentHistory![0].content).toBe(
|
||||
'Thinking...',
|
||||
);
|
||||
|
||||
// Publish same ID with updated content
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: 'research',
|
||||
activity: {
|
||||
id: '1',
|
||||
type: 'thought',
|
||||
content: 'Thinking... Done!',
|
||||
status: 'completed',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Should still be length 1, and content should be updated
|
||||
expect(result.current[0][0].subagentHistory).toHaveLength(1);
|
||||
expect(result.current[0][0].subagentHistory![0].content).toBe(
|
||||
'Thinking... Done!',
|
||||
);
|
||||
expect(result.current[0][0].subagentHistory![0].status).toBe('completed');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
type EditorType,
|
||||
type ToolCallsUpdateMessage,
|
||||
CoreToolCallStatus,
|
||||
type SubagentActivityItem,
|
||||
type SubagentActivityMessage,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { useCallback, useState, useMemo, useEffect, useRef } from 'react';
|
||||
|
||||
@@ -33,6 +35,7 @@ export type CancelAllFn = (signal: AbortSignal) => void;
|
||||
*/
|
||||
export type TrackedToolCall = ToolCall & {
|
||||
responseSubmittedToGemini?: boolean;
|
||||
subagentHistory?: SubagentActivityItem[];
|
||||
};
|
||||
|
||||
// Narrowed types for specific statuses (used by useGeminiStream)
|
||||
@@ -81,6 +84,9 @@ export function useToolScheduler(
|
||||
Record<string, TrackedToolCall[]>
|
||||
>({});
|
||||
const [lastToolOutputTime, setLastToolOutputTime] = useState<number>(0);
|
||||
const [subagentHistoryMap, setSubagentHistoryMap] = useState<
|
||||
Record<string, SubagentActivityItem[]>
|
||||
>({});
|
||||
|
||||
const messageBus = useMemo(() => config.getMessageBus(), [config]);
|
||||
|
||||
@@ -173,10 +179,37 @@ export function useToolScheduler(
|
||||
};
|
||||
}, [messageBus, internalAdaptToolCalls]);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (event: SubagentActivityMessage) => {
|
||||
setSubagentHistoryMap((prev) => {
|
||||
const history = prev[event.subagentName] ?? [];
|
||||
const index = history.findIndex(
|
||||
(item) => item.id === event.activity.id,
|
||||
);
|
||||
const nextHistory = [...history];
|
||||
if (index >= 0) {
|
||||
nextHistory[index] = event.activity;
|
||||
} else {
|
||||
nextHistory.push(event.activity);
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
[event.subagentName]: nextHistory,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
messageBus.subscribe(MessageBusType.SUBAGENT_ACTIVITY, handler);
|
||||
return () => {
|
||||
messageBus.unsubscribe(MessageBusType.SUBAGENT_ACTIVITY, handler);
|
||||
};
|
||||
}, [messageBus]);
|
||||
|
||||
const schedule: ScheduleFn = useCallback(
|
||||
async (request, signal) => {
|
||||
// Clear state for new run
|
||||
setToolCallsMap({});
|
||||
setSubagentHistoryMap({});
|
||||
|
||||
// 1. Await Core Scheduler directly
|
||||
const results = await scheduler.schedule(request, signal);
|
||||
@@ -216,10 +249,38 @@ export function useToolScheduler(
|
||||
);
|
||||
|
||||
// Flatten the map for the UI components that expect a single list of tools.
|
||||
const toolCalls = useMemo(
|
||||
() => Object.values(toolCallsMap).flat(),
|
||||
[toolCallsMap],
|
||||
);
|
||||
const toolCalls = useMemo(() => {
|
||||
const flattened = Object.values(toolCallsMap).flat();
|
||||
return flattened.map((tc) => {
|
||||
let subagentName = tc.request.name;
|
||||
if (tc.request.name === 'invoke_subagent') {
|
||||
const argsObj = tc.request.args;
|
||||
let parsedArgs: unknown = argsObj;
|
||||
|
||||
if (typeof argsObj === 'string') {
|
||||
try {
|
||||
parsedArgs = JSON.parse(argsObj);
|
||||
} catch {
|
||||
parsedArgs = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof parsedArgs === 'object' && parsedArgs !== null) {
|
||||
for (const [key, value] of Object.entries(parsedArgs)) {
|
||||
if (key === 'subagent_name' && typeof value === 'string') {
|
||||
subagentName = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...tc,
|
||||
subagentHistory: subagentHistoryMap[subagentName] ?? tc.subagentHistory,
|
||||
};
|
||||
});
|
||||
}, [toolCallsMap, subagentHistoryMap]);
|
||||
|
||||
// Provide a setter that maintains compatibility with legacy [].
|
||||
const setToolCallsForDisplay = useCallback(
|
||||
@@ -272,7 +333,6 @@ function adaptToolCalls(
|
||||
return coreCalls.map((coreCall): TrackedToolCall => {
|
||||
const prev = prevMap.get(coreCall.request.callId);
|
||||
const responseSubmittedToGemini = prev?.responseSubmittedToGemini ?? false;
|
||||
|
||||
let status = coreCall.status;
|
||||
// If a tool call has completed but scheduled a tail call, it is in a transitional
|
||||
// state. Force the UI to render it as "executing".
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from '../../theme.js';
|
||||
import { interpolateColor } from '../../color-utils.js';
|
||||
|
||||
const palette = {
|
||||
bg: '#1a1b26',
|
||||
bg_dark: '#16161e',
|
||||
bg_dark1: '#0C0E14',
|
||||
bg_highlight: '#292e42',
|
||||
blue: '#7aa2f7',
|
||||
blue0: '#3d59a1',
|
||||
blue1: '#2ac3de',
|
||||
blue2: '#0db9d7',
|
||||
blue5: '#89ddff',
|
||||
blue6: '#b4f9f8',
|
||||
blue7: '#394b70',
|
||||
comment: '#565f89',
|
||||
cyan: '#7dcfff',
|
||||
fg: '#c0caf5',
|
||||
fg_dark: '#a9b1d6',
|
||||
fg_gutter: '#3b4261',
|
||||
green: '#9ece6a',
|
||||
green1: '#73daca',
|
||||
green2: '#41a6b5',
|
||||
magenta: '#bb9af7',
|
||||
magenta2: '#ff007c',
|
||||
orange: '#ff9e64',
|
||||
purple: '#9d7cd8',
|
||||
red: '#f7768e',
|
||||
red1: '#db4b4b',
|
||||
teal: '#1abc9c',
|
||||
yellow: '#e0af68',
|
||||
diff: {
|
||||
add: '#243e4a',
|
||||
change: '#1f2231',
|
||||
delete: '#4a272f',
|
||||
},
|
||||
};
|
||||
|
||||
const tokyoNightColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
Background: palette.bg,
|
||||
Foreground: palette.fg,
|
||||
LightBlue: palette.purple,
|
||||
AccentBlue: palette.magenta,
|
||||
AccentPurple: palette.blue,
|
||||
AccentCyan: palette.cyan,
|
||||
AccentGreen: palette.teal,
|
||||
AccentYellow: palette.yellow,
|
||||
AccentRed: palette.red1,
|
||||
DiffAdded: palette.diff.add,
|
||||
DiffRemoved: palette.diff.delete,
|
||||
Comment: palette.comment,
|
||||
Gray: palette.fg_dark,
|
||||
DarkGray: palette.fg_gutter,
|
||||
FocusColor: palette.blue,
|
||||
GradientColors: [palette.blue, palette.magenta, palette.cyan],
|
||||
};
|
||||
|
||||
export const TokyoNight: Theme = new Theme(
|
||||
'Tokyo Night',
|
||||
'dark',
|
||||
{
|
||||
hljs: {
|
||||
display: 'block',
|
||||
overflowX: 'auto',
|
||||
padding: '0.5em',
|
||||
background: palette.bg,
|
||||
color: palette.fg,
|
||||
},
|
||||
'hljs-addition': { background: palette.diff.add },
|
||||
'hljs-attr': { color: palette.green1 },
|
||||
'hljs-attribute': { color: palette.green1 },
|
||||
'hljs-brace': { color: palette.fg_dark },
|
||||
'hljs-built_in': { color: palette.blue1 },
|
||||
'hljs-builtin-symbol': { color: palette.blue1 },
|
||||
'hljs-bullet': {
|
||||
color: palette.orange,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-char': { color: palette.green },
|
||||
'hljs-char-escape': { color: palette.magenta },
|
||||
'hljs-character': { color: palette.green },
|
||||
'hljs-class': { color: palette.blue1 },
|
||||
'hljs-class-title': { color: palette.blue1 },
|
||||
'hljs-code': { color: palette.green },
|
||||
'hljs-comment': {
|
||||
color: palette.comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-computation-expression': { color: palette.cyan },
|
||||
'hljs-deletion': { background: palette.diff.delete },
|
||||
'hljs-doctag': { color: palette.yellow },
|
||||
'hljs-emphasis': { fontStyle: 'italic' },
|
||||
'hljs-function': { color: palette.blue },
|
||||
'hljs-function-dispatch': { color: palette.blue },
|
||||
'hljs-keyword': {
|
||||
color: palette.magenta,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-label': { color: palette.blue },
|
||||
'hljs-link': { color: palette.teal },
|
||||
'hljs-literal': { color: palette.orange },
|
||||
'hljs-message-name': { color: palette.blue },
|
||||
'hljs-meta': { color: palette.cyan },
|
||||
'hljs-meta-prompt': { color: palette.fg_dark },
|
||||
'hljs-name': { color: palette.magenta },
|
||||
'hljs-named-character': { color: palette.blue1 },
|
||||
'hljs-number': { color: palette.orange },
|
||||
'hljs-operator': { color: palette.blue5 },
|
||||
'hljs-params': { color: palette.yellow },
|
||||
'hljs-property': { color: palette.green1 },
|
||||
'hljs-punctuation': { color: palette.fg_dark },
|
||||
'hljs-quote': {
|
||||
color: palette.comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-regex': { color: palette.blue6 },
|
||||
'hljs-regexp': { color: palette.blue6 },
|
||||
'hljs-rest_arg': {
|
||||
color: interpolateColor(palette.yellow, palette.fg, 0.8),
|
||||
},
|
||||
'hljs-section': {
|
||||
color: palette.blue,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-selector-attr': { color: palette.cyan },
|
||||
'hljs-selector-class': { color: palette.green1 },
|
||||
'hljs-selector-id': { color: palette.green1 },
|
||||
'hljs-selector-pseudo': { color: palette.cyan },
|
||||
'hljs-selector-tag': { color: palette.magenta },
|
||||
'hljs-string': { color: palette.green },
|
||||
'hljs-strong': { fontWeight: 'bold' },
|
||||
'hljs-subst': { color: palette.blue5 },
|
||||
'hljs-symbol': { color: palette.magenta },
|
||||
'hljs-tag': { color: palette.blue1 },
|
||||
'hljs-template-tag': { color: palette.blue5 },
|
||||
'hljs-template-variable': { color: palette.fg },
|
||||
'hljs-title': { color: palette.blue },
|
||||
'hljs-title-class': { color: palette.blue1 },
|
||||
'hljs-title-class-inherited': { color: palette.blue1 },
|
||||
'hljs-title-function': { color: palette.blue },
|
||||
'hljs-title-function-invoke': { color: palette.blue },
|
||||
'hljs-type': { color: palette.blue1 },
|
||||
'hljs-variable': { color: palette.fg },
|
||||
'hljs-variable-constant': { color: palette.orange },
|
||||
'hljs-variable-language': { color: palette.red },
|
||||
},
|
||||
tokyoNightColors,
|
||||
);
|
||||
@@ -18,6 +18,7 @@ import { ShadesOfPurple } from './builtin/dark/shades-of-purple-dark.js';
|
||||
import { SolarizedDark } from './builtin/dark/solarized-dark.js';
|
||||
import { SolarizedLight } from './builtin/light/solarized-light.js';
|
||||
import { XCode } from './builtin/light/xcode-light.js';
|
||||
import { TokyoNight } from './builtin/dark/tokyonight-dark.js';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { Theme, ThemeType, ColorsTheme, CustomTheme } from './theme.js';
|
||||
@@ -84,6 +85,7 @@ class ThemeManager {
|
||||
SolarizedDark,
|
||||
SolarizedLight,
|
||||
XCode,
|
||||
TokyoNight,
|
||||
ANSI,
|
||||
ANSILight,
|
||||
];
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
type AnsiOutput,
|
||||
CoreToolCallStatus,
|
||||
checkExhaustive,
|
||||
type SubagentActivityItem,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { PartListUnion } from '@google/genai';
|
||||
import { type ReactNode } from 'react';
|
||||
@@ -135,6 +136,7 @@ export interface IndividualToolCallDisplay {
|
||||
originalRequestName?: string;
|
||||
progress?: number;
|
||||
progressTotal?: number;
|
||||
subagentHistory?: SubagentActivityItem[];
|
||||
}
|
||||
|
||||
export interface CompressionProps {
|
||||
@@ -290,6 +292,12 @@ export type HistoryItemChatList = HistoryItemBase & {
|
||||
chats: ChatDetail[];
|
||||
};
|
||||
|
||||
export type HistoryItemSubagent = HistoryItemBase & {
|
||||
type: 'subagent';
|
||||
agentName: string;
|
||||
history: SubagentActivityItem[];
|
||||
};
|
||||
|
||||
export interface ToolDefinition {
|
||||
name: string;
|
||||
displayName: string;
|
||||
@@ -395,7 +403,8 @@ export type HistoryItemWithoutId =
|
||||
| HistoryItemMcpStatus
|
||||
| HistoryItemChatList
|
||||
| HistoryItemThinking
|
||||
| HistoryItemHint;
|
||||
| HistoryItemHint
|
||||
| HistoryItemSubagent;
|
||||
|
||||
export type HistoryItem = HistoryItemWithoutId & { id: number };
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { styledCharsToString } from '@alcalzone/ansi-tokenize';
|
||||
import {
|
||||
Text,
|
||||
Box,
|
||||
type StyledChar,
|
||||
StyledLine,
|
||||
toStyledCharacters,
|
||||
styledCharsWidth,
|
||||
wordBreakStyledChars,
|
||||
wrapStyledChars,
|
||||
widestLineFromStyledChars,
|
||||
styledCharsWidth,
|
||||
styledCharsToString,
|
||||
} from 'ink';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { parseMarkdownToANSI } from './markdownParsingUtils.js';
|
||||
@@ -31,22 +31,22 @@ const COLUMN_PADDING = 2;
|
||||
const TABLE_MARGIN = 2;
|
||||
|
||||
/**
|
||||
* Parses markdown to StyledChar array by first converting to ANSI.
|
||||
* Parses markdown to StyledLine by first converting to ANSI.
|
||||
* This ensures character counts are accurate (markdown markers are removed
|
||||
* and styles are applied to the character's internal style object).
|
||||
*/
|
||||
const parseMarkdownToStyledChars = (
|
||||
const parseMarkdownToStyledLine = (
|
||||
text: string,
|
||||
defaultColor?: string,
|
||||
): StyledChar[] => {
|
||||
): StyledLine => {
|
||||
const ansi = parseMarkdownToANSI(text, defaultColor);
|
||||
return toStyledCharacters(ansi);
|
||||
};
|
||||
|
||||
const calculateWidths = (styledChars: StyledChar[]) => {
|
||||
const contentWidth = styledCharsWidth(styledChars);
|
||||
const calculateWidths = (styledLine: StyledLine) => {
|
||||
const contentWidth = styledCharsWidth(styledLine);
|
||||
|
||||
const words: StyledChar[][] = wordBreakStyledChars(styledChars);
|
||||
const words: StyledLine[] = wordBreakStyledChars(styledLine);
|
||||
const maxWordWidth = widestLineFromStyledChars(words);
|
||||
|
||||
return { contentWidth, maxWordWidth };
|
||||
@@ -67,10 +67,10 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
rows,
|
||||
terminalWidth,
|
||||
}) => {
|
||||
const styledHeaders = useMemo(
|
||||
const styledHeaders = useMemo<StyledLine[]>(
|
||||
() =>
|
||||
headers.map((header) =>
|
||||
parseMarkdownToStyledChars(
|
||||
parseMarkdownToStyledLine(
|
||||
stripUnsafeCharacters(header),
|
||||
theme.text.link,
|
||||
),
|
||||
@@ -78,11 +78,11 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
[headers],
|
||||
);
|
||||
|
||||
const styledRows = useMemo(
|
||||
const styledRows = useMemo<StyledLine[][]>(
|
||||
() =>
|
||||
rows.map((row) =>
|
||||
row.map((cell) =>
|
||||
parseMarkdownToStyledChars(
|
||||
parseMarkdownToStyledLine(
|
||||
stripUnsafeCharacters(cell),
|
||||
theme.text.primary,
|
||||
),
|
||||
@@ -100,14 +100,14 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
// --- Define Constraints per Column ---
|
||||
const constraints = Array.from({ length: numColumns }).map(
|
||||
(_, colIndex) => {
|
||||
const headerStyledChars = styledHeaders[colIndex] || [];
|
||||
const headerStyledLine = styledHeaders[colIndex] || StyledLine.empty(0);
|
||||
let { contentWidth: maxContentWidth, maxWordWidth } =
|
||||
calculateWidths(headerStyledChars);
|
||||
calculateWidths(headerStyledLine);
|
||||
|
||||
styledRows.forEach((row) => {
|
||||
const cellStyledChars = row[colIndex] || [];
|
||||
const cellStyledLine = row[colIndex] || StyledLine.empty(0);
|
||||
const { contentWidth: cellWidth, maxWordWidth: cellWordWidth } =
|
||||
calculateWidths(cellStyledChars);
|
||||
calculateWidths(cellStyledLine);
|
||||
|
||||
maxContentWidth = Math.max(maxContentWidth, cellWidth);
|
||||
maxWordWidth = Math.max(maxWordWidth, cellWordWidth);
|
||||
@@ -176,16 +176,16 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
// --- Pre-wrap and Optimize Widths ---
|
||||
const actualColumnWidths = new Array(numColumns).fill(0);
|
||||
|
||||
const wrapAndProcessRow = (row: StyledChar[][]) => {
|
||||
const wrapAndProcessRow = (row: StyledLine[]) => {
|
||||
const rowResult: ProcessedLine[][] = [];
|
||||
// Ensure we iterate up to numColumns, filling with empty cells if needed
|
||||
for (let colIndex = 0; colIndex < numColumns; colIndex++) {
|
||||
const cellStyledChars = row[colIndex] || [];
|
||||
const cellStyledLine = row[colIndex] || StyledLine.empty(0);
|
||||
const allocatedWidth = finalContentWidths[colIndex];
|
||||
const contentWidth = Math.max(1, allocatedWidth);
|
||||
|
||||
const wrappedStyledLines = wrapStyledChars(
|
||||
cellStyledChars,
|
||||
cellStyledLine,
|
||||
contentWidth,
|
||||
);
|
||||
|
||||
|
||||
@@ -14,25 +14,25 @@
|
||||
<text x="243" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="252" lengthAdjust="spacingAndGlyphs">├────────┼────────┼────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold">123456</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> 123456 </text>
|
||||
<text x="81" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="99" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Normal</text>
|
||||
<text x="90" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Normal </text>
|
||||
<text x="162" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="180" y="70" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="171" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="243" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="81" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="99" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold">123456</text>
|
||||
<text x="90" y="87" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> 123456 </text>
|
||||
<text x="162" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="180" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Normal</text>
|
||||
<text x="171" y="87" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Normal </text>
|
||||
<text x="243" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Normal</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Normal </text>
|
||||
<text x="81" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="99" y="104" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="90" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="162" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="180" y="104" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold">123456</text>
|
||||
<text x="171" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> 123456 </text>
|
||||
<text x="243" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="252" lengthAdjust="spacingAndGlyphs">└────────┴────────┴────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -14,31 +14,25 @@
|
||||
<text x="918" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="927" lengthAdjust="spacingAndGlyphs">├───────────────────────────────────┼───────────────────────────────┼─────────────────────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Visit Google (</text>
|
||||
<text x="144" y="70" fill="#87afff" textLength="162" lengthAdjust="spacingAndGlyphs">https://google.com</text>
|
||||
<text x="306" y="70" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">)</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="315" lengthAdjust="spacingAndGlyphs"> Visit Google (https://google.com) </text>
|
||||
<text x="324" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">Plain Text</text>
|
||||
<text x="333" y="70" fill="#ffffff" textLength="279" lengthAdjust="spacingAndGlyphs"> Plain Text </text>
|
||||
<text x="612" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="630" y="70" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">More Info</text>
|
||||
<text x="621" y="70" fill="#ffffff" textLength="297" lengthAdjust="spacingAndGlyphs"> More Info </text>
|
||||
<text x="918" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">Info Here</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="315" lengthAdjust="spacingAndGlyphs"> Info Here </text>
|
||||
<text x="324" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="87" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Visit Bing (</text>
|
||||
<text x="450" y="87" fill="#87afff" textLength="144" lengthAdjust="spacingAndGlyphs">https://bing.com</text>
|
||||
<text x="594" y="87" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">)</text>
|
||||
<text x="333" y="87" fill="#ffffff" textLength="279" lengthAdjust="spacingAndGlyphs"> Visit Bing (https://bing.com) </text>
|
||||
<text x="612" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="630" y="87" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Links</text>
|
||||
<text x="621" y="87" fill="#ffffff" textLength="297" lengthAdjust="spacingAndGlyphs"> Links </text>
|
||||
<text x="918" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">Check This</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="315" lengthAdjust="spacingAndGlyphs"> Check This </text>
|
||||
<text x="324" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="104" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Search</text>
|
||||
<text x="333" y="104" fill="#ffffff" textLength="279" lengthAdjust="spacingAndGlyphs"> Search </text>
|
||||
<text x="612" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="630" y="104" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs">Visit Yahoo (</text>
|
||||
<text x="747" y="104" fill="#87afff" textLength="153" lengthAdjust="spacingAndGlyphs">https://yahoo.com</text>
|
||||
<text x="900" y="104" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">)</text>
|
||||
<text x="621" y="104" fill="#ffffff" textLength="297" lengthAdjust="spacingAndGlyphs"> Visit Yahoo (https://yahoo.com) </text>
|
||||
<text x="918" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="927" lengthAdjust="spacingAndGlyphs">└───────────────────────────────────┴───────────────────────────────┴─────────────────────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.5 KiB |
@@ -14,26 +14,25 @@
|
||||
<text x="540" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="549" lengthAdjust="spacingAndGlyphs">├─────────────────┼──────────────────────┼──────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#d7afff" textLength="108" lengthAdjust="spacingAndGlyphs">**not bold**</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> **not bold** </text>
|
||||
<text x="162" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="180" y="70" fill="#d7afff" textLength="108" lengthAdjust="spacingAndGlyphs">_not italic_</text>
|
||||
<text x="171" y="70" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs"> _not italic_ </text>
|
||||
<text x="369" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="387" y="70" fill="#d7afff" textLength="126" lengthAdjust="spacingAndGlyphs">~~not strike~~</text>
|
||||
<text x="378" y="70" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> ~~not strike~~ </text>
|
||||
<text x="540" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#d7afff" textLength="135" lengthAdjust="spacingAndGlyphs">[not link](url)</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> [not link](url) </text>
|
||||
<text x="162" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="180" y="87" fill="#d7afff" textLength="180" lengthAdjust="spacingAndGlyphs"><u>not underline</u></text>
|
||||
<text x="171" y="87" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs"> <u>not underline</u> </text>
|
||||
<text x="369" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="387" y="87" fill="#d7afff" textLength="144" lengthAdjust="spacingAndGlyphs">https://not.link</text>
|
||||
<text x="378" y="87" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> https://not.link </text>
|
||||
<text x="540" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">Normal Text</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> Normal Text </text>
|
||||
<text x="162" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="180" y="104" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">More Code: </text>
|
||||
<text x="279" y="104" fill="#d7afff" textLength="54" lengthAdjust="spacingAndGlyphs">*test*</text>
|
||||
<text x="171" y="104" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs"> More Code: *test* </text>
|
||||
<text x="369" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="387" y="104" fill="#d7afff" textLength="108" lengthAdjust="spacingAndGlyphs">***nested***</text>
|
||||
<text x="378" y="104" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> ***nested*** </text>
|
||||
<text x="540" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="549" lengthAdjust="spacingAndGlyphs">└─────────────────┴──────────────────────┴──────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
@@ -14,31 +14,25 @@
|
||||
<text x="810" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="819" lengthAdjust="spacingAndGlyphs">├─────────────────────────────┼─────────────────────────────┼─────────────────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs" font-weight="bold">Bold with </text>
|
||||
<text x="108" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold" font-style="italic">Italic</text>
|
||||
<text x="162" y="70" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs" font-weight="bold"> and Strike</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Bold with Italic and Strike </text>
|
||||
<text x="270" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Normal</text>
|
||||
<text x="279" y="70" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Normal </text>
|
||||
<text x="540" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="558" y="70" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="549" y="70" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="810" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="270" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="87" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs" font-weight="bold">Bold with </text>
|
||||
<text x="378" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold" font-style="italic">Italic</text>
|
||||
<text x="432" y="87" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs" font-weight="bold"> and Strike</text>
|
||||
<text x="279" y="87" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Bold with Italic and Strike </text>
|
||||
<text x="540" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="558" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Normal</text>
|
||||
<text x="549" y="87" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Normal </text>
|
||||
<text x="810" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Normal</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Normal </text>
|
||||
<text x="270" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="104" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="279" y="104" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="540" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="558" y="104" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs" font-weight="bold">Bold with </text>
|
||||
<text x="648" y="104" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold" font-style="italic">Italic</text>
|
||||
<text x="702" y="104" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs" font-weight="bold"> and Strike</text>
|
||||
<text x="549" y="104" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Bold with Italic and Strike </text>
|
||||
<text x="810" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="819" lengthAdjust="spacingAndGlyphs">└─────────────────────────────┴─────────────────────────────┴─────────────────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -14,18 +14,18 @@
|
||||
<text x="378" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="405" lengthAdjust="spacingAndGlyphs">├──────────────┼────────────┼───────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">Start 🌟 End</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs"> Start 🌟 End </text>
|
||||
<text x="126" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="144" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">你好世界</text>
|
||||
<text x="135" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs"> 你好世界 </text>
|
||||
<text x="243" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="261" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Rocket 🚀 Man</text>
|
||||
<text x="252" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Rocket 🚀 Man </text>
|
||||
<text x="378" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">Thumbs 👍 Up</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs"> Thumbs 👍 Up </text>
|
||||
<text x="126" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="144" y="87" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">こんにちは</text>
|
||||
<text x="135" y="87" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs"> こんにちは </text>
|
||||
<text x="243" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="261" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Fire 🔥</text>
|
||||
<text x="252" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Fire 🔥 </text>
|
||||
<text x="378" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="405" lengthAdjust="spacingAndGlyphs">└──────────────┴────────────┴───────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -31,15 +31,15 @@
|
||||
<text x="288" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="297" lengthAdjust="spacingAndGlyphs">├─────────────┼───────┼─────────┤</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 1</text>
|
||||
<text x="9" y="121" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs"> Data 1 </text>
|
||||
<text x="126" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="144" y="121" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">Data</text>
|
||||
<text x="135" y="121" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> Data </text>
|
||||
<text x="198" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="216" y="121" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 3</text>
|
||||
<text x="207" y="121" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs"> Data 3 </text>
|
||||
<text x="288" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="126" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="144" y="138" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">2</text>
|
||||
<text x="135" y="138" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> 2 </text>
|
||||
<text x="198" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#333333" textLength="297" lengthAdjust="spacingAndGlyphs">└─────────────┴───────┴─────────┘</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
@@ -14,25 +14,25 @@
|
||||
<text x="405" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="414" lengthAdjust="spacingAndGlyphs">├──────────────┼──────────────┼──────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 1, Col 1</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 1, Col 1 </text>
|
||||
<text x="135" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 1, Col 2</text>
|
||||
<text x="144" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 1, Col 2 </text>
|
||||
<text x="270" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 1, Col 3</text>
|
||||
<text x="279" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 1, Col 3 </text>
|
||||
<text x="405" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 2, Col 1</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 2, Col 1 </text>
|
||||
<text x="135" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="87" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 2, Col 2</text>
|
||||
<text x="144" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 2, Col 2 </text>
|
||||
<text x="270" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="87" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 2, Col 3</text>
|
||||
<text x="279" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 2, Col 3 </text>
|
||||
<text x="405" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 3, Col 1</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 3, Col 1 </text>
|
||||
<text x="135" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="104" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 3, Col 2</text>
|
||||
<text x="144" y="104" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 3, Col 2 </text>
|
||||
<text x="270" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="104" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Row 3, Col 3</text>
|
||||
<text x="279" y="104" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Row 3, Col 3 </text>
|
||||
<text x="405" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="414" lengthAdjust="spacingAndGlyphs">└──────────────┴──────────────┴──────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
@@ -93,105 +93,105 @@
|
||||
<text x="1395" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#333333" textLength="1404" lengthAdjust="spacingAndGlyphs">├─────────────────────────────┼──────────────────────────────┼─────────────────────────────┼──────────────────────────────┼─────┼────────┼─────────┼───────┤</text>
|
||||
<text x="0" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="172" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">The primary architecture</text>
|
||||
<text x="9" y="172" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> The primary architecture </text>
|
||||
<text x="270" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="172" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">Each message is processed</text>
|
||||
<text x="279" y="172" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> Each message is processed </text>
|
||||
<text x="549" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="172" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">Historical data indicates a</text>
|
||||
<text x="558" y="172" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Historical data indicates a </text>
|
||||
<text x="819" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="172" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">A multi-layered defense</text>
|
||||
<text x="828" y="172" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> A multi-layered defense </text>
|
||||
<text x="1098" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1116" y="172" fill="#ffffff" textLength="27" lengthAdjust="spacingAndGlyphs">INF</text>
|
||||
<text x="1107" y="172" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs"> INF </text>
|
||||
<text x="1152" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1170" y="172" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Active</text>
|
||||
<text x="1161" y="172" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Active </text>
|
||||
<text x="1233" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1251" y="172" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">v2.4</text>
|
||||
<text x="1242" y="172" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs"> v2.4 </text>
|
||||
<text x="1323" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1341" y="172" fill="#ffffff" textLength="18" lengthAdjust="spacingAndGlyphs">J.</text>
|
||||
<text x="1332" y="172" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> J. </text>
|
||||
<text x="1395" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="189" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">utilizes a decoupled</text>
|
||||
<text x="9" y="189" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> utilizes a decoupled </text>
|
||||
<text x="270" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="189" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs">through a series of</text>
|
||||
<text x="279" y="189" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> through a series of </text>
|
||||
<text x="549" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="189" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">significant reduction in</text>
|
||||
<text x="558" y="189" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> significant reduction in </text>
|
||||
<text x="819" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="189" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">strategy incorporates</text>
|
||||
<text x="828" y="189" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> strategy incorporates </text>
|
||||
<text x="1098" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1341" y="189" fill="#ffffff" textLength="27" lengthAdjust="spacingAndGlyphs">Doe</text>
|
||||
<text x="1332" y="189" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> Doe </text>
|
||||
<text x="1395" y="189" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="206" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">microservices approach,</text>
|
||||
<text x="9" y="206" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> microservices approach, </text>
|
||||
<text x="270" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="206" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">specialized workers that</text>
|
||||
<text x="279" y="206" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> specialized workers that </text>
|
||||
<text x="549" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="206" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">tail latency when utilizing</text>
|
||||
<text x="558" y="206" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> tail latency when utilizing </text>
|
||||
<text x="819" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="206" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">content security policies,</text>
|
||||
<text x="828" y="206" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> content security policies, </text>
|
||||
<text x="1098" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="206" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="223" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">leveraging container</text>
|
||||
<text x="9" y="223" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> leveraging container </text>
|
||||
<text x="270" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="223" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">handle data transformation,</text>
|
||||
<text x="279" y="223" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> handle data transformation, </text>
|
||||
<text x="549" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="223" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">edge computing nodes closer</text>
|
||||
<text x="558" y="223" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> edge computing nodes closer </text>
|
||||
<text x="819" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="223" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">input sanitization</text>
|
||||
<text x="828" y="223" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> input sanitization </text>
|
||||
<text x="1098" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="223" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="240" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs">orchestration for</text>
|
||||
<text x="9" y="240" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> orchestration for </text>
|
||||
<text x="270" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="240" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">validation, and persistent</text>
|
||||
<text x="279" y="240" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> validation, and persistent </text>
|
||||
<text x="549" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="240" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">to the geographic location</text>
|
||||
<text x="558" y="240" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> to the geographic location </text>
|
||||
<text x="819" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="240" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">libraries, and regular</text>
|
||||
<text x="828" y="240" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> libraries, and regular </text>
|
||||
<text x="1098" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="240" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="257" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">scalability and fault</text>
|
||||
<text x="9" y="257" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> scalability and fault </text>
|
||||
<text x="270" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="257" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">storage using a persistent</text>
|
||||
<text x="279" y="257" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> storage using a persistent </text>
|
||||
<text x="549" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="257" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">of the end-user base.</text>
|
||||
<text x="558" y="257" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> of the end-user base. </text>
|
||||
<text x="819" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="257" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">automated penetration</text>
|
||||
<text x="828" y="257" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> automated penetration </text>
|
||||
<text x="1098" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="257" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="274" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">tolerance in high-load</text>
|
||||
<text x="9" y="274" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> tolerance in high-load </text>
|
||||
<text x="270" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="274" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">queue.</text>
|
||||
<text x="279" y="274" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> queue. </text>
|
||||
<text x="549" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="819" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="274" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs">testing routines.</text>
|
||||
<text x="828" y="274" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> testing routines. </text>
|
||||
<text x="1098" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="274" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="291" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">scenarios.</text>
|
||||
<text x="9" y="291" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> scenarios. </text>
|
||||
<text x="270" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="549" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="291" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">Monitoring tools have</text>
|
||||
<text x="558" y="291" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Monitoring tools have </text>
|
||||
<text x="819" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1098" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
@@ -200,85 +200,85 @@
|
||||
<text x="1395" y="291" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="270" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="308" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">The pipeline features</text>
|
||||
<text x="279" y="308" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> The pipeline features </text>
|
||||
<text x="549" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="308" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">captured a steady increase</text>
|
||||
<text x="558" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> captured a steady increase </text>
|
||||
<text x="819" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="308" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">Developers are required to</text>
|
||||
<text x="828" y="308" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> Developers are required to </text>
|
||||
<text x="1098" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="308" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="325" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">This layer provides the</text>
|
||||
<text x="9" y="325" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> This layer provides the </text>
|
||||
<text x="270" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="325" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">built-in retry mechanisms</text>
|
||||
<text x="279" y="325" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> built-in retry mechanisms </text>
|
||||
<text x="549" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="325" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">in throughput efficiency</text>
|
||||
<text x="558" y="325" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> in throughput efficiency </text>
|
||||
<text x="819" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="325" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">undergo mandatory security</text>
|
||||
<text x="828" y="325" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> undergo mandatory security </text>
|
||||
<text x="1098" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="325" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="342" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">fundamental building blocks</text>
|
||||
<text x="9" y="342" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> fundamental building blocks </text>
|
||||
<text x="270" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="342" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">with exponential backoff to</text>
|
||||
<text x="279" y="342" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> with exponential backoff to </text>
|
||||
<text x="549" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="342" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">since the introduction of</text>
|
||||
<text x="558" y="342" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> since the introduction of </text>
|
||||
<text x="819" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="342" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">training focusing on the</text>
|
||||
<text x="828" y="342" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> training focusing on the </text>
|
||||
<text x="1098" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="342" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="359" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">for service discovery, load</text>
|
||||
<text x="9" y="359" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> for service discovery, load </text>
|
||||
<text x="270" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="359" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">ensure message delivery</text>
|
||||
<text x="279" y="359" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> ensure message delivery </text>
|
||||
<text x="549" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="359" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">the vectorized query engine</text>
|
||||
<text x="558" y="359" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> the vectorized query engine </text>
|
||||
<text x="819" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">OWASP Top Ten to ensure that</text>
|
||||
<text x="828" y="359" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> OWASP Top Ten to ensure that </text>
|
||||
<text x="1098" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="359" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="376" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">balancing, and</text>
|
||||
<text x="9" y="376" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> balancing, and </text>
|
||||
<text x="270" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="376" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">integrity even during</text>
|
||||
<text x="279" y="376" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> integrity even during </text>
|
||||
<text x="549" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="376" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs">in the primary data</text>
|
||||
<text x="558" y="376" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> in the primary data </text>
|
||||
<text x="819" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="376" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">security is integrated into</text>
|
||||
<text x="828" y="376" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> security is integrated into </text>
|
||||
<text x="1098" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="376" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="393" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">inter-service communication</text>
|
||||
<text x="9" y="393" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> inter-service communication </text>
|
||||
<text x="270" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="393" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">transient network or service</text>
|
||||
<text x="279" y="393" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> transient network or service </text>
|
||||
<text x="549" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="393" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">warehouse.</text>
|
||||
<text x="558" y="393" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> warehouse. </text>
|
||||
<text x="819" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="393" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">the initial design phase.</text>
|
||||
<text x="828" y="393" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> the initial design phase. </text>
|
||||
<text x="1098" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="393" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="410" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">via highly efficient</text>
|
||||
<text x="9" y="410" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> via highly efficient </text>
|
||||
<text x="270" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="410" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">failures.</text>
|
||||
<text x="279" y="410" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> failures. </text>
|
||||
<text x="549" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="819" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1098" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
@@ -287,12 +287,12 @@
|
||||
<text x="1323" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="410" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="427" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs">protocol buffers.</text>
|
||||
<text x="9" y="427" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> protocol buffers. </text>
|
||||
<text x="270" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="549" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="427" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Resource utilization</text>
|
||||
<text x="558" y="427" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Resource utilization </text>
|
||||
<text x="819" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="427" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">The implementation of a</text>
|
||||
<text x="828" y="427" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> The implementation of a </text>
|
||||
<text x="1098" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
@@ -300,85 +300,85 @@
|
||||
<text x="1395" y="427" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="270" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="444" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">Horizontal autoscaling is</text>
|
||||
<text x="279" y="444" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> Horizontal autoscaling is </text>
|
||||
<text x="549" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="444" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">metrics demonstrate that</text>
|
||||
<text x="558" y="444" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> metrics demonstrate that </text>
|
||||
<text x="819" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="444" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">robust Identity and Access</text>
|
||||
<text x="828" y="444" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> robust Identity and Access </text>
|
||||
<text x="1098" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="444" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="461" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">Advanced telemetry and</text>
|
||||
<text x="9" y="461" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Advanced telemetry and </text>
|
||||
<text x="270" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="461" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">triggered automatically</text>
|
||||
<text x="279" y="461" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> triggered automatically </text>
|
||||
<text x="549" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="461" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs">the transition to</text>
|
||||
<text x="558" y="461" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> the transition to </text>
|
||||
<text x="819" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="461" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">Management system ensures</text>
|
||||
<text x="828" y="461" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> Management system ensures </text>
|
||||
<text x="1098" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="461" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="478" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">logging integrations allow</text>
|
||||
<text x="9" y="478" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> logging integrations allow </text>
|
||||
<text x="270" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="478" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">based on the depth of the</text>
|
||||
<text x="279" y="478" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> based on the depth of the </text>
|
||||
<text x="549" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="478" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">serverless compute for</text>
|
||||
<text x="558" y="478" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> serverless compute for </text>
|
||||
<text x="819" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="478" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">that the principle of least</text>
|
||||
<text x="828" y="478" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> that the principle of least </text>
|
||||
<text x="1098" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="478" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="495" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">for real-time monitoring of</text>
|
||||
<text x="9" y="495" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> for real-time monitoring of </text>
|
||||
<text x="270" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="495" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">processing queue, ensuring</text>
|
||||
<text x="279" y="495" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> processing queue, ensuring </text>
|
||||
<text x="549" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="495" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">intermittent tasks has</text>
|
||||
<text x="558" y="495" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> intermittent tasks has </text>
|
||||
<text x="819" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="495" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">privilege is strictly</text>
|
||||
<text x="828" y="495" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> privilege is strictly </text>
|
||||
<text x="1098" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="495" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="512" fill="#ffffff" textLength="207" lengthAdjust="spacingAndGlyphs">system health and rapid</text>
|
||||
<text x="9" y="512" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> system health and rapid </text>
|
||||
<text x="270" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="512" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">consistent performance</text>
|
||||
<text x="279" y="512" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> consistent performance </text>
|
||||
<text x="549" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="512" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">resulted in a thirty</text>
|
||||
<text x="558" y="512" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> resulted in a thirty </text>
|
||||
<text x="819" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="512" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs">enforced across all</text>
|
||||
<text x="828" y="512" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> enforced across all </text>
|
||||
<text x="1098" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="512" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="529" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs">identification of</text>
|
||||
<text x="9" y="529" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> identification of </text>
|
||||
<text x="270" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="529" fill="#ffffff" textLength="225" lengthAdjust="spacingAndGlyphs">during unexpected traffic</text>
|
||||
<text x="279" y="529" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> during unexpected traffic </text>
|
||||
<text x="549" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="567" y="529" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">percent cost optimization.</text>
|
||||
<text x="558" y="529" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> percent cost optimization. </text>
|
||||
<text x="819" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="837" y="529" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs">environments.</text>
|
||||
<text x="828" y="529" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> environments. </text>
|
||||
<text x="1098" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1152" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1233" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1323" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="529" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="546" fill="#ffffff" textLength="198" lengthAdjust="spacingAndGlyphs">bottlenecks within the</text>
|
||||
<text x="9" y="546" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> bottlenecks within the </text>
|
||||
<text x="270" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="546" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">spikes.</text>
|
||||
<text x="279" y="546" fill="#ffffff" textLength="270" lengthAdjust="spacingAndGlyphs"> spikes. </text>
|
||||
<text x="549" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="819" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1098" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
@@ -387,7 +387,7 @@
|
||||
<text x="1323" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="1395" y="546" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="563" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="563" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs">service mesh.</text>
|
||||
<text x="9" y="563" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> service mesh. </text>
|
||||
<text x="270" y="563" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="549" y="563" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="819" y="563" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
@@ -32,31 +32,31 @@
|
||||
<text x="630" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="639" lengthAdjust="spacingAndGlyphs">├───────────────┼───────────────┼──────────────────┼──────────────────┤</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 1.1</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 1.1 </text>
|
||||
<text x="144" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 1.2</text>
|
||||
<text x="153" y="104" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 1.2 </text>
|
||||
<text x="288" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="306" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 1.3</text>
|
||||
<text x="297" y="104" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Data 1.3 </text>
|
||||
<text x="459" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="477" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 1.4</text>
|
||||
<text x="468" y="104" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Data 1.4 </text>
|
||||
<text x="630" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 2.1</text>
|
||||
<text x="9" y="121" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 2.1 </text>
|
||||
<text x="144" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="121" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 2.2</text>
|
||||
<text x="153" y="121" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 2.2 </text>
|
||||
<text x="288" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="306" y="121" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 2.3</text>
|
||||
<text x="297" y="121" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Data 2.3 </text>
|
||||
<text x="459" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="477" y="121" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 2.4</text>
|
||||
<text x="468" y="121" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Data 2.4 </text>
|
||||
<text x="630" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="138" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 3.1</text>
|
||||
<text x="9" y="138" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 3.1 </text>
|
||||
<text x="144" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="138" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 3.2</text>
|
||||
<text x="153" y="138" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 3.2 </text>
|
||||
<text x="288" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="306" y="138" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 3.3</text>
|
||||
<text x="297" y="138" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Data 3.3 </text>
|
||||
<text x="459" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="477" y="138" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Data 3.4</text>
|
||||
<text x="468" y="138" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Data 3.4 </text>
|
||||
<text x="630" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#333333" textLength="639" lengthAdjust="spacingAndGlyphs">└───────────────┴───────────────┴──────────────────┴──────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.7 KiB |
@@ -14,18 +14,18 @@
|
||||
<text x="450" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="486" lengthAdjust="spacingAndGlyphs">├───────────────┼───────────────────┼────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">你好 😃</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> 你好 😃 </text>
|
||||
<text x="135" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">こんにちは 🚀</text>
|
||||
<text x="144" y="70" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> こんにちは 🚀 </text>
|
||||
<text x="306" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">안녕하세요 📝</text>
|
||||
<text x="315" y="70" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> 안녕하세요 📝 </text>
|
||||
<text x="450" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">World 🌍</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> World 🌍 </text>
|
||||
<text x="135" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Code 💻</text>
|
||||
<text x="144" y="87" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs"> Code 💻 </text>
|
||||
<text x="306" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="87" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">Pizza 🍕</text>
|
||||
<text x="315" y="87" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Pizza 🍕 </text>
|
||||
<text x="450" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="486" lengthAdjust="spacingAndGlyphs">└───────────────┴───────────────────┴────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -14,18 +14,18 @@
|
||||
<text x="441" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="450" lengthAdjust="spacingAndGlyphs">├──────────────┼─────────────────┼───────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">你好</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> 你好 </text>
|
||||
<text x="135" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">こんにちは</text>
|
||||
<text x="144" y="70" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> こんにちは </text>
|
||||
<text x="297" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="315" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">안녕하세요</text>
|
||||
<text x="306" y="70" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> 안녕하세요 </text>
|
||||
<text x="441" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">世界</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> 世界 </text>
|
||||
<text x="135" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="87" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">世界</text>
|
||||
<text x="144" y="87" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> 世界 </text>
|
||||
<text x="297" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="315" y="87" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">세계</text>
|
||||
<text x="306" y="87" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> 세계 </text>
|
||||
<text x="441" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="450" lengthAdjust="spacingAndGlyphs">└──────────────┴─────────────────┴───────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -14,18 +14,18 @@
|
||||
<text x="279" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="315" lengthAdjust="spacingAndGlyphs">├──────────┼───────────┼──────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">Smile 😃</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs"> Smile 😃 </text>
|
||||
<text x="90" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="108" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Fire 🔥</text>
|
||||
<text x="99" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs"> Fire 🔥 </text>
|
||||
<text x="189" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="207" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Love 💖</text>
|
||||
<text x="198" y="70" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs"> Love 💖 </text>
|
||||
<text x="279" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Cool 😎</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs"> Cool 😎 </text>
|
||||
<text x="90" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="108" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Star ⭐</text>
|
||||
<text x="99" y="87" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs"> Star ⭐ </text>
|
||||
<text x="189" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="207" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Blue 💙</text>
|
||||
<text x="198" y="87" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs"> Blue 💙 </text>
|
||||
<text x="279" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="315" lengthAdjust="spacingAndGlyphs">└──────────┴───────────┴──────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.1 KiB |
@@ -12,41 +12,39 @@
|
||||
<text x="414" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="423" lengthAdjust="spacingAndGlyphs">├───────────────┼─────────────────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">Bold</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Bold </text>
|
||||
<text x="144" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="70" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs" font-weight="bold">Bold Text</text>
|
||||
<text x="153" y="70" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Bold Text </text>
|
||||
<text x="414" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Italic</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Italic </text>
|
||||
<text x="144" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="87" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs" font-style="italic">Italic Text</text>
|
||||
<text x="153" y="87" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Italic Text </text>
|
||||
<text x="414" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Combined</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Combined </text>
|
||||
<text x="144" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="104" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs" font-weight="bold" font-style="italic">Bold and Italic</text>
|
||||
<text x="153" y="104" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Bold and Italic </text>
|
||||
<text x="414" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">Link</text>
|
||||
<text x="9" y="121" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Link </text>
|
||||
<text x="144" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="121" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">Google (</text>
|
||||
<text x="234" y="121" fill="#87afff" textLength="162" lengthAdjust="spacingAndGlyphs">https://google.com</text>
|
||||
<text x="396" y="121" fill="#ffffff" textLength="9" lengthAdjust="spacingAndGlyphs">)</text>
|
||||
<text x="153" y="121" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Google (https://google.com) </text>
|
||||
<text x="414" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="138" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">Code</text>
|
||||
<text x="9" y="138" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Code </text>
|
||||
<text x="144" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="138" fill="#d7afff" textLength="99" lengthAdjust="spacingAndGlyphs">const x = 1</text>
|
||||
<text x="153" y="138" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> const x = 1 </text>
|
||||
<text x="414" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="155" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs">Strikethrough</text>
|
||||
<text x="9" y="155" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Strikethrough </text>
|
||||
<text x="144" y="155" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="155" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Strike</text>
|
||||
<text x="153" y="155" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Strike </text>
|
||||
<text x="414" y="155" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="172" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">Underline</text>
|
||||
<text x="9" y="172" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Underline </text>
|
||||
<text x="144" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="162" y="172" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs" text-decoration="underline">Underline</text>
|
||||
<text x="153" y="172" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> Underline </text>
|
||||
<text x="414" y="172" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="189" fill="#333333" textLength="423" lengthAdjust="spacingAndGlyphs">└───────────────┴─────────────────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.2 KiB |
@@ -10,9 +10,9 @@
|
||||
<text x="162" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="171" lengthAdjust="spacingAndGlyphs">├────────┼────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 1</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Data 1 </text>
|
||||
<text x="81" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="99" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 2</text>
|
||||
<text x="90" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Data 2 </text>
|
||||
<text x="162" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="171" lengthAdjust="spacingAndGlyphs">└────────┴────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -14,9 +14,9 @@
|
||||
<text x="297" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="306" lengthAdjust="spacingAndGlyphs">├──────────┼──────────┼──────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 1</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs"> Data 1 </text>
|
||||
<text x="99" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="117" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 2</text>
|
||||
<text x="108" y="70" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs"> Data 2 </text>
|
||||
<text x="198" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="297" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="306" lengthAdjust="spacingAndGlyphs">└──────────┴──────────┴──────────┘</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -14,11 +14,11 @@
|
||||
<text x="405" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="414" lengthAdjust="spacingAndGlyphs">├─────────────┼───────────────┼──────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 1</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="117" lengthAdjust="spacingAndGlyphs"> Data 1 </text>
|
||||
<text x="126" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="144" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 2</text>
|
||||
<text x="135" y="70" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Data 2 </text>
|
||||
<text x="270" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="288" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Data 3</text>
|
||||
<text x="279" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs"> Data 3 </text>
|
||||
<text x="405" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="414" lengthAdjust="spacingAndGlyphs">└─────────────┴───────────────┴──────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -14,38 +14,38 @@
|
||||
<text x="468" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="477" lengthAdjust="spacingAndGlyphs">├────────────────┼────────────────┼─────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">This is a very</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> This is a very </text>
|
||||
<text x="153" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="171" y="70" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">This is also a</text>
|
||||
<text x="162" y="70" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> This is also a </text>
|
||||
<text x="306" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="70" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs">And this is the</text>
|
||||
<text x="315" y="70" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> And this is the </text>
|
||||
<text x="468" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">long text that</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> long text that </text>
|
||||
<text x="153" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="171" y="87" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">very long text</text>
|
||||
<text x="162" y="87" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> very long text </text>
|
||||
<text x="306" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="87" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs">third long text</text>
|
||||
<text x="315" y="87" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> third long text </text>
|
||||
<text x="468" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">needs wrapping</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> needs wrapping </text>
|
||||
<text x="153" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="171" y="104" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">that needs</text>
|
||||
<text x="162" y="104" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> that needs </text>
|
||||
<text x="306" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="104" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">that needs</text>
|
||||
<text x="315" y="104" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> that needs </text>
|
||||
<text x="468" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">in column 1</text>
|
||||
<text x="9" y="121" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> in column 1 </text>
|
||||
<text x="153" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="171" y="121" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">wrapping in</text>
|
||||
<text x="162" y="121" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> wrapping in </text>
|
||||
<text x="306" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="121" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">wrapping in</text>
|
||||
<text x="315" y="121" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> wrapping in </text>
|
||||
<text x="468" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="153" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="171" y="138" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">column 2</text>
|
||||
<text x="162" y="138" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs"> column 2 </text>
|
||||
<text x="306" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="138" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs">column 3</text>
|
||||
<text x="315" y="138" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> column 3 </text>
|
||||
<text x="468" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#333333" textLength="477" lengthAdjust="spacingAndGlyphs">└────────────────┴────────────────┴─────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.3 KiB |
@@ -14,37 +14,37 @@
|
||||
<text x="486" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="495" lengthAdjust="spacingAndGlyphs">├───────────────────┼───────────────┼─────────────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Start. Stop.</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs"> Start. Stop. </text>
|
||||
<text x="180" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="198" y="70" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Semi; colon:</text>
|
||||
<text x="189" y="70" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Semi; colon: </text>
|
||||
<text x="324" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="70" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">At@ Hash#</text>
|
||||
<text x="333" y="70" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> At@ Hash# </text>
|
||||
<text x="486" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="87" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs">Comma, separated.</text>
|
||||
<text x="9" y="87" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs"> Comma, separated. </text>
|
||||
<text x="180" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="198" y="87" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Pipe| Slash/</text>
|
||||
<text x="189" y="87" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Pipe| Slash/ </text>
|
||||
<text x="324" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="87" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs">Dollar$</text>
|
||||
<text x="333" y="87" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> Dollar$ </text>
|
||||
<text x="486" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="104" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Exclamation!</text>
|
||||
<text x="9" y="104" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs"> Exclamation! </text>
|
||||
<text x="180" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="198" y="104" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">Backslash\</text>
|
||||
<text x="189" y="104" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs"> Backslash\ </text>
|
||||
<text x="324" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="104" fill="#ffffff" textLength="135" lengthAdjust="spacingAndGlyphs">Percent% Caret^</text>
|
||||
<text x="333" y="104" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> Percent% Caret^ </text>
|
||||
<text x="486" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">Question?</text>
|
||||
<text x="9" y="121" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs"> Question? </text>
|
||||
<text x="180" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="121" fill="#ffffff" textLength="90" lengthAdjust="spacingAndGlyphs">Ampersand&</text>
|
||||
<text x="333" y="121" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> Ampersand& </text>
|
||||
<text x="486" y="121" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="138" fill="#ffffff" textLength="99" lengthAdjust="spacingAndGlyphs">hyphen-ated</text>
|
||||
<text x="9" y="138" fill="#ffffff" textLength="171" lengthAdjust="spacingAndGlyphs"> hyphen-ated </text>
|
||||
<text x="180" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="324" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="342" y="138" fill="#ffffff" textLength="81" lengthAdjust="spacingAndGlyphs">Asterisk*</text>
|
||||
<text x="333" y="138" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs"> Asterisk* </text>
|
||||
<text x="486" y="138" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#333333" textLength="495" lengthAdjust="spacingAndGlyphs">└───────────────────┴───────────────┴─────────────────┘</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.2 KiB |
@@ -14,20 +14,20 @@
|
||||
<text x="414" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="423" lengthAdjust="spacingAndGlyphs">├───────┼─────────────────────────────┼───────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="72" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="90" y="70" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">This is a very long cell</text>
|
||||
<text x="81" y="70" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> This is a very long cell </text>
|
||||
<text x="342" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="360" y="70" fill="#ffffff" textLength="45" lengthAdjust="spacingAndGlyphs">Short</text>
|
||||
<text x="351" y="70" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> Short </text>
|
||||
<text x="414" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="72" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="90" y="87" fill="#ffffff" textLength="243" lengthAdjust="spacingAndGlyphs">content that should wrap to</text>
|
||||
<text x="81" y="87" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> content that should wrap to </text>
|
||||
<text x="342" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="414" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="72" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="90" y="104" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">multiple lines</text>
|
||||
<text x="81" y="104" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs"> multiple lines </text>
|
||||
<text x="342" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="414" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="423" lengthAdjust="spacingAndGlyphs">└───────┴─────────────────────────────┴───────┘</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
@@ -14,21 +14,21 @@
|
||||
<text x="396" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="405" lengthAdjust="spacingAndGlyphs">├───────┼──────────────────────────┼────────┤</text>
|
||||
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="70" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">Tiny</text>
|
||||
<text x="9" y="70" fill="#ffffff" textLength="63" lengthAdjust="spacingAndGlyphs"> Tiny </text>
|
||||
<text x="72" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="90" y="70" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">This is a very long text</text>
|
||||
<text x="81" y="70" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs"> This is a very long text </text>
|
||||
<text x="315" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="333" y="70" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Not so</text>
|
||||
<text x="324" y="70" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> Not so </text>
|
||||
<text x="396" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="72" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="90" y="87" fill="#ffffff" textLength="216" lengthAdjust="spacingAndGlyphs">that definitely needs to</text>
|
||||
<text x="81" y="87" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs"> that definitely needs to </text>
|
||||
<text x="315" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="333" y="87" fill="#ffffff" textLength="36" lengthAdjust="spacingAndGlyphs">long</text>
|
||||
<text x="324" y="87" fill="#ffffff" textLength="72" lengthAdjust="spacingAndGlyphs"> long </text>
|
||||
<text x="396" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="72" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="90" y="104" fill="#ffffff" textLength="189" lengthAdjust="spacingAndGlyphs">wrap to the next line</text>
|
||||
<text x="81" y="104" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs"> wrap to the next line </text>
|
||||
<text x="315" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="396" y="104" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#333333" textLength="405" lengthAdjust="spacingAndGlyphs">└───────┴──────────────────────────┴────────┘</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
@@ -6,7 +6,7 @@
|
||||
|
||||
import { vi, beforeEach, afterEach } from 'vitest';
|
||||
import { format } from 'node:util';
|
||||
import { coreEvents } from '@google/gemini-cli-core';
|
||||
import { coreEvents, debugLogger } from '@google/gemini-cli-core';
|
||||
import { themeManager } from './src/ui/themes/theme-manager.js';
|
||||
import { mockInkSpinner } from './src/test-utils/mockSpinner.js';
|
||||
|
||||
@@ -42,10 +42,25 @@ import './src/test-utils/customMatchers.js';
|
||||
let consoleErrorSpy: vi.SpyInstance;
|
||||
let actWarnings: Array<{ message: string; stack: string }> = [];
|
||||
|
||||
let logSpy: vi.SpyInstance;
|
||||
let warnSpy: vi.SpyInstance;
|
||||
let errorSpy: vi.SpyInstance;
|
||||
let debugSpy: vi.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset themeManager state to ensure test isolation
|
||||
themeManager.resetForTesting();
|
||||
|
||||
// Mock debugLogger to avoid test output noise
|
||||
logSpy = vi.spyOn(debugLogger, 'log').mockImplementation(() => {});
|
||||
warnSpy = vi.spyOn(debugLogger, 'warn').mockImplementation((...args) => {
|
||||
console.warn(...args);
|
||||
});
|
||||
errorSpy = vi.spyOn(debugLogger, 'error').mockImplementation((...args) => {
|
||||
console.error(...args);
|
||||
});
|
||||
debugSpy = vi.spyOn(debugLogger, 'debug').mockImplementation(() => {});
|
||||
|
||||
actWarnings = [];
|
||||
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation((...args) => {
|
||||
const firstArg = args[0];
|
||||
@@ -88,8 +103,12 @@ beforeEach(() => {
|
||||
afterEach(() => {
|
||||
consoleErrorSpy.mockRestore();
|
||||
|
||||
vi.unstubAllEnvs();
|
||||
logSpy?.mockRestore();
|
||||
warnSpy?.mockRestore();
|
||||
errorSpy?.mockRestore();
|
||||
debugSpy?.mockRestore();
|
||||
|
||||
vi.unstubAllEnvs();
|
||||
if (actWarnings.length > 0) {
|
||||
const messages = actWarnings
|
||||
.map(({ message, stack }) => `${message}\n${stack}`)
|
||||
|
||||
@@ -166,7 +166,7 @@ describe('browserAgentFactory', () => {
|
||||
expect(browserManager).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call printOutput when provided', async () => {
|
||||
it('should not call printOutput for internal setup messages', async () => {
|
||||
const printOutput = vi.fn();
|
||||
|
||||
await createBrowserAgentDefinition(
|
||||
@@ -175,7 +175,7 @@ describe('browserAgentFactory', () => {
|
||||
printOutput,
|
||||
);
|
||||
|
||||
expect(printOutput).toHaveBeenCalled();
|
||||
expect(printOutput).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create definition with correct structure', async () => {
|
||||
|
||||
@@ -53,7 +53,7 @@ import {
|
||||
export async function createBrowserAgentDefinition(
|
||||
config: Config,
|
||||
messageBus: MessageBus,
|
||||
printOutput?: (msg: string) => void,
|
||||
_printOutput?: (msg: string) => void,
|
||||
): Promise<{
|
||||
definition: LocalAgentDefinition<typeof BrowserTaskResultSchema>;
|
||||
browserManager: BrowserManager;
|
||||
@@ -66,23 +66,17 @@ export async function createBrowserAgentDefinition(
|
||||
const browserManager = BrowserManager.getInstance(config);
|
||||
await browserManager.ensureConnection();
|
||||
|
||||
if (printOutput) {
|
||||
printOutput('Browser connected with isolated MCP client.');
|
||||
}
|
||||
debugLogger.log('Browser connected with isolated MCP client.');
|
||||
|
||||
// Determine if input blocker should be active (non-headless + enabled)
|
||||
const shouldDisableInput = config.shouldDisableBrowserUserInput();
|
||||
// Inject automation overlay and input blocker if not in headless mode
|
||||
const browserConfig = config.getBrowserAgentConfig();
|
||||
if (!browserConfig?.customConfig?.headless) {
|
||||
if (printOutput) {
|
||||
printOutput('Injecting automation overlay...');
|
||||
}
|
||||
debugLogger.log('Injecting automation overlay...');
|
||||
await injectAutomationOverlay(browserManager);
|
||||
if (shouldDisableInput) {
|
||||
if (printOutput) {
|
||||
printOutput('Injecting input blocker...');
|
||||
}
|
||||
debugLogger.log('Injecting input blocker...');
|
||||
await injectInputBlocker(browserManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import { randomUUID } from 'node:crypto';
|
||||
import type { Config } from '../../config/config.js';
|
||||
import { type AgentLoopContext } from '../../config/agent-loop-context.js';
|
||||
import { LocalAgentExecutor } from '../local-executor.js';
|
||||
import { safeJsonToMarkdown } from '../../utils/markdownUtils.js';
|
||||
import {
|
||||
BaseToolInvocation,
|
||||
type ToolResult,
|
||||
@@ -30,6 +29,7 @@ import {
|
||||
type SubagentActivityEvent,
|
||||
type SubagentProgress,
|
||||
type SubagentActivityItem,
|
||||
AgentTerminateMode,
|
||||
isToolActivityError,
|
||||
} from '../types.js';
|
||||
import type { MessageBus } from '../../confirmation-bus/message-bus.js';
|
||||
@@ -56,6 +56,8 @@ export class BrowserAgentInvocation extends BaseToolInvocation<
|
||||
AgentInputs,
|
||||
ToolResult
|
||||
> {
|
||||
private readonly agentName: string;
|
||||
|
||||
constructor(
|
||||
private readonly context: AgentLoopContext,
|
||||
params: AgentInputs,
|
||||
@@ -63,13 +65,15 @@ export class BrowserAgentInvocation extends BaseToolInvocation<
|
||||
_toolName?: string,
|
||||
_toolDisplayName?: string,
|
||||
) {
|
||||
const resolvedName = _toolName ?? 'browser_agent';
|
||||
// Note: BrowserAgentDefinition is a factory function, so we use hardcoded names
|
||||
super(
|
||||
params,
|
||||
messageBus,
|
||||
_toolName ?? 'browser_agent',
|
||||
resolvedName,
|
||||
_toolDisplayName ?? 'Browser Agent',
|
||||
);
|
||||
this.agentName = resolvedName;
|
||||
}
|
||||
|
||||
private get config(): Config {
|
||||
@@ -112,7 +116,7 @@ export class BrowserAgentInvocation extends BaseToolInvocation<
|
||||
// Send initial state
|
||||
const initialProgress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this['_toolName'] ?? 'browser_agent',
|
||||
agentName: this.agentName,
|
||||
recentActivity: [],
|
||||
state: 'running',
|
||||
};
|
||||
@@ -135,7 +139,7 @@ export class BrowserAgentInvocation extends BaseToolInvocation<
|
||||
}
|
||||
updateOutput({
|
||||
isSubagentProgress: true,
|
||||
agentName: this['_toolName'] ?? 'browser_agent',
|
||||
agentName: this.agentName,
|
||||
recentActivity: [...recentActivity],
|
||||
state: 'running',
|
||||
} as SubagentProgress);
|
||||
@@ -280,7 +284,7 @@ export class BrowserAgentInvocation extends BaseToolInvocation<
|
||||
|
||||
const progress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this['_toolName'] ?? 'browser_agent',
|
||||
agentName: this.agentName,
|
||||
recentActivity: [...recentActivity],
|
||||
state: 'running',
|
||||
};
|
||||
@@ -297,34 +301,40 @@ export class BrowserAgentInvocation extends BaseToolInvocation<
|
||||
|
||||
const output = await executor.run(this.params, signal);
|
||||
|
||||
const displayResult = safeJsonToMarkdown(output.result);
|
||||
|
||||
const resultContent = `Browser agent finished.
|
||||
Termination Reason: ${output.terminate_reason}
|
||||
Result:
|
||||
${output.result}`;
|
||||
|
||||
const displayContent = `
|
||||
Browser Agent Finished
|
||||
// Map terminate_reason to the correct SubagentProgress state.
|
||||
// GOAL = agent completed its task normally.
|
||||
// ABORTED = user cancelled.
|
||||
// Others (ERROR, MAX_TURNS, ERROR_NO_COMPLETE_TASK_CALL) = error.
|
||||
let progressState: SubagentProgress['state'];
|
||||
if (output.terminate_reason === AgentTerminateMode.ABORTED) {
|
||||
progressState = 'cancelled';
|
||||
} else if (output.terminate_reason === AgentTerminateMode.GOAL) {
|
||||
progressState = 'completed';
|
||||
} else {
|
||||
progressState = 'error';
|
||||
}
|
||||
|
||||
Termination Reason: ${output.terminate_reason}
|
||||
|
||||
Result:
|
||||
${displayResult}
|
||||
`;
|
||||
const progress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this.agentName,
|
||||
recentActivity: [...recentActivity],
|
||||
state: progressState,
|
||||
result: output.result,
|
||||
terminateReason: output.terminate_reason,
|
||||
};
|
||||
|
||||
if (updateOutput) {
|
||||
updateOutput({
|
||||
isSubagentProgress: true,
|
||||
agentName: this['_toolName'] ?? 'browser_agent',
|
||||
recentActivity: [...recentActivity],
|
||||
state: 'completed',
|
||||
} as SubagentProgress);
|
||||
updateOutput(progress);
|
||||
}
|
||||
|
||||
return {
|
||||
llmContent: [{ text: resultContent }],
|
||||
returnDisplay: displayContent,
|
||||
returnDisplay: progress,
|
||||
};
|
||||
} catch (error) {
|
||||
const rawErrorMessage =
|
||||
@@ -343,7 +353,7 @@ ${displayResult}
|
||||
|
||||
const progress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this['_toolName'] ?? 'browser_agent',
|
||||
agentName: this.agentName,
|
||||
recentActivity: [...recentActivity],
|
||||
state: isAbort ? 'cancelled' : 'error',
|
||||
};
|
||||
|
||||
@@ -108,7 +108,7 @@ import {
|
||||
} from '../scheduler/types.js';
|
||||
|
||||
import { CompressionStatus } from '../core/turn.js';
|
||||
import { ChatCompressionService } from '../services/chatCompressionService.js';
|
||||
import { ChatCompressionService } from '../context/chatCompressionService.js';
|
||||
import type {
|
||||
ModelConfigKey,
|
||||
ResolvedModelConfig,
|
||||
@@ -121,7 +121,7 @@ const mockSetHistory = vi.fn((newHistory: Content[]) => {
|
||||
mockChatHistory = newHistory;
|
||||
});
|
||||
|
||||
vi.mock('../services/chatCompressionService.js', () => ({
|
||||
vi.mock('../context/chatCompressionService.js', () => ({
|
||||
ChatCompressionService: vi.fn().mockImplementation(() => ({
|
||||
compress: mockCompress,
|
||||
})),
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
} from '../tools/mcp-tool.js';
|
||||
import { CompressionStatus } from '../core/turn.js';
|
||||
import { type ToolCallRequestInfo } from '../scheduler/types.js';
|
||||
import { ChatCompressionService } from '../services/chatCompressionService.js';
|
||||
import { ChatCompressionService } from '../context/chatCompressionService.js';
|
||||
import { getDirectoryContextString } from '../utils/environmentContext.js';
|
||||
import { renderUserMemory } from '../prompts/snippets.js';
|
||||
import { promptIdContext } from '../utils/promptIdContext.js';
|
||||
|
||||
@@ -510,5 +510,36 @@ describe('LocalSubagentInvocation', () => {
|
||||
'Operation cancelled by user',
|
||||
);
|
||||
});
|
||||
|
||||
it('should publish SUBAGENT_ACTIVITY events to the MessageBus', async () => {
|
||||
const { MessageBusType } = await import('../confirmation-bus/types.js');
|
||||
|
||||
mockExecutorInstance.run.mockImplementation(async () => {
|
||||
const onActivity = MockLocalAgentExecutor.create.mock.calls[0][2];
|
||||
|
||||
if (onActivity) {
|
||||
onActivity({
|
||||
isSubagentActivityEvent: true,
|
||||
agentName: 'MockAgent',
|
||||
type: 'THOUGHT_CHUNK',
|
||||
data: { text: 'Thinking...' },
|
||||
} as SubagentActivityEvent);
|
||||
}
|
||||
return { result: 'Done', terminate_reason: AgentTerminateMode.GOAL };
|
||||
});
|
||||
|
||||
await invocation.execute(signal, updateOutput);
|
||||
|
||||
expect(mockMessageBus.publish).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: 'Mock Agent',
|
||||
activity: expect.objectContaining({
|
||||
type: 'thought',
|
||||
content: 'Thinking...',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type AgentLoopContext } from '../config/agent-loop-context.js';
|
||||
import { MessageBusType } from '../confirmation-bus/types.js';
|
||||
import { LocalAgentExecutor } from './local-executor.js';
|
||||
import {
|
||||
BaseToolInvocation,
|
||||
@@ -33,7 +34,6 @@ import {
|
||||
|
||||
const INPUT_PREVIEW_MAX_LENGTH = 50;
|
||||
const DESCRIPTION_MAX_LENGTH = 200;
|
||||
const MAX_RECENT_ACTIVITY = 3;
|
||||
|
||||
/**
|
||||
* Represents a validated, executable instance of a subagent tool.
|
||||
@@ -87,6 +87,14 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
return description.slice(0, DESCRIPTION_MAX_LENGTH);
|
||||
}
|
||||
|
||||
private publishActivity(activity: SubagentActivityItem): void {
|
||||
void this.messageBus.publish({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: this.definition.displayName ?? this.definition.name,
|
||||
activity,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the subagent.
|
||||
*
|
||||
@@ -99,7 +107,7 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
signal: AbortSignal,
|
||||
updateOutput?: (output: ToolLiveOutput) => void,
|
||||
): Promise<ToolResult> {
|
||||
let recentActivity: SubagentActivityItem[] = [];
|
||||
const recentActivity: SubagentActivityItem[] = [];
|
||||
|
||||
try {
|
||||
if (updateOutput) {
|
||||
@@ -140,6 +148,11 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
});
|
||||
}
|
||||
updated = true;
|
||||
|
||||
const latestThought = recentActivity[recentActivity.length - 1];
|
||||
if (latestThought) {
|
||||
this.publishActivity(latestThought);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'TOOL_CALL_START': {
|
||||
@@ -163,6 +176,11 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
status: 'running',
|
||||
});
|
||||
updated = true;
|
||||
|
||||
const latestTool = recentActivity[recentActivity.length - 1];
|
||||
if (latestTool) {
|
||||
this.publishActivity(latestTool);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'TOOL_CALL_END': {
|
||||
@@ -178,6 +196,8 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
) {
|
||||
recentActivity[i].status = isError ? 'error' : 'completed';
|
||||
updated = true;
|
||||
|
||||
this.publishActivity(recentActivity[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -242,11 +262,6 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
// Keep only the last N items
|
||||
if (recentActivity.length > MAX_RECENT_ACTIVITY) {
|
||||
recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
|
||||
}
|
||||
|
||||
const progress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this.definition.name,
|
||||
@@ -332,9 +347,7 @@ ${output.result}`;
|
||||
status: 'error',
|
||||
});
|
||||
// Maintain size limit
|
||||
if (recentActivity.length > MAX_RECENT_ACTIVITY) {
|
||||
recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
|
||||
}
|
||||
// No limit on UI events sent via bus
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ vi.mock('../utils/fetch.js', () => ({
|
||||
setGlobalProxy: mockSetGlobalProxy,
|
||||
}));
|
||||
|
||||
vi.mock('../services/contextManager.js', () => ({
|
||||
vi.mock('../context/contextManager.js', () => ({
|
||||
ContextManager: vi.fn().mockImplementation(() => ({
|
||||
refresh: vi.fn(),
|
||||
getGlobalMemory: vi.fn().mockReturnValue(''),
|
||||
@@ -237,7 +237,7 @@ import { tokenLimit } from '../core/tokenLimits.js';
|
||||
import { getCodeAssistServer } from '../code_assist/codeAssist.js';
|
||||
import { getExperiments } from '../code_assist/experiments/experiments.js';
|
||||
import type { CodeAssistServer } from '../code_assist/server.js';
|
||||
import { ContextManager } from '../services/contextManager.js';
|
||||
import { ContextManager } from '../context/contextManager.js';
|
||||
import { UserTierId } from '../code_assist/types.js';
|
||||
import type {
|
||||
ModelConfigService,
|
||||
@@ -591,6 +591,55 @@ describe('Server Config (config.ts)', () => {
|
||||
expect(await config.getResolvedClassifierThreshold()).toBe(90);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGemini31LaunchedSync', () => {
|
||||
it.each([AuthType.USE_GEMINI, AuthType.USE_VERTEX_AI, AuthType.GATEWAY])(
|
||||
'should return true for %s',
|
||||
async (authType) => {
|
||||
const config = new Config(baseParams);
|
||||
vi.mocked(createContentGeneratorConfig).mockResolvedValue({
|
||||
authType,
|
||||
});
|
||||
await config.refreshAuth(authType);
|
||||
expect(config.getGemini31LaunchedSync()).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it('should fallback to experiments for other auth types', async () => {
|
||||
vi.mocked(getExperiments).mockResolvedValue({
|
||||
experimentIds: [],
|
||||
flags: {
|
||||
[ExperimentFlags.GEMINI_3_1_PRO_LAUNCHED]: {
|
||||
flagId: ExperimentFlags.GEMINI_3_1_PRO_LAUNCHED,
|
||||
boolValue: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const config = new Config(baseParams);
|
||||
|
||||
vi.mocked(createContentGeneratorConfig).mockResolvedValue({
|
||||
authType: AuthType.LOGIN_WITH_GOOGLE,
|
||||
});
|
||||
|
||||
await config.refreshAuth(AuthType.LOGIN_WITH_GOOGLE);
|
||||
expect(config.getGemini31LaunchedSync()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGemini31FlashLiteLaunchedSync', () => {
|
||||
it.each([AuthType.USE_GEMINI, AuthType.USE_VERTEX_AI, AuthType.GATEWAY])(
|
||||
'should return true for %s',
|
||||
async (authType) => {
|
||||
const config = new Config(baseParams);
|
||||
vi.mocked(createContentGeneratorConfig).mockResolvedValue({
|
||||
authType,
|
||||
});
|
||||
await config.refreshAuth(authType);
|
||||
expect(config.getGemini31FlashLiteLaunchedSync()).toBe(true);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('refreshAuth', () => {
|
||||
|
||||
@@ -116,7 +116,7 @@ import {
|
||||
type ModelConfigServiceConfig,
|
||||
} from '../services/modelConfigService.js';
|
||||
import { DEFAULT_MODEL_CONFIGS } from './defaultModelConfigs.js';
|
||||
import { ContextManager } from '../services/contextManager.js';
|
||||
import { ContextManager } from '../context/contextManager.js';
|
||||
import { TrackerService } from '../services/trackerService.js';
|
||||
import type { GenerateContentParameters } from '@google/genai';
|
||||
|
||||
@@ -451,7 +451,7 @@ import {
|
||||
DEFAULT_TOOL_PROTECTION_THRESHOLD,
|
||||
DEFAULT_MIN_PRUNABLE_TOKENS_THRESHOLD,
|
||||
DEFAULT_PROTECT_LATEST_TURN,
|
||||
} from '../services/toolOutputMaskingService.js';
|
||||
} from '../context/toolOutputMaskingService.js';
|
||||
|
||||
import {
|
||||
type ExtensionLoader,
|
||||
@@ -979,9 +979,29 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
networkAccess: false,
|
||||
};
|
||||
|
||||
this._sandboxManager = createSandboxManager(this.sandbox, {
|
||||
workspace: params.targetDir,
|
||||
});
|
||||
this.targetDir = path.resolve(params.targetDir);
|
||||
this.folderTrust = params.folderTrust ?? false;
|
||||
this.workspaceContext = new WorkspaceContext(this.targetDir, []);
|
||||
this.pendingIncludeDirectories = params.includeDirectories ?? [];
|
||||
this.debugMode = params.debugMode;
|
||||
this.question = params.question;
|
||||
this.worktreeSettings = params.worktreeSettings;
|
||||
|
||||
this._sandboxPolicyManager = new SandboxPolicyManager();
|
||||
const initialApprovalMode =
|
||||
params.approvalMode ??
|
||||
params.policyEngineConfig?.approvalMode ??
|
||||
'default';
|
||||
|
||||
this._sandboxManager = createSandboxManager(
|
||||
this.sandbox,
|
||||
{
|
||||
workspace: this.targetDir,
|
||||
includeDirectories: this.pendingIncludeDirectories,
|
||||
policyManager: this._sandboxPolicyManager,
|
||||
},
|
||||
initialApprovalMode,
|
||||
);
|
||||
|
||||
if (
|
||||
!(this._sandboxManager instanceof NoopSandboxManager) &&
|
||||
@@ -995,36 +1015,6 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
this.fileSystemService = new StandardFileSystemService();
|
||||
}
|
||||
|
||||
this._sandboxPolicyManager = new SandboxPolicyManager();
|
||||
const initialApprovalMode =
|
||||
params.approvalMode ??
|
||||
params.policyEngineConfig?.approvalMode ??
|
||||
'default';
|
||||
this._sandboxManager = createSandboxManager(
|
||||
this.sandbox,
|
||||
{
|
||||
workspace: params.targetDir,
|
||||
policyManager: this._sandboxPolicyManager,
|
||||
},
|
||||
initialApprovalMode,
|
||||
);
|
||||
|
||||
if (
|
||||
!(this._sandboxManager instanceof NoopSandboxManager) &&
|
||||
this.sandbox?.enabled
|
||||
) {
|
||||
this.fileSystemService = new SandboxedFileSystemService(
|
||||
this._sandboxManager,
|
||||
params.targetDir,
|
||||
);
|
||||
} else {
|
||||
this.fileSystemService = new StandardFileSystemService();
|
||||
}
|
||||
|
||||
this.targetDir = path.resolve(params.targetDir);
|
||||
this.folderTrust = params.folderTrust ?? false;
|
||||
this.workspaceContext = new WorkspaceContext(this.targetDir, []);
|
||||
this.pendingIncludeDirectories = params.includeDirectories ?? [];
|
||||
this.debugMode = params.debugMode;
|
||||
this.question = params.question;
|
||||
this.worktreeSettings = params.worktreeSettings;
|
||||
@@ -1151,7 +1141,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
modelConfigServiceConfig ?? DEFAULT_MODEL_CONFIGS,
|
||||
);
|
||||
|
||||
this.experimentalJitContext = params.experimentalJitContext ?? true;
|
||||
this.experimentalJitContext = params.experimentalJitContext ?? false;
|
||||
this.experimentalMemoryManager = params.experimentalMemoryManager ?? false;
|
||||
this.memoryBoundaryMarkers = params.memoryBoundaryMarkers ?? ['.git'];
|
||||
this.contextManagement = {
|
||||
@@ -3093,6 +3083,14 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
return useGemini3_1 && authType === AuthType.USE_GEMINI;
|
||||
}
|
||||
|
||||
private isGemini31LaunchedForAuthType(authType?: AuthType): boolean {
|
||||
return (
|
||||
authType === AuthType.USE_GEMINI ||
|
||||
authType === AuthType.USE_VERTEX_AI ||
|
||||
authType === AuthType.GATEWAY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Gemini 3.1 has been launched.
|
||||
*
|
||||
@@ -3102,10 +3100,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
*/
|
||||
getGemini31LaunchedSync(): boolean {
|
||||
const authType = this.contentGeneratorConfig?.authType;
|
||||
if (
|
||||
authType === AuthType.USE_GEMINI ||
|
||||
authType === AuthType.USE_VERTEX_AI
|
||||
) {
|
||||
if (this.isGemini31LaunchedForAuthType(authType)) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
@@ -3123,10 +3118,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
*/
|
||||
getGemini31FlashLiteLaunchedSync(): boolean {
|
||||
const authType = this.contentGeneratorConfig?.authType;
|
||||
if (
|
||||
authType === AuthType.USE_GEMINI ||
|
||||
authType === AuthType.USE_VERTEX_AI
|
||||
) {
|
||||
if (this.isGemini31LaunchedForAuthType(authType)) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
} from '../tools/tools.js';
|
||||
import type { ToolCall } from '../scheduler/types.js';
|
||||
import type { SandboxPermissions } from '../services/sandboxManager.js';
|
||||
import type { SubagentActivityItem } from '../agents/types.js';
|
||||
|
||||
export enum MessageBusType {
|
||||
TOOL_CONFIRMATION_REQUEST = 'tool-confirmation-request',
|
||||
@@ -23,6 +24,7 @@ export enum MessageBusType {
|
||||
TOOL_CALLS_UPDATE = 'tool-calls-update',
|
||||
ASK_USER_REQUEST = 'ask-user-request',
|
||||
ASK_USER_RESPONSE = 'ask-user-response',
|
||||
SUBAGENT_ACTIVITY = 'subagent-activity',
|
||||
}
|
||||
|
||||
export interface ToolCallsUpdateMessage {
|
||||
@@ -207,6 +209,12 @@ export interface AskUserResponse {
|
||||
cancelled?: boolean;
|
||||
}
|
||||
|
||||
export interface SubagentActivityMessage {
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY;
|
||||
subagentName: string;
|
||||
activity: SubagentActivityItem;
|
||||
}
|
||||
|
||||
export type Message =
|
||||
| ToolConfirmationRequest
|
||||
| ToolConfirmationResponse
|
||||
@@ -216,4 +224,5 @@ export type Message =
|
||||
| UpdatePolicy
|
||||
| AskUserRequest
|
||||
| AskUserResponse
|
||||
| ToolCallsUpdateMessage;
|
||||
| ToolCallsUpdateMessage
|
||||
| SubagentActivityMessage;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`ToolOutputMaskingService > should match the expected snapshot for a masked tool output 1`] = `
|
||||
"<tool_output_masked>
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
|
||||
... [6 lines omitted] ...
|
||||
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
|
||||
|
||||
Output too large. Full output available at: /mock/temp/tool-outputs/session-mock-session/run_shell_command_deterministic.txt
|
||||
</tool_output_masked>"
|
||||
`;
|
||||
@@ -17,12 +17,12 @@ vi.mock('../utils/tokenCalculation.js', () => ({
|
||||
import type { Content, GenerateContentResponse, Part } from '@google/genai';
|
||||
import type { Config, ContextManagementConfig } from '../config/config.js';
|
||||
import type { BaseLlmClient } from '../core/baseLlmClient.js';
|
||||
import type { AgentHistoryProviderConfig } from './types.js';
|
||||
import type { AgentHistoryProviderConfig } from '../services/types.js';
|
||||
import {
|
||||
TEXT_TRUNCATION_PREFIX,
|
||||
TOOL_TRUNCATION_PREFIX,
|
||||
truncateProportionally,
|
||||
} from 'src/utils/truncation.js';
|
||||
} from './truncation.js';
|
||||
|
||||
describe('AgentHistoryProvider', () => {
|
||||
let config: Config;
|
||||
@@ -9,7 +9,7 @@ import { getResponseText } from '../utils/partUtils.js';
|
||||
import { estimateTokenCountSync } from '../utils/tokenCalculation.js';
|
||||
import { LlmRole } from '../telemetry/llmRole.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import type { AgentHistoryProviderConfig } from './types.js';
|
||||
import type { AgentHistoryProviderConfig } from '../services/types.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import {
|
||||
MIN_TARGET_TOKENS,
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
estimateCharsFromTokens,
|
||||
truncateProportionally,
|
||||
normalizeFunctionResponse,
|
||||
} from '../utils/truncation.js';
|
||||
} from './truncation.js';
|
||||
|
||||
export class AgentHistoryProvider {
|
||||
// TODO(joshualitt): just pass the BaseLlmClient instead of the whole Config.
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
MIN_TARGET_TOKENS,
|
||||
estimateCharsFromTokens,
|
||||
normalizeFunctionResponse,
|
||||
} from '../utils/truncation.js';
|
||||
} from './truncation.js';
|
||||
|
||||
// Skip structural map generation for outputs larger than this threshold (in characters)
|
||||
// as it consumes excessive tokens and may not be representative of the full content.
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
estimateTokenCountSync,
|
||||
ASCII_TOKENS_PER_CHAR,
|
||||
NON_ASCII_TOKENS_PER_CHAR,
|
||||
} from './tokenCalculation.js';
|
||||
} from '../utils/tokenCalculation.js';
|
||||
|
||||
export const MIN_TARGET_TOKENS = 10;
|
||||
export const MIN_CHARS_FOR_TRUNCATION = 100;
|
||||
@@ -39,7 +39,7 @@ import { tokenLimit } from './tokenLimits.js';
|
||||
import { ideContextStore } from '../ide/ideContext.js';
|
||||
import type { ModelRouterService } from '../routing/modelRouterService.js';
|
||||
import { uiTelemetryService } from '../telemetry/uiTelemetry.js';
|
||||
import { ChatCompressionService } from '../services/chatCompressionService.js';
|
||||
import { ChatCompressionService } from '../context/chatCompressionService.js';
|
||||
import type { ChatRecordingService } from '../services/chatRecordingService.js';
|
||||
import { createAvailabilityServiceMock } from '../availability/testUtils.js';
|
||||
import type { ModelAvailabilityService } from '../availability/modelAvailabilityService.js';
|
||||
|
||||
@@ -43,8 +43,8 @@ import type {
|
||||
} from '../services/chatRecordingService.js';
|
||||
import type { ContentGenerator } from './contentGenerator.js';
|
||||
import { LoopDetectionService } from '../services/loopDetectionService.js';
|
||||
import { ChatCompressionService } from '../services/chatCompressionService.js';
|
||||
import { AgentHistoryProvider } from '../services/agentHistoryProvider.js';
|
||||
import { ChatCompressionService } from '../context/chatCompressionService.js';
|
||||
import { AgentHistoryProvider } from '../context/agentHistoryProvider.js';
|
||||
import { ideContextStore } from '../ide/ideContext.js';
|
||||
import {
|
||||
logContentRetryFailure,
|
||||
@@ -65,7 +65,7 @@ import { handleFallback } from '../fallback/handler.js';
|
||||
import type { RoutingContext } from '../routing/routingStrategy.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import type { ModelConfigKey } from '../services/modelConfigService.js';
|
||||
import { ToolOutputMaskingService } from '../services/toolOutputMaskingService.js';
|
||||
import { ToolOutputMaskingService } from '../context/toolOutputMaskingService.js';
|
||||
import { calculateRequestTokenCount } from '../utils/tokenCalculation.js';
|
||||
import {
|
||||
applyModelSelection,
|
||||
|
||||
@@ -134,7 +134,7 @@ export * from './services/fileSystemService.js';
|
||||
export * from './services/sandboxedFileSystemService.js';
|
||||
export * from './sandbox/windows/WindowsSandboxManager.js';
|
||||
export * from './services/sessionSummaryUtils.js';
|
||||
export * from './services/contextManager.js';
|
||||
export * from './context/contextManager.js';
|
||||
export * from './services/trackerService.js';
|
||||
export * from './services/trackerTypes.js';
|
||||
export * from './services/keychainService.js';
|
||||
|
||||