owletto 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,41 +1,39 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  parseGlobalFlags
4
- } from "./chunk-XND7KOWH.js";
4
+ } from "./chunk-NG33L2S7.js";
5
5
  import {
6
6
  CliError
7
- } from "./chunk-ESFNDADB.js";
7
+ } from "./chunk-LPKFXYXP.js";
8
8
  import {
9
- printError
10
- } from "./chunk-AQRA3MYH.js";
9
+ defineCommand,
10
+ printError,
11
+ runMain
12
+ } from "./chunk-TMPMAYY4.js";
11
13
  import "./chunk-QGM4M3NI.js";
12
14
 
13
- // src/bin.ts
14
- import { runMain } from "citty";
15
-
16
15
  // src/main.ts
17
- import { defineCommand } from "citty";
18
16
  var main = defineCommand({
19
17
  meta: {
20
18
  name: "owletto",
21
19
  description: "Unified CLI for Owletto"
22
20
  },
23
21
  subCommands: {
24
- version: () => import("./version-W46WPOSI.js").then((m) => m.default),
25
- context: () => import("./context-REO6DUR5.js").then((m) => m.default),
26
- login: () => import("./openclaw-3J6IH47E.js").then((m) => m.login),
27
- token: () => import("./openclaw-3J6IH47E.js").then((m) => m.token),
28
- health: () => import("./openclaw-3J6IH47E.js").then((m) => m.health),
29
- configure: () => import("./openclaw-3J6IH47E.js").then((m) => m.configure),
30
- db: () => import("./db-ISICJAGW.js").then((m) => m.default),
31
- dev: () => import("./dev-EUVPKCOU.js").then((m) => m.default),
32
- doctor: () => import("./doctor-NB76DKAH.js").then((m) => m.default),
33
- server: () => import("./server-PWKDT56X.js").then((m) => m.default),
34
- worker: () => import("./worker-S3BDMAET.js").then((m) => m.default),
35
- embeddings: () => import("./embeddings-BLXQTSKP.js").then((m) => m.default),
36
- connector: () => import("./connector-W37CK37D.js").then((m) => m.default),
37
- feed: () => import("./feed-JGCNLMLO.js").then((m) => m.default),
38
- mcp: () => import("./mcp-SDFMQ3PD.js").then((m) => m.default)
22
+ version: () => import("./version-6NLY47MV.js").then((m) => m.default),
23
+ context: () => import("./context-R36C4KTS.js").then((m) => m.default),
24
+ login: () => import("./openclaw-NN7EIOSB.js").then((m) => m.login),
25
+ token: () => import("./openclaw-NN7EIOSB.js").then((m) => m.token),
26
+ health: () => import("./openclaw-NN7EIOSB.js").then((m) => m.health),
27
+ configure: () => import("./openclaw-NN7EIOSB.js").then((m) => m.configure),
28
+ db: () => import("./db-APU4VTB6.js").then((m) => m.default),
29
+ dev: () => import("./dev-EVH2ITQ7.js").then((m) => m.default),
30
+ doctor: () => import("./doctor-XONDHUND.js").then((m) => m.default),
31
+ server: () => import("./server-5GYVVR2T.js").then((m) => m.default),
32
+ worker: () => import("./worker-ETZD3I3B.js").then((m) => m.default),
33
+ embeddings: () => import("./embeddings-AH3BLVFN.js").then((m) => m.default),
34
+ connector: () => import("./connector-WVYEJLPU.js").then((m) => m.default),
35
+ feed: () => import("./feed-QKU5LWE6.js").then((m) => m.default),
36
+ mcp: () => import("./mcp-M2P7KK4C.js").then((m) => m.default)
39
37
  }
40
38
  });
41
39
 
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CliError,
3
3
  DependencyError
4
- } from "./chunk-ESFNDADB.js";
4
+ } from "./chunk-LPKFXYXP.js";
5
5
 
6
6
  // src/lib/process-runner.ts
7
7
  import { execFileSync, spawn } from "child_process";
@@ -1,3 +1,31 @@
1
+ // src/lib/errors.ts
2
+ var CliError = class extends Error {
3
+ constructor(message, exitCode = 1) {
4
+ super(message);
5
+ this.exitCode = exitCode;
6
+ this.name = "CliError";
7
+ }
8
+ };
9
+ var ValidationError = class extends CliError {
10
+ constructor(message) {
11
+ super(message, 2);
12
+ this.name = "ValidationError";
13
+ }
14
+ };
15
+ var DependencyError = class extends CliError {
16
+ constructor(binary) {
17
+ super(`Required binary "${binary}" not found. Install it and ensure it's on your PATH.`, 127);
18
+ this.name = "DependencyError";
19
+ }
20
+ };
21
+ var ApiError = class extends CliError {
22
+ constructor(message, status) {
23
+ super(message, 3);
24
+ this.status = status;
25
+ this.name = "ApiError";
26
+ }
27
+ };
28
+
1
29
  // src/lib/openclaw-auth.ts
