@link-assistant/agent 0.0.8
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/EXAMPLES.md +383 -0
- package/LICENSE +24 -0
- package/MODELS.md +95 -0
- package/README.md +388 -0
- package/TOOLS.md +134 -0
- package/package.json +89 -0
- package/src/agent/agent.ts +150 -0
- package/src/agent/generate.txt +75 -0
- package/src/auth/index.ts +64 -0
- package/src/bun/index.ts +96 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +119 -0
- package/src/cli/bootstrap.js +41 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/agent.ts +165 -0
- package/src/cli/cmd/cmd.ts +5 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/mcp.ts +80 -0
- package/src/cli/cmd/models.ts +58 -0
- package/src/cli/cmd/run.ts +359 -0
- package/src/cli/cmd/stats.ts +276 -0
- package/src/cli/error.ts +27 -0
- package/src/command/index.ts +73 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/config/config.ts +705 -0
- package/src/config/markdown.ts +41 -0
- package/src/file/ripgrep.ts +391 -0
- package/src/file/time.ts +38 -0
- package/src/file/watcher.ts +75 -0
- package/src/file.ts +6 -0
- package/src/flag/flag.ts +19 -0
- package/src/format/formatter.ts +248 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +52 -0
- package/src/id/id.ts +72 -0
- package/src/index.js +371 -0
- package/src/mcp/index.ts +289 -0
- package/src/patch/index.ts +622 -0
- package/src/project/bootstrap.ts +22 -0
- package/src/project/instance.ts +67 -0
- package/src/project/project.ts +105 -0
- package/src/project/state.ts +65 -0
- package/src/provider/models-macro.ts +11 -0
- package/src/provider/models.ts +98 -0
- package/src/provider/opencode.js +47 -0
- package/src/provider/provider.ts +636 -0
- package/src/provider/transform.ts +241 -0
- package/src/server/project.ts +48 -0
- package/src/server/server.ts +249 -0
- package/src/session/agent.js +204 -0
- package/src/session/compaction.ts +249 -0
- package/src/session/index.ts +380 -0
- package/src/session/message-v2.ts +758 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +356 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +105 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +147 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex.txt +318 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/grok-code.txt +1 -0
- package/src/session/prompt/plan.txt +8 -0
- package/src/session/prompt/polaris.txt +107 -0
- package/src/session/prompt/qwen.txt +109 -0
- package/src/session/prompt/summarize-turn.txt +5 -0
- package/src/session/prompt/summarize.txt +10 -0
- package/src/session/prompt/title.txt +25 -0
- package/src/session/prompt.ts +1390 -0
- package/src/session/retry.ts +53 -0
- package/src/session/revert.ts +108 -0
- package/src/session/status.ts +75 -0
- package/src/session/summary.ts +179 -0
- package/src/session/system.ts +138 -0
- package/src/session/todo.ts +36 -0
- package/src/snapshot/index.ts +197 -0
- package/src/storage/storage.ts +226 -0
- package/src/tool/bash.ts +193 -0
- package/src/tool/bash.txt +121 -0
- package/src/tool/batch.ts +173 -0
- package/src/tool/batch.txt +28 -0
- package/src/tool/codesearch.ts +123 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +604 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/glob.ts +65 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +116 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +110 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/patch.ts +188 -0
- package/src/tool/patch.txt +1 -0
- package/src/tool/read.ts +201 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +87 -0
- package/src/tool/task.ts +126 -0
- package/src/tool/task.txt +60 -0
- package/src/tool/todo.ts +39 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +66 -0
- package/src/tool/webfetch.ts +171 -0
- package/src/tool/webfetch.txt +14 -0
- package/src/tool/websearch.ts +133 -0
- package/src/tool/websearch.txt +11 -0
- package/src/tool/write.ts +33 -0
- package/src/tool/write.txt +8 -0
- package/src/util/binary.ts +41 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/error.ts +54 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +69 -0
- package/src/util/fn.ts +11 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +79 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/locale.ts +39 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +177 -0
- package/src/util/queue.ts +19 -0
- package/src/util/rpc.ts +42 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +54 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import z from "zod"
|
|
2
|
+
import { Filesystem } from "../util/filesystem"
|
|
3
|
+
import path from "path"
|
|
4
|
+
import { $ } from "bun"
|
|
5
|
+
import { Storage } from "../storage/storage"
|
|
6
|
+
import { Log } from "../util/log"
|
|
7
|
+
import { Flag } from "../flag/flag"
|
|
8
|
+
|
|
9
|
+
export namespace Project {
|
|
10
|
+
const log = Log.create({ service: "project" })
|
|
11
|
+
export const Info = z
|
|
12
|
+
.object({
|
|
13
|
+
id: z.string(),
|
|
14
|
+
worktree: z.string(),
|
|
15
|
+
vcs: z.literal("git").optional(),
|
|
16
|
+
time: z.object({
|
|
17
|
+
created: z.number(),
|
|
18
|
+
initialized: z.number().optional(),
|
|
19
|
+
}),
|
|
20
|
+
})
|
|
21
|
+
.meta({
|
|
22
|
+
ref: "Project",
|
|
23
|
+
})
|
|
24
|
+
export type Info = z.infer<typeof Info>
|
|
25
|
+
|
|
26
|
+
export async function fromDirectory(directory: string) {
|
|
27
|
+
log.info("fromDirectory", { directory })
|
|
28
|
+
const matches = Filesystem.up({ targets: [".git"], start: directory })
|
|
29
|
+
const git = await matches.next().then((x) => x.value)
|
|
30
|
+
await matches.return()
|
|
31
|
+
if (!git) {
|
|
32
|
+
const project: Info = {
|
|
33
|
+
id: "global",
|
|
34
|
+
worktree: "/",
|
|
35
|
+
vcs: "none", // No VCS
|
|
36
|
+
time: {
|
|
37
|
+
created: Date.now(),
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
await Storage.write<Info>(["project", "global"], project)
|
|
41
|
+
return project
|
|
42
|
+
}
|
|
43
|
+
let worktree = path.dirname(git)
|
|
44
|
+
const timer = log.time("git.rev-parse")
|
|
45
|
+
let id = await Bun.file(path.join(git, "opencode"))
|
|
46
|
+
.text()
|
|
47
|
+
.then((x) => x.trim())
|
|
48
|
+
.catch(() => {})
|
|
49
|
+
if (!id) {
|
|
50
|
+
const roots = await $`git rev-list --max-parents=0 --all`
|
|
51
|
+
.quiet()
|
|
52
|
+
.nothrow()
|
|
53
|
+
.cwd(worktree)
|
|
54
|
+
.text()
|
|
55
|
+
.then((x) =>
|
|
56
|
+
x
|
|
57
|
+
.split("\n")
|
|
58
|
+
.filter(Boolean)
|
|
59
|
+
.map((x) => x.trim())
|
|
60
|
+
.toSorted(),
|
|
61
|
+
)
|
|
62
|
+
id = roots[0]
|
|
63
|
+
if (id) Bun.file(path.join(git, "opencode")).write(id)
|
|
64
|
+
}
|
|
65
|
+
timer.stop()
|
|
66
|
+
if (!id) {
|
|
67
|
+
const project: Info = {
|
|
68
|
+
id: "global",
|
|
69
|
+
worktree: "/",
|
|
70
|
+
time: {
|
|
71
|
+
created: Date.now(),
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
await Storage.write<Info>(["project", "global"], project)
|
|
75
|
+
return project
|
|
76
|
+
}
|
|
77
|
+
worktree = await $`git rev-parse --path-format=absolute --show-toplevel`
|
|
78
|
+
.quiet()
|
|
79
|
+
.nothrow()
|
|
80
|
+
.cwd(worktree)
|
|
81
|
+
.text()
|
|
82
|
+
.then((x) => x.trim())
|
|
83
|
+
const project: Info = {
|
|
84
|
+
id,
|
|
85
|
+
worktree,
|
|
86
|
+
vcs: "git",
|
|
87
|
+
time: {
|
|
88
|
+
created: Date.now(),
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
await Storage.write<Info>(["project", id], project)
|
|
92
|
+
return project
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function setInitialized(projectID: string) {
|
|
96
|
+
await Storage.update<Info>(["project", projectID], (draft) => {
|
|
97
|
+
draft.time.initialized = Date.now()
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function list() {
|
|
102
|
+
const keys = await Storage.list(["project"])
|
|
103
|
+
return await Promise.all(keys.map((x) => Storage.read<Info>(x)))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Log } from "../util/log"
|
|
2
|
+
|
|
3
|
+
export namespace State {
|
|
4
|
+
interface Entry {
|
|
5
|
+
state: any
|
|
6
|
+
dispose?: (state: any) => Promise<void>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const log = Log.create({ service: "state" })
|
|
10
|
+
const recordsByKey = new Map<string, Map<any, Entry>>()
|
|
11
|
+
|
|
12
|
+
export function create<S>(root: () => string, init: () => S, dispose?: (state: Awaited<S>) => Promise<void>) {
|
|
13
|
+
return () => {
|
|
14
|
+
const key = root()
|
|
15
|
+
let entries = recordsByKey.get(key)
|
|
16
|
+
if (!entries) {
|
|
17
|
+
entries = new Map<string, Entry>()
|
|
18
|
+
recordsByKey.set(key, entries)
|
|
19
|
+
}
|
|
20
|
+
const exists = entries.get(init)
|
|
21
|
+
if (exists) return exists.state as S
|
|
22
|
+
const state = init()
|
|
23
|
+
entries.set(init, {
|
|
24
|
+
state,
|
|
25
|
+
dispose,
|
|
26
|
+
})
|
|
27
|
+
return state
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function dispose(key: string) {
|
|
32
|
+
const entries = recordsByKey.get(key)
|
|
33
|
+
if (!entries) return
|
|
34
|
+
|
|
35
|
+
log.info("waiting for state disposal to complete", { key })
|
|
36
|
+
|
|
37
|
+
let disposalFinished = false
|
|
38
|
+
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
if (!disposalFinished) {
|
|
41
|
+
log.warn(
|
|
42
|
+
"state disposal is taking an unusually long time - if it does not complete in a reasonable time, please report this as a bug",
|
|
43
|
+
{ key },
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
}, 10000).unref()
|
|
47
|
+
|
|
48
|
+
const tasks: Promise<void>[] = []
|
|
49
|
+
for (const entry of entries.values()) {
|
|
50
|
+
if (!entry.dispose) continue
|
|
51
|
+
|
|
52
|
+
const task = Promise.resolve(entry.state)
|
|
53
|
+
.then((state) => entry.dispose!(state))
|
|
54
|
+
.catch((error) => {
|
|
55
|
+
log.error("Error while disposing state:", { error, key })
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
tasks.push(task)
|
|
59
|
+
}
|
|
60
|
+
await Promise.all(tasks)
|
|
61
|
+
recordsByKey.delete(key)
|
|
62
|
+
disposalFinished = true
|
|
63
|
+
log.info("state disposal completed", { key })
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function data() {
|
|
2
|
+
const path = Bun.env.MODELS_DEV_API_JSON
|
|
3
|
+
if (path) {
|
|
4
|
+
const file = Bun.file(path)
|
|
5
|
+
if (await file.exists()) {
|
|
6
|
+
return await file.text()
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const json = await fetch("https://models.dev/api.json").then((x) => x.text())
|
|
10
|
+
return json
|
|
11
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Global } from "../global"
|
|
2
|
+
import { Log } from "../util/log"
|
|
3
|
+
import path from "path"
|
|
4
|
+
import z from "zod"
|
|
5
|
+
import { data } from "./models-macro"
|
|
6
|
+
|
|
7
|
+
export namespace ModelsDev {
|
|
8
|
+
const log = Log.create({ service: "models.dev" })
|
|
9
|
+
const filepath = path.join(Global.Path.cache, "models.json")
|
|
10
|
+
|
|
11
|
+
export const Model = z
|
|
12
|
+
.object({
|
|
13
|
+
id: z.string(),
|
|
14
|
+
name: z.string(),
|
|
15
|
+
release_date: z.string(),
|
|
16
|
+
attachment: z.boolean(),
|
|
17
|
+
reasoning: z.boolean(),
|
|
18
|
+
temperature: z.boolean(),
|
|
19
|
+
tool_call: z.boolean(),
|
|
20
|
+
cost: z.object({
|
|
21
|
+
input: z.number(),
|
|
22
|
+
output: z.number(),
|
|
23
|
+
cache_read: z.number().optional(),
|
|
24
|
+
cache_write: z.number().optional(),
|
|
25
|
+
context_over_200k: z
|
|
26
|
+
.object({
|
|
27
|
+
input: z.number(),
|
|
28
|
+
output: z.number(),
|
|
29
|
+
cache_read: z.number().optional(),
|
|
30
|
+
cache_write: z.number().optional(),
|
|
31
|
+
})
|
|
32
|
+
.optional(),
|
|
33
|
+
}),
|
|
34
|
+
limit: z.object({
|
|
35
|
+
context: z.number(),
|
|
36
|
+
output: z.number(),
|
|
37
|
+
}),
|
|
38
|
+
modalities: z
|
|
39
|
+
.object({
|
|
40
|
+
input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
|
|
41
|
+
output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
|
|
42
|
+
})
|
|
43
|
+
.optional(),
|
|
44
|
+
experimental: z.boolean().optional(),
|
|
45
|
+
status: z.enum(["alpha", "beta", "deprecated"]).optional(),
|
|
46
|
+
options: z.record(z.string(), z.any()),
|
|
47
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
48
|
+
provider: z.object({ npm: z.string() }).optional(),
|
|
49
|
+
})
|
|
50
|
+
.meta({
|
|
51
|
+
ref: "Model",
|
|
52
|
+
})
|
|
53
|
+
export type Model = z.infer<typeof Model>
|
|
54
|
+
|
|
55
|
+
export const Provider = z
|
|
56
|
+
.object({
|
|
57
|
+
api: z.string().optional(),
|
|
58
|
+
name: z.string(),
|
|
59
|
+
env: z.array(z.string()),
|
|
60
|
+
id: z.string(),
|
|
61
|
+
npm: z.string().optional(),
|
|
62
|
+
models: z.record(z.string(), Model),
|
|
63
|
+
})
|
|
64
|
+
.meta({
|
|
65
|
+
ref: "Provider",
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
export type Provider = z.infer<typeof Provider>
|
|
69
|
+
|
|
70
|
+
export async function get() {
|
|
71
|
+
refresh()
|
|
72
|
+
const file = Bun.file(filepath)
|
|
73
|
+
const result = await file.json().catch(() => {})
|
|
74
|
+
if (result) return result as Record<string, Provider>
|
|
75
|
+
const json = await data()
|
|
76
|
+
return JSON.parse(json) as Record<string, Provider>
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function refresh() {
|
|
80
|
+
const file = Bun.file(filepath)
|
|
81
|
+
log.info("refreshing", {
|
|
82
|
+
file,
|
|
83
|
+
})
|
|
84
|
+
const result = await fetch("https://models.dev/api.json", {
|
|
85
|
+
headers: {
|
|
86
|
+
"User-Agent": "agent-cli/1.0.0",
|
|
87
|
+
},
|
|
88
|
+
signal: AbortSignal.timeout(10 * 1000),
|
|
89
|
+
}).catch((e) => {
|
|
90
|
+
log.error("Failed to fetch models.dev", {
|
|
91
|
+
error: e,
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
if (result && result.ok) await Bun.write(file, await result.text())
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
setInterval(() => ModelsDev.refresh(), 60 * 1000 * 60).unref()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Permalink: https://github.com/sst/opencode/blob/main/packages/opencode/src/provider/provider.ts
|
|
2
|
+
|
|
3
|
+
import { createOpenCode } from '@opencode-ai/sdk'
|
|
4
|
+
|
|
5
|
+
class OpenCodeProvider {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'opencode'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async getModel(modelId) {
|
|
11
|
+
// For grok-code, return a model that uses the opencode API
|
|
12
|
+
if (modelId === 'grok-code') {
|
|
13
|
+
return {
|
|
14
|
+
id: 'grok-code',
|
|
15
|
+
provider: this,
|
|
16
|
+
generateText: async (options) => {
|
|
17
|
+
// Use opencode API
|
|
18
|
+
const opencode = await createOpenCode()
|
|
19
|
+
const { client } = opencode
|
|
20
|
+
|
|
21
|
+
const sessionResult = await client.session.create()
|
|
22
|
+
const sessionId = sessionResult.data?.id
|
|
23
|
+
|
|
24
|
+
await client.session.prompt({
|
|
25
|
+
path: { id: sessionId },
|
|
26
|
+
body: {
|
|
27
|
+
agent: "build",
|
|
28
|
+
model: { providerID: "opencode", modelID: "grok-code" },
|
|
29
|
+
parts: [{ type: "text", text: options.prompt }]
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// For simplicity, return a mock response
|
|
34
|
+
return {
|
|
35
|
+
text: 'Hello from Grok Code!',
|
|
36
|
+
usage: { promptTokens: 10, completionTokens: 5 }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
throw new Error(`Model ${modelId} not found`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const opencodeProvider = new OpenCodeProvider()
|
|
46
|
+
|
|
47
|
+
export { opencodeProvider }
|