grix-connector 1.0.2
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 +149 -0
- package/dist/adapter/acp/acp-adapter.js +13 -0
- package/dist/adapter/acp/index.js +1 -0
- package/dist/adapter/acp/usage-parser.js +1 -0
- package/dist/adapter/claude/activity-status-manager.js +1 -0
- package/dist/adapter/claude/channel-notification.js +1 -0
- package/dist/adapter/claude/claude-adapter.js +15 -0
- package/dist/adapter/claude/claude-bridge-server.js +1 -0
- package/dist/adapter/claude/claude-tools.js +1 -0
- package/dist/adapter/claude/claude-worker-client.js +1 -0
- package/dist/adapter/claude/index.js +1 -0
- package/dist/adapter/claude/interaction-protocol.js +1 -0
- package/dist/adapter/claude/mcp-http-launcher.js +2 -0
- package/dist/adapter/claude/model-list.js +1 -0
- package/dist/adapter/claude/protocol-contract.js +1 -0
- package/dist/adapter/claude/result-timeout.js +1 -0
- package/dist/adapter/claude/skill-scanner.js +2 -0
- package/dist/adapter/claude/usage-parser.js +3 -0
- package/dist/adapter/codewhale/codewhale-adapter.js +6 -0
- package/dist/adapter/codewhale/index.js +1 -0
- package/dist/adapter/codex/codex-bridge.js +10 -0
- package/dist/adapter/codex/codex-trust.js +8 -0
- package/dist/adapter/codex/index.js +1 -0
- package/dist/adapter/codex/usage-parser.js +1 -0
- package/dist/adapter/cursor/cursor-adapter.js +8 -0
- package/dist/adapter/cursor/index.js +1 -0
- package/dist/adapter/deepseek/deepseek-adapter.js +6 -0
- package/dist/adapter/deepseek/index.js +1 -0
- package/dist/adapter/index.js +1 -0
- package/dist/adapter/opencode/index.js +1 -0
- package/dist/adapter/opencode/opencode-adapter.js +8 -0
- package/dist/adapter/opencode/opencode-transport.js +5 -0
- package/dist/adapter/opencode/opencode-types.js +0 -0
- package/dist/adapter/openhuman/index.js +1 -0
- package/dist/adapter/openhuman/openhuman-adapter.js +7 -0
- package/dist/adapter/openhuman/openhuman-transport.js +1 -0
- package/dist/adapter/openhuman/openhuman-types.js +0 -0
- package/dist/adapter/pi/index.js +1 -0
- package/dist/adapter/pi/pi-adapter.js +10 -0
- package/dist/adapter/pi/pi-transport.js +4 -0
- package/dist/adapter/pi/pi-types.js +0 -0
- package/dist/adapter/pi/usage-parser.js +1 -0
- package/dist/adapter/qwen/index.js +1 -0
- package/dist/adapter/qwen/qwen-adapter.js +4 -0
- package/dist/adapter/types.js +1 -0
- package/dist/agent/index.js +1 -0
- package/dist/agent/process.js +2 -0
- package/dist/aibot/client.js +1 -0
- package/dist/aibot/index.js +1 -0
- package/dist/aibot/types.js +0 -0
- package/dist/bridge/adapter-pool.js +1 -0
- package/dist/bridge/bridge.js +10 -0
- package/dist/bridge/deferred-events.js +1 -0
- package/dist/bridge/event-queue.js +1 -0
- package/dist/bridge/index.js +1 -0
- package/dist/bridge/respawn-manager.js +1 -0
- package/dist/bridge/revoke-handler.js +1 -0
- package/dist/bridge/runtime-config.js +1 -0
- package/dist/bridge/send-controller.js +1 -0
- package/dist/bridge/session-controller.js +9 -0
- package/dist/bridge/tool-card-utils.js +1 -0
- package/dist/core/access/allowlist-gate.js +1 -0
- package/dist/core/access/allowlist-store.js +1 -0
- package/dist/core/access/index.js +1 -0
- package/dist/core/aibot/client.js +1 -0
- package/dist/core/aibot/connection-handle.js +1 -0
- package/dist/core/aibot/connection-manager.js +1 -0
- package/dist/core/aibot/event-lifecycle-types.js +0 -0
- package/dist/core/aibot/index.js +1 -0
- package/dist/core/aibot/types.js +0 -0
- package/dist/core/config/index.js +1 -0
- package/dist/core/config/paths.js +1 -0
- package/dist/core/context/channel-context-resolution.js +1 -0
- package/dist/core/context/channel-context-store.js +1 -0
- package/dist/core/context/index.js +1 -0
- package/dist/core/context/transcript-channel-context.js +1 -0
- package/dist/core/file-ops/handler.js +1 -0
- package/dist/core/file-ops/list-files.js +1 -0
- package/dist/core/file-ops/types.js +0 -0
- package/dist/core/files/create-folder.js +1 -0
- package/dist/core/files/index.js +1 -0
- package/dist/core/files/list-files.js +1 -0
- package/dist/core/files/list-handler.js +1 -0
- package/dist/core/files/types.js +0 -0
- package/dist/core/files/utils.js +1 -0
- package/dist/core/hooks/hook-signal-store.js +2 -0
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/log/bridge-event-log.js +2 -0
- package/dist/core/log/conversation-log.js +3 -0
- package/dist/core/log/index.js +1 -0
- package/dist/core/log/logger.js +6 -0
- package/dist/core/log/packet-log.js +2 -0
- package/dist/core/log/rotation.js +2 -0
- package/dist/core/mcp/event-tool-executor.js +1 -0
- package/dist/core/mcp/index.js +1 -0
- package/dist/core/mcp/internal-api-server.js +1 -0
- package/dist/core/mcp/tool-schemas.js +1 -0
- package/dist/core/mcp/tools.js +1 -0
- package/dist/core/persistence/active-event-store.js +1 -0
- package/dist/core/persistence/agent-global-config-store.js +1 -0
- package/dist/core/persistence/elicitation-store.js +1 -0
- package/dist/core/persistence/event-results-store.js +1 -0
- package/dist/core/persistence/permission-store.js +1 -0
- package/dist/core/persistence/question-store.js +1 -0
- package/dist/core/persistence/session-binding-store.js +1 -0
- package/dist/core/protocol/agent-api-media.js +1 -0
- package/dist/core/protocol/attachment-file.js +1 -0
- package/dist/core/protocol/index.js +1 -0
- package/dist/core/protocol/interaction-parser.js +1 -0
- package/dist/core/protocol/message-metadata.js +2 -0
- package/dist/core/protocol/message-reference.js +2 -0
- package/dist/core/protocol/payload-parser.js +11 -0
- package/dist/core/protocol/protocol-descriptor.js +1 -0
- package/dist/core/protocol/protocol-text.js +1 -0
- package/dist/core/provider-quota/index.js +1 -0
- package/dist/core/provider-quota/kiro.js +1 -0
- package/dist/core/provider-quota/providers.js +1 -0
- package/dist/core/provider-quota/types.js +0 -0
- package/dist/core/runtime/health.js +1 -0
- package/dist/core/runtime/index.js +1 -0
- package/dist/core/runtime/pidfile.js +2 -0
- package/dist/core/runtime/spawn.js +1 -0
- package/dist/core/text-segmentation/index.js +1 -0
- package/dist/core/text-segmentation/safe-markdown-stream-segmenter.js +6 -0
- package/dist/core/transport/index.js +1 -0
- package/dist/core/transport/json-rpc.js +3 -0
- package/dist/core/upgrade/npm-upgrader.js +2 -0
- package/dist/core/upgrade/upgrade-checker.js +1 -0
- package/dist/core/util/client-version.js +1 -0
- package/dist/core/util/codex-output-policy.js +1 -0
- package/dist/core/util/event-buffer.js +1 -0
- package/dist/core/util/index.js +1 -0
- package/dist/core/util/json-file.js +2 -0
- package/dist/core/util/normalize-string.js +1 -0
- package/dist/core/util/quoted-message-stream.js +3 -0
- package/dist/grix.js +28 -0
- package/dist/index.js +1 -0
- package/dist/log.js +3 -0
- package/dist/main.js +31 -0
- package/dist/manager.js +1 -0
- package/dist/mcp/acp-mcp-server.js +5 -0
- package/dist/mcp/stdio/server.js +10 -0
- package/dist/mcp/stream-http/config.js +1 -0
- package/dist/mcp/stream-http/connection-binding.js +1 -0
- package/dist/mcp/stream-http/event-tool-executor.js +1 -0
- package/dist/mcp/stream-http/gateway.js +1 -0
- package/dist/mcp/stream-http/index.js +1 -0
- package/dist/mcp/stream-http/security.js +1 -0
- package/dist/mcp/stream-http/session-manager.js +1 -0
- package/dist/mcp/stream-http/tool-executor.js +1 -0
- package/dist/mcp/stream-http/tool-registry.js +1 -0
- package/dist/mcp/stream-http/tool-schemas.js +1 -0
- package/dist/protocol/acp-client.js +1 -0
- package/dist/protocol/event-mapper.js +5 -0
- package/dist/protocol/index.js +1 -0
- package/dist/runtime/daemon-lock.js +2 -0
- package/dist/runtime/service-state.js +2 -0
- package/dist/scripts/approve-plan-hook.js +2 -0
- package/dist/scripts/elicitation-hook.js +6 -0
- package/dist/scripts/lib/read-stdin.js +1 -0
- package/dist/scripts/lifecycle-hook.js +2 -0
- package/dist/scripts/notification-hook.js +4 -0
- package/dist/scripts/permission-hook.js +5 -0
- package/dist/scripts/status-line-forwarder.js +2 -0
- package/dist/scripts/user-prompt-submit-hook.js +2 -0
- package/dist/service/platform-adapter.js +45 -0
- package/dist/service/process-control.js +1 -0
- package/dist/service/service-install-store.js +1 -0
- package/dist/service/service-manager.js +1 -0
- package/dist/service/service-paths.js +1 -0
- package/dist/session/index.js +1 -0
- package/dist/session/manager.js +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/json-rpc.js +3 -0
- package/dist/types/events.js +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/protocol.js +0 -0
- package/dist/types/session-state.js +0 -0
- package/dist/types/usage.js +0 -0
- package/openclaw-plugin/index.js +11271 -0
- package/openclaw-plugin/skills/grix-admin/SKILL.md +202 -0
- package/openclaw-plugin/skills/grix-admin/references/api-contract.md +210 -0
- package/openclaw-plugin/skills/grix-egg/SKILL.md +81 -0
- package/openclaw-plugin/skills/grix-egg/references/api-contract.md +40 -0
- package/openclaw-plugin/skills/grix-group/SKILL.md +164 -0
- package/openclaw-plugin/skills/grix-group/references/api-contract.md +97 -0
- package/openclaw-plugin/skills/grix-query/SKILL.md +247 -0
- package/openclaw-plugin/skills/grix-register/SKILL.md +86 -0
- package/openclaw-plugin/skills/grix-register/references/api-contract.md +76 -0
- package/openclaw-plugin/skills/grix-register/references/grix-concepts.md +26 -0
- package/openclaw-plugin/skills/grix-register/references/handoff-contract.md +24 -0
- package/openclaw-plugin/skills/grix-register/references/openclaw-setup.md +6 -0
- package/openclaw-plugin/skills/grix-register/references/user-replies.md +25 -0
- package/openclaw-plugin/skills/grix-register/scripts/grix_auth.ts +599 -0
- package/openclaw-plugin/skills/grix-update/SKILL.md +310 -0
- package/openclaw-plugin/skills/grix-update/references/cron-setup.md +56 -0
- package/openclaw-plugin/skills/grix-update/references/update-contract.md +149 -0
- package/openclaw-plugin/skills/message-send/SKILL.md +197 -0
- package/openclaw-plugin/skills/message-unsend/SKILL.md +186 -0
- package/openclaw-plugin/skills/message-unsend/flowchart.mermaid +27 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/SKILL.md +282 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/references/case-study-macpro.md +52 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/references/host-readiness.md +147 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/scripts/bench_ollama_embeddings.ts +326 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/scripts/set_openclaw_memory_model.ts +385 -0
- package/openclaw-plugin/skills/openclaw-memory-setup/scripts/survey_host_readiness.ts +294 -0
- package/openclaw.plugin.json +24 -0
- package/package.json +114 -0
- package/scripts/install-guardian.mjs +30 -0
- package/scripts/install-guardian.sh +30 -0
- package/scripts/upgrade-guardian.sh +98 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Survey host readiness for Ollama and OpenClaw memory setup.
|
|
4
|
+
*
|
|
5
|
+
* Emits a readable report by default, or JSON with --json.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { accessSync, constants, readFileSync, statSync } from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
import { parseArgs } from "node:util";
|
|
12
|
+
|
|
13
|
+
type Report = {
|
|
14
|
+
os: string;
|
|
15
|
+
release: string;
|
|
16
|
+
arch: string;
|
|
17
|
+
shell_context: string;
|
|
18
|
+
cpu_count: number;
|
|
19
|
+
memory_gib: number | null;
|
|
20
|
+
commands: Record<string, string | null>;
|
|
21
|
+
versions: Record<string, string | null>;
|
|
22
|
+
ollama_api: { reachable: boolean; models: string[] };
|
|
23
|
+
recommended_candidates: string[];
|
|
24
|
+
openclaw_install_note: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function usageText(): string {
|
|
28
|
+
return [
|
|
29
|
+
"Usage:",
|
|
30
|
+
" node scripts/survey_host_readiness.ts [--ollama-host <url>] [--json]",
|
|
31
|
+
"",
|
|
32
|
+
"Options:",
|
|
33
|
+
" --ollama-host <url> Ollama host to probe (default http://127.0.0.1:11434)",
|
|
34
|
+
" --json Emit JSON instead of a readable report",
|
|
35
|
+
].join("\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function systemName(): string {
|
|
39
|
+
if (process.platform === "win32") return "Windows";
|
|
40
|
+
if (process.platform === "darwin") return "Darwin";
|
|
41
|
+
if (process.platform === "linux") return "Linux";
|
|
42
|
+
return process.platform;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function shellContext(): string {
|
|
46
|
+
if (process.platform === "win32") return "windows-native";
|
|
47
|
+
if (process.platform === "darwin") return "macos-native";
|
|
48
|
+
if (process.platform === "linux") {
|
|
49
|
+
const lowerRelease = os.release().toLowerCase();
|
|
50
|
+
if (lowerRelease.includes("microsoft") || lowerRelease.includes("wsl")) {
|
|
51
|
+
return "wsl";
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const version = readFileSync("/proc/version", "utf8").toLowerCase();
|
|
55
|
+
if (version.includes("microsoft")) {
|
|
56
|
+
return "wsl";
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
// ignore
|
|
60
|
+
}
|
|
61
|
+
return "linux-native";
|
|
62
|
+
}
|
|
63
|
+
return "unknown";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isExecutableFile(path: string): boolean {
|
|
67
|
+
try {
|
|
68
|
+
const stats = statSync(path);
|
|
69
|
+
if (!stats.isFile()) return false;
|
|
70
|
+
if (process.platform === "win32") return true;
|
|
71
|
+
accessSync(path, constants.X_OK);
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function commandCandidates(command: string): string[] {
|
|
79
|
+
const normalized = command.trim();
|
|
80
|
+
if (!normalized) return [];
|
|
81
|
+
|
|
82
|
+
const candidates: string[] = [];
|
|
83
|
+
const unixBins = ["/usr/local/bin", "/opt/homebrew/bin", "/usr/bin", "/bin"];
|
|
84
|
+
|
|
85
|
+
if (normalized === "node") {
|
|
86
|
+
candidates.push(process.execPath);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (normalized === "npm") {
|
|
90
|
+
const base = dirname(process.execPath);
|
|
91
|
+
if (process.platform === "win32") {
|
|
92
|
+
candidates.push(join(base, "npm.cmd"), join(base, "npm.exe"));
|
|
93
|
+
} else {
|
|
94
|
+
candidates.push(join(base, "npm"));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (process.platform === "win32") {
|
|
99
|
+
if (normalized === "ollama") {
|
|
100
|
+
candidates.push(
|
|
101
|
+
"C:\\\\Program Files\\\\Ollama\\\\ollama.exe",
|
|
102
|
+
"C:\\\\Program Files (x86)\\\\Ollama\\\\ollama.exe",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (normalized === "node") {
|
|
106
|
+
candidates.push("C:\\\\Program Files\\\\nodejs\\\\node.exe", "C:\\\\Program Files (x86)\\\\nodejs\\\\node.exe");
|
|
107
|
+
}
|
|
108
|
+
if (normalized === "npm") {
|
|
109
|
+
candidates.push("C:\\\\Program Files\\\\nodejs\\\\npm.cmd", "C:\\\\Program Files (x86)\\\\nodejs\\\\npm.cmd");
|
|
110
|
+
}
|
|
111
|
+
if (normalized === "openclaw") {
|
|
112
|
+
candidates.push("C:\\\\Program Files\\\\OpenClaw\\\\openclaw.exe", "C:\\\\Program Files (x86)\\\\OpenClaw\\\\openclaw.exe");
|
|
113
|
+
}
|
|
114
|
+
return candidates;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (const dir of unixBins) {
|
|
118
|
+
candidates.push(join(dir, normalized));
|
|
119
|
+
}
|
|
120
|
+
return candidates;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function resolveCommandPath(command: string): string | null {
|
|
124
|
+
for (const candidate of commandCandidates(command)) {
|
|
125
|
+
if (isExecutableFile(candidate)) {
|
|
126
|
+
return candidate;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function commandVersion(command: string, path: string | null): string | null {
|
|
133
|
+
if (!path) return null;
|
|
134
|
+
if (command === "node") {
|
|
135
|
+
return process.version;
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function recommendCandidates(memoryGib: number | null): string[] {
|
|
141
|
+
if (memoryGib === null) {
|
|
142
|
+
return ["embeddinggemma:300m-qat-q8_0", "nomic-embed-text:latest", "qwen3-embedding:0.6b"];
|
|
143
|
+
}
|
|
144
|
+
if (memoryGib < 8) {
|
|
145
|
+
return ["nomic-embed-text:latest", "embeddinggemma:300m-qat-q8_0"];
|
|
146
|
+
}
|
|
147
|
+
if (memoryGib < 32) {
|
|
148
|
+
return ["embeddinggemma:300m-qat-q8_0", "nomic-embed-text:latest", "qwen3-embedding:0.6b"];
|
|
149
|
+
}
|
|
150
|
+
return [
|
|
151
|
+
"embeddinggemma:300m-qat-q8_0",
|
|
152
|
+
"nomic-embed-text:latest",
|
|
153
|
+
"qwen3-embedding:0.6b",
|
|
154
|
+
"qwen3-embedding:latest",
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function fetchWithTimeout(url: string, timeoutMs: number): Promise<Response> {
|
|
159
|
+
const controller = new AbortController();
|
|
160
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
161
|
+
try {
|
|
162
|
+
return await fetch(url, { signal: controller.signal });
|
|
163
|
+
} finally {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function probeOllama(host: string): Promise<{ reachable: boolean; models: string[] }> {
|
|
169
|
+
const url = host.replace(/\/+$/, "") + "/api/tags";
|
|
170
|
+
try {
|
|
171
|
+
const response = await fetchWithTimeout(url, 5000);
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
return { reachable: false, models: [] };
|
|
174
|
+
}
|
|
175
|
+
const text = await response.text();
|
|
176
|
+
const payload = JSON.parse(text) as { models?: unknown };
|
|
177
|
+
const models = Array.isArray(payload.models) ? payload.models : [];
|
|
178
|
+
const names = models
|
|
179
|
+
.map((item) => (item && typeof item === "object" ? (item as Record<string, unknown>).name : undefined))
|
|
180
|
+
.filter((name): name is string => typeof name === "string");
|
|
181
|
+
return { reachable: true, models: names };
|
|
182
|
+
} catch {
|
|
183
|
+
return { reachable: false, models: [] };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function buildReport(ollamaHost: string): Promise<Report> {
|
|
188
|
+
const memoryGib = os.totalmem() ? os.totalmem() / 1024 / 1024 / 1024 : null;
|
|
189
|
+
const commands: Record<string, string | null> = {};
|
|
190
|
+
const versions: Record<string, string | null> = {};
|
|
191
|
+
|
|
192
|
+
for (const command of ["ollama", "openclaw", "node", "npm"]) {
|
|
193
|
+
const path = resolveCommandPath(command);
|
|
194
|
+
commands[command] = path;
|
|
195
|
+
versions[command] = commandVersion(command, path);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
commands.openclaw_management = commands.openclaw;
|
|
199
|
+
versions.openclaw_management = versions.openclaw;
|
|
200
|
+
|
|
201
|
+
const ollamaApi = await probeOllama(ollamaHost);
|
|
202
|
+
const osName = systemName();
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
os: osName,
|
|
206
|
+
release: os.release(),
|
|
207
|
+
arch: os.arch(),
|
|
208
|
+
shell_context: shellContext(),
|
|
209
|
+
cpu_count: os.cpus().length,
|
|
210
|
+
memory_gib: memoryGib === null ? null : Math.round(memoryGib * 100) / 100,
|
|
211
|
+
commands,
|
|
212
|
+
versions,
|
|
213
|
+
ollama_api: ollamaApi,
|
|
214
|
+
recommended_candidates: recommendCandidates(memoryGib === null ? null : memoryGib),
|
|
215
|
+
openclaw_install_note:
|
|
216
|
+
osName === "Windows"
|
|
217
|
+
? "Use Mac or Linux directly; use WSL on Windows for current official OpenClaw setup."
|
|
218
|
+
: "Use the official Ollama OpenClaw launch flow.",
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function printText(report: Report, ollamaHost: string): void {
|
|
223
|
+
process.stdout.write("System\n");
|
|
224
|
+
process.stdout.write(` OS: ${report.os} ${report.release}\n`);
|
|
225
|
+
process.stdout.write(` Context: ${report.shell_context}\n`);
|
|
226
|
+
process.stdout.write(` Arch: ${report.arch}\n`);
|
|
227
|
+
process.stdout.write(` CPUs: ${report.cpu_count}\n`);
|
|
228
|
+
process.stdout.write(` RAM GiB: ${report.memory_gib ?? "unknown"}\n\n`);
|
|
229
|
+
|
|
230
|
+
process.stdout.write("Commands\n");
|
|
231
|
+
for (const [command, path] of Object.entries(report.commands)) {
|
|
232
|
+
const version = report.versions[command] ?? null;
|
|
233
|
+
const label = command === "openclaw_management" ? "openclaw management" : command;
|
|
234
|
+
if (path) {
|
|
235
|
+
const suffix = version ? ` (${version})` : "";
|
|
236
|
+
process.stdout.write(` ${label}: ${path}${suffix}\n`);
|
|
237
|
+
} else {
|
|
238
|
+
process.stdout.write(` ${label}: missing\n`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
process.stdout.write("\nOllama API\n");
|
|
243
|
+
if (report.ollama_api.reachable) {
|
|
244
|
+
process.stdout.write(` ${ollamaHost}: reachable\n`);
|
|
245
|
+
process.stdout.write(
|
|
246
|
+
` Models: ${report.ollama_api.models.length ? report.ollama_api.models.join(", ") : "none pulled"}\n`,
|
|
247
|
+
);
|
|
248
|
+
} else {
|
|
249
|
+
process.stdout.write(` ${ollamaHost}: unreachable\n`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
process.stdout.write("\nRecommended candidates\n");
|
|
253
|
+
for (const model of report.recommended_candidates) {
|
|
254
|
+
process.stdout.write(` - ${model}\n`);
|
|
255
|
+
}
|
|
256
|
+
process.stdout.write(`\nOpenClaw install note\n ${report.openclaw_install_note}\n`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function main(): Promise<number> {
|
|
260
|
+
const parsed = parseArgs({
|
|
261
|
+
args: process.argv.slice(2),
|
|
262
|
+
options: {
|
|
263
|
+
"ollama-host": { type: "string", default: "http://127.0.0.1:11434" },
|
|
264
|
+
json: { type: "boolean", default: false },
|
|
265
|
+
help: { type: "boolean", default: false },
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
if (parsed.values.help) {
|
|
270
|
+
process.stdout.write(`${usageText()}\n`);
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const ollamaHost = String(parsed.values["ollama-host"] ?? "").trim() || "http://127.0.0.1:11434";
|
|
275
|
+
const report = await buildReport(ollamaHost);
|
|
276
|
+
|
|
277
|
+
if (parsed.values.json) {
|
|
278
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
279
|
+
} else {
|
|
280
|
+
printText(report, ollamaHost);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
void main()
|
|
287
|
+
.then((code) => {
|
|
288
|
+
process.exitCode = code;
|
|
289
|
+
})
|
|
290
|
+
.catch((err) => {
|
|
291
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
292
|
+
process.stderr.write(`${message}\n`);
|
|
293
|
+
process.exitCode = 1;
|
|
294
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "grix",
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"skills": [
|
|
5
|
+
"./openclaw-plugin/skills"
|
|
6
|
+
],
|
|
7
|
+
"channels": [
|
|
8
|
+
"grix"
|
|
9
|
+
],
|
|
10
|
+
"channelConfigs": {
|
|
11
|
+
"grix": {
|
|
12
|
+
"schema": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": true
|
|
15
|
+
},
|
|
16
|
+
"label": "Grix"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"configSchema": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"properties": {}
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "grix-connector",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"grix-connector": "dist/grix.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"!dist/**/*.map",
|
|
13
|
+
"!dist/**/*.d.ts",
|
|
14
|
+
"openclaw-plugin",
|
|
15
|
+
"scripts/install-guardian.mjs",
|
|
16
|
+
"scripts/install-guardian.sh",
|
|
17
|
+
"scripts/upgrade-guardian.sh",
|
|
18
|
+
"openclaw.plugin.json"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"postinstall": "node scripts/install-guardian.mjs",
|
|
22
|
+
"prepublishOnly": "npm run build:all",
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"build:plugin": "node scripts/build-plugin.mjs",
|
|
25
|
+
"build:all": "npm run build && node scripts/minify-dist.mjs && npm run build:plugin",
|
|
26
|
+
"dev": "npm run build && node dist/grix.js",
|
|
27
|
+
"test": "node --experimental-vm-modules node_modules/vitest/vitest.mjs run",
|
|
28
|
+
"test:watch": "node --experimental-vm-modules node_modules/vitest/vitest.mjs",
|
|
29
|
+
"lint": "tsc --noEmit",
|
|
30
|
+
"start": "node dist/grix.js start",
|
|
31
|
+
"stop": "node dist/grix.js stop",
|
|
32
|
+
"restart": "node dist/grix.js restart",
|
|
33
|
+
"status": "node dist/grix.js status"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"grix",
|
|
37
|
+
"aibot",
|
|
38
|
+
"agent-connector",
|
|
39
|
+
"claude",
|
|
40
|
+
"codex",
|
|
41
|
+
"gemini",
|
|
42
|
+
"qwen",
|
|
43
|
+
"deepseek",
|
|
44
|
+
"cursor",
|
|
45
|
+
"opencode",
|
|
46
|
+
"pi",
|
|
47
|
+
"openhuman",
|
|
48
|
+
"reasonix",
|
|
49
|
+
"acp",
|
|
50
|
+
"agent-client-protocol",
|
|
51
|
+
"mcp",
|
|
52
|
+
"openclaw",
|
|
53
|
+
"openclaw-plugin"
|
|
54
|
+
],
|
|
55
|
+
"author": "askie",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/askie/grix-connector.git"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/askie/grix-connector#readme",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/askie/grix-connector/issues"
|
|
63
|
+
},
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/node": "^25.6.0",
|
|
67
|
+
"@types/ws": "^8.18.1",
|
|
68
|
+
"esbuild": "^0.27.7",
|
|
69
|
+
"fast-check": "^4.8.0",
|
|
70
|
+
"typescript": "^5.7.0",
|
|
71
|
+
"vitest": "^3.0.0"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"openclaw": ">=2026.4.8"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"openclaw": {
|
|
78
|
+
"optional": true
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"engines": {
|
|
82
|
+
"node": ">=18.0.0"
|
|
83
|
+
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
86
|
+
"extract-zip": "^2.0.1",
|
|
87
|
+
"socket.io-client": "^4.8.3",
|
|
88
|
+
"ws": "^8.20.0"
|
|
89
|
+
},
|
|
90
|
+
"optionalDependencies": {
|
|
91
|
+
"node-pty": "^1.1.0"
|
|
92
|
+
},
|
|
93
|
+
"openclaw": {
|
|
94
|
+
"extensions": [
|
|
95
|
+
"./openclaw-plugin/index.js"
|
|
96
|
+
],
|
|
97
|
+
"channel": {
|
|
98
|
+
"id": "grix",
|
|
99
|
+
"label": "Grix",
|
|
100
|
+
"selectionLabel": "Grix",
|
|
101
|
+
"docsPath": "/channels/grix",
|
|
102
|
+
"blurb": "Connect OpenClaw to a Grix deployment for website management with mobile PWA support.",
|
|
103
|
+
"aliases": [
|
|
104
|
+
"gr"
|
|
105
|
+
],
|
|
106
|
+
"order": 90
|
|
107
|
+
},
|
|
108
|
+
"install": {
|
|
109
|
+
"npmSpec": "grix-connector",
|
|
110
|
+
"localPath": ".",
|
|
111
|
+
"defaultChoice": "npm"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// install-guardian — cross-platform npm postinstall script
|
|
3
|
+
// Copies upgrade-guardian.sh to ~/.grix/bin/ (idempotent, won't overwrite existing)
|
|
4
|
+
// On Windows, skips since the guardian is a bash script.
|
|
5
|
+
|
|
6
|
+
import { existsSync, copyFileSync, mkdirSync } from 'node:fs';
|
|
7
|
+
import { join, resolve } from 'node:path';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
|
|
10
|
+
// Guardian is a bash script — skip on Windows entirely
|
|
11
|
+
if (process.platform === 'win32') {
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const GRIX_HOME = process.env.GRIX_CONNECTOR_HOME || join(homedir(), '.grix');
|
|
16
|
+
const GUARDIAN_DEST = join(GRIX_HOME, 'bin', 'upgrade-guardian.sh');
|
|
17
|
+
|
|
18
|
+
if (existsSync(GUARDIAN_DEST)) {
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const INIT_CWD = process.env.INIT_CWD || resolve(import.meta.dirname);
|
|
23
|
+
const GUARDIAN_SRC = join(INIT_CWD, 'scripts', 'upgrade-guardian.sh');
|
|
24
|
+
|
|
25
|
+
if (!existsSync(GUARDIAN_SRC)) {
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
mkdirSync(join(GRIX_HOME, 'bin'), { recursive: true });
|
|
30
|
+
copyFileSync(GUARDIAN_SRC, GUARDIAN_DEST);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# install-guardian.sh — npm postinstall script
|
|
3
|
+
# Copies upgrade-guardian.sh to ~/.grix/bin/ (idempotent, won't overwrite existing)
|
|
4
|
+
# This ensures the guardian script exists on first install and survives npm upgrades.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
GRIX_HOME="${GRIX_CONNECTOR_HOME:-$HOME/.grix}"
|
|
9
|
+
GUARDIAN_DEST="$GRIX_HOME/bin/upgrade-guardian.sh"
|
|
10
|
+
|
|
11
|
+
# Don't overwrite — user may have custom modifications
|
|
12
|
+
if [ -f "$GUARDIAN_DEST" ]; then
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Locate source: INIT_CWD is set by npm to the package root during lifecycle scripts
|
|
17
|
+
GUARDIAN_SRC="${INIT_CWD:-$(dirname "$0")}/scripts/upgrade-guardian.sh"
|
|
18
|
+
if [ ! -f "$GUARDIAN_SRC" ]; then
|
|
19
|
+
# Fallback: try relative to this script
|
|
20
|
+
GUARDIAN_SRC="$(cd "$(dirname "$0")" && pwd)/upgrade-guardian.sh"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
if [ ! -f "$GUARDIAN_SRC" ]; then
|
|
24
|
+
echo "grix-connector postinstall: guardian source not found, skipping" >&2
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
mkdir -p "$GRIX_HOME/bin"
|
|
29
|
+
cp "$GUARDIAN_SRC" "$GUARDIAN_DEST"
|
|
30
|
+
chmod +x "$GUARDIAN_DEST"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# upgrade-guardian.sh — post-upgrade health monitor
|
|
3
|
+
# Started by daemon after npm install, runs as detached background process.
|
|
4
|
+
# Monitors healthz for 90s, rolls back on crash_count >= 3.
|
|
5
|
+
# This file is NOT inside the npm package — installed once to ~/.grix/bin/.
|
|
6
|
+
|
|
7
|
+
GRIX_HOME="${GRIX_CONNECTOR_HOME:-$HOME/.grix}"
|
|
8
|
+
PENDING_FILE="$GRIX_HOME/data/upgrade-pending.json"
|
|
9
|
+
LOCK_FILE="$GRIX_HOME/upgrade-guardian.lock"
|
|
10
|
+
LOG_FILE="$GRIX_HOME/log/upgrade.log"
|
|
11
|
+
MAX_CRASHES=3
|
|
12
|
+
HEALTH_TIMEOUT=90
|
|
13
|
+
HEALTH_PORT_FILE="$GRIX_HOME/data/health-port"
|
|
14
|
+
HEALTH_PORT=$(cat "$HEALTH_PORT_FILE" 2>/dev/null || echo "19579")
|
|
15
|
+
HEALTH_URL="http://127.0.0.1:${HEALTH_PORT}/healthz"
|
|
16
|
+
NPM_PACKAGE="grix-connector"
|
|
17
|
+
|
|
18
|
+
# Ensure directories exist
|
|
19
|
+
mkdir -p "$GRIX_HOME/log" "$GRIX_HOME/data"
|
|
20
|
+
|
|
21
|
+
log() {
|
|
22
|
+
echo "[$(date '+%Y-%m-%dT%H:%M:%S%z')] guardian: $1" >> "$LOG_FILE"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Prevent duplicate guardian instances
|
|
26
|
+
if [ -f "$LOCK_FILE" ]; then
|
|
27
|
+
LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null)
|
|
28
|
+
if [ -n "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2>/dev/null; then
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
rm -f "$LOCK_FILE"
|
|
32
|
+
fi
|
|
33
|
+
echo $$ > "$LOCK_FILE"
|
|
34
|
+
trap 'rm -f "$LOCK_FILE"' EXIT
|
|
35
|
+
|
|
36
|
+
# Read pending marker
|
|
37
|
+
if [ ! -f "$PENDING_FILE" ]; then
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Extract fields from JSON (portable: no jq dependency)
|
|
42
|
+
FROM_VERSION=$(cat "$PENDING_FILE" | grep -o '"from_version":"[^"]*"' | cut -d'"' -f4)
|
|
43
|
+
TARGET_VERSION=$(cat "$PENDING_FILE" | grep -o '"target_version":"[^"]*"' | cut -d'"' -f4)
|
|
44
|
+
UPGRADED_AT=$(cat "$PENDING_FILE" | grep -o '"upgraded_at":"[^"]*"' | cut -d'"' -f4)
|
|
45
|
+
CRASH_COUNT=$(cat "$PENDING_FILE" | grep -o '"crash_count":[0-9]*' | cut -d: -f2)
|
|
46
|
+
CRASH_COUNT=${CRASH_COUNT:-0}
|
|
47
|
+
|
|
48
|
+
# Validate pending file
|
|
49
|
+
if [ -z "$FROM_VERSION" ]; then
|
|
50
|
+
log "pending file corrupt, missing from_version, removing"
|
|
51
|
+
rm -f "$PENDING_FILE"
|
|
52
|
+
exit 0
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
log "started: from=$FROM_VERSION target=$TARGET_VERSION crash_count=$CRASH_COUNT"
|
|
56
|
+
|
|
57
|
+
# Wait for old daemon to exit (SIGTERM + shutdown + restart)
|
|
58
|
+
sleep 15
|
|
59
|
+
|
|
60
|
+
# Monitor loop: wait for healthz to return 200
|
|
61
|
+
ELAPSED=0
|
|
62
|
+
while [ $ELAPSED -lt $HEALTH_TIMEOUT ]; do
|
|
63
|
+
if curl -sf "$HEALTH_URL" > /dev/null 2>&1; then
|
|
64
|
+
log "healthz passed, upgrade successful"
|
|
65
|
+
rm -f "$PENDING_FILE"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
sleep 3
|
|
69
|
+
ELAPSED=$((ELAPSED + 3))
|
|
70
|
+
done
|
|
71
|
+
|
|
72
|
+
# Extra grace period for slow systems
|
|
73
|
+
sleep 15
|
|
74
|
+
if curl -sf "$HEALTH_URL" > /dev/null 2>&1; then
|
|
75
|
+
log "healthz passed (delayed), upgrade successful"
|
|
76
|
+
rm -f "$PENDING_FILE"
|
|
77
|
+
exit 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Health check failed
|
|
81
|
+
CRASH_COUNT=$((CRASH_COUNT + 1))
|
|
82
|
+
log "healthz timeout, crash_count=$CRASH_COUNT"
|
|
83
|
+
|
|
84
|
+
if [ $CRASH_COUNT -ge $MAX_CRASHES ]; then
|
|
85
|
+
log "rollback: installing ${NPM_PACKAGE}@${FROM_VERSION}"
|
|
86
|
+
if npm install -g "${NPM_PACKAGE}@${FROM_VERSION}" --prefer-online --no-audit --no-fund >> "$LOG_FILE" 2>&1; then
|
|
87
|
+
log "rollback succeeded"
|
|
88
|
+
rm -f "$PENDING_FILE"
|
|
89
|
+
else
|
|
90
|
+
log "ROLLBACK FAILED — manual intervention required"
|
|
91
|
+
fi
|
|
92
|
+
exit 0
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Under threshold — update crash_count and exit, let process manager restart
|
|
96
|
+
echo "{\"from_version\":\"$FROM_VERSION\",\"target_version\":\"$TARGET_VERSION\",\"upgraded_at\":\"$UPGRADED_AT\",\"crash_count\":$CRASH_COUNT}" > "$PENDING_FILE.tmp"
|
|
97
|
+
mv "$PENDING_FILE.tmp" "$PENDING_FILE"
|
|
98
|
+
log "updated crash_count to $CRASH_COUNT, exiting"
|