@hasna/browser 0.3.2 → 0.3.4
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/index.js +999 -299
- package/dist/index.js +75 -22
- package/dist/mcp/index.js +1086 -338
- package/dist/server/index.js +90 -40
- package/package.json +1 -1
- package/dashboard/dist/assets/index-Cy4XUbL1.js +0 -40
- package/dashboard/dist/index.html +0 -16
- package/dist/cli/commands/browse.d.ts +0 -3
- package/dist/cli/commands/browse.d.ts.map +0 -1
- package/dist/cli/commands/script.d.ts +0 -3
- package/dist/cli/commands/script.d.ts.map +0 -1
- package/dist/cli/commands/session.d.ts +0 -3
- package/dist/cli/commands/session.d.ts.map +0 -1
- package/dist/cli/commands/tools.d.ts +0 -3
- package/dist/cli/commands/tools.d.ts.map +0 -1
- package/dist/cli/index.d.ts +0 -3
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.test.d.ts +0 -2
- package/dist/cli/index.test.d.ts.map +0 -1
- package/dist/db/agents.d.ts +0 -16
- package/dist/db/agents.d.ts.map +0 -1
- package/dist/db/agents.test.d.ts +0 -2
- package/dist/db/agents.test.d.ts.map +0 -1
- package/dist/db/console-log.d.ts +0 -6
- package/dist/db/console-log.d.ts.map +0 -1
- package/dist/db/crawl-results.d.ts +0 -6
- package/dist/db/crawl-results.d.ts.map +0 -1
- package/dist/db/gallery.d.ts +0 -26
- package/dist/db/gallery.d.ts.map +0 -1
- package/dist/db/gallery.test.d.ts +0 -2
- package/dist/db/gallery.test.d.ts.map +0 -1
- package/dist/db/heartbeats.d.ts +0 -6
- package/dist/db/heartbeats.d.ts.map +0 -1
- package/dist/db/network-log.d.ts +0 -7
- package/dist/db/network-log.d.ts.map +0 -1
- package/dist/db/projects.d.ts +0 -9
- package/dist/db/projects.d.ts.map +0 -1
- package/dist/db/projects.test.d.ts +0 -2
- package/dist/db/projects.test.d.ts.map +0 -1
- package/dist/db/recordings.d.ts +0 -11
- package/dist/db/recordings.d.ts.map +0 -1
- package/dist/db/recordings.test.d.ts +0 -2
- package/dist/db/recordings.test.d.ts.map +0 -1
- package/dist/db/schema.d.ts +0 -5
- package/dist/db/schema.d.ts.map +0 -1
- package/dist/db/schema.test.d.ts +0 -2
- package/dist/db/schema.test.d.ts.map +0 -1
- package/dist/db/scripts.d.ts +0 -84
- package/dist/db/scripts.d.ts.map +0 -1
- package/dist/db/sessions.d.ts +0 -35
- package/dist/db/sessions.d.ts.map +0 -1
- package/dist/db/sessions.test.d.ts +0 -2
- package/dist/db/sessions.test.d.ts.map +0 -1
- package/dist/db/snapshots.d.ts +0 -7
- package/dist/db/snapshots.d.ts.map +0 -1
- package/dist/db/timeline.d.ts +0 -11
- package/dist/db/timeline.d.ts.map +0 -1
- package/dist/engines/bun-webview.d.ts +0 -147
- package/dist/engines/bun-webview.d.ts.map +0 -1
- package/dist/engines/bun-webview.test.d.ts +0 -2
- package/dist/engines/bun-webview.test.d.ts.map +0 -1
- package/dist/engines/cdp.d.ts +0 -27
- package/dist/engines/cdp.d.ts.map +0 -1
- package/dist/engines/lightpanda.d.ts +0 -25
- package/dist/engines/lightpanda.d.ts.map +0 -1
- package/dist/engines/playwright.d.ts +0 -27
- package/dist/engines/playwright.d.ts.map +0 -1
- package/dist/engines/selector.d.ts +0 -17
- package/dist/engines/selector.d.ts.map +0 -1
- package/dist/engines/selector.test.d.ts +0 -2
- package/dist/engines/selector.test.d.ts.map +0 -1
- package/dist/index.d.ts +0 -28
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/actions-ref.test.d.ts +0 -2
- package/dist/lib/actions-ref.test.d.ts.map +0 -1
- package/dist/lib/actions.d.ts +0 -91
- package/dist/lib/actions.d.ts.map +0 -1
- package/dist/lib/actions.test.d.ts +0 -2
- package/dist/lib/actions.test.d.ts.map +0 -1
- package/dist/lib/agents.d.ts +0 -9
- package/dist/lib/agents.d.ts.map +0 -1
- package/dist/lib/agents.test.d.ts +0 -2
- package/dist/lib/agents.test.d.ts.map +0 -1
- package/dist/lib/ai-inference.d.ts +0 -21
- package/dist/lib/ai-inference.d.ts.map +0 -1
- package/dist/lib/ai-task.d.ts +0 -23
- package/dist/lib/ai-task.d.ts.map +0 -1
- package/dist/lib/annotate.d.ts +0 -18
- package/dist/lib/annotate.d.ts.map +0 -1
- package/dist/lib/annotate.test.d.ts +0 -2
- package/dist/lib/annotate.test.d.ts.map +0 -1
- package/dist/lib/api-detector.d.ts +0 -17
- package/dist/lib/api-detector.d.ts.map +0 -1
- package/dist/lib/auth-flow.d.ts +0 -43
- package/dist/lib/auth-flow.d.ts.map +0 -1
- package/dist/lib/auth.d.ts +0 -28
- package/dist/lib/auth.d.ts.map +0 -1
- package/dist/lib/console.d.ts +0 -6
- package/dist/lib/console.d.ts.map +0 -1
- package/dist/lib/coordination.d.ts +0 -12
- package/dist/lib/coordination.d.ts.map +0 -1
- package/dist/lib/crawler.d.ts +0 -3
- package/dist/lib/crawler.d.ts.map +0 -1
- package/dist/lib/cron-manager.d.ts +0 -43
- package/dist/lib/cron-manager.d.ts.map +0 -1
- package/dist/lib/daemon-client.d.ts +0 -16
- package/dist/lib/daemon-client.d.ts.map +0 -1
- package/dist/lib/datasets.d.ts +0 -33
- package/dist/lib/datasets.d.ts.map +0 -1
- package/dist/lib/deep-performance.d.ts +0 -49
- package/dist/lib/deep-performance.d.ts.map +0 -1
- package/dist/lib/dialogs.d.ts +0 -15
- package/dist/lib/dialogs.d.ts.map +0 -1
- package/dist/lib/downloads.d.ts +0 -15
- package/dist/lib/downloads.d.ts.map +0 -1
- package/dist/lib/downloads.test.d.ts +0 -2
- package/dist/lib/downloads.test.d.ts.map +0 -1
- package/dist/lib/env-detector.d.ts +0 -12
- package/dist/lib/env-detector.d.ts.map +0 -1
- package/dist/lib/extractor.d.ts +0 -22
- package/dist/lib/extractor.d.ts.map +0 -1
- package/dist/lib/extractor.test.d.ts +0 -2
- package/dist/lib/extractor.test.d.ts.map +0 -1
- package/dist/lib/files-integration.d.ts +0 -13
- package/dist/lib/files-integration.d.ts.map +0 -1
- package/dist/lib/gallery-diff.d.ts +0 -3
- package/dist/lib/gallery-diff.d.ts.map +0 -1
- package/dist/lib/integrations.test.d.ts +0 -2
- package/dist/lib/integrations.test.d.ts.map +0 -1
- package/dist/lib/login-scripts.d.ts +0 -89
- package/dist/lib/login-scripts.d.ts.map +0 -1
- package/dist/lib/network.d.ts +0 -11
- package/dist/lib/network.d.ts.map +0 -1
- package/dist/lib/network.test.d.ts +0 -2
- package/dist/lib/network.test.d.ts.map +0 -1
- package/dist/lib/page-memory.d.ts +0 -14
- package/dist/lib/page-memory.d.ts.map +0 -1
- package/dist/lib/performance.d.ts +0 -13
- package/dist/lib/performance.d.ts.map +0 -1
- package/dist/lib/profiles.d.ts +0 -23
- package/dist/lib/profiles.d.ts.map +0 -1
- package/dist/lib/qol.test.d.ts +0 -2
- package/dist/lib/qol.test.d.ts.map +0 -1
- package/dist/lib/recorder.d.ts +0 -11
- package/dist/lib/recorder.d.ts.map +0 -1
- package/dist/lib/recorder.test.d.ts +0 -2
- package/dist/lib/recorder.test.d.ts.map +0 -1
- package/dist/lib/ref-cache.d.ts +0 -9
- package/dist/lib/ref-cache.d.ts.map +0 -1
- package/dist/lib/sanitize.d.ts +0 -21
- package/dist/lib/sanitize.d.ts.map +0 -1
- package/dist/lib/screenshot-v4.test.d.ts +0 -2
- package/dist/lib/screenshot-v4.test.d.ts.map +0 -1
- package/dist/lib/screenshot.d.ts +0 -11
- package/dist/lib/screenshot.d.ts.map +0 -1
- package/dist/lib/screenshot.test.d.ts +0 -2
- package/dist/lib/screenshot.test.d.ts.map +0 -1
- package/dist/lib/script-engine.d.ts +0 -28
- package/dist/lib/script-engine.d.ts.map +0 -1
- package/dist/lib/self-heal.d.ts +0 -18
- package/dist/lib/self-heal.d.ts.map +0 -1
- package/dist/lib/session-v3.test.d.ts +0 -2
- package/dist/lib/session-v3.test.d.ts.map +0 -1
- package/dist/lib/session.d.ts +0 -38
- package/dist/lib/session.d.ts.map +0 -1
- package/dist/lib/skills-runner.d.ts +0 -14
- package/dist/lib/skills-runner.d.ts.map +0 -1
- package/dist/lib/snapshot-diff.test.d.ts +0 -2
- package/dist/lib/snapshot-diff.test.d.ts.map +0 -1
- package/dist/lib/snapshot.d.ts +0 -34
- package/dist/lib/snapshot.d.ts.map +0 -1
- package/dist/lib/snapshot.test.d.ts +0 -2
- package/dist/lib/snapshot.test.d.ts.map +0 -1
- package/dist/lib/stealth.d.ts +0 -5
- package/dist/lib/stealth.d.ts.map +0 -1
- package/dist/lib/stealth.test.d.ts +0 -2
- package/dist/lib/stealth.test.d.ts.map +0 -1
- package/dist/lib/storage-state.d.ts +0 -15
- package/dist/lib/storage-state.d.ts.map +0 -1
- package/dist/lib/storage.d.ts +0 -19
- package/dist/lib/storage.d.ts.map +0 -1
- package/dist/lib/structured-extract.d.ts +0 -26
- package/dist/lib/structured-extract.d.ts.map +0 -1
- package/dist/lib/tabs.d.ts +0 -18
- package/dist/lib/tabs.d.ts.map +0 -1
- package/dist/lib/task-queue.d.ts +0 -21
- package/dist/lib/task-queue.d.ts.map +0 -1
- package/dist/lib/url-watcher.d.ts +0 -33
- package/dist/lib/url-watcher.d.ts.map +0 -1
- package/dist/lib/vision-fallback.d.ts +0 -29
- package/dist/lib/vision-fallback.d.ts.map +0 -1
- package/dist/lib/workflows.d.ts +0 -46
- package/dist/lib/workflows.d.ts.map +0 -1
- package/dist/mcp/actions.d.ts +0 -3
- package/dist/mcp/actions.d.ts.map +0 -1
- package/dist/mcp/capture.d.ts +0 -3
- package/dist/mcp/capture.d.ts.map +0 -1
- package/dist/mcp/data.d.ts +0 -3
- package/dist/mcp/data.d.ts.map +0 -1
- package/dist/mcp/gallery.test.d.ts +0 -2
- package/dist/mcp/gallery.test.d.ts.map +0 -1
- package/dist/mcp/helpers.d.ts +0 -55
- package/dist/mcp/helpers.d.ts.map +0 -1
- package/dist/mcp/index.d.ts +0 -3
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.test.d.ts +0 -2
- package/dist/mcp/index.test.d.ts.map +0 -1
- package/dist/mcp/meta.d.ts +0 -3
- package/dist/mcp/meta.d.ts.map +0 -1
- package/dist/mcp/network.d.ts +0 -3
- package/dist/mcp/network.d.ts.map +0 -1
- package/dist/mcp/recordings.d.ts +0 -3
- package/dist/mcp/recordings.d.ts.map +0 -1
- package/dist/mcp/scripts.d.ts +0 -3
- package/dist/mcp/scripts.d.ts.map +0 -1
- package/dist/mcp/sessions.d.ts +0 -3
- package/dist/mcp/sessions.d.ts.map +0 -1
- package/dist/mcp/v4.test.d.ts +0 -2
- package/dist/mcp/v4.test.d.ts.map +0 -1
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.test.d.ts +0 -2
- package/dist/server/index.test.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -425
- package/dist/types/index.d.ts.map +0 -1
package/dist/mcp/index.js
CHANGED
|
@@ -6,39 +6,60 @@ var __defProp = Object.defineProperty;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
function __accessProp(key) {
|
|
10
|
+
return this[key];
|
|
11
|
+
}
|
|
12
|
+
var __toESMCache_node;
|
|
13
|
+
var __toESMCache_esm;
|
|
9
14
|
var __toESM = (mod, isNodeMode, target) => {
|
|
15
|
+
var canCache = mod != null && typeof mod === "object";
|
|
16
|
+
if (canCache) {
|
|
17
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
18
|
+
var cached = cache.get(mod);
|
|
19
|
+
if (cached)
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
10
22
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
11
23
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
12
24
|
for (let key of __getOwnPropNames(mod))
|
|
13
25
|
if (!__hasOwnProp.call(to, key))
|
|
14
26
|
__defProp(to, key, {
|
|
15
|
-
get: (
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
16
28
|
enumerable: true
|
|
17
29
|
});
|
|
30
|
+
if (canCache)
|
|
31
|
+
cache.set(mod, to);
|
|
18
32
|
return to;
|
|
19
33
|
};
|
|
20
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
34
|
var __toCommonJS = (from) => {
|
|
22
|
-
var entry = __moduleCache.get(from), desc;
|
|
35
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
23
36
|
if (entry)
|
|
24
37
|
return entry;
|
|
25
38
|
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
40
|
+
for (var key of __getOwnPropNames(from))
|
|
41
|
+
if (!__hasOwnProp.call(entry, key))
|
|
42
|
+
__defProp(entry, key, {
|
|
43
|
+
get: __accessProp.bind(from, key),
|
|
44
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
45
|
+
});
|
|
46
|
+
}
|
|
31
47
|
__moduleCache.set(from, entry);
|
|
32
48
|
return entry;
|
|
33
49
|
};
|
|
50
|
+
var __moduleCache;
|
|
34
51
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
52
|
+
var __returnValue = (v) => v;
|
|
53
|
+
function __exportSetter(name, newValue) {
|
|
54
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
55
|
+
}
|
|
35
56
|
var __export = (target, all) => {
|
|
36
57
|
for (var name in all)
|
|
37
58
|
__defProp(target, name, {
|
|
38
59
|
get: all[name],
|
|
39
60
|
enumerable: true,
|
|
40
61
|
configurable: true,
|
|
41
|
-
set: (
|
|
62
|
+
set: __exportSetter.bind(all, name)
|
|
42
63
|
});
|
|
43
64
|
};
|
|
44
65
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -110,10 +131,30 @@ __export(exports_schema, {
|
|
|
110
131
|
});
|
|
111
132
|
import { Database } from "bun:sqlite";
|
|
112
133
|
import { join } from "path";
|
|
113
|
-
import { mkdirSync } from "fs";
|
|
134
|
+
import { mkdirSync, existsSync, readdirSync, copyFileSync, statSync } from "fs";
|
|
114
135
|
import { homedir } from "os";
|
|
115
136
|
function getDataDir() {
|
|
116
|
-
|
|
137
|
+
if (process.env["BROWSER_DATA_DIR"])
|
|
138
|
+
return process.env["BROWSER_DATA_DIR"];
|
|
139
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
140
|
+
const newDir = join(home, ".hasna", "browser");
|
|
141
|
+
const oldDir = join(home, ".browser");
|
|
142
|
+
if (existsSync(oldDir) && !existsSync(newDir)) {
|
|
143
|
+
mkdirSync(newDir, { recursive: true });
|
|
144
|
+
try {
|
|
145
|
+
for (const file of readdirSync(oldDir)) {
|
|
146
|
+
const oldPath = join(oldDir, file);
|
|
147
|
+
const newPath = join(newDir, file);
|
|
148
|
+
try {
|
|
149
|
+
if (statSync(oldPath).isFile()) {
|
|
150
|
+
copyFileSync(oldPath, newPath);
|
|
151
|
+
}
|
|
152
|
+
} catch {}
|
|
153
|
+
}
|
|
154
|
+
} catch {}
|
|
155
|
+
}
|
|
156
|
+
mkdirSync(newDir, { recursive: true });
|
|
157
|
+
return newDir;
|
|
117
158
|
}
|
|
118
159
|
function getDatabase(path) {
|
|
119
160
|
const resolvedPath = path ?? process.env["BROWSER_DB_PATH"] ?? join(getDataDir(), "browser.db");
|
|
@@ -640,10 +681,15 @@ class BrowserPool {
|
|
|
640
681
|
this.pool.push({ browser, inUse: true, createdAt: Date.now() });
|
|
641
682
|
return browser;
|
|
642
683
|
}
|
|
643
|
-
return new Promise((resolve) => {
|
|
684
|
+
return new Promise((resolve, reject) => {
|
|
685
|
+
const timeout = setTimeout(() => {
|
|
686
|
+
clearInterval(interval);
|
|
687
|
+
reject(new BrowserError("Browser pool exhausted \u2014 no browser became available within 30s", "POOL_TIMEOUT", true));
|
|
688
|
+
}, 30000);
|
|
644
689
|
const interval = setInterval(() => {
|
|
645
690
|
const free = this.pool.find((e) => !e.inUse);
|
|
646
691
|
if (free) {
|
|
692
|
+
clearTimeout(timeout);
|
|
647
693
|
clearInterval(interval);
|
|
648
694
|
free.inUse = true;
|
|
649
695
|
resolve(free.browser);
|
|
@@ -684,7 +730,7 @@ function isLightpandaAvailable() {
|
|
|
684
730
|
const paths = [
|
|
685
731
|
"/usr/local/bin/lightpanda",
|
|
686
732
|
"/usr/bin/lightpanda",
|
|
687
|
-
`${process.env["HOME"]}/.browser/bin/lightpanda`
|
|
733
|
+
`${process.env["HOME"]}/.hasna/browser/bin/lightpanda`
|
|
688
734
|
];
|
|
689
735
|
return paths.some((p) => {
|
|
690
736
|
try {
|
|
@@ -703,7 +749,7 @@ function getLightpandaBinaryPath() {
|
|
|
703
749
|
"lightpanda",
|
|
704
750
|
"/usr/local/bin/lightpanda",
|
|
705
751
|
"/usr/bin/lightpanda",
|
|
706
|
-
`${process.env["HOME"]}/.browser/bin/lightpanda`
|
|
752
|
+
`${process.env["HOME"]}/.hasna/browser/bin/lightpanda`
|
|
707
753
|
];
|
|
708
754
|
for (const p of paths) {
|
|
709
755
|
try {
|
|
@@ -777,18 +823,18 @@ var init_lightpanda = __esm(() => {
|
|
|
777
823
|
// src/engines/bun-webview.ts
|
|
778
824
|
import { join as join2 } from "path";
|
|
779
825
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
780
|
-
import { homedir as homedir2 } from "os";
|
|
781
826
|
function isBunWebViewAvailable() {
|
|
782
827
|
return typeof globalThis.Bun !== "undefined" && typeof globalThis.Bun.WebView !== "undefined";
|
|
783
828
|
}
|
|
784
829
|
function getProfileDir(profileName) {
|
|
785
|
-
const base =
|
|
830
|
+
const base = getDataDir();
|
|
786
831
|
const dir = join2(base, "profiles", profileName);
|
|
787
832
|
mkdirSync2(dir, { recursive: true });
|
|
788
833
|
return dir;
|
|
789
834
|
}
|
|
790
835
|
var BunWebViewSession;
|
|
791
836
|
var init_bun_webview = __esm(() => {
|
|
837
|
+
init_schema();
|
|
792
838
|
BunWebViewSession = class BunWebViewSession {
|
|
793
839
|
view;
|
|
794
840
|
_sessionId;
|
|
@@ -1246,6 +1292,7 @@ function enableNetworkLogging(page, sessionId) {
|
|
|
1246
1292
|
};
|
|
1247
1293
|
const onResponse = (res) => {
|
|
1248
1294
|
const start = requestStart.get(res.url()) ?? Date.now();
|
|
1295
|
+
requestStart.delete(res.url());
|
|
1249
1296
|
const duration = Date.now() - start;
|
|
1250
1297
|
const req = res.request();
|
|
1251
1298
|
try {
|
|
@@ -1262,11 +1309,17 @@ function enableNetworkLogging(page, sessionId) {
|
|
|
1262
1309
|
});
|
|
1263
1310
|
} catch {}
|
|
1264
1311
|
};
|
|
1312
|
+
const onRequestFailed = (req) => {
|
|
1313
|
+
requestStart.delete(req.url());
|
|
1314
|
+
};
|
|
1265
1315
|
page.on("request", onRequest);
|
|
1266
1316
|
page.on("response", onResponse);
|
|
1317
|
+
page.on("requestfailed", onRequestFailed);
|
|
1267
1318
|
return () => {
|
|
1268
1319
|
page.off("request", onRequest);
|
|
1269
1320
|
page.off("response", onResponse);
|
|
1321
|
+
page.off("requestfailed", onRequestFailed);
|
|
1322
|
+
requestStart.clear();
|
|
1270
1323
|
};
|
|
1271
1324
|
}
|
|
1272
1325
|
async function addInterceptRule(page, rule) {
|
|
@@ -1300,6 +1353,7 @@ function startHAR(page) {
|
|
|
1300
1353
|
const start = requestStart.get(key);
|
|
1301
1354
|
if (!start)
|
|
1302
1355
|
return;
|
|
1356
|
+
requestStart.delete(key);
|
|
1303
1357
|
const duration = Date.now() - start.time;
|
|
1304
1358
|
const entry = {
|
|
1305
1359
|
startedDateTime: new Date(start.time).toISOString(),
|
|
@@ -1322,15 +1376,20 @@ function startHAR(page) {
|
|
|
1322
1376
|
timings: { send: 0, wait: duration, receive: 0 }
|
|
1323
1377
|
};
|
|
1324
1378
|
entries.push(entry);
|
|
1325
|
-
|
|
1379
|
+
};
|
|
1380
|
+
const onRequestFailed = (req) => {
|
|
1381
|
+
requestStart.delete(req.url() + req.method());
|
|
1326
1382
|
};
|
|
1327
1383
|
page.on("request", onRequest);
|
|
1328
1384
|
page.on("response", onResponse);
|
|
1385
|
+
page.on("requestfailed", onRequestFailed);
|
|
1329
1386
|
return {
|
|
1330
1387
|
entries,
|
|
1331
1388
|
stop: () => {
|
|
1332
1389
|
page.off("request", onRequest);
|
|
1333
1390
|
page.off("response", onResponse);
|
|
1391
|
+
page.off("requestfailed", onRequestFailed);
|
|
1392
|
+
requestStart.clear();
|
|
1334
1393
|
return {
|
|
1335
1394
|
log: {
|
|
1336
1395
|
version: "1.2",
|
|
@@ -1696,9 +1755,8 @@ __export(exports_storage_state, {
|
|
|
1696
1755
|
listStates: () => listStates,
|
|
1697
1756
|
deleteState: () => deleteState
|
|
1698
1757
|
});
|
|
1699
|
-
import { mkdirSync as mkdirSync3, existsSync, readdirSync, unlinkSync } from "fs";
|
|
1758
|
+
import { mkdirSync as mkdirSync3, existsSync as existsSync2, readdirSync as readdirSync2, unlinkSync } from "fs";
|
|
1700
1759
|
import { join as join3 } from "path";
|
|
1701
|
-
import { homedir as homedir3 } from "os";
|
|
1702
1760
|
function ensureDir() {
|
|
1703
1761
|
mkdirSync3(STATES_DIR, { recursive: true });
|
|
1704
1762
|
}
|
|
@@ -1716,11 +1774,11 @@ async function saveStateFromPage(page, name) {
|
|
|
1716
1774
|
}
|
|
1717
1775
|
function loadStatePath(name) {
|
|
1718
1776
|
const path = statePath(name);
|
|
1719
|
-
return
|
|
1777
|
+
return existsSync2(path) ? path : null;
|
|
1720
1778
|
}
|
|
1721
1779
|
function listStates() {
|
|
1722
1780
|
ensureDir();
|
|
1723
|
-
return
|
|
1781
|
+
return readdirSync2(STATES_DIR).filter((f) => f.endsWith(".json")).map((f) => {
|
|
1724
1782
|
const path = join3(STATES_DIR, f);
|
|
1725
1783
|
const stat = Bun.file(path);
|
|
1726
1784
|
return {
|
|
@@ -1732,7 +1790,7 @@ function listStates() {
|
|
|
1732
1790
|
}
|
|
1733
1791
|
function deleteState(name) {
|
|
1734
1792
|
const path = statePath(name);
|
|
1735
|
-
if (
|
|
1793
|
+
if (existsSync2(path)) {
|
|
1736
1794
|
unlinkSync(path);
|
|
1737
1795
|
return true;
|
|
1738
1796
|
}
|
|
@@ -1740,7 +1798,8 @@ function deleteState(name) {
|
|
|
1740
1798
|
}
|
|
1741
1799
|
var STATES_DIR;
|
|
1742
1800
|
var init_storage_state = __esm(() => {
|
|
1743
|
-
|
|
1801
|
+
init_schema();
|
|
1802
|
+
STATES_DIR = join3(getDataDir(), "states");
|
|
1744
1803
|
});
|
|
1745
1804
|
|
|
1746
1805
|
// src/lib/session.ts
|
|
@@ -9789,6 +9848,121 @@ var init_recorder = __esm(() => {
|
|
|
9789
9848
|
activeRecordings = new Map;
|
|
9790
9849
|
});
|
|
9791
9850
|
|
|
9851
|
+
// src/db/agents.ts
|
|
9852
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
9853
|
+
function registerAgent(name, opts = {}) {
|
|
9854
|
+
const db = getDatabase();
|
|
9855
|
+
const existing = db.query("SELECT * FROM agents WHERE name = ?").get(name);
|
|
9856
|
+
if (existing) {
|
|
9857
|
+
db.prepare("UPDATE agents SET last_seen = datetime('now'), session_id = ?, project_id = ?, working_dir = ? WHERE name = ?").run(opts.sessionId ?? existing.session_id ?? null, opts.projectId ?? existing.project_id ?? null, opts.workingDir ?? existing.working_dir ?? null, name);
|
|
9858
|
+
return getAgentByName(name);
|
|
9859
|
+
}
|
|
9860
|
+
const id = randomUUID7();
|
|
9861
|
+
db.prepare("INSERT INTO agents (id, name, description, session_id, project_id, working_dir) VALUES (?, ?, ?, ?, ?, ?)").run(id, name, opts.description ?? null, opts.sessionId ?? null, opts.projectId ?? null, opts.workingDir ?? null);
|
|
9862
|
+
return getAgent(id);
|
|
9863
|
+
}
|
|
9864
|
+
function heartbeat(agentId) {
|
|
9865
|
+
const db = getDatabase();
|
|
9866
|
+
const agent = db.query("SELECT * FROM agents WHERE id = ?").get(agentId);
|
|
9867
|
+
if (!agent)
|
|
9868
|
+
throw new AgentNotFoundError(agentId);
|
|
9869
|
+
db.prepare("UPDATE agents SET last_seen = datetime('now') WHERE id = ?").run(agentId);
|
|
9870
|
+
db.prepare("INSERT INTO heartbeats (id, agent_id, session_id) VALUES (?, ?, ?)").run(randomUUID7(), agentId, agent.session_id ?? null);
|
|
9871
|
+
}
|
|
9872
|
+
function getAgent(id) {
|
|
9873
|
+
const db = getDatabase();
|
|
9874
|
+
const row = db.query("SELECT * FROM agents WHERE id = ?").get(id);
|
|
9875
|
+
if (!row)
|
|
9876
|
+
throw new AgentNotFoundError(id);
|
|
9877
|
+
return row;
|
|
9878
|
+
}
|
|
9879
|
+
function getAgentByName(name) {
|
|
9880
|
+
const db = getDatabase();
|
|
9881
|
+
return db.query("SELECT * FROM agents WHERE name = ?").get(name) ?? null;
|
|
9882
|
+
}
|
|
9883
|
+
function listAgents(projectId) {
|
|
9884
|
+
const db = getDatabase();
|
|
9885
|
+
if (projectId) {
|
|
9886
|
+
return db.query("SELECT * FROM agents WHERE project_id = ? ORDER BY last_seen DESC").all(projectId);
|
|
9887
|
+
}
|
|
9888
|
+
return db.query("SELECT * FROM agents ORDER BY last_seen DESC").all();
|
|
9889
|
+
}
|
|
9890
|
+
function updateAgent(id, data) {
|
|
9891
|
+
const db = getDatabase();
|
|
9892
|
+
const fields = [];
|
|
9893
|
+
const values = [];
|
|
9894
|
+
if (data.name !== undefined) {
|
|
9895
|
+
fields.push("name = ?");
|
|
9896
|
+
values.push(data.name ?? null);
|
|
9897
|
+
}
|
|
9898
|
+
if (data.description !== undefined) {
|
|
9899
|
+
fields.push("description = ?");
|
|
9900
|
+
values.push(data.description ?? null);
|
|
9901
|
+
}
|
|
9902
|
+
if (data.session_id !== undefined) {
|
|
9903
|
+
fields.push("session_id = ?");
|
|
9904
|
+
values.push(data.session_id ?? null);
|
|
9905
|
+
}
|
|
9906
|
+
if (data.project_id !== undefined) {
|
|
9907
|
+
fields.push("project_id = ?");
|
|
9908
|
+
values.push(data.project_id ?? null);
|
|
9909
|
+
}
|
|
9910
|
+
if (data.working_dir !== undefined) {
|
|
9911
|
+
fields.push("working_dir = ?");
|
|
9912
|
+
values.push(data.working_dir ?? null);
|
|
9913
|
+
}
|
|
9914
|
+
if (fields.length === 0)
|
|
9915
|
+
return getAgent(id);
|
|
9916
|
+
values.push(id);
|
|
9917
|
+
db.prepare(`UPDATE agents SET ${fields.join(", ")} WHERE id = ?`).run(...values);
|
|
9918
|
+
return getAgent(id);
|
|
9919
|
+
}
|
|
9920
|
+
function deleteAgent(id) {
|
|
9921
|
+
const db = getDatabase();
|
|
9922
|
+
db.prepare("DELETE FROM agents WHERE id = ?").run(id);
|
|
9923
|
+
}
|
|
9924
|
+
function cleanStaleAgents(thresholdMs) {
|
|
9925
|
+
const db = getDatabase();
|
|
9926
|
+
const cutoff = new Date(Date.now() - thresholdMs).toISOString().replace("T", " ").split(".")[0];
|
|
9927
|
+
const result = db.prepare("DELETE FROM agents WHERE last_seen < ?").run(cutoff);
|
|
9928
|
+
return result.changes;
|
|
9929
|
+
}
|
|
9930
|
+
var init_agents = __esm(() => {
|
|
9931
|
+
init_schema();
|
|
9932
|
+
init_types();
|
|
9933
|
+
});
|
|
9934
|
+
|
|
9935
|
+
// src/lib/agents.ts
|
|
9936
|
+
var exports_agents = {};
|
|
9937
|
+
__export(exports_agents, {
|
|
9938
|
+
updateAgent: () => updateAgent,
|
|
9939
|
+
registerAgent: () => registerAgent2,
|
|
9940
|
+
listAgents: () => listAgents,
|
|
9941
|
+
isAgentStale: () => isAgentStale,
|
|
9942
|
+
heartbeat: () => heartbeat2,
|
|
9943
|
+
getAgentByName: () => getAgentByName,
|
|
9944
|
+
getAgent: () => getAgent,
|
|
9945
|
+
getActiveAgents: () => getActiveAgents,
|
|
9946
|
+
deleteAgent: () => deleteAgent,
|
|
9947
|
+
cleanStaleAgents: () => cleanStaleAgents
|
|
9948
|
+
});
|
|
9949
|
+
function registerAgent2(name, opts = {}) {
|
|
9950
|
+
return registerAgent(name, opts);
|
|
9951
|
+
}
|
|
9952
|
+
function heartbeat2(agentId) {
|
|
9953
|
+
heartbeat(agentId);
|
|
9954
|
+
}
|
|
9955
|
+
function isAgentStale(agent, thresholdMs = 5 * 60 * 1000) {
|
|
9956
|
+
const lastSeen = new Date(agent.last_seen).getTime();
|
|
9957
|
+
return Date.now() - lastSeen > thresholdMs;
|
|
9958
|
+
}
|
|
9959
|
+
function getActiveAgents(thresholdMs = 5 * 60 * 1000) {
|
|
9960
|
+
return listAgents().filter((a) => !isAgentStale(a, thresholdMs));
|
|
9961
|
+
}
|
|
9962
|
+
var init_agents2 = __esm(() => {
|
|
9963
|
+
init_agents();
|
|
9964
|
+
});
|
|
9965
|
+
|
|
9792
9966
|
// src/lib/profiles.ts
|
|
9793
9967
|
var exports_profiles = {};
|
|
9794
9968
|
__export(exports_profiles, {
|
|
@@ -9798,11 +9972,10 @@ __export(exports_profiles, {
|
|
|
9798
9972
|
deleteProfile: () => deleteProfile,
|
|
9799
9973
|
applyProfile: () => applyProfile
|
|
9800
9974
|
});
|
|
9801
|
-
import { mkdirSync as mkdirSync8, existsSync as
|
|
9975
|
+
import { mkdirSync as mkdirSync8, existsSync as existsSync5, readdirSync as readdirSync4, rmSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
9802
9976
|
import { join as join8 } from "path";
|
|
9803
|
-
import { homedir as homedir8 } from "os";
|
|
9804
9977
|
function getProfilesDir() {
|
|
9805
|
-
const dataDir =
|
|
9978
|
+
const dataDir = getDataDir();
|
|
9806
9979
|
const dir = join8(dataDir, "profiles");
|
|
9807
9980
|
mkdirSync8(dir, { recursive: true });
|
|
9808
9981
|
return dir;
|
|
@@ -9841,17 +10014,17 @@ async function saveProfile(page, name) {
|
|
|
9841
10014
|
}
|
|
9842
10015
|
function loadProfile(name) {
|
|
9843
10016
|
const dir = getProfileDir2(name);
|
|
9844
|
-
if (!
|
|
10017
|
+
if (!existsSync5(dir)) {
|
|
9845
10018
|
throw new Error(`Profile not found: ${name}`);
|
|
9846
10019
|
}
|
|
9847
10020
|
const cookiesPath = join8(dir, "cookies.json");
|
|
9848
10021
|
const storagePath = join8(dir, "storage.json");
|
|
9849
10022
|
const metaPath2 = join8(dir, "meta.json");
|
|
9850
|
-
const cookies =
|
|
9851
|
-
const localStorage2 =
|
|
10023
|
+
const cookies = existsSync5(cookiesPath) ? JSON.parse(readFileSync2(cookiesPath, "utf8")) : [];
|
|
10024
|
+
const localStorage2 = existsSync5(storagePath) ? JSON.parse(readFileSync2(storagePath, "utf8")) : {};
|
|
9852
10025
|
let savedAt = new Date().toISOString();
|
|
9853
10026
|
let url;
|
|
9854
|
-
if (
|
|
10027
|
+
if (existsSync5(metaPath2)) {
|
|
9855
10028
|
const meta = JSON.parse(readFileSync2(metaPath2, "utf8"));
|
|
9856
10029
|
savedAt = meta.saved_at ?? savedAt;
|
|
9857
10030
|
url = meta.url;
|
|
@@ -9879,9 +10052,9 @@ async function applyProfile(page, profileData) {
|
|
|
9879
10052
|
}
|
|
9880
10053
|
function listProfiles() {
|
|
9881
10054
|
const dir = getProfilesDir();
|
|
9882
|
-
if (!
|
|
10055
|
+
if (!existsSync5(dir))
|
|
9883
10056
|
return [];
|
|
9884
|
-
const entries =
|
|
10057
|
+
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
9885
10058
|
const profiles = [];
|
|
9886
10059
|
for (const entry of entries) {
|
|
9887
10060
|
if (!entry.isDirectory())
|
|
@@ -9894,18 +10067,18 @@ function listProfiles() {
|
|
|
9894
10067
|
let storageKeyCount = 0;
|
|
9895
10068
|
try {
|
|
9896
10069
|
const metaPath2 = join8(profileDir, "meta.json");
|
|
9897
|
-
if (
|
|
10070
|
+
if (existsSync5(metaPath2)) {
|
|
9898
10071
|
const meta = JSON.parse(readFileSync2(metaPath2, "utf8"));
|
|
9899
10072
|
savedAt = meta.saved_at ?? "";
|
|
9900
10073
|
url = meta.url;
|
|
9901
10074
|
}
|
|
9902
10075
|
const cookiesPath = join8(profileDir, "cookies.json");
|
|
9903
|
-
if (
|
|
10076
|
+
if (existsSync5(cookiesPath)) {
|
|
9904
10077
|
const cookies = JSON.parse(readFileSync2(cookiesPath, "utf8"));
|
|
9905
10078
|
cookieCount = Array.isArray(cookies) ? cookies.length : 0;
|
|
9906
10079
|
}
|
|
9907
10080
|
const storagePath = join8(profileDir, "storage.json");
|
|
9908
|
-
if (
|
|
10081
|
+
if (existsSync5(storagePath)) {
|
|
9909
10082
|
const storage = JSON.parse(readFileSync2(storagePath, "utf8"));
|
|
9910
10083
|
storageKeyCount = Object.keys(storage).length;
|
|
9911
10084
|
}
|
|
@@ -9922,7 +10095,7 @@ function listProfiles() {
|
|
|
9922
10095
|
}
|
|
9923
10096
|
function deleteProfile(name) {
|
|
9924
10097
|
const dir = getProfileDir2(name);
|
|
9925
|
-
if (!
|
|
10098
|
+
if (!existsSync5(dir))
|
|
9926
10099
|
return false;
|
|
9927
10100
|
try {
|
|
9928
10101
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -9931,7 +10104,9 @@ function deleteProfile(name) {
|
|
|
9931
10104
|
return false;
|
|
9932
10105
|
}
|
|
9933
10106
|
}
|
|
9934
|
-
var init_profiles = () => {
|
|
10107
|
+
var init_profiles = __esm(() => {
|
|
10108
|
+
init_schema();
|
|
10109
|
+
});
|
|
9935
10110
|
|
|
9936
10111
|
// src/lib/vision-fallback.ts
|
|
9937
10112
|
var exports_vision_fallback = {};
|
|
@@ -10492,16 +10667,22 @@ var init_deep_performance = __esm(() => {
|
|
|
10492
10667
|
};
|
|
10493
10668
|
});
|
|
10494
10669
|
|
|
10495
|
-
//
|
|
10670
|
+
// node_modules/@hasna/skills/dist/index.js
|
|
10496
10671
|
var exports_dist = {};
|
|
10497
10672
|
__export(exports_dist, {
|
|
10673
|
+
validateCron: () => validateCron,
|
|
10498
10674
|
skillExists: () => skillExists,
|
|
10675
|
+
setScheduleEnabled: () => setScheduleEnabled,
|
|
10499
10676
|
searchSkills: () => searchSkills,
|
|
10500
10677
|
saveConfig: () => saveConfig,
|
|
10501
10678
|
runSkill: () => runSkill,
|
|
10502
10679
|
removeSkillForAgent: () => removeSkillForAgent,
|
|
10503
10680
|
removeSkill: () => removeSkill,
|
|
10681
|
+
removeSchedule: () => removeSchedule,
|
|
10682
|
+
recordScheduleRun: () => recordScheduleRun,
|
|
10683
|
+
loadRegistry: () => loadRegistry,
|
|
10504
10684
|
loadConfig: () => loadConfig,
|
|
10685
|
+
listSchedules: () => listSchedules,
|
|
10505
10686
|
installSkills: () => installSkills,
|
|
10506
10687
|
installSkillForAgent: () => installSkillForAgent,
|
|
10507
10688
|
installSkill: () => installSkill,
|
|
@@ -10512,8 +10693,10 @@ __export(exports_dist, {
|
|
|
10512
10693
|
getSkillDocs: () => getSkillDocs,
|
|
10513
10694
|
getSkillBestDoc: () => getSkillBestDoc,
|
|
10514
10695
|
getSkill: () => getSkill,
|
|
10696
|
+
getNextRun: () => getNextRun,
|
|
10515
10697
|
getInstalledSkills: () => getInstalledSkills,
|
|
10516
10698
|
getInstallMeta: () => getInstallMeta,
|
|
10699
|
+
getDueSchedules: () => getDueSchedules,
|
|
10517
10700
|
getDisabledSkills: () => getDisabledSkills,
|
|
10518
10701
|
getConfigPath: () => getConfigPath,
|
|
10519
10702
|
getAllTags: () => getAllTags,
|
|
@@ -10521,23 +10704,111 @@ __export(exports_dist, {
|
|
|
10521
10704
|
getAgentSkillPath: () => getAgentSkillPath,
|
|
10522
10705
|
generateSkillMd: () => generateSkillMd,
|
|
10523
10706
|
generateEnvExample: () => generateEnvExample,
|
|
10707
|
+
findSimilarSkills: () => findSimilarSkills,
|
|
10524
10708
|
enableSkill: () => enableSkill,
|
|
10525
10709
|
disableSkill: () => disableSkill,
|
|
10710
|
+
clearRegistryCache: () => clearRegistryCache,
|
|
10711
|
+
addSchedule: () => addSchedule,
|
|
10526
10712
|
SKILLS: () => SKILLS,
|
|
10527
10713
|
CATEGORIES: () => CATEGORIES,
|
|
10528
10714
|
AGENT_TARGETS: () => AGENT_TARGETS
|
|
10529
10715
|
});
|
|
10530
|
-
import { existsSync as
|
|
10531
|
-
import { join as join9
|
|
10532
|
-
import { homedir as
|
|
10533
|
-
import {
|
|
10534
|
-
import {
|
|
10535
|
-
import { join as join22 } from "path";
|
|
10536
|
-
import { existsSync as existsSync32, readFileSync as readFileSync32, writeFileSync as writeFileSync22, mkdirSync as mkdirSync22 } from "fs";
|
|
10537
|
-
import { join as join32, dirname as dirname2 } from "path";
|
|
10716
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, readdirSync as readdirSync5 } from "fs";
|
|
10717
|
+
import { join as join9 } from "path";
|
|
10718
|
+
import { homedir as homedir2 } from "os";
|
|
10719
|
+
import { existsSync as existsSync22, cpSync, mkdirSync as mkdirSync9, writeFileSync as writeFileSync3, rmSync as rmSync2, readdirSync as readdirSync22, statSync as statSync3, readFileSync as readFileSync22, accessSync, constants } from "fs";
|
|
10720
|
+
import { join as join22, dirname } from "path";
|
|
10538
10721
|
import { homedir as homedir22 } from "os";
|
|
10722
|
+
import { fileURLToPath } from "url";
|
|
10723
|
+
import { existsSync as existsSync32, readFileSync as readFileSync32, readdirSync as readdirSync32 } from "fs";
|
|
10724
|
+
import { join as join32 } from "path";
|
|
10725
|
+
import { existsSync as existsSync42, readFileSync as readFileSync4, writeFileSync as writeFileSync22, mkdirSync as mkdirSync22 } from "fs";
|
|
10726
|
+
import { join as join42, dirname as dirname2 } from "path";
|
|
10727
|
+
import { homedir as homedir3 } from "os";
|
|
10728
|
+
import { existsSync as existsSync52, readFileSync as readFileSync5, writeFileSync as writeFileSync32, mkdirSync as mkdirSync32 } from "fs";
|
|
10729
|
+
import { join as join52 } from "path";
|
|
10730
|
+
function parseSkillMdFrontmatter(content) {
|
|
10731
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
10732
|
+
if (!match)
|
|
10733
|
+
return null;
|
|
10734
|
+
const result = {};
|
|
10735
|
+
for (const line of match[1].split(`
|
|
10736
|
+
`)) {
|
|
10737
|
+
const colon = line.indexOf(":");
|
|
10738
|
+
if (colon === -1)
|
|
10739
|
+
continue;
|
|
10740
|
+
const key = line.slice(0, colon).trim();
|
|
10741
|
+
const value = line.slice(colon + 1).trim();
|
|
10742
|
+
if (!key || !value)
|
|
10743
|
+
continue;
|
|
10744
|
+
if (key === "name")
|
|
10745
|
+
result.name = value;
|
|
10746
|
+
else if (key === "description")
|
|
10747
|
+
result.description = value;
|
|
10748
|
+
else if (key === "displayName" || key === "display_name")
|
|
10749
|
+
result.displayName = value;
|
|
10750
|
+
else if (key === "category")
|
|
10751
|
+
result.category = value;
|
|
10752
|
+
else if (key === "tags") {
|
|
10753
|
+
result.tags = value.replace(/[\[\]]/g, "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
10754
|
+
}
|
|
10755
|
+
}
|
|
10756
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
10757
|
+
}
|
|
10758
|
+
function discoverSkillsInDir(dir) {
|
|
10759
|
+
if (!existsSync6(dir))
|
|
10760
|
+
return [];
|
|
10761
|
+
const result = [];
|
|
10762
|
+
try {
|
|
10763
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
10764
|
+
for (const entry of entries) {
|
|
10765
|
+
if (!entry.isDirectory())
|
|
10766
|
+
continue;
|
|
10767
|
+
const skillMdPath = join9(dir, entry.name, "SKILL.md");
|
|
10768
|
+
if (!existsSync6(skillMdPath))
|
|
10769
|
+
continue;
|
|
10770
|
+
let content;
|
|
10771
|
+
try {
|
|
10772
|
+
content = readFileSync3(skillMdPath, "utf-8");
|
|
10773
|
+
} catch {
|
|
10774
|
+
continue;
|
|
10775
|
+
}
|
|
10776
|
+
const fm = parseSkillMdFrontmatter(content);
|
|
10777
|
+
if (!fm?.name)
|
|
10778
|
+
continue;
|
|
10779
|
+
const name = fm.name.replace(/^skill-/, "");
|
|
10780
|
+
result.push({
|
|
10781
|
+
name,
|
|
10782
|
+
displayName: fm.displayName || name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
10783
|
+
description: fm.description || "",
|
|
10784
|
+
category: fm.category || "Development Tools",
|
|
10785
|
+
tags: fm.tags || [],
|
|
10786
|
+
source: "custom"
|
|
10787
|
+
});
|
|
10788
|
+
}
|
|
10789
|
+
} catch {}
|
|
10790
|
+
return result;
|
|
10791
|
+
}
|
|
10792
|
+
function loadRegistry(cwd) {
|
|
10793
|
+
const now = Date.now();
|
|
10794
|
+
if (_registryCache && now - _registryCacheTime < REGISTRY_CACHE_TTL) {
|
|
10795
|
+
return _registryCache;
|
|
10796
|
+
}
|
|
10797
|
+
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
10798
|
+
const globalCustom = discoverSkillsInDir(join9(homedir2(), ".skills"));
|
|
10799
|
+
const projectCustom = discoverSkillsInDir(join9(cwd || process.cwd(), ".skills", "custom-skills"));
|
|
10800
|
+
const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
|
|
10801
|
+
const filtered = official.filter((s) => !customNames.has(s.name));
|
|
10802
|
+
_registryCache = [...filtered, ...globalCustom, ...projectCustom];
|
|
10803
|
+
_registryCacheTime = now;
|
|
10804
|
+
return _registryCache;
|
|
10805
|
+
}
|
|
10806
|
+
function clearRegistryCache() {
|
|
10807
|
+
_registryCache = null;
|
|
10808
|
+
_registryCacheTime = 0;
|
|
10809
|
+
}
|
|
10539
10810
|
function getSkillsByCategory(category) {
|
|
10540
|
-
return
|
|
10811
|
+
return loadRegistry().filter((s) => s.category === category);
|
|
10541
10812
|
}
|
|
10542
10813
|
function editDistance(a, b) {
|
|
10543
10814
|
if (a === b)
|
|
@@ -10583,7 +10854,7 @@ function searchSkills(query) {
|
|
|
10583
10854
|
if (words.length === 0)
|
|
10584
10855
|
return [];
|
|
10585
10856
|
const scored = [];
|
|
10586
|
-
for (const skill of
|
|
10857
|
+
for (const skill of loadRegistry()) {
|
|
10587
10858
|
const nameLower = skill.name.toLowerCase();
|
|
10588
10859
|
const displayNameLower = skill.displayName.toLowerCase();
|
|
10589
10860
|
const descriptionLower = skill.description.toLowerCase();
|
|
@@ -10619,56 +10890,71 @@ function searchSkills(query) {
|
|
|
10619
10890
|
return scored.map((s) => s.skill);
|
|
10620
10891
|
}
|
|
10621
10892
|
function getSkill(name) {
|
|
10622
|
-
return
|
|
10893
|
+
return loadRegistry().find((s) => s.name === name);
|
|
10623
10894
|
}
|
|
10624
10895
|
function getSkillsByTag(tag) {
|
|
10625
10896
|
const needle = tag.toLowerCase();
|
|
10626
|
-
return
|
|
10897
|
+
return loadRegistry().filter((s) => s.tags.some((t) => t.toLowerCase().includes(needle)));
|
|
10627
10898
|
}
|
|
10628
10899
|
function getAllTags() {
|
|
10629
10900
|
const tagSet = new Set;
|
|
10630
|
-
for (const skill of
|
|
10901
|
+
for (const skill of loadRegistry()) {
|
|
10631
10902
|
for (const tag of skill.tags) {
|
|
10632
10903
|
tagSet.add(tag.toLowerCase());
|
|
10633
10904
|
}
|
|
10634
10905
|
}
|
|
10635
10906
|
return Array.from(tagSet).sort();
|
|
10636
10907
|
}
|
|
10908
|
+
function levenshtein(a, b) {
|
|
10909
|
+
const m = a.length, n = b.length;
|
|
10910
|
+
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0));
|
|
10911
|
+
for (let i = 1;i <= m; i++) {
|
|
10912
|
+
for (let j = 1;j <= n; j++) {
|
|
10913
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
10914
|
+
}
|
|
10915
|
+
}
|
|
10916
|
+
return dp[m][n];
|
|
10917
|
+
}
|
|
10918
|
+
function findSimilarSkills(query, maxResults = 3) {
|
|
10919
|
+
const q = query.toLowerCase();
|
|
10920
|
+
const scored = loadRegistry().map((s) => ({ name: s.name, dist: levenshtein(q, s.name.toLowerCase()) })).filter((s) => s.dist <= Math.max(3, Math.floor(q.length / 2))).sort((a, b) => a.dist - b.dist);
|
|
10921
|
+
return scored.slice(0, maxResults).map((s) => s.name);
|
|
10922
|
+
}
|
|
10637
10923
|
function normalizeSkillName(name) {
|
|
10638
10924
|
return name.startsWith("skill-") ? name : `skill-${name}`;
|
|
10639
10925
|
}
|
|
10640
10926
|
function findSkillsDir() {
|
|
10641
10927
|
let dir = __dirname2;
|
|
10642
10928
|
for (let i = 0;i < 5; i++) {
|
|
10643
|
-
const candidate =
|
|
10644
|
-
if (
|
|
10929
|
+
const candidate = join22(dir, "skills");
|
|
10930
|
+
if (existsSync22(candidate) && !dir.includes(".skills")) {
|
|
10645
10931
|
return candidate;
|
|
10646
10932
|
}
|
|
10647
10933
|
dir = dirname(dir);
|
|
10648
10934
|
}
|
|
10649
|
-
return
|
|
10935
|
+
return join22(__dirname2, "..", "skills");
|
|
10650
10936
|
}
|
|
10651
10937
|
function getSkillPath(name) {
|
|
10652
10938
|
const skillName = normalizeSkillName(name);
|
|
10653
|
-
return
|
|
10939
|
+
return join22(SKILLS_DIR, skillName);
|
|
10654
10940
|
}
|
|
10655
10941
|
function skillExists(name) {
|
|
10656
|
-
return
|
|
10942
|
+
return existsSync22(getSkillPath(name));
|
|
10657
10943
|
}
|
|
10658
10944
|
function installSkill(name, options = {}) {
|
|
10659
10945
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
10660
10946
|
const skillName = normalizeSkillName(name);
|
|
10661
10947
|
const sourcePath = getSkillPath(name);
|
|
10662
|
-
const destDir =
|
|
10663
|
-
const destPath =
|
|
10664
|
-
if (!
|
|
10948
|
+
const destDir = join22(targetDir, ".skills");
|
|
10949
|
+
const destPath = join22(destDir, skillName);
|
|
10950
|
+
if (!existsSync22(sourcePath)) {
|
|
10665
10951
|
return {
|
|
10666
10952
|
skill: name,
|
|
10667
10953
|
success: false,
|
|
10668
10954
|
error: `Skill '${name}' not found`
|
|
10669
10955
|
};
|
|
10670
10956
|
}
|
|
10671
|
-
if (
|
|
10957
|
+
if (existsSync22(destPath) && !overwrite) {
|
|
10672
10958
|
return {
|
|
10673
10959
|
skill: name,
|
|
10674
10960
|
success: false,
|
|
@@ -10677,10 +10963,10 @@ function installSkill(name, options = {}) {
|
|
|
10677
10963
|
};
|
|
10678
10964
|
}
|
|
10679
10965
|
try {
|
|
10680
|
-
if (!
|
|
10966
|
+
if (!existsSync22(destDir)) {
|
|
10681
10967
|
mkdirSync9(destDir, { recursive: true });
|
|
10682
10968
|
}
|
|
10683
|
-
if (
|
|
10969
|
+
if (existsSync22(destPath) && overwrite) {
|
|
10684
10970
|
rmSync2(destPath, { recursive: true, force: true });
|
|
10685
10971
|
}
|
|
10686
10972
|
cpSync(sourcePath, destPath, {
|
|
@@ -10719,10 +11005,10 @@ function installSkills(names, options = {}) {
|
|
|
10719
11005
|
return names.map((name) => installSkill(name, options));
|
|
10720
11006
|
}
|
|
10721
11007
|
function updateSkillsIndex(skillsDir) {
|
|
10722
|
-
const indexPath =
|
|
11008
|
+
const indexPath = join22(skillsDir, "index.ts");
|
|
10723
11009
|
const meta = loadMeta(skillsDir);
|
|
10724
11010
|
const disabledSet = new Set(meta.disabled || []);
|
|
10725
|
-
const skills =
|
|
11011
|
+
const skills = readdirSync22(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes(".") && !disabledSet.has(f.replace("skill-", "")));
|
|
10726
11012
|
const exports = skills.map((s) => {
|
|
10727
11013
|
const name = s.replace("skill-", "").replace(/-/g, "_");
|
|
10728
11014
|
return `export * as ${name} from './${s}/src/index.js';`;
|
|
@@ -10738,13 +11024,13 @@ ${exports}
|
|
|
10738
11024
|
writeFileSync3(indexPath, content);
|
|
10739
11025
|
}
|
|
10740
11026
|
function getMetaPath(skillsDir) {
|
|
10741
|
-
return
|
|
11027
|
+
return join22(skillsDir, ".meta.json");
|
|
10742
11028
|
}
|
|
10743
11029
|
function loadMeta(skillsDir) {
|
|
10744
11030
|
const metaPath2 = getMetaPath(skillsDir);
|
|
10745
|
-
if (
|
|
11031
|
+
if (existsSync22(metaPath2)) {
|
|
10746
11032
|
try {
|
|
10747
|
-
return JSON.parse(
|
|
11033
|
+
return JSON.parse(readFileSync22(metaPath2, "utf-8"));
|
|
10748
11034
|
} catch {}
|
|
10749
11035
|
}
|
|
10750
11036
|
return { skills: {} };
|
|
@@ -10757,9 +11043,9 @@ function recordInstall(skillsDir, name) {
|
|
|
10757
11043
|
const skillName = normalizeSkillName(name);
|
|
10758
11044
|
let version = "unknown";
|
|
10759
11045
|
try {
|
|
10760
|
-
const pkgPath =
|
|
10761
|
-
if (
|
|
10762
|
-
const pkg = JSON.parse(
|
|
11046
|
+
const pkgPath = join22(skillsDir, skillName, "package.json");
|
|
11047
|
+
if (existsSync22(pkgPath)) {
|
|
11048
|
+
const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
|
|
10763
11049
|
version = pkg.version || "unknown";
|
|
10764
11050
|
}
|
|
10765
11051
|
} catch {}
|
|
@@ -10772,12 +11058,12 @@ function recordRemove(skillsDir, name) {
|
|
|
10772
11058
|
saveMeta(skillsDir, meta);
|
|
10773
11059
|
}
|
|
10774
11060
|
function getInstallMeta(targetDir = process.cwd()) {
|
|
10775
|
-
return loadMeta(
|
|
11061
|
+
return loadMeta(join22(targetDir, ".skills"));
|
|
10776
11062
|
}
|
|
10777
11063
|
function disableSkill(name, targetDir = process.cwd()) {
|
|
10778
|
-
const skillsDir =
|
|
11064
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
10779
11065
|
const skillName = normalizeSkillName(name);
|
|
10780
|
-
if (!
|
|
11066
|
+
if (!existsSync22(join22(skillsDir, skillName)))
|
|
10781
11067
|
return false;
|
|
10782
11068
|
const meta = loadMeta(skillsDir);
|
|
10783
11069
|
const disabled = new Set(meta.disabled || []);
|
|
@@ -10790,7 +11076,7 @@ function disableSkill(name, targetDir = process.cwd()) {
|
|
|
10790
11076
|
return true;
|
|
10791
11077
|
}
|
|
10792
11078
|
function enableSkill(name, targetDir = process.cwd()) {
|
|
10793
|
-
const skillsDir =
|
|
11079
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
10794
11080
|
const meta = loadMeta(skillsDir);
|
|
10795
11081
|
const disabled = new Set(meta.disabled || []);
|
|
10796
11082
|
if (!disabled.has(name))
|
|
@@ -10802,24 +11088,24 @@ function enableSkill(name, targetDir = process.cwd()) {
|
|
|
10802
11088
|
return true;
|
|
10803
11089
|
}
|
|
10804
11090
|
function getDisabledSkills(targetDir = process.cwd()) {
|
|
10805
|
-
const meta = loadMeta(
|
|
11091
|
+
const meta = loadMeta(join22(targetDir, ".skills"));
|
|
10806
11092
|
return meta.disabled || [];
|
|
10807
11093
|
}
|
|
10808
11094
|
function getInstalledSkills(targetDir = process.cwd()) {
|
|
10809
|
-
const skillsDir =
|
|
10810
|
-
if (!
|
|
11095
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
11096
|
+
if (!existsSync22(skillsDir)) {
|
|
10811
11097
|
return [];
|
|
10812
11098
|
}
|
|
10813
|
-
return
|
|
10814
|
-
const fullPath =
|
|
10815
|
-
return f.startsWith("skill-") &&
|
|
11099
|
+
return readdirSync22(skillsDir).filter((f) => {
|
|
11100
|
+
const fullPath = join22(skillsDir, f);
|
|
11101
|
+
return f.startsWith("skill-") && statSync3(fullPath).isDirectory();
|
|
10816
11102
|
}).map((f) => f.replace("skill-", ""));
|
|
10817
11103
|
}
|
|
10818
11104
|
function removeSkill(name, targetDir = process.cwd()) {
|
|
10819
11105
|
const skillName = normalizeSkillName(name);
|
|
10820
|
-
const skillsDir =
|
|
10821
|
-
const skillPath =
|
|
10822
|
-
if (!
|
|
11106
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
11107
|
+
const skillPath = join22(skillsDir, skillName);
|
|
11108
|
+
if (!existsSync22(skillPath)) {
|
|
10823
11109
|
return false;
|
|
10824
11110
|
}
|
|
10825
11111
|
rmSync2(skillPath, { recursive: true, force: true });
|
|
@@ -10828,27 +11114,31 @@ function removeSkill(name, targetDir = process.cwd()) {
|
|
|
10828
11114
|
return true;
|
|
10829
11115
|
}
|
|
10830
11116
|
function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
10831
|
-
const
|
|
10832
|
-
|
|
10833
|
-
|
|
11117
|
+
const base = projectDir || process.cwd();
|
|
11118
|
+
switch (agent) {
|
|
11119
|
+
case "pi":
|
|
11120
|
+
return scope === "project" ? join22(base, ".pi", "skills") : join22(homedir22(), ".pi", "agent", "skills");
|
|
11121
|
+
case "opencode":
|
|
11122
|
+
return scope === "project" ? join22(base, ".opencode", "skills") : join22(homedir22(), ".opencode", "skills");
|
|
11123
|
+
default:
|
|
11124
|
+
return scope === "project" ? join22(base, `.${agent}`, "skills") : join22(homedir22(), `.${agent}`, "skills");
|
|
10834
11125
|
}
|
|
10835
|
-
return join9(homedir9(), agentDir, "skills");
|
|
10836
11126
|
}
|
|
10837
11127
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
10838
11128
|
const skillName = normalizeSkillName(name);
|
|
10839
|
-
return
|
|
11129
|
+
return join22(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
10840
11130
|
}
|
|
10841
11131
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
10842
11132
|
const { agent, scope = "global", projectDir } = options;
|
|
10843
11133
|
const skillName = normalizeSkillName(name);
|
|
10844
11134
|
const sourcePath = getSkillPath(name);
|
|
10845
|
-
if (!
|
|
11135
|
+
if (!existsSync22(sourcePath)) {
|
|
10846
11136
|
return { skill: name, success: false, error: `Skill '${name}' not found` };
|
|
10847
11137
|
}
|
|
10848
11138
|
let skillMdContent = null;
|
|
10849
|
-
const skillMdPath =
|
|
10850
|
-
if (
|
|
10851
|
-
skillMdContent =
|
|
11139
|
+
const skillMdPath = join22(sourcePath, "SKILL.md");
|
|
11140
|
+
if (existsSync22(skillMdPath)) {
|
|
11141
|
+
skillMdContent = readFileSync22(skillMdPath, "utf-8");
|
|
10852
11142
|
} else if (generateSkillMd) {
|
|
10853
11143
|
skillMdContent = generateSkillMd(name);
|
|
10854
11144
|
}
|
|
@@ -10857,17 +11147,12 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
10857
11147
|
}
|
|
10858
11148
|
const destDir = getAgentSkillPath(name, agent, scope, projectDir);
|
|
10859
11149
|
if (scope === "global") {
|
|
10860
|
-
const agentBaseDir =
|
|
10861
|
-
if (!
|
|
10862
|
-
const agentLabels = {
|
|
10863
|
-
claude: "Claude Code",
|
|
10864
|
-
codex: "Codex CLI",
|
|
10865
|
-
gemini: "Gemini CLI"
|
|
10866
|
-
};
|
|
11150
|
+
const agentBaseDir = agent === "pi" ? join22(homedir22(), ".pi", "agent") : join22(homedir22(), `.${agent}`);
|
|
11151
|
+
if (!existsSync22(agentBaseDir)) {
|
|
10867
11152
|
return {
|
|
10868
11153
|
skill: name,
|
|
10869
11154
|
success: false,
|
|
10870
|
-
error: `Agent directory ${agentBaseDir} does not exist. Is ${
|
|
11155
|
+
error: `Agent directory ${agentBaseDir} does not exist. Is ${AGENT_LABELS[agent]} installed?`
|
|
10871
11156
|
};
|
|
10872
11157
|
}
|
|
10873
11158
|
try {
|
|
@@ -10882,7 +11167,7 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
10882
11167
|
}
|
|
10883
11168
|
try {
|
|
10884
11169
|
mkdirSync9(destDir, { recursive: true });
|
|
10885
|
-
writeFileSync3(
|
|
11170
|
+
writeFileSync3(join22(destDir, "SKILL.md"), skillMdContent);
|
|
10886
11171
|
return { skill: name, success: true, path: destDir };
|
|
10887
11172
|
} catch (error) {
|
|
10888
11173
|
return {
|
|
@@ -10895,7 +11180,7 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
10895
11180
|
function removeSkillForAgent(name, options) {
|
|
10896
11181
|
const { agent, scope = "global", projectDir } = options;
|
|
10897
11182
|
const destDir = getAgentSkillPath(name, agent, scope, projectDir);
|
|
10898
|
-
if (!
|
|
11183
|
+
if (!existsSync22(destDir)) {
|
|
10899
11184
|
return false;
|
|
10900
11185
|
}
|
|
10901
11186
|
rmSync2(destDir, { recursive: true, force: true });
|
|
@@ -10903,12 +11188,12 @@ function removeSkillForAgent(name, options) {
|
|
|
10903
11188
|
}
|
|
10904
11189
|
function getSkillDocs(name) {
|
|
10905
11190
|
const skillPath = getSkillPath(name);
|
|
10906
|
-
if (!
|
|
11191
|
+
if (!existsSync32(skillPath))
|
|
10907
11192
|
return null;
|
|
10908
11193
|
return {
|
|
10909
|
-
skillMd: readIfExists(
|
|
10910
|
-
readme: readIfExists(
|
|
10911
|
-
claudeMd: readIfExists(
|
|
11194
|
+
skillMd: readIfExists(join32(skillPath, "SKILL.md")),
|
|
11195
|
+
readme: readIfExists(join32(skillPath, "README.md")),
|
|
11196
|
+
claudeMd: readIfExists(join32(skillPath, "CLAUDE.md"))
|
|
10912
11197
|
};
|
|
10913
11198
|
}
|
|
10914
11199
|
function getSkillBestDoc(name) {
|
|
@@ -10919,11 +11204,11 @@ function getSkillBestDoc(name) {
|
|
|
10919
11204
|
}
|
|
10920
11205
|
function getSkillRequirements(name) {
|
|
10921
11206
|
const skillPath = getSkillPath(name);
|
|
10922
|
-
if (!
|
|
11207
|
+
if (!existsSync32(skillPath))
|
|
10923
11208
|
return null;
|
|
10924
11209
|
const texts = [];
|
|
10925
11210
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
10926
|
-
const content = readIfExists(
|
|
11211
|
+
const content = readIfExists(join32(skillPath, file));
|
|
10927
11212
|
if (content)
|
|
10928
11213
|
texts.push(content);
|
|
10929
11214
|
}
|
|
@@ -10950,10 +11235,10 @@ function getSkillRequirements(name) {
|
|
|
10950
11235
|
}
|
|
10951
11236
|
let cliCommand = null;
|
|
10952
11237
|
let dependencies = {};
|
|
10953
|
-
const pkgPath =
|
|
10954
|
-
if (
|
|
11238
|
+
const pkgPath = join32(skillPath, "package.json");
|
|
11239
|
+
if (existsSync32(pkgPath)) {
|
|
10955
11240
|
try {
|
|
10956
|
-
const pkg = JSON.parse(
|
|
11241
|
+
const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
|
|
10957
11242
|
if (pkg.bin) {
|
|
10958
11243
|
const binKeys = Object.keys(pkg.bin);
|
|
10959
11244
|
if (binKeys.length > 0)
|
|
@@ -10973,25 +11258,25 @@ async function runSkill(name, args, options = {}) {
|
|
|
10973
11258
|
const skillName = normalizeSkillName(name);
|
|
10974
11259
|
let skillPath;
|
|
10975
11260
|
if (options.installed) {
|
|
10976
|
-
skillPath =
|
|
11261
|
+
skillPath = join32(process.cwd(), ".skills", skillName);
|
|
10977
11262
|
} else {
|
|
10978
|
-
const installedPath =
|
|
10979
|
-
if (
|
|
11263
|
+
const installedPath = join32(process.cwd(), ".skills", skillName);
|
|
11264
|
+
if (existsSync32(installedPath)) {
|
|
10980
11265
|
skillPath = installedPath;
|
|
10981
11266
|
} else {
|
|
10982
11267
|
skillPath = getSkillPath(name);
|
|
10983
11268
|
}
|
|
10984
11269
|
}
|
|
10985
|
-
if (!
|
|
11270
|
+
if (!existsSync32(skillPath)) {
|
|
10986
11271
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
10987
11272
|
}
|
|
10988
|
-
const pkgPath =
|
|
10989
|
-
if (!
|
|
11273
|
+
const pkgPath = join32(skillPath, "package.json");
|
|
11274
|
+
if (!existsSync32(pkgPath)) {
|
|
10990
11275
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
10991
11276
|
}
|
|
10992
11277
|
let entryPoint;
|
|
10993
11278
|
try {
|
|
10994
|
-
const pkg = JSON.parse(
|
|
11279
|
+
const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
|
|
10995
11280
|
if (pkg.bin) {
|
|
10996
11281
|
const binValues = Object.values(pkg.bin);
|
|
10997
11282
|
entryPoint = binValues[0];
|
|
@@ -11005,12 +11290,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
11005
11290
|
} catch {
|
|
11006
11291
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
11007
11292
|
}
|
|
11008
|
-
const entryPath =
|
|
11009
|
-
if (!
|
|
11293
|
+
const entryPath = join32(skillPath, entryPoint);
|
|
11294
|
+
if (!existsSync32(entryPath)) {
|
|
11010
11295
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
11011
11296
|
}
|
|
11012
|
-
const nodeModules =
|
|
11013
|
-
if (!
|
|
11297
|
+
const nodeModules = join32(skillPath, "node_modules");
|
|
11298
|
+
if (!existsSync32(nodeModules)) {
|
|
11014
11299
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
11015
11300
|
cwd: skillPath,
|
|
11016
11301
|
stdout: "pipe",
|
|
@@ -11028,17 +11313,17 @@ async function runSkill(name, args, options = {}) {
|
|
|
11028
11313
|
return { exitCode };
|
|
11029
11314
|
}
|
|
11030
11315
|
function generateEnvExample(targetDir = process.cwd()) {
|
|
11031
|
-
const skillsDir =
|
|
11032
|
-
if (!
|
|
11316
|
+
const skillsDir = join32(targetDir, ".skills");
|
|
11317
|
+
if (!existsSync32(skillsDir))
|
|
11033
11318
|
return "";
|
|
11034
|
-
const dirs =
|
|
11319
|
+
const dirs = readdirSync32(skillsDir).filter((f) => f.startsWith("skill-") && existsSync32(join32(skillsDir, f, "package.json")));
|
|
11035
11320
|
const envMap = new Map;
|
|
11036
11321
|
for (const dir of dirs) {
|
|
11037
11322
|
const skillName = dir.replace("skill-", "");
|
|
11038
|
-
const skillPath =
|
|
11323
|
+
const skillPath = join32(skillsDir, dir);
|
|
11039
11324
|
const texts = [];
|
|
11040
11325
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example"]) {
|
|
11041
|
-
const content = readIfExists(
|
|
11326
|
+
const content = readIfExists(join32(skillPath, file));
|
|
11042
11327
|
if (content)
|
|
11043
11328
|
texts.push(content);
|
|
11044
11329
|
}
|
|
@@ -11083,7 +11368,7 @@ function generateSkillMd(name) {
|
|
|
11083
11368
|
if (!meta)
|
|
11084
11369
|
return null;
|
|
11085
11370
|
const skillPath = getSkillPath(name);
|
|
11086
|
-
if (!
|
|
11371
|
+
if (!existsSync32(skillPath))
|
|
11087
11372
|
return null;
|
|
11088
11373
|
const frontmatter = [
|
|
11089
11374
|
"---",
|
|
@@ -11092,13 +11377,13 @@ function generateSkillMd(name) {
|
|
|
11092
11377
|
"---"
|
|
11093
11378
|
].join(`
|
|
11094
11379
|
`);
|
|
11095
|
-
const readme = readIfExists(
|
|
11096
|
-
const claudeMd = readIfExists(
|
|
11380
|
+
const readme = readIfExists(join32(skillPath, "README.md"));
|
|
11381
|
+
const claudeMd = readIfExists(join32(skillPath, "CLAUDE.md"));
|
|
11097
11382
|
let cliCommand = null;
|
|
11098
|
-
const pkgPath =
|
|
11099
|
-
if (
|
|
11383
|
+
const pkgPath = join32(skillPath, "package.json");
|
|
11384
|
+
if (existsSync32(pkgPath)) {
|
|
11100
11385
|
try {
|
|
11101
|
-
const pkg = JSON.parse(
|
|
11386
|
+
const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
|
|
11102
11387
|
if (pkg.bin) {
|
|
11103
11388
|
const binKeys = Object.keys(pkg.bin);
|
|
11104
11389
|
if (binKeys.length > 0)
|
|
@@ -11171,23 +11456,23 @@ function extractEnvVars(text) {
|
|
|
11171
11456
|
}
|
|
11172
11457
|
function readIfExists(path) {
|
|
11173
11458
|
try {
|
|
11174
|
-
if (
|
|
11175
|
-
return
|
|
11459
|
+
if (existsSync32(path)) {
|
|
11460
|
+
return readFileSync32(path, "utf-8");
|
|
11176
11461
|
}
|
|
11177
11462
|
} catch {}
|
|
11178
11463
|
return null;
|
|
11179
11464
|
}
|
|
11180
11465
|
function getConfigPath(scope) {
|
|
11181
11466
|
if (scope === "global") {
|
|
11182
|
-
return
|
|
11467
|
+
return join42(homedir3(), ".skillsrc");
|
|
11183
11468
|
}
|
|
11184
|
-
return
|
|
11469
|
+
return join42(process.cwd(), "skills.config.json");
|
|
11185
11470
|
}
|
|
11186
11471
|
function readConfigFile(path) {
|
|
11187
|
-
if (!
|
|
11472
|
+
if (!existsSync42(path))
|
|
11188
11473
|
return {};
|
|
11189
11474
|
try {
|
|
11190
|
-
const raw =
|
|
11475
|
+
const raw = readFileSync4(path, "utf-8");
|
|
11191
11476
|
const parsed = JSON.parse(raw);
|
|
11192
11477
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
11193
11478
|
return {};
|
|
@@ -11218,9 +11503,9 @@ function saveConfig(key, value, scope = "project") {
|
|
|
11218
11503
|
}
|
|
11219
11504
|
const filePath = getConfigPath(scope);
|
|
11220
11505
|
let existing = {};
|
|
11221
|
-
if (
|
|
11506
|
+
if (existsSync42(filePath)) {
|
|
11222
11507
|
try {
|
|
11223
|
-
existing = JSON.parse(
|
|
11508
|
+
existing = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
11224
11509
|
if (typeof existing !== "object" || existing === null || Array.isArray(existing)) {
|
|
11225
11510
|
existing = {};
|
|
11226
11511
|
}
|
|
@@ -11229,7 +11514,7 @@ function saveConfig(key, value, scope = "project") {
|
|
|
11229
11514
|
}
|
|
11230
11515
|
} else {
|
|
11231
11516
|
const dir = dirname2(filePath);
|
|
11232
|
-
if (!
|
|
11517
|
+
if (!existsSync42(dir)) {
|
|
11233
11518
|
mkdirSync22(dir, { recursive: true });
|
|
11234
11519
|
}
|
|
11235
11520
|
}
|
|
@@ -11237,7 +11522,158 @@ function saveConfig(key, value, scope = "project") {
|
|
|
11237
11522
|
writeFileSync22(filePath, JSON.stringify(existing, null, 2) + `
|
|
11238
11523
|
`);
|
|
11239
11524
|
}
|
|
11240
|
-
|
|
11525
|
+
function getSchedulesPath(targetDir = process.cwd()) {
|
|
11526
|
+
return join52(targetDir, ".skills", "schedules.json");
|
|
11527
|
+
}
|
|
11528
|
+
function loadSchedules(targetDir = process.cwd()) {
|
|
11529
|
+
const path = getSchedulesPath(targetDir);
|
|
11530
|
+
if (existsSync52(path)) {
|
|
11531
|
+
try {
|
|
11532
|
+
return JSON.parse(readFileSync5(path, "utf-8"));
|
|
11533
|
+
} catch {}
|
|
11534
|
+
}
|
|
11535
|
+
return { version: 1, schedules: [] };
|
|
11536
|
+
}
|
|
11537
|
+
function saveSchedules(data, targetDir = process.cwd()) {
|
|
11538
|
+
const path = getSchedulesPath(targetDir);
|
|
11539
|
+
const dir = join52(targetDir, ".skills");
|
|
11540
|
+
if (!existsSync52(dir))
|
|
11541
|
+
mkdirSync32(dir, { recursive: true });
|
|
11542
|
+
writeFileSync32(path, JSON.stringify(data, null, 2));
|
|
11543
|
+
}
|
|
11544
|
+
function validateCron(expr) {
|
|
11545
|
+
const fields = expr.trim().split(/\s+/);
|
|
11546
|
+
if (fields.length !== 5) {
|
|
11547
|
+
return { valid: false, error: `Expected 5 fields, got ${fields.length}. Format: "minute hour day-of-month month day-of-week"` };
|
|
11548
|
+
}
|
|
11549
|
+
return { valid: true };
|
|
11550
|
+
}
|
|
11551
|
+
function getNextRun(cron, from = new Date) {
|
|
11552
|
+
const { valid } = validateCron(cron);
|
|
11553
|
+
if (!valid)
|
|
11554
|
+
return null;
|
|
11555
|
+
const [minuteF, hourF, domF, monthF, dowF] = cron.trim().split(/\s+/);
|
|
11556
|
+
function parseField(f, min, max) {
|
|
11557
|
+
if (f === "*")
|
|
11558
|
+
return Array.from({ length: max - min + 1 }, (_, i) => i + min);
|
|
11559
|
+
if (f.startsWith("*/")) {
|
|
11560
|
+
const step = parseInt(f.slice(2));
|
|
11561
|
+
if (isNaN(step))
|
|
11562
|
+
return [];
|
|
11563
|
+
const vals = [];
|
|
11564
|
+
for (let i = min;i <= max; i += step)
|
|
11565
|
+
vals.push(i);
|
|
11566
|
+
return vals;
|
|
11567
|
+
}
|
|
11568
|
+
return f.split(",").flatMap((part) => {
|
|
11569
|
+
if (part.includes("-")) {
|
|
11570
|
+
const [lo, hi] = part.split("-").map(Number);
|
|
11571
|
+
return Array.from({ length: hi - lo + 1 }, (_, i) => i + lo);
|
|
11572
|
+
}
|
|
11573
|
+
const n = parseInt(part);
|
|
11574
|
+
return isNaN(n) ? [] : [n];
|
|
11575
|
+
});
|
|
11576
|
+
}
|
|
11577
|
+
const minutes = parseField(minuteF, 0, 59);
|
|
11578
|
+
const hours = parseField(hourF, 0, 23);
|
|
11579
|
+
const doms = parseField(domF, 1, 31);
|
|
11580
|
+
const months = parseField(monthF, 1, 12);
|
|
11581
|
+
const dows = parseField(dowF, 0, 6);
|
|
11582
|
+
const candidate = new Date(from);
|
|
11583
|
+
candidate.setSeconds(0, 0);
|
|
11584
|
+
candidate.setMinutes(candidate.getMinutes() + 1);
|
|
11585
|
+
const limit = new Date(from);
|
|
11586
|
+
limit.setFullYear(limit.getFullYear() + 1);
|
|
11587
|
+
while (candidate < limit) {
|
|
11588
|
+
const month = candidate.getMonth() + 1;
|
|
11589
|
+
const dom = candidate.getDate();
|
|
11590
|
+
const dow = candidate.getDay();
|
|
11591
|
+
const hour = candidate.getHours();
|
|
11592
|
+
const minute = candidate.getMinutes();
|
|
11593
|
+
if (!months.includes(month)) {
|
|
11594
|
+
candidate.setMonth(candidate.getMonth() + 1, 1);
|
|
11595
|
+
candidate.setHours(0, 0, 0, 0);
|
|
11596
|
+
continue;
|
|
11597
|
+
}
|
|
11598
|
+
if (!doms.includes(dom) || !dows.includes(dow)) {
|
|
11599
|
+
candidate.setDate(candidate.getDate() + 1);
|
|
11600
|
+
candidate.setHours(0, 0, 0, 0);
|
|
11601
|
+
continue;
|
|
11602
|
+
}
|
|
11603
|
+
if (!hours.includes(hour)) {
|
|
11604
|
+
candidate.setHours(candidate.getHours() + 1, 0, 0, 0);
|
|
11605
|
+
continue;
|
|
11606
|
+
}
|
|
11607
|
+
if (!minutes.includes(minute)) {
|
|
11608
|
+
candidate.setMinutes(candidate.getMinutes() + 1, 0, 0);
|
|
11609
|
+
continue;
|
|
11610
|
+
}
|
|
11611
|
+
return new Date(candidate);
|
|
11612
|
+
}
|
|
11613
|
+
return null;
|
|
11614
|
+
}
|
|
11615
|
+
function addSchedule(skill, cron, options = {}) {
|
|
11616
|
+
const { valid, error } = validateCron(cron);
|
|
11617
|
+
if (!valid)
|
|
11618
|
+
return { schedule: null, error };
|
|
11619
|
+
const data = loadSchedules(options.targetDir);
|
|
11620
|
+
const id = `${skill}-${Date.now()}`;
|
|
11621
|
+
const now = new Date;
|
|
11622
|
+
const nextRun = getNextRun(cron, now);
|
|
11623
|
+
const schedule = {
|
|
11624
|
+
id,
|
|
11625
|
+
name: options.name || `${skill} (${cron})`,
|
|
11626
|
+
skill,
|
|
11627
|
+
cron,
|
|
11628
|
+
args: options.args,
|
|
11629
|
+
enabled: true,
|
|
11630
|
+
createdAt: now.toISOString(),
|
|
11631
|
+
nextRun: nextRun?.toISOString()
|
|
11632
|
+
};
|
|
11633
|
+
data.schedules.push(schedule);
|
|
11634
|
+
saveSchedules(data, options.targetDir);
|
|
11635
|
+
return { schedule };
|
|
11636
|
+
}
|
|
11637
|
+
function listSchedules(targetDir) {
|
|
11638
|
+
return loadSchedules(targetDir).schedules;
|
|
11639
|
+
}
|
|
11640
|
+
function removeSchedule(idOrName, targetDir) {
|
|
11641
|
+
const data = loadSchedules(targetDir);
|
|
11642
|
+
const before = data.schedules.length;
|
|
11643
|
+
data.schedules = data.schedules.filter((s) => s.id !== idOrName && s.name !== idOrName);
|
|
11644
|
+
if (data.schedules.length === before)
|
|
11645
|
+
return false;
|
|
11646
|
+
saveSchedules(data, targetDir);
|
|
11647
|
+
return true;
|
|
11648
|
+
}
|
|
11649
|
+
function setScheduleEnabled(idOrName, enabled, targetDir) {
|
|
11650
|
+
const data = loadSchedules(targetDir);
|
|
11651
|
+
const schedule = data.schedules.find((s) => s.id === idOrName || s.name === idOrName);
|
|
11652
|
+
if (!schedule)
|
|
11653
|
+
return false;
|
|
11654
|
+
schedule.enabled = enabled;
|
|
11655
|
+
if (enabled) {
|
|
11656
|
+
schedule.nextRun = getNextRun(schedule.cron)?.toISOString();
|
|
11657
|
+
}
|
|
11658
|
+
saveSchedules(data, targetDir);
|
|
11659
|
+
return true;
|
|
11660
|
+
}
|
|
11661
|
+
function getDueSchedules(targetDir) {
|
|
11662
|
+
const now = new Date;
|
|
11663
|
+
return listSchedules(targetDir).filter((s) => s.enabled && s.nextRun && new Date(s.nextRun) <= now);
|
|
11664
|
+
}
|
|
11665
|
+
function recordScheduleRun(id, status, targetDir) {
|
|
11666
|
+
const data = loadSchedules(targetDir);
|
|
11667
|
+
const schedule = data.schedules.find((s) => s.id === id);
|
|
11668
|
+
if (!schedule)
|
|
11669
|
+
return;
|
|
11670
|
+
const now = new Date;
|
|
11671
|
+
schedule.lastRun = now.toISOString();
|
|
11672
|
+
schedule.lastRunStatus = status;
|
|
11673
|
+
schedule.nextRun = getNextRun(schedule.cron, now)?.toISOString();
|
|
11674
|
+
saveSchedules(data, targetDir);
|
|
11675
|
+
}
|
|
11676
|
+
var CATEGORIES, SKILLS, _registryCache = null, _registryCacheTime = 0, REGISTRY_CACHE_TTL = 5000, __dirname2, SKILLS_DIR, AGENT_TARGETS, AGENT_LABELS, ENV_VAR_PATTERN, GENERIC_ENV_PATTERN, VALID_KEYS;
|
|
11241
11677
|
var init_dist = __esm(() => {
|
|
11242
11678
|
CATEGORIES = [
|
|
11243
11679
|
"Development Tools",
|
|
@@ -12275,6 +12711,20 @@ var init_dist = __esm(() => {
|
|
|
12275
12711
|
category: "Design & Branding",
|
|
12276
12712
|
tags: ["testimonials", "graphics", "social-proof", "marketing"]
|
|
12277
12713
|
},
|
|
12714
|
+
{
|
|
12715
|
+
name: "colorextract",
|
|
12716
|
+
displayName: "Color Extract",
|
|
12717
|
+
description: "Extract complete color palettes from screenshots and images using Claude Vision. Outputs open-styles compatible profiles.",
|
|
12718
|
+
category: "Design & Branding",
|
|
12719
|
+
tags: ["colors", "palette", "design", "vision", "screenshot", "extract", "open-styles"]
|
|
12720
|
+
},
|
|
12721
|
+
{
|
|
12722
|
+
name: "siteanalyze",
|
|
12723
|
+
displayName: "Site Analyze",
|
|
12724
|
+
description: "Analyze any website's design system \u2014 detects shadcn/ui, Tailwind, extracts colors, typography, and components via Playwright + Claude Vision.",
|
|
12725
|
+
category: "Design & Branding",
|
|
12726
|
+
tags: ["design", "shadcn", "tailwind", "colors", "typography", "playwright", "analysis", "open-styles"]
|
|
12727
|
+
},
|
|
12278
12728
|
{
|
|
12279
12729
|
name: "browse",
|
|
12280
12730
|
displayName: "Browse",
|
|
@@ -12677,7 +13127,14 @@ var init_dist = __esm(() => {
|
|
|
12677
13127
|
];
|
|
12678
13128
|
__dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
12679
13129
|
SKILLS_DIR = findSkillsDir();
|
|
12680
|
-
AGENT_TARGETS = ["claude", "codex", "gemini"];
|
|
13130
|
+
AGENT_TARGETS = ["claude", "codex", "gemini", "pi", "opencode"];
|
|
13131
|
+
AGENT_LABELS = {
|
|
13132
|
+
claude: "Claude Code",
|
|
13133
|
+
codex: "Codex CLI",
|
|
13134
|
+
gemini: "Gemini CLI",
|
|
13135
|
+
pi: "pi.dev",
|
|
13136
|
+
opencode: "OpenCode"
|
|
13137
|
+
};
|
|
12681
13138
|
ENV_VAR_PATTERN = /\b([A-Z][A-Z0-9_]{2,}(?:_API_KEY|_KEY|_TOKEN|_SECRET|_URL|_ID|_PASSWORD|_ENDPOINT|_REGION|_BUCKET))\b/g;
|
|
12682
13139
|
GENERIC_ENV_PATTERN = /\b((?:OPENAI|ANTHROPIC|GEMINI|XAI|ELEVENLABS|DEEPGRAM|REPLICATE|FAL|STABILITY|EXA|FIRECRAWL|TWILIO|SENDGRID|RESEND|SLACK|DISCORD|NOTION|LINEAR|GITHUB|AWS|GOOGLE|CLOUDFLARE|VERCEL|SUPABASE|STRIPE)_[A-Z_]+)\b/g;
|
|
12683
13140
|
VALID_KEYS = {
|
|
@@ -12693,21 +13150,21 @@ __export(exports_auth, {
|
|
|
12693
13150
|
loginWithCredentials: () => loginWithCredentials,
|
|
12694
13151
|
getCredentials: () => getCredentials
|
|
12695
13152
|
});
|
|
12696
|
-
import { existsSync as
|
|
13153
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
12697
13154
|
import { join as join10 } from "path";
|
|
12698
|
-
import { homedir as
|
|
13155
|
+
import { homedir as homedir4 } from "os";
|
|
12699
13156
|
async function getCredentials(service) {
|
|
12700
13157
|
try {
|
|
12701
|
-
const { getSecret } = await import(`${
|
|
13158
|
+
const { getSecret } = await import(`${homedir4()}/Workspace/hasna/opensource/opensourcedev/open-secrets/src/store.js`);
|
|
12702
13159
|
const email = getSecret(`${service}_email`) ?? getSecret(`${service}_username`) ?? getSecret(`${service}_login`);
|
|
12703
13160
|
const password = getSecret(`${service}_password`) ?? getSecret(`${service}_pass`);
|
|
12704
13161
|
if (email?.value && password?.value) {
|
|
12705
13162
|
return { email: email.value, password: password.value };
|
|
12706
13163
|
}
|
|
12707
13164
|
} catch {}
|
|
12708
|
-
const secretsPath = join10(
|
|
12709
|
-
if (
|
|
12710
|
-
const content =
|
|
13165
|
+
const secretsPath = join10(homedir4(), ".secrets");
|
|
13166
|
+
if (existsSync7(secretsPath)) {
|
|
13167
|
+
const content = readFileSync6(secretsPath, "utf8");
|
|
12711
13168
|
const lines = content.split(`
|
|
12712
13169
|
`);
|
|
12713
13170
|
const prefix = service.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
@@ -12901,6 +13358,7 @@ var init_skills_runner = __esm(() => {
|
|
|
12901
13358
|
var exports_cron_manager = {};
|
|
12902
13359
|
__export(exports_cron_manager, {
|
|
12903
13360
|
runCronJobNow: () => runCronJobNow,
|
|
13361
|
+
pruneCronEvents: () => pruneCronEvents,
|
|
12904
13362
|
loadCronJobsOnStartup: () => loadCronJobsOnStartup,
|
|
12905
13363
|
listCronJobs: () => listCronJobs,
|
|
12906
13364
|
getCronJob: () => getCronJob,
|
|
@@ -12993,6 +13451,13 @@ function getCronEvents(jobId, limit = 10) {
|
|
|
12993
13451
|
const rows = db.query("SELECT * FROM cron_events WHERE job_id = ? ORDER BY started_at DESC LIMIT ?").all(jobId, limit);
|
|
12994
13452
|
return rows.map((r) => ({ ...r, success: r.success === 1, result: r.result ? JSON.parse(r.result) : undefined }));
|
|
12995
13453
|
}
|
|
13454
|
+
function pruneCronEvents(retentionDays = 7) {
|
|
13455
|
+
ensureCronTable();
|
|
13456
|
+
const db = getDatabase();
|
|
13457
|
+
const cutoff = new Date(Date.now() - retentionDays * 86400000).toISOString();
|
|
13458
|
+
const result = db.prepare("DELETE FROM cron_events WHERE started_at < ?").run(cutoff);
|
|
13459
|
+
return result.changes;
|
|
13460
|
+
}
|
|
12996
13461
|
async function executeCronJob(job) {
|
|
12997
13462
|
ensureCronTable();
|
|
12998
13463
|
const db = getDatabase();
|
|
@@ -13061,6 +13526,9 @@ function unregisterCronJob(id) {
|
|
|
13061
13526
|
}
|
|
13062
13527
|
function loadCronJobsOnStartup() {
|
|
13063
13528
|
try {
|
|
13529
|
+
const pruned = pruneCronEvents();
|
|
13530
|
+
if (pruned > 0)
|
|
13531
|
+
console.error(`[browser] Pruned ${pruned} old cron event(s)`);
|
|
13064
13532
|
const jobs = listCronJobs();
|
|
13065
13533
|
for (const job of jobs) {
|
|
13066
13534
|
if (job.enabled)
|
|
@@ -13297,9 +13765,9 @@ async function tryReplayAuth(page, domain) {
|
|
|
13297
13765
|
return { replayed: false };
|
|
13298
13766
|
if (flow.storage_state_path) {
|
|
13299
13767
|
try {
|
|
13300
|
-
const { existsSync:
|
|
13301
|
-
if (
|
|
13302
|
-
const state = JSON.parse(
|
|
13768
|
+
const { existsSync: existsSync8, readFileSync: readFileSync7 } = await import("fs");
|
|
13769
|
+
if (existsSync8(flow.storage_state_path)) {
|
|
13770
|
+
const state = JSON.parse(readFileSync7(flow.storage_state_path, "utf8"));
|
|
13303
13771
|
if (state.cookies?.length) {
|
|
13304
13772
|
await page.context().addCookies(state.cookies);
|
|
13305
13773
|
await page.reload();
|
|
@@ -13460,17 +13928,17 @@ function listRuns(scriptId) {
|
|
|
13460
13928
|
}));
|
|
13461
13929
|
}
|
|
13462
13930
|
function migrateJsonScripts() {
|
|
13463
|
-
const { existsSync:
|
|
13931
|
+
const { existsSync: existsSync8, readdirSync: readdirSync6, readFileSync: readFileSync7 } = __require("fs");
|
|
13464
13932
|
const { join: join11 } = __require("path");
|
|
13465
|
-
const { getDataDir:
|
|
13466
|
-
const dir = join11(
|
|
13467
|
-
if (!
|
|
13933
|
+
const { getDataDir: getDataDir2 } = (init_schema(), __toCommonJS(exports_schema));
|
|
13934
|
+
const dir = join11(getDataDir2(), "scripts");
|
|
13935
|
+
if (!existsSync8(dir))
|
|
13468
13936
|
return 0;
|
|
13469
|
-
const files =
|
|
13937
|
+
const files = readdirSync6(dir).filter((f) => f.endsWith(".json"));
|
|
13470
13938
|
let migrated = 0;
|
|
13471
13939
|
for (const file of files) {
|
|
13472
13940
|
try {
|
|
13473
|
-
const raw = JSON.parse(
|
|
13941
|
+
const raw = JSON.parse(readFileSync7(join11(dir, file), "utf8"));
|
|
13474
13942
|
if (!raw.name || !raw.steps)
|
|
13475
13943
|
continue;
|
|
13476
13944
|
if (getScriptByName(raw.name))
|
|
@@ -13913,7 +14381,6 @@ __export(exports_datasets, {
|
|
|
13913
14381
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
13914
14382
|
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync10 } from "fs";
|
|
13915
14383
|
import { join as join11 } from "path";
|
|
13916
|
-
import { homedir as homedir11 } from "os";
|
|
13917
14384
|
function saveDataset(data) {
|
|
13918
14385
|
const db = getDatabase();
|
|
13919
14386
|
const id = randomUUID15();
|
|
@@ -13951,7 +14418,7 @@ function exportDataset(name, format) {
|
|
|
13951
14418
|
const dataset = getDatasetByName(name);
|
|
13952
14419
|
if (!dataset)
|
|
13953
14420
|
throw new Error(`Dataset '${name}' not found`);
|
|
13954
|
-
const dir = join11(
|
|
14421
|
+
const dir = join11(getDataDir(), "exports");
|
|
13955
14422
|
mkdirSync10(dir, { recursive: true });
|
|
13956
14423
|
const filename = `${name}.${format}`;
|
|
13957
14424
|
const path = join11(dir, filename);
|
|
@@ -13981,9 +14448,10 @@ function exportDataset(name, format) {
|
|
|
13981
14448
|
}
|
|
13982
14449
|
var init_datasets = __esm(() => {
|
|
13983
14450
|
init_schema();
|
|
14451
|
+
init_schema();
|
|
13984
14452
|
});
|
|
13985
14453
|
|
|
13986
|
-
//
|
|
14454
|
+
// node_modules/@hasna/mementos/dist/index.js
|
|
13987
14455
|
var exports_dist2 = {};
|
|
13988
14456
|
__export(exports_dist2, {
|
|
13989
14457
|
withMemoryLock: () => withMemoryLock,
|
|
@@ -14093,17 +14561,20 @@ __export(exports_dist2, {
|
|
|
14093
14561
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG
|
|
14094
14562
|
});
|
|
14095
14563
|
import { Database as Database2 } from "bun:sqlite";
|
|
14096
|
-
import { existsSync as
|
|
14564
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync11 } from "fs";
|
|
14097
14565
|
import { dirname as dirname3, join as join12, resolve as resolve2 } from "path";
|
|
14098
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as
|
|
14099
|
-
import { homedir as
|
|
14566
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync8, readdirSync as readdirSync6, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
14567
|
+
import { homedir as homedir6 } from "os";
|
|
14100
14568
|
import { basename as basename2, dirname as dirname22, join as join23, resolve as resolve22 } from "path";
|
|
14101
|
-
import { existsSync as existsSync33, mkdirSync as
|
|
14569
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync33, readFileSync as readFileSync23, writeFileSync as writeFileSync23 } from "fs";
|
|
14102
14570
|
import { homedir as homedir23 } from "os";
|
|
14103
14571
|
import { join as join33 } from "path";
|
|
14104
|
-
import { existsSync as
|
|
14572
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync42, readFileSync as readFileSync33, writeFileSync as writeFileSync33 } from "fs";
|
|
14105
14573
|
import { homedir as homedir32 } from "os";
|
|
14106
|
-
import { join as
|
|
14574
|
+
import { join as join43 } from "path";
|
|
14575
|
+
function __exportSetter2(name, newValue) {
|
|
14576
|
+
this[name] = __returnValue2.bind(null, newValue);
|
|
14577
|
+
}
|
|
14107
14578
|
function isInMemoryDb(path) {
|
|
14108
14579
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
14109
14580
|
}
|
|
@@ -14111,7 +14582,7 @@ function findNearestMementosDb(startDir) {
|
|
|
14111
14582
|
let dir = resolve2(startDir);
|
|
14112
14583
|
while (true) {
|
|
14113
14584
|
const candidate = join12(dir, ".mementos", "mementos.db");
|
|
14114
|
-
if (
|
|
14585
|
+
if (existsSync8(candidate))
|
|
14115
14586
|
return candidate;
|
|
14116
14587
|
const parent = dirname3(dir);
|
|
14117
14588
|
if (parent === dir)
|
|
@@ -14123,7 +14594,7 @@ function findNearestMementosDb(startDir) {
|
|
|
14123
14594
|
function findGitRoot(startDir) {
|
|
14124
14595
|
let dir = resolve2(startDir);
|
|
14125
14596
|
while (true) {
|
|
14126
|
-
if (
|
|
14597
|
+
if (existsSync8(join12(dir, ".git")))
|
|
14127
14598
|
return dir;
|
|
14128
14599
|
const parent = dirname3(dir);
|
|
14129
14600
|
if (parent === dir)
|
|
@@ -14153,7 +14624,7 @@ function ensureDir2(filePath) {
|
|
|
14153
14624
|
if (isInMemoryDb(filePath))
|
|
14154
14625
|
return;
|
|
14155
14626
|
const dir = dirname3(resolve2(filePath));
|
|
14156
|
-
if (!
|
|
14627
|
+
if (!existsSync8(dir)) {
|
|
14157
14628
|
mkdirSync11(dir, { recursive: true });
|
|
14158
14629
|
}
|
|
14159
14630
|
}
|
|
@@ -16004,11 +16475,11 @@ function isValidCategory(value) {
|
|
|
16004
16475
|
return VALID_CATEGORIES.includes(value);
|
|
16005
16476
|
}
|
|
16006
16477
|
function loadConfig2() {
|
|
16007
|
-
const configPath = join23(
|
|
16478
|
+
const configPath = join23(homedir6(), ".mementos", "config.json");
|
|
16008
16479
|
let fileConfig = {};
|
|
16009
16480
|
if (existsSync23(configPath)) {
|
|
16010
16481
|
try {
|
|
16011
|
-
const raw =
|
|
16482
|
+
const raw = readFileSync8(configPath, "utf-8");
|
|
16012
16483
|
fileConfig = JSON.parse(raw);
|
|
16013
16484
|
} catch {}
|
|
16014
16485
|
}
|
|
@@ -16031,17 +16502,17 @@ function loadConfig2() {
|
|
|
16031
16502
|
return merged;
|
|
16032
16503
|
}
|
|
16033
16504
|
function profilesDir() {
|
|
16034
|
-
return join23(
|
|
16505
|
+
return join23(homedir6(), ".mementos", "profiles");
|
|
16035
16506
|
}
|
|
16036
16507
|
function globalConfigPath() {
|
|
16037
|
-
return join23(
|
|
16508
|
+
return join23(homedir6(), ".mementos", "config.json");
|
|
16038
16509
|
}
|
|
16039
16510
|
function readGlobalConfig() {
|
|
16040
16511
|
const p = globalConfigPath();
|
|
16041
16512
|
if (!existsSync23(p))
|
|
16042
16513
|
return {};
|
|
16043
16514
|
try {
|
|
16044
|
-
return JSON.parse(
|
|
16515
|
+
return JSON.parse(readFileSync8(p, "utf-8"));
|
|
16045
16516
|
} catch {
|
|
16046
16517
|
return {};
|
|
16047
16518
|
}
|
|
@@ -16071,7 +16542,7 @@ function listProfiles2() {
|
|
|
16071
16542
|
const dir = profilesDir();
|
|
16072
16543
|
if (!existsSync23(dir))
|
|
16073
16544
|
return [];
|
|
16074
|
-
return
|
|
16545
|
+
return readdirSync6(dir).filter((f) => f.endsWith(".db")).map((f) => basename2(f, ".db")).sort();
|
|
16075
16546
|
}
|
|
16076
16547
|
function deleteProfile2(name) {
|
|
16077
16548
|
const dbPath = join23(profilesDir(), `${name}.db`);
|
|
@@ -16433,7 +16904,7 @@ function runCleanup(config, db) {
|
|
|
16433
16904
|
function getAgentSyncDir(agentName) {
|
|
16434
16905
|
const dir = join33(homedir23(), ".mementos", "agents", agentName);
|
|
16435
16906
|
if (!existsSync33(dir)) {
|
|
16436
|
-
|
|
16907
|
+
mkdirSync33(dir, { recursive: true });
|
|
16437
16908
|
}
|
|
16438
16909
|
return dir;
|
|
16439
16910
|
}
|
|
@@ -17186,7 +17657,7 @@ ${matched.map((m) => `- ${m.key}: ${m.value.slice(0, 120)}${m.value.length > 120
|
|
|
17186
17657
|
};
|
|
17187
17658
|
}
|
|
17188
17659
|
function readConfig() {
|
|
17189
|
-
if (!
|
|
17660
|
+
if (!existsSync43(CONFIG_PATH))
|
|
17190
17661
|
return {};
|
|
17191
17662
|
try {
|
|
17192
17663
|
const raw = readFileSync33(CONFIG_PATH, "utf-8");
|
|
@@ -17196,10 +17667,10 @@ function readConfig() {
|
|
|
17196
17667
|
}
|
|
17197
17668
|
}
|
|
17198
17669
|
function writeConfig(config) {
|
|
17199
|
-
if (!
|
|
17670
|
+
if (!existsSync43(CONFIG_DIR)) {
|
|
17200
17671
|
mkdirSync42(CONFIG_DIR, { recursive: true });
|
|
17201
17672
|
}
|
|
17202
|
-
|
|
17673
|
+
writeFileSync33(CONFIG_PATH, JSON.stringify(config, null, 2) + `
|
|
17203
17674
|
`, "utf-8");
|
|
17204
17675
|
}
|
|
17205
17676
|
function getActiveModel() {
|
|
@@ -17216,13 +17687,13 @@ function clearActiveModel() {
|
|
|
17216
17687
|
delete config.activeModel;
|
|
17217
17688
|
writeConfig(config);
|
|
17218
17689
|
}
|
|
17219
|
-
var __defProp2, __export2 = (target, all) => {
|
|
17690
|
+
var __defProp2, __returnValue2 = (v) => v, __export2 = (target, all) => {
|
|
17220
17691
|
for (var name in all)
|
|
17221
17692
|
__defProp2(target, name, {
|
|
17222
17693
|
get: all[name],
|
|
17223
17694
|
enumerable: true,
|
|
17224
17695
|
configurable: true,
|
|
17225
|
-
set: (
|
|
17696
|
+
set: __exportSetter2.bind(all, name)
|
|
17226
17697
|
});
|
|
17227
17698
|
}, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), exports_database, MIGRATIONS, _db2 = null, init_database, AgentConflictError, EntityNotFoundError, MemoryNotFoundError, DuplicateMemoryError, MemoryExpiredError, InvalidScopeError, VersionConflictError, MemoryConflictError, OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings", EMBED_MODEL = "text-embedding-3-small", EMBED_DIMENSIONS = 1536, REDACTED = "[REDACTED]", SECRET_PATTERNS, _idCounter = 0, hookRegistry, INSTRUCTION_PATTERNS, PROMOTIONAL_PATTERNS, RECALL_PROMOTE_THRESHOLD = 3, CONFLICT_WINDOW_MS, MEMORY_WRITE_TTL = 30, MemoryLockConflictError, sessionFocus, STOP_WORDS, DEFAULT_CONFIG, VALID_SCOPES, VALID_CATEGORIES, defaultSyncAgents, DEFAULT_AUTO_MEMORY_CONFIG, MEMORY_EXTRACTION_SYSTEM_PROMPT = `You are a precise memory extraction engine for an AI agent.
|
|
17228
17699
|
Given text, extract facts worth remembering as structured JSON.
|
|
@@ -18558,8 +19029,8 @@ Return only a number 0-10.`);
|
|
|
18558
19029
|
keepLonger: true
|
|
18559
19030
|
};
|
|
18560
19031
|
_stats = { checked: 0, skipped: 0, updated: 0 };
|
|
18561
|
-
CONFIG_DIR =
|
|
18562
|
-
CONFIG_PATH =
|
|
19032
|
+
CONFIG_DIR = join43(homedir32(), ".mementos");
|
|
19033
|
+
CONFIG_PATH = join43(CONFIG_DIR, "config.json");
|
|
18563
19034
|
});
|
|
18564
19035
|
|
|
18565
19036
|
// src/lib/page-memory.ts
|
|
@@ -18637,7 +19108,7 @@ var init_page_memory = __esm(() => {
|
|
|
18637
19108
|
inMemoryCache = new Map;
|
|
18638
19109
|
});
|
|
18639
19110
|
|
|
18640
|
-
//
|
|
19111
|
+
// node_modules/@hasna/conversations/dist/index.js
|
|
18641
19112
|
var exports_dist3 = {};
|
|
18642
19113
|
__export(exports_dist3, {
|
|
18643
19114
|
useSpaceMessages: () => useSpaceMessages,
|
|
@@ -18646,6 +19117,7 @@ __export(exports_dist3, {
|
|
|
18646
19117
|
updateProject: () => updateProject,
|
|
18647
19118
|
unpinMessage: () => unpinMessage,
|
|
18648
19119
|
unarchiveSpace: () => unarchiveSpace,
|
|
19120
|
+
tryBulkAcquireLock: () => tryBulkAcquireLock,
|
|
18649
19121
|
startPolling: () => startPolling,
|
|
18650
19122
|
sendMessage: () => sendMessage,
|
|
18651
19123
|
searchMessages: () => searchMessages,
|
|
@@ -18654,6 +19126,7 @@ __export(exports_dist3, {
|
|
|
18654
19126
|
renameAgent: () => renameAgent,
|
|
18655
19127
|
removeReaction: () => removeReaction,
|
|
18656
19128
|
removePresence: () => removePresence,
|
|
19129
|
+
releaseStaleAgentLocks: () => releaseStaleAgentLocks,
|
|
18657
19130
|
releaseLock: () => releaseLock2,
|
|
18658
19131
|
registerAgent: () => registerAgent4,
|
|
18659
19132
|
readMessages: () => readMessages,
|
|
@@ -18665,6 +19138,7 @@ __export(exports_dist3, {
|
|
|
18665
19138
|
listSpaces: () => listSpaces,
|
|
18666
19139
|
listSessions: () => listSessions3,
|
|
18667
19140
|
listProjects: () => listProjects3,
|
|
19141
|
+
listLocksEnriched: () => listLocksEnriched,
|
|
18668
19142
|
listLocks: () => listLocks,
|
|
18669
19143
|
listHotSessions: () => listHotSessions,
|
|
18670
19144
|
listAgents: () => listAgents3,
|
|
@@ -18716,22 +19190,28 @@ __export(exports_dist3, {
|
|
|
18716
19190
|
import { Database as Database3 } from "bun:sqlite";
|
|
18717
19191
|
import { mkdirSync as mkdirSync12 } from "fs";
|
|
18718
19192
|
import { join as join13, dirname as dirname5 } from "path";
|
|
18719
|
-
import { homedir as
|
|
19193
|
+
import { homedir as homedir7 } from "os";
|
|
18720
19194
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
18721
|
-
import { mkdirSync as mkdirSync24, copyFileSync as
|
|
19195
|
+
import { mkdirSync as mkdirSync24, copyFileSync as copyFileSync4, statSync as statSync4 } from "fs";
|
|
18722
19196
|
import { join as join34 } from "path";
|
|
18723
19197
|
import { homedir as homedir33 } from "os";
|
|
18724
|
-
import { readFileSync as
|
|
19198
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
18725
19199
|
import { join as join24 } from "path";
|
|
18726
19200
|
import { homedir as homedir24 } from "os";
|
|
18727
19201
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
18728
|
-
import { readFileSync as readFileSync24, writeFileSync as writeFileSync6, mkdirSync as
|
|
18729
|
-
import { join as
|
|
19202
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync6, mkdirSync as mkdirSync34 } from "fs";
|
|
19203
|
+
import { join as join44, dirname as dirname23 } from "path";
|
|
18730
19204
|
import { homedir as homedir42 } from "os";
|
|
19205
|
+
function __accessProp2(key) {
|
|
19206
|
+
return this[key];
|
|
19207
|
+
}
|
|
19208
|
+
function __exportSetter3(name, newValue) {
|
|
19209
|
+
this[name] = __returnValue3.bind(null, newValue);
|
|
19210
|
+
}
|
|
18731
19211
|
function getDbPath2() {
|
|
18732
19212
|
if (process.env.CONVERSATIONS_DB_PATH)
|
|
18733
19213
|
return process.env.CONVERSATIONS_DB_PATH;
|
|
18734
|
-
return join13(
|
|
19214
|
+
return join13(homedir7(), ".conversations", "messages.db");
|
|
18735
19215
|
}
|
|
18736
19216
|
function getDb() {
|
|
18737
19217
|
if (db)
|
|
@@ -18883,6 +19363,9 @@ function getDb() {
|
|
|
18883
19363
|
if (!spaceColNames.includes("archived_at")) {
|
|
18884
19364
|
db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
|
|
18885
19365
|
}
|
|
19366
|
+
if (!spaceColNames.includes("topic")) {
|
|
19367
|
+
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
19368
|
+
}
|
|
18886
19369
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
18887
19370
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
18888
19371
|
if (!colNames2.includes("edited_at")) {
|
|
@@ -18930,6 +19413,30 @@ function getDb() {
|
|
|
18930
19413
|
if (!presenceColNames.includes("project_id")) {
|
|
18931
19414
|
db.exec("ALTER TABLE agent_presence ADD COLUMN project_id TEXT");
|
|
18932
19415
|
}
|
|
19416
|
+
db.exec(`
|
|
19417
|
+
CREATE TABLE IF NOT EXISTS message_read_receipts (
|
|
19418
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
19419
|
+
agent TEXT NOT NULL,
|
|
19420
|
+
read_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
19421
|
+
PRIMARY KEY (message_id, agent)
|
|
19422
|
+
)
|
|
19423
|
+
`);
|
|
19424
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_read_receipts_message ON message_read_receipts(message_id)");
|
|
19425
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_read_receipts_agent ON message_read_receipts(agent)");
|
|
19426
|
+
db.exec(`
|
|
19427
|
+
CREATE TABLE IF NOT EXISTS message_mentions (
|
|
19428
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
19429
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
19430
|
+
mentioned_agent TEXT NOT NULL,
|
|
19431
|
+
from_agent TEXT NOT NULL,
|
|
19432
|
+
space TEXT,
|
|
19433
|
+
notified_at TEXT,
|
|
19434
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))
|
|
19435
|
+
)
|
|
19436
|
+
`);
|
|
19437
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_mentions_agent ON message_mentions(mentioned_agent)");
|
|
19438
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_mentions_message ON message_mentions(message_id)");
|
|
19439
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_mentions_notified ON message_mentions(notified_at)");
|
|
18933
19440
|
const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
|
|
18934
19441
|
if (!ftsExists) {
|
|
18935
19442
|
db.exec(`
|
|
@@ -18979,7 +19486,7 @@ function loadConfig3() {
|
|
|
18979
19486
|
if (cachedConfig && now2 - configLoadedAt < CONFIG_CACHE_MS)
|
|
18980
19487
|
return cachedConfig;
|
|
18981
19488
|
try {
|
|
18982
|
-
const raw =
|
|
19489
|
+
const raw = readFileSync9(getConfigPath2(), "utf-8");
|
|
18983
19490
|
cachedConfig = JSON.parse(raw);
|
|
18984
19491
|
configLoadedAt = now2;
|
|
18985
19492
|
return cachedConfig;
|
|
@@ -19115,8 +19622,8 @@ function sendMessage(opts) {
|
|
|
19115
19622
|
const attachmentInfos = [];
|
|
19116
19623
|
for (const att of opts.attachments) {
|
|
19117
19624
|
const destPath = join34(attachmentsDir, att.name);
|
|
19118
|
-
|
|
19119
|
-
const stat =
|
|
19625
|
+
copyFileSync4(att.source_path, destPath);
|
|
19626
|
+
const stat = statSync4(destPath);
|
|
19120
19627
|
attachmentInfos.push({
|
|
19121
19628
|
name: att.name,
|
|
19122
19629
|
path: destPath,
|
|
@@ -19128,6 +19635,12 @@ function sendMessage(opts) {
|
|
|
19128
19635
|
db2.prepare("UPDATE messages SET attachments = ? WHERE id = ?").run(attachmentsJson, message.id);
|
|
19129
19636
|
message.attachments = attachmentInfos;
|
|
19130
19637
|
}
|
|
19638
|
+
if (opts.space) {
|
|
19639
|
+
const mentions = parseMentions(opts.content);
|
|
19640
|
+
if (mentions.length > 0) {
|
|
19641
|
+
processMentions(message.id, opts.from, opts.space, mentions, db2);
|
|
19642
|
+
}
|
|
19643
|
+
}
|
|
19131
19644
|
fireWebhooks(message);
|
|
19132
19645
|
return message;
|
|
19133
19646
|
}
|
|
@@ -19166,11 +19679,34 @@ function readMessages(opts = {}) {
|
|
|
19166
19679
|
if (opts.unread_only) {
|
|
19167
19680
|
conditions.push("read_at IS NULL");
|
|
19168
19681
|
}
|
|
19682
|
+
if (opts.threads_only) {
|
|
19683
|
+
conditions.push("reply_to IS NULL");
|
|
19684
|
+
}
|
|
19685
|
+
if (opts.mentions_only) {
|
|
19686
|
+
conditions.push(`id IN (SELECT message_id FROM message_mentions WHERE mentioned_agent = ?)`);
|
|
19687
|
+
params.push(opts.mentions_only.toLowerCase());
|
|
19688
|
+
}
|
|
19689
|
+
const isLatest = opts.latest && opts.latest > 0;
|
|
19169
19690
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
19170
|
-
const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
19171
|
-
const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
19172
|
-
const
|
|
19173
|
-
const
|
|
19691
|
+
const resolvedLimit = isLatest ? Math.floor(opts.latest) : Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
19692
|
+
const order = isLatest ? "DESC" : opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
19693
|
+
const resolvedOffset = opts.offset && opts.offset > 0 ? Math.floor(opts.offset) : 0;
|
|
19694
|
+
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit} OFFSET ${resolvedOffset}`).all(...params);
|
|
19695
|
+
let messages = rows.map(parseMessage);
|
|
19696
|
+
if (opts.include_reply_counts && messages.length > 0) {
|
|
19697
|
+
const db22 = getDb();
|
|
19698
|
+
const counts = db22.prepare(`SELECT reply_to, COUNT(*) as c FROM messages WHERE reply_to IN (${messages.map(() => "?").join(",")}) GROUP BY reply_to`).all(...messages.map((m) => m.id));
|
|
19699
|
+
const countMap = new Map(counts.map((r) => [r.reply_to, r.c]));
|
|
19700
|
+
messages = messages.map((m) => ({ ...m, reply_count: countMap.get(m.id) ?? 0 }));
|
|
19701
|
+
}
|
|
19702
|
+
if (opts.max_content_length && opts.max_content_length > 0) {
|
|
19703
|
+
messages = messages.map((m) => {
|
|
19704
|
+
if (m.content.length > opts.max_content_length) {
|
|
19705
|
+
return { ...m, content: m.content.slice(0, opts.max_content_length) + "\u2026", truncated: true };
|
|
19706
|
+
}
|
|
19707
|
+
return m;
|
|
19708
|
+
});
|
|
19709
|
+
}
|
|
19174
19710
|
if (opts.compact)
|
|
19175
19711
|
return messages.map(compactMessage);
|
|
19176
19712
|
return messages;
|
|
@@ -19351,6 +19887,14 @@ function searchMessages(opts) {
|
|
|
19351
19887
|
extraWhere += " AND m.to_agent = ?";
|
|
19352
19888
|
ftsParams.push(opts.to);
|
|
19353
19889
|
}
|
|
19890
|
+
if (opts.since) {
|
|
19891
|
+
extraWhere += " AND m.created_at >= ?";
|
|
19892
|
+
ftsParams.push(opts.since);
|
|
19893
|
+
}
|
|
19894
|
+
if (opts.until) {
|
|
19895
|
+
extraWhere += " AND m.created_at <= ?";
|
|
19896
|
+
ftsParams.push(opts.until);
|
|
19897
|
+
}
|
|
19354
19898
|
const orderClause = sortByRelevance ? "ORDER BY rank" : "ORDER BY m.created_at DESC, m.id DESC";
|
|
19355
19899
|
const rows2 = db2.prepare(`SELECT m.*, rank,
|
|
19356
19900
|
snippet(messages_fts, 0, '**', '**', '...', 20) as snippet
|
|
@@ -19383,6 +19927,14 @@ function searchMessages(opts) {
|
|
|
19383
19927
|
conditions.push("to_agent = ?");
|
|
19384
19928
|
params.push(opts.to);
|
|
19385
19929
|
}
|
|
19930
|
+
if (opts.since) {
|
|
19931
|
+
conditions.push("created_at >= ?");
|
|
19932
|
+
params.push(opts.since);
|
|
19933
|
+
}
|
|
19934
|
+
if (opts.until) {
|
|
19935
|
+
conditions.push("created_at <= ?");
|
|
19936
|
+
params.push(opts.until);
|
|
19937
|
+
}
|
|
19386
19938
|
const where = `WHERE ${conditions.join(" AND ")}`;
|
|
19387
19939
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
|
|
19388
19940
|
return rows.map((row) => {
|
|
@@ -19390,6 +19942,26 @@ function searchMessages(opts) {
|
|
|
19390
19942
|
return { ...msg, snippet: null, relevance_score: 0 };
|
|
19391
19943
|
});
|
|
19392
19944
|
}
|
|
19945
|
+
function parseMentions(content) {
|
|
19946
|
+
const matches = content.match(/@([a-zA-Z0-9_-]+)/g) ?? [];
|
|
19947
|
+
return [...new Set(matches.map((m) => m.slice(1).toLowerCase()))];
|
|
19948
|
+
}
|
|
19949
|
+
async function processMentions(messageId, fromAgent, space, mentionedAgents, db2) {
|
|
19950
|
+
const stmt = db2.prepare("INSERT INTO message_mentions (message_id, mentioned_agent, from_agent, space) VALUES (?, ?, ?, ?)");
|
|
19951
|
+
for (const agent of mentionedAgents) {
|
|
19952
|
+
try {
|
|
19953
|
+
stmt.run(messageId, agent, fromAgent, space);
|
|
19954
|
+
if (agent !== fromAgent.toLowerCase()) {
|
|
19955
|
+
sendMessage({
|
|
19956
|
+
from: fromAgent,
|
|
19957
|
+
to: agent,
|
|
19958
|
+
content: `You were mentioned in #${space} by ${fromAgent} (message #${messageId})`,
|
|
19959
|
+
metadata: { type: "mention_notification", source_message_id: messageId, space }
|
|
19960
|
+
});
|
|
19961
|
+
}
|
|
19962
|
+
} catch {}
|
|
19963
|
+
}
|
|
19964
|
+
}
|
|
19393
19965
|
function listSessions3(agent) {
|
|
19394
19966
|
const db2 = getDb();
|
|
19395
19967
|
const agentFilter = agent ? "WHERE from_agent = ? OR to_agent = ?" : "";
|
|
@@ -19924,7 +20496,7 @@ function getAutoName() {
|
|
|
19924
20496
|
}
|
|
19925
20497
|
cachedAutoName = name;
|
|
19926
20498
|
try {
|
|
19927
|
-
|
|
20499
|
+
mkdirSync34(dirname23(AGENT_ID_FILE), { recursive: true });
|
|
19928
20500
|
writeFileSync6(AGENT_ID_FILE, name + `
|
|
19929
20501
|
`, "utf-8");
|
|
19930
20502
|
} catch {}
|
|
@@ -20116,6 +20688,7 @@ function acquireLock2(resourceType, resourceId, agentId, lockType = "advisory",
|
|
|
20116
20688
|
const db2 = getDb();
|
|
20117
20689
|
return db2.transaction(() => {
|
|
20118
20690
|
cleanExpiredLocks2();
|
|
20691
|
+
releaseStaleAgentLocks();
|
|
20119
20692
|
const existing = db2.prepare(`
|
|
20120
20693
|
SELECT * FROM resource_locks
|
|
20121
20694
|
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
@@ -20142,6 +20715,55 @@ function acquireLock2(resourceType, resourceId, agentId, lockType = "advisory",
|
|
|
20142
20715
|
return { acquired: true, lock };
|
|
20143
20716
|
}).immediate();
|
|
20144
20717
|
}
|
|
20718
|
+
function bulkAcquireLock(resources, agentId) {
|
|
20719
|
+
const db2 = getDb();
|
|
20720
|
+
return db2.transaction(() => {
|
|
20721
|
+
cleanExpiredLocks2();
|
|
20722
|
+
releaseStaleAgentLocks();
|
|
20723
|
+
const acquired = [];
|
|
20724
|
+
for (const { resource_type, resource_id, lock_type = "advisory", expiry_ms = DEFAULT_LOCK_EXPIRY_MS } of resources) {
|
|
20725
|
+
const existing = db2.prepare(`
|
|
20726
|
+
SELECT * FROM resource_locks
|
|
20727
|
+
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
20728
|
+
`).get(resource_type, resource_id, lock_type);
|
|
20729
|
+
if (existing && existing.agent_id !== agentId) {
|
|
20730
|
+
throw { _bulkConflict: true, resource_type, resource_id, held_by: existing.agent_id };
|
|
20731
|
+
}
|
|
20732
|
+
const expiresAt = new Date(Date.now() + expiry_ms).toISOString().slice(0, -1);
|
|
20733
|
+
if (existing) {
|
|
20734
|
+
db2.prepare(`
|
|
20735
|
+
UPDATE resource_locks SET expires_at = ?, locked_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
|
|
20736
|
+
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
20737
|
+
`).run(expiresAt, resource_type, resource_id, lock_type);
|
|
20738
|
+
} else {
|
|
20739
|
+
db2.prepare(`
|
|
20740
|
+
INSERT INTO resource_locks (resource_type, resource_id, agent_id, lock_type, locked_at, expires_at)
|
|
20741
|
+
VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%f', 'now'), ?)
|
|
20742
|
+
`).run(resource_type, resource_id, agentId, lock_type, expiresAt);
|
|
20743
|
+
}
|
|
20744
|
+
const lock = db2.prepare(`
|
|
20745
|
+
SELECT * FROM resource_locks WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
20746
|
+
`).get(resource_type, resource_id, lock_type);
|
|
20747
|
+
acquired.push(lock);
|
|
20748
|
+
}
|
|
20749
|
+
return { acquired: true, locks: acquired };
|
|
20750
|
+
}).immediate();
|
|
20751
|
+
}
|
|
20752
|
+
function tryBulkAcquireLock(resources, agentId) {
|
|
20753
|
+
try {
|
|
20754
|
+
return bulkAcquireLock(resources, agentId);
|
|
20755
|
+
} catch (err2) {
|
|
20756
|
+
const e = err2;
|
|
20757
|
+
if (e?._bulkConflict) {
|
|
20758
|
+
return {
|
|
20759
|
+
acquired: false,
|
|
20760
|
+
locks: [],
|
|
20761
|
+
blocked_by: { resource_type: e.resource_type, resource_id: e.resource_id, held_by: e.held_by }
|
|
20762
|
+
};
|
|
20763
|
+
}
|
|
20764
|
+
throw err2;
|
|
20765
|
+
}
|
|
20766
|
+
}
|
|
20145
20767
|
function releaseLock2(resourceType, resourceId, agentId) {
|
|
20146
20768
|
const db2 = getDb();
|
|
20147
20769
|
const result = db2.prepare(`
|
|
@@ -20153,6 +20775,7 @@ function releaseLock2(resourceType, resourceId, agentId) {
|
|
|
20153
20775
|
function checkLock2(resourceType, resourceId) {
|
|
20154
20776
|
const db2 = getDb();
|
|
20155
20777
|
cleanExpiredLocks2();
|
|
20778
|
+
releaseStaleAgentLocks();
|
|
20156
20779
|
return db2.prepare(`
|
|
20157
20780
|
SELECT * FROM resource_locks
|
|
20158
20781
|
WHERE resource_type = ? AND resource_id = ?
|
|
@@ -20160,6 +20783,17 @@ function checkLock2(resourceType, resourceId) {
|
|
|
20160
20783
|
LIMIT 1
|
|
20161
20784
|
`).get(resourceType, resourceId);
|
|
20162
20785
|
}
|
|
20786
|
+
function releaseStaleAgentLocks() {
|
|
20787
|
+
const db2 = getDb();
|
|
20788
|
+
const result = db2.prepare(`
|
|
20789
|
+
DELETE FROM resource_locks
|
|
20790
|
+
WHERE LOWER(agent_id) IN (
|
|
20791
|
+
SELECT LOWER(agent) FROM agent_presence
|
|
20792
|
+
WHERE last_seen_at < strftime('%Y-%m-%dT%H:%M:%f', 'now', '-${STALE_HEARTBEAT_SECONDS} seconds')
|
|
20793
|
+
)
|
|
20794
|
+
`).run();
|
|
20795
|
+
return result.changes;
|
|
20796
|
+
}
|
|
20163
20797
|
function cleanExpiredLocks2() {
|
|
20164
20798
|
const db2 = getDb();
|
|
20165
20799
|
const result = db2.prepare(`
|
|
@@ -20170,6 +20804,7 @@ function cleanExpiredLocks2() {
|
|
|
20170
20804
|
function listLocks(opts) {
|
|
20171
20805
|
const db2 = getDb();
|
|
20172
20806
|
cleanExpiredLocks2();
|
|
20807
|
+
releaseStaleAgentLocks();
|
|
20173
20808
|
let query = "SELECT * FROM resource_locks WHERE 1=1";
|
|
20174
20809
|
const params = [];
|
|
20175
20810
|
if (opts?.resource_type) {
|
|
@@ -20183,6 +20818,31 @@ function listLocks(opts) {
|
|
|
20183
20818
|
query += " ORDER BY locked_at ASC";
|
|
20184
20819
|
return db2.prepare(query).all(...params);
|
|
20185
20820
|
}
|
|
20821
|
+
function listLocksEnriched(opts) {
|
|
20822
|
+
const locks = listLocks(opts);
|
|
20823
|
+
const db2 = getDb();
|
|
20824
|
+
const nowMs = Date.now();
|
|
20825
|
+
return locks.map((lock) => {
|
|
20826
|
+
const lockedMs = new Date(lock.locked_at + "Z").getTime();
|
|
20827
|
+
const expiresMs = new Date(lock.expires_at + "Z").getTime();
|
|
20828
|
+
const presenceRow = db2.prepare(`
|
|
20829
|
+
SELECT role, status, last_seen_at, project_id FROM agent_presence WHERE LOWER(agent) = LOWER(?)
|
|
20830
|
+
`).get(lock.agent_id);
|
|
20831
|
+
const agent = presenceRow ? {
|
|
20832
|
+
role: presenceRow.role ?? null,
|
|
20833
|
+
status: presenceRow.status ?? null,
|
|
20834
|
+
online: presenceRow.last_seen_at ? nowMs - new Date(presenceRow.last_seen_at + "Z").getTime() < 60000 : false,
|
|
20835
|
+
last_seen_at: presenceRow.last_seen_at ?? null,
|
|
20836
|
+
project_id: presenceRow.project_id ?? null
|
|
20837
|
+
} : null;
|
|
20838
|
+
return {
|
|
20839
|
+
...lock,
|
|
20840
|
+
locked_seconds_ago: Math.round((nowMs - lockedMs) / 1000),
|
|
20841
|
+
expires_in_seconds: Math.round((expiresMs - nowMs) / 1000),
|
|
20842
|
+
agent
|
|
20843
|
+
};
|
|
20844
|
+
});
|
|
20845
|
+
}
|
|
20186
20846
|
function computeHotness(sessionId) {
|
|
20187
20847
|
const db2 = getDb();
|
|
20188
20848
|
const base = db2.prepare(`
|
|
@@ -20531,37 +21191,49 @@ function getGraphStats() {
|
|
|
20531
21191
|
map[r.relation] = r.c;
|
|
20532
21192
|
return { total_edges: total, by_relation: map };
|
|
20533
21193
|
}
|
|
20534
|
-
var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2, __getOwnPropDesc2, __hasOwnProp2, __toESM2 = (mod, isNodeMode, target) => {
|
|
21194
|
+
var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2, __getOwnPropDesc2, __hasOwnProp2, __toESMCache_node2, __toESMCache_esm2, __toESM2 = (mod, isNodeMode, target) => {
|
|
21195
|
+
var canCache = mod != null && typeof mod === "object";
|
|
21196
|
+
if (canCache) {
|
|
21197
|
+
var cache = isNodeMode ? __toESMCache_node2 ??= new WeakMap : __toESMCache_esm2 ??= new WeakMap;
|
|
21198
|
+
var cached = cache.get(mod);
|
|
21199
|
+
if (cached)
|
|
21200
|
+
return cached;
|
|
21201
|
+
}
|
|
20535
21202
|
target = mod != null ? __create2(__getProtoOf2(mod)) : {};
|
|
20536
21203
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp3(target, "default", { value: mod, enumerable: true }) : target;
|
|
20537
21204
|
for (let key of __getOwnPropNames2(mod))
|
|
20538
21205
|
if (!__hasOwnProp2.call(to, key))
|
|
20539
21206
|
__defProp3(to, key, {
|
|
20540
|
-
get: (
|
|
21207
|
+
get: __accessProp2.bind(mod, key),
|
|
20541
21208
|
enumerable: true
|
|
20542
21209
|
});
|
|
21210
|
+
if (canCache)
|
|
21211
|
+
cache.set(mod, to);
|
|
20543
21212
|
return to;
|
|
20544
|
-
},
|
|
20545
|
-
var entry = __moduleCache2.get(from), desc;
|
|
21213
|
+
}, __toCommonJS2 = (from) => {
|
|
21214
|
+
var entry = (__moduleCache2 ??= new WeakMap).get(from), desc;
|
|
20546
21215
|
if (entry)
|
|
20547
21216
|
return entry;
|
|
20548
21217
|
entry = __defProp3({}, "__esModule", { value: true });
|
|
20549
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
20550
|
-
|
|
20551
|
-
|
|
20552
|
-
|
|
20553
|
-
|
|
21218
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21219
|
+
for (var key of __getOwnPropNames2(from))
|
|
21220
|
+
if (!__hasOwnProp2.call(entry, key))
|
|
21221
|
+
__defProp3(entry, key, {
|
|
21222
|
+
get: __accessProp2.bind(from, key),
|
|
21223
|
+
enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
|
|
21224
|
+
});
|
|
21225
|
+
}
|
|
20554
21226
|
__moduleCache2.set(from, entry);
|
|
20555
21227
|
return entry;
|
|
20556
|
-
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __export3 = (target, all) => {
|
|
21228
|
+
}, __moduleCache2, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue3 = (v) => v, __export3 = (target, all) => {
|
|
20557
21229
|
for (var name in all)
|
|
20558
21230
|
__defProp3(target, name, {
|
|
20559
21231
|
get: all[name],
|
|
20560
21232
|
enumerable: true,
|
|
20561
21233
|
configurable: true,
|
|
20562
|
-
set: (
|
|
21234
|
+
set: __exportSetter3.bind(all, name)
|
|
20563
21235
|
});
|
|
20564
|
-
}, exports_db, db = null, init_db = () => {}, require_react_development, require_react, cachedConfig = null, configLoadedAt = 0, CONFIG_CACHE_MS = 1e4, import_react, AGENT_NAMES, AGENT_ID_FILE, cachedAutoName = null, ONLINE_THRESHOLD_SECONDS = 60, CONFLICT_THRESHOLD_SECONDS, DEFAULT_LOCK_EXPIRY_MS, STOPWORDS;
|
|
21236
|
+
}, exports_db, db = null, init_db = () => {}, require_react_development, require_react, cachedConfig = null, configLoadedAt = 0, CONFIG_CACHE_MS = 1e4, import_react, AGENT_NAMES, AGENT_ID_FILE, cachedAutoName = null, ONLINE_THRESHOLD_SECONDS = 60, CONFLICT_THRESHOLD_SECONDS, DEFAULT_LOCK_EXPIRY_MS, STALE_HEARTBEAT_SECONDS, STOPWORDS;
|
|
20565
21237
|
var init_dist3 = __esm(() => {
|
|
20566
21238
|
__create2 = Object.create;
|
|
20567
21239
|
__getProtoOf2 = Object.getPrototypeOf;
|
|
@@ -20569,7 +21241,6 @@ var init_dist3 = __esm(() => {
|
|
|
20569
21241
|
__getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
20570
21242
|
__getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
20571
21243
|
__hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
20572
|
-
__moduleCache2 = /* @__PURE__ */ new WeakMap;
|
|
20573
21244
|
exports_db = {};
|
|
20574
21245
|
__export3(exports_db, {
|
|
20575
21246
|
getDbPath: () => getDbPath2,
|
|
@@ -22736,12 +23407,13 @@ Check the top-level render call using <` + parentName + ">.";
|
|
|
22736
23407
|
"zinc-eagle",
|
|
22737
23408
|
"zone-fox"
|
|
22738
23409
|
];
|
|
22739
|
-
AGENT_ID_FILE =
|
|
23410
|
+
AGENT_ID_FILE = join44(homedir42(), ".conversations", "agent-id");
|
|
22740
23411
|
init_db();
|
|
22741
23412
|
init_db();
|
|
22742
23413
|
CONFLICT_THRESHOLD_SECONDS = 30 * 60;
|
|
22743
23414
|
init_db();
|
|
22744
23415
|
DEFAULT_LOCK_EXPIRY_MS = 5 * 60 * 1000;
|
|
23416
|
+
STALE_HEARTBEAT_SECONDS = 30 * 60;
|
|
22745
23417
|
init_db();
|
|
22746
23418
|
init_db();
|
|
22747
23419
|
STOPWORDS = new Set([
|
|
@@ -22938,7 +23610,7 @@ var init_coordination = __esm(() => {
|
|
|
22938
23610
|
activeNavigations = new Map;
|
|
22939
23611
|
});
|
|
22940
23612
|
|
|
22941
|
-
//
|
|
23613
|
+
// node_modules/@hasna/todos/dist/index.js
|
|
22942
23614
|
var exports_dist4 = {};
|
|
22943
23615
|
__export(exports_dist4, {
|
|
22944
23616
|
uuid: () => uuid2,
|
|
@@ -22965,6 +23637,7 @@ __export(exports_dist4, {
|
|
|
22965
23637
|
setTaskStatus: () => setTaskStatus,
|
|
22966
23638
|
setTaskPriority: () => setTaskPriority,
|
|
22967
23639
|
setBudget: () => setBudget,
|
|
23640
|
+
setActiveModel: () => setActiveModel2,
|
|
22968
23641
|
searchTasks: () => searchTasks,
|
|
22969
23642
|
scoreTask: () => scoreTask,
|
|
22970
23643
|
saveSnapshot: () => saveSnapshot,
|
|
@@ -23064,6 +23737,8 @@ __export(exports_dist4, {
|
|
|
23064
23737
|
getAgentByName: () => getAgentByName2,
|
|
23065
23738
|
getAgent: () => getAgent3,
|
|
23066
23739
|
getActiveWork: () => getActiveWork,
|
|
23740
|
+
getActiveModel: () => getActiveModel2,
|
|
23741
|
+
gatherTrainingData: () => gatherTrainingData2,
|
|
23067
23742
|
findTasksByFile: () => findTasksByFile,
|
|
23068
23743
|
findRelatedTaskIds: () => findRelatedTaskIds,
|
|
23069
23744
|
findPath: () => findPath2,
|
|
@@ -23101,6 +23776,7 @@ __export(exports_dist4, {
|
|
|
23101
23776
|
closeDatabase: () => closeDatabase2,
|
|
23102
23777
|
cloneTask: () => cloneTask,
|
|
23103
23778
|
clearChecklist: () => clearChecklist,
|
|
23779
|
+
clearActiveModel: () => clearActiveModel2,
|
|
23104
23780
|
cleanExpiredLocks: () => cleanExpiredLocks3,
|
|
23105
23781
|
claimOrSteal: () => claimOrSteal,
|
|
23106
23782
|
claimNextTask: () => claimNextTask,
|
|
@@ -23135,22 +23811,26 @@ __export(exports_dist4, {
|
|
|
23135
23811
|
LockError: () => LockError,
|
|
23136
23812
|
EXTRACT_TAGS: () => EXTRACT_TAGS,
|
|
23137
23813
|
DependencyCycleError: () => DependencyCycleError,
|
|
23814
|
+
DEFAULT_MODEL: () => DEFAULT_MODEL3,
|
|
23138
23815
|
CompletionGuardError: () => CompletionGuardError,
|
|
23139
23816
|
AgentNotFoundError: () => AgentNotFoundError2
|
|
23140
23817
|
});
|
|
23141
23818
|
import { Database as Database4 } from "bun:sqlite";
|
|
23142
|
-
import { existsSync as
|
|
23819
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync13 } from "fs";
|
|
23143
23820
|
import { dirname as dirname6, join as join14, resolve as resolve3 } from "path";
|
|
23144
23821
|
import { existsSync as existsSync34 } from "fs";
|
|
23145
23822
|
import { join as join35 } from "path";
|
|
23146
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync25, readFileSync as
|
|
23823
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync25, readFileSync as readFileSync10, readdirSync as readdirSync7, statSync as statSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
23147
23824
|
import { join as join25 } from "path";
|
|
23148
|
-
import { existsSync as
|
|
23149
|
-
import {
|
|
23150
|
-
import {
|
|
23151
|
-
import {
|
|
23152
|
-
import {
|
|
23153
|
-
import {
|
|
23825
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync35, readFileSync as readFileSync25, writeFileSync as writeFileSync24 } from "fs";
|
|
23826
|
+
import { homedir as homedir8 } from "os";
|
|
23827
|
+
import { join as join45 } from "path";
|
|
23828
|
+
import { existsSync as existsSync53, readFileSync as readFileSync34, readdirSync as readdirSync23, writeFileSync as writeFileSync34 } from "fs";
|
|
23829
|
+
import { join as join53 } from "path";
|
|
23830
|
+
import { existsSync as existsSync62 } from "fs";
|
|
23831
|
+
import { join as join62 } from "path";
|
|
23832
|
+
import { readFileSync as readFileSync42, statSync as statSync22 } from "fs";
|
|
23833
|
+
import { relative, resolve as resolve23, join as join72 } from "path";
|
|
23154
23834
|
import { execSync as execSync2 } from "child_process";
|
|
23155
23835
|
|
|
23156
23836
|
class TodosClient {
|
|
@@ -23374,7 +24054,7 @@ function findNearestTodosDb(startDir) {
|
|
|
23374
24054
|
let dir = resolve3(startDir);
|
|
23375
24055
|
while (true) {
|
|
23376
24056
|
const candidate = join14(dir, ".todos", "todos.db");
|
|
23377
|
-
if (
|
|
24057
|
+
if (existsSync9(candidate))
|
|
23378
24058
|
return candidate;
|
|
23379
24059
|
const parent = dirname6(dir);
|
|
23380
24060
|
if (parent === dir)
|
|
@@ -23386,7 +24066,7 @@ function findNearestTodosDb(startDir) {
|
|
|
23386
24066
|
function findGitRoot2(startDir) {
|
|
23387
24067
|
let dir = resolve3(startDir);
|
|
23388
24068
|
while (true) {
|
|
23389
|
-
if (
|
|
24069
|
+
if (existsSync9(join14(dir, ".git")))
|
|
23390
24070
|
return dir;
|
|
23391
24071
|
const parent = dirname6(dir);
|
|
23392
24072
|
if (parent === dir)
|
|
@@ -23416,7 +24096,7 @@ function ensureDir3(filePath) {
|
|
|
23416
24096
|
if (isInMemoryDb2(filePath))
|
|
23417
24097
|
return;
|
|
23418
24098
|
const dir = dirname6(resolve3(filePath));
|
|
23419
|
-
if (!
|
|
24099
|
+
if (!existsSync9(dir)) {
|
|
23420
24100
|
mkdirSync13(dir, { recursive: true });
|
|
23421
24101
|
}
|
|
23422
24102
|
}
|
|
@@ -23883,11 +24563,11 @@ function ensureDir23(dir) {
|
|
|
23883
24563
|
function listJsonFiles(dir) {
|
|
23884
24564
|
if (!existsSync24(dir))
|
|
23885
24565
|
return [];
|
|
23886
|
-
return
|
|
24566
|
+
return readdirSync7(dir).filter((f) => f.endsWith(".json"));
|
|
23887
24567
|
}
|
|
23888
24568
|
function readJsonFile(path) {
|
|
23889
24569
|
try {
|
|
23890
|
-
return JSON.parse(
|
|
24570
|
+
return JSON.parse(readFileSync10(path, "utf-8"));
|
|
23891
24571
|
} catch {
|
|
23892
24572
|
return null;
|
|
23893
24573
|
}
|
|
@@ -23900,7 +24580,7 @@ function readHighWaterMark(dir) {
|
|
|
23900
24580
|
const path = join25(dir, ".highwatermark");
|
|
23901
24581
|
if (!existsSync24(path))
|
|
23902
24582
|
return 1;
|
|
23903
|
-
const val = parseInt(
|
|
24583
|
+
const val = parseInt(readFileSync10(path, "utf-8").trim(), 10);
|
|
23904
24584
|
return isNaN(val) ? 1 : val;
|
|
23905
24585
|
}
|
|
23906
24586
|
function writeHighWaterMark(dir, value) {
|
|
@@ -23908,7 +24588,7 @@ function writeHighWaterMark(dir, value) {
|
|
|
23908
24588
|
}
|
|
23909
24589
|
function getFileMtimeMs(path) {
|
|
23910
24590
|
try {
|
|
23911
|
-
return
|
|
24591
|
+
return statSync5(path).mtimeMs;
|
|
23912
24592
|
} catch {
|
|
23913
24593
|
return null;
|
|
23914
24594
|
}
|
|
@@ -25881,6 +26561,91 @@ function deleteSession2(id, db2) {
|
|
|
25881
26561
|
const result = d.run("DELETE FROM sessions WHERE id = ?", [id]);
|
|
25882
26562
|
return result.changes > 0;
|
|
25883
26563
|
}
|
|
26564
|
+
function taskToCreateExample(task) {
|
|
26565
|
+
const userMsg = `Create a task: ${task.title}${task.description ? `
|
|
26566
|
+
|
|
26567
|
+
Description: ${task.description}` : ""}`;
|
|
26568
|
+
const taskDetails = {
|
|
26569
|
+
id: task.short_id ?? task.id,
|
|
26570
|
+
title: task.title,
|
|
26571
|
+
description: task.description ?? "",
|
|
26572
|
+
status: task.status,
|
|
26573
|
+
priority: task.priority,
|
|
26574
|
+
tags: task.tags,
|
|
26575
|
+
created_at: task.created_at
|
|
26576
|
+
};
|
|
26577
|
+
return {
|
|
26578
|
+
messages: [
|
|
26579
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
26580
|
+
{ role: "user", content: userMsg },
|
|
26581
|
+
{
|
|
26582
|
+
role: "assistant",
|
|
26583
|
+
content: `Created task: ${JSON.stringify(taskDetails, null, 2)}`
|
|
26584
|
+
}
|
|
26585
|
+
]
|
|
26586
|
+
};
|
|
26587
|
+
}
|
|
26588
|
+
function taskToStatusUpdateExample(task) {
|
|
26589
|
+
if (!task.completed_at && task.status === "pending")
|
|
26590
|
+
return null;
|
|
26591
|
+
const id = task.short_id ?? task.id;
|
|
26592
|
+
return {
|
|
26593
|
+
messages: [
|
|
26594
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
26595
|
+
{ role: "user", content: `Mark task ${id} as ${task.status}` },
|
|
26596
|
+
{
|
|
26597
|
+
role: "assistant",
|
|
26598
|
+
content: `Task ${id} has been updated to status: ${task.status}. ${task.completed_at ? `Completed at: ${task.completed_at}` : ""}`.trim()
|
|
26599
|
+
}
|
|
26600
|
+
]
|
|
26601
|
+
};
|
|
26602
|
+
}
|
|
26603
|
+
function taskToSearchExample(tasks, query) {
|
|
26604
|
+
const matched = tasks.filter((t) => t.title.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
|
|
26605
|
+
return {
|
|
26606
|
+
messages: [
|
|
26607
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
26608
|
+
{ role: "user", content: `Search tasks for: "${query}"` },
|
|
26609
|
+
{
|
|
26610
|
+
role: "assistant",
|
|
26611
|
+
content: matched.length > 0 ? `Found ${matched.length} task(s):
|
|
26612
|
+
${matched.map((t) => `- [${t.short_id ?? t.id}] ${t.title} (${t.status})`).join(`
|
|
26613
|
+
`)}` : `No tasks found matching "${query}".`
|
|
26614
|
+
}
|
|
26615
|
+
]
|
|
26616
|
+
};
|
|
26617
|
+
}
|
|
26618
|
+
function readConfig2() {
|
|
26619
|
+
if (!existsSync44(CONFIG_PATH2))
|
|
26620
|
+
return {};
|
|
26621
|
+
try {
|
|
26622
|
+
const raw = readFileSync25(CONFIG_PATH2, "utf-8");
|
|
26623
|
+
return JSON.parse(raw);
|
|
26624
|
+
} catch {
|
|
26625
|
+
return {};
|
|
26626
|
+
}
|
|
26627
|
+
}
|
|
26628
|
+
function writeConfig2(config) {
|
|
26629
|
+
if (!existsSync44(CONFIG_DIR2)) {
|
|
26630
|
+
mkdirSync35(CONFIG_DIR2, { recursive: true });
|
|
26631
|
+
}
|
|
26632
|
+
writeFileSync24(CONFIG_PATH2, JSON.stringify(config, null, 2) + `
|
|
26633
|
+
`, "utf-8");
|
|
26634
|
+
}
|
|
26635
|
+
function getActiveModel2() {
|
|
26636
|
+
const config = readConfig2();
|
|
26637
|
+
return config.activeModel ?? DEFAULT_MODEL3;
|
|
26638
|
+
}
|
|
26639
|
+
function setActiveModel2(modelId) {
|
|
26640
|
+
const config = readConfig2();
|
|
26641
|
+
config.activeModel = modelId;
|
|
26642
|
+
writeConfig2(config);
|
|
26643
|
+
}
|
|
26644
|
+
function clearActiveModel2() {
|
|
26645
|
+
const config = readConfig2();
|
|
26646
|
+
delete config.activeModel;
|
|
26647
|
+
writeConfig2(config);
|
|
26648
|
+
}
|
|
25884
26649
|
function createHandoff(input, db2) {
|
|
25885
26650
|
const d = db2 || getDatabase3();
|
|
25886
26651
|
const id = uuid2();
|
|
@@ -26695,13 +27460,13 @@ function searchTasks(options, projectId, taskListId, db2) {
|
|
|
26695
27460
|
return rows.map(rowToTask3);
|
|
26696
27461
|
}
|
|
26697
27462
|
function getTaskListDir(taskListId) {
|
|
26698
|
-
return
|
|
27463
|
+
return join53(HOME, ".claude", "tasks", taskListId);
|
|
26699
27464
|
}
|
|
26700
27465
|
function readClaudeTask(dir, filename) {
|
|
26701
|
-
return readJsonFile(
|
|
27466
|
+
return readJsonFile(join53(dir, filename));
|
|
26702
27467
|
}
|
|
26703
27468
|
function writeClaudeTask(dir, task) {
|
|
26704
|
-
writeJsonFile(
|
|
27469
|
+
writeJsonFile(join53(dir, `${task.id}.json`), task);
|
|
26705
27470
|
}
|
|
26706
27471
|
function toClaudeStatus(status) {
|
|
26707
27472
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -26713,14 +27478,14 @@ function toSqliteStatus(status) {
|
|
|
26713
27478
|
return status;
|
|
26714
27479
|
}
|
|
26715
27480
|
function readPrefixCounter(dir) {
|
|
26716
|
-
const path =
|
|
26717
|
-
if (!
|
|
27481
|
+
const path = join53(dir, ".prefix-counter");
|
|
27482
|
+
if (!existsSync53(path))
|
|
26718
27483
|
return 0;
|
|
26719
|
-
const val = parseInt(
|
|
27484
|
+
const val = parseInt(readFileSync34(path, "utf-8").trim(), 10);
|
|
26720
27485
|
return isNaN(val) ? 0 : val;
|
|
26721
27486
|
}
|
|
26722
27487
|
function writePrefixCounter(dir, value) {
|
|
26723
|
-
|
|
27488
|
+
writeFileSync34(join53(dir, ".prefix-counter"), String(value));
|
|
26724
27489
|
}
|
|
26725
27490
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
26726
27491
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -26747,7 +27512,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
26747
27512
|
}
|
|
26748
27513
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
26749
27514
|
const dir = getTaskListDir(taskListId);
|
|
26750
|
-
if (!
|
|
27515
|
+
if (!existsSync53(dir))
|
|
26751
27516
|
ensureDir23(dir);
|
|
26752
27517
|
const filter = {};
|
|
26753
27518
|
if (projectId)
|
|
@@ -26756,7 +27521,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
26756
27521
|
const existingByTodosId = new Map;
|
|
26757
27522
|
const files = listJsonFiles(dir);
|
|
26758
27523
|
for (const f of files) {
|
|
26759
|
-
const path =
|
|
27524
|
+
const path = join53(dir, f);
|
|
26760
27525
|
const ct = readClaudeTask(dir, f);
|
|
26761
27526
|
if (ct?.metadata?.["todos_id"]) {
|
|
26762
27527
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -26843,7 +27608,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
26843
27608
|
}
|
|
26844
27609
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
26845
27610
|
const dir = getTaskListDir(taskListId);
|
|
26846
|
-
if (!
|
|
27611
|
+
if (!existsSync53(dir)) {
|
|
26847
27612
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
26848
27613
|
}
|
|
26849
27614
|
const files = readdirSync23(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -26863,7 +27628,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
26863
27628
|
}
|
|
26864
27629
|
for (const f of files) {
|
|
26865
27630
|
try {
|
|
26866
|
-
const filePath =
|
|
27631
|
+
const filePath = join53(dir, f);
|
|
26867
27632
|
const ct = readClaudeTask(dir, f);
|
|
26868
27633
|
if (!ct)
|
|
26869
27634
|
continue;
|
|
@@ -26931,16 +27696,16 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
26931
27696
|
}
|
|
26932
27697
|
function agentBaseDir(agent) {
|
|
26933
27698
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
26934
|
-
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
27699
|
+
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join62(HOME, ".todos", "agents");
|
|
26935
27700
|
}
|
|
26936
27701
|
function getTaskListDir2(agent, taskListId) {
|
|
26937
|
-
return
|
|
27702
|
+
return join62(agentBaseDir(agent), agent, taskListId);
|
|
26938
27703
|
}
|
|
26939
27704
|
function readAgentTask(dir, filename) {
|
|
26940
|
-
return readJsonFile(
|
|
27705
|
+
return readJsonFile(join62(dir, filename));
|
|
26941
27706
|
}
|
|
26942
27707
|
function writeAgentTask(dir, task) {
|
|
26943
|
-
writeJsonFile(
|
|
27708
|
+
writeJsonFile(join62(dir, `${task.id}.json`), task);
|
|
26944
27709
|
}
|
|
26945
27710
|
function taskToAgentTask(task, externalId, existingMeta) {
|
|
26946
27711
|
return {
|
|
@@ -26965,7 +27730,7 @@ function metadataKey(agent) {
|
|
|
26965
27730
|
}
|
|
26966
27731
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
26967
27732
|
const dir = getTaskListDir2(agent, taskListId);
|
|
26968
|
-
if (!
|
|
27733
|
+
if (!existsSync62(dir))
|
|
26969
27734
|
ensureDir23(dir);
|
|
26970
27735
|
const filter = {};
|
|
26971
27736
|
if (projectId)
|
|
@@ -26974,7 +27739,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
26974
27739
|
const existingByTodosId = new Map;
|
|
26975
27740
|
const files = listJsonFiles(dir);
|
|
26976
27741
|
for (const f of files) {
|
|
26977
|
-
const path =
|
|
27742
|
+
const path = join62(dir, f);
|
|
26978
27743
|
const at = readAgentTask(dir, f);
|
|
26979
27744
|
if (at?.metadata?.["todos_id"]) {
|
|
26980
27745
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -27048,7 +27813,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
27048
27813
|
}
|
|
27049
27814
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
27050
27815
|
const dir = getTaskListDir2(agent, taskListId);
|
|
27051
|
-
if (!
|
|
27816
|
+
if (!existsSync62(dir)) {
|
|
27052
27817
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
27053
27818
|
}
|
|
27054
27819
|
const files = listJsonFiles(dir);
|
|
@@ -27067,7 +27832,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
27067
27832
|
}
|
|
27068
27833
|
for (const f of files) {
|
|
27069
27834
|
try {
|
|
27070
|
-
const filePath =
|
|
27835
|
+
const filePath = join62(dir, f);
|
|
27071
27836
|
const at = readAgentTask(dir, f);
|
|
27072
27837
|
if (!at)
|
|
27073
27838
|
continue;
|
|
@@ -27272,9 +28037,9 @@ function extractTodos(options, db2) {
|
|
|
27272
28037
|
const files = collectFiles(basePath, extensions);
|
|
27273
28038
|
const allComments = [];
|
|
27274
28039
|
for (const file of files) {
|
|
27275
|
-
const fullPath = statSync22(basePath).isFile() ? basePath :
|
|
28040
|
+
const fullPath = statSync22(basePath).isFile() ? basePath : join72(basePath, file);
|
|
27276
28041
|
try {
|
|
27277
|
-
const source =
|
|
28042
|
+
const source = readFileSync42(fullPath, "utf-8");
|
|
27278
28043
|
const relPath = statSync22(basePath).isFile() ? relative(resolve23(basePath, ".."), fullPath) : file;
|
|
27279
28044
|
const comments = extractFromSource(source, relPath, tags);
|
|
27280
28045
|
allComments.push(...comments);
|
|
@@ -27634,7 +28399,29 @@ function checkBudget(agentId, db2) {
|
|
|
27634
28399
|
}
|
|
27635
28400
|
return { allowed: true, current_concurrent: concurrent, max_concurrent: budget.max_concurrent };
|
|
27636
28401
|
}
|
|
27637
|
-
var LOCK_EXPIRY_MINUTES = 30, MIGRATIONS2, _db3 = null, TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError2, TaskNotFoundError, ProjectNotFoundError2, PlanNotFoundError, LockError, AgentNotFoundError2, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, HOME, cached = null, GUARD_DEFAULTS, DAY_NAMES,
|
|
28402
|
+
var LOCK_EXPIRY_MINUTES = 30, MIGRATIONS2, _db3 = null, TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError2, TaskNotFoundError, ProjectNotFoundError2, PlanNotFoundError, LockError, AgentNotFoundError2, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, HOME, cached = null, GUARD_DEFAULTS, DAY_NAMES, SYSTEM_PROMPT2 = "You are a task management assistant that creates, updates, and tracks tasks and projects.", gatherTrainingData2 = async (options = {}) => {
|
|
28403
|
+
const allTasks = listTasks({});
|
|
28404
|
+
const filtered = options.since ? allTasks.filter((t) => new Date(t.created_at) >= options.since) : allTasks;
|
|
28405
|
+
const sorted = filtered.slice().sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
28406
|
+
const fetchSet = options.limit ? sorted.slice(0, options.limit * 2) : sorted;
|
|
28407
|
+
const examples = [];
|
|
28408
|
+
for (const task of fetchSet) {
|
|
28409
|
+
examples.push(taskToCreateExample(task));
|
|
28410
|
+
const statusEx = taskToStatusUpdateExample(task);
|
|
28411
|
+
if (statusEx)
|
|
28412
|
+
examples.push(statusEx);
|
|
28413
|
+
}
|
|
28414
|
+
const searchTerms = ["urgent", "fix", "implement", "create", "update", "review"];
|
|
28415
|
+
for (const term of searchTerms) {
|
|
28416
|
+
examples.push(taskToSearchExample(sorted, term));
|
|
28417
|
+
}
|
|
28418
|
+
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
28419
|
+
return {
|
|
28420
|
+
source: "todos",
|
|
28421
|
+
examples: finalExamples,
|
|
28422
|
+
count: finalExamples.length
|
|
28423
|
+
};
|
|
28424
|
+
}, DEFAULT_MODEL3 = "gpt-4o-mini", CONFIG_DIR2, CONFIG_PATH2, RELATIONSHIP_TYPES, EXTRACT_TAGS, DEFAULT_EXTENSIONS, SKIP_DIRS;
|
|
27638
28425
|
var init_dist4 = __esm(() => {
|
|
27639
28426
|
MIGRATIONS2 = [
|
|
27640
28427
|
`
|
|
@@ -28311,6 +29098,8 @@ var init_dist4 = __esm(() => {
|
|
|
28311
29098
|
saturday: 6,
|
|
28312
29099
|
sat: 6
|
|
28313
29100
|
};
|
|
29101
|
+
CONFIG_DIR2 = join45(homedir8(), ".todos");
|
|
29102
|
+
CONFIG_PATH2 = join45(CONFIG_DIR2, "config.json");
|
|
28314
29103
|
RELATIONSHIP_TYPES = [
|
|
28315
29104
|
"related_to",
|
|
28316
29105
|
"conflicts_with",
|
|
@@ -28634,7 +29423,7 @@ ${snap.tree.slice(0, 2000)}`;
|
|
|
28634
29423
|
const response = await client.messages.create({
|
|
28635
29424
|
model,
|
|
28636
29425
|
max_tokens: 512,
|
|
28637
|
-
system:
|
|
29426
|
+
system: SYSTEM_PROMPT3,
|
|
28638
29427
|
messages: [{
|
|
28639
29428
|
role: "user",
|
|
28640
29429
|
content: `Task: ${task}
|
|
@@ -28699,7 +29488,7 @@ What actions should I take next? Return JSON array.`
|
|
|
28699
29488
|
}
|
|
28700
29489
|
return { success: false, result: null, steps_taken: steps.length, steps, cost_estimate: totalTokens / 1000 * 0.00025, error: `Reached max steps (${maxSteps}) without completing task` };
|
|
28701
29490
|
}
|
|
28702
|
-
var
|
|
29491
|
+
var SYSTEM_PROMPT3 = `You are a browser automation agent. Given a task and the current page state, decide which browser actions to take.
|
|
28703
29492
|
|
|
28704
29493
|
Return a JSON array of at most 3 actions to execute next:
|
|
28705
29494
|
[{"tool": "navigate|click|type|scroll|evaluate|done", "args": {...}, "reason": "..."}]
|
|
@@ -28711,7 +29500,7 @@ var init_ai_task = () => {};
|
|
|
28711
29500
|
// src/mcp/index.ts
|
|
28712
29501
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
28713
29502
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
28714
|
-
import { readFileSync as
|
|
29503
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
28715
29504
|
import { join as join15 } from "path";
|
|
28716
29505
|
|
|
28717
29506
|
// node_modules/zod/v3/external.js
|
|
@@ -32695,15 +33484,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
32695
33484
|
// src/lib/screenshot.ts
|
|
32696
33485
|
init_types();
|
|
32697
33486
|
init_gallery();
|
|
33487
|
+
init_schema();
|
|
32698
33488
|
var import_sharp = __toESM(require_lib(), 1);
|
|
32699
33489
|
import { join as join4 } from "path";
|
|
32700
33490
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
32701
|
-
import { homedir as homedir4 } from "os";
|
|
32702
|
-
function getDataDir2() {
|
|
32703
|
-
return process.env["BROWSER_DATA_DIR"] ?? join4(homedir4(), ".browser");
|
|
32704
|
-
}
|
|
32705
33491
|
function getScreenshotDir(projectId) {
|
|
32706
|
-
const base = join4(
|
|
33492
|
+
const base = join4(getDataDir(), "screenshots");
|
|
32707
33493
|
const date = new Date().toISOString().split("T")[0];
|
|
32708
33494
|
const dir = projectId ? join4(base, projectId, date) : join4(base, date);
|
|
32709
33495
|
mkdirSync4(dir, { recursive: true });
|
|
@@ -32838,7 +33624,7 @@ async function takeScreenshot(page, opts) {
|
|
|
32838
33624
|
}
|
|
32839
33625
|
async function generatePDF(page, opts) {
|
|
32840
33626
|
try {
|
|
32841
|
-
const base = join4(
|
|
33627
|
+
const base = join4(getDataDir(), "pdfs");
|
|
32842
33628
|
const date = new Date().toISOString().split("T")[0];
|
|
32843
33629
|
const dir = opts?.projectId ? join4(base, opts.projectId, date) : join4(base, date);
|
|
32844
33630
|
mkdirSync4(dir, { recursive: true });
|
|
@@ -33054,55 +33840,10 @@ async function crawl(startUrl, opts = {}) {
|
|
|
33054
33840
|
});
|
|
33055
33841
|
return result;
|
|
33056
33842
|
}
|
|
33057
|
-
// src/db/agents.ts
|
|
33058
|
-
init_schema();
|
|
33059
|
-
init_types();
|
|
33060
|
-
import { randomUUID as randomUUID7 } from "crypto";
|
|
33061
|
-
function registerAgent(name, opts = {}) {
|
|
33062
|
-
const db = getDatabase();
|
|
33063
|
-
const existing = db.query("SELECT * FROM agents WHERE name = ?").get(name);
|
|
33064
|
-
if (existing) {
|
|
33065
|
-
db.prepare("UPDATE agents SET last_seen = datetime('now'), session_id = ?, project_id = ?, working_dir = ? WHERE name = ?").run(opts.sessionId ?? existing.session_id ?? null, opts.projectId ?? existing.project_id ?? null, opts.workingDir ?? existing.working_dir ?? null, name);
|
|
33066
|
-
return getAgentByName(name);
|
|
33067
|
-
}
|
|
33068
|
-
const id = randomUUID7();
|
|
33069
|
-
db.prepare("INSERT INTO agents (id, name, description, session_id, project_id, working_dir) VALUES (?, ?, ?, ?, ?, ?)").run(id, name, opts.description ?? null, opts.sessionId ?? null, opts.projectId ?? null, opts.workingDir ?? null);
|
|
33070
|
-
return getAgent(id);
|
|
33071
|
-
}
|
|
33072
|
-
function heartbeat(agentId) {
|
|
33073
|
-
const db = getDatabase();
|
|
33074
|
-
const agent = db.query("SELECT * FROM agents WHERE id = ?").get(agentId);
|
|
33075
|
-
if (!agent)
|
|
33076
|
-
throw new AgentNotFoundError(agentId);
|
|
33077
|
-
db.prepare("UPDATE agents SET last_seen = datetime('now') WHERE id = ?").run(agentId);
|
|
33078
|
-
db.prepare("INSERT INTO heartbeats (id, agent_id, session_id) VALUES (?, ?, ?)").run(randomUUID7(), agentId, agent.session_id ?? null);
|
|
33079
|
-
}
|
|
33080
|
-
function getAgent(id) {
|
|
33081
|
-
const db = getDatabase();
|
|
33082
|
-
const row = db.query("SELECT * FROM agents WHERE id = ?").get(id);
|
|
33083
|
-
if (!row)
|
|
33084
|
-
throw new AgentNotFoundError(id);
|
|
33085
|
-
return row;
|
|
33086
|
-
}
|
|
33087
|
-
function getAgentByName(name) {
|
|
33088
|
-
const db = getDatabase();
|
|
33089
|
-
return db.query("SELECT * FROM agents WHERE name = ?").get(name) ?? null;
|
|
33090
|
-
}
|
|
33091
|
-
function listAgents(projectId) {
|
|
33092
|
-
const db = getDatabase();
|
|
33093
|
-
if (projectId) {
|
|
33094
|
-
return db.query("SELECT * FROM agents WHERE project_id = ? ORDER BY last_seen DESC").all(projectId);
|
|
33095
|
-
}
|
|
33096
|
-
return db.query("SELECT * FROM agents ORDER BY last_seen DESC").all();
|
|
33097
|
-
}
|
|
33098
33843
|
|
|
33099
|
-
// src/
|
|
33100
|
-
|
|
33101
|
-
|
|
33102
|
-
}
|
|
33103
|
-
function heartbeat2(agentId) {
|
|
33104
|
-
heartbeat(agentId);
|
|
33105
|
-
}
|
|
33844
|
+
// src/mcp/helpers.ts
|
|
33845
|
+
init_agents2();
|
|
33846
|
+
|
|
33106
33847
|
// src/db/projects.ts
|
|
33107
33848
|
init_schema();
|
|
33108
33849
|
init_types();
|
|
@@ -33138,15 +33879,12 @@ init_console_log();
|
|
|
33138
33879
|
init_gallery();
|
|
33139
33880
|
|
|
33140
33881
|
// src/lib/downloads.ts
|
|
33882
|
+
init_schema();
|
|
33141
33883
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
33142
33884
|
import { join as join5, basename, extname } from "path";
|
|
33143
|
-
import { mkdirSync as mkdirSync5, existsSync as
|
|
33144
|
-
import { homedir as homedir5 } from "os";
|
|
33145
|
-
function getDataDir3() {
|
|
33146
|
-
return process.env["BROWSER_DATA_DIR"] ?? join5(homedir5(), ".browser");
|
|
33147
|
-
}
|
|
33885
|
+
import { mkdirSync as mkdirSync5, existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync2, copyFileSync as copyFileSync2, writeFileSync, readFileSync } from "fs";
|
|
33148
33886
|
function getDownloadsDir(sessionId) {
|
|
33149
|
-
const base = join5(
|
|
33887
|
+
const base = join5(getDataDir(), "downloads");
|
|
33150
33888
|
const dir = sessionId ? join5(base, sessionId) : base;
|
|
33151
33889
|
mkdirSync5(dir, { recursive: true });
|
|
33152
33890
|
return dir;
|
|
@@ -33189,20 +33927,20 @@ function listDownloads(sessionId) {
|
|
|
33189
33927
|
const dir = getDownloadsDir(sessionId);
|
|
33190
33928
|
const results = [];
|
|
33191
33929
|
function scanDir(d) {
|
|
33192
|
-
if (!
|
|
33930
|
+
if (!existsSync3(d))
|
|
33193
33931
|
return;
|
|
33194
|
-
const entries =
|
|
33932
|
+
const entries = readdirSync3(d);
|
|
33195
33933
|
for (const entry of entries) {
|
|
33196
33934
|
if (entry.endsWith(".meta.json"))
|
|
33197
33935
|
continue;
|
|
33198
33936
|
const full = join5(d, entry);
|
|
33199
|
-
const stat =
|
|
33937
|
+
const stat = statSync2(full);
|
|
33200
33938
|
if (stat.isDirectory()) {
|
|
33201
33939
|
scanDir(full);
|
|
33202
33940
|
continue;
|
|
33203
33941
|
}
|
|
33204
33942
|
const mpath = metaPath(full);
|
|
33205
|
-
if (!
|
|
33943
|
+
if (!existsSync3(mpath))
|
|
33206
33944
|
continue;
|
|
33207
33945
|
try {
|
|
33208
33946
|
const meta = JSON.parse(readFileSync(mpath, "utf8"));
|
|
@@ -33233,7 +33971,7 @@ function deleteDownload(id, sessionId) {
|
|
|
33233
33971
|
return false;
|
|
33234
33972
|
try {
|
|
33235
33973
|
unlinkSync2(file.path);
|
|
33236
|
-
if (
|
|
33974
|
+
if (existsSync3(file.meta_path))
|
|
33237
33975
|
unlinkSync2(file.meta_path);
|
|
33238
33976
|
return true;
|
|
33239
33977
|
} catch {
|
|
@@ -33257,7 +33995,7 @@ function exportToPath(id, targetPath, sessionId) {
|
|
|
33257
33995
|
const file = getDownload(id, sessionId);
|
|
33258
33996
|
if (!file)
|
|
33259
33997
|
throw new Error(`Download not found: ${id}`);
|
|
33260
|
-
|
|
33998
|
+
copyFileSync2(file.path, targetPath);
|
|
33261
33999
|
return targetPath;
|
|
33262
34000
|
}
|
|
33263
34001
|
function detectType(filename) {
|
|
@@ -33278,10 +34016,10 @@ function detectType(filename) {
|
|
|
33278
34016
|
return map[ext] ?? "file";
|
|
33279
34017
|
}
|
|
33280
34018
|
// src/lib/gallery-diff.ts
|
|
34019
|
+
init_schema();
|
|
33281
34020
|
var import_sharp2 = __toESM(require_lib(), 1);
|
|
33282
34021
|
import { join as join6 } from "path";
|
|
33283
34022
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
33284
|
-
import { homedir as homedir6 } from "os";
|
|
33285
34023
|
async function diffImages(path1, path2) {
|
|
33286
34024
|
const img1 = import_sharp2.default(path1);
|
|
33287
34025
|
const img2 = import_sharp2.default(path2);
|
|
@@ -33312,7 +34050,7 @@ async function diffImages(path1, path2) {
|
|
|
33312
34050
|
diffBuffer[i + 2] = Math.round(raw1[i + 2] * 0.4);
|
|
33313
34051
|
}
|
|
33314
34052
|
}
|
|
33315
|
-
const dataDir =
|
|
34053
|
+
const dataDir = getDataDir();
|
|
33316
34054
|
const diffDir = join6(dataDir, "diffs");
|
|
33317
34055
|
mkdirSync6(diffDir, { recursive: true });
|
|
33318
34056
|
const diffPath = join6(diffDir, `diff-${Date.now()}.webp`);
|
|
@@ -33331,9 +34069,9 @@ async function diffImages(path1, path2) {
|
|
|
33331
34069
|
init_snapshot();
|
|
33332
34070
|
|
|
33333
34071
|
// src/lib/files-integration.ts
|
|
34072
|
+
init_schema();
|
|
33334
34073
|
import { join as join7 } from "path";
|
|
33335
|
-
import { mkdirSync as mkdirSync7, copyFileSync as
|
|
33336
|
-
import { homedir as homedir7 } from "os";
|
|
34074
|
+
import { mkdirSync as mkdirSync7, copyFileSync as copyFileSync3 } from "fs";
|
|
33337
34075
|
async function persistFile(localPath, opts) {
|
|
33338
34076
|
try {
|
|
33339
34077
|
const mod = await import("@hasna/files");
|
|
@@ -33342,13 +34080,13 @@ async function persistFile(localPath, opts) {
|
|
|
33342
34080
|
return { id: ref.id, path: ref.path ?? localPath, permanent: true, provider: "open-files" };
|
|
33343
34081
|
}
|
|
33344
34082
|
} catch {}
|
|
33345
|
-
const dataDir =
|
|
34083
|
+
const dataDir = getDataDir();
|
|
33346
34084
|
const date = new Date().toISOString().split("T")[0];
|
|
33347
34085
|
const dir = join7(dataDir, "persistent", date);
|
|
33348
34086
|
mkdirSync7(dir, { recursive: true });
|
|
33349
34087
|
const filename = localPath.split("/").pop() ?? "file";
|
|
33350
34088
|
const targetPath = join7(dir, filename);
|
|
33351
|
-
|
|
34089
|
+
copyFileSync3(localPath, targetPath);
|
|
33352
34090
|
return {
|
|
33353
34091
|
id: `local-${Date.now()}`,
|
|
33354
34092
|
path: targetPath,
|
|
@@ -35234,7 +35972,7 @@ function register6(server) {
|
|
|
35234
35972
|
|
|
35235
35973
|
// src/mcp/meta.ts
|
|
35236
35974
|
function register7(server) {
|
|
35237
|
-
server.tool("
|
|
35975
|
+
server.tool("register_agent", "Register an agent session. Returns agent_id. Auto-triggers a heartbeat.", {
|
|
35238
35976
|
name: exports_external.string(),
|
|
35239
35977
|
description: exports_external.string().optional(),
|
|
35240
35978
|
session_id: exports_external.string().optional().optional(),
|
|
@@ -35248,7 +35986,7 @@ function register7(server) {
|
|
|
35248
35986
|
return err(e);
|
|
35249
35987
|
}
|
|
35250
35988
|
});
|
|
35251
|
-
server.tool("
|
|
35989
|
+
server.tool("heartbeat", "Update last_seen_at to signal agent is active.", { agent_id: exports_external.string() }, async ({ agent_id }) => {
|
|
35252
35990
|
try {
|
|
35253
35991
|
heartbeat2(agent_id);
|
|
35254
35992
|
return json({ ok: true, agent_id, timestamp: new Date().toISOString() });
|
|
@@ -35256,13 +35994,22 @@ function register7(server) {
|
|
|
35256
35994
|
return err(e);
|
|
35257
35995
|
}
|
|
35258
35996
|
});
|
|
35259
|
-
server.tool("
|
|
35997
|
+
server.tool("list_agents", "List all registered agents.", { project_id: exports_external.string().optional() }, async ({ project_id }) => {
|
|
35260
35998
|
try {
|
|
35261
35999
|
return json({ agents: listAgents(project_id) });
|
|
35262
36000
|
} catch (e) {
|
|
35263
36001
|
return err(e);
|
|
35264
36002
|
}
|
|
35265
36003
|
});
|
|
36004
|
+
server.tool("set_focus", "Set active project context for this agent session.", { agent_id: exports_external.string(), project_id: exports_external.string().optional() }, async ({ agent_id, project_id }) => {
|
|
36005
|
+
try {
|
|
36006
|
+
const { updateAgent: update } = await Promise.resolve().then(() => (init_agents2(), exports_agents));
|
|
36007
|
+
update(agent_id, { project_id: project_id ?? null });
|
|
36008
|
+
return json({ ok: true, agent_id, project_id });
|
|
36009
|
+
} catch (e) {
|
|
36010
|
+
return err(e);
|
|
36011
|
+
}
|
|
36012
|
+
});
|
|
35266
36013
|
server.tool("browser_project_create", "Create or ensure a project exists", { name: exports_external.string(), path: exports_external.string(), description: exports_external.string().optional() }, async ({ name, path, description }) => {
|
|
35267
36014
|
try {
|
|
35268
36015
|
const project = ensureProject(name, path, description);
|
|
@@ -35562,9 +36309,10 @@ function register7(server) {
|
|
|
35562
36309
|
{ tool: "browser_crawl", description: "Crawl a URL recursively" }
|
|
35563
36310
|
],
|
|
35564
36311
|
Agent: [
|
|
35565
|
-
{ tool: "
|
|
35566
|
-
{ tool: "
|
|
35567
|
-
{ tool: "
|
|
36312
|
+
{ tool: "register_agent", description: "Register an agent session" },
|
|
36313
|
+
{ tool: "heartbeat", description: "Update agent last_seen_at" },
|
|
36314
|
+
{ tool: "list_agents", description: "List registered agents" },
|
|
36315
|
+
{ tool: "set_focus", description: "Set active project context" }
|
|
35568
36316
|
],
|
|
35569
36317
|
Project: [
|
|
35570
36318
|
{ tool: "browser_project_create", description: "Create or ensure a project" },
|
|
@@ -35630,16 +36378,16 @@ function register7(server) {
|
|
|
35630
36378
|
});
|
|
35631
36379
|
server.tool("browser_version", "Get the running browser MCP version, tool count, and environment info. Use this to verify which binary is active.", {}, async () => {
|
|
35632
36380
|
try {
|
|
35633
|
-
const { getDataDir:
|
|
36381
|
+
const { getDataDir: getDataDir2 } = await Promise.resolve().then(() => (init_schema(), exports_schema));
|
|
35634
36382
|
const toolCount = Object.keys(server._registeredTools ?? {}).length;
|
|
35635
|
-
const { readFileSync:
|
|
36383
|
+
const { readFileSync: readFileSync7 } = await import("fs");
|
|
35636
36384
|
const { join: join15 } = await import("path");
|
|
35637
|
-
const _pkg = JSON.parse(
|
|
36385
|
+
const _pkg = JSON.parse(readFileSync7(join15(import.meta.dir, "../../package.json"), "utf8"));
|
|
35638
36386
|
return json({
|
|
35639
36387
|
version: _pkg.version,
|
|
35640
36388
|
mcp_tools_count: toolCount,
|
|
35641
36389
|
bun_version: Bun.version,
|
|
35642
|
-
data_dir:
|
|
36390
|
+
data_dir: getDataDir2(),
|
|
35643
36391
|
node_env: process.env["NODE_ENV"] ?? "production"
|
|
35644
36392
|
});
|
|
35645
36393
|
} catch (e) {
|
|
@@ -36013,7 +36761,7 @@ function register8(server) {
|
|
|
36013
36761
|
}
|
|
36014
36762
|
|
|
36015
36763
|
// src/mcp/index.ts
|
|
36016
|
-
var _pkg = JSON.parse(
|
|
36764
|
+
var _pkg = JSON.parse(readFileSync11(join15(import.meta.dir, "../../package.json"), "utf8"));
|
|
36017
36765
|
var server = new McpServer2({
|
|
36018
36766
|
name: "@hasna/browser",
|
|
36019
36767
|
version: "0.0.1"
|