@sheepbun/yips 0.1.1

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.
Files changed (99) hide show
  1. package/dist/agent/commands/command-catalog.js +243 -0
  2. package/dist/agent/commands/commands.js +418 -0
  3. package/dist/agent/conductor.js +118 -0
  4. package/dist/agent/context/code-context.js +68 -0
  5. package/dist/agent/context/memory-store.js +159 -0
  6. package/dist/agent/context/session-store.js +211 -0
  7. package/dist/agent/protocol/tool-protocol.js +160 -0
  8. package/dist/agent/skills/skills.js +327 -0
  9. package/dist/agent/tools/tool-executor.js +415 -0
  10. package/dist/agent/tools/tool-safety.js +52 -0
  11. package/dist/app/index.js +35 -0
  12. package/dist/app/repl.js +105 -0
  13. package/dist/app/update-check.js +132 -0
  14. package/dist/app/version.js +51 -0
  15. package/dist/code-context.js +68 -0
  16. package/dist/colors.js +204 -0
  17. package/dist/command-catalog.js +242 -0
  18. package/dist/commands.js +350 -0
  19. package/dist/conductor.js +94 -0
  20. package/dist/config/config.js +335 -0
  21. package/dist/config/hooks.js +187 -0
  22. package/dist/config.js +335 -0
  23. package/dist/downloader-state.js +302 -0
  24. package/dist/downloader-ui.js +289 -0
  25. package/dist/gateway/adapters/discord.js +108 -0
  26. package/dist/gateway/adapters/formatting.js +96 -0
  27. package/dist/gateway/adapters/telegram.js +106 -0
  28. package/dist/gateway/adapters/types.js +2 -0
  29. package/dist/gateway/adapters/whatsapp.js +124 -0
  30. package/dist/gateway/auth-policy.js +66 -0
  31. package/dist/gateway/core.js +87 -0
  32. package/dist/gateway/headless-conductor.js +328 -0
  33. package/dist/gateway/message-router.js +23 -0
  34. package/dist/gateway/rate-limiter.js +48 -0
  35. package/dist/gateway/runtime/backend-policy.js +18 -0
  36. package/dist/gateway/runtime/discord-bot.js +104 -0
  37. package/dist/gateway/runtime/discord-main.js +69 -0
  38. package/dist/gateway/session-manager.js +77 -0
  39. package/dist/gateway/types.js +2 -0
  40. package/dist/hardware.js +92 -0
  41. package/dist/hooks.js +187 -0
  42. package/dist/index.js +34 -0
  43. package/dist/input-engine.js +250 -0
  44. package/dist/llama-client.js +227 -0
  45. package/dist/llama-server.js +620 -0
  46. package/dist/llm/llama-client.js +227 -0
  47. package/dist/llm/llama-server.js +620 -0
  48. package/dist/llm/token-counter.js +47 -0
  49. package/dist/memory-store.js +159 -0
  50. package/dist/messages.js +59 -0
  51. package/dist/model-downloader.js +382 -0
  52. package/dist/model-manager-state.js +118 -0
  53. package/dist/model-manager-ui.js +194 -0
  54. package/dist/model-manager.js +190 -0
  55. package/dist/models/hardware.js +92 -0
  56. package/dist/models/model-downloader.js +382 -0
  57. package/dist/models/model-manager.js +190 -0
  58. package/dist/prompt-box.js +78 -0
  59. package/dist/prompt-composer.js +498 -0
  60. package/dist/repl.js +105 -0
  61. package/dist/session-store.js +211 -0
  62. package/dist/spinner.js +76 -0
  63. package/dist/title-box.js +388 -0
  64. package/dist/token-counter.js +47 -0
  65. package/dist/tool-executor.js +415 -0
  66. package/dist/tool-protocol.js +121 -0
  67. package/dist/tool-safety.js +52 -0
  68. package/dist/tui/app.js +2553 -0
  69. package/dist/tui/startup.js +56 -0
  70. package/dist/tui-input-routing.js +53 -0
  71. package/dist/tui.js +51 -0
  72. package/dist/types/app-types.js +2 -0
  73. package/dist/types.js +2 -0
  74. package/dist/ui/colors.js +204 -0
  75. package/dist/ui/downloader/downloader-state.js +302 -0
  76. package/dist/ui/downloader/downloader-ui.js +289 -0
  77. package/dist/ui/input/input-engine.js +250 -0
  78. package/dist/ui/input/tui-input-routing.js +53 -0
  79. package/dist/ui/input/vt-session.js +168 -0
  80. package/dist/ui/messages.js +59 -0
  81. package/dist/ui/model-manager/model-manager-state.js +118 -0
  82. package/dist/ui/model-manager/model-manager-ui.js +194 -0
  83. package/dist/ui/prompt/prompt-box.js +78 -0
  84. package/dist/ui/prompt/prompt-composer.js +498 -0
  85. package/dist/ui/spinner.js +76 -0
  86. package/dist/ui/title-box.js +388 -0
  87. package/dist/ui/tui/app.js +6 -0
  88. package/dist/ui/tui/autocomplete.js +85 -0
  89. package/dist/ui/tui/constants.js +18 -0
  90. package/dist/ui/tui/history.js +29 -0
  91. package/dist/ui/tui/layout.js +341 -0
  92. package/dist/ui/tui/runtime-core.js +2584 -0
  93. package/dist/ui/tui/runtime-utils.js +53 -0
  94. package/dist/ui/tui/start-tui.js +54 -0
  95. package/dist/ui/tui/startup.js +56 -0
  96. package/dist/version.js +51 -0
  97. package/dist/vt-session.js +168 -0
  98. package/install.sh +457 -0
  99. package/package.json +128 -0
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseToolProtocol = parseToolProtocol;
4
+ const TOOL_BLOCK_REGEX = /```yips-tools\s*\n([\s\S]*?)```/u;
5
+ const ALLOWED_TOOLS = new Set([
6
+ "read_file",
7
+ "write_file",
8
+ "edit_file",
9
+ "list_dir",
10
+ "grep",
11
+ "run_command"
12
+ ]);
13
+ const ALLOWED_SKILLS = new Set([
14
+ "search",
15
+ "fetch",
16
+ "build",
17
+ "todos",
18
+ "virtual_terminal"
19
+ ]);
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null;
22
+ }
23
+ function normalizeToolCall(value) {
24
+ if (!isRecord(value)) {
25
+ return null;
26
+ }
27
+ const id = value["id"];
28
+ const name = value["name"];
29
+ const args = value["arguments"];
30
+ if (typeof id !== "string" || id.trim().length === 0) {
31
+ return null;
32
+ }
33
+ if (typeof name !== "string" || !ALLOWED_TOOLS.has(name)) {
34
+ return null;
35
+ }
36
+ if (!isRecord(args)) {
37
+ return null;
38
+ }
39
+ return {
40
+ id: id.trim(),
41
+ name: name,
42
+ arguments: args
43
+ };
44
+ }
45
+ function normalizeSubagentCall(value) {
46
+ if (!isRecord(value)) {
47
+ return null;
48
+ }
49
+ const id = value["id"];
50
+ const task = value["task"];
51
+ if (typeof id !== "string" || id.trim().length === 0) {
52
+ return null;
53
+ }
54
+ if (typeof task !== "string" || task.trim().length === 0) {
55
+ return null;
56
+ }
57
+ const contextRaw = value["context"];
58
+ const context = typeof contextRaw === "string" && contextRaw.trim().length > 0 ? contextRaw : undefined;
59
+ const allowedToolsRaw = value["allowed_tools"];
60
+ const allowedTools = Array.isArray(allowedToolsRaw)
61
+ ? allowedToolsRaw
62
+ .filter((item) => typeof item === "string" && ALLOWED_TOOLS.has(item))
63
+ .map((item) => item)
64
+ : undefined;
65
+ const maxRoundsRaw = value["max_rounds"];
66
+ const maxRounds = typeof maxRoundsRaw === "number" && Number.isInteger(maxRoundsRaw) && maxRoundsRaw > 0
67
+ ? Math.min(maxRoundsRaw, 6)
68
+ : undefined;
69
+ return {
70
+ id: id.trim(),
71
+ task: task.trim(),
72
+ context,
73
+ allowedTools,
74
+ maxRounds
75
+ };
76
+ }
77
+ function normalizeSkillCall(value) {
78
+ if (!isRecord(value)) {
79
+ return null;
80
+ }
81
+ const id = value["id"];
82
+ const name = value["name"];
83
+ const args = value["arguments"];
84
+ if (typeof id !== "string" || id.trim().length === 0) {
85
+ return null;
86
+ }
87
+ if (typeof name !== "string" || !ALLOWED_SKILLS.has(name)) {
88
+ return null;
89
+ }
90
+ if (!isRecord(args)) {
91
+ return null;
92
+ }
93
+ return {
94
+ id: id.trim(),
95
+ name: name,
96
+ arguments: args
97
+ };
98
+ }
99
+ function parseToolProtocol(input) {
100
+ const match = input.match(TOOL_BLOCK_REGEX);
101
+ if (!match) {
102
+ return {
103
+ assistantText: input,
104
+ toolCalls: [],
105
+ subagentCalls: [],
106
+ skillCalls: []
107
+ };
108
+ }
109
+ const jsonBody = (match[1] ?? "").trim();
110
+ if (jsonBody.length === 0) {
111
+ return {
112
+ assistantText: input,
113
+ toolCalls: [],
114
+ subagentCalls: [],
115
+ skillCalls: []
116
+ };
117
+ }
118
+ let parsed;
119
+ try {
120
+ parsed = JSON.parse(jsonBody);
121
+ }
122
+ catch {
123
+ return {
124
+ assistantText: input,
125
+ toolCalls: [],
126
+ subagentCalls: [],
127
+ skillCalls: []
128
+ };
129
+ }
130
+ if (!isRecord(parsed)) {
131
+ return {
132
+ assistantText: input,
133
+ toolCalls: [],
134
+ subagentCalls: [],
135
+ skillCalls: []
136
+ };
137
+ }
138
+ const normalizedTools = Array.isArray(parsed["tool_calls"])
139
+ ? parsed["tool_calls"]
140
+ .map((item) => normalizeToolCall(item))
141
+ .filter((call) => call !== null)
142
+ : [];
143
+ const normalizedSubagents = Array.isArray(parsed["subagent_calls"])
144
+ ? parsed["subagent_calls"]
145
+ .map((item) => normalizeSubagentCall(item))
146
+ .filter((call) => call !== null)
147
+ : [];
148
+ const normalizedSkills = Array.isArray(parsed["skill_calls"])
149
+ ? parsed["skill_calls"]
150
+ .map((item) => normalizeSkillCall(item))
151
+ .filter((call) => call !== null)
152
+ : [];
153
+ const assistantText = input.replace(match[0], "").trim();
154
+ return {
155
+ assistantText,
156
+ toolCalls: normalizedTools,
157
+ subagentCalls: normalizedSubagents,
158
+ skillCalls: normalizedSkills
159
+ };
160
+ }
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeSearchSkill = executeSearchSkill;
4
+ exports.executeFetchSkill = executeFetchSkill;
5
+ exports.executeSkillCall = executeSkillCall;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_util_1 = require("node:util");
9
+ const node_path_1 = require("node:path");
10
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
11
+ const SEARCH_ENDPOINT = "https://duckduckgo.com/html/";
12
+ const MAX_SKILL_TIMEOUT_MS = 300_000;
13
+ function normalizeString(value) {
14
+ if (typeof value !== "string") {
15
+ return null;
16
+ }
17
+ const trimmed = value.trim();
18
+ return trimmed.length > 0 ? trimmed : null;
19
+ }
20
+ function normalizePositiveInt(value, fallback, max) {
21
+ if (typeof value === "number" && Number.isInteger(value) && value > 0) {
22
+ return Math.min(value, max);
23
+ }
24
+ if (typeof value === "string") {
25
+ const parsed = Number.parseInt(value.trim(), 10);
26
+ if (Number.isInteger(parsed) && parsed > 0) {
27
+ return Math.min(parsed, max);
28
+ }
29
+ }
30
+ return fallback;
31
+ }
32
+ function toErrorMessage(error) {
33
+ return error instanceof Error ? error.message : String(error);
34
+ }
35
+ function stripHtml(input) {
36
+ return input
37
+ .replace(/<script\b[^>]*>[\s\S]*?<\/script>/giu, " ")
38
+ .replace(/<style\b[^>]*>[\s\S]*?<\/style>/giu, " ")
39
+ .replace(/<[^>]+>/gu, " ");
40
+ }
41
+ function decodeEntities(input) {
42
+ return input
43
+ .replace(/&amp;/gu, "&")
44
+ .replace(/&quot;/gu, '"')
45
+ .replace(/&#39;/gu, "'")
46
+ .replace(/&apos;/gu, "'")
47
+ .replace(/&lt;/gu, "<")
48
+ .replace(/&gt;/gu, ">")
49
+ .replace(/&nbsp;/gu, " ");
50
+ }
51
+ function normalizeText(input) {
52
+ return decodeEntities(stripHtml(input)).replace(/\s+/gu, " ").trim();
53
+ }
54
+ function decodeDuckDuckGoHref(href) {
55
+ try {
56
+ const parsed = new URL(href, SEARCH_ENDPOINT);
57
+ if (parsed.hostname.endsWith("duckduckgo.com") && parsed.pathname === "/l/") {
58
+ const redirected = parsed.searchParams.get("uddg");
59
+ if (redirected && redirected.trim().length > 0) {
60
+ return decodeURIComponent(redirected);
61
+ }
62
+ }
63
+ return parsed.toString();
64
+ }
65
+ catch {
66
+ return href;
67
+ }
68
+ }
69
+ function parseSearchResults(html, maxResults) {
70
+ const results = [];
71
+ const anchorPattern = /<a\b[^>]*class="[^"]*result__a[^"]*"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/giu;
72
+ let match = anchorPattern.exec(html);
73
+ while (match && results.length < maxResults) {
74
+ const rawHref = match[1] ?? "";
75
+ const rawTitle = match[2] ?? "";
76
+ const title = normalizeText(rawTitle);
77
+ const url = decodeDuckDuckGoHref(rawHref);
78
+ if (title.length > 0 && url.length > 0) {
79
+ results.push({ title, url });
80
+ }
81
+ match = anchorPattern.exec(html);
82
+ }
83
+ return results;
84
+ }
85
+ async function executeSearchSkill(args, fetchImpl = fetch) {
86
+ const query = normalizeString(args["query"]) ?? normalizeString(args["q"]);
87
+ if (!query) {
88
+ return "search skill requires a non-empty 'query' argument.";
89
+ }
90
+ const maxResults = normalizePositiveInt(args["maxResults"], 5, 10);
91
+ const url = `${SEARCH_ENDPOINT}?q=${encodeURIComponent(query)}`;
92
+ const response = await fetchImpl(url, {
93
+ method: "GET",
94
+ headers: {
95
+ "user-agent": "yips/0"
96
+ }
97
+ });
98
+ if (!response.ok) {
99
+ return `search skill failed: HTTP ${response.status} ${response.statusText}`;
100
+ }
101
+ const html = await response.text();
102
+ const results = parseSearchResults(html, maxResults);
103
+ if (results.length === 0) {
104
+ return `No search results found for: ${query}`;
105
+ }
106
+ const lines = [`Search results for: ${query}`];
107
+ for (const [index, result] of results.entries()) {
108
+ lines.push(`${index + 1}. ${result.title}`);
109
+ lines.push(` ${result.url}`);
110
+ }
111
+ return lines.join("\n");
112
+ }
113
+ async function executeFetchSkill(args, fetchImpl = fetch) {
114
+ const rawUrl = normalizeString(args["url"]);
115
+ if (!rawUrl) {
116
+ return "fetch skill requires a non-empty 'url' argument.";
117
+ }
118
+ let parsed;
119
+ try {
120
+ parsed = new URL(rawUrl);
121
+ }
122
+ catch {
123
+ return "fetch skill requires a valid absolute URL.";
124
+ }
125
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
126
+ return "fetch skill only supports http/https URLs.";
127
+ }
128
+ const maxChars = normalizePositiveInt(args["maxChars"], 6000, 20000);
129
+ const response = await fetchImpl(parsed.toString(), {
130
+ method: "GET",
131
+ headers: {
132
+ "user-agent": "yips/0"
133
+ }
134
+ });
135
+ if (!response.ok) {
136
+ return `fetch skill failed: HTTP ${response.status} ${response.statusText}`;
137
+ }
138
+ const contentType = response.headers.get("content-type") ?? "unknown";
139
+ const body = await response.text();
140
+ const normalized = normalizeText(body);
141
+ const clipped = normalized.slice(0, maxChars);
142
+ const truncated = clipped.length < normalized.length;
143
+ const lines = [
144
+ `Fetched: ${parsed.toString()}`,
145
+ `Content-Type: ${contentType}`,
146
+ "",
147
+ clipped.length > 0 ? clipped : "(empty response body)"
148
+ ];
149
+ if (truncated) {
150
+ lines.push("");
151
+ lines.push(`[truncated at ${maxChars} chars]`);
152
+ }
153
+ return lines.join("\n");
154
+ }
155
+ function detectBuildCommand(workingDirectory) {
156
+ const packageJsonPath = (0, node_path_1.resolve)(workingDirectory, "package.json");
157
+ if ((0, node_fs_1.existsSync)(packageJsonPath)) {
158
+ return "npm run build";
159
+ }
160
+ const makefilePath = (0, node_path_1.resolve)(workingDirectory, "Makefile");
161
+ if ((0, node_fs_1.existsSync)(makefilePath)) {
162
+ return "make";
163
+ }
164
+ return "npm run build";
165
+ }
166
+ async function executeBuildSkill(args, context) {
167
+ const command = normalizeString(args["command"]) ?? detectBuildCommand(context.workingDirectory);
168
+ const cwdArg = normalizeString(args["cwd"]) ?? ".";
169
+ const cwd = (0, node_path_1.resolve)(context.workingDirectory, cwdArg);
170
+ const timeoutMs = normalizePositiveInt(args["timeoutMs"], 120_000, MAX_SKILL_TIMEOUT_MS);
171
+ const run = await context.vtSession.runCommand(command, {
172
+ cwd,
173
+ timeoutMs
174
+ });
175
+ return {
176
+ callId: "",
177
+ skill: "build",
178
+ status: run.exitCode === 0 ? "ok" : run.timedOut ? "timeout" : "error",
179
+ output: `Build command: ${command}\n${run.output}`.trim(),
180
+ metadata: {
181
+ cwd,
182
+ command,
183
+ exitCode: run.exitCode,
184
+ timedOut: run.timedOut
185
+ }
186
+ };
187
+ }
188
+ async function executeTodosSkill(args, context) {
189
+ const pathArg = normalizeString(args["path"]) ?? ".";
190
+ const pattern = normalizeString(args["pattern"]) ?? "TODO|FIXME|HACK|BUG";
191
+ const maxMatches = normalizePositiveInt(args["maxMatches"], 200, 2000);
192
+ const targetPath = (0, node_path_1.resolve)(context.workingDirectory, pathArg);
193
+ try {
194
+ const { stdout } = await execFileAsync("rg", [
195
+ "--line-number",
196
+ "--color",
197
+ "never",
198
+ "--max-count",
199
+ String(maxMatches),
200
+ pattern,
201
+ targetPath
202
+ ]);
203
+ const trimmed = stdout.trim();
204
+ return {
205
+ callId: "",
206
+ skill: "todos",
207
+ status: "ok",
208
+ output: trimmed.length > 0 ? trimmed : "No TODO markers found.",
209
+ metadata: { path: targetPath, pattern, maxMatches }
210
+ };
211
+ }
212
+ catch (error) {
213
+ if (typeof error === "object" && error !== null) {
214
+ const maybeCode = error.code;
215
+ const maybeStdout = error.stdout;
216
+ if (maybeCode === 1) {
217
+ return {
218
+ callId: "",
219
+ skill: "todos",
220
+ status: "ok",
221
+ output: "No TODO markers found.",
222
+ metadata: { path: targetPath, pattern, maxMatches }
223
+ };
224
+ }
225
+ if (typeof maybeStdout === "string" && maybeStdout.trim().length > 0) {
226
+ return {
227
+ callId: "",
228
+ skill: "todos",
229
+ status: "ok",
230
+ output: maybeStdout.trim(),
231
+ metadata: { path: targetPath, pattern, maxMatches }
232
+ };
233
+ }
234
+ }
235
+ return {
236
+ callId: "",
237
+ skill: "todos",
238
+ status: "error",
239
+ output: `todos skill failed: ${toErrorMessage(error)}`,
240
+ metadata: { path: targetPath, pattern, maxMatches }
241
+ };
242
+ }
243
+ }
244
+ async function executeVirtualTerminalSkill(args, context) {
245
+ const command = normalizeString(args["command"]);
246
+ if (!command) {
247
+ return {
248
+ callId: "",
249
+ skill: "virtual_terminal",
250
+ status: "error",
251
+ output: "virtual_terminal skill requires a non-empty 'command' argument."
252
+ };
253
+ }
254
+ const cwdArg = normalizeString(args["cwd"]) ?? ".";
255
+ const cwd = (0, node_path_1.resolve)(context.workingDirectory, cwdArg);
256
+ const timeoutMs = normalizePositiveInt(args["timeoutMs"], 60_000, MAX_SKILL_TIMEOUT_MS);
257
+ const run = await context.vtSession.runCommand(command, {
258
+ cwd,
259
+ timeoutMs
260
+ });
261
+ return {
262
+ callId: "",
263
+ skill: "virtual_terminal",
264
+ status: run.exitCode === 0 ? "ok" : run.timedOut ? "timeout" : "error",
265
+ output: run.output,
266
+ metadata: {
267
+ cwd,
268
+ command,
269
+ exitCode: run.exitCode,
270
+ timedOut: run.timedOut
271
+ }
272
+ };
273
+ }
274
+ async function executeSkillCall(call, context) {
275
+ try {
276
+ if (call.name === "search") {
277
+ const output = await executeSearchSkill(call.arguments, context.fetchImpl ?? fetch);
278
+ return {
279
+ callId: call.id,
280
+ skill: call.name,
281
+ status: output.startsWith("search skill failed:") || output.startsWith("search skill requires")
282
+ ? "error"
283
+ : "ok",
284
+ output
285
+ };
286
+ }
287
+ if (call.name === "fetch") {
288
+ const output = await executeFetchSkill(call.arguments, context.fetchImpl ?? fetch);
289
+ return {
290
+ callId: call.id,
291
+ skill: call.name,
292
+ status: output.startsWith("fetch skill failed:") ||
293
+ output.startsWith("fetch skill requires") ||
294
+ output.startsWith("fetch skill only supports")
295
+ ? "error"
296
+ : "ok",
297
+ output
298
+ };
299
+ }
300
+ if (call.name === "build") {
301
+ const result = await executeBuildSkill(call.arguments, context);
302
+ return { ...result, callId: call.id, skill: call.name };
303
+ }
304
+ if (call.name === "todos") {
305
+ const result = await executeTodosSkill(call.arguments, context);
306
+ return { ...result, callId: call.id, skill: call.name };
307
+ }
308
+ if (call.name === "virtual_terminal") {
309
+ const result = await executeVirtualTerminalSkill(call.arguments, context);
310
+ return { ...result, callId: call.id, skill: call.name };
311
+ }
312
+ return {
313
+ callId: call.id,
314
+ skill: call.name,
315
+ status: "error",
316
+ output: `Unsupported skill: ${call.name}`
317
+ };
318
+ }
319
+ catch (error) {
320
+ return {
321
+ callId: call.id,
322
+ skill: call.name,
323
+ status: "error",
324
+ output: `${call.name} skill failed: ${toErrorMessage(error)}`
325
+ };
326
+ }
327
+ }