@ceki/sdk 1.13.0 → 1.14.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/dist/cli.js +898 -79
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +396 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +154 -1
- package/dist/index.d.ts +154 -1
- package/dist/index.js +385 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -472,8 +472,8 @@ function saveSession(sid, data) {
|
|
|
472
472
|
function deleteSession(sid) {
|
|
473
473
|
try {
|
|
474
474
|
fs2.unlinkSync(statePath(sid));
|
|
475
|
-
} catch (
|
|
476
|
-
if (
|
|
475
|
+
} catch (err3) {
|
|
476
|
+
if (err3.code !== "ENOENT") throw err3;
|
|
477
477
|
}
|
|
478
478
|
}
|
|
479
479
|
function getLastSeenTs(sid) {
|
|
@@ -1189,10 +1189,10 @@ var Browser = class _Browser {
|
|
|
1189
1189
|
_onChatSendError(msg) {
|
|
1190
1190
|
this.chat._onSendError(msg);
|
|
1191
1191
|
}
|
|
1192
|
-
_rejectAllPending(
|
|
1192
|
+
_rejectAllPending(err3) {
|
|
1193
1193
|
for (const [id, pending] of this._pendingCdp) {
|
|
1194
1194
|
clearTimeout(pending.timer);
|
|
1195
|
-
pending.reject(
|
|
1195
|
+
pending.reject(err3);
|
|
1196
1196
|
}
|
|
1197
1197
|
this._pendingCdp.clear();
|
|
1198
1198
|
}
|
|
@@ -1604,9 +1604,9 @@ var Client = class _Client {
|
|
|
1604
1604
|
this._stopHeartbeat();
|
|
1605
1605
|
const reasonStr = reason.toString();
|
|
1606
1606
|
if (code === 4401 || code === 4403) {
|
|
1607
|
-
const
|
|
1607
|
+
const err3 = new AuthError(reasonStr || `Auth failed (${code})`);
|
|
1608
1608
|
if (this._connectReject) {
|
|
1609
|
-
this._connectReject(
|
|
1609
|
+
this._connectReject(err3);
|
|
1610
1610
|
this._connectResolve = null;
|
|
1611
1611
|
this._connectReject = null;
|
|
1612
1612
|
}
|
|
@@ -1616,9 +1616,9 @@ var Client = class _Client {
|
|
|
1616
1616
|
this._scheduleReconnect();
|
|
1617
1617
|
}
|
|
1618
1618
|
});
|
|
1619
|
-
this._ws.on("error", (
|
|
1619
|
+
this._ws.on("error", (err3) => {
|
|
1620
1620
|
if (this._connectReject) {
|
|
1621
|
-
this._connectReject(new TransportError(
|
|
1621
|
+
this._connectReject(new TransportError(err3.message));
|
|
1622
1622
|
this._connectResolve = null;
|
|
1623
1623
|
this._connectReject = null;
|
|
1624
1624
|
}
|
|
@@ -1637,8 +1637,8 @@ var Client = class _Client {
|
|
|
1637
1637
|
_scheduleReconnect() {
|
|
1638
1638
|
if (this._closed || this._reconnecting) return;
|
|
1639
1639
|
if (this._reconnectAttempt >= MAX_RECONNECT_ATTEMPTS) {
|
|
1640
|
-
const
|
|
1641
|
-
this._rejectAllPending(
|
|
1640
|
+
const err3 = new ConnectionLost("Max reconnection attempts exceeded");
|
|
1641
|
+
this._rejectAllPending(err3);
|
|
1642
1642
|
return;
|
|
1643
1643
|
}
|
|
1644
1644
|
this._reconnecting = true;
|
|
@@ -1929,44 +1929,44 @@ var Client = class _Client {
|
|
|
1929
1929
|
}
|
|
1930
1930
|
}
|
|
1931
1931
|
}
|
|
1932
|
-
let
|
|
1932
|
+
let err3;
|
|
1933
1933
|
switch (code) {
|
|
1934
1934
|
case -1012:
|
|
1935
|
-
|
|
1936
|
-
this._rejectAllPending(
|
|
1935
|
+
err3 = new InsufficientFunds(reason);
|
|
1936
|
+
this._rejectAllPending(err3);
|
|
1937
1937
|
break;
|
|
1938
1938
|
case -1013:
|
|
1939
|
-
|
|
1940
|
-
this._rejectAllPending(
|
|
1939
|
+
err3 = new RateLimitExceeded(0, reason);
|
|
1940
|
+
this._rejectAllPending(err3);
|
|
1941
1941
|
break;
|
|
1942
1942
|
case -1015:
|
|
1943
|
-
|
|
1944
|
-
this._rejectFirstPendingRent(
|
|
1943
|
+
err3 = new ProviderOffline(reason);
|
|
1944
|
+
this._rejectFirstPendingRent(err3);
|
|
1945
1945
|
break;
|
|
1946
1946
|
default:
|
|
1947
|
-
|
|
1948
|
-
this._rejectFirstPendingRent(
|
|
1947
|
+
err3 = new CekiBrowserError(reason || `relay error ${code}`);
|
|
1948
|
+
this._rejectFirstPendingRent(err3);
|
|
1949
1949
|
break;
|
|
1950
1950
|
}
|
|
1951
1951
|
}
|
|
1952
|
-
_rejectFirstPendingRent(
|
|
1952
|
+
_rejectFirstPendingRent(err3) {
|
|
1953
1953
|
const eventId = this._pendingRents.keys().next().value;
|
|
1954
1954
|
if (eventId != null) {
|
|
1955
1955
|
const pending = this._pendingRents.get(eventId);
|
|
1956
1956
|
clearTimeout(pending.timer);
|
|
1957
1957
|
this._pendingRents.delete(eventId);
|
|
1958
|
-
pending.reject(
|
|
1958
|
+
pending.reject(err3);
|
|
1959
1959
|
}
|
|
1960
1960
|
}
|
|
1961
|
-
_rejectAllPending(
|
|
1961
|
+
_rejectAllPending(err3) {
|
|
1962
1962
|
for (const [key, pending] of this._pendingRents) {
|
|
1963
1963
|
clearTimeout(pending.timer);
|
|
1964
|
-
pending.reject(
|
|
1964
|
+
pending.reject(err3);
|
|
1965
1965
|
}
|
|
1966
1966
|
this._pendingRents.clear();
|
|
1967
1967
|
for (const [key, pending] of this._pendingResumes) {
|
|
1968
1968
|
clearTimeout(pending.timer);
|
|
1969
|
-
pending.reject(
|
|
1969
|
+
pending.reject(err3);
|
|
1970
1970
|
}
|
|
1971
1971
|
this._pendingResumes.clear();
|
|
1972
1972
|
}
|
|
@@ -1990,17 +1990,796 @@ async function connect(apiKey, opts) {
|
|
|
1990
1990
|
return Client.create(apiKey, opts);
|
|
1991
1991
|
}
|
|
1992
1992
|
|
|
1993
|
-
// src/
|
|
1993
|
+
// src/contract.ts
|
|
1994
|
+
var ROLE_REVIEWER = 5;
|
|
1995
|
+
var ROLE_QA = 6;
|
|
1996
|
+
var ContractError = class extends Error {
|
|
1997
|
+
constructor(message) {
|
|
1998
|
+
super(message);
|
|
1999
|
+
this.name = "ContractError";
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
function parseBenefitable(value) {
|
|
2003
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
2004
|
+
const parts = String(value).split(":");
|
|
2005
|
+
if (parts.length !== 2) {
|
|
2006
|
+
throw new Error(`benefitable must be 'type:id', got: ${JSON.stringify(value)}`);
|
|
2007
|
+
}
|
|
2008
|
+
const [btype, bid] = parts;
|
|
2009
|
+
const num = Number.parseInt(bid, 10);
|
|
2010
|
+
if (!Number.isFinite(num) || Number.isNaN(num)) {
|
|
2011
|
+
throw new Error(`benefitable id must be int, got: ${JSON.stringify(bid)}`);
|
|
2012
|
+
}
|
|
2013
|
+
return { type: btype, value: num };
|
|
2014
|
+
}
|
|
2015
|
+
function parseParticipant(value, roleId) {
|
|
2016
|
+
const base = parseBenefitable(value);
|
|
2017
|
+
if (base === null) return null;
|
|
2018
|
+
return {
|
|
2019
|
+
participable_id: base.value,
|
|
2020
|
+
type: base.type,
|
|
2021
|
+
role_id: roleId
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
function cleanArgs(o) {
|
|
2025
|
+
const out3 = {};
|
|
2026
|
+
for (const [k, v] of Object.entries(o)) {
|
|
2027
|
+
if (v !== void 0 && v !== null) {
|
|
2028
|
+
out3[k] = v;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
return out3;
|
|
2032
|
+
}
|
|
2033
|
+
function deriveLabel(desc) {
|
|
2034
|
+
if (!desc) return "progress";
|
|
2035
|
+
const lines = String(desc).split(/\r?\n/);
|
|
2036
|
+
for (const ln of lines) {
|
|
2037
|
+
const t = ln.trim();
|
|
2038
|
+
if (t) return t.slice(0, 60);
|
|
2039
|
+
}
|
|
2040
|
+
return "progress";
|
|
2041
|
+
}
|
|
2042
|
+
function contractIdsFromEnv() {
|
|
2043
|
+
const raw = (process.env.CEKI_CONTRACT_IDS ?? "").trim();
|
|
2044
|
+
if (!raw) return [];
|
|
2045
|
+
try {
|
|
2046
|
+
const parsed = JSON.parse(raw);
|
|
2047
|
+
if (Array.isArray(parsed)) return parsed.map((x) => String(x));
|
|
2048
|
+
} catch {
|
|
2049
|
+
}
|
|
2050
|
+
return raw.replace(/\[/g, "").replace(/\]/g, "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2051
|
+
}
|
|
2052
|
+
function resolveEndpoint() {
|
|
2053
|
+
const override = process.env.CEKI_AGENT_MCP_ENDPOINT;
|
|
2054
|
+
if (override) return override.replace(/\/+$/, "");
|
|
2055
|
+
const base = (process.env.CEKI_API_URL ?? defaults.apiUrl).replace(/\/+$/, "");
|
|
2056
|
+
return `${base}/mcp/agent`;
|
|
2057
|
+
}
|
|
2058
|
+
function resolveApiBase() {
|
|
2059
|
+
const override = process.env.CEKI_API_BASE;
|
|
2060
|
+
if (override) return override.replace(/\/+$/, "");
|
|
2061
|
+
const base = (process.env.CEKI_API_URL ?? defaults.apiUrl).replace(/\/+$/, "");
|
|
2062
|
+
return `${base}/api`;
|
|
2063
|
+
}
|
|
2064
|
+
function resolveToken() {
|
|
2065
|
+
return process.env.CEKI_AGENT_TOKEN ?? process.env.CEKI_API_KEY ?? "";
|
|
2066
|
+
}
|
|
2067
|
+
var TOOL_MAP = {
|
|
2068
|
+
list: "get-my-contracts",
|
|
2069
|
+
members: "get-contract-members",
|
|
2070
|
+
tasks: "get-contract-events",
|
|
2071
|
+
"my-jobs": "get-my-jobs",
|
|
2072
|
+
task: "get-event",
|
|
2073
|
+
children: "get-event-children",
|
|
2074
|
+
history: "get-event-history",
|
|
2075
|
+
create: "create-contract-event",
|
|
2076
|
+
comment: "comment",
|
|
2077
|
+
propose: "propose-correction",
|
|
2078
|
+
vote: "vote-correction"
|
|
2079
|
+
};
|
|
2080
|
+
var FetchHttpClient = class {
|
|
2081
|
+
constructor(timeoutMs) {
|
|
2082
|
+
this.timeoutMs = timeoutMs;
|
|
2083
|
+
}
|
|
2084
|
+
timeoutMs;
|
|
2085
|
+
withTimeout() {
|
|
2086
|
+
const ctl = new AbortController();
|
|
2087
|
+
const t = setTimeout(() => ctl.abort(), this.timeoutMs);
|
|
2088
|
+
return { signal: ctl.signal, cancel: () => clearTimeout(t) };
|
|
2089
|
+
}
|
|
2090
|
+
async post(url, init) {
|
|
2091
|
+
const { signal, cancel } = this.withTimeout();
|
|
2092
|
+
try {
|
|
2093
|
+
const r = await fetch(url, { method: "POST", headers: init.headers, body: init.body, signal });
|
|
2094
|
+
const text = await r.text();
|
|
2095
|
+
return {
|
|
2096
|
+
status: r.status,
|
|
2097
|
+
text: async () => text,
|
|
2098
|
+
json: async () => {
|
|
2099
|
+
try {
|
|
2100
|
+
return JSON.parse(text);
|
|
2101
|
+
} catch {
|
|
2102
|
+
return { raw: text };
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
} finally {
|
|
2107
|
+
cancel();
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
async get(url, init) {
|
|
2111
|
+
const { signal, cancel } = this.withTimeout();
|
|
2112
|
+
try {
|
|
2113
|
+
const r = await fetch(url, { method: "GET", headers: init.headers, signal });
|
|
2114
|
+
const text = await r.text();
|
|
2115
|
+
return {
|
|
2116
|
+
status: r.status,
|
|
2117
|
+
text: async () => text,
|
|
2118
|
+
json: async () => {
|
|
2119
|
+
try {
|
|
2120
|
+
return JSON.parse(text);
|
|
2121
|
+
} catch {
|
|
2122
|
+
return { raw: text };
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
};
|
|
2126
|
+
} finally {
|
|
2127
|
+
cancel();
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
var ContractClient = class {
|
|
2132
|
+
endpoint;
|
|
2133
|
+
apiBase;
|
|
2134
|
+
token;
|
|
2135
|
+
http;
|
|
2136
|
+
constructor(opts = {}) {
|
|
2137
|
+
this.endpoint = (opts.endpoint ?? resolveEndpoint()).replace(/\/+$/, "");
|
|
2138
|
+
this.apiBase = (opts.apiBase ?? resolveApiBase()).replace(/\/+$/, "");
|
|
2139
|
+
this.token = opts.token !== void 0 ? opts.token : resolveToken();
|
|
2140
|
+
this.http = opts.http ?? new FetchHttpClient(opts.timeoutMs ?? 3e4);
|
|
2141
|
+
}
|
|
2142
|
+
headers() {
|
|
2143
|
+
if (!this.token) {
|
|
2144
|
+
throw new ContractError("agent token not set (CEKI_AGENT_TOKEN or CEKI_API_KEY)");
|
|
2145
|
+
}
|
|
2146
|
+
return {
|
|
2147
|
+
"Content-Type": "application/json",
|
|
2148
|
+
Accept: "application/json",
|
|
2149
|
+
Authorization: `Bearer ${this.token}`
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
async rpc(method, params) {
|
|
2153
|
+
const body = JSON.stringify({
|
|
2154
|
+
jsonrpc: "2.0",
|
|
2155
|
+
id: Date.now(),
|
|
2156
|
+
method,
|
|
2157
|
+
params
|
|
2158
|
+
});
|
|
2159
|
+
const resp = await this.http.post(this.endpoint, { headers: this.headers(), body });
|
|
2160
|
+
let parsed;
|
|
2161
|
+
try {
|
|
2162
|
+
parsed = await resp.json();
|
|
2163
|
+
} catch {
|
|
2164
|
+
parsed = { raw: await resp.text() };
|
|
2165
|
+
}
|
|
2166
|
+
if (resp.status !== 200) {
|
|
2167
|
+
const snippet = JSON.stringify(parsed).slice(0, 400);
|
|
2168
|
+
throw new ContractError(`HTTP ${resp.status}: ${snippet}`);
|
|
2169
|
+
}
|
|
2170
|
+
return parsed ?? {};
|
|
2171
|
+
}
|
|
2172
|
+
/** Call MCP tool; unwrap content[].text (JSON-parsed) or structuredContent. */
|
|
2173
|
+
async call(tool, args = {}) {
|
|
2174
|
+
const body = await this.rpc("tools/call", { name: tool, arguments: args });
|
|
2175
|
+
if (body["error"]) {
|
|
2176
|
+
throw new ContractError(`${tool} \u2192 ${JSON.stringify(body["error"]).slice(0, 400)}`);
|
|
2177
|
+
}
|
|
2178
|
+
const result = body["result"] ?? {};
|
|
2179
|
+
const content = result["content"];
|
|
2180
|
+
if (Array.isArray(content)) {
|
|
2181
|
+
const texts = content.filter((c) => c["type"] === "text").map((c) => String(c["text"] ?? ""));
|
|
2182
|
+
const joined = texts.join("\n");
|
|
2183
|
+
try {
|
|
2184
|
+
return JSON.parse(joined);
|
|
2185
|
+
} catch {
|
|
2186
|
+
return joined;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
if (result["structuredContent"] !== void 0) return result["structuredContent"];
|
|
2190
|
+
return result;
|
|
2191
|
+
}
|
|
2192
|
+
async tools() {
|
|
2193
|
+
const body = await this.rpc("tools/list", {});
|
|
2194
|
+
const result = body["result"] ?? {};
|
|
2195
|
+
const tools = result["tools"];
|
|
2196
|
+
if (Array.isArray(tools)) return tools.map((t) => t["name"]);
|
|
2197
|
+
return body;
|
|
2198
|
+
}
|
|
2199
|
+
async raw(tool, args = {}) {
|
|
2200
|
+
return this.call(tool, args);
|
|
2201
|
+
}
|
|
2202
|
+
// ── domain helpers ──────────────────────────────────────────────
|
|
2203
|
+
async listContracts() {
|
|
2204
|
+
return this.call(TOOL_MAP.list, {});
|
|
2205
|
+
}
|
|
2206
|
+
async members(contractId) {
|
|
2207
|
+
return this.call(TOOL_MAP.members, { contract_id: Number(contractId) });
|
|
2208
|
+
}
|
|
2209
|
+
async tasks(contractId) {
|
|
2210
|
+
return this.call(TOOL_MAP.tasks, { contract_id: Number(contractId) });
|
|
2211
|
+
}
|
|
2212
|
+
async myJobs() {
|
|
2213
|
+
return this.call(TOOL_MAP["my-jobs"], {});
|
|
2214
|
+
}
|
|
2215
|
+
async task(eventId) {
|
|
2216
|
+
return this.call(TOOL_MAP.task, { event_id: Number(eventId) });
|
|
2217
|
+
}
|
|
2218
|
+
async children(eventId) {
|
|
2219
|
+
return this.call(TOOL_MAP.children, { event_id: Number(eventId) });
|
|
2220
|
+
}
|
|
2221
|
+
async history(eventId, opts = {}) {
|
|
2222
|
+
const args = cleanArgs({ event_id: Number(eventId), limit: opts.limit });
|
|
2223
|
+
return this.call(TOOL_MAP.history, args);
|
|
2224
|
+
}
|
|
2225
|
+
async create(contractId, opts) {
|
|
2226
|
+
const users = [];
|
|
2227
|
+
const rev = parseParticipant(opts.reviewer, ROLE_REVIEWER);
|
|
2228
|
+
if (rev !== null) users.push(rev);
|
|
2229
|
+
const qa = parseParticipant(opts.qa, ROLE_QA);
|
|
2230
|
+
if (qa !== null) users.push(qa);
|
|
2231
|
+
if (opts.participants && opts.participants.length) {
|
|
2232
|
+
users.push(...opts.participants);
|
|
2233
|
+
}
|
|
2234
|
+
const args = cleanArgs({
|
|
2235
|
+
contract_id: Number(contractId),
|
|
2236
|
+
label: opts.label,
|
|
2237
|
+
type_id: opts.type,
|
|
2238
|
+
status_id: opts.status,
|
|
2239
|
+
kal_schedule_id: opts.kalScheduleId,
|
|
2240
|
+
start: opts.start,
|
|
2241
|
+
end: opts.end,
|
|
2242
|
+
timezone: opts.timezone,
|
|
2243
|
+
date: opts.date,
|
|
2244
|
+
duration: opts.duration,
|
|
2245
|
+
amount: opts.amount,
|
|
2246
|
+
currency: opts.currency,
|
|
2247
|
+
description: opts.description,
|
|
2248
|
+
data: opts.data,
|
|
2249
|
+
benefitable: opts.benefitable !== void 0 ? parseBenefitable(opts.benefitable) : void 0,
|
|
2250
|
+
users: users.length > 0 ? users : void 0
|
|
2251
|
+
});
|
|
2252
|
+
return this.call(TOOL_MAP.create, args);
|
|
2253
|
+
}
|
|
2254
|
+
async comment(eventId, opts = {}) {
|
|
2255
|
+
const args = cleanArgs({
|
|
2256
|
+
event_id: Number(eventId),
|
|
2257
|
+
label: opts.label,
|
|
2258
|
+
type_id: opts.type,
|
|
2259
|
+
status_id: opts.status,
|
|
2260
|
+
start: opts.start,
|
|
2261
|
+
end: opts.end,
|
|
2262
|
+
date: opts.date,
|
|
2263
|
+
duration: opts.duration,
|
|
2264
|
+
amount: opts.amount,
|
|
2265
|
+
currency: opts.currency,
|
|
2266
|
+
description: opts.description,
|
|
2267
|
+
benefitable: opts.benefitable !== void 0 ? parseBenefitable(opts.benefitable) : void 0
|
|
2268
|
+
});
|
|
2269
|
+
return this.call(TOOL_MAP.comment, args);
|
|
2270
|
+
}
|
|
2271
|
+
async propose(eventId, opts = {}) {
|
|
2272
|
+
const args = cleanArgs({
|
|
2273
|
+
event_id: Number(eventId),
|
|
2274
|
+
status_id: opts.status,
|
|
2275
|
+
label: opts.label,
|
|
2276
|
+
description: opts.description,
|
|
2277
|
+
start: opts.start,
|
|
2278
|
+
end: opts.end,
|
|
2279
|
+
date: opts.date,
|
|
2280
|
+
duration: opts.duration,
|
|
2281
|
+
amount: opts.amount,
|
|
2282
|
+
currency: opts.currency,
|
|
2283
|
+
benefitable: opts.benefitable !== void 0 ? parseBenefitable(opts.benefitable) : void 0
|
|
2284
|
+
});
|
|
2285
|
+
return this.call(TOOL_MAP.propose, args);
|
|
2286
|
+
}
|
|
2287
|
+
/** Status correction (optional) + progress comment in one shot.
|
|
2288
|
+
*
|
|
2289
|
+
* The event's own description is NOT touched. `desc` becomes the
|
|
2290
|
+
* body of a child comment-event, not a label/description overwrite
|
|
2291
|
+
* on the parent event. Use this for Hand/QA/Reviewer progress
|
|
2292
|
+
* reports — `propose --desc` would clobber the parent spec.
|
|
2293
|
+
*/
|
|
2294
|
+
async progress(eventId, opts) {
|
|
2295
|
+
let statusResult = null;
|
|
2296
|
+
if (opts.status !== void 0 && opts.status !== null) {
|
|
2297
|
+
statusResult = await this.propose(eventId, { status: Number(opts.status) });
|
|
2298
|
+
}
|
|
2299
|
+
const label = deriveLabel(opts.desc);
|
|
2300
|
+
const commentResult = await this.comment(eventId, { label, description: opts.desc });
|
|
2301
|
+
return { status_correction: statusResult, comment: commentResult };
|
|
2302
|
+
}
|
|
2303
|
+
async vote(eventId, ids, vote) {
|
|
2304
|
+
return this.call(TOOL_MAP.vote, {
|
|
2305
|
+
event_id: Number(eventId),
|
|
2306
|
+
ids: ids.map((i) => Number(i)),
|
|
2307
|
+
vote: Boolean(vote)
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
// ── polling (REST, not MCP) ────────────────────────────────────
|
|
2311
|
+
/** GET /agent/polling. Returns [] on 429 (rate-limit, 10/min/token). */
|
|
2312
|
+
async poll() {
|
|
2313
|
+
const resp = await this.http.get(`${this.apiBase}/agent/polling`, {
|
|
2314
|
+
headers: { Accept: "application/json", Authorization: `Bearer ${this.token}` }
|
|
2315
|
+
});
|
|
2316
|
+
if (resp.status === 429) return [];
|
|
2317
|
+
if (resp.status !== 200) {
|
|
2318
|
+
let body2;
|
|
2319
|
+
try {
|
|
2320
|
+
body2 = await resp.json();
|
|
2321
|
+
} catch {
|
|
2322
|
+
body2 = await resp.text();
|
|
2323
|
+
}
|
|
2324
|
+
throw new ContractError(`polling HTTP ${resp.status}: ${JSON.stringify(body2).slice(0, 300)}`);
|
|
2325
|
+
}
|
|
2326
|
+
const body = await resp.json();
|
|
2327
|
+
if (Array.isArray(body)) return body;
|
|
2328
|
+
if (body && typeof body === "object") {
|
|
2329
|
+
const obj = body;
|
|
2330
|
+
for (const k of ["notifications", "data", "items"]) {
|
|
2331
|
+
const v = obj[k];
|
|
2332
|
+
if (Array.isArray(v)) return v;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
return [];
|
|
2336
|
+
}
|
|
2337
|
+
};
|
|
2338
|
+
|
|
2339
|
+
// src/timelog.ts
|
|
2340
|
+
var TOOL_MAP2 = {
|
|
2341
|
+
start: "timelog-start",
|
|
2342
|
+
stop: "timelog-stop",
|
|
2343
|
+
check: "timelog-check"
|
|
2344
|
+
};
|
|
2345
|
+
var TimelogClient = class {
|
|
2346
|
+
c;
|
|
2347
|
+
constructor(opts = {}) {
|
|
2348
|
+
if (opts.contract) {
|
|
2349
|
+
this.c = opts.contract;
|
|
2350
|
+
} else {
|
|
2351
|
+
this.c = new ContractClient(opts);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
async start(eventId) {
|
|
2355
|
+
return this.c.call(TOOL_MAP2.start, { event_id: Number(eventId) });
|
|
2356
|
+
}
|
|
2357
|
+
async stop(eventId, label) {
|
|
2358
|
+
const args = { event_id: Number(eventId) };
|
|
2359
|
+
if (label !== void 0 && label !== null) args["label"] = label;
|
|
2360
|
+
return this.c.call(TOOL_MAP2.stop, args);
|
|
2361
|
+
}
|
|
2362
|
+
async check(eventId) {
|
|
2363
|
+
return this.c.call(TOOL_MAP2.check, { event_id: Number(eventId) });
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
|
|
2367
|
+
// src/contract-cli.ts
|
|
1994
2368
|
function out(data) {
|
|
2369
|
+
if (typeof data === "string") {
|
|
2370
|
+
process.stdout.write(data + "\n");
|
|
2371
|
+
} else {
|
|
2372
|
+
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
function err(message, code = "error") {
|
|
2376
|
+
process.stderr.write(JSON.stringify({ error: message, code }) + "\n");
|
|
2377
|
+
}
|
|
2378
|
+
function parseParticipantSpec(spec) {
|
|
2379
|
+
if (!spec || typeof spec !== "string") {
|
|
2380
|
+
throw new Error(`--participant must be a non-empty string, got: ${JSON.stringify(spec)}`);
|
|
2381
|
+
}
|
|
2382
|
+
const parts = spec.split(":");
|
|
2383
|
+
if (parts.length < 3) {
|
|
2384
|
+
throw new Error(
|
|
2385
|
+
`--participant must be 'type:id:role' (e.g. agent:5:reviewer), got: ${JSON.stringify(spec)}`
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2388
|
+
const [ptype, pid, role, ...rest] = parts;
|
|
2389
|
+
if (ptype !== "agent" && ptype !== "user") {
|
|
2390
|
+
throw new Error(`--participant type must be 'agent' or 'user', got: ${JSON.stringify(ptype)}`);
|
|
2391
|
+
}
|
|
2392
|
+
const value = Number.parseInt(pid, 10);
|
|
2393
|
+
if (!Number.isFinite(value) || Number.isNaN(value)) {
|
|
2394
|
+
throw new Error(`--participant id must be int, got: ${JSON.stringify(pid)}`);
|
|
2395
|
+
}
|
|
2396
|
+
const roleMap = { reviewer: ROLE_REVIEWER, qa: ROLE_QA };
|
|
2397
|
+
let roleId;
|
|
2398
|
+
if (role in roleMap) {
|
|
2399
|
+
roleId = roleMap[role];
|
|
2400
|
+
} else if (role === "role") {
|
|
2401
|
+
if (rest.length === 0) {
|
|
2402
|
+
throw new Error(`--participant 'role:NUMBER' needs a number, got: ${JSON.stringify(spec)}`);
|
|
2403
|
+
}
|
|
2404
|
+
const n = Number.parseInt(rest[0], 10);
|
|
2405
|
+
if (!Number.isFinite(n) || Number.isNaN(n)) {
|
|
2406
|
+
throw new Error(`--participant role id must be int, got: ${JSON.stringify(rest[0])}`);
|
|
2407
|
+
}
|
|
2408
|
+
roleId = n;
|
|
2409
|
+
} else {
|
|
2410
|
+
throw new Error(
|
|
2411
|
+
`--participant unknown role ${JSON.stringify(role)}; expected 'reviewer', 'qa', or 'role:NUMBER'`
|
|
2412
|
+
);
|
|
2413
|
+
}
|
|
2414
|
+
return { participable_id: value, type: ptype, role_id: roleId };
|
|
2415
|
+
}
|
|
2416
|
+
function parseArgs(argv) {
|
|
2417
|
+
const positional = [];
|
|
2418
|
+
const flags = {};
|
|
2419
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2420
|
+
const a = argv[i];
|
|
2421
|
+
if (a.startsWith("--")) {
|
|
2422
|
+
const name = a.slice(2);
|
|
2423
|
+
const next = argv[i + 1];
|
|
2424
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
2425
|
+
flags[name] = true;
|
|
2426
|
+
} else {
|
|
2427
|
+
if (flags[name] !== void 0) {
|
|
2428
|
+
const cur = flags[name];
|
|
2429
|
+
if (Array.isArray(cur)) cur.push(next);
|
|
2430
|
+
else flags[name] = [cur, next];
|
|
2431
|
+
} else {
|
|
2432
|
+
flags[name] = next;
|
|
2433
|
+
}
|
|
2434
|
+
i++;
|
|
2435
|
+
}
|
|
2436
|
+
} else {
|
|
2437
|
+
positional.push(a);
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
return { positional, flags };
|
|
2441
|
+
}
|
|
2442
|
+
function flagStr(args, key) {
|
|
2443
|
+
const v = args.flags[key];
|
|
2444
|
+
if (v === void 0 || v === true) return void 0;
|
|
2445
|
+
if (Array.isArray(v)) return v[v.length - 1];
|
|
2446
|
+
return v;
|
|
2447
|
+
}
|
|
2448
|
+
function flagInt(args, key) {
|
|
2449
|
+
const v = flagStr(args, key);
|
|
2450
|
+
if (v === void 0) return void 0;
|
|
2451
|
+
const n = Number.parseInt(v, 10);
|
|
2452
|
+
if (Number.isNaN(n)) throw new Error(`--${key} must be int, got: ${JSON.stringify(v)}`);
|
|
2453
|
+
return n;
|
|
2454
|
+
}
|
|
2455
|
+
function flagList(args, key) {
|
|
2456
|
+
const v = args.flags[key];
|
|
2457
|
+
if (v === void 0) return [];
|
|
2458
|
+
if (v === true) return [];
|
|
2459
|
+
if (Array.isArray(v)) return v;
|
|
2460
|
+
return [v];
|
|
2461
|
+
}
|
|
2462
|
+
function requireFlag(args, key) {
|
|
2463
|
+
const v = flagStr(args, key);
|
|
2464
|
+
if (v === void 0) throw new Error(`--${key} is required`);
|
|
2465
|
+
return v;
|
|
2466
|
+
}
|
|
2467
|
+
function dump(value) {
|
|
2468
|
+
out(value);
|
|
2469
|
+
}
|
|
2470
|
+
var contractClientFactory = () => new ContractClient();
|
|
2471
|
+
var timelogClientFactory = () => new TimelogClient();
|
|
2472
|
+
async function cmdContract(argv) {
|
|
2473
|
+
const action = argv[0];
|
|
2474
|
+
if (!action) {
|
|
2475
|
+
err("contract: subcommand required", "args");
|
|
2476
|
+
return 1;
|
|
2477
|
+
}
|
|
2478
|
+
const rest = argv.slice(1);
|
|
2479
|
+
const args = parseArgs(rest);
|
|
2480
|
+
const client = contractClientFactory();
|
|
2481
|
+
try {
|
|
2482
|
+
switch (action) {
|
|
2483
|
+
case "list": {
|
|
2484
|
+
dump(await client.listContracts());
|
|
2485
|
+
return 0;
|
|
2486
|
+
}
|
|
2487
|
+
case "members": {
|
|
2488
|
+
const cid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2489
|
+
if (Number.isNaN(cid)) {
|
|
2490
|
+
err("contract members: cid required", "args");
|
|
2491
|
+
return 1;
|
|
2492
|
+
}
|
|
2493
|
+
dump(await client.members(cid));
|
|
2494
|
+
return 0;
|
|
2495
|
+
}
|
|
2496
|
+
case "tasks": {
|
|
2497
|
+
const explicit = args.positional[0];
|
|
2498
|
+
const ids = explicit !== void 0 ? [explicit] : contractIdsFromEnv();
|
|
2499
|
+
if (ids.length === 0) {
|
|
2500
|
+
err("no contract id (positional or CEKI_CONTRACT_IDS)", "args");
|
|
2501
|
+
return 1;
|
|
2502
|
+
}
|
|
2503
|
+
for (const cid of ids) {
|
|
2504
|
+
process.stdout.write(`--- contract ${cid} ---
|
|
2505
|
+
`);
|
|
2506
|
+
dump(await client.tasks(Number(cid)));
|
|
2507
|
+
}
|
|
2508
|
+
return 0;
|
|
2509
|
+
}
|
|
2510
|
+
case "my-jobs": {
|
|
2511
|
+
dump(await client.myJobs());
|
|
2512
|
+
return 0;
|
|
2513
|
+
}
|
|
2514
|
+
case "task": {
|
|
2515
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2516
|
+
if (Number.isNaN(eid)) {
|
|
2517
|
+
err("contract task: eid required", "args");
|
|
2518
|
+
return 1;
|
|
2519
|
+
}
|
|
2520
|
+
dump(await client.task(eid));
|
|
2521
|
+
return 0;
|
|
2522
|
+
}
|
|
2523
|
+
case "children": {
|
|
2524
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2525
|
+
if (Number.isNaN(eid)) {
|
|
2526
|
+
err("contract children: eid required", "args");
|
|
2527
|
+
return 1;
|
|
2528
|
+
}
|
|
2529
|
+
dump(await client.children(eid));
|
|
2530
|
+
return 0;
|
|
2531
|
+
}
|
|
2532
|
+
case "history": {
|
|
2533
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2534
|
+
if (Number.isNaN(eid)) {
|
|
2535
|
+
err("contract history: eid required", "args");
|
|
2536
|
+
return 1;
|
|
2537
|
+
}
|
|
2538
|
+
dump(await client.history(eid, { limit: flagInt(args, "limit") }));
|
|
2539
|
+
return 0;
|
|
2540
|
+
}
|
|
2541
|
+
case "create": {
|
|
2542
|
+
const explicit = args.positional[0];
|
|
2543
|
+
let cid;
|
|
2544
|
+
if (explicit !== void 0) {
|
|
2545
|
+
cid = Number.parseInt(explicit, 10);
|
|
2546
|
+
} else {
|
|
2547
|
+
const envIds = contractIdsFromEnv();
|
|
2548
|
+
if (envIds.length === 0) {
|
|
2549
|
+
err("contract id required (positional or CEKI_CONTRACT_IDS)", "args");
|
|
2550
|
+
return 1;
|
|
2551
|
+
}
|
|
2552
|
+
cid = Number.parseInt(envIds[0], 10);
|
|
2553
|
+
}
|
|
2554
|
+
if (Number.isNaN(cid)) {
|
|
2555
|
+
err("contract create: cid must be int", "args");
|
|
2556
|
+
return 1;
|
|
2557
|
+
}
|
|
2558
|
+
const label = requireFlag(args, "label");
|
|
2559
|
+
const dataRaw = flagStr(args, "data");
|
|
2560
|
+
const dataObj = dataRaw ? JSON.parse(dataRaw) : void 0;
|
|
2561
|
+
let extras = [];
|
|
2562
|
+
try {
|
|
2563
|
+
extras = flagList(args, "participant").map(parseParticipantSpec);
|
|
2564
|
+
} catch (e) {
|
|
2565
|
+
err(e.message, "args");
|
|
2566
|
+
return 1;
|
|
2567
|
+
}
|
|
2568
|
+
dump(
|
|
2569
|
+
await client.create(cid, {
|
|
2570
|
+
label,
|
|
2571
|
+
type: flagInt(args, "type"),
|
|
2572
|
+
status: flagInt(args, "status"),
|
|
2573
|
+
kalScheduleId: flagInt(args, "kal-schedule"),
|
|
2574
|
+
start: flagStr(args, "start"),
|
|
2575
|
+
end: flagStr(args, "end"),
|
|
2576
|
+
timezone: flagStr(args, "timezone"),
|
|
2577
|
+
date: flagStr(args, "date"),
|
|
2578
|
+
duration: flagInt(args, "duration"),
|
|
2579
|
+
amount: flagInt(args, "amount"),
|
|
2580
|
+
currency: flagStr(args, "currency"),
|
|
2581
|
+
description: flagStr(args, "desc"),
|
|
2582
|
+
data: dataObj,
|
|
2583
|
+
benefitable: flagStr(args, "benefitable"),
|
|
2584
|
+
reviewer: flagStr(args, "reviewer"),
|
|
2585
|
+
qa: flagStr(args, "qa"),
|
|
2586
|
+
participants: extras.length > 0 ? extras : void 0
|
|
2587
|
+
})
|
|
2588
|
+
);
|
|
2589
|
+
return 0;
|
|
2590
|
+
}
|
|
2591
|
+
case "comment": {
|
|
2592
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2593
|
+
if (Number.isNaN(eid)) {
|
|
2594
|
+
err("contract comment: eid required", "args");
|
|
2595
|
+
return 1;
|
|
2596
|
+
}
|
|
2597
|
+
dump(
|
|
2598
|
+
await client.comment(eid, {
|
|
2599
|
+
label: flagStr(args, "label"),
|
|
2600
|
+
type: flagInt(args, "type"),
|
|
2601
|
+
status: flagInt(args, "status"),
|
|
2602
|
+
start: flagStr(args, "start"),
|
|
2603
|
+
end: flagStr(args, "end"),
|
|
2604
|
+
date: flagStr(args, "date"),
|
|
2605
|
+
duration: flagInt(args, "duration"),
|
|
2606
|
+
amount: flagInt(args, "amount"),
|
|
2607
|
+
currency: flagStr(args, "currency"),
|
|
2608
|
+
description: flagStr(args, "desc"),
|
|
2609
|
+
benefitable: flagStr(args, "benefitable")
|
|
2610
|
+
})
|
|
2611
|
+
);
|
|
2612
|
+
return 0;
|
|
2613
|
+
}
|
|
2614
|
+
case "propose": {
|
|
2615
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2616
|
+
if (Number.isNaN(eid)) {
|
|
2617
|
+
err("contract propose: eid required", "args");
|
|
2618
|
+
return 1;
|
|
2619
|
+
}
|
|
2620
|
+
dump(
|
|
2621
|
+
await client.propose(eid, {
|
|
2622
|
+
status: flagInt(args, "status"),
|
|
2623
|
+
label: flagStr(args, "label"),
|
|
2624
|
+
description: flagStr(args, "desc"),
|
|
2625
|
+
start: flagStr(args, "start"),
|
|
2626
|
+
end: flagStr(args, "end"),
|
|
2627
|
+
date: flagStr(args, "date"),
|
|
2628
|
+
duration: flagInt(args, "duration"),
|
|
2629
|
+
amount: flagInt(args, "amount"),
|
|
2630
|
+
currency: flagStr(args, "currency"),
|
|
2631
|
+
benefitable: flagStr(args, "benefitable")
|
|
2632
|
+
})
|
|
2633
|
+
);
|
|
2634
|
+
return 0;
|
|
2635
|
+
}
|
|
2636
|
+
case "progress": {
|
|
2637
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2638
|
+
if (Number.isNaN(eid)) {
|
|
2639
|
+
err("contract progress: eid required", "args");
|
|
2640
|
+
return 1;
|
|
2641
|
+
}
|
|
2642
|
+
const desc = flagStr(args, "desc");
|
|
2643
|
+
if (desc === void 0) {
|
|
2644
|
+
err("contract progress: --desc is required", "args");
|
|
2645
|
+
return 1;
|
|
2646
|
+
}
|
|
2647
|
+
dump(
|
|
2648
|
+
await client.progress(eid, {
|
|
2649
|
+
status: flagInt(args, "status"),
|
|
2650
|
+
desc
|
|
2651
|
+
})
|
|
2652
|
+
);
|
|
2653
|
+
return 0;
|
|
2654
|
+
}
|
|
2655
|
+
case "vote": {
|
|
2656
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2657
|
+
if (Number.isNaN(eid)) {
|
|
2658
|
+
err("contract vote: eid required", "args");
|
|
2659
|
+
return 1;
|
|
2660
|
+
}
|
|
2661
|
+
const idsRaw = requireFlag(args, "ids");
|
|
2662
|
+
const voteRaw = requireFlag(args, "vote");
|
|
2663
|
+
const ids = idsRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => Number.parseInt(s, 10));
|
|
2664
|
+
const vote = ["true", "1", "yes"].includes(voteRaw.toLowerCase());
|
|
2665
|
+
dump(await client.vote(eid, ids, vote));
|
|
2666
|
+
return 0;
|
|
2667
|
+
}
|
|
2668
|
+
case "poll": {
|
|
2669
|
+
const items = await client.poll();
|
|
2670
|
+
dump({ count: items.length, notifications: items });
|
|
2671
|
+
return 0;
|
|
2672
|
+
}
|
|
2673
|
+
case "watch": {
|
|
2674
|
+
const interval = Math.max(6, Number.parseInt(args.positional[0] ?? "8", 10) || 8);
|
|
2675
|
+
process.stderr.write(
|
|
2676
|
+
`[watch] poll every ${interval}s (limit 10/min/token; do not go below 6s)
|
|
2677
|
+
`
|
|
2678
|
+
);
|
|
2679
|
+
while (true) {
|
|
2680
|
+
const items = await client.poll();
|
|
2681
|
+
if (items.length > 0) {
|
|
2682
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
2683
|
+
for (const n of items) {
|
|
2684
|
+
process.stdout.write(JSON.stringify({ ts, notification: n }) + "\n");
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
await new Promise((r) => setTimeout(r, interval * 1e3));
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
case "tools": {
|
|
2691
|
+
dump(await client.tools());
|
|
2692
|
+
return 0;
|
|
2693
|
+
}
|
|
2694
|
+
case "raw": {
|
|
2695
|
+
const tool = args.positional[0];
|
|
2696
|
+
if (!tool) {
|
|
2697
|
+
err("contract raw: tool name required", "args");
|
|
2698
|
+
return 1;
|
|
2699
|
+
}
|
|
2700
|
+
const payloadRaw = args.positional[1] ?? "{}";
|
|
2701
|
+
const payload = JSON.parse(payloadRaw);
|
|
2702
|
+
dump(await client.raw(tool, payload));
|
|
2703
|
+
return 0;
|
|
2704
|
+
}
|
|
2705
|
+
default: {
|
|
2706
|
+
err(`unknown contract action: ${action}`, "args");
|
|
2707
|
+
return 1;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
} catch (e) {
|
|
2711
|
+
if (e instanceof ContractError) {
|
|
2712
|
+
err(e.message, "contract");
|
|
2713
|
+
return 1;
|
|
2714
|
+
}
|
|
2715
|
+
err(e.message ?? String(e), "error");
|
|
2716
|
+
return 1;
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
async function cmdTimelog(argv) {
|
|
2720
|
+
const action = argv[0];
|
|
2721
|
+
if (!action) {
|
|
2722
|
+
err("timelog: subcommand required", "args");
|
|
2723
|
+
return 1;
|
|
2724
|
+
}
|
|
2725
|
+
const rest = argv.slice(1);
|
|
2726
|
+
const args = parseArgs(rest);
|
|
2727
|
+
const client = timelogClientFactory();
|
|
2728
|
+
try {
|
|
2729
|
+
switch (action) {
|
|
2730
|
+
case "start": {
|
|
2731
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2732
|
+
if (Number.isNaN(eid)) {
|
|
2733
|
+
err("timelog start: event_id required", "args");
|
|
2734
|
+
return 1;
|
|
2735
|
+
}
|
|
2736
|
+
dump(await client.start(eid));
|
|
2737
|
+
return 0;
|
|
2738
|
+
}
|
|
2739
|
+
case "stop": {
|
|
2740
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2741
|
+
if (Number.isNaN(eid)) {
|
|
2742
|
+
err("timelog stop: event_id required", "args");
|
|
2743
|
+
return 1;
|
|
2744
|
+
}
|
|
2745
|
+
dump(await client.stop(eid, flagStr(args, "label")));
|
|
2746
|
+
return 0;
|
|
2747
|
+
}
|
|
2748
|
+
case "check": {
|
|
2749
|
+
const eid = Number.parseInt(args.positional[0] ?? "", 10);
|
|
2750
|
+
if (Number.isNaN(eid)) {
|
|
2751
|
+
err("timelog check: event_id required", "args");
|
|
2752
|
+
return 1;
|
|
2753
|
+
}
|
|
2754
|
+
dump(await client.check(eid));
|
|
2755
|
+
return 0;
|
|
2756
|
+
}
|
|
2757
|
+
default: {
|
|
2758
|
+
err(`unknown timelog action: ${action}`, "args");
|
|
2759
|
+
return 1;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
} catch (e) {
|
|
2763
|
+
if (e instanceof ContractError) {
|
|
2764
|
+
err(e.message, "timelog");
|
|
2765
|
+
return 1;
|
|
2766
|
+
}
|
|
2767
|
+
err(e.message ?? String(e), "error");
|
|
2768
|
+
return 1;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
// src/cli.ts
|
|
2773
|
+
function out2(data) {
|
|
1995
2774
|
process.stdout.write(JSON.stringify(data) + "\n");
|
|
1996
2775
|
}
|
|
1997
|
-
function
|
|
2776
|
+
function err2(error, code = "error") {
|
|
1998
2777
|
process.stderr.write(JSON.stringify({ error, code }) + "\n");
|
|
1999
2778
|
}
|
|
2000
2779
|
function getApiKey() {
|
|
2001
2780
|
const key = process.env.CEKI_API_KEY;
|
|
2002
2781
|
if (!key) {
|
|
2003
|
-
|
|
2782
|
+
err2("CEKI_API_KEY not set", "auth");
|
|
2004
2783
|
process.exit(2);
|
|
2005
2784
|
}
|
|
2006
2785
|
return key;
|
|
@@ -2032,14 +2811,14 @@ async function cmdRent(args) {
|
|
|
2032
2811
|
if (args[i] === "--mode" && args[i + 1]) {
|
|
2033
2812
|
const v = args[++i];
|
|
2034
2813
|
if (v !== "incognito" && v !== "main") {
|
|
2035
|
-
|
|
2814
|
+
err2("invalid mode, must be incognito or main", "args");
|
|
2036
2815
|
process.exit(1);
|
|
2037
2816
|
}
|
|
2038
2817
|
mode = v;
|
|
2039
2818
|
}
|
|
2040
2819
|
}
|
|
2041
2820
|
if (scheduleId == null) {
|
|
2042
|
-
|
|
2821
|
+
err2("--schedule is required", "args");
|
|
2043
2822
|
process.exit(1);
|
|
2044
2823
|
}
|
|
2045
2824
|
const apiKey = getApiKey();
|
|
@@ -2057,7 +2836,7 @@ async function cmdRent(args) {
|
|
|
2057
2836
|
schedule_id: browser.scheduleId,
|
|
2058
2837
|
last_seen_ts: null
|
|
2059
2838
|
});
|
|
2060
|
-
|
|
2839
|
+
out2({
|
|
2061
2840
|
session_id: browser.sessionId,
|
|
2062
2841
|
chat_topic_id: browser.chatTopicId,
|
|
2063
2842
|
schedule_id: browser.scheduleId
|
|
@@ -2080,7 +2859,7 @@ async function cmdSearch(args) {
|
|
|
2080
2859
|
const client = await connect(apiKey, connectOptions());
|
|
2081
2860
|
try {
|
|
2082
2861
|
const results = await client.search(filters, limit);
|
|
2083
|
-
|
|
2862
|
+
out2(results);
|
|
2084
2863
|
} finally {
|
|
2085
2864
|
await closeClient(client);
|
|
2086
2865
|
}
|
|
@@ -2099,7 +2878,7 @@ async function cmdSessions(args) {
|
|
|
2099
2878
|
try {
|
|
2100
2879
|
const results = await client.listSessions({ active: !showAll, limit });
|
|
2101
2880
|
if (jsonOutput) {
|
|
2102
|
-
|
|
2881
|
+
out2(results);
|
|
2103
2882
|
} else {
|
|
2104
2883
|
if (!results.length) {
|
|
2105
2884
|
process.stdout.write("No sessions found.\n");
|
|
@@ -2128,7 +2907,7 @@ async function cmdMyBrowsers() {
|
|
|
2128
2907
|
const client = await connect(apiKey, connectOptions());
|
|
2129
2908
|
try {
|
|
2130
2909
|
const results = await client.myBrowsers();
|
|
2131
|
-
|
|
2910
|
+
out2(results);
|
|
2132
2911
|
} finally {
|
|
2133
2912
|
await closeClient(client);
|
|
2134
2913
|
}
|
|
@@ -2139,7 +2918,7 @@ async function cmdSnapshot(sid, args) {
|
|
|
2139
2918
|
if ((args[i] === "-o" || args[i] === "--output") && args[i + 1]) outputPath = args[++i];
|
|
2140
2919
|
}
|
|
2141
2920
|
if (!outputPath) {
|
|
2142
|
-
|
|
2921
|
+
err2("-o/--output is required", "args");
|
|
2143
2922
|
process.exit(1);
|
|
2144
2923
|
}
|
|
2145
2924
|
const apiKey = getApiKey();
|
|
@@ -2158,7 +2937,7 @@ async function cmdSnapshot(sid, args) {
|
|
|
2158
2937
|
text: m.text,
|
|
2159
2938
|
ts: m.created_at
|
|
2160
2939
|
}));
|
|
2161
|
-
|
|
2940
|
+
out2({ screenshot: outputPath, chat: chatList, ts: snap.ts.toISOString() });
|
|
2162
2941
|
} finally {
|
|
2163
2942
|
await closeClient(client);
|
|
2164
2943
|
}
|
|
@@ -2169,7 +2948,7 @@ function parseNoHuman(args) {
|
|
|
2169
2948
|
async function cmdNavigate(sid, args) {
|
|
2170
2949
|
const url = args.find((a) => !a.startsWith("--"));
|
|
2171
2950
|
if (!url) {
|
|
2172
|
-
|
|
2951
|
+
err2("URL is required", "args");
|
|
2173
2952
|
process.exit(1);
|
|
2174
2953
|
}
|
|
2175
2954
|
const raw = parseNoHuman(args);
|
|
@@ -2177,7 +2956,7 @@ async function cmdNavigate(sid, args) {
|
|
|
2177
2956
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2178
2957
|
try {
|
|
2179
2958
|
await browser.navigate(url, 3e4, raw ? { human: false } : void 0);
|
|
2180
|
-
|
|
2959
|
+
out2({ ok: true });
|
|
2181
2960
|
} finally {
|
|
2182
2961
|
await closeClient(client);
|
|
2183
2962
|
}
|
|
@@ -2187,7 +2966,7 @@ async function cmdClick(sid, args) {
|
|
|
2187
2966
|
const x = parseInt(positional[0], 10);
|
|
2188
2967
|
const y = parseInt(positional[1], 10);
|
|
2189
2968
|
if (isNaN(x) || isNaN(y)) {
|
|
2190
|
-
|
|
2969
|
+
err2("x and y coordinates are required", "args");
|
|
2191
2970
|
process.exit(1);
|
|
2192
2971
|
}
|
|
2193
2972
|
const raw = parseNoHuman(args);
|
|
@@ -2195,7 +2974,7 @@ async function cmdClick(sid, args) {
|
|
|
2195
2974
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2196
2975
|
try {
|
|
2197
2976
|
await browser.click(x, y, raw ? { human: false } : void 0);
|
|
2198
|
-
|
|
2977
|
+
out2({ ok: true, pointer: [x, y] });
|
|
2199
2978
|
} finally {
|
|
2200
2979
|
await closeClient(client);
|
|
2201
2980
|
}
|
|
@@ -2209,7 +2988,7 @@ async function cmdType(sid, args) {
|
|
|
2209
2988
|
} else if (!text) text = args[i];
|
|
2210
2989
|
}
|
|
2211
2990
|
if (!text) {
|
|
2212
|
-
|
|
2991
|
+
err2("text is required", "args");
|
|
2213
2992
|
process.exit(1);
|
|
2214
2993
|
}
|
|
2215
2994
|
const apiKey = getApiKey();
|
|
@@ -2217,7 +2996,7 @@ async function cmdType(sid, args) {
|
|
|
2217
2996
|
try {
|
|
2218
2997
|
const browser = await client.resume(sid);
|
|
2219
2998
|
await browser.type(text, raw ? { human: false } : void 0);
|
|
2220
|
-
|
|
2999
|
+
out2({ ok: true });
|
|
2221
3000
|
} finally {
|
|
2222
3001
|
await closeClient(client);
|
|
2223
3002
|
}
|
|
@@ -2228,7 +3007,7 @@ async function cmdScroll(sid, args) {
|
|
|
2228
3007
|
const y = parseInt(positional[1], 10);
|
|
2229
3008
|
const dy = parseInt(positional[2], 10);
|
|
2230
3009
|
if (isNaN(x) || isNaN(y) || isNaN(dy)) {
|
|
2231
|
-
|
|
3010
|
+
err2("x, y, dy are required", "args");
|
|
2232
3011
|
process.exit(1);
|
|
2233
3012
|
}
|
|
2234
3013
|
const raw = parseNoHuman(args);
|
|
@@ -2238,7 +3017,7 @@ async function cmdScroll(sid, args) {
|
|
|
2238
3017
|
const scrollOpts = { x, y, deltaY: dy };
|
|
2239
3018
|
if (raw) scrollOpts.human = false;
|
|
2240
3019
|
await browser.scroll(scrollOpts);
|
|
2241
|
-
|
|
3020
|
+
out2({ ok: true });
|
|
2242
3021
|
} finally {
|
|
2243
3022
|
await closeClient(client);
|
|
2244
3023
|
}
|
|
@@ -2251,11 +3030,11 @@ async function cmdChat(sid, action, args) {
|
|
|
2251
3030
|
case "send": {
|
|
2252
3031
|
const text = args[0];
|
|
2253
3032
|
if (!text) {
|
|
2254
|
-
|
|
3033
|
+
err2("text is required", "args");
|
|
2255
3034
|
process.exit(1);
|
|
2256
3035
|
}
|
|
2257
3036
|
const result = await browser.chat.send(text);
|
|
2258
|
-
|
|
3037
|
+
out2({ ok: true, message_id: result.messageId });
|
|
2259
3038
|
break;
|
|
2260
3039
|
}
|
|
2261
3040
|
case "send-image": {
|
|
@@ -2266,14 +3045,14 @@ async function cmdChat(sid, action, args) {
|
|
|
2266
3045
|
if (args[i] === "--text" && args[i + 1]) text = args[++i];
|
|
2267
3046
|
}
|
|
2268
3047
|
if (!imagePath) {
|
|
2269
|
-
|
|
3048
|
+
err2("--image is required", "args");
|
|
2270
3049
|
process.exit(1);
|
|
2271
3050
|
}
|
|
2272
3051
|
if (text) {
|
|
2273
3052
|
await browser.chat.send(text);
|
|
2274
3053
|
}
|
|
2275
3054
|
const result = await browser.chat.sendImage(imagePath);
|
|
2276
|
-
|
|
3055
|
+
out2({ ok: true, message_id: result.messageId });
|
|
2277
3056
|
break;
|
|
2278
3057
|
}
|
|
2279
3058
|
case "next": {
|
|
@@ -2286,7 +3065,7 @@ async function cmdChat(sid, action, args) {
|
|
|
2286
3065
|
if (msgs.length > 0) {
|
|
2287
3066
|
const m = msgs[0];
|
|
2288
3067
|
updateLastSeenTs(sid, m.created_at);
|
|
2289
|
-
|
|
3068
|
+
out2({ from: m.sender_id, text: m.text, ts: m.created_at });
|
|
2290
3069
|
} else {
|
|
2291
3070
|
let resolved = false;
|
|
2292
3071
|
const waitPromise = new Promise((resolve2) => {
|
|
@@ -2307,9 +3086,9 @@ async function cmdChat(sid, action, args) {
|
|
|
2307
3086
|
const msg = await waitPromise;
|
|
2308
3087
|
if (msg) {
|
|
2309
3088
|
updateLastSeenTs(sid, msg.created_at);
|
|
2310
|
-
|
|
3089
|
+
out2({ from: msg.sender_id, text: msg.text, ts: msg.created_at });
|
|
2311
3090
|
} else {
|
|
2312
|
-
|
|
3091
|
+
out2(null);
|
|
2313
3092
|
}
|
|
2314
3093
|
}
|
|
2315
3094
|
break;
|
|
@@ -2330,11 +3109,11 @@ async function cmdChat(sid, action, args) {
|
|
|
2330
3109
|
if (args[i] === "--limit" && args[i + 1]) limit = parseInt(args[++i], 10);
|
|
2331
3110
|
}
|
|
2332
3111
|
const msgs = await browser.chat.history({ since, limit });
|
|
2333
|
-
|
|
3112
|
+
out2(msgs.map((m) => ({ from: m.sender_id, text: m.text, ts: m.created_at })));
|
|
2334
3113
|
break;
|
|
2335
3114
|
}
|
|
2336
3115
|
default:
|
|
2337
|
-
|
|
3116
|
+
err2(`Unknown chat action: ${action}`, "args");
|
|
2338
3117
|
process.exit(1);
|
|
2339
3118
|
}
|
|
2340
3119
|
} finally {
|
|
@@ -2347,7 +3126,7 @@ async function cmdStop(sid) {
|
|
|
2347
3126
|
try {
|
|
2348
3127
|
await browser.close();
|
|
2349
3128
|
deleteSession(sid);
|
|
2350
|
-
|
|
3129
|
+
out2({ ok: true });
|
|
2351
3130
|
} finally {
|
|
2352
3131
|
await closeClient(client);
|
|
2353
3132
|
}
|
|
@@ -2367,7 +3146,7 @@ async function cmdProfile(sid, action, args) {
|
|
|
2367
3146
|
if (args[i] === "--no-session-storage") noSessionStorage = true;
|
|
2368
3147
|
}
|
|
2369
3148
|
if (!outputPath) {
|
|
2370
|
-
|
|
3149
|
+
err2("-o/--output is required", "args");
|
|
2371
3150
|
process.exit(1);
|
|
2372
3151
|
}
|
|
2373
3152
|
const profile = await browser.profile.export({
|
|
@@ -2375,7 +3154,7 @@ async function cmdProfile(sid, action, args) {
|
|
|
2375
3154
|
includeSessionStorage: !noSessionStorage
|
|
2376
3155
|
});
|
|
2377
3156
|
fs4.writeFileSync(outputPath, JSON.stringify(profile, null, 2), "utf-8");
|
|
2378
|
-
|
|
3157
|
+
out2({ ok: true, path: outputPath });
|
|
2379
3158
|
break;
|
|
2380
3159
|
}
|
|
2381
3160
|
case "import": {
|
|
@@ -2384,16 +3163,16 @@ async function cmdProfile(sid, action, args) {
|
|
|
2384
3163
|
if ((args[i] === "-i" || args[i] === "--input") && args[i + 1]) inputPath = args[++i];
|
|
2385
3164
|
}
|
|
2386
3165
|
if (!inputPath) {
|
|
2387
|
-
|
|
3166
|
+
err2("-i/--input is required", "args");
|
|
2388
3167
|
process.exit(1);
|
|
2389
3168
|
}
|
|
2390
3169
|
const profileData = JSON.parse(fs4.readFileSync(inputPath, "utf-8"));
|
|
2391
3170
|
await browser.profile.import(profileData);
|
|
2392
|
-
|
|
3171
|
+
out2({ ok: true });
|
|
2393
3172
|
break;
|
|
2394
3173
|
}
|
|
2395
3174
|
default:
|
|
2396
|
-
|
|
3175
|
+
err2(`Unknown profile action: ${action}`, "args");
|
|
2397
3176
|
process.exit(1);
|
|
2398
3177
|
}
|
|
2399
3178
|
} finally {
|
|
@@ -2405,7 +3184,7 @@ async function cmdWait(sid) {
|
|
|
2405
3184
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2406
3185
|
try {
|
|
2407
3186
|
const reason = await browser.waitUntilEnded();
|
|
2408
|
-
|
|
3187
|
+
out2({ ended: true, reason });
|
|
2409
3188
|
} finally {
|
|
2410
3189
|
await closeClient(client);
|
|
2411
3190
|
}
|
|
@@ -2418,7 +3197,7 @@ async function cmdScreenshot(sid, args) {
|
|
|
2418
3197
|
if (args[i] === "--full") fullPage = true;
|
|
2419
3198
|
}
|
|
2420
3199
|
if (!outputPath) {
|
|
2421
|
-
|
|
3200
|
+
err2("-o/--output is required", "args");
|
|
2422
3201
|
process.exit(1);
|
|
2423
3202
|
}
|
|
2424
3203
|
const apiKey = getApiKey();
|
|
@@ -2426,7 +3205,7 @@ async function cmdScreenshot(sid, args) {
|
|
|
2426
3205
|
try {
|
|
2427
3206
|
const data = await browser.screenshot({ format: "png", fullPage });
|
|
2428
3207
|
fs4.writeFileSync(outputPath, data);
|
|
2429
|
-
|
|
3208
|
+
out2({ ok: true, path: outputPath });
|
|
2430
3209
|
} finally {
|
|
2431
3210
|
await closeClient(client);
|
|
2432
3211
|
}
|
|
@@ -2436,7 +3215,7 @@ async function cmdSwitchTab(sid) {
|
|
|
2436
3215
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2437
3216
|
try {
|
|
2438
3217
|
await browser.switchTab();
|
|
2439
|
-
|
|
3218
|
+
out2({ ok: true });
|
|
2440
3219
|
} finally {
|
|
2441
3220
|
await closeClient(client);
|
|
2442
3221
|
}
|
|
@@ -2451,7 +3230,7 @@ async function cmdConfigure(sid, args) {
|
|
|
2451
3230
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2452
3231
|
try {
|
|
2453
3232
|
await browser.configure(opts);
|
|
2454
|
-
|
|
3233
|
+
out2({ ok: true });
|
|
2455
3234
|
} finally {
|
|
2456
3235
|
await closeClient(client);
|
|
2457
3236
|
}
|
|
@@ -2464,14 +3243,14 @@ async function cmdCdp(sid, args) {
|
|
|
2464
3243
|
if (args[i] === "--params" && args[i + 1]) params = JSON.parse(args[++i]);
|
|
2465
3244
|
}
|
|
2466
3245
|
if (!method) {
|
|
2467
|
-
|
|
3246
|
+
err2("--method is required", "args");
|
|
2468
3247
|
process.exit(1);
|
|
2469
3248
|
}
|
|
2470
3249
|
const apiKey = getApiKey();
|
|
2471
3250
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2472
3251
|
try {
|
|
2473
3252
|
const result = await browser.send({ method, params });
|
|
2474
|
-
|
|
3253
|
+
out2(result);
|
|
2475
3254
|
} finally {
|
|
2476
3255
|
await closeClient(client);
|
|
2477
3256
|
}
|
|
@@ -2493,7 +3272,7 @@ async function cmdRequestCaptcha(sid, args) {
|
|
|
2493
3272
|
completionTimeout: completion,
|
|
2494
3273
|
autoAccept: !manual
|
|
2495
3274
|
});
|
|
2496
|
-
|
|
3275
|
+
out2({
|
|
2497
3276
|
solved: result.solved,
|
|
2498
3277
|
proof_message_id: result.proofMessageId,
|
|
2499
3278
|
cancel_reason: result.cancelReason,
|
|
@@ -2503,7 +3282,7 @@ async function cmdRequestCaptcha(sid, args) {
|
|
|
2503
3282
|
if (!result.solved) process.exit(1);
|
|
2504
3283
|
} catch (e) {
|
|
2505
3284
|
if (e instanceof CaptchaTimeoutError) {
|
|
2506
|
-
|
|
3285
|
+
out2({ solved: false, cancel_reason: `timeout:${e.phase}`, child_event_id: null, correction_id: null });
|
|
2507
3286
|
process.exit(1);
|
|
2508
3287
|
}
|
|
2509
3288
|
throw e;
|
|
@@ -2523,18 +3302,18 @@ async function cmdUpload(sid, args) {
|
|
|
2523
3302
|
if (args[i] === "--mime" && args[i + 1]) mime2 = args[++i];
|
|
2524
3303
|
}
|
|
2525
3304
|
if (!selector || !filePath) {
|
|
2526
|
-
|
|
3305
|
+
err2("--selector and --file are required", "args");
|
|
2527
3306
|
process.exit(1);
|
|
2528
3307
|
}
|
|
2529
3308
|
if (!fs4.existsSync(filePath)) {
|
|
2530
|
-
|
|
3309
|
+
err2(`File not found: ${filePath}`, "args");
|
|
2531
3310
|
process.exit(1);
|
|
2532
3311
|
}
|
|
2533
3312
|
const apiKey = getApiKey();
|
|
2534
3313
|
const [client, browser] = await resumeBrowser(apiKey, sid);
|
|
2535
3314
|
try {
|
|
2536
3315
|
const result = await browser.upload(selector, filePath, filename, mime2);
|
|
2537
|
-
|
|
3316
|
+
out2(result);
|
|
2538
3317
|
} finally {
|
|
2539
3318
|
await closeClient(client);
|
|
2540
3319
|
}
|
|
@@ -2568,12 +3347,46 @@ Commands:
|
|
|
2568
3347
|
profile import <sid> -i file
|
|
2569
3348
|
stop <sid>
|
|
2570
3349
|
|
|
3350
|
+
contract list
|
|
3351
|
+
contract members <cid>
|
|
3352
|
+
contract tasks [cid] (default: CEKI_CONTRACT_IDS)
|
|
3353
|
+
contract my-jobs
|
|
3354
|
+
contract task <eid>
|
|
3355
|
+
contract children <eid>
|
|
3356
|
+
contract history <eid> [--limit N]
|
|
3357
|
+
contract create [cid] --label X [--type N] [--status N] [--kal-schedule N]
|
|
3358
|
+
[--start S] [--end E] [--timezone TZ] [--date D]
|
|
3359
|
+
[--duration N] [--amount N] [--currency C]
|
|
3360
|
+
[--benefitable agent:N|user:N]
|
|
3361
|
+
[--reviewer agent:N|user:N] [--qa agent:N|user:N]
|
|
3362
|
+
[--participant agent:N:reviewer|user:N:qa|agent:N:role:NUM]...
|
|
3363
|
+
[--desc text] [--data JSON]
|
|
3364
|
+
contract comment <eid> [--label X] [--type N] [--status N] [--start S]
|
|
3365
|
+
[--end E] [--date D] [--duration N] [--amount N]
|
|
3366
|
+
[--currency C] [--benefitable agent:N] [--desc text]
|
|
3367
|
+
contract propose <eid> [--status N] [--label X] [--desc text] [--start S]
|
|
3368
|
+
[--end E] [--date D] [--duration N] [--amount N]
|
|
3369
|
+
[--currency C] [--benefitable agent:N]
|
|
3370
|
+
contract progress <eid> [--status N] --desc TEXT
|
|
3371
|
+
contract vote <eid> --ids 1,2,3 --vote true|false
|
|
3372
|
+
contract poll
|
|
3373
|
+
contract watch [interval]
|
|
3374
|
+
contract tools
|
|
3375
|
+
contract raw <tool> [JSON]
|
|
3376
|
+
|
|
3377
|
+
timelog start <event_id>
|
|
3378
|
+
timelog stop <event_id> [--label TEXT]
|
|
3379
|
+
timelog check <event_id>
|
|
3380
|
+
|
|
2571
3381
|
Environment:
|
|
2572
3382
|
CEKI_API_KEY (required)
|
|
2573
3383
|
CEKI_RELAY_URL (default: wss://browser.ceki.me/ws/agent)
|
|
2574
3384
|
CEKI_API_URL (default: https://api.ceki.me)
|
|
2575
3385
|
CEKI_CHAT_URL (default: https://chat.ceki.me/api/chat)
|
|
2576
3386
|
CEKI_BASIC_AUTH_USER / CEKI_BASIC_AUTH_PASS (optional)
|
|
3387
|
+
CEKI_AGENT_TOKEN (contract/timelog; falls back to CEKI_API_KEY)
|
|
3388
|
+
CEKI_AGENT_MCP_ENDPOINT (override /mcp/agent endpoint)
|
|
3389
|
+
CEKI_CONTRACT_IDS (default contract for 'contract tasks'/'create')
|
|
2577
3390
|
|
|
2578
3391
|
Exit codes: 0=success, 1=error, 2=auth, 3=session_not_found, 4=timeout, 5=network`);
|
|
2579
3392
|
}
|
|
@@ -2595,6 +3408,12 @@ async function main() {
|
|
|
2595
3408
|
}
|
|
2596
3409
|
const command = argv[0];
|
|
2597
3410
|
const rest = argv.slice(1);
|
|
3411
|
+
if (command === "contract") {
|
|
3412
|
+
process.exit(await cmdContract(rest));
|
|
3413
|
+
}
|
|
3414
|
+
if (command === "timelog") {
|
|
3415
|
+
process.exit(await cmdTimelog(rest));
|
|
3416
|
+
}
|
|
2598
3417
|
switch (command) {
|
|
2599
3418
|
case "rent":
|
|
2600
3419
|
await cmdRent(rest);
|
|
@@ -2649,45 +3468,45 @@ async function main() {
|
|
|
2649
3468
|
break;
|
|
2650
3469
|
case "chat":
|
|
2651
3470
|
if (rest.length < 2) {
|
|
2652
|
-
|
|
3471
|
+
err2("Usage: ceki chat <sid> <action> [args]", "args");
|
|
2653
3472
|
process.exit(1);
|
|
2654
3473
|
}
|
|
2655
3474
|
await cmdChat(rest[0], rest[1], rest.slice(2));
|
|
2656
3475
|
break;
|
|
2657
3476
|
case "profile":
|
|
2658
3477
|
if (rest.length < 2) {
|
|
2659
|
-
|
|
3478
|
+
err2("Usage: ceki profile export|import <sid> [args]", "args");
|
|
2660
3479
|
process.exit(1);
|
|
2661
3480
|
}
|
|
2662
3481
|
await cmdProfile(rest[1], rest[0], rest.slice(2));
|
|
2663
3482
|
break;
|
|
2664
3483
|
default:
|
|
2665
|
-
|
|
3484
|
+
err2(`Unknown command: ${command}`, "args");
|
|
2666
3485
|
process.exit(1);
|
|
2667
3486
|
}
|
|
2668
3487
|
}
|
|
2669
3488
|
main().catch((e) => {
|
|
2670
3489
|
if (e instanceof SessionExpired || e instanceof SessionNotFound) {
|
|
2671
|
-
|
|
3490
|
+
err2(String(e), "session_not_found");
|
|
2672
3491
|
process.exit(3);
|
|
2673
3492
|
}
|
|
2674
3493
|
if (e instanceof NotOwner) {
|
|
2675
|
-
|
|
3494
|
+
err2(String(e), "not_owner");
|
|
2676
3495
|
process.exit(3);
|
|
2677
3496
|
}
|
|
2678
3497
|
if (e instanceof TimeoutError) {
|
|
2679
|
-
|
|
3498
|
+
err2(String(e), "timeout");
|
|
2680
3499
|
process.exit(4);
|
|
2681
3500
|
}
|
|
2682
3501
|
if (e instanceof ConnectionLost || e instanceof AuthError || e instanceof TransportError) {
|
|
2683
|
-
|
|
3502
|
+
err2(String(e), "network");
|
|
2684
3503
|
process.exit(5);
|
|
2685
3504
|
}
|
|
2686
3505
|
if (e instanceof CekiBrowserError) {
|
|
2687
|
-
|
|
3506
|
+
err2(String(e), "ceki_error");
|
|
2688
3507
|
process.exit(1);
|
|
2689
3508
|
}
|
|
2690
|
-
|
|
3509
|
+
err2(e instanceof Error ? e.message : String(e), "error");
|
|
2691
3510
|
process.exit(1);
|
|
2692
3511
|
});
|
|
2693
3512
|
//# sourceMappingURL=cli.js.map
|