dsh-plugin-logicmargin 0.0.0-stage → 0.9.18

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LogicMargin contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,37 @@
1
- # Temporary Holding Version
1
+ # LogicMargin for DeepSeek Harness
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Connect source-backed logic diagrams, saved code diffs, and human review feedback to **DSH 0.2.2-rc.1**. This thin host plugin uses DSH's official MCP Client and filesystem skill provider. It starts or reuses LogicMargin's native Go service; users do not install Go or a second Node runtime.
4
+
5
+ The distributable is generated from the repository with `npm run package:dsh`. It includes the fixed-version native download launchers and a DSH-specific skill generated from the shared review workflow. Installing this source directory directly is not supported.
6
+
7
+ ## Install a built package
8
+
9
+ For the profile you actually use:
10
+
11
+ ```sh
12
+ dsh plugin --profile YOUR_PROFILE add /absolute/path/dsh-plugin-logicmargin-0.9.18.tgz
13
+ ```
14
+
15
+ Reload the plugin/profile, verify the `logic-margin` skill, and verify `mcp__logic_margin__start_review` and `mcp__logic_margin__wait_review`. Use the skill in the original workspace. Installation alone is not proof that tools are loaded.
16
+
17
+ The first activation downloads the matching official LogicMargin 0.9.18 release and verifies SHA-256. macOS/Linux need `curl`, `unzip`, and `shasum` or `sha256sum`; Windows uses PowerShell. Git and compilers are not required. Native availability matches the five LogicMargin targets: macOS ARM64/x64, Linux ARM64/x64, Windows x64.
18
+
19
+ The default reuses the same user's compatible local LogicMargin service. Optional plugin config fields are `home` (an absolute path) and `port` (0–65535). A separate home isolates the daemon registry; its data defaults to `<home>/sessions`, unless the host explicitly supplies `LOGIC_MARGIN_DATA_DIR`. Existing daemons retain their registered data directory. A conflicting or incompatible daemon fails explicitly; this plugin does not stop or replace it.
20
+
21
+ MCP waits have a 24-hour per-call budget, not a promise of durable or infinite execution. Cancellation and disconnection never acknowledge or archive feedback. Resume the original session using its saved submission cursor. Unloading this plugin withdraws its tools and skill while retaining the shared daemon and data.
22
+
23
+ ## Updates and distribution
24
+
25
+ Update the DSH package through DSH. The webpage's one-click updater currently updates **Codex**, even if both hosts are present on the machine; it does not upgrade this DSH bundle. Preserve service home, data, port, and session IDs when updating the native service.
26
+
27
+ This package targets local execution: MCP and the source workspace must be on the same machine. No remote provider, Desktop UI, model inference, or market listing is implied by a local Host test. See the repository's DeepSeek Harness guide for tested and untested paths.
28
+
29
+ Publishing to npm, adding a GitHub topic, submitting to a community catalog, and showing up in a chosen Discover index are separate actions. No DeepSeek model-account login is required to load this plugin or connect its local MCP.
30
+
31
+ This package uses the MIT license included in `LICENSE`. Native ZIPs retain their third-party notices. The release workflow prepares the tgz, its SHA-256 file, and the five native ZIPs together; npm publication and market submissions remain separate actions.
32
+
33
+ ## 中文
34
+
35
+ 适配 DSH `0.2.2-rc.1`:加载后启动或复用 Go 后台,接入官方 MCP Client,并注册 `logic-margin` 技能。安装生成的 tgz 后,在实际使用的 profile 重载并核对技能与工具;不要运行 Codex 专用 `server setup`。
36
+
37
+ 等待预算为单次 24 小时;取消不领取、不归档。卸载仅撤销本插件的连接和技能,不停止共享服务。更新 DSH 包使用宿主安装器,网页一键更新当前只更新 Codex。会话数据独立保存,保持原 home、端口和 session ID。
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: logic-margin
3
+ name: ./index.js
package/icon.svg ADDED
@@ -0,0 +1,17 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96" fill="none" role="img" aria-labelledby="title description">
2
+ <title id="title">LogicMargin</title>
3
+ <desc id="description">流程节点连接到右侧的批注气泡,代表在具体逻辑旁留下评审意见。</desc>
4
+ <style>
5
+ :root { --mark: #2563eb; }
6
+ @media (prefers-color-scheme: dark) { :root { --mark: #99baff; } }
7
+ .mark { stroke: var(--mark); stroke-width: 6; stroke-linecap: round; stroke-linejoin: round; }
8
+ </style>
9
+ <g class="mark">
10
+ <path d="M20 31v34m7 7h38M27 24h11" />
11
+ <circle cx="20" cy="24" r="7" />
12
+ <circle cx="20" cy="72" r="7" />
13
+ <circle cx="72" cy="72" r="7" />
14
+ <path d="M46 12h32a8 8 0 0 1 8 8v18a8 8 0 0 1-8 8H61L48 57V46h-2a8 8 0 0 1-8-8V20a8 8 0 0 1 8-8Z" />
15
+ <path d="M52 25h20M52 35h12" />
16
+ </g>
17
+ </svg>
package/index.js ADDED
@@ -0,0 +1,29 @@
1
+ import { fileURLToPath } from 'node:url'
2
+ import z from '@deepseek-ai/schemastery'
3
+ import * as McpClient from '@deepseek-ai/dsh-mcp-client'
4
+ import * as SkillFilesystem from '@deepseek-ai/dsh-skill-filesystem'
5
+ import { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'
6
+ import { startNativeServer } from './native.js'
7
+
8
+ export const name = 'logic-margin'
9
+ export const inject = ['tools', 'skills']
10
+ export const Config = z.object({
11
+ home: z.string().description('Optional absolute LogicMargin service home; omit to reuse the normal shared service.'),
12
+ port: z.number().step(1).min(0).max(65535).description('Optional local service port; 0 selects an available port for an isolated service.'),
13
+ })
14
+
15
+ export async function apply(ctx, config = {}) {
16
+ const startup = new AbortController()
17
+ ctx.effect(() => () => startup.abort(new Error('LogicMargin plugin unloaded')))
18
+ const resources = fileURLToPath(new URL('./resources/logic-margin/', import.meta.url))
19
+ const { mcpUrl } = await startNativeServer(resources, config, startup.signal, scrubbedParentEnv())
20
+ await ctx.plugin(McpClient, {
21
+ serverName: 'logic_margin', transport: 'streamable-http', url: mcpUrl,
22
+ toolCallTimeoutMs: 86_400_000, failOnStartupError: true,
23
+ })
24
+ await ctx.plugin(SkillFilesystem, {
25
+ providerName: 'logic-margin-bundled', includeDefaultRoots: false,
26
+ bundledSkillDir: fileURLToPath(new URL('./resources/logic-margin/skills/', import.meta.url)), watch: false,
27
+ })
28
+ // The daemon is shared with other hosts; unloading this plugin only withdraws its MCP and skill.
29
+ }
package/locale/en.json ADDED
@@ -0,0 +1 @@
1
+ {"meta":{"title":"LogicMargin","description":"Review source-backed logic diagrams and saved code diffs; keep human feedback across revisions."}}
package/locale/zh.json ADDED
@@ -0,0 +1 @@
1
+ {"meta":{"title":"LogicMargin · 逻辑旁批","description":"在有源码依据的流程图和代码差异中审查逻辑,保留批注、回复与修订历史。"}}
package/native.js ADDED
@@ -0,0 +1,91 @@
1
+ import { execFile, spawn } from 'node:child_process'
2
+ import { isAbsolute, join } from 'node:path'
3
+ import { promisify } from 'node:util'
4
+
5
+ const run = promisify(execFile)
6
+
7
+ async function settleStartup(child, closed) {
8
+ const signal = kind => {
9
+ try {
10
+ if (process.platform !== 'win32' && child.pid) process.kill(-child.pid, kind)
11
+ else child.kill(kind)
12
+ } catch (error) { if (error.code !== 'ESRCH') throw error }
13
+ }
14
+ const wait = async () => {
15
+ let timer
16
+ try { return await Promise.race([closed.then(() => true), new Promise(resolve => { timer = setTimeout(() => resolve(false), 1000) })]) }
17
+ finally { clearTimeout(timer) }
18
+ }
19
+ signal('SIGTERM')
20
+ const exited = await wait()
21
+ if (process.platform === 'win32' && child.pid) {
22
+ if (!exited) await run('taskkill.exe', ['/PID', String(child.pid), '/T', '/F'], { timeout: 1000, windowsHide: true }).catch(() => {})
23
+ } else signal('SIGKILL')
24
+ if (!await wait()) {
25
+ child.stdout?.destroy()
26
+ child.stderr?.destroy()
27
+ child.unref()
28
+ }
29
+ }
30
+
31
+ export function launcherCommand(resources, platform = process.platform) {
32
+ const scripts = join(resources, 'skills/logic-margin/scripts')
33
+ if (platform === 'win32') return ['powershell.exe', ['-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', join(scripts, 'logic-margin.ps1')]]
34
+ if (platform === 'darwin' || platform === 'linux') return ['/bin/sh', [join(scripts, 'logic-margin.sh')]]
35
+ throw new Error(`Unsupported LogicMargin platform: ${platform}`)
36
+ }
37
+
38
+ export function validateServer(value) {
39
+ if (!value || value.managed !== true || typeof value.url !== 'string' || typeof value.mcpUrl !== 'string') throw new Error('LogicMargin startup did not confirm a managed local service')
40
+ let url, base
41
+ try { url = new URL(value.mcpUrl); base = new URL(value.url) } catch { throw new Error('LogicMargin returned an invalid MCP URL') }
42
+ if (url.protocol !== 'http:' || !['127.0.0.1', '[::1]', 'localhost'].includes(url.hostname)
43
+ || url.username || url.password || url.pathname !== '/mcp' || url.search || url.hash
44
+ || base.origin !== url.origin || base.username || base.password || base.pathname !== '/' || base.search || base.hash) throw new Error('LogicMargin MCP must use a local HTTP endpoint')
45
+ return { url: url.origin, mcpUrl: url.href }
46
+ }
47
+
48
+ export async function startNativeServer(resources, config, signal, parentEnv) {
49
+ signal.throwIfAborted()
50
+ if (config.home !== undefined && (typeof config.home !== 'string' || !isAbsolute(config.home))) throw new Error('LogicMargin home must be an absolute path')
51
+ if (config.port !== undefined && (!Number.isInteger(config.port) || config.port < 0 || config.port > 65535)) throw new Error('LogicMargin port must be an integer from 0 to 65535')
52
+ const [command, args] = launcherCommand(resources)
53
+ const env = { ...parentEnv }
54
+ if (config.home !== undefined) env.LOGIC_MARGIN_HOME = config.home
55
+ let stdout
56
+ // execFile does not forward detached; spawn gives the launcher its own POSIX process group.
57
+ const child = spawn(command, [...args, 'server', 'start', ...(config.port === undefined ? [] : ['--port', String(config.port)])], {
58
+ cwd: resources, env, windowsHide: true, detached: process.platform !== 'win32', stdio: ['ignore', 'pipe', 'pipe'],
59
+ })
60
+ let didClose = false
61
+ const closed = new Promise(resolve => child.once('close', () => { didClose = true; resolve() }))
62
+ let timer, abort
63
+ try {
64
+ stdout = await new Promise((resolve, reject) => {
65
+ const chunks = []
66
+ let size = 0
67
+ child.stdout.on('data', chunk => {
68
+ size += chunk.length
69
+ if (size > 1024 * 1024) reject(new Error('LogicMargin startup output exceeded its limit'))
70
+ else chunks.push(chunk)
71
+ })
72
+ child.stderr.resume()
73
+ child.once('error', reject)
74
+ child.once('close', code => code === 0 ? resolve(Buffer.concat(chunks).toString('utf8')) : reject(new Error('LogicMargin startup exited unsuccessfully')))
75
+ timer = setTimeout(() => reject(new Error('LogicMargin startup timed out')), 300_000)
76
+ abort = () => reject(signal.reason)
77
+ signal.addEventListener('abort', abort, { once: true })
78
+ if (signal.aborted) abort()
79
+ })
80
+ } catch {
81
+ if (!didClose) await settleStartup(child, closed)
82
+ if (signal.aborted) throw signal.reason
83
+ throw new Error('LogicMargin native startup failed; run the packaged launcher with "server status" to diagnose. No Codex configuration was changed.')
84
+ } finally {
85
+ clearTimeout(timer)
86
+ signal.removeEventListener('abort', abort)
87
+ }
88
+ let value
89
+ try { value = JSON.parse(stdout) } catch { throw new Error('LogicMargin startup returned invalid JSON') }
90
+ return validateServer(value)
91
+ }
package/package.json CHANGED
@@ -1,6 +1,21 @@
1
1
  {
2
2
  "name": "dsh-plugin-logicmargin",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.9.18",
4
+ "type": "module",
5
+ "description": "Source-backed logic reviews with diagrams, saved code diffs, and resumable human feedback.",
6
+ "license": "MIT",
7
+ "engines": { "node": ">=24.9.0", "dsh": "0.2.2-rc.1" },
8
+ "keywords": ["dsh-plugin", "deepseek-harness", "logicmargin", "code-review", "mcp"],
9
+ "repository": { "type": "git", "url": "https://github.com/SunneeYang/LogicMargin.git", "directory": "plugins/deepseek-harness" },
10
+ "homepage": "https://github.com/SunneeYang/LogicMargin",
11
+ "exports": { ".": "./index.js", "./package.json": "./package.json", "./locale/*.json": "./locale/*.json", "./icon": "./icon.svg" },
12
+ "files": ["index.js", "native.js", "cordis.patch.yml", "locale", "icon.svg", "resources", "README.md", "LICENSE"],
13
+ "peerDependencies": {
14
+ "@deepseek-ai/cordis": "~4.1.0",
15
+ "@deepseek-ai/schemastery": "~3.19.0",
16
+ "@deepseek-ai/dsh-mcp-client": "0.2.2-rc.1",
17
+ "@deepseek-ai/dsh-skill-filesystem": "0.2.2-rc.1",
18
+ "@deepseek-ai/dsh-subprocess": "0.2.2-rc.1"
19
+ },
20
+ "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
21
+ }