2
30
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
3
31
  import { homedir } from "os";
@@ -108,14 +136,81 @@ function listContexts(storePath) {
108
136
  return { key, mcpUrl, org, active: key === store.activeContext, session };
109
137
  });
110
138
  }
139
+ function isTokenFresh(session) {
140
+ if (!session.accessToken) return false;
141
+ if (!session.accessTokenExpiresAt) return true;
142
+ const expiresAt = new Date(session.accessTokenExpiresAt).getTime();
143
+ return Number.isFinite(expiresAt) && expiresAt > Date.now() + 6e4;
144
+ }
145
+ function computeExpiryIso(expiresInSeconds) {
146
+ if (!expiresInSeconds || !Number.isFinite(expiresInSeconds)) return void 0;
147
+ return new Date(Date.now() + Math.max(0, Math.floor(expiresInSeconds)) * 1e3).toISOString();
148
+ }
149
+ async function refreshAccessToken(session) {
150
+ const body = {
151
+ grant_type: "refresh_token",
152
+ client_id: session.clientId,
153
+ refresh_token: session.refreshToken
154
+ };
155
+ if (session.clientSecret) {
156
+ body.client_secret = session.clientSecret;
157
+ }
158
+ const res = await fetch(`${session.issuer}/oauth/token`, {
159
+ method: "POST",
160
+ headers: { "Content-Type": "application/json" },
161
+ body: JSON.stringify(body)
162
+ });
163
+ if (!res.ok) {
164
+ const text = await res.text();
165
+ throw new Error(`OAuth refresh failed: ${res.status} ${text}`);
166
+ }
167
+ const token = await res.json();
168
+ if (!token.access_token) {
169
+ throw new Error("OAuth refresh response missing access_token");
170
+ }
171
+ return {
172
+ ...session,
173
+ accessToken: token.access_token,
174
+ refreshToken: token.refresh_token || session.refreshToken,
175
+ scope: token.scope || session.scope,
176
+ tokenType: token.token_type || session.tokenType || "Bearer",
177
+ accessTokenExpiresAt: computeExpiryIso(token.expires_in),
178
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
179
+ };
180
+ }
181
+ async function getUsableToken(mcpUrl, org, storePath) {
182
+ let session = null;
183
+ let path;
184
+ if (mcpUrl) {
185
+ const result = getStoredSession(mcpUrl, org, storePath);
186
+ session = result.session;
187
+ path = result.path;
188
+ } else {
189
+ const active = getActiveSession(storePath);
190
+ session = active.session;
191
+ path = active.path;
192
+ }
193
+ if (!session) return null;
194
+ if (isTokenFresh(session)) {
195
+ return { token: session.accessToken, session, storePath: path };
196
+ }
197
+ const refreshed = await refreshAccessToken(session);
198
+ upsertStoredSession(refreshed, refreshed.organizationSlug, path);
199
+ if (!refreshed.accessToken) return null;
200
+ return { token: refreshed.accessToken, session: refreshed, storePath: path };
201
+ }
111
202
 
112
203
  export {
204
+ CliError,
205
+ ValidationError,
206
+ DependencyError,
207
+ ApiError,
113
208
  sessionKey,
114
209
  normalizeMcpUrl,
115
210
  deriveMcpUrl,
116
- getStoredSession,
117
211
  upsertStoredSession,
118
212
  getActiveSession,
119
213
  setActiveContextByKey,
120
- listContexts
214
+ listContexts,
215
+ getUsableToken
121
216
  };
@@ -1,9 +1,10 @@
1
1
  import {
2
- ValidationError
3
- } from "./chunk-ESFNDADB.js";
2
+ ValidationError,
3
+ getActiveSession
4
+ } from "./chunk-LPKFXYXP.js";
4
5
  import {
5
6
  setOutputMode
6
- } from "./chunk-AQRA3MYH.js";
7
+ } from "./chunk-TMPMAYY4.js";
7
8
 
8
9
  // src/lib/config.ts
9
10
  import { existsSync, readFileSync } from "fs";
@@ -51,6 +52,15 @@ function resolveProfile(profileFlag, contextName) {
51
52
  const configPath = findConfigFile();
52
53
  const requestedName = profileFlag ?? process.env.OWLETTO_PROFILE ?? contextName ?? null;
53
54
  if (!configPath) {
55
+ const { session } = getActiveSession();
56
+ if (session?.mcpUrl) {
57
+ const origin = new URL(session.mcpUrl).origin;
58
+ return {
59
+ name: requestedName ?? "default",
60
+ config: { ...DEFAULT_PROFILE, apiUrl: origin },
61
+ configPath: null
62
+ };
63
+ }
54
64
  return {
55
65
  name: requestedName ?? "default",
56
66
  config: DEFAULT_PROFILE,