@openheinerss/sdk 0.0.0-stage → 0.1.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 CHANGED
@@ -1,3 +1,52 @@
1
- # Temporary Holding Version
1
+ # @openheinerss/sdk
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
+ SDK oficial em **TypeScript / JavaScript** para integração com o **Openheinerss** (crom-org).
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ npm install @openheinerss/sdk
9
+ ```
10
+
11
+ ## Uso no Backend / Node / Bun
12
+
13
+ ```typescript
14
+ import { Openheinerss } from "@openheinerss/sdk";
15
+
16
+ const agent = new Openheinerss({
17
+ options: {
18
+ harness: "claude-code", // ou "opencode", "mock"
19
+ provider: "openrouter",
20
+ model: "anthropic/claude-3.7-sonnet"
21
+ }
22
+ });
23
+
24
+ agent.on("thinking", (delta) => console.log("Pensando:", delta));
25
+ agent.on("text", (delta) => process.stdout.write(delta));
26
+ agent.on("permission", async (req) => {
27
+ console.log("Permissão solicitada para:", req.command);
28
+ await req.allow();
29
+ });
30
+
31
+ await agent.prompt("Refatore a autenticação");
32
+ ```
33
+
34
+ ## Uso no Frontend / React
35
+
36
+ ```tsx
37
+ import { useOpenheinerss } from "@openheinerss/sdk";
38
+
39
+ export function Chat() {
40
+ const { messages, isThinking, prompt } = useOpenheinerss();
41
+
42
+ return (
43
+ <div>
44
+ {messages.map((m) => (
45
+ <div key={m.id}><b>{m.role}:</b> {m.text}</div>
46
+ ))}
47
+ {isThinking && <p>Pensando...</p>}
48
+ <button onClick={() => prompt("Olá Openheinerss!")}>Enviar</button>
49
+ </div>
50
+ );
51
+ }
52
+ ```
@@ -0,0 +1,46 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { SessionOptions } from "./types.js";
3
+ export * from "./types.js";
4
+ export * from "./react.js";
5
+ export interface ClientConfig {
6
+ transport?: "stdio" | "websocket";
7
+ wsEndpoint?: string;
8
+ binPath?: string;
9
+ options?: SessionOptions;
10
+ }
11
+ export declare class Openheinerss extends EventEmitter {
12
+ private proc?;
13
+ private ws?;
14
+ private sessionId?;
15
+ private reqId;
16
+ private pendingCallbacks;
17
+ private config;
18
+ constructor(config?: ClientConfig);
19
+ /**
20
+ * Conecta e inicializa a sessão com o harness desejado
21
+ */
22
+ start(options?: SessionOptions): Promise<string>;
23
+ /**
24
+ * Envia uma instrução textual e anexos para o agente
25
+ */
26
+ prompt(text: string, images?: Array<{
27
+ mediaType: string;
28
+ data: string;
29
+ }>): Promise<void>;
30
+ /**
31
+ * Responde uma autorização de ferramenta
32
+ */
33
+ respondPermission(requestId: string, allow: boolean, message?: string): Promise<void>;
34
+ /**
35
+ * Interrompe o processamento da sessão
36
+ */
37
+ abort(): Promise<void>;
38
+ /**
39
+ * Fecha os processos ou conexões
40
+ */
41
+ close(): void;
42
+ private initStdio;
43
+ private initWebSocket;
44
+ private handleIncoming;
45
+ private sendRPC;
46
+ }
package/dist/index.js ADDED
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.Openheinerss = void 0;
18
+ const node_events_1 = require("node:events");
19
+ const node_child_process_1 = require("node:child_process");
20
+ __exportStar(require("./types.js"), exports);
21
+ __exportStar(require("./react.js"), exports);
22
+ class Openheinerss extends node_events_1.EventEmitter {
23
+ proc;
24
+ ws;
25
+ sessionId;
26
+ reqId = 1;
27
+ pendingCallbacks = new Map();
28
+ config;
29
+ constructor(config = {}) {
30
+ super();
31
+ this.config = {
32
+ transport: config.transport || (typeof window !== "undefined" ? "websocket" : "stdio"),
33
+ wsEndpoint: config.wsEndpoint || "ws://127.0.0.1:4799",
34
+ binPath: config.binPath || "openheinerss",
35
+ options: config.options || {},
36
+ ...config,
37
+ };
38
+ }
39
+ /**
40
+ * Conecta e inicializa a sessão com o harness desejado
41
+ */
42
+ async start(options) {
43
+ const opts = { ...this.config.options, ...options };
44
+ if (this.config.transport === "stdio") {
45
+ this.initStdio();
46
+ }
47
+ else {
48
+ await this.initWebSocket();
49
+ }
50
+ const res = await this.sendRPC("session.create", {
51
+ harness: opts.harness || "mock",
52
+ mode: opts.mode,
53
+ cwd: opts.cwd || (typeof process !== "undefined" ? process.cwd() : "/"),
54
+ provider: opts.provider,
55
+ model: opts.model,
56
+ options: {
57
+ permissionMode: opts.permissionMode || "ask",
58
+ systemPrompt: opts.systemPrompt,
59
+ },
60
+ });
61
+ this.sessionId = res.sessionId;
62
+ return this.sessionId;
63
+ }
64
+ /**
65
+ * Envia uma instrução textual e anexos para o agente
66
+ */
67
+ async prompt(text, images = []) {
68
+ if (!this.sessionId) {
69
+ await this.start();
70
+ }
71
+ await this.sendRPC("session.prompt", {
72
+ sessionId: this.sessionId,
73
+ text,
74
+ images,
75
+ });
76
+ }
77
+ /**
78
+ * Responde uma autorização de ferramenta
79
+ */
80
+ async respondPermission(requestId, allow, message) {
81
+ if (!this.sessionId)
82
+ return;
83
+ await this.sendRPC("session.permission_respond", {
84
+ sessionId: this.sessionId,
85
+ requestId,
86
+ decision: allow ? "allow" : "deny",
87
+ message,
88
+ });
89
+ }
90
+ /**
91
+ * Interrompe o processamento da sessão
92
+ */
93
+ async abort() {
94
+ if (!this.sessionId)
95
+ return;
96
+ await this.sendRPC("session.abort", {
97
+ sessionId: this.sessionId,
98
+ });
99
+ }
100
+ /**
101
+ * Fecha os processos ou conexões
102
+ */
103
+ close() {
104
+ if (this.proc) {
105
+ this.proc.kill();
106
+ this.proc = undefined;
107
+ }
108
+ if (this.ws) {
109
+ this.ws.close();
110
+ this.ws = undefined;
111
+ }
112
+ }
113
+ initStdio() {
114
+ this.proc = (0, node_child_process_1.spawn)(this.config.binPath, ["serve", "--stdio"]);
115
+ let buffer = "";
116
+ this.proc.stdout?.on("data", (chunk) => {
117
+ buffer += chunk.toString("utf8");
118
+ const lines = buffer.split("\n");
119
+ buffer = lines.pop() || "";
120
+ for (const line of lines) {
121
+ if (!line.trim())
122
+ continue;
123
+ try {
124
+ const msg = JSON.parse(line);
125
+ this.handleIncoming(msg);
126
+ }
127
+ catch (_) { }
128
+ }
129
+ });
130
+ this.proc.on("error", (err) => {
131
+ this.emit("error", { message: `Falha ao iniciar binário openheinerss: ${err.message}` });
132
+ });
133
+ }
134
+ async initWebSocket() {
135
+ return new Promise((resolve, reject) => {
136
+ const WebSocketImpl = typeof WebSocket !== "undefined" ? WebSocket : globalThis.WebSocket;
137
+ if (!WebSocketImpl) {
138
+ return reject(new Error("Ambiente WebSocket não encontrado"));
139
+ }
140
+ this.ws = new WebSocketImpl(this.config.wsEndpoint);
141
+ this.ws.onopen = () => resolve();
142
+ this.ws.onerror = (err) => reject(new Error(`Falha ao conectar no WebSocket: ${err}`));
143
+ this.ws.onmessage = (event) => {
144
+ try {
145
+ const data = typeof event.data === "string" ? event.data : event.data.toString();
146
+ const msg = JSON.parse(data);
147
+ this.handleIncoming(msg);
148
+ }
149
+ catch (_) { }
150
+ };
151
+ });
152
+ }
153
+ handleIncoming(msg) {
154
+ // Resposta a requisição enviada
155
+ if (msg.id !== undefined && this.pendingCallbacks.has(msg.id)) {
156
+ const cb = this.pendingCallbacks.get(msg.id);
157
+ this.pendingCallbacks.delete(msg.id);
158
+ if (msg.error) {
159
+ const err = new Error(msg.error.message);
160
+ err.code = msg.error.code;
161
+ err.data = msg.error.data;
162
+ throw err;
163
+ }
164
+ cb(msg.result);
165
+ return;
166
+ }
167
+ // Notificação de evento
168
+ if (msg.method) {
169
+ const p = msg.params || {};
170
+ switch (msg.method) {
171
+ case "agent.thinking":
172
+ this.emit("thinking", p.delta);
173
+ break;
174
+ case "agent.text":
175
+ this.emit("text", p.delta);
176
+ break;
177
+ case "agent.tool_call":
178
+ this.emit("tool_call", p);
179
+ break;
180
+ case "agent.tool_result":
181
+ this.emit("tool_result", p);
182
+ break;
183
+ case "agent.permission_request": {
184
+ const permReq = {
185
+ ...p,
186
+ allow: async () => this.respondPermission(p.requestId, true),
187
+ deny: async (reason) => this.respondPermission(p.requestId, false, reason),
188
+ };
189
+ this.emit("permission", permReq);
190
+ break;
191
+ }
192
+ case "agent.complete":
193
+ this.emit("complete", p.reason);
194
+ break;
195
+ case "agent.error":
196
+ this.emit("error", p);
197
+ break;
198
+ }
199
+ }
200
+ }
201
+ sendRPC(method, params) {
202
+ return new Promise((resolve, reject) => {
203
+ const id = this.reqId++;
204
+ this.pendingCallbacks.set(id, resolve);
205
+ const payload = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
206
+ if (this.config.transport === "stdio" && this.proc?.stdin) {
207
+ this.proc.stdin.write(payload);
208
+ }
209
+ else if (this.ws) {
210
+ this.ws.send(payload);
211
+ }
212
+ else {
213
+ this.pendingCallbacks.delete(id);
214
+ reject(new Error("Nenhum transporte ativo configurado"));
215
+ }
216
+ });
217
+ }
218
+ }
219
+ exports.Openheinerss = Openheinerss;
@@ -0,0 +1,22 @@
1
+ import { Openheinerss, type ClientConfig } from "./index.js";
2
+ import type { PermissionRequest } from "./types.js";
3
+ export interface ChatMessage {
4
+ id: string;
5
+ role: "user" | "assistant" | "system";
6
+ text: string;
7
+ timestamp: string;
8
+ }
9
+ export interface UseOpenheinerssOptions extends ClientConfig {
10
+ autoConnect?: boolean;
11
+ }
12
+ export declare function useOpenheinerss(options?: UseOpenheinerssOptions): {
13
+ messages: ChatMessage[];
14
+ isThinking: boolean;
15
+ thinkingText: string;
16
+ permissionRequest: PermissionRequest | null;
17
+ status: "idle" | "running" | "waiting_permission";
18
+ prompt: (text: string) => Promise<void>;
19
+ respondPermission: (requestId: string, allow: boolean) => Promise<void>;
20
+ abort: () => Promise<void>;
21
+ client: Openheinerss | null;
22
+ };
package/dist/react.js ADDED
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useOpenheinerss = useOpenheinerss;
4
+ const react_1 = require("react");
5
+ const index_js_1 = require("./index.js");
6
+ function useOpenheinerss(options = {}) {
7
+ const [messages, setMessages] = (0, react_1.useState)([]);
8
+ const [isThinking, setIsThinking] = (0, react_1.useState)(false);
9
+ const [thinkingText, setThinkingText] = (0, react_1.useState)("");
10
+ const [permissionRequest, setPermissionRequest] = (0, react_1.useState)(null);
11
+ const [status, setStatus] = (0, react_1.useState)("idle");
12
+ const clientRef = (0, react_1.useRef)(null);
13
+ (0, react_1.useEffect)(() => {
14
+ const client = new index_js_1.Openheinerss({
15
+ transport: "websocket",
16
+ wsEndpoint: options.wsEndpoint || "ws://127.0.0.1:4799",
17
+ options: options.options,
18
+ ...options,
19
+ });
20
+ clientRef.current = client;
21
+ client.on("thinking", (delta) => {
22
+ setIsThinking(true);
23
+ setThinkingText((prev) => prev + delta);
24
+ });
25
+ client.on("text", (delta) => {
26
+ setIsThinking(false);
27
+ setMessages((prev) => {
28
+ const last = prev[prev.length - 1];
29
+ if (last && last.role === "assistant") {
30
+ return [
31
+ ...prev.slice(0, -1),
32
+ { ...last, text: last.text + delta },
33
+ ];
34
+ }
35
+ return [
36
+ ...prev,
37
+ {
38
+ id: Math.random().toString(36).substring(2, 9),
39
+ role: "assistant",
40
+ text: delta,
41
+ timestamp: new Date().toISOString(),
42
+ },
43
+ ];
44
+ });
45
+ });
46
+ client.on("permission", (req) => {
47
+ setStatus("waiting_permission");
48
+ setPermissionRequest(req);
49
+ });
50
+ client.on("complete", () => {
51
+ setIsThinking(false);
52
+ setThinkingText("");
53
+ setStatus("idle");
54
+ });
55
+ client.on("error", (err) => {
56
+ setIsThinking(false);
57
+ setStatus("idle");
58
+ setMessages((prev) => [
59
+ ...prev,
60
+ {
61
+ id: Math.random().toString(36).substring(2, 9),
62
+ role: "system",
63
+ text: `Erro: ${err.message}`,
64
+ timestamp: new Date().toISOString(),
65
+ },
66
+ ]);
67
+ });
68
+ return () => {
69
+ client.close();
70
+ };
71
+ }, [options.wsEndpoint]);
72
+ const prompt = (0, react_1.useCallback)(async (text) => {
73
+ if (!clientRef.current)
74
+ return;
75
+ setStatus("running");
76
+ setMessages((prev) => [
77
+ ...prev,
78
+ {
79
+ id: Math.random().toString(36).substring(2, 9),
80
+ role: "user",
81
+ text,
82
+ timestamp: new Date().toISOString(),
83
+ },
84
+ ]);
85
+ await clientRef.current.prompt(text);
86
+ }, []);
87
+ const respondPermission = (0, react_1.useCallback)(async (requestId, allow) => {
88
+ if (!clientRef.current)
89
+ return;
90
+ await clientRef.current.respondPermission(requestId, allow);
91
+ setPermissionRequest(null);
92
+ setStatus("running");
93
+ }, []);
94
+ const abort = (0, react_1.useCallback)(async () => {
95
+ if (!clientRef.current)
96
+ return;
97
+ await clientRef.current.abort();
98
+ setIsThinking(false);
99
+ setStatus("idle");
100
+ }, []);
101
+ return {
102
+ messages,
103
+ isThinking,
104
+ thinkingText,
105
+ permissionRequest,
106
+ status,
107
+ prompt,
108
+ respondPermission,
109
+ abort,
110
+ client: clientRef.current,
111
+ };
112
+ }
@@ -0,0 +1,44 @@
1
+ export type HarnessType = "mock" | "claude-code" | "opencode" | string;
2
+ export type HarnessMode = "sdk" | "cli" | "api" | "mock";
3
+ export interface SessionOptions {
4
+ harness?: HarnessType;
5
+ mode?: HarnessMode;
6
+ cwd?: string;
7
+ provider?: string;
8
+ model?: string;
9
+ permissionMode?: "ask" | "always_allow" | "plan";
10
+ systemPrompt?: string;
11
+ }
12
+ export interface PermissionRequest {
13
+ sessionId: string;
14
+ requestId: string;
15
+ tool: string;
16
+ command?: string;
17
+ risk?: string;
18
+ allow: () => Promise<void>;
19
+ deny: (reason?: string) => Promise<void>;
20
+ }
21
+ export interface ToolCall {
22
+ sessionId: string;
23
+ callId: string;
24
+ tool: string;
25
+ input: Record<string, unknown>;
26
+ }
27
+ export interface ToolResult {
28
+ sessionId: string;
29
+ callId: string;
30
+ status: "success" | "error";
31
+ output: string;
32
+ }
33
+ export interface OpenheinerssEvents {
34
+ thinking: (delta: string) => void;
35
+ text: (delta: string) => void;
36
+ tool_call: (call: ToolCall) => void;
37
+ tool_result: (result: ToolResult) => void;
38
+ permission: (req: PermissionRequest) => void;
39
+ complete: (reason: string) => void;
40
+ error: (err: {
41
+ message: string;
42
+ code?: number;
43
+ }) => void;
44
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@openheinerss/sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "SDK oficial em TypeScript/JavaScript para o maestro Openheinerss",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/crom-org/openheinerss.git",
17
+ "directory": "sdk/typescript"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc"
21
+ },
22
+ "keywords": [
23
+ "ai",
24
+ "agents",
25
+ "claude-code",
26
+ "opencode",
27
+ "orchestration",
28
+ "json-rpc",
29
+ "openheinerss"
30
+ ],
31
+ "author": "crom-org",
32
+ "license": "MIT",
33
+ "peerDependencies": {
34
+ "react": "^18.0.0 || ^19.0.0"
35
+ },
36
+ "peerDependenciesMeta": {
37
+ "react": {
38
+ "optional": true
39
+ }
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.12.7",
43
+ "@types/react": "^18.3.0",
44
+ "react": "^18.3.0",
45
+ "typescript": "^5.4.5"
46
+ }
47
+ }