@stevezhou/sisu 0.1.11 → 0.2.1

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.
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toProviderMessages = toProviderMessages;
4
+ exports.completeUrl = completeUrl;
5
+ exports.openaiCompatUrl = openaiCompatUrl;
6
+ exports.buildCompleteRequest = buildCompleteRequest;
7
+ exports.isServerSideAgentPayload = isServerSideAgentPayload;
8
+ exports.parseCompleteSse = parseCompleteSse;
9
+ exports.parseOpenAiChatCompletion = parseOpenAiChatCompletion;
10
+ exports.createSisuCloudModel = createSisuCloudModel;
11
+ const client_1 = require("../client");
12
+ const http_1 = require("../http");
13
+ const sse_1 = require("../sse");
14
+ const suite_1 = require("./suite");
15
+ /** OpenAI/Poe wire: assistant.tool_calls is {id,type,function:{name,arguments:string}}. */
16
+ function toProviderMessages(messages) {
17
+ return messages.map((row) => {
18
+ const out = { role: row.role, content: row.content };
19
+ if (row.tool_call_id)
20
+ out.tool_call_id = row.tool_call_id;
21
+ if (row.name)
22
+ out.name = row.name;
23
+ if (row.tool_calls?.length) {
24
+ out.tool_calls = row.tool_calls.map((call) => ({
25
+ id: call.id,
26
+ type: 'function',
27
+ function: {
28
+ name: call.name,
29
+ arguments: JSON.stringify(call.arguments || {}),
30
+ },
31
+ }));
32
+ }
33
+ return out;
34
+ });
35
+ }
36
+ function completeUrl(apiBase) {
37
+ return `${apiBase.replace(/\/+$/, '')}${suite_1.COMPLETE_PATH}`;
38
+ }
39
+ function openaiCompatUrl(apiBase) {
40
+ return `${apiBase.replace(/\/+$/, '')}${suite_1.OPENAI_COMPAT_PATH}`;
41
+ }
42
+ function buildCompleteRequest(request, options = {}) {
43
+ const stamp = (0, client_1.clientStamp)(options.client || 'cli');
44
+ return {
45
+ model: request.model,
46
+ messages: toProviderMessages(request.messages),
47
+ tools: request.tools,
48
+ stream: true,
49
+ client: stamp.client,
50
+ client_version: stamp.client_version,
51
+ client_request_id: stamp.client_request_id,
52
+ };
53
+ }
54
+ function isServerSideAgentPayload(body) {
55
+ if (!body || typeof body !== 'object')
56
+ return false;
57
+ const row = body;
58
+ return row.task_category === 'coding' && typeof row.message === 'string' && !Array.isArray(row.messages);
59
+ }
60
+ function asToolCall(raw, index) {
61
+ if (!raw || typeof raw !== 'object')
62
+ return null;
63
+ const row = raw;
64
+ const fn = row.function && typeof row.function === 'object' ? row.function : row;
65
+ const name = String(fn.name || row.name || '');
66
+ if (!name)
67
+ return null;
68
+ let args = {};
69
+ const rawArgs = fn.arguments ?? row.arguments ?? row.input;
70
+ if (typeof rawArgs === 'string') {
71
+ try {
72
+ args = JSON.parse(rawArgs);
73
+ }
74
+ catch {
75
+ args = { raw: rawArgs };
76
+ }
77
+ }
78
+ else if (rawArgs && typeof rawArgs === 'object') {
79
+ args = rawArgs;
80
+ }
81
+ return { id: String(row.id || `call_${index}`), name, arguments: args };
82
+ }
83
+ function parseCompleteSse(buffer) {
84
+ const parsed = (0, sse_1.consumeSse)(buffer.endsWith('\n\n') ? buffer : `${buffer}\n\n`);
85
+ let text = '';
86
+ const tool_calls = [];
87
+ for (const event of parsed.events) {
88
+ if (event.type === 'error') {
89
+ throw new Error(typeof event.data === 'string' ? event.data : 'stream error');
90
+ }
91
+ if (event.name === 'tool_call') {
92
+ const mapped = asToolCall(event.data, tool_calls.length);
93
+ if (mapped)
94
+ tool_calls.push(mapped);
95
+ continue;
96
+ }
97
+ if (event.name === 'delta' || event.type === 'text' || event.name === 'text') {
98
+ const chunk = (0, sse_1.sseEventText)(event);
99
+ if (chunk)
100
+ text += chunk;
101
+ }
102
+ if (event.data && typeof event.data === 'object') {
103
+ const row = event.data;
104
+ if (Array.isArray(row.tool_calls)) {
105
+ row.tool_calls.forEach((item, index) => {
106
+ const mapped = asToolCall(item, tool_calls.length + index);
107
+ if (mapped)
108
+ tool_calls.push(mapped);
109
+ });
110
+ }
111
+ if (typeof row.content === 'string')
112
+ text += row.content;
113
+ }
114
+ }
115
+ return { text, tool_calls };
116
+ }
117
+ function parseOpenAiChatCompletion(body) {
118
+ const row = body && typeof body === 'object' ? body : {};
119
+ const choices = Array.isArray(row.choices) ? row.choices : [];
120
+ const first = choices[0] && typeof choices[0] === 'object' ? choices[0] : {};
121
+ const message = first.message && typeof first.message === 'object' ? first.message : first;
122
+ const text = typeof message.content === 'string' ? message.content : '';
123
+ const rawCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
124
+ const tool_calls = rawCalls
125
+ .map((item, index) => asToolCall(item, index))
126
+ .filter((item) => Boolean(item));
127
+ return { text, tool_calls };
128
+ }
129
+ function createSisuCloudModel(http, options) {
130
+ return {
131
+ async complete(request) {
132
+ const payload = buildCompleteRequest(request, { client: options.client });
133
+ if (isServerSideAgentPayload(payload)) {
134
+ throw new Error('refusing server-side /api/chat/send agent payload');
135
+ }
136
+ const sent = await http(completeUrl(options.apiBase), {
137
+ method: 'POST',
138
+ headers: (0, http_1.authHeaders)(options.token),
139
+ body: JSON.stringify(payload),
140
+ });
141
+ if (!sent.ok) {
142
+ const body = await sent.json().catch(() => ({}));
143
+ throw new Error((0, http_1.errorDetail)(body, `complete failed (${sent.status})`));
144
+ }
145
+ const stream = sent.stream;
146
+ if (stream) {
147
+ let buffer = '';
148
+ for await (const chunk of stream())
149
+ buffer += chunk;
150
+ return parseCompleteSse(buffer);
151
+ }
152
+ const raw = await sent.text();
153
+ if (raw.trim().startsWith('{')) {
154
+ try {
155
+ return parseOpenAiChatCompletion(JSON.parse(raw));
156
+ }
157
+ catch {
158
+ // fall through to SSE
159
+ }
160
+ }
161
+ return parseCompleteSse(raw);
162
+ },
163
+ };
164
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.launchGrokBuildHeadless = exports.findGrokBuildBinary = exports.execLocalTurn = exports.createLocalRuntimeTransport = exports.resolveWorkspaceRoot = exports.localToolDefinitions = exports.dispatchLocalTool = exports.runLocalTurn = exports.createScriptedModel = exports.createLaunchStubModel = exports.collectLocalTurn = exports.toProviderMessages = exports.parseOpenAiChatCompletion = exports.parseCompleteSse = exports.isServerSideAgentPayload = exports.createSisuCloudModel = exports.completeUrl = exports.buildCompleteRequest = exports.PRODUCT_NAME = exports.PRODUCT_BIN = exports.grokBuildSuitePresent = exports.grokBuildRoot = exports.grokBuildPath = exports.assertGrokBuildSuite = void 0;
4
+ var suite_1 = require("./suite");
5
+ Object.defineProperty(exports, "assertGrokBuildSuite", { enumerable: true, get: function () { return suite_1.assertGrokBuildSuite; } });
6
+ Object.defineProperty(exports, "grokBuildPath", { enumerable: true, get: function () { return suite_1.grokBuildPath; } });
7
+ Object.defineProperty(exports, "grokBuildRoot", { enumerable: true, get: function () { return suite_1.grokBuildRoot; } });
8
+ Object.defineProperty(exports, "grokBuildSuitePresent", { enumerable: true, get: function () { return suite_1.grokBuildSuitePresent; } });
9
+ Object.defineProperty(exports, "PRODUCT_BIN", { enumerable: true, get: function () { return suite_1.PRODUCT_BIN; } });
10
+ Object.defineProperty(exports, "PRODUCT_NAME", { enumerable: true, get: function () { return suite_1.PRODUCT_NAME; } });
11
+ var adapter_1 = require("./adapter");
12
+ Object.defineProperty(exports, "buildCompleteRequest", { enumerable: true, get: function () { return adapter_1.buildCompleteRequest; } });
13
+ Object.defineProperty(exports, "completeUrl", { enumerable: true, get: function () { return adapter_1.completeUrl; } });
14
+ Object.defineProperty(exports, "createSisuCloudModel", { enumerable: true, get: function () { return adapter_1.createSisuCloudModel; } });
15
+ Object.defineProperty(exports, "isServerSideAgentPayload", { enumerable: true, get: function () { return adapter_1.isServerSideAgentPayload; } });
16
+ Object.defineProperty(exports, "parseCompleteSse", { enumerable: true, get: function () { return adapter_1.parseCompleteSse; } });
17
+ Object.defineProperty(exports, "parseOpenAiChatCompletion", { enumerable: true, get: function () { return adapter_1.parseOpenAiChatCompletion; } });
18
+ Object.defineProperty(exports, "toProviderMessages", { enumerable: true, get: function () { return adapter_1.toProviderMessages; } });
19
+ var loop_1 = require("./loop");
20
+ Object.defineProperty(exports, "collectLocalTurn", { enumerable: true, get: function () { return loop_1.collectLocalTurn; } });
21
+ Object.defineProperty(exports, "createLaunchStubModel", { enumerable: true, get: function () { return loop_1.createLaunchStubModel; } });
22
+ Object.defineProperty(exports, "createScriptedModel", { enumerable: true, get: function () { return loop_1.createScriptedModel; } });
23
+ Object.defineProperty(exports, "runLocalTurn", { enumerable: true, get: function () { return loop_1.runLocalTurn; } });
24
+ var tools_1 = require("./tools");
25
+ Object.defineProperty(exports, "dispatchLocalTool", { enumerable: true, get: function () { return tools_1.dispatchLocalTool; } });
26
+ Object.defineProperty(exports, "localToolDefinitions", { enumerable: true, get: function () { return tools_1.localToolDefinitions; } });
27
+ Object.defineProperty(exports, "resolveWorkspaceRoot", { enumerable: true, get: function () { return tools_1.resolveWorkspaceRoot; } });
28
+ var transport_1 = require("./transport");
29
+ Object.defineProperty(exports, "createLocalRuntimeTransport", { enumerable: true, get: function () { return transport_1.createLocalRuntimeTransport; } });
30
+ Object.defineProperty(exports, "execLocalTurn", { enumerable: true, get: function () { return transport_1.execLocalTurn; } });
31
+ var launch_1 = require("./launch");
32
+ Object.defineProperty(exports, "findGrokBuildBinary", { enumerable: true, get: function () { return launch_1.findGrokBuildBinary; } });
33
+ Object.defineProperty(exports, "launchGrokBuildHeadless", { enumerable: true, get: function () { return launch_1.launchGrokBuildHeadless; } });
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.grokBuildBinaryCandidates = grokBuildBinaryCandidates;
7
+ exports.findGrokBuildBinary = findGrokBuildBinary;
8
+ exports.sisuRuntimeApiBase = sisuRuntimeApiBase;
9
+ exports.writeSisuGrokConfig = writeSisuGrokConfig;
10
+ exports.sisuGrokBuildEnv = sisuGrokBuildEnv;
11
+ exports.launchGrokBuildHeadless = launchGrokBuildHeadless;
12
+ const child_process_1 = require("child_process");
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const store_1 = require("../store");
16
+ const suite_1 = require("./suite");
17
+ const adapter_1 = require("./adapter");
18
+ function grokBuildBinaryCandidates() {
19
+ const env = (process.env.SISU_GROK_BIN || '').trim();
20
+ const root = (0, suite_1.grokBuildRoot)();
21
+ const packaged = path_1.default.resolve(__dirname, '..', 'bin', 'xai-grok-pager');
22
+ const npmInstalled = path_1.default.join((0, store_1.getSisuHome)(), 'bin', process.platform === 'win32' ? 'xai-grok-pager.exe' : 'xai-grok-pager');
23
+ return [
24
+ env,
25
+ npmInstalled,
26
+ packaged,
27
+ path_1.default.join(root, 'target', 'release', 'xai-grok-pager'),
28
+ path_1.default.join(root, 'target', 'debug', 'xai-grok-pager'),
29
+ path_1.default.join(root, 'target', 'release', 'sisu-agent'),
30
+ ].filter(Boolean);
31
+ }
32
+ function findGrokBuildBinary() {
33
+ for (const candidate of grokBuildBinaryCandidates()) {
34
+ if (candidate && fs_1.default.existsSync(candidate) && fs_1.default.statSync(candidate).isFile())
35
+ return candidate;
36
+ }
37
+ return null;
38
+ }
39
+ function sisuRuntimeApiBase(apiBase) {
40
+ return (0, adapter_1.openaiCompatUrl)(apiBase).replace(/\/chat\/completions$/, '');
41
+ }
42
+ function writeSisuGrokConfig() {
43
+ const auth = (0, store_1.readAuth)();
44
+ const home = (0, store_1.getSisuHome)();
45
+ fs_1.default.mkdirSync(home, { recursive: true, mode: 0o700 });
46
+ const file = path_1.default.join(home, 'config.toml');
47
+ const runtimeBase = sisuRuntimeApiBase(auth?.api_base || process.env.SISU_API_BASE || 'https://www.sisu.chat');
48
+ const body = [
49
+ '# sisu-managed grok-build config — SiSu auth + models + quota',
50
+ '[endpoints]',
51
+ `xai_api_base_url = "${runtimeBase}"`,
52
+ '',
53
+ ].join('\n');
54
+ const existing = fs_1.default.existsSync(file) ? fs_1.default.readFileSync(file, 'utf8') : '';
55
+ if (!existing || existing.includes('sisu-managed grok-build')) {
56
+ fs_1.default.writeFileSync(file, `${body}\n`, { encoding: 'utf8', mode: 0o600 });
57
+ }
58
+ return file;
59
+ }
60
+ function sisuGrokBuildEnv() {
61
+ const auth = (0, store_1.readAuth)();
62
+ const home = (0, store_1.getSisuHome)();
63
+ const runtimeBase = auth ? sisuRuntimeApiBase(auth.api_base) : '';
64
+ return {
65
+ ...process.env,
66
+ GROK_HOME: process.env.GROK_HOME || home,
67
+ SISU_HOME: home,
68
+ GROK_TELEMETRY_ENABLED: process.env.GROK_TELEMETRY_ENABLED || '0',
69
+ XAI_API_KEY: process.env.XAI_API_KEY || auth?.token || '',
70
+ SISU_API_BASE: auth?.api_base || process.env.SISU_API_BASE || 'https://www.sisu.chat',
71
+ ...(runtimeBase
72
+ ? {
73
+ GROK_XAI_API_BASE_URL: runtimeBase,
74
+ XAI_API_BASE_URL: runtimeBase,
75
+ }
76
+ : {}),
77
+ };
78
+ }
79
+ function launchGrokBuildHeadless(prompt, cwd) {
80
+ const binary = findGrokBuildBinary();
81
+ if (!binary) {
82
+ return { status: 127, stdout: '', stderr: 'grok-build binary not built', binary: null };
83
+ }
84
+ const result = (0, child_process_1.spawnSync)(binary, ['-p', prompt], {
85
+ cwd,
86
+ encoding: 'utf8',
87
+ env: sisuGrokBuildEnv(),
88
+ timeout: 30_000,
89
+ });
90
+ return {
91
+ status: result.status ?? 1,
92
+ stdout: result.stdout || '',
93
+ stderr: result.stderr || result.error?.message || '',
94
+ binary,
95
+ };
96
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runLocalTurn = runLocalTurn;
4
+ exports.collectLocalTurn = collectLocalTurn;
5
+ exports.createLaunchStubModel = createLaunchStubModel;
6
+ exports.createScriptedModel = createScriptedModel;
7
+ const crypto_1 = require("crypto");
8
+ const tools_1 = require("./tools");
9
+ const DEFAULT_MAX_ROUNDS = 8;
10
+ async function* runLocalTurn(options) {
11
+ const prompt = options.prompt.trim();
12
+ if (!prompt)
13
+ throw new Error('prompt is required');
14
+ const cwd = (0, tools_1.resolveWorkspaceRoot)(options.cwd);
15
+ const conversationId = options.conversationId || (0, crypto_1.randomUUID)();
16
+ yield { type: 'bound', text: conversationId };
17
+ const messages = [...(options.messages || []), { role: 'user', content: prompt }];
18
+ const tools = (0, tools_1.localToolDefinitions)();
19
+ const toolResults = [];
20
+ const requests = [];
21
+ let text = '';
22
+ const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
23
+ for (let round = 0; round < maxRounds; round += 1) {
24
+ const request = { model: options.model, messages: messages.map((row) => ({ ...row })), tools };
25
+ requests.push(request);
26
+ const completion = await options.client.complete(request);
27
+ if (completion.text) {
28
+ text += completion.text;
29
+ yield { type: 'text', text: completion.text };
30
+ }
31
+ if (!completion.tool_calls.length) {
32
+ return { conversationId, text, toolResults, requests };
33
+ }
34
+ messages.push({
35
+ role: 'assistant',
36
+ content: completion.text || '',
37
+ tool_calls: completion.tool_calls,
38
+ });
39
+ for (const call of completion.tool_calls) {
40
+ const result = (0, tools_1.dispatchLocalTool)(cwd, {
41
+ ...call,
42
+ id: call.id || (0, crypto_1.randomUUID)(),
43
+ arguments: call.arguments || {},
44
+ });
45
+ toolResults.push(result);
46
+ yield { type: 'tool', text: `${result.name} · ${result.ok ? 'ok' : 'error'} · ${result.content}` };
47
+ messages.push({
48
+ role: 'tool',
49
+ name: result.name,
50
+ tool_call_id: result.id,
51
+ content: result.content,
52
+ });
53
+ }
54
+ }
55
+ yield { type: 'status', text: `stopped after ${maxRounds} tool rounds` };
56
+ return { conversationId, text, toolResults, requests };
57
+ }
58
+ async function collectLocalTurn(options) {
59
+ const gen = runLocalTurn(options);
60
+ let step = await gen.next();
61
+ while (!step.done)
62
+ step = await gen.next();
63
+ return step.value;
64
+ }
65
+ function createLaunchStubModel() {
66
+ let step = 0;
67
+ return {
68
+ async complete(request) {
69
+ step += 1;
70
+ if (step === 1) {
71
+ return {
72
+ text: '',
73
+ tool_calls: [{ id: 'stub-read', name: 'read_file', arguments: { target_file: 'hello.txt' } }],
74
+ };
75
+ }
76
+ const lastTool = [...request.messages].reverse().find((row) => row.role === 'tool');
77
+ return { text: `local tool result:\n${lastTool?.content || ''}`, tool_calls: [] };
78
+ },
79
+ };
80
+ }
81
+ function createScriptedModel(script) {
82
+ const remaining = [...script];
83
+ return {
84
+ async complete() {
85
+ const next = remaining.shift();
86
+ if (!next)
87
+ return { text: '', tool_calls: [] };
88
+ return { text: next.text || '', tool_calls: next.tool_calls || [] };
89
+ },
90
+ };
91
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchModelCatalog = fetchModelCatalog;
4
+ exports.resolveCatalogModel = resolveCatalogModel;
5
+ exports.resolveRuntimeModel = resolveRuntimeModel;
6
+ const http_1 = require("../http");
7
+ const store_1 = require("../store");
8
+ function normalizeModelKey(value) {
9
+ return value.toLowerCase().replace(/[-_.\s]/g, '');
10
+ }
11
+ async function fetchModelCatalog(http = http_1.defaultHttp) {
12
+ const auth = (0, store_1.requireAuth)();
13
+ const response = await http(`${auth.api_base}/api/chat/models`, { headers: (0, http_1.authHeaders)(auth.token) });
14
+ const body = await response.json().catch(() => ({}));
15
+ if (!response.ok)
16
+ throw new Error((0, http_1.errorDetail)(body, `models failed (${response.status})`));
17
+ const rows = Array.isArray(body?.models) ? body.models : [];
18
+ const models = rows
19
+ .map((row) => {
20
+ const name = String(row?.name || '').trim();
21
+ if (!name)
22
+ return null;
23
+ return { name, label: String(row.display_name || row.label || name) };
24
+ })
25
+ .filter((row) => Boolean(row));
26
+ return { models, defaultModel: String(body?.default_model || '') };
27
+ }
28
+ function resolveCatalogModel(query, models) {
29
+ const needle = normalizeModelKey(query);
30
+ if (!needle)
31
+ return undefined;
32
+ return (models.find((row) => normalizeModelKey(row.name) === needle) ||
33
+ models.find((row) => normalizeModelKey(row.label) === needle) ||
34
+ models.find((row) => normalizeModelKey(row.name).includes(needle) || normalizeModelKey(row.label).includes(needle)));
35
+ }
36
+ async function resolveRuntimeModel(http, options = {}) {
37
+ if (options.stub)
38
+ return (options.explicit || '').trim() || 'stub';
39
+ const wanted = (options.explicit || '').trim();
40
+ const { models, defaultModel } = await fetchModelCatalog(http);
41
+ if (wanted) {
42
+ const match = resolveCatalogModel(wanted, models);
43
+ if (!match)
44
+ throw new Error(`unknown model ${wanted}`);
45
+ (0, store_1.writeSession)({ ...(0, store_1.readSession)(), last_model: match.name });
46
+ return match.name;
47
+ }
48
+ const last = ((0, store_1.readSession)().last_model || '').trim();
49
+ if (last && models.some((row) => row.name === last))
50
+ return last;
51
+ const name = defaultModel || models[0]?.name || '';
52
+ if (!name)
53
+ throw new Error('no SiSu model available');
54
+ (0, store_1.writeSession)({ ...(0, store_1.readSession)(), last_model: name });
55
+ return name;
56
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createLocalSession = createLocalSession;
7
+ exports.loadLocalSession = loadLocalSession;
8
+ exports.saveLocalSession = saveLocalSession;
9
+ exports.listLocalSessions = listLocalSessions;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const crypto_1 = require("crypto");
13
+ const store_1 = require("../store");
14
+ function sessionsDir() {
15
+ return path_1.default.join((0, store_1.getSisuHome)(), 'sessions');
16
+ }
17
+ function sessionFile(id) {
18
+ return path_1.default.join(sessionsDir(), `${id}.json`);
19
+ }
20
+ function createLocalSession(title, cwd, model) {
21
+ const session = {
22
+ id: (0, crypto_1.randomUUID)(),
23
+ title: title.slice(0, 80) || 'session',
24
+ cwd,
25
+ model,
26
+ messages: [],
27
+ updatedAt: new Date().toISOString(),
28
+ };
29
+ saveLocalSession(session);
30
+ return session;
31
+ }
32
+ function loadLocalSession(id) {
33
+ try {
34
+ return JSON.parse(fs_1.default.readFileSync(sessionFile(id), 'utf8'));
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function saveLocalSession(session) {
41
+ fs_1.default.mkdirSync(sessionsDir(), { recursive: true, mode: 0o700 });
42
+ const file = sessionFile(session.id);
43
+ fs_1.default.writeFileSync(file, JSON.stringify({ ...session, updatedAt: new Date().toISOString() }, null, 2) + '\n', {
44
+ encoding: 'utf8',
45
+ mode: 0o600,
46
+ });
47
+ }
48
+ function listLocalSessions() {
49
+ const dir = sessionsDir();
50
+ if (!fs_1.default.existsSync(dir))
51
+ return [];
52
+ return fs_1.default
53
+ .readdirSync(dir)
54
+ .filter((name) => name.endsWith('.json'))
55
+ .map((name) => {
56
+ try {
57
+ return JSON.parse(fs_1.default.readFileSync(path_1.default.join(dir, name), 'utf8'));
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ })
63
+ .filter((row) => Boolean(row))
64
+ .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
65
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OPENAI_COMPAT_PATH = exports.COMPLETE_PATH = exports.PRODUCT_BIN = exports.PRODUCT_NAME = exports.GROK_BUILD_SURFACE = void 0;
7
+ exports.grokBuildRoot = grokBuildRoot;
8
+ exports.grokBuildPath = grokBuildPath;
9
+ exports.grokBuildSuitePresent = grokBuildSuitePresent;
10
+ exports.assertGrokBuildSuite = assertGrokBuildSuite;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ /** Absolute path to the vendored grok-build first-party tree. */
14
+ function grokBuildRoot() {
15
+ return path_1.default.resolve(__dirname, '..', '..', 'vendor', 'grok-build');
16
+ }
17
+ exports.GROK_BUILD_SURFACE = {
18
+ agent: 'crates/codegen/xai-grok-agent',
19
+ tools: 'crates/codegen/xai-grok-tools',
20
+ pager: 'crates/codegen/xai-grok-pager',
21
+ hooks: 'crates/codegen/xai-grok-hooks',
22
+ mcp: 'crates/codegen/xai-grok-mcp',
23
+ plugins: 'crates/codegen/xai-grok-plugin-marketplace',
24
+ subagents: 'crates/codegen/xai-grok-subagent-resolution',
25
+ skills: 'crates/codegen/xai-grok-tools/src/implementations/skills',
26
+ };
27
+ function grokBuildPath(surface) {
28
+ const root = grokBuildRoot();
29
+ if (surface === 'license')
30
+ return path_1.default.join(root, 'LICENSE');
31
+ if (surface === 'notice')
32
+ return path_1.default.join(root, 'NOTICE');
33
+ if (surface === 'thirdParty')
34
+ return path_1.default.join(root, 'THIRD-PARTY-NOTICES');
35
+ return path_1.default.join(root, exports.GROK_BUILD_SURFACE[surface]);
36
+ }
37
+ function grokBuildSuitePresent() {
38
+ const keys = [
39
+ 'agent',
40
+ 'tools',
41
+ 'pager',
42
+ 'hooks',
43
+ 'mcp',
44
+ 'plugins',
45
+ 'subagents',
46
+ 'skills',
47
+ 'license',
48
+ 'notice',
49
+ ];
50
+ return keys.map((surface) => {
51
+ const file = grokBuildPath(surface);
52
+ return { surface, path: file, ok: fs_1.default.existsSync(file) };
53
+ });
54
+ }
55
+ function assertGrokBuildSuite() {
56
+ const missing = grokBuildSuitePresent().filter((row) => !row.ok);
57
+ if (missing.length) {
58
+ throw new Error(`grok-build suite missing: ${missing.map((row) => row.surface).join(', ')}`);
59
+ }
60
+ }
61
+ exports.PRODUCT_NAME = 'SiSu';
62
+ exports.PRODUCT_BIN = 'sisu';
63
+ exports.COMPLETE_PATH = '/api/runtime/complete';
64
+ exports.OPENAI_COMPAT_PATH = '/api/runtime/v1/chat/completions';