orynacode-ai 1.16.8 → 1.16.10
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/package.json +1 -1
- package/src/cli/upgrade.ts +1 -0
- package/src/installation/index.ts +11 -49
- package/src/plugin/oryna.ts +28 -25
- package/src/session/processor.ts +8 -1
- package/src/session/status.ts +5 -0
- package/src/tool/registry.ts +2 -2
- package/src/tool/reply.ts +1 -1
package/package.json
CHANGED
package/src/cli/upgrade.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { InstallationVersion } from "@opencode-ai/core/installation/version"
|
|
|
6
6
|
import { GlobalBus } from "@/bus/global"
|
|
7
7
|
|
|
8
8
|
export async function upgrade() {
|
|
9
|
+
if (InstallationVersion.startsWith("0.0.0-")) return
|
|
9
10
|
const config = await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.getGlobal()))
|
|
10
11
|
if (config.autoupdate === false || Flag.OPENCODE_DISABLE_AUTOUPDATE) return
|
|
11
12
|
const method = await Installation.method()
|
|
@@ -136,11 +136,9 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|
|
136
136
|
)
|
|
137
137
|
|
|
138
138
|
const getBrewFormula = Effect.fnUntraced(function* () {
|
|
139
|
-
const tapFormula = yield* text(["brew", "list", "--formula", "
|
|
140
|
-
if (tapFormula.includes("
|
|
141
|
-
|
|
142
|
-
if (coreFormula.includes("opencode")) return "opencode"
|
|
143
|
-
return "opencode"
|
|
139
|
+
const tapFormula = yield* text(["brew", "list", "--formula", "oryna-ai/tap/orynacode"])
|
|
140
|
+
if (tapFormula.includes("orynacode")) return "oryna-ai/tap/orynacode"
|
|
141
|
+
return "oryna-ai/tap/orynacode"
|
|
144
142
|
})
|
|
145
143
|
|
|
146
144
|
const upgradeFailure = (method: Method, result?: { code: number; stdout: string; stderr: string }) => {
|
|
@@ -194,9 +192,7 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|
|
194
192
|
{ name: "yarn", command: () => text(["yarn", "global", "list"]) },
|
|
195
193
|
{ name: "pnpm", command: () => text(["pnpm", "list", "-g", "--depth=0"]) },
|
|
196
194
|
{ name: "bun", command: () => text(["bun", "pm", "ls", "-g"]) },
|
|
197
|
-
{ name: "brew", command: () => text(["brew", "list", "--formula", "
|
|
198
|
-
{ name: "scoop", command: () => text(["scoop", "list", "opencode"]) },
|
|
199
|
-
{ name: "choco", command: () => text(["choco", "list", "--limit-output", "opencode"]) },
|
|
195
|
+
{ name: "brew", command: () => text(["brew", "list", "--formula", "orynacode"]) },
|
|
200
196
|
]
|
|
201
197
|
|
|
202
198
|
checks.sort((a, b) => {
|
|
@@ -209,8 +205,7 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|
|
209
205
|
|
|
210
206
|
for (const check of checks) {
|
|
211
207
|
const output = yield* check.command()
|
|
212
|
-
const installedName =
|
|
213
|
-
check.name === "brew" || check.name === "choco" || check.name === "scoop" ? "opencode" : "opencode-ai"
|
|
208
|
+
const installedName = check.name === "brew" ? "orynacode" : "orynacode-ai"
|
|
214
209
|
if (output.includes(installedName)) {
|
|
215
210
|
return check.name
|
|
216
211
|
}
|
|
@@ -228,45 +223,18 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|
|
228
223
|
const info = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(BrewInfoV2))(infoJson)
|
|
229
224
|
return info.formulae[0].versions.stable
|
|
230
225
|
}
|
|
231
|
-
const response = yield* httpOk.execute(
|
|
232
|
-
HttpClientRequest.get("https://formulae.brew.sh/api/formula/opencode.json").pipe(
|
|
233
|
-
HttpClientRequest.acceptJson,
|
|
234
|
-
),
|
|
235
|
-
)
|
|
236
|
-
const data = yield* HttpClientResponse.schemaBodyJson(BrewFormula)(response)
|
|
237
|
-
return data.versions.stable
|
|
238
226
|
}
|
|
239
227
|
|
|
240
228
|
if (detectedMethod === "npm" || detectedMethod === "bun" || detectedMethod === "pnpm") {
|
|
241
229
|
const response = yield* httpOk.execute(
|
|
242
230
|
HttpClientRequest.get(
|
|
243
|
-
`${yield* NpmConfig.registry(process.cwd())}/
|
|
231
|
+
`${yield* NpmConfig.registry(process.cwd())}/orynacode-ai/${InstallationChannel}`,
|
|
244
232
|
).pipe(HttpClientRequest.acceptJson),
|
|
245
233
|
)
|
|
246
234
|
const data = yield* HttpClientResponse.schemaBodyJson(NpmPackage)(response)
|
|
247
235
|
return data.version
|
|
248
236
|
}
|
|
249
237
|
|
|
250
|
-
if (detectedMethod === "choco") {
|
|
251
|
-
const response = yield* httpOk.execute(
|
|
252
|
-
HttpClientRequest.get(
|
|
253
|
-
"https://community.chocolatey.org/api/v2/Packages?$filter=Id%20eq%20%27opencode%27%20and%20IsLatestVersion&$select=Version",
|
|
254
|
-
).pipe(HttpClientRequest.setHeaders({ Accept: "application/json;odata=verbose" })),
|
|
255
|
-
)
|
|
256
|
-
const data = yield* HttpClientResponse.schemaBodyJson(ChocoPackage)(response)
|
|
257
|
-
return data.d.results[0].Version
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (detectedMethod === "scoop") {
|
|
261
|
-
const response = yield* httpOk.execute(
|
|
262
|
-
HttpClientRequest.get(
|
|
263
|
-
"https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/opencode.json",
|
|
264
|
-
).pipe(HttpClientRequest.setHeaders({ Accept: "application/json" })),
|
|
265
|
-
)
|
|
266
|
-
const data = yield* HttpClientResponse.schemaBodyJson(ScoopManifest)(response)
|
|
267
|
-
return data.version
|
|
268
|
-
}
|
|
269
|
-
|
|
270
238
|
const response = yield* httpOk.execute(
|
|
271
239
|
HttpClientRequest.get("https://api.github.com/repos/oryna-ai/orynacode/releases/latest").pipe(
|
|
272
240
|
HttpClientRequest.acceptJson,
|
|
@@ -282,24 +250,24 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|
|
282
250
|
upgradeResult = yield* upgradeCurl(target)
|
|
283
251
|
break
|
|
284
252
|
case "npm":
|
|
285
|
-
upgradeResult = yield* run(["npm", "install", "-g", `
|
|
253
|
+
upgradeResult = yield* run(["npm", "install", "-g", `orynacode-ai@${target}`])
|
|
286
254
|
break
|
|
287
255
|
case "pnpm":
|
|
288
|
-
upgradeResult = yield* run(["pnpm", "install", "-g", `
|
|
256
|
+
upgradeResult = yield* run(["pnpm", "install", "-g", `orynacode-ai@${target}`])
|
|
289
257
|
break
|
|
290
258
|
case "bun":
|
|
291
|
-
upgradeResult = yield* run(["bun", "install", "-g", `
|
|
259
|
+
upgradeResult = yield* run(["bun", "install", "-g", `orynacode-ai@${target}`])
|
|
292
260
|
break
|
|
293
261
|
case "brew": {
|
|
294
262
|
const formula = yield* getBrewFormula()
|
|
295
263
|
const env = { HOMEBREW_NO_AUTO_UPDATE: "1" }
|
|
296
264
|
if (formula.includes("/")) {
|
|
297
|
-
const tap = yield* run(["brew", "tap", "
|
|
265
|
+
const tap = yield* run(["brew", "tap", "oryna-ai/tap"], { env })
|
|
298
266
|
if (tap.code !== 0) {
|
|
299
267
|
upgradeResult = tap
|
|
300
268
|
break
|
|
301
269
|
}
|
|
302
|
-
const repo = yield* text(["brew", "--repo", "
|
|
270
|
+
const repo = yield* text(["brew", "--repo", "oryna-ai/tap"])
|
|
303
271
|
const dir = repo.trim()
|
|
304
272
|
if (dir) {
|
|
305
273
|
const pull = yield* run(["git", "pull", "--ff-only"], { cwd: dir, env })
|
|
@@ -312,12 +280,6 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|
|
312
280
|
upgradeResult = yield* run(["brew", "upgrade", formula], { env })
|
|
313
281
|
break
|
|
314
282
|
}
|
|
315
|
-
case "choco":
|
|
316
|
-
upgradeResult = yield* run(["choco", "upgrade", "opencode", `--version=${target}`, "-y"])
|
|
317
|
-
break
|
|
318
|
-
case "scoop":
|
|
319
|
-
upgradeResult = yield* run(["scoop", "install", `opencode@${target}`])
|
|
320
|
-
break
|
|
321
283
|
default:
|
|
322
284
|
return yield* new UpgradeFailedError({ stderr: `Unknown installation method: ${m}` })
|
|
323
285
|
}
|
package/src/plugin/oryna.ts
CHANGED
|
@@ -224,6 +224,22 @@ function mapOrynaModels(data: Record<string, any>): Record<string, any> {
|
|
|
224
224
|
return result
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
export async function reAuthOryna(): Promise<string> {
|
|
228
|
+
const port = await startOAuthServer()
|
|
229
|
+
const state = randomState()
|
|
230
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`
|
|
231
|
+
const loginUrl = `${ORYNA_LOGIN_URL}?redirect_uri=${encodeURIComponent(redirectUri)}&state=${state}`
|
|
232
|
+
|
|
233
|
+
const tokenPromise = waitForToken(state)
|
|
234
|
+
await open(loginUrl)
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
return await tokenPromise
|
|
238
|
+
} finally {
|
|
239
|
+
stopOAuthServer()
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
227
243
|
export async function OrynaAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
228
244
|
return {
|
|
229
245
|
provider: {
|
|
@@ -251,15 +267,18 @@ export async function OrynaAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
251
267
|
|
|
252
268
|
if (jwtExpired(jwt)) {
|
|
253
269
|
if (!_refreshPromise) {
|
|
254
|
-
_refreshPromise = refreshJwt(jwt).catch(() => {
|
|
270
|
+
_refreshPromise = refreshJwt(jwt).catch(async () => {
|
|
255
271
|
_refreshPromise = undefined
|
|
256
|
-
|
|
272
|
+
log.info("oryna token refresh failed, removing stale auth")
|
|
273
|
+
await (input.client as any)._client.delete({ url: "/auth/{id}", path: { id: "oryna" } }).catch(() => {})
|
|
274
|
+
log.info("oryna stale auth removed")
|
|
275
|
+
return ""
|
|
257
276
|
})
|
|
258
277
|
}
|
|
259
278
|
jwt = await _refreshPromise
|
|
260
279
|
_refreshPromise = undefined
|
|
261
280
|
|
|
262
|
-
if (jwt !== auth.key) {
|
|
281
|
+
if (jwt && jwt !== auth.key) {
|
|
263
282
|
await input.client.auth
|
|
264
283
|
.set({
|
|
265
284
|
path: { id: "oryna" },
|
|
@@ -269,7 +288,7 @@ export async function OrynaAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
269
288
|
}
|
|
270
289
|
}
|
|
271
290
|
|
|
272
|
-
return { apiKey: jwt }
|
|
291
|
+
return jwt ? { apiKey: jwt } : {}
|
|
273
292
|
},
|
|
274
293
|
methods: [
|
|
275
294
|
{
|
|
@@ -277,36 +296,20 @@ export async function OrynaAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
277
296
|
label: "Login with Oryna AI (Browser)",
|
|
278
297
|
authorize: async () => {
|
|
279
298
|
try {
|
|
280
|
-
const
|
|
281
|
-
const state = randomState()
|
|
282
|
-
const redirectUri = `http://127.0.0.1:${port}/callback`
|
|
283
|
-
const loginUrl = `${ORYNA_LOGIN_URL}?redirect_uri=${encodeURIComponent(redirectUri)}&state=${state}`
|
|
284
|
-
|
|
285
|
-
const tokenPromise = waitForToken(state)
|
|
286
|
-
|
|
287
|
-
await open(loginUrl)
|
|
288
|
-
|
|
299
|
+
const tokenPromise = reAuthOryna()
|
|
289
300
|
return {
|
|
290
|
-
url:
|
|
301
|
+
url: ORYNA_LOGIN_URL,
|
|
291
302
|
instructions: "Complete login in your browser. This window will close automatically when done.",
|
|
292
303
|
method: "auto" as const,
|
|
293
304
|
callback: async () => {
|
|
294
305
|
try {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
type: "success" as const,
|
|
298
|
-
key: token,
|
|
299
|
-
}
|
|
300
|
-
} catch (err) {
|
|
301
|
-
log.error("oryna login callback failed", { error: err })
|
|
306
|
+
return { type: "success" as const, key: await tokenPromise }
|
|
307
|
+
} catch {
|
|
302
308
|
return { type: "failed" as const }
|
|
303
|
-
} finally {
|
|
304
|
-
stopOAuthServer()
|
|
305
309
|
}
|
|
306
310
|
},
|
|
307
311
|
}
|
|
308
|
-
} catch
|
|
309
|
-
log.error("oryna login authorize failed", { error: err })
|
|
312
|
+
} catch {
|
|
310
313
|
return {
|
|
311
314
|
url: ORYNA_LOGIN_URL,
|
|
312
315
|
instructions: "Failed to start login server. Please use API key instead.",
|
package/src/session/processor.ts
CHANGED
|
@@ -952,7 +952,14 @@ export const layer = Layer.effect(
|
|
|
952
952
|
sessionID: ctx.assistantMessage.sessionID,
|
|
953
953
|
error: ctx.assistantMessage.error,
|
|
954
954
|
})
|
|
955
|
-
|
|
955
|
+
if (
|
|
956
|
+
error.name === "ProviderAuthError" ||
|
|
957
|
+
(error.data as any)?.statusCode === 401
|
|
958
|
+
) {
|
|
959
|
+
yield* status.set(ctx.sessionID, { type: "needs_auth", providerID: String(input.model.providerID) })
|
|
960
|
+
} else {
|
|
961
|
+
yield* status.set(ctx.sessionID, { type: "idle" })
|
|
962
|
+
}
|
|
956
963
|
})
|
|
957
964
|
|
|
958
965
|
const process = Effect.fn("SessionProcessor.process")(function* (streamInput: LLM.StreamInput) {
|
package/src/session/status.ts
CHANGED
|
@@ -28,6 +28,10 @@ export const Info = Schema.Union([
|
|
|
28
28
|
Schema.Struct({
|
|
29
29
|
type: Schema.Literal("busy"),
|
|
30
30
|
}),
|
|
31
|
+
Schema.Struct({
|
|
32
|
+
type: Schema.Literal("needs_auth"),
|
|
33
|
+
providerID: Schema.String,
|
|
34
|
+
}),
|
|
31
35
|
]).annotate({ identifier: "SessionStatus" })
|
|
32
36
|
export type Info = Schema.Schema.Type<typeof Info>
|
|
33
37
|
|
|
@@ -76,6 +80,7 @@ export const layer = Layer.effect(
|
|
|
76
80
|
|
|
77
81
|
const set = Effect.fn("SessionStatus.set")(function* (sessionID: SessionID, status: Info) {
|
|
78
82
|
const data = yield* InstanceState.get(state)
|
|
83
|
+
if (status.type === "idle" && data.get(sessionID)?.type === "needs_auth") return
|
|
79
84
|
yield* events.publish(Event.Status, { sessionID, status })
|
|
80
85
|
if (status.type === "idle") {
|
|
81
86
|
yield* events.publish(Event.Idle, { sessionID })
|
package/src/tool/registry.ts
CHANGED
|
@@ -240,7 +240,7 @@ export const layer: Layer.Layer<
|
|
|
240
240
|
question: Tool.init(question),
|
|
241
241
|
lsp: Tool.init(lsptool),
|
|
242
242
|
plan: Tool.init(plan),
|
|
243
|
-
|
|
243
|
+
collab_reply: Tool.init(replytool),
|
|
244
244
|
})
|
|
245
245
|
|
|
246
246
|
return {
|
|
@@ -260,7 +260,7 @@ export const layer: Layer.Layer<
|
|
|
260
260
|
tool.search,
|
|
261
261
|
tool.skill,
|
|
262
262
|
tool.patch,
|
|
263
|
-
tool.
|
|
263
|
+
tool.collab_reply,
|
|
264
264
|
...(flags.experimentalLspTool ? [tool.lsp] : []),
|
|
265
265
|
...(flags.experimentalPlanMode && flags.client === "cli" ? [tool.plan] : []),
|
|
266
266
|
],
|