hanzi-browse 2.2.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 +182 -0
- package/dist/agent/loop.d.ts +63 -0
- package/dist/agent/loop.js +186 -0
- package/dist/agent/system-prompt.d.ts +7 -0
- package/dist/agent/system-prompt.js +41 -0
- package/dist/agent/tools.d.ts +9 -0
- package/dist/agent/tools.js +154 -0
- package/dist/cli/detect-credentials.d.ts +31 -0
- package/dist/cli/detect-credentials.js +44 -0
- package/dist/cli/import-credentials-handler.d.ts +14 -0
- package/dist/cli/import-credentials-handler.js +22 -0
- package/dist/cli/session-files.d.ts +28 -0
- package/dist/cli/session-files.js +118 -0
- package/dist/cli/setup.d.ts +10 -0
- package/dist/cli/setup.js +915 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +506 -0
- package/dist/dashboard/assets/index-CEFyesbT.js +46 -0
- package/dist/dashboard/assets/index-Dnht2kLU.css +1 -0
- package/dist/dashboard/index.html +13 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1116 -0
- package/dist/ipc/index.d.ts +8 -0
- package/dist/ipc/index.js +8 -0
- package/dist/ipc/native-host.d.ts +96 -0
- package/dist/ipc/native-host.js +223 -0
- package/dist/ipc/websocket-client.d.ts +73 -0
- package/dist/ipc/websocket-client.js +199 -0
- package/dist/license/manager.d.ts +20 -0
- package/dist/license/manager.js +15 -0
- package/dist/llm/client.d.ts +72 -0
- package/dist/llm/client.js +227 -0
- package/dist/llm/credentials.d.ts +61 -0
- package/dist/llm/credentials.js +200 -0
- package/dist/llm/vertex.d.ts +22 -0
- package/dist/llm/vertex.js +335 -0
- package/dist/managed/api-http.test.d.ts +7 -0
- package/dist/managed/api-http.test.js +623 -0
- package/dist/managed/api.d.ts +51 -0
- package/dist/managed/api.js +1448 -0
- package/dist/managed/api.test.d.ts +10 -0
- package/dist/managed/api.test.js +146 -0
- package/dist/managed/auth.d.ts +38 -0
- package/dist/managed/auth.js +192 -0
- package/dist/managed/billing.d.ts +70 -0
- package/dist/managed/billing.js +227 -0
- package/dist/managed/deploy.d.ts +17 -0
- package/dist/managed/deploy.js +385 -0
- package/dist/managed/e2e.test.d.ts +15 -0
- package/dist/managed/e2e.test.js +151 -0
- package/dist/managed/hardening.test.d.ts +14 -0
- package/dist/managed/hardening.test.js +346 -0
- package/dist/managed/integration.test.d.ts +8 -0
- package/dist/managed/integration.test.js +274 -0
- package/dist/managed/log.d.ts +18 -0
- package/dist/managed/log.js +31 -0
- package/dist/managed/server.d.ts +12 -0
- package/dist/managed/server.js +69 -0
- package/dist/managed/store-pg.d.ts +191 -0
- package/dist/managed/store-pg.js +479 -0
- package/dist/managed/store.d.ts +188 -0
- package/dist/managed/store.js +379 -0
- package/dist/relay/auto-start.d.ts +19 -0
- package/dist/relay/auto-start.js +71 -0
- package/dist/relay/server.d.ts +17 -0
- package/dist/relay/server.js +403 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +4 -0
- package/dist/types/session.d.ts +134 -0
- package/dist/types/session.js +16 -0
- package/package.json +61 -0
- package/skills/README.md +48 -0
- package/skills/a11y-auditor/SKILL.md +42 -0
- package/skills/e2e-tester/SKILL.md +154 -0
- package/skills/hanzi-browse/SKILL.md +182 -0
- package/skills/linkedin-prospector/SKILL.md +149 -0
- package/skills/social-poster/SKILL.md +146 -0
- package/skills/x-marketer/SKILL.md +479 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Managed Backend Server
|
|
4
|
+
*
|
|
5
|
+
* Starts the REST API + connects to the WebSocket relay.
|
|
6
|
+
* On first run, creates a default workspace and API key.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* VERTEX_SA_PATH=/path/to/sa.json node dist/managed/server.js
|
|
10
|
+
* node dist/managed/server.js --sa /path/to/sa.json --port 3456
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Managed Backend Server
|
|
4
|
+
*
|
|
5
|
+
* Starts the REST API + connects to the WebSocket relay.
|
|
6
|
+
* On first run, creates a default workspace and API key.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* VERTEX_SA_PATH=/path/to/sa.json node dist/managed/server.js
|
|
10
|
+
* node dist/managed/server.js --sa /path/to/sa.json --port 3456
|
|
11
|
+
*/
|
|
12
|
+
import { initVertex } from "../llm/vertex.js";
|
|
13
|
+
import { WebSocketClient } from "../ipc/websocket-client.js";
|
|
14
|
+
import { startManagedAPI, initManagedAPI, handleRelayMessage } from "./api.js";
|
|
15
|
+
import { ensureDefaultWorkspace } from "./store.js";
|
|
16
|
+
const SA_PATH = process.env.VERTEX_SA_PATH ||
|
|
17
|
+
process.argv.find((_, i, arr) => arr[i - 1] === "--sa") ||
|
|
18
|
+
"/tmp/hanzi-vertex-sa.json";
|
|
19
|
+
const RELAY_URL = process.env.RELAY_URL || "ws://localhost:7862";
|
|
20
|
+
const API_PORT = parseInt(process.env.API_PORT || "3456", 10);
|
|
21
|
+
async function main() {
|
|
22
|
+
// 1. Init Vertex AI
|
|
23
|
+
console.error(`[Server] Loading Vertex AI credentials from ${SA_PATH}`);
|
|
24
|
+
initVertex(SA_PATH);
|
|
25
|
+
// 2. Bootstrap default workspace + API key
|
|
26
|
+
const { workspace, apiKey } = ensureDefaultWorkspace();
|
|
27
|
+
console.error(`[Server] Workspace: ${workspace.name} (${workspace.id})`);
|
|
28
|
+
console.error(`[Server] API Key: ${apiKey.key}`);
|
|
29
|
+
// 3. Connect to WebSocket relay
|
|
30
|
+
console.error(`[Server] Connecting to relay at ${RELAY_URL}`);
|
|
31
|
+
const relay = new WebSocketClient({
|
|
32
|
+
role: "mcp",
|
|
33
|
+
relayUrl: RELAY_URL,
|
|
34
|
+
autoStartRelay: true,
|
|
35
|
+
});
|
|
36
|
+
relay.onMessage((message) => {
|
|
37
|
+
if (handleRelayMessage(message))
|
|
38
|
+
return;
|
|
39
|
+
// Ignore pong and registered messages
|
|
40
|
+
if (message?.type === "pong" || message?.type === "registered")
|
|
41
|
+
return;
|
|
42
|
+
console.error(`[Server] Unhandled relay message: ${message?.type}`);
|
|
43
|
+
});
|
|
44
|
+
await relay.connect();
|
|
45
|
+
// 4. Start the API
|
|
46
|
+
initManagedAPI(relay);
|
|
47
|
+
startManagedAPI(API_PORT);
|
|
48
|
+
console.error(`
|
|
49
|
+
╔═══════════════════════════════════════════════════════╗
|
|
50
|
+
║ Hanzi Managed Backend ║
|
|
51
|
+
║ ║
|
|
52
|
+
║ API: http://localhost:${String(API_PORT).padEnd(5)} ║
|
|
53
|
+
║ Relay: ${RELAY_URL.padEnd(43)} ║
|
|
54
|
+
║ LLM: Vertex AI (Gemini 2.5 Flash) ║
|
|
55
|
+
║ ║
|
|
56
|
+
║ API Key: ${apiKey.key.slice(0, 20)}... ║
|
|
57
|
+
║ ║
|
|
58
|
+
║ Test: ║
|
|
59
|
+
║ curl -X POST http://localhost:${String(API_PORT).padEnd(5)}v1/tasks \\ ║
|
|
60
|
+
║ -H "Authorization: Bearer ${apiKey.key.slice(0, 16)}..." \\ ║
|
|
61
|
+
║ -H "Content-Type: application/json" \\ ║
|
|
62
|
+
║ -d '{"task": "Go to example.com"}' ║
|
|
63
|
+
╚═══════════════════════════════════════════════════════╝
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
main().catch((err) => {
|
|
67
|
+
console.error("[Server] Fatal error:", err);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Postgres-backed Managed Platform Store
|
|
3
|
+
*
|
|
4
|
+
* Drop-in replacement for store.ts (file-based).
|
|
5
|
+
* Uses Neon Postgres via the `pg` driver.
|
|
6
|
+
* Same exported function signatures — swap by changing the import.
|
|
7
|
+
*/
|
|
8
|
+
export interface ApiKey {
|
|
9
|
+
id: string;
|
|
10
|
+
key: string;
|
|
11
|
+
keyPrefix?: string;
|
|
12
|
+
name: string;
|
|
13
|
+
workspaceId: string;
|
|
14
|
+
createdAt: number;
|
|
15
|
+
lastUsedAt?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface Workspace {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
createdAt: number;
|
|
21
|
+
stripeCustomerId?: string;
|
|
22
|
+
plan: "free" | "pro" | "enterprise";
|
|
23
|
+
subscriptionId?: string;
|
|
24
|
+
subscriptionStatus?: "active" | "past_due" | "cancelled";
|
|
25
|
+
creditBalance: number;
|
|
26
|
+
freeTasksThisMonth: number;
|
|
27
|
+
freeTasksResetAt: number;
|
|
28
|
+
}
|
|
29
|
+
export interface PairingToken {
|
|
30
|
+
token: string;
|
|
31
|
+
workspaceId: string;
|
|
32
|
+
createdBy: string;
|
|
33
|
+
createdAt: number;
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
consumed: boolean;
|
|
36
|
+
label?: string;
|
|
37
|
+
externalUserId?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface BrowserSession {
|
|
40
|
+
id: string;
|
|
41
|
+
workspaceId: string;
|
|
42
|
+
sessionToken: string;
|
|
43
|
+
status: "connected" | "disconnected";
|
|
44
|
+
connectedAt: number;
|
|
45
|
+
lastHeartbeat: number;
|
|
46
|
+
tabId?: number;
|
|
47
|
+
windowId?: number;
|
|
48
|
+
label?: string;
|
|
49
|
+
externalUserId?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface TaskRun {
|
|
52
|
+
id: string;
|
|
53
|
+
workspaceId: string;
|
|
54
|
+
apiKeyId: string;
|
|
55
|
+
browserSessionId?: string;
|
|
56
|
+
task: string;
|
|
57
|
+
url?: string;
|
|
58
|
+
context?: string;
|
|
59
|
+
status: "running" | "complete" | "error" | "cancelled";
|
|
60
|
+
answer?: string;
|
|
61
|
+
steps: number;
|
|
62
|
+
usage: {
|
|
63
|
+
inputTokens: number;
|
|
64
|
+
outputTokens: number;
|
|
65
|
+
apiCalls: number;
|
|
66
|
+
};
|
|
67
|
+
createdAt: number;
|
|
68
|
+
completedAt?: number;
|
|
69
|
+
}
|
|
70
|
+
export interface UsageEvent {
|
|
71
|
+
id: string;
|
|
72
|
+
workspaceId: string;
|
|
73
|
+
apiKeyId: string;
|
|
74
|
+
taskRunId: string;
|
|
75
|
+
inputTokens: number;
|
|
76
|
+
outputTokens: number;
|
|
77
|
+
apiCalls: number;
|
|
78
|
+
model: string;
|
|
79
|
+
costUsd: number;
|
|
80
|
+
createdAt: number;
|
|
81
|
+
}
|
|
82
|
+
export declare function initPgStore(connectionString: string): void;
|
|
83
|
+
export declare function createWorkspace(name: string): Promise<Workspace>;
|
|
84
|
+
export declare function getWorkspace(id: string): Promise<Workspace | null>;
|
|
85
|
+
export declare function updateWorkspaceBilling(id: string, fields: {
|
|
86
|
+
stripeCustomerId?: string;
|
|
87
|
+
plan?: Workspace["plan"];
|
|
88
|
+
subscriptionId?: string;
|
|
89
|
+
subscriptionStatus?: Workspace["subscriptionStatus"];
|
|
90
|
+
}): Promise<Workspace | null>;
|
|
91
|
+
export interface TaskAllowance {
|
|
92
|
+
allowed: boolean;
|
|
93
|
+
reason?: string;
|
|
94
|
+
source?: "free" | "credits";
|
|
95
|
+
freeRemaining?: number;
|
|
96
|
+
creditBalance?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if a workspace can run a task. Returns allowance with source info.
|
|
100
|
+
* Automatically resets the free tier counter on new month.
|
|
101
|
+
*/
|
|
102
|
+
export declare function checkTaskAllowance(workspaceId: string): Promise<TaskAllowance>;
|
|
103
|
+
/**
|
|
104
|
+
* Deduct for a completed task. Call ONLY on status="complete".
|
|
105
|
+
* Uses atomic SQL to prevent double-deduct races.
|
|
106
|
+
*/
|
|
107
|
+
export declare function deductTaskCredit(workspaceId: string): Promise<"free" | "credits">;
|
|
108
|
+
/**
|
|
109
|
+
* Add purchased credits to a workspace.
|
|
110
|
+
*/
|
|
111
|
+
export declare function addCredits(workspaceId: string, amount: number): Promise<number>;
|
|
112
|
+
export declare function createApiKey(workspaceId: string, name: string): Promise<ApiKey>;
|
|
113
|
+
export declare function validateApiKey(key: string): Promise<ApiKey | null>;
|
|
114
|
+
export declare function listApiKeys(workspaceId: string): Promise<ApiKey[]>;
|
|
115
|
+
export declare function deleteApiKey(id: string, workspaceId: string): Promise<boolean>;
|
|
116
|
+
export declare function createPairingToken(workspaceId: string, apiKeyId: string | null, metadata?: {
|
|
117
|
+
label?: string;
|
|
118
|
+
externalUserId?: string;
|
|
119
|
+
}): Promise<PairingToken & {
|
|
120
|
+
_plainToken: string;
|
|
121
|
+
}>;
|
|
122
|
+
export declare function consumePairingToken(pairingTokenStr: string): Promise<BrowserSession | null>;
|
|
123
|
+
export declare function validateSessionToken(sessionToken: string): Promise<BrowserSession | null>;
|
|
124
|
+
export declare function heartbeatSession(id: string): Promise<boolean>;
|
|
125
|
+
/**
|
|
126
|
+
* Rotate a session's token. Returns the new plaintext token, or null if session is invalid.
|
|
127
|
+
* The old token hash is atomically replaced. One-step rotation — no dual-token window.
|
|
128
|
+
*/
|
|
129
|
+
export declare function rotateSessionToken(id: string): Promise<string | null>;
|
|
130
|
+
export declare function disconnectSession(id: string): Promise<void>;
|
|
131
|
+
export declare function updateSessionContext(id: string, tabId: number, windowId?: number): Promise<void>;
|
|
132
|
+
export declare function getBrowserSession(id: string): Promise<BrowserSession | null>;
|
|
133
|
+
export declare function listBrowserSessions(workspaceId?: string): Promise<BrowserSession[]>;
|
|
134
|
+
export declare function deleteBrowserSession(id: string, workspaceId: string): Promise<boolean>;
|
|
135
|
+
export declare function createTaskRun(params: {
|
|
136
|
+
workspaceId: string;
|
|
137
|
+
apiKeyId: string;
|
|
138
|
+
task: string;
|
|
139
|
+
url?: string;
|
|
140
|
+
context?: string;
|
|
141
|
+
browserSessionId?: string;
|
|
142
|
+
}): Promise<TaskRun>;
|
|
143
|
+
export declare function updateTaskRun(id: string, updates: Partial<TaskRun>): Promise<TaskRun | null>;
|
|
144
|
+
export declare function getTaskRun(id: string): Promise<TaskRun | null>;
|
|
145
|
+
export declare function listStuckTasks(maxAgeMs: number): Promise<TaskRun[]>;
|
|
146
|
+
export declare function listTaskRuns(workspaceId: string, limit?: number): Promise<TaskRun[]>;
|
|
147
|
+
export interface TaskStep {
|
|
148
|
+
id: string;
|
|
149
|
+
taskRunId: string;
|
|
150
|
+
step: number;
|
|
151
|
+
status: string;
|
|
152
|
+
toolName?: string;
|
|
153
|
+
toolInput?: Record<string, any>;
|
|
154
|
+
output?: string;
|
|
155
|
+
screenshot?: string;
|
|
156
|
+
createdAt: number;
|
|
157
|
+
durationMs?: number;
|
|
158
|
+
}
|
|
159
|
+
export declare function insertTaskStep(params: {
|
|
160
|
+
taskRunId: string;
|
|
161
|
+
step: number;
|
|
162
|
+
status: string;
|
|
163
|
+
toolName?: string;
|
|
164
|
+
toolInput?: Record<string, any>;
|
|
165
|
+
output?: string;
|
|
166
|
+
screenshot?: string;
|
|
167
|
+
durationMs?: number;
|
|
168
|
+
}): Promise<void>;
|
|
169
|
+
export declare function getTaskSteps(taskRunId: string): Promise<TaskStep[]>;
|
|
170
|
+
export declare function getTaskStepScreenshot(taskRunId: string, step: number): Promise<string | null>;
|
|
171
|
+
export declare function recordUsage(params: {
|
|
172
|
+
workspaceId: string;
|
|
173
|
+
apiKeyId: string;
|
|
174
|
+
taskRunId: string;
|
|
175
|
+
inputTokens: number;
|
|
176
|
+
outputTokens: number;
|
|
177
|
+
apiCalls: number;
|
|
178
|
+
model: string;
|
|
179
|
+
}): Promise<UsageEvent>;
|
|
180
|
+
export declare function getUsageSummary(workspaceId: string, since?: number): Promise<{
|
|
181
|
+
totalInputTokens: number;
|
|
182
|
+
totalOutputTokens: number;
|
|
183
|
+
totalApiCalls: number;
|
|
184
|
+
totalCostUsd: number;
|
|
185
|
+
taskCount: number;
|
|
186
|
+
}>;
|
|
187
|
+
export declare function ensureDefaultWorkspace(): Promise<{
|
|
188
|
+
workspace: Workspace;
|
|
189
|
+
apiKey: ApiKey;
|
|
190
|
+
}>;
|
|
191
|
+
export declare function startHeartbeatFlush(): void;
|