@imricci/zaker 0.1.1 → 0.1.3
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/dist/commands/app-server.d.ts +67 -0
- package/dist/commands/app-server.js +601 -0
- package/dist/commands/app-server.js.map +1 -0
- package/dist/commands/audit.js +2 -1
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.d.ts +3 -0
- package/dist/commands/build.js +22 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/confirm.d.ts +0 -2
- package/dist/commands/confirm.js +2 -16
- package/dist/commands/confirm.js.map +1 -1
- package/dist/commands/dialog-handlers/auth.d.ts +3 -0
- package/dist/commands/dialog-handlers/auth.js +174 -0
- package/dist/commands/dialog-handlers/auth.js.map +1 -0
- package/dist/commands/dialog-handlers/basic.d.ts +7 -0
- package/dist/commands/dialog-handlers/basic.js +82 -0
- package/dist/commands/dialog-handlers/basic.js.map +1 -0
- package/dist/commands/dialog-handlers/bootstrap.d.ts +10 -0
- package/dist/commands/dialog-handlers/bootstrap.js +38 -0
- package/dist/commands/dialog-handlers/bootstrap.js.map +1 -0
- package/dist/commands/dialog-handlers/index.d.ts +2 -0
- package/dist/commands/dialog-handlers/index.js +6 -0
- package/dist/commands/dialog-handlers/index.js.map +1 -0
- package/dist/commands/dialog-handlers/message.d.ts +2 -0
- package/dist/commands/dialog-handlers/message.js +103 -0
- package/dist/commands/dialog-handlers/message.js.map +1 -0
- package/dist/commands/dialog-handlers/model.d.ts +2 -0
- package/dist/commands/dialog-handlers/model.js +168 -0
- package/dist/commands/dialog-handlers/model.js.map +1 -0
- package/dist/commands/dialog-handlers/new.d.ts +2 -0
- package/dist/commands/dialog-handlers/new.js +53 -0
- package/dist/commands/dialog-handlers/new.js.map +1 -0
- package/dist/commands/dialog-handlers/resume.d.ts +2 -0
- package/dist/commands/dialog-handlers/resume.js +25 -0
- package/dist/commands/dialog-handlers/resume.js.map +1 -0
- package/dist/commands/dialog-handlers/router.d.ts +11 -0
- package/dist/commands/dialog-handlers/router.js +112 -0
- package/dist/commands/dialog-handlers/router.js.map +1 -0
- package/dist/commands/dialog-handlers/run.d.ts +2 -0
- package/dist/commands/dialog-handlers/run.js +161 -0
- package/dist/commands/dialog-handlers/run.js.map +1 -0
- package/dist/commands/dialog-handlers/status.d.ts +2 -0
- package/dist/commands/dialog-handlers/status.js +13 -0
- package/dist/commands/dialog-handlers/status.js.map +1 -0
- package/dist/commands/dialog-handlers/types.d.ts +107 -0
- package/dist/commands/dialog-handlers/types.js +3 -0
- package/dist/commands/dialog-handlers/types.js.map +1 -0
- package/dist/commands/dialog.d.ts +92 -0
- package/dist/commands/dialog.js +1784 -236
- package/dist/commands/dialog.js.map +1 -1
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.js +6 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/plan.js +10 -6
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/run.js +8 -10
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/status.js +6 -12
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/tui-launcher.d.ts +1 -0
- package/dist/commands/tui-launcher.js +8 -0
- package/dist/commands/tui-launcher.js.map +1 -0
- package/dist/core/alignment-reply.d.ts +1 -0
- package/dist/core/alignment-reply.js +44 -0
- package/dist/core/alignment-reply.js.map +1 -0
- package/dist/core/checkpoint.js +3 -1
- package/dist/core/checkpoint.js.map +1 -1
- package/dist/core/planner.d.ts +16 -16
- package/dist/core/planner.js +3 -1
- package/dist/core/planner.js.map +1 -1
- package/dist/core/planning-prep.d.ts +12 -0
- package/dist/core/planning-prep.js +26 -0
- package/dist/core/planning-prep.js.map +1 -0
- package/dist/core/preflight.js +1 -2
- package/dist/core/preflight.js.map +1 -1
- package/dist/core/provider-onboarding.js +6 -11
- package/dist/core/provider-onboarding.js.map +1 -1
- package/dist/core/readonly-checkpoint.d.ts +2 -0
- package/dist/core/readonly-checkpoint.js +35 -0
- package/dist/core/readonly-checkpoint.js.map +1 -0
- package/dist/core/run-loop.js +3 -1
- package/dist/core/run-loop.js.map +1 -1
- package/dist/core/types.d.ts +20 -1
- package/dist/index.js +20 -6
- package/dist/index.js.map +1 -1
- package/dist/infra/artifact-schema.d.ts +25 -0
- package/dist/infra/artifact-schema.js +353 -0
- package/dist/infra/artifact-schema.js.map +1 -0
- package/dist/infra/config.d.ts +14 -1
- package/dist/infra/config.js +542 -22
- package/dist/infra/config.js.map +1 -1
- package/dist/infra/dependency-report.d.ts +5 -0
- package/dist/infra/dependency-report.js +22 -0
- package/dist/infra/dependency-report.js.map +1 -0
- package/dist/infra/dialog-session.d.ts +29 -0
- package/dist/infra/dialog-session.js +244 -0
- package/dist/infra/dialog-session.js.map +1 -0
- package/dist/infra/intent.js +63 -13
- package/dist/infra/intent.js.map +1 -1
- package/dist/infra/model-accounts.d.ts +22 -0
- package/dist/infra/model-accounts.js +172 -0
- package/dist/infra/model-accounts.js.map +1 -0
- package/dist/infra/model-catalog.d.ts +4 -1
- package/dist/infra/model-catalog.js +102 -27
- package/dist/infra/model-catalog.js.map +1 -1
- package/dist/infra/openai-codex-oauth.d.ts +18 -0
- package/dist/infra/openai-codex-oauth.js +267 -0
- package/dist/infra/openai-codex-oauth.js.map +1 -0
- package/dist/infra/provider-registry.d.ts +36 -0
- package/dist/infra/provider-registry.js +403 -0
- package/dist/infra/provider-registry.js.map +1 -0
- package/dist/infra/session-status.d.ts +6 -0
- package/dist/infra/session-status.js +34 -0
- package/dist/infra/session-status.js.map +1 -0
- package/dist/infra/tui-utils.d.ts +6 -0
- package/dist/infra/tui-utils.js +163 -0
- package/dist/infra/tui-utils.js.map +1 -0
- package/dist/infra/tui-view.d.ts +44 -0
- package/dist/infra/tui-view.js +314 -0
- package/dist/infra/tui-view.js.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { ConversationRuntime } from "../infra/dialog-session";
|
|
3
|
+
import { ModelProviderId } from "../infra/provider-registry";
|
|
4
|
+
import { loginOpenAICodexOAuth } from "../infra/openai-codex-oauth";
|
|
5
|
+
import { TaskBoardState } from "./dialog-handlers";
|
|
6
|
+
export declare const APP_SERVER_PROTOCOL_VERSION = "zaker.app/1";
|
|
7
|
+
export declare const APP_SERVER_METHODS: readonly ["initialize", "ping", "session.get", "command.execute", "menu.context", "oauth.start", "oauth.cancel", "shutdown"];
|
|
8
|
+
export declare const APP_SERVER_EVENTS: readonly ["session.update", "run.stage", "audit.result", "oauth.status"];
|
|
9
|
+
type JsonRpcId = string | number | null;
|
|
10
|
+
type AppServerEventName = (typeof APP_SERVER_EVENTS)[number];
|
|
11
|
+
interface JsonRpcRequest {
|
|
12
|
+
jsonrpc?: string;
|
|
13
|
+
id?: JsonRpcId;
|
|
14
|
+
method?: string;
|
|
15
|
+
params?: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface JsonRpcResult {
|
|
18
|
+
jsonrpc: "2.0";
|
|
19
|
+
id: JsonRpcId;
|
|
20
|
+
result: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface JsonRpcErrorResult {
|
|
23
|
+
jsonrpc: "2.0";
|
|
24
|
+
id: JsonRpcId;
|
|
25
|
+
error: {
|
|
26
|
+
code: number;
|
|
27
|
+
message: string;
|
|
28
|
+
data?: unknown;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export interface AppServerEvent {
|
|
32
|
+
event: AppServerEventName;
|
|
33
|
+
timestamp: string;
|
|
34
|
+
payload: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
type OAuthLoginAdapter = typeof loginOpenAICodexOAuth;
|
|
37
|
+
interface PendingOAuthRequest {
|
|
38
|
+
request_id: string;
|
|
39
|
+
provider: ModelProviderId;
|
|
40
|
+
started_at: string;
|
|
41
|
+
controller: AbortController;
|
|
42
|
+
}
|
|
43
|
+
export interface AppServerState {
|
|
44
|
+
cwd: string;
|
|
45
|
+
defaultSopOut: string;
|
|
46
|
+
defaultCheckpointOut: string;
|
|
47
|
+
protocolInitialized: boolean;
|
|
48
|
+
terminated: boolean;
|
|
49
|
+
board: TaskBoardState;
|
|
50
|
+
conversations: ConversationRuntime;
|
|
51
|
+
oauthRequestSeq: number;
|
|
52
|
+
pendingOAuthRequests: Map<string, PendingOAuthRequest>;
|
|
53
|
+
oauthLogin: OAuthLoginAdapter;
|
|
54
|
+
}
|
|
55
|
+
export declare function createAppServerState(cwd?: string, options?: {
|
|
56
|
+
sopOut?: string;
|
|
57
|
+
checkpointOut?: string;
|
|
58
|
+
oauthLogin?: OAuthLoginAdapter;
|
|
59
|
+
}): Promise<AppServerState>;
|
|
60
|
+
export declare function handleAppServerRequest(state: AppServerState, request: JsonRpcRequest, emitEvent: (event: AppServerEvent) => Promise<void>): Promise<JsonRpcResult | JsonRpcErrorResult | undefined>;
|
|
61
|
+
export declare function runAppServer(cwd?: string, options?: {
|
|
62
|
+
sopOut?: string;
|
|
63
|
+
checkpointOut?: string;
|
|
64
|
+
oauthLogin?: OAuthLoginAdapter;
|
|
65
|
+
}): Promise<void>;
|
|
66
|
+
export declare function registerAppServerCommand(program: Command): void;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,601 @@
|
|
|
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.APP_SERVER_EVENTS = exports.APP_SERVER_METHODS = exports.APP_SERVER_PROTOCOL_VERSION = void 0;
|
|
7
|
+
exports.createAppServerState = createAppServerState;
|
|
8
|
+
exports.handleAppServerRequest = handleAppServerRequest;
|
|
9
|
+
exports.runAppServer = runAppServer;
|
|
10
|
+
exports.registerAppServerCommand = registerAppServerCommand;
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_path_1 = require("node:path");
|
|
13
|
+
const node_readline_1 = __importDefault(require("node:readline"));
|
|
14
|
+
const dialog_session_1 = require("../infra/dialog-session");
|
|
15
|
+
const intent_1 = require("../infra/intent");
|
|
16
|
+
const model_accounts_1 = require("../infra/model-accounts");
|
|
17
|
+
const provider_registry_1 = require("../infra/provider-registry");
|
|
18
|
+
const session_status_1 = require("../infra/session-status");
|
|
19
|
+
const openai_codex_oauth_1 = require("../infra/openai-codex-oauth");
|
|
20
|
+
const config_1 = require("../infra/config");
|
|
21
|
+
const dialog_1 = require("./dialog");
|
|
22
|
+
exports.APP_SERVER_PROTOCOL_VERSION = "zaker.app/1";
|
|
23
|
+
exports.APP_SERVER_METHODS = [
|
|
24
|
+
"initialize",
|
|
25
|
+
"ping",
|
|
26
|
+
"session.get",
|
|
27
|
+
"command.execute",
|
|
28
|
+
"menu.context",
|
|
29
|
+
"oauth.start",
|
|
30
|
+
"oauth.cancel",
|
|
31
|
+
"shutdown"
|
|
32
|
+
];
|
|
33
|
+
exports.APP_SERVER_EVENTS = [
|
|
34
|
+
"session.update",
|
|
35
|
+
"run.stage",
|
|
36
|
+
"audit.result",
|
|
37
|
+
"oauth.status"
|
|
38
|
+
];
|
|
39
|
+
function now() {
|
|
40
|
+
return new Date().toISOString();
|
|
41
|
+
}
|
|
42
|
+
function resolveServerVersion() {
|
|
43
|
+
try {
|
|
44
|
+
const packagePath = (0, node_path_1.resolve)(__dirname, "..", "..", "package.json");
|
|
45
|
+
const raw = (0, node_fs_1.readFileSync)(packagePath, "utf8");
|
|
46
|
+
const parsed = JSON.parse(raw);
|
|
47
|
+
return typeof parsed.version === "string" && parsed.version.trim()
|
|
48
|
+
? parsed.version.trim()
|
|
49
|
+
: "0.0.0";
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return "0.0.0";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isRecord(value) {
|
|
56
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
57
|
+
}
|
|
58
|
+
function cloneBoard(board) {
|
|
59
|
+
return { ...board };
|
|
60
|
+
}
|
|
61
|
+
async function buildSessionSnapshot(state) {
|
|
62
|
+
const session = await (0, intent_1.readSessionStore)(state.cwd);
|
|
63
|
+
const draft = await (0, intent_1.readIntentCard)(state.cwd);
|
|
64
|
+
const confirmed = await (0, intent_1.readConfirmedIntent)(state.cwd);
|
|
65
|
+
const statusLines = session
|
|
66
|
+
? (0, session_status_1.formatSessionStatusLines)(session, draft, confirmed, {
|
|
67
|
+
includeDialog: true,
|
|
68
|
+
recentRoundLimit: 5
|
|
69
|
+
})
|
|
70
|
+
: ["session_state: UNINITIALIZED"];
|
|
71
|
+
const history = session?.dialog?.history
|
|
72
|
+
? session.dialog.history.slice(-80).map((entry) => ({
|
|
73
|
+
turn: entry.turn,
|
|
74
|
+
timestamp: entry.timestamp,
|
|
75
|
+
role: entry.role,
|
|
76
|
+
kind: entry.kind,
|
|
77
|
+
content: entry.content
|
|
78
|
+
}))
|
|
79
|
+
: [];
|
|
80
|
+
return {
|
|
81
|
+
session_state: session?.state ?? "UNINITIALIZED",
|
|
82
|
+
active_conversation_id: state.conversations.index.active_id || null,
|
|
83
|
+
draft_intent_id: draft?.intent_id ?? null,
|
|
84
|
+
confirmed_intent_id: confirmed?.intent_id ?? null,
|
|
85
|
+
current_intent_id: session?.current_intent_id ?? null,
|
|
86
|
+
board: cloneBoard(state.board),
|
|
87
|
+
status_lines: statusLines,
|
|
88
|
+
history
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async function buildMenuContext(state) {
|
|
92
|
+
const config = await (0, config_1.readConfig)(state.cwd);
|
|
93
|
+
const modelMenu = (0, model_accounts_1.buildModelMenuSnapshot)(config);
|
|
94
|
+
const sessionIds = await (0, dialog_session_1.listConversationIds)(state.conversations.index, state.cwd);
|
|
95
|
+
const providerIds = (0, provider_registry_1.getModelProviderIds)().filter((providerId) => providerId !== "mock");
|
|
96
|
+
return {
|
|
97
|
+
sessions: {
|
|
98
|
+
active_id: state.conversations.index.active_id || null,
|
|
99
|
+
ids: sessionIds
|
|
100
|
+
},
|
|
101
|
+
model_menu: modelMenu,
|
|
102
|
+
login: {
|
|
103
|
+
providers: providerIds.map((id) => ({
|
|
104
|
+
id,
|
|
105
|
+
supports_oauth: (0, provider_registry_1.providerSupportsOAuth)(id)
|
|
106
|
+
}))
|
|
107
|
+
},
|
|
108
|
+
logout: {
|
|
109
|
+
targets: [...providerIds, "ollama", "all"]
|
|
110
|
+
},
|
|
111
|
+
oauth: {
|
|
112
|
+
pending: [...state.pendingOAuthRequests.values()].map((request) => ({
|
|
113
|
+
request_id: request.request_id,
|
|
114
|
+
provider: request.provider,
|
|
115
|
+
started_at: request.started_at
|
|
116
|
+
}))
|
|
117
|
+
},
|
|
118
|
+
current_model: {
|
|
119
|
+
provider: config.model.provider,
|
|
120
|
+
planner_model: config.model.planner_model,
|
|
121
|
+
auditor_model: config.model.auditor_model,
|
|
122
|
+
execution_model: config.execution.model
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function toError(id, code, message, data) {
|
|
127
|
+
return {
|
|
128
|
+
jsonrpc: "2.0",
|
|
129
|
+
id,
|
|
130
|
+
error: {
|
|
131
|
+
code,
|
|
132
|
+
message,
|
|
133
|
+
data
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function toResult(id, result) {
|
|
138
|
+
return {
|
|
139
|
+
jsonrpc: "2.0",
|
|
140
|
+
id,
|
|
141
|
+
result
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function parseExecuteParams(params, fallbackSopOut, fallbackCheckpointOut) {
|
|
145
|
+
if (!isRecord(params)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const input = typeof params.input === "string" ? params.input : "";
|
|
149
|
+
const sopOut = typeof params.sop_out === "string" && params.sop_out.trim()
|
|
150
|
+
? params.sop_out.trim()
|
|
151
|
+
: fallbackSopOut;
|
|
152
|
+
const checkpointOut = typeof params.checkpoint_out === "string" && params.checkpoint_out.trim()
|
|
153
|
+
? params.checkpoint_out.trim()
|
|
154
|
+
: fallbackCheckpointOut;
|
|
155
|
+
if (!input.trim()) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
input,
|
|
160
|
+
sopOut,
|
|
161
|
+
checkpointOut
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function parseOAuthStartParams(params) {
|
|
165
|
+
if (!isRecord(params)) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const provider = typeof params.provider === "string" ? params.provider.trim() : "";
|
|
169
|
+
if (!provider) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
return { provider };
|
|
173
|
+
}
|
|
174
|
+
function parseOAuthCancelParams(params) {
|
|
175
|
+
if (!isRecord(params)) {
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
const requestId = typeof params.request_id === "string" ? params.request_id.trim() : "";
|
|
179
|
+
if (!requestId) {
|
|
180
|
+
return {};
|
|
181
|
+
}
|
|
182
|
+
return { requestId };
|
|
183
|
+
}
|
|
184
|
+
function parseOAuthCommandShortcut(input) {
|
|
185
|
+
const tokens = input.trim().split(/\s+/).filter(Boolean);
|
|
186
|
+
if (tokens.length === 3 && tokens[0] === "/login" && tokens[2].toLowerCase() === "oauth") {
|
|
187
|
+
return { provider: tokens[1] || "" };
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
async function emitSessionUpdate(state, emitEvent, snapshot) {
|
|
192
|
+
await emitEvent({
|
|
193
|
+
event: "session.update",
|
|
194
|
+
timestamp: now(),
|
|
195
|
+
payload: {
|
|
196
|
+
session_state: snapshot.session_state,
|
|
197
|
+
active_conversation_id: snapshot.active_conversation_id,
|
|
198
|
+
current_intent_id: snapshot.current_intent_id
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
async function emitOAuthStatus(emitEvent, payload) {
|
|
203
|
+
await emitEvent({
|
|
204
|
+
event: "oauth.status",
|
|
205
|
+
timestamp: now(),
|
|
206
|
+
payload
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function nextOAuthRequestId(state) {
|
|
210
|
+
state.oauthRequestSeq += 1;
|
|
211
|
+
return `oauth_${Date.now()}_${state.oauthRequestSeq}`;
|
|
212
|
+
}
|
|
213
|
+
async function performOAuthStart(state, providerInput, emitEvent) {
|
|
214
|
+
let provider;
|
|
215
|
+
try {
|
|
216
|
+
provider = (0, provider_registry_1.toLoginProviderId)(providerInput);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
throw new Error(`Unsupported provider: ${providerInput}`);
|
|
220
|
+
}
|
|
221
|
+
if (!(0, provider_registry_1.providerSupportsOAuth)(provider)) {
|
|
222
|
+
throw new Error(`Provider \"${provider}\" does not support oauth login.`);
|
|
223
|
+
}
|
|
224
|
+
if (provider !== "openai-codex") {
|
|
225
|
+
throw new Error(`UNSUPPORTED_OAUTH_PROVIDER: ${provider}`);
|
|
226
|
+
}
|
|
227
|
+
const requestId = nextOAuthRequestId(state);
|
|
228
|
+
const controller = new AbortController();
|
|
229
|
+
const requestState = {
|
|
230
|
+
request_id: requestId,
|
|
231
|
+
provider,
|
|
232
|
+
started_at: now(),
|
|
233
|
+
controller
|
|
234
|
+
};
|
|
235
|
+
state.pendingOAuthRequests.set(requestId, requestState);
|
|
236
|
+
await emitOAuthStatus(emitEvent, {
|
|
237
|
+
request_id: requestId,
|
|
238
|
+
provider,
|
|
239
|
+
phase: "started",
|
|
240
|
+
status: "OAuth started"
|
|
241
|
+
});
|
|
242
|
+
void (async () => {
|
|
243
|
+
try {
|
|
244
|
+
const config = await (0, config_1.readConfig)(state.cwd);
|
|
245
|
+
const endpoint = config.model.endpoint?.trim() || "";
|
|
246
|
+
const oauth = await state.oauthLogin({
|
|
247
|
+
onAuth: async ({ url, instructions }) => {
|
|
248
|
+
await emitOAuthStatus(emitEvent, {
|
|
249
|
+
request_id: requestId,
|
|
250
|
+
provider,
|
|
251
|
+
phase: "authorize",
|
|
252
|
+
status: instructions,
|
|
253
|
+
url
|
|
254
|
+
});
|
|
255
|
+
},
|
|
256
|
+
onProgress: async (message) => {
|
|
257
|
+
await emitOAuthStatus(emitEvent, {
|
|
258
|
+
request_id: requestId,
|
|
259
|
+
provider,
|
|
260
|
+
phase: "progress",
|
|
261
|
+
status: message
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
onPrompt: async () => "",
|
|
265
|
+
open_browser: true,
|
|
266
|
+
originator: "pi",
|
|
267
|
+
abort_signal: controller.signal
|
|
268
|
+
});
|
|
269
|
+
const loginLine = `/login ${provider} oauth ${oauth.access_token}${endpoint ? ` ${endpoint}` : ""}`;
|
|
270
|
+
await (0, dialog_1.handleDialogInput)(loginLine, state.cwd, {
|
|
271
|
+
sopOut: state.defaultSopOut,
|
|
272
|
+
checkpointOut: state.defaultCheckpointOut,
|
|
273
|
+
interactive: true,
|
|
274
|
+
quiet: true,
|
|
275
|
+
board: state.board,
|
|
276
|
+
conversations: state.conversations,
|
|
277
|
+
redraw: async (nextNotice) => {
|
|
278
|
+
await emitEvent({
|
|
279
|
+
event: "run.stage",
|
|
280
|
+
timestamp: now(),
|
|
281
|
+
payload: {
|
|
282
|
+
notice: nextNotice ?? "",
|
|
283
|
+
run_stage: state.board.run_stage,
|
|
284
|
+
run_status: state.board.run_status,
|
|
285
|
+
verification_status: state.board.verification_status,
|
|
286
|
+
verification_passed: state.board.verification_passed,
|
|
287
|
+
verification_total: state.board.verification_total,
|
|
288
|
+
risk_hit: state.board.risk_hit,
|
|
289
|
+
audit_verdict: state.board.audit_verdict,
|
|
290
|
+
budget_plan_calls: state.board.budget_plan_calls,
|
|
291
|
+
budget_audit_calls: state.board.budget_audit_calls,
|
|
292
|
+
budget_challenge_used: state.board.budget_challenge_used
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
const snapshot = await buildSessionSnapshot(state);
|
|
298
|
+
await emitSessionUpdate(state, emitEvent, snapshot);
|
|
299
|
+
await emitOAuthStatus(emitEvent, {
|
|
300
|
+
request_id: requestId,
|
|
301
|
+
provider,
|
|
302
|
+
phase: "success",
|
|
303
|
+
status: "OAuth login completed"
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
308
|
+
const phase = /cancel/i.test(message) || controller.signal.aborted ? "cancelled" : "failed";
|
|
309
|
+
await emitOAuthStatus(emitEvent, {
|
|
310
|
+
request_id: requestId,
|
|
311
|
+
provider,
|
|
312
|
+
phase,
|
|
313
|
+
status: message
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
state.pendingOAuthRequests.delete(requestId);
|
|
318
|
+
}
|
|
319
|
+
})();
|
|
320
|
+
return {
|
|
321
|
+
request_id: requestId,
|
|
322
|
+
status: "started"
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
async function performOAuthCancel(state, params, emitEvent) {
|
|
326
|
+
const parsed = parseOAuthCancelParams(params);
|
|
327
|
+
const requestId = parsed.requestId || [...state.pendingOAuthRequests.keys()].at(-1) || "";
|
|
328
|
+
if (!requestId) {
|
|
329
|
+
throw new Error("No pending OAuth request.");
|
|
330
|
+
}
|
|
331
|
+
const pending = state.pendingOAuthRequests.get(requestId);
|
|
332
|
+
if (!pending) {
|
|
333
|
+
const error = new Error("OAuth request not found.");
|
|
334
|
+
error.code = -32004;
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
pending.controller.abort();
|
|
338
|
+
await emitOAuthStatus(emitEvent, {
|
|
339
|
+
request_id: requestId,
|
|
340
|
+
provider: pending.provider,
|
|
341
|
+
phase: "cancel_requested",
|
|
342
|
+
status: "OAuth cancellation requested"
|
|
343
|
+
});
|
|
344
|
+
return {
|
|
345
|
+
ok: true,
|
|
346
|
+
cancelled_request_id: requestId
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
async function executeDialogCommand(state, params, emitEvent) {
|
|
350
|
+
const parsed = parseExecuteParams(params, state.defaultSopOut, state.defaultCheckpointOut);
|
|
351
|
+
if (!parsed) {
|
|
352
|
+
throw new Error("Invalid params: input must be non-empty string.");
|
|
353
|
+
}
|
|
354
|
+
const trimmedInput = parsed.input.trim();
|
|
355
|
+
const oauthShortcut = parseOAuthCommandShortcut(trimmedInput);
|
|
356
|
+
if (oauthShortcut) {
|
|
357
|
+
const started = await performOAuthStart(state, oauthShortcut.provider, emitEvent);
|
|
358
|
+
const snapshot = await buildSessionSnapshot(state);
|
|
359
|
+
await emitSessionUpdate(state, emitEvent, snapshot);
|
|
360
|
+
return {
|
|
361
|
+
action: "continue",
|
|
362
|
+
notice: `oauth started: ${started.request_id}`,
|
|
363
|
+
snapshot
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
const result = await (0, dialog_1.handleDialogInput)(parsed.input, state.cwd, {
|
|
367
|
+
sopOut: parsed.sopOut,
|
|
368
|
+
checkpointOut: parsed.checkpointOut,
|
|
369
|
+
interactive: true,
|
|
370
|
+
quiet: true,
|
|
371
|
+
board: state.board,
|
|
372
|
+
conversations: state.conversations,
|
|
373
|
+
redraw: async (nextNotice) => {
|
|
374
|
+
await emitEvent({
|
|
375
|
+
event: "run.stage",
|
|
376
|
+
timestamp: now(),
|
|
377
|
+
payload: {
|
|
378
|
+
notice: nextNotice ?? "",
|
|
379
|
+
run_stage: state.board.run_stage,
|
|
380
|
+
run_status: state.board.run_status,
|
|
381
|
+
verification_status: state.board.verification_status,
|
|
382
|
+
verification_passed: state.board.verification_passed,
|
|
383
|
+
verification_total: state.board.verification_total,
|
|
384
|
+
risk_hit: state.board.risk_hit,
|
|
385
|
+
audit_verdict: state.board.audit_verdict,
|
|
386
|
+
budget_plan_calls: state.board.budget_plan_calls,
|
|
387
|
+
budget_audit_calls: state.board.budget_audit_calls,
|
|
388
|
+
budget_challenge_used: state.board.budget_challenge_used
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
if (/oauth/i.test(nextNotice ?? "")) {
|
|
392
|
+
await emitOAuthStatus(emitEvent, {
|
|
393
|
+
phase: "progress",
|
|
394
|
+
status: nextNotice ?? ""
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
if (result.action === "exit") {
|
|
400
|
+
state.terminated = true;
|
|
401
|
+
}
|
|
402
|
+
const snapshot = await buildSessionSnapshot(state);
|
|
403
|
+
await emitSessionUpdate(state, emitEvent, snapshot);
|
|
404
|
+
if (trimmedInput.startsWith("/run")) {
|
|
405
|
+
await emitEvent({
|
|
406
|
+
event: "audit.result",
|
|
407
|
+
timestamp: now(),
|
|
408
|
+
payload: {
|
|
409
|
+
verdict: state.board.audit_verdict,
|
|
410
|
+
reason: state.board.audit_reason,
|
|
411
|
+
conclusion: state.board.audit_conclusion,
|
|
412
|
+
retry_allowed: state.board.retry_allowed
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
action: result.action,
|
|
418
|
+
notice: result.notice,
|
|
419
|
+
snapshot
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
async function createAppServerState(cwd = process.cwd(), options = {}) {
|
|
423
|
+
return {
|
|
424
|
+
cwd,
|
|
425
|
+
defaultSopOut: options.sopOut ?? "sop.json",
|
|
426
|
+
defaultCheckpointOut: options.checkpointOut ?? "checkpoint.json",
|
|
427
|
+
protocolInitialized: false,
|
|
428
|
+
terminated: false,
|
|
429
|
+
board: (0, dialog_1.createTaskBoardState)(),
|
|
430
|
+
conversations: {
|
|
431
|
+
index: await (0, dialog_session_1.readConversationIndex)(cwd)
|
|
432
|
+
},
|
|
433
|
+
oauthRequestSeq: 0,
|
|
434
|
+
pendingOAuthRequests: new Map(),
|
|
435
|
+
oauthLogin: options.oauthLogin ?? openai_codex_oauth_1.loginOpenAICodexOAuth
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
async function handleAppServerRequest(state, request, emitEvent) {
|
|
439
|
+
const id = request.id ?? null;
|
|
440
|
+
if (request.jsonrpc !== "2.0" || typeof request.method !== "string") {
|
|
441
|
+
if (request.id === undefined) {
|
|
442
|
+
return undefined;
|
|
443
|
+
}
|
|
444
|
+
return toError(id, -32600, "INVALID_REQUEST");
|
|
445
|
+
}
|
|
446
|
+
const method = request.method;
|
|
447
|
+
const needsInitialized = method === "session.get" ||
|
|
448
|
+
method === "command.execute" ||
|
|
449
|
+
method === "menu.context" ||
|
|
450
|
+
method === "oauth.start" ||
|
|
451
|
+
method === "oauth.cancel" ||
|
|
452
|
+
method === "shutdown";
|
|
453
|
+
if (needsInitialized && !state.protocolInitialized) {
|
|
454
|
+
return toError(id, -32002, "NOT_INITIALIZED");
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
if (method === "initialize") {
|
|
458
|
+
const params = isRecord(request.params) ? request.params : {};
|
|
459
|
+
const protocolVersion = typeof params.protocol_version === "string"
|
|
460
|
+
? params.protocol_version.trim()
|
|
461
|
+
: "";
|
|
462
|
+
if (protocolVersion && protocolVersion !== exports.APP_SERVER_PROTOCOL_VERSION) {
|
|
463
|
+
return toError(id, -32001, "PROTOCOL_VERSION_MISMATCH", {
|
|
464
|
+
expected: exports.APP_SERVER_PROTOCOL_VERSION,
|
|
465
|
+
received: protocolVersion
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
state.protocolInitialized = true;
|
|
469
|
+
return toResult(id, {
|
|
470
|
+
protocol_version: exports.APP_SERVER_PROTOCOL_VERSION,
|
|
471
|
+
server: {
|
|
472
|
+
name: "zaker-app-server",
|
|
473
|
+
version: resolveServerVersion()
|
|
474
|
+
},
|
|
475
|
+
capabilities: {
|
|
476
|
+
methods: [...exports.APP_SERVER_METHODS],
|
|
477
|
+
events: [...exports.APP_SERVER_EVENTS]
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (method === "ping") {
|
|
482
|
+
return toResult(id, {
|
|
483
|
+
ok: true,
|
|
484
|
+
timestamp: now()
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (method === "session.get") {
|
|
488
|
+
return toResult(id, await buildSessionSnapshot(state));
|
|
489
|
+
}
|
|
490
|
+
if (method === "menu.context") {
|
|
491
|
+
return toResult(id, await buildMenuContext(state));
|
|
492
|
+
}
|
|
493
|
+
if (method === "oauth.start") {
|
|
494
|
+
const parsed = parseOAuthStartParams(request.params);
|
|
495
|
+
if (!parsed) {
|
|
496
|
+
return toError(id, -32602, "INVALID_PARAMS", {
|
|
497
|
+
expected: { provider: "openai-codex" }
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
return toResult(id, await performOAuthStart(state, parsed.provider, emitEvent));
|
|
502
|
+
}
|
|
503
|
+
catch (error) {
|
|
504
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
505
|
+
return toError(id, -32003, "COMMAND_EXECUTION_FAILED", { message });
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (method === "oauth.cancel") {
|
|
509
|
+
try {
|
|
510
|
+
return toResult(id, await performOAuthCancel(state, request.params, emitEvent));
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
const errorCode = typeof error === "object" && error !== null && "code" in error
|
|
514
|
+
? Number(error.code)
|
|
515
|
+
: NaN;
|
|
516
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
517
|
+
if (Number.isFinite(errorCode) && errorCode === -32004) {
|
|
518
|
+
return toError(id, -32004, "OAUTH_REQUEST_NOT_FOUND", { message });
|
|
519
|
+
}
|
|
520
|
+
return toError(id, -32003, "COMMAND_EXECUTION_FAILED", { message });
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (method === "command.execute") {
|
|
524
|
+
try {
|
|
525
|
+
const executed = await executeDialogCommand(state, request.params, emitEvent);
|
|
526
|
+
return toResult(id, executed);
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
530
|
+
return toError(id, -32003, "COMMAND_EXECUTION_FAILED", { message });
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (method === "shutdown") {
|
|
534
|
+
for (const pending of state.pendingOAuthRequests.values()) {
|
|
535
|
+
pending.controller.abort();
|
|
536
|
+
}
|
|
537
|
+
state.pendingOAuthRequests.clear();
|
|
538
|
+
state.terminated = true;
|
|
539
|
+
return toResult(id, { ok: true });
|
|
540
|
+
}
|
|
541
|
+
return toError(id, -32601, "METHOD_NOT_FOUND");
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
545
|
+
return toError(id, -32603, "INTERNAL_ERROR", { message });
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function writeJsonLine(payload) {
|
|
549
|
+
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
550
|
+
}
|
|
551
|
+
async function runAppServer(cwd = process.cwd(), options = {}) {
|
|
552
|
+
const state = await createAppServerState(cwd, options);
|
|
553
|
+
const input = node_readline_1.default.createInterface({
|
|
554
|
+
input: process.stdin,
|
|
555
|
+
crlfDelay: Infinity,
|
|
556
|
+
terminal: false
|
|
557
|
+
});
|
|
558
|
+
const emitEvent = async (event) => {
|
|
559
|
+
writeJsonLine({
|
|
560
|
+
jsonrpc: "2.0",
|
|
561
|
+
method: "event",
|
|
562
|
+
params: event
|
|
563
|
+
});
|
|
564
|
+
};
|
|
565
|
+
for await (const line of input) {
|
|
566
|
+
if (!line.trim()) {
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
let parsed;
|
|
570
|
+
try {
|
|
571
|
+
parsed = JSON.parse(line);
|
|
572
|
+
}
|
|
573
|
+
catch {
|
|
574
|
+
writeJsonLine(toError(null, -32700, "PARSE_ERROR"));
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
const response = await handleAppServerRequest(state, parsed, emitEvent);
|
|
578
|
+
if (response && parsed.id !== undefined) {
|
|
579
|
+
writeJsonLine(response);
|
|
580
|
+
}
|
|
581
|
+
if (state.terminated) {
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
input.close();
|
|
586
|
+
}
|
|
587
|
+
function registerAppServerCommand(program) {
|
|
588
|
+
program
|
|
589
|
+
.command("app-server")
|
|
590
|
+
.description("start zaker JSON-RPC app server over stdio")
|
|
591
|
+
.option("--cwd <path>", "workspace directory", process.cwd())
|
|
592
|
+
.option("-o, --sop-out <path>", "default sop output path", "sop.json")
|
|
593
|
+
.option("-c, --checkpoint-out <path>", "default checkpoint output path", "checkpoint.json")
|
|
594
|
+
.action(async (options) => {
|
|
595
|
+
await runAppServer(options.cwd, {
|
|
596
|
+
sopOut: options.sopOut,
|
|
597
|
+
checkpointOut: options.checkpointOut
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
//# sourceMappingURL=app-server.js.map
|