ziprin-context-optimizer 8.0.0
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/README.md +48 -0
- package/bin/ziprin-context-mcp.js +34 -0
- package/bin/ziprin-context-setup.js +10 -0
- package/install-source.json +5 -0
- package/media/context-activity.svg +7 -0
- package/package.json +154 -0
- package/releases/ziprin-context-optimizer-8.0.0.vsix +0 -0
- package/scripts/install.mjs +204 -0
- package/scripts/package-vsix.mjs +38 -0
- package/scripts/paths.mjs +40 -0
- package/scripts/publish.mjs +37 -0
- package/scripts/update.mjs +101 -0
- package/src/adaptive-budget.js +46 -0
- package/src/analyzer.js +456 -0
- package/src/audit-history.js +137 -0
- package/src/bm25.js +132 -0
- package/src/collector.js +343 -0
- package/src/compression.js +67 -0
- package/src/config.js +28 -0
- package/src/context-memory.js +151 -0
- package/src/context-profiles.js +124 -0
- package/src/dependency-graph.js +90 -0
- package/src/estimate.js +109 -0
- package/src/eval-harness.js +76 -0
- package/src/extension.js +322 -0
- package/src/firewall.js +35 -0
- package/src/fts-index.js +319 -0
- package/src/gateway-api.js +404 -0
- package/src/git-recency.js +43 -0
- package/src/glob.js +42 -0
- package/src/identifier.js +37 -0
- package/src/inspector-panel.js +470 -0
- package/src/language.js +157 -0
- package/src/mcp-event-stream.js +179 -0
- package/src/mcp-health-cli.js +34 -0
- package/src/mcp-lifecycle-manager.js +427 -0
- package/src/mcp-server.js +372 -0
- package/src/mmr.js +57 -0
- package/src/pagerank.js +176 -0
- package/src/profiles.js +74 -0
- package/src/pruner.js +130 -0
- package/src/quality-guard.js +122 -0
- package/src/query-rewrite.js +32 -0
- package/src/relevance-scorer.js +197 -0
- package/src/repo-map.js +134 -0
- package/src/retrieve.js +350 -0
- package/src/serena.js +126 -0
- package/src/session-ledger.js +83 -0
- package/src/session-store.js +78 -0
- package/src/skeleton.js +129 -0
- package/src/slice-pack.js +70 -0
- package/src/supervisor.js +113 -0
- package/src/task-analyzer.js +189 -0
- package/src/tool-router.js +92 -0
- package/src/version.js +5 -0
- package/templates/ziprin-context-mcp.mjs +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Ziprin Context Optimizer 8.0.0
|
|
2
|
+
|
|
3
|
+
Standalone MCP + Context Inspector — **not part of ziprin-monorepo**.
|
|
4
|
+
|
|
5
|
+
| Registry | URL |
|
|
6
|
+
|----------|-----|
|
|
7
|
+
| GitLab | https://185.226.118.181/ah.lotfali/ziprin-context-optimizer |
|
|
8
|
+
| npm | `ziprin-context-optimizer@8.0.0` (after `npm publish`) |
|
|
9
|
+
|
|
10
|
+
## Install (local dev → ~/.ziprin)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cd ~/Desktop/ziprin-context-optimizer
|
|
14
|
+
npm run install:local
|
|
15
|
+
# or with monorepo path:
|
|
16
|
+
node scripts/install.mjs --workspace ~/Desktop/ziprin-monorepo
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Update from GitLab (sync monorepo ref)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm run update:local
|
|
23
|
+
# or:
|
|
24
|
+
node scripts/update.mjs --workspace ~/Desktop/ziprin-monorepo
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Publish GitLab + npm
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git push -u origin main --tags
|
|
31
|
+
npm login
|
|
32
|
+
npm run publish:all
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
GitLab CI (`.gitlab-ci.yml`) runs tests on push and `npm publish` on tags.
|
|
36
|
+
|
|
37
|
+
## Monorepo integration
|
|
38
|
+
|
|
39
|
+
Monorepo keeps only:
|
|
40
|
+
- `.cursor/ziprin-context-mcp.mjs` — thin launcher (~60 lines)
|
|
41
|
+
- `.cursor/ziprin-context-ref.json` — version pointer
|
|
42
|
+
- `.cursor/mcp.json` — points to launcher
|
|
43
|
+
|
|
44
|
+
Runtime: `~/.ziprin/ziprin-context-optimizer`
|
|
45
|
+
|
|
46
|
+
## MCP tools (8)
|
|
47
|
+
|
|
48
|
+
`ziprin_optimize_context` · `ziprin_analyze_task` · `ziprin_rank_context` · `ziprin_find_symbol` · `ziprin_unfold_symbol` · `ziprin_validate_context` · `ziprin_context_memory` · `ziprin_health`
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/** npm bin entry — stdio MCP for Cursor / CLI */
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawn } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const entry = path.join(__dirname, '..', 'src', 'mcp-server.js');
|
|
9
|
+
const workspace = process.env.ZIPRIN_WORKSPACE
|
|
10
|
+
? path.resolve(process.env.ZIPRIN_WORKSPACE)
|
|
11
|
+
: process.cwd();
|
|
12
|
+
|
|
13
|
+
const child = spawn(process.execPath, [entry, '--project', workspace], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
env: { ...process.env, ZIPRIN_WORKSPACE: workspace },
|
|
16
|
+
windowsHide: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
child.on('exit', (code, signal) => {
|
|
20
|
+
if (signal) {
|
|
21
|
+
try {
|
|
22
|
+
process.kill(process.pid, signal);
|
|
23
|
+
} catch {
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
process.exit(code ?? 1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
child.on('error', (err) => {
|
|
32
|
+
console.error('[ziprin-context-mcp]', err.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/** One-command install: MCP runtime + VSIX + workspace mcp.json */
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const script = path.join(__dirname, '..', 'scripts', 'install.mjs');
|
|
9
|
+
const r = spawnSync(process.execPath, [script, ...process.argv.slice(2)], { stdio: 'inherit' });
|
|
10
|
+
process.exit(r.status ?? 1);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<rect x="3" y="4" width="8" height="6" rx="1.5"/>
|
|
3
|
+
<rect x="13" y="4" width="8" height="6" rx="1.5"/>
|
|
4
|
+
<rect x="3" y="14" width="8" height="6" rx="1.5"/>
|
|
5
|
+
<path d="M13 17h8"/>
|
|
6
|
+
<path d="M17 14v6"/>
|
|
7
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ziprin-context-optimizer",
|
|
3
|
+
"displayName": "Ziprin Context Inspector",
|
|
4
|
+
"description": "Live observability dashboard for Ziprin Context MCP — history, health, token analytics. Intelligence runs only via MCP in native Cursor Chat.",
|
|
5
|
+
"version": "8.0.0",
|
|
6
|
+
"publisher": "ziprin",
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://185.226.118.181/ah.lotfali/ziprin-context-optimizer.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://185.226.118.181/ah.lotfali/ziprin-context-optimizer/-/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://185.226.118.181/ah.lotfali/ziprin-context-optimizer",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ziprin",
|
|
18
|
+
"mcp",
|
|
19
|
+
"cursor",
|
|
20
|
+
"context",
|
|
21
|
+
"model-context-protocol"
|
|
22
|
+
],
|
|
23
|
+
"files": [
|
|
24
|
+
"bin/",
|
|
25
|
+
"src/",
|
|
26
|
+
"media/",
|
|
27
|
+
"scripts/",
|
|
28
|
+
"templates/",
|
|
29
|
+
"releases/",
|
|
30
|
+
"install-source.json",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"ziprin-context-mcp": "./bin/ziprin-context-mcp.js",
|
|
38
|
+
"ziprin-context-setup": "./bin/ziprin-context-setup.js"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"vscode": "^1.85.0"
|
|
42
|
+
},
|
|
43
|
+
"categories": [
|
|
44
|
+
"Other",
|
|
45
|
+
"Machine Learning"
|
|
46
|
+
],
|
|
47
|
+
"activationEvents": [
|
|
48
|
+
"onStartupFinished",
|
|
49
|
+
"onView:ziprinContext.inspector"
|
|
50
|
+
],
|
|
51
|
+
"main": "./src/extension.js",
|
|
52
|
+
"contributes": {
|
|
53
|
+
"viewsContainers": {
|
|
54
|
+
"activitybar": [
|
|
55
|
+
{
|
|
56
|
+
"id": "ziprinContext",
|
|
57
|
+
"title": "Context Inspector",
|
|
58
|
+
"icon": "media/context-activity.svg"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
"views": {
|
|
63
|
+
"ziprinContext": [
|
|
64
|
+
{
|
|
65
|
+
"type": "webview",
|
|
66
|
+
"id": "ziprinContext.inspector",
|
|
67
|
+
"name": "Context Dashboard"
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"commands": [
|
|
72
|
+
{
|
|
73
|
+
"command": "ziprinContext.openInspector",
|
|
74
|
+
"title": "Ziprin Context: Open Inspector Dashboard"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"command": "ziprinContext.refreshDashboard",
|
|
78
|
+
"title": "Ziprin Context: Reload Observer State"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"command": "ziprinContext.diagnoseMcp",
|
|
82
|
+
"title": "Ziprin Context: Diagnose MCP Health"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"command": "ziprinContext.installTokenBudget",
|
|
86
|
+
"title": "Ziprin Context: Install Token Budget (stub + strip mdc)"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"configuration": {
|
|
90
|
+
"title": "Ziprin Context Inspector",
|
|
91
|
+
"properties": {
|
|
92
|
+
"ziprinContext.profile": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"enum": [
|
|
95
|
+
"frontend",
|
|
96
|
+
"backend",
|
|
97
|
+
"architecture",
|
|
98
|
+
"standard",
|
|
99
|
+
"minimal",
|
|
100
|
+
"strict"
|
|
101
|
+
],
|
|
102
|
+
"default": "standard",
|
|
103
|
+
"description": "Default context profile label in the dashboard (MCP may pass profileId explicitly)"
|
|
104
|
+
},
|
|
105
|
+
"ziprinContext.charsPerToken": {
|
|
106
|
+
"type": "number",
|
|
107
|
+
"default": 4,
|
|
108
|
+
"description": "Heuristic bytes per token"
|
|
109
|
+
},
|
|
110
|
+
"ziprinContext.stripOtherMdc": {
|
|
111
|
+
"type": "boolean",
|
|
112
|
+
"default": true,
|
|
113
|
+
"description": "When installing token budget, delete non-stub .mdc rules"
|
|
114
|
+
},
|
|
115
|
+
"ziprinContext.liveRefresh": {
|
|
116
|
+
"type": "boolean",
|
|
117
|
+
"default": true,
|
|
118
|
+
"description": "Auto-update dashboard when MCP event/session files change"
|
|
119
|
+
},
|
|
120
|
+
"ziprinContext.refreshDebounceMs": {
|
|
121
|
+
"type": "number",
|
|
122
|
+
"default": 500,
|
|
123
|
+
"minimum": 120,
|
|
124
|
+
"description": "Debounce for live dashboard updates"
|
|
125
|
+
},
|
|
126
|
+
"ziprinContext.autoRevealPanel": {
|
|
127
|
+
"type": "boolean",
|
|
128
|
+
"default": true,
|
|
129
|
+
"description": "Reveal the Context Inspector Activity Bar panel on activate"
|
|
130
|
+
},
|
|
131
|
+
"ziprinContext.maxSessions": {
|
|
132
|
+
"type": "number",
|
|
133
|
+
"default": 80,
|
|
134
|
+
"minimum": 10,
|
|
135
|
+
"description": "Maximum recorded MCP sessions per workspace"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"scripts": {
|
|
141
|
+
"test": "node --test tests/*.test.js",
|
|
142
|
+
"test:mcp": "node --test tests/mcp-gateway.test.js tests/v6-mandatory.test.js tests/mcp-lifecycle.test.js tests/mcp-event-stream.test.js",
|
|
143
|
+
"mcp": "node src/mcp-server.js",
|
|
144
|
+
"mcp:health": "node src/mcp-health-cli.js",
|
|
145
|
+
"package": "node scripts/package-vsix.mjs",
|
|
146
|
+
"install:local": "node scripts/install.mjs",
|
|
147
|
+
"setup": "node bin/ziprin-context-setup.js",
|
|
148
|
+
"update:local": "node scripts/update.mjs",
|
|
149
|
+
"publish:all": "node scripts/publish.mjs"
|
|
150
|
+
},
|
|
151
|
+
"dependencies": {
|
|
152
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Install to ~/.ziprin + VSIX + patch monorepo mcp.json
|
|
4
|
+
*
|
|
5
|
+
* node scripts/install.mjs
|
|
6
|
+
* node scripts/install.mjs --workspace C:/path/to/ziprin-monorepo
|
|
7
|
+
* node scripts/install.mjs --from bundle.zip
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import os from "node:os";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import {
|
|
16
|
+
defaultInstallRoot,
|
|
17
|
+
isPluginRoot,
|
|
18
|
+
writeManifest,
|
|
19
|
+
ziprinHome,
|
|
20
|
+
} from "./paths.mjs";
|
|
21
|
+
|
|
22
|
+
const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
23
|
+
const SOURCE_CFG = path.join(PKG_ROOT, "install-source.json");
|
|
24
|
+
const INSTALL_ROOT = defaultInstallRoot();
|
|
25
|
+
const LOG = "[ziprin-context-install]";
|
|
26
|
+
|
|
27
|
+
function log(...a) {
|
|
28
|
+
console.error(LOG, ...a);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function fail(msg, code = 1) {
|
|
32
|
+
console.error(LOG, "FATAL:", msg);
|
|
33
|
+
process.exit(code);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseArgs(argv) {
|
|
37
|
+
const out = { from: null, npm: null, git: null, workspace: null, skipVsix: false, force: false };
|
|
38
|
+
for (let i = 2; i < argv.length; i++) {
|
|
39
|
+
const a = argv[i];
|
|
40
|
+
if (a === "--from" && argv[i + 1]) out.from = path.resolve(argv[++i]);
|
|
41
|
+
else if (a === "--npm" && argv[i + 1]) out.npm = argv[++i];
|
|
42
|
+
else if (a === "--git" && argv[i + 1]) out.git = argv[++i];
|
|
43
|
+
else if (a === "--workspace" && argv[i + 1]) out.workspace = path.resolve(argv[++i]);
|
|
44
|
+
else if (a === "--skip-vsix") out.skipVsix = true;
|
|
45
|
+
else if (a === "--force") out.force = true;
|
|
46
|
+
}
|
|
47
|
+
if (!out.workspace) {
|
|
48
|
+
const guess = path.join(os.homedir(), "Desktop", "ziprin-monorepo");
|
|
49
|
+
if (fs.existsSync(path.join(guess, ".cursor"))) out.workspace = guess;
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function loadDefaults() {
|
|
55
|
+
if (!fs.existsSync(SOURCE_CFG)) return { version: "8.0.0", git: null, npm: null };
|
|
56
|
+
return JSON.parse(fs.readFileSync(SOURCE_CFG, "utf8"));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function run(cmd, args, opts = {}) {
|
|
60
|
+
const r = spawnSync(cmd, args, {
|
|
61
|
+
stdio: "inherit",
|
|
62
|
+
cwd: opts.cwd,
|
|
63
|
+
shell: opts.shell ?? false,
|
|
64
|
+
env: process.env,
|
|
65
|
+
});
|
|
66
|
+
if (r.status !== 0) throw new Error(`${cmd} failed`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function npmInstall(cwd) {
|
|
70
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
71
|
+
run(npm, ["install", "--omit=dev"], { cwd, shell: process.platform === "win32" });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function installFromGit(spec) {
|
|
75
|
+
const hash = spec.lastIndexOf("#");
|
|
76
|
+
const url = hash === -1 ? spec : spec.slice(0, hash);
|
|
77
|
+
const ref = hash === -1 ? null : spec.slice(hash + 1);
|
|
78
|
+
if (fs.existsSync(INSTALL_ROOT)) fs.rmSync(INSTALL_ROOT, { recursive: true, force: true });
|
|
79
|
+
const args = ["clone", "--depth", "1"];
|
|
80
|
+
if (ref) args.push("--branch", ref);
|
|
81
|
+
args.push(url, INSTALL_ROOT);
|
|
82
|
+
run("git", args);
|
|
83
|
+
if (!isPluginRoot(INSTALL_ROOT)) fail("git clone missing src/mcp-server.js");
|
|
84
|
+
npmInstall(INSTALL_ROOT);
|
|
85
|
+
return INSTALL_ROOT;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function installFromNpm(spec) {
|
|
89
|
+
if (fs.existsSync(INSTALL_ROOT)) fs.rmSync(INSTALL_ROOT, { recursive: true, force: true });
|
|
90
|
+
fs.mkdirSync(INSTALL_ROOT, { recursive: true });
|
|
91
|
+
fs.writeFileSync(
|
|
92
|
+
path.join(INSTALL_ROOT, "package.json"),
|
|
93
|
+
JSON.stringify({ name: "ziprin-context-host", private: true }, null, 2),
|
|
94
|
+
);
|
|
95
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
96
|
+
run(npm, ["install", spec, "--omit=dev"], { cwd: INSTALL_ROOT, shell: process.platform === "win32" });
|
|
97
|
+
const nested = path.join(INSTALL_ROOT, "node_modules", "@ziprin", "context-optimizer");
|
|
98
|
+
if (!isPluginRoot(nested)) fail("npm install missing plugin");
|
|
99
|
+
return nested;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function installLocalDev() {
|
|
103
|
+
log("dev install from Desktop repo →", INSTALL_ROOT);
|
|
104
|
+
if (fs.existsSync(INSTALL_ROOT)) fs.rmSync(INSTALL_ROOT, { recursive: true, force: true });
|
|
105
|
+
fs.cpSync(PKG_ROOT, INSTALL_ROOT, { recursive: true, filter: (src) => !src.includes("node_modules") });
|
|
106
|
+
npmInstall(INSTALL_ROOT);
|
|
107
|
+
return INSTALL_ROOT;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function patchMonorepo(workspace, version, ref) {
|
|
111
|
+
if (!workspace) return;
|
|
112
|
+
const mcpJson = path.join(workspace, ".cursor", "mcp.json");
|
|
113
|
+
const refJson = path.join(workspace, ".cursor", "ziprin-context-ref.json");
|
|
114
|
+
const launcher = path.join(workspace, ".cursor", "ziprin-context-mcp.mjs");
|
|
115
|
+
const template = path.join(PKG_ROOT, "templates", "ziprin-context-mcp.mjs");
|
|
116
|
+
if (fs.existsSync(template)) {
|
|
117
|
+
fs.mkdirSync(path.dirname(launcher), { recursive: true });
|
|
118
|
+
fs.copyFileSync(template, launcher);
|
|
119
|
+
log("installed launcher", launcher);
|
|
120
|
+
}
|
|
121
|
+
if (fs.existsSync(mcpJson)) {
|
|
122
|
+
const cfg = JSON.parse(fs.readFileSync(mcpJson, "utf8"));
|
|
123
|
+
cfg.mcpServers = cfg.mcpServers || {};
|
|
124
|
+
cfg.mcpServers["ziprin-context"] = {
|
|
125
|
+
command: "node",
|
|
126
|
+
args: ["${workspaceFolder}/.cursor/ziprin-context-mcp.mjs"],
|
|
127
|
+
env: { ZIPRIN_WORKSPACE: "${workspaceFolder}" },
|
|
128
|
+
};
|
|
129
|
+
fs.writeFileSync(mcpJson, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
130
|
+
log("patched", mcpJson);
|
|
131
|
+
}
|
|
132
|
+
if (fs.existsSync(refJson)) {
|
|
133
|
+
const refCfg = JSON.parse(fs.readFileSync(refJson, "utf8"));
|
|
134
|
+
refCfg.ref = ref || refCfg.ref;
|
|
135
|
+
refCfg.npm = `@ziprin/context-optimizer@${version}`;
|
|
136
|
+
fs.writeFileSync(refJson, `${JSON.stringify(refCfg, null, 2)}\n`);
|
|
137
|
+
log("patched", refJson);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function installVsix() {
|
|
142
|
+
const version = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, "package.json"), "utf8")).version;
|
|
143
|
+
const vsix = path.join(PKG_ROOT, "releases", `ziprin-context-optimizer-${version}.vsix`);
|
|
144
|
+
if (!fs.existsSync(vsix)) {
|
|
145
|
+
log("WARN: no VSIX in releases/ — run npm run package");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
for (const cli of ["cursor", "code"]) {
|
|
149
|
+
const r = spawnSync(process.platform === "win32" ? "where" : "which", [cli], {
|
|
150
|
+
encoding: "utf8",
|
|
151
|
+
shell: true,
|
|
152
|
+
});
|
|
153
|
+
if (r.status === 0 && r.stdout.trim()) {
|
|
154
|
+
run(cli, ["--install-extension", vsix, "--force"], { shell: true });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
log("WARN: install VSIX manually:", vsix);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function main() {
|
|
162
|
+
const args = parseArgs(process.argv);
|
|
163
|
+
const defs = loadDefaults();
|
|
164
|
+
fs.mkdirSync(ziprinHome(), { recursive: true });
|
|
165
|
+
|
|
166
|
+
let pluginRoot;
|
|
167
|
+
if (args.from) {
|
|
168
|
+
fail("--from not implemented in Desktop install yet; use local dev copy");
|
|
169
|
+
} else if (args.git) {
|
|
170
|
+
try {
|
|
171
|
+
pluginRoot = installFromGit(args.git);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
log("git install failed, falling back to Desktop repo copy:", err.message);
|
|
174
|
+
pluginRoot = installLocalDev();
|
|
175
|
+
}
|
|
176
|
+
} else if (args.npm) {
|
|
177
|
+
pluginRoot = installFromNpm(args.npm);
|
|
178
|
+
} else if (isPluginRoot(INSTALL_ROOT) && !args.force) {
|
|
179
|
+
pluginRoot = INSTALL_ROOT;
|
|
180
|
+
npmInstall(pluginRoot);
|
|
181
|
+
} else {
|
|
182
|
+
pluginRoot = installLocalDev();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const version = JSON.parse(fs.readFileSync(path.join(pluginRoot, "package.json"), "utf8")).version;
|
|
186
|
+
const ref = args.git?.split("#")[1] || defs.git?.split("#")[1] || `v${version}`;
|
|
187
|
+
|
|
188
|
+
writeManifest({
|
|
189
|
+
version,
|
|
190
|
+
pluginRoot,
|
|
191
|
+
installedAt: new Date().toISOString(),
|
|
192
|
+
source: args.npm ? "npm" : args.git ? "git" : "local",
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
patchMonorepo(args.workspace, version, ref);
|
|
196
|
+
if (!args.skipVsix) installVsix();
|
|
197
|
+
|
|
198
|
+
console.log(`\n✓ Ziprin Context v${version}`);
|
|
199
|
+
console.log(` Plugin: ${pluginRoot}`);
|
|
200
|
+
console.log(` Monorepo: ${args.workspace || "(not found)"}`);
|
|
201
|
+
console.log(" Next: Developer → Reload Window in Cursor\n");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
main();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* VSCE rejects scoped npm names (@scope/pkg). Build VSIX with extension-safe name.
|
|
4
|
+
*/
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
const pkgFile = path.join(PKG_ROOT, 'package.json');
|
|
12
|
+
const backup = path.join(PKG_ROOT, 'package.json.vsce-backup');
|
|
13
|
+
const releases = path.join(PKG_ROOT, 'releases');
|
|
14
|
+
|
|
15
|
+
const original = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
|
|
16
|
+
const version = original.version;
|
|
17
|
+
const vsixName = `ziprin-context-optimizer-${version}.vsix`;
|
|
18
|
+
|
|
19
|
+
fs.mkdirSync(releases, { recursive: true });
|
|
20
|
+
fs.writeFileSync(backup, JSON.stringify(original, null, 2));
|
|
21
|
+
|
|
22
|
+
const vscePkg = { ...original, name: 'ziprin-context-optimizer' };
|
|
23
|
+
delete vscePkg.files;
|
|
24
|
+
delete vscePkg.publishConfig;
|
|
25
|
+
fs.writeFileSync(pkgFile, `${JSON.stringify(vscePkg, null, 2)}\n`);
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const r = spawnSync(
|
|
29
|
+
process.platform === 'win32' ? 'npx.cmd' : 'npx',
|
|
30
|
+
['--yes', '@vscode/vsce', 'package', '--no-dependencies', '--out', path.join('releases', vsixName)],
|
|
31
|
+
{ cwd: PKG_ROOT, stdio: 'inherit', shell: process.platform === 'win32' },
|
|
32
|
+
);
|
|
33
|
+
if (r.status !== 0) process.exit(r.status ?? 1);
|
|
34
|
+
console.error(`\n✓ VSIX: releases/${vsixName}\n`);
|
|
35
|
+
} finally {
|
|
36
|
+
fs.writeFileSync(pkgFile, `${JSON.stringify(original, null, 2)}\n`);
|
|
37
|
+
fs.rmSync(backup, { force: true });
|
|
38
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
export const MANIFEST_REL = ".ziprin/ziprin-context-install.json";
|
|
8
|
+
|
|
9
|
+
export function ziprinHome() {
|
|
10
|
+
return path.join(os.homedir(), ".ziprin");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function defaultInstallRoot() {
|
|
14
|
+
return path.join(ziprinHome(), "ziprin-context-optimizer");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function manifestPath() {
|
|
18
|
+
return path.join(os.homedir(), MANIFEST_REL);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isPluginRoot(dir) {
|
|
22
|
+
if (!dir) return false;
|
|
23
|
+
return fs.existsSync(path.join(dir, "src", "mcp-server.js"));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function readManifest() {
|
|
27
|
+
const file = manifestPath();
|
|
28
|
+
if (!fs.existsSync(file)) return null;
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function writeManifest(data) {
|
|
37
|
+
const file = manifestPath();
|
|
38
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
39
|
+
fs.writeFileSync(file, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
40
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Publish ziprin-context-optimizer to GitLab + npm (run from package root).
|
|
4
|
+
*
|
|
5
|
+
* node scripts/publish.mjs
|
|
6
|
+
*
|
|
7
|
+
* Prerequisites:
|
|
8
|
+
* - GitLab project: https://185.226.118.181/ah.lotfali/ziprin-context-optimizer (create empty)
|
|
9
|
+
* - npm login (npm login) with access to publish ziprin-context-optimizer
|
|
10
|
+
* - VPN/network to 185.226.118.181 if self-hosted GitLab is internal
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
19
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
|
|
20
|
+
const tag = `v${pkg.version}`;
|
|
21
|
+
|
|
22
|
+
function run(cmd, args, opts = {}) {
|
|
23
|
+
console.error(`> ${cmd} ${args.join(' ')}`);
|
|
24
|
+
const r = spawnSync(cmd, args, { stdio: 'inherit', cwd: ROOT, shell: opts.shell ?? false });
|
|
25
|
+
if (r.status !== 0) process.exit(r.status ?? 1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.error(`[publish] ${pkg.name}@${pkg.version}`);
|
|
29
|
+
|
|
30
|
+
run('git', ['push', '-u', 'origin', 'main', '--tags']);
|
|
31
|
+
run('npm', ['publish', '--access', 'public'], { shell: process.platform === 'win32' });
|
|
32
|
+
|
|
33
|
+
console.log('');
|
|
34
|
+
console.log(`✓ Published ${pkg.name}@${pkg.version}`);
|
|
35
|
+
console.log(` GitLab: ${pkg.repository?.url || 'see package.json'}`);
|
|
36
|
+
console.log(` npm: https://www.npmjs.com/package/${pkg.name}`);
|
|
37
|
+
console.log(` Tag: ${tag}`);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pull latest from GitLab/npm, refresh ~/.ziprin, sync monorepo ref.
|
|
4
|
+
*
|
|
5
|
+
* node scripts/update.mjs
|
|
6
|
+
* node scripts/update.mjs --workspace C:/path/to/ziprin-monorepo
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import os from "node:os";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { defaultInstallRoot, isPluginRoot, readManifest, writeManifest } from "./paths.mjs";
|
|
15
|
+
|
|
16
|
+
const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
17
|
+
const SOURCE_CFG = path.join(PKG_ROOT, "install-source.json");
|
|
18
|
+
const INSTALL_ROOT = defaultInstallRoot();
|
|
19
|
+
const LOG = "[ziprin-context-update]";
|
|
20
|
+
|
|
21
|
+
function log(...a) {
|
|
22
|
+
console.error(LOG, ...a);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseArgs(argv) {
|
|
26
|
+
const out = { workspace: null };
|
|
27
|
+
for (let i = 2; i < argv.length; i++) {
|
|
28
|
+
if (argv[i] === "--workspace" && argv[i + 1]) out.workspace = path.resolve(argv[++i]);
|
|
29
|
+
}
|
|
30
|
+
if (!out.workspace) {
|
|
31
|
+
const guess = path.join(os.homedir(), "Desktop", "ziprin-monorepo");
|
|
32
|
+
if (fs.existsSync(path.join(guess, ".cursor"))) out.workspace = guess;
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function run(cmd, args, opts = {}) {
|
|
38
|
+
const r = spawnSync(cmd, args, { stdio: "inherit", cwd: opts.cwd, shell: opts.shell ?? false });
|
|
39
|
+
if (r.status !== 0) process.exit(r.status ?? 1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function loadDefaults() {
|
|
43
|
+
return JSON.parse(fs.readFileSync(SOURCE_CFG, "utf8"));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function syncMonorepoRef(workspace, version, ref) {
|
|
47
|
+
if (!workspace) return;
|
|
48
|
+
const refJson = path.join(workspace, ".cursor", "ziprin-context-ref.json");
|
|
49
|
+
if (!fs.existsSync(refJson)) return;
|
|
50
|
+
const cfg = JSON.parse(fs.readFileSync(refJson, "utf8"));
|
|
51
|
+
cfg.ref = ref;
|
|
52
|
+
cfg.npm = `ziprin-context-optimizer@${version}`;
|
|
53
|
+
fs.writeFileSync(refJson, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
54
|
+
log("synced", refJson, "→", ref);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function main() {
|
|
58
|
+
const args = parseArgs(process.argv);
|
|
59
|
+
const defs = loadDefaults();
|
|
60
|
+
const manifest = readManifest();
|
|
61
|
+
|
|
62
|
+
if (fs.existsSync(path.join(INSTALL_ROOT, ".git"))) {
|
|
63
|
+
log("git pull in", INSTALL_ROOT);
|
|
64
|
+
run("git", ["pull", "--ff-only"], { cwd: INSTALL_ROOT });
|
|
65
|
+
} else if (defs.git) {
|
|
66
|
+
log("re-install from git", defs.git);
|
|
67
|
+
run(process.execPath, [path.join(PKG_ROOT, "scripts", "install.mjs"), "--git", defs.git, "--force"], {
|
|
68
|
+
shell: true,
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
} else if (defs.npm) {
|
|
72
|
+
log("re-install from npm", defs.npm);
|
|
73
|
+
run(process.execPath, [path.join(PKG_ROOT, "scripts", "install.mjs"), "--npm", defs.npm, "--force"], {
|
|
74
|
+
shell: true,
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isPluginRoot(INSTALL_ROOT)) {
|
|
80
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
81
|
+
run(npm, ["install", "--omit=dev"], { cwd: INSTALL_ROOT, shell: process.platform === "win32" });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const version = JSON.parse(fs.readFileSync(path.join(INSTALL_ROOT, "package.json"), "utf8")).version;
|
|
85
|
+
const ref = defs.git?.split("#")[1] || `v${version}`;
|
|
86
|
+
|
|
87
|
+
writeManifest({
|
|
88
|
+
...(manifest || {}),
|
|
89
|
+
version,
|
|
90
|
+
pluginRoot: INSTALL_ROOT,
|
|
91
|
+
updatedAt: new Date().toISOString(),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
syncMonorepoRef(args.workspace, version, ref);
|
|
95
|
+
|
|
96
|
+
run(process.execPath, [path.join(PKG_ROOT, "scripts", "install.mjs"), "--skip-vsix"], { shell: true });
|
|
97
|
+
|
|
98
|
+
console.log(`\n✓ Updated to v${version}. Reload Cursor window.\n`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main();
|