dsh-ops 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,13 +5,33 @@ All notable changes to this package are recorded here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
6
6
  this package adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.2.1] — Windows payload packaging
8
+ ## [0.2.3] — Strict-argument guidance and display metadata
9
+
10
+ - Add one routing-section reminder: `ops_* arguments are strict: pass only declared fields.` Keep FastCtx's portable schema subset and runtime guards unchanged.
11
+ - Use `dsh-ops` as the display title in both locales and align package/install descriptions with the maintainer's Windows bash, PowerShell 7, and Rust tools wording.
12
+ - Replace the display icon with the maintainer-provided image, resized without cropping to a 256×256 PNG (119,677 bytes), below the official host's 256 KiB limit.
13
+ - Reuse all three runtime payload dependencies at 0.2.1; preserve the 0.2.2 bash object-root schema fix.
14
+
15
+ ## [0.2.2] — Bash parameter schema hotfix
16
+
17
+ - Fix `ops_bash` parameters to use a JSON Schema object root with `properties`, `required: ['command']`, and `additionalProperties: false`. The previous field map was forwarded unchanged by the official host and rejected by the model API before tool execution.
18
+ - Reuse the three published Windows runtime packages at exact version 0.2.1; only the main plugin package changes.
19
+ - Validate the exported schema through the official host tool registry without calling a model. Registry installation and shell version probes alone did not verify this boundary in 0.2.1.
20
+
21
+ ## [0.2.1] — Windows payload packaging — published
22
+
23
+ Published to the public npm registry on 2026-10-08 as `dsh-ops@0.2.1` with
24
+ `@dsh-ops/fastctx-win32-x64@0.2.1`, `@dsh-ops/bash-win32-x64@0.2.1` and
25
+ `@dsh-ops/pwsh-win32-x64@0.2.1`. Packed sizes and registry digests:
26
+ [docs/release-0.2.1.md](docs/release-0.2.1.md).
9
27
 
10
28
  - Assemble complete digest-verified PortableGit/bash and PowerShell 7 runtime packages instead of metadata-only pins; inject all three Windows x64 runtime dependencies in the publish artifact.
11
29
  - Add explicit-profile install/status/uninstall delegation to the official DSH manager; map tui to dsh-tui and use Desktop's installation-owned CLI.
12
30
  - Resolve the pwsh dependency from the plugin package under pnpm isolation.
13
31
  - Make the default README Chinese and add a concise English translation.
14
- - Correct the npm credential selection: the initial E403 used an old local token, not the maintainer-provided bypass token. The explicitly selected bypass token was accepted for publication. Local payload builds are not license-compliance evidence.
32
+ - Materialize PortableGit's hardlinked paths during assembly: npm rejects hard links with E415, so the shell packages publish regular files with identical bytes.
33
+ - Fix credential selection: the first publish attempt used an unrelated local npm token and received E403. The maintainer's explicitly selected bypass credential was accepted; the earlier attribution of that failure to the maintainer's token was wrong.
34
+ - Known unresolved item: complete corresponding-source delivery for the GPL/LGPL components in the PortableGit inventory was not collected or reviewed, and no source offer is claimed. Publication proceeded at the maintainer's explicit direction.
15
35
 
16
36
  ## [Unreleased] — additive tool surface
17
37
 
package/PROVENANCE.md CHANGED
@@ -3,6 +3,28 @@
3
3
  What this repository is, where its parts came from, what was verified, and what
4
4
  was not.
5
5
 
6
+ ## 0.2.3 Prompt and display update
7
+
8
+ Add one model-facing sentence in `lib/policy.js`: `ops_* arguments are strict:
9
+ pass only declared fields.` FastCtx strips `additionalProperties` from published
10
+ schemas for provider portability but retains its runtime unknown-field guards;
11
+ this prompt reminder does not change schemas or Rust behaviour. No files under
12
+ `vendor/fastctx` were modified. The display title and bilingual descriptions use
13
+ the maintainer's wording. The new icon is an operator-supplied image resized,
14
+ without cropping, to a 256×256 PNG under the official host's 256 KiB limit;
15
+ no independent authorship or licence verification of that image is claimed.
16
+
17
+ ## 0.2.2 Bash schema hotfix
18
+
19
+ The maintainer reported a model API rejection after official marketplace installation:
20
+ `ops_bash` had no object-root JSON Schema. The plugin supplied a field map directly to
21
+ `tools.register`, whereas only the host's `defineTool` helper compiles such maps; raw
22
+ registration and model projection preserve `parameters` unchanged. The plugin now
23
+ supplies explicit `type: 'object'`, `properties`, and root `required`. Inspection through
24
+ the installed official 0.2.0-rc.2 registry confirms the exported schema is object-rooted
25
+ and valid. No model API request or full marketplace round trip is claimed. The three
26
+ existing 0.2.1 runtime payloads are reused unchanged; only the main package is patched.
27
+
6
28
  ## 0.2.1 Windows payload packaging
7
29
 
8
30
  The assembler now builds all three Windows x64 payload packages. Bash carries
@@ -11,15 +33,22 @@ PowerShell 7.6.6 under bin/. Original licenses/notices are preserved. Archive
11
33
  and executable hashes are pinned in lib/shells.js. All three runtime packages
12
34
  are injected into the main publish artifact; no install lifecycle downloads.
13
35
 
14
- The maintainer authorized publication after the source-delivery risk was reported.
15
- The first attempt used an old local npm credential and received E403; explicitly
16
- selecting the maintainer-provided bypass token succeeded. This was a credential
17
- selection error, not proof the provided token lacked bypass permission. PortableGit's
18
- etc/package-versions.txt includes many GPL/LGPL components; complete matching
19
- source closure/delivery has not been collected or reviewed. Retaining upstream
20
- licenses does not attest that those obligations have been fulfilled. No source
21
- offer is invented. Historical 0.2.0 pin-package descriptions below do not describe
22
- this new payload layout.
36
+ The maintainer directed publication after the source-delivery risk was reported. The
37
+ first attempt used an unrelated local npm credential and received E403; selecting the
38
+ maintainer's bypass credential succeeded, so that failure was credential selection,
39
+ not the maintainer's token. Publishing hit a second real blocker: npm rejects tar
40
+ hard links (E415), so the assembler materializes PortableGit's 84 linked paths and the
41
+ published bash package is 161.2 MB packed rather than the 136.1 MB first measured.
42
+ All four packages are published at 0.2.1; the registry-reported digests of exactly
43
+ what users receive are recorded in docs/release-0.2.1.md, because the local dist
44
+ provenance is regenerated with a new timestamp on every build and does not describe
45
+ the earlier-published FastCtx tarball byte for byte.
46
+
47
+ PortableGit's etc/package-versions.txt includes many GPL/LGPL components; complete
48
+ matching source closure/delivery has not been collected or reviewed. Retaining
49
+ upstream licenses does not attest that those obligations have been fulfilled. No
50
+ source offer is invented. Historical 0.2.0 pin-package descriptions below do not
51
+ describe this new payload layout.
23
52
 
24
53
  The profile installer delegates to the official DSH CLI, retaining its locks,
25
54
  compatibility checks and rollback rather than cloning them. Live installation
package/README.en.md CHANGED
@@ -41,6 +41,11 @@ dsh plugin --profile dsh-tui add dsh-ops
41
41
  Update by repeating the npx install command, or official `add dsh-ops@latest`.
42
42
  Reload/restart as the application requests; replacing loaded code may require restart.
43
43
 
44
+ The current version is `0.2.3`: it reminds the model to pass only declared `ops_*`
45
+ fields and updates the display title, descriptions, and icon. It retains the 0.2.2
46
+ bash parameter schema fix. Runtime dependencies remain pinned to `0.2.1`; their
47
+ original release record is in [docs/release-0.2.1.md](docs/release-0.2.1.md).
48
+
44
49
  ```console
45
50
  npx --yes dsh-ops@latest status --profile desktop
46
51
  npx --yes dsh-ops@latest uninstall --profile desktop
package/README.md CHANGED
@@ -40,6 +40,8 @@ dsh plugin --profile dsh-tui add dsh-ops
40
40
 
41
41
  **更新**:重新运行相同的 `npx --yes dsh-ops@latest install --profile ...`,或用官方 CLI `add dsh-ops@latest`。按应用提示重载;替换已加载代码时重启应用。
42
42
 
43
+ 当前 npm 版本为 `0.2.3`:提示词提醒 `ops_*` 只传声明字段,标题统一为 `dsh-ops`,并更新中英文介绍和图标;保留 `0.2.2` 的 bash schema 修复,三个运行包仍使用 `0.2.1`。原始载荷发布记录见 [docs/release-0.2.1.md](docs/release-0.2.1.md)。
44
+
43
45
  **卸载与查看状态**:
44
46
 
45
47
  ```console
package/README.zh.md CHANGED
@@ -40,6 +40,8 @@ dsh plugin --profile dsh-tui add dsh-ops
40
40
 
41
41
  **更新**:重新运行相同的 `npx --yes dsh-ops@latest install --profile ...`,或用官方 CLI `add dsh-ops@latest`。按应用提示重载;替换已加载代码时重启应用。
42
42
 
43
+ 当前 npm 版本为 `0.2.3`:提示词提醒 `ops_*` 只传声明字段,标题统一为 `dsh-ops`,并更新中英文介绍和图标;保留 `0.2.2` 的 bash schema 修复,三个运行包仍使用 `0.2.1`。原始载荷发布记录见 [docs/release-0.2.1.md](docs/release-0.2.1.md)。
44
+
43
45
  **卸载与查看状态**:
44
46
 
45
47
  ```console
@@ -0,0 +1,72 @@
1
+ # Published release record — 0.2.1
2
+
3
+ Exactly what this release published to the public npm registry. `npm` reports these
4
+ digests; they are the authoritative record of the bytes users receive. They are not
5
+ derived from the local `dist` directory, whose `provenance.json` is regenerated on
6
+ every build and therefore carries a different build timestamp.
7
+
8
+ | Package | Packed | Unpacked | shasum (sha1) |
9
+ | --- | ---: | ---: | --- |
10
+ | `dsh-ops@0.2.1` | 501.9 kB | 2.4 MB | `fe4fc569565e5544b1b779b90192f610de1783d3` |
11
+ | `@dsh-ops/fastctx-win32-x64@0.2.1` | 24.7 MB | 49.9 MB | `96caf16a5978f699560d05b2126a2c6f92efb08c` |
12
+ | `@dsh-ops/bash-win32-x64@0.2.1` | 161.2 MB | 411.1 MB | `8df967f0f9ac0104e327ae1e50d55036f4790121` |
13
+ | `@dsh-ops/pwsh-win32-x64@0.2.1` | 107.6 MB | 256.6 MB | `4a3cd69f68ffc616dd6d334f170bf7423e660f24` |
14
+
15
+ All four are published with public access and tag `latest`. The main package declares
16
+ the three Windows x64 runtime packages as exact `optionalDependencies`; the platform
17
+ packages were published first, so the main package never pointed at a version the
18
+ registry did not have.
19
+
20
+ ## Two publishing problems this release hit
21
+
22
+ 1. **Wrong credential selected.** The first attempt used a pre-existing credential in
23
+ the operator's `~/.npmrc`, which is a different token, and npm answered `E403`
24
+ (2FA or a granular bypass token required). The maintainer's explicitly selected
25
+ bypass credential was accepted. The earlier local message blaming the maintainer's
26
+ token was wrong; the error was credential selection.
27
+ 2. **Hard links are rejected by the registry.** PortableGit's tree contains 84
28
+ hardlinked paths, and npm refused the first bash upload with
29
+ `E415 Unsupported Media Type — Hard link is not allowed`. The assembler now
30
+ materializes every linked path as an independent file with identical bytes, which
31
+ is why the published bash package is 161.2 MB (411.1 MB unpacked) rather than the
32
+ 136.1 MB measured before. Runtime layout and file contents are unchanged; the
33
+ executable digests still match `lib/shells.js`.
34
+
35
+ ## Distribution
36
+
37
+ - Tag `v0.2.1` and a GitHub Release with **notes only, no assets**. `v0.2.0`
38
+ attached four tarballs and `SHA256SUMS`; npm is now the installation channel, so
39
+ re-uploading ~290 MB of tarballs would only duplicate it.
40
+ - Repository Actions are **disabled at repository level**. Nothing runs on push,
41
+ tag, schedule or dispatch; the tag push above triggered no workflow. `.github/workflows/`
42
+ is kept as documentation of the intended gate and pipeline, and each file now says
43
+ at the top that it does not run. Publication is performed from a maintainer machine.
44
+
45
+ ## What was verified, and what was not
46
+
47
+ Verified by installing the published artifacts from the registry into an isolated
48
+ directory with `--ignore-scripts`:
49
+
50
+ - `resolveShells` finds both bundled shells inside the installed dependency tree;
51
+ - the installed bash reports `GNU bash, version 5.3.15(2)-release`;
52
+ - the installed pwsh reports `7.6.6`;
53
+ - `npx --yes dsh-ops@0.2.1 status --profile tui` runs and maps `tui` to `dsh-tui`;
54
+ - `install --profile tui|desktop --dry-run` selects the expected official CLI,
55
+ including Desktop's own `resources/runtime/cli/bin/dsh.cmd`.
56
+
57
+ Not verified: a live install into a real profile, the marketplace's pnpm path and hot
58
+ reload, official uninstall behaviour, and end-to-end plugin mount inside a running
59
+ DSH session. The repository regression suites were not updated or run for this
60
+ release, and no CI gate guarded this publication.
61
+
62
+ ## Licence status
63
+
64
+ The Windows payload packages redistribute complete upstream runtime trees: Git for
65
+ Windows (GPL and other licences) and PowerShell (MIT and third-party licences). Their
66
+ original licences and notices travel inside the packages, and `provenance.json`
67
+ records the upstream URL, release, byte count and SHA-256 of the archive each payload
68
+ came from. The complete corresponding-source closure for every GPL/LGPL component in
69
+ the PortableGit inventory has **not** been collected or reviewed; no written offer was
70
+ invented, and the plugin's MIT licence does not relicense the upstream components.
71
+ This is a documented, unresolved compliance item, published at the maintainer's
72
+ explicit direction.
@@ -58,20 +58,20 @@
58
58
  "approximateTokens": 1681
59
59
  },
60
60
  "fileOnlyPrompt": {
61
- "bytes": 470,
62
- "approximateTokens": 118
61
+ "bytes": 527,
62
+ "approximateTokens": 132
63
63
  },
64
64
  "bashSchema": {
65
- "bytes": 894,
66
- "approximateTokens": 224
65
+ "bytes": 961,
66
+ "approximateTokens": 241
67
67
  },
68
68
  "fullWithBash": {
69
- "bytes": 10633,
70
- "approximateTokens": 2659
69
+ "bytes": 10700,
70
+ "approximateTokens": 2675
71
71
  },
72
72
  "toolingPrompt": {
73
- "bytes": 1053,
74
- "approximateTokens": 264
73
+ "bytes": 1110,
74
+ "approximateTokens": 278
75
75
  },
76
76
  "publishedServerInstructions": {
77
77
  "bytes": 0,
@@ -8,9 +8,9 @@ Baseline: plugin `dee3c57`, FastCtx 0.2.6, before presentation changes. Current:
8
8
  | --- | ---: | ---: | ---: |
9
9
  | Nine FastCtx schemas (full-access session) | 18,889 | 9,739 | 48.4% |
10
10
  | Four file schemas | 12,807 | 6,724 | 47.5% |
11
- | Routing section (original full ladder vs restored compact three-layer table) | 3,373 | 1,053 | 68.8% |
11
+ | Routing section (original full ladder vs compact three-layer table with strict-argument reminder) | 3,373 | 1,110 | 67.1% |
12
12
 
13
- Full-access FastCtx schema estimate: 4,723 → 2,435 tokens. The restored ops_bash schema adds 894 bytes (~224 tokens); full FastCtx+bash surface is 10,633 bytes (~2,659 tokens). Restricted file-only surface: about 1,681 tokens; its routing table is 470 bytes (~118 tokens). No server instructions are published (the original raw server instructions were 246 bytes); the old host-shell section is also removed. Baseline excludes ops_bash, so compare nine FastCtx tools like-for-like rather than treating restoration as a regression of those numbers. Total request savings depend on host presentation; these are not API usage/billing measurements.
13
+ Full-access FastCtx schema estimate: 4,723 → 2,435 tokens. The corrected object-root ops_bash schema adds 961 bytes (~241 tokens); full FastCtx+bash surface is 10,700 bytes (~2,675 tokens). Restricted file-only surface: about 1,681 tokens; its routing table is 527 bytes (~132 tokens). No server instructions are published (the original raw server instructions were 246 bytes); the old host-shell section is also removed. Baseline excludes ops_bash, so compare nine FastCtx tools like-for-like rather than treating restoration as a regression of those numbers. Total request savings depend on host presentation; these are not API usage/billing measurements.
14
14
 
15
15
  `ops_grep` went from 3,766 → 2,019 bytes; `ops_inspect_local_file` from 4,375 → 1,968. `ops_replace` is retained: schema cost cannot establish invocation frequency, and no usage-frequency measurement was collected.
16
16
 
package/dsh-plugin.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifestVersion": "0.15",
4
4
  "id": "dsh-ops.fastctx",
5
5
  "name": "dsh-ops",
6
- "version": "0.2.1",
6
+ "version": "0.2.3",
7
7
  "license": "MIT AND Apache-2.0",
8
8
  "facets": {
9
9
  "host": {
@@ -39,9 +39,9 @@
39
39
  "contributes": {
40
40
  "x-display": [
41
41
  {
42
- "icon": "./icon.svg",
43
- "title": "Repository tools",
44
- "description": "Read, search, replace, and run commands through the hosted FastCtx ops_* tool surface instead of shell commands.",
42
+ "icon": "./icon.png",
43
+ "title": "dsh-ops",
44
+ "description": "Provides bash, PowerShell 7, and a suite of high-performance tools written in Rust for Windows DSH to enhance token efficiency",
45
45
  "locales": [
46
46
  "locale/en.json",
47
47
  "locale/zh.json"
package/icon.png ADDED
Binary file
package/lib/policy.js CHANGED
@@ -43,7 +43,8 @@ export function renderToolingPolicy({ published, enableShellTools, mounted, leve
43
43
  if (names.has(publicToolName('run_background'))) {
44
44
  lines.push(`| Background commands / owned jobs | ${SHELL_TOOLS.slice(1).map(publicToolName).join(', ')} |`)
45
45
  }
46
- lines.push('', '- Do not build shell command lines for file operations.',
46
+ lines.push('', '- ops_* arguments are strict: pass only declared fields.',
47
+ '- Do not build shell command lines for file operations.',
47
48
  '- On a tool error, correct the arguments and retry; do not switch to a shell workaround.')
48
49
  if (names.has(BASH_TOOL)) lines.push('- Prefer bash for command execution. Use PowerShell only when Windows-native functionality is necessary; fix bash errors in bash, do not switch shells or mix their syntax.')
49
50
  if (names.has(publicToolName('run_background'))) lines.push('- Only operate on job IDs you started in this session.')
package/lib/shells.js CHANGED
@@ -807,21 +807,26 @@ export function bashToolDefinition({ file, source, subprocess }) {
807
807
  name: BASH_TOOL_NAME,
808
808
  description: bashToolDescription(),
809
809
  parameters: {
810
- command: { type: 'string', required: true, description: 'The bash command to execute.' },
811
- workdir: {
812
- type: 'string',
813
- description: 'Working directory for this command. Defaults to the session workspace when omitted.',
814
- },
815
- timeoutMs: {
816
- type: 'number',
817
- description: 'Timeout in milliseconds; the command is killed on expiry. '
818
- + `Defaults to ${DEFAULT_BASH_TIMEOUT_MS}.`,
819
- },
820
- graceMs: {
821
- type: 'number',
822
- description: 'Grace period in milliseconds between termination and a forced kill. '
823
- + `Defaults to ${DEFAULT_GRACE_MS}.`,
810
+ type: 'object',
811
+ properties: {
812
+ command: { type: 'string', description: 'The bash command to execute.' },
813
+ workdir: {
814
+ type: 'string',
815
+ description: 'Working directory for this command. Defaults to the session workspace when omitted.',
816
+ },
817
+ timeoutMs: {
818
+ type: 'number',
819
+ description: 'Timeout in milliseconds; the command is killed on expiry. '
820
+ + `Defaults to ${DEFAULT_BASH_TIMEOUT_MS}.`,
821
+ },
822
+ graceMs: {
823
+ type: 'number',
824
+ description: 'Grace period in milliseconds between termination and a forced kill. '
825
+ + `Defaults to ${DEFAULT_GRACE_MS}.`,
826
+ },
824
827
  },
828
+ required: ['command'],
829
+ additionalProperties: false,
825
830
  },
826
831
  output: {
827
832
  schema: BASH_OUTPUT_SCHEMA,
package/locale/en.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "title": "Repository tools",
4
- "description": "Read, search, replace, and run commands through the hosted FastCtx ops_* tool surface instead of shell commands."
3
+ "title": "dsh-ops",
4
+ "description": "Provides bash, PowerShell 7, and a suite of high-performance tools written in Rust for Windows DSH to enhance token efficiency"
5
5
  }
6
6
  }
package/locale/zh.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
- "title": "仓库工具",
4
- "description": "通过托管的 FastCtx ops_* 工具完成读取、搜索、替换与命令执行,替代 shell 命令。"
3
+ "title": "dsh-ops",
4
+ "description": "为windows的dsh提供bash、powershell7及一系列rust编写的高性能tools来提高token效率"
5
5
  }
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ops",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -18,8 +18,8 @@
18
18
  "cpu": [
19
19
  "x64"
20
20
  ],
21
- "description": "DSH plugin: hosts the vendored FastCtx MCP runtime as the profile's repository tool surface, and steers the model away from PowerShell.",
22
- "icon": "./icon.svg",
21
+ "description": "Provides bash, PowerShell 7, and a suite of high-performance tools written in Rust for Windows DSH to enhance token efficiency",
22
+ "icon": "./icon.png",
23
23
  "keywords": [
24
24
  "dsh",
25
25
  "dsh-plugin",
@@ -54,7 +54,7 @@
54
54
  "bin",
55
55
  "cordis.patch.yml",
56
56
  "dsh-plugin.json",
57
- "icon.svg",
57
+ "icon.png",
58
58
  "locale",
59
59
  "docs",
60
60
  "LICENSE",
@@ -96,6 +96,11 @@
96
96
  "optional": true
97
97
  }
98
98
  },
99
+ "optionalDependencies": {
100
+ "@dsh-ops/fastctx-win32-x64": "0.2.1",
101
+ "@dsh-ops/bash-win32-x64": "0.2.1",
102
+ "@dsh-ops/pwsh-win32-x64": "0.2.1"
103
+ },
99
104
  "devDependencies": {
100
105
  "@deepseek-ai/cordis": "4.0.4",
101
106
  "@deepseek-ai/dsh-scope": "0.2.0-rc.2",
@@ -107,10 +112,5 @@
107
112
  },
108
113
  "engines": {
109
114
  "node": "^22.19 || >=24"
110
- },
111
- "optionalDependencies": {
112
- "@dsh-ops/fastctx-win32-x64": "0.2.1",
113
- "@dsh-ops/bash-win32-x64": "0.2.1",
114
- "@dsh-ops/pwsh-win32-x64": "0.2.1"
115
115
  }
116
116
  }
package/icon.svg DELETED
@@ -1,12 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36" fill="none">
2
- <g stroke="#7C7C82" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
3
- <rect x="4.2" y="6.2" width="27.6" height="23.6" rx="4.2" />
4
- <path d="M10 14.4l4 3.8-4 3.8" />
5
- <path d="M17.4 22h4.4" />
6
- <path d="M25.6 13v10" />
7
- </g>
8
- <g fill="#7C7C82">
9
- <circle cx="25.6" cy="13" r="2.3" />
10
- <circle cx="25.6" cy="23" r="2.3" />
11
- </g>
12
- </svg>