@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/cli/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);
|
|
@@ -2144,10 +2165,30 @@ __export(exports_schema, {
|
|
|
2144
2165
|
});
|
|
2145
2166
|
import { Database } from "bun:sqlite";
|
|
2146
2167
|
import { join } from "path";
|
|
2147
|
-
import { mkdirSync } from "fs";
|
|
2168
|
+
import { mkdirSync, existsSync, readdirSync, copyFileSync, statSync } from "fs";
|
|
2148
2169
|
import { homedir } from "os";
|
|
2149
2170
|
function getDataDir() {
|
|
2150
|
-
|
|
2171
|
+
if (process.env["BROWSER_DATA_DIR"])
|
|
2172
|
+
return process.env["BROWSER_DATA_DIR"];
|
|
2173
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
2174
|
+
const newDir = join(home, ".hasna", "browser");
|
|
2175
|
+
const oldDir = join(home, ".browser");
|
|
2176
|
+
if (existsSync(oldDir) && !existsSync(newDir)) {
|
|
2177
|
+
mkdirSync(newDir, { recursive: true });
|
|
2178
|
+
try {
|
|
2179
|
+
for (const file of readdirSync(oldDir)) {
|
|
2180
|
+
const oldPath = join(oldDir, file);
|
|
2181
|
+
const newPath = join(newDir, file);
|
|
2182
|
+
try {
|
|
2183
|
+
if (statSync(oldPath).isFile()) {
|
|
2184
|
+
copyFileSync(oldPath, newPath);
|
|
2185
|
+
}
|
|
2186
|
+
} catch {}
|
|
2187
|
+
}
|
|
2188
|
+
} catch {}
|
|
2189
|
+
}
|
|
2190
|
+
mkdirSync(newDir, { recursive: true });
|
|
2191
|
+
return newDir;
|
|
2151
2192
|
}
|
|
2152
2193
|
function getDatabase(path) {
|
|
2153
2194
|
const resolvedPath = path ?? process.env["BROWSER_DB_PATH"] ?? join(getDataDir(), "browser.db");
|
|
@@ -2674,10 +2715,15 @@ class BrowserPool {
|
|
|
2674
2715
|
this.pool.push({ browser, inUse: true, createdAt: Date.now() });
|
|
2675
2716
|
return browser;
|
|
2676
2717
|
}
|
|
2677
|
-
return new Promise((resolve) => {
|
|
2718
|
+
return new Promise((resolve, reject) => {
|
|
2719
|
+
const timeout = setTimeout(() => {
|
|
2720
|
+
clearInterval(interval);
|
|
2721
|
+
reject(new BrowserError("Browser pool exhausted \u2014 no browser became available within 30s", "POOL_TIMEOUT", true));
|
|
2722
|
+
}, 30000);
|
|
2678
2723
|
const interval = setInterval(() => {
|
|
2679
2724
|
const free = this.pool.find((e) => !e.inUse);
|
|
2680
2725
|
if (free) {
|
|
2726
|
+
clearTimeout(timeout);
|
|
2681
2727
|
clearInterval(interval);
|
|
2682
2728
|
free.inUse = true;
|
|
2683
2729
|
resolve(free.browser);
|
|
@@ -2718,7 +2764,7 @@ function isLightpandaAvailable() {
|
|
|
2718
2764
|
const paths = [
|
|
2719
2765
|
"/usr/local/bin/lightpanda",
|
|
2720
2766
|
"/usr/bin/lightpanda",
|
|
2721
|
-
`${process.env["HOME"]}/.browser/bin/lightpanda`
|
|
2767
|
+
`${process.env["HOME"]}/.hasna/browser/bin/lightpanda`
|
|
2722
2768
|
];
|
|
2723
2769
|
return paths.some((p) => {
|
|
2724
2770
|
try {
|
|
@@ -2737,7 +2783,7 @@ function getLightpandaBinaryPath() {
|
|
|
2737
2783
|
"lightpanda",
|
|
2738
2784
|
"/usr/local/bin/lightpanda",
|
|
2739
2785
|
"/usr/bin/lightpanda",
|
|
2740
|
-
`${process.env["HOME"]}/.browser/bin/lightpanda`
|
|
2786
|
+
`${process.env["HOME"]}/.hasna/browser/bin/lightpanda`
|
|
2741
2787
|
];
|
|
2742
2788
|
for (const p of paths) {
|
|
2743
2789
|
try {
|
|
@@ -2811,18 +2857,18 @@ var init_lightpanda = __esm(() => {
|
|
|
2811
2857
|
// src/engines/bun-webview.ts
|
|
2812
2858
|
import { join as join2 } from "path";
|
|
2813
2859
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
2814
|
-
import { homedir as homedir2 } from "os";
|
|
2815
2860
|
function isBunWebViewAvailable() {
|
|
2816
2861
|
return typeof globalThis.Bun !== "undefined" && typeof globalThis.Bun.WebView !== "undefined";
|
|
2817
2862
|
}
|
|
2818
2863
|
function getProfileDir(profileName) {
|
|
2819
|
-
const base =
|
|
2864
|
+
const base = getDataDir();
|
|
2820
2865
|
const dir = join2(base, "profiles", profileName);
|
|
2821
2866
|
mkdirSync2(dir, { recursive: true });
|
|
2822
2867
|
return dir;
|
|
2823
2868
|
}
|
|
2824
2869
|
var BunWebViewSession;
|
|
2825
2870
|
var init_bun_webview = __esm(() => {
|
|
2871
|
+
init_schema();
|
|
2826
2872
|
BunWebViewSession = class BunWebViewSession {
|
|
2827
2873
|
view;
|
|
2828
2874
|
_sessionId;
|
|
@@ -3284,6 +3330,7 @@ function enableNetworkLogging(page, sessionId) {
|
|
|
3284
3330
|
};
|
|
3285
3331
|
const onResponse = (res) => {
|
|
3286
3332
|
const start = requestStart.get(res.url()) ?? Date.now();
|
|
3333
|
+
requestStart.delete(res.url());
|
|
3287
3334
|
const duration = Date.now() - start;
|
|
3288
3335
|
const req = res.request();
|
|
3289
3336
|
try {
|
|
@@ -3300,11 +3347,17 @@ function enableNetworkLogging(page, sessionId) {
|
|
|
3300
3347
|
});
|
|
3301
3348
|
} catch {}
|
|
3302
3349
|
};
|
|
3350
|
+
const onRequestFailed = (req) => {
|
|
3351
|
+
requestStart.delete(req.url());
|
|
3352
|
+
};
|
|
3303
3353
|
page.on("request", onRequest);
|
|
3304
3354
|
page.on("response", onResponse);
|
|
3355
|
+
page.on("requestfailed", onRequestFailed);
|
|
3305
3356
|
return () => {
|
|
3306
3357
|
page.off("request", onRequest);
|
|
3307
3358
|
page.off("response", onResponse);
|
|
3359
|
+
page.off("requestfailed", onRequestFailed);
|
|
3360
|
+
requestStart.clear();
|
|
3308
3361
|
};
|
|
3309
3362
|
}
|
|
3310
3363
|
async function addInterceptRule(page, rule) {
|
|
@@ -3338,6 +3391,7 @@ function startHAR(page) {
|
|
|
3338
3391
|
const start = requestStart.get(key);
|
|
3339
3392
|
if (!start)
|
|
3340
3393
|
return;
|
|
3394
|
+
requestStart.delete(key);
|
|
3341
3395
|
const duration = Date.now() - start.time;
|
|
3342
3396
|
const entry = {
|
|
3343
3397
|
startedDateTime: new Date(start.time).toISOString(),
|
|
@@ -3360,15 +3414,20 @@ function startHAR(page) {
|
|
|
3360
3414
|
timings: { send: 0, wait: duration, receive: 0 }
|
|
3361
3415
|
};
|
|
3362
3416
|
entries.push(entry);
|
|
3363
|
-
|
|
3417
|
+
};
|
|
3418
|
+
const onRequestFailed = (req) => {
|
|
3419
|
+
requestStart.delete(req.url() + req.method());
|
|
3364
3420
|
};
|
|
3365
3421
|
page.on("request", onRequest);
|
|
3366
3422
|
page.on("response", onResponse);
|
|
3423
|
+
page.on("requestfailed", onRequestFailed);
|
|
3367
3424
|
return {
|
|
3368
3425
|
entries,
|
|
3369
3426
|
stop: () => {
|
|
3370
3427
|
page.off("request", onRequest);
|
|
3371
3428
|
page.off("response", onResponse);
|
|
3429
|
+
page.off("requestfailed", onRequestFailed);
|
|
3430
|
+
requestStart.clear();
|
|
3372
3431
|
return {
|
|
3373
3432
|
log: {
|
|
3374
3433
|
version: "1.2",
|
|
@@ -3734,9 +3793,8 @@ __export(exports_storage_state, {
|
|
|
3734
3793
|
listStates: () => listStates,
|
|
3735
3794
|
deleteState: () => deleteState
|
|
3736
3795
|
});
|
|
3737
|
-
import { mkdirSync as mkdirSync3, existsSync, readdirSync, unlinkSync } from "fs";
|
|
3796
|
+
import { mkdirSync as mkdirSync3, existsSync as existsSync2, readdirSync as readdirSync2, unlinkSync } from "fs";
|
|
3738
3797
|
import { join as join3 } from "path";
|
|
3739
|
-
import { homedir as homedir3 } from "os";
|
|
3740
3798
|
function ensureDir() {
|
|
3741
3799
|
mkdirSync3(STATES_DIR, { recursive: true });
|
|
3742
3800
|
}
|
|
@@ -3754,11 +3812,11 @@ async function saveStateFromPage(page, name) {
|
|
|
3754
3812
|
}
|
|
3755
3813
|
function loadStatePath(name) {
|
|
3756
3814
|
const path = statePath(name);
|
|
3757
|
-
return
|
|
3815
|
+
return existsSync2(path) ? path : null;
|
|
3758
3816
|
}
|
|
3759
3817
|
function listStates() {
|
|
3760
3818
|
ensureDir();
|
|
3761
|
-
return
|
|
3819
|
+
return readdirSync2(STATES_DIR).filter((f) => f.endsWith(".json")).map((f) => {
|
|
3762
3820
|
const path = join3(STATES_DIR, f);
|
|
3763
3821
|
const stat = Bun.file(path);
|
|
3764
3822
|
return {
|
|
@@ -3770,7 +3828,7 @@ function listStates() {
|
|
|
3770
3828
|
}
|
|
3771
3829
|
function deleteState(name) {
|
|
3772
3830
|
const path = statePath(name);
|
|
3773
|
-
if (
|
|
3831
|
+
if (existsSync2(path)) {
|
|
3774
3832
|
unlinkSync(path);
|
|
3775
3833
|
return true;
|
|
3776
3834
|
}
|
|
@@ -3778,7 +3836,8 @@ function deleteState(name) {
|
|
|
3778
3836
|
}
|
|
3779
3837
|
var STATES_DIR;
|
|
3780
3838
|
var init_storage_state = __esm(() => {
|
|
3781
|
-
|
|
3839
|
+
init_schema();
|
|
3840
|
+
STATES_DIR = join3(getDataDir(), "states");
|
|
3782
3841
|
});
|
|
3783
3842
|
|
|
3784
3843
|
// src/lib/session.ts
|
|
@@ -11599,12 +11658,8 @@ var init_gallery = __esm(() => {
|
|
|
11599
11658
|
// src/lib/screenshot.ts
|
|
11600
11659
|
import { join as join4 } from "path";
|
|
11601
11660
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
11602
|
-
import { homedir as homedir4 } from "os";
|
|
11603
|
-
function getDataDir2() {
|
|
11604
|
-
return process.env["BROWSER_DATA_DIR"] ?? join4(homedir4(), ".browser");
|
|
11605
|
-
}
|
|
11606
11661
|
function getScreenshotDir(projectId) {
|
|
11607
|
-
const base = join4(
|
|
11662
|
+
const base = join4(getDataDir(), "screenshots");
|
|
11608
11663
|
const date = new Date().toISOString().split("T")[0];
|
|
11609
11664
|
const dir = projectId ? join4(base, projectId, date) : join4(base, date);
|
|
11610
11665
|
mkdirSync4(dir, { recursive: true });
|
|
@@ -11739,7 +11794,7 @@ async function takeScreenshot(page, opts) {
|
|
|
11739
11794
|
}
|
|
11740
11795
|
async function generatePDF(page, opts) {
|
|
11741
11796
|
try {
|
|
11742
|
-
const base = join4(
|
|
11797
|
+
const base = join4(getDataDir(), "pdfs");
|
|
11743
11798
|
const date = new Date().toISOString().split("T")[0];
|
|
11744
11799
|
const dir = opts?.projectId ? join4(base, opts.projectId, date) : join4(base, date);
|
|
11745
11800
|
mkdirSync4(dir, { recursive: true });
|
|
@@ -11765,6 +11820,7 @@ var import_sharp;
|
|
|
11765
11820
|
var init_screenshot = __esm(() => {
|
|
11766
11821
|
init_types();
|
|
11767
11822
|
init_gallery();
|
|
11823
|
+
init_schema();
|
|
11768
11824
|
import_sharp = __toESM(require_lib(), 1);
|
|
11769
11825
|
});
|
|
11770
11826
|
|
|
@@ -12263,7 +12319,6 @@ __export(exports_gallery_diff, {
|
|
|
12263
12319
|
});
|
|
12264
12320
|
import { join as join5 } from "path";
|
|
12265
12321
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
12266
|
-
import { homedir as homedir5 } from "os";
|
|
12267
12322
|
async function diffImages(path1, path2) {
|
|
12268
12323
|
const img1 = import_sharp2.default(path1);
|
|
12269
12324
|
const img2 = import_sharp2.default(path2);
|
|
@@ -12294,7 +12349,7 @@ async function diffImages(path1, path2) {
|
|
|
12294
12349
|
diffBuffer[i + 2] = Math.round(raw1[i + 2] * 0.4);
|
|
12295
12350
|
}
|
|
12296
12351
|
}
|
|
12297
|
-
const dataDir =
|
|
12352
|
+
const dataDir = getDataDir();
|
|
12298
12353
|
const diffDir = join5(dataDir, "diffs");
|
|
12299
12354
|
mkdirSync5(diffDir, { recursive: true });
|
|
12300
12355
|
const diffPath = join5(diffDir, `diff-${Date.now()}.webp`);
|
|
@@ -12310,6 +12365,7 @@ async function diffImages(path1, path2) {
|
|
|
12310
12365
|
}
|
|
12311
12366
|
var import_sharp2;
|
|
12312
12367
|
var init_gallery_diff = __esm(() => {
|
|
12368
|
+
init_schema();
|
|
12313
12369
|
import_sharp2 = __toESM(require_lib(), 1);
|
|
12314
12370
|
});
|
|
12315
12371
|
|
|
@@ -12425,13 +12481,13 @@ function listRuns(scriptId) {
|
|
|
12425
12481
|
}));
|
|
12426
12482
|
}
|
|
12427
12483
|
function migrateJsonScripts() {
|
|
12428
|
-
const { existsSync:
|
|
12484
|
+
const { existsSync: existsSync4, readdirSync: readdirSync3, readFileSync } = __require("fs");
|
|
12429
12485
|
const { join: join6 } = __require("path");
|
|
12430
|
-
const { getDataDir:
|
|
12431
|
-
const dir = join6(
|
|
12432
|
-
if (!
|
|
12486
|
+
const { getDataDir: getDataDir2 } = (init_schema(), __toCommonJS(exports_schema));
|
|
12487
|
+
const dir = join6(getDataDir2(), "scripts");
|
|
12488
|
+
if (!existsSync4(dir))
|
|
12433
12489
|
return 0;
|
|
12434
|
-
const files =
|
|
12490
|
+
const files = readdirSync3(dir).filter((f) => f.endsWith(".json"));
|
|
12435
12491
|
let migrated = 0;
|
|
12436
12492
|
for (const file of files) {
|
|
12437
12493
|
try {
|
|
@@ -12979,12 +13035,32 @@ var init_agents = __esm(() => {
|
|
|
12979
13035
|
});
|
|
12980
13036
|
|
|
12981
13037
|
// src/lib/agents.ts
|
|
13038
|
+
var exports_agents2 = {};
|
|
13039
|
+
__export(exports_agents2, {
|
|
13040
|
+
updateAgent: () => updateAgent,
|
|
13041
|
+
registerAgent: () => registerAgent2,
|
|
13042
|
+
listAgents: () => listAgents,
|
|
13043
|
+
isAgentStale: () => isAgentStale,
|
|
13044
|
+
heartbeat: () => heartbeat2,
|
|
13045
|
+
getAgentByName: () => getAgentByName,
|
|
13046
|
+
getAgent: () => getAgent,
|
|
13047
|
+
getActiveAgents: () => getActiveAgents,
|
|
13048
|
+
deleteAgent: () => deleteAgent,
|
|
13049
|
+
cleanStaleAgents: () => cleanStaleAgents
|
|
13050
|
+
});
|
|
12982
13051
|
function registerAgent2(name, opts = {}) {
|
|
12983
13052
|
return registerAgent(name, opts);
|
|
12984
13053
|
}
|
|
12985
13054
|
function heartbeat2(agentId) {
|
|
12986
13055
|
heartbeat(agentId);
|
|
12987
13056
|
}
|
|
13057
|
+
function isAgentStale(agent, thresholdMs = 5 * 60 * 1000) {
|
|
13058
|
+
const lastSeen = new Date(agent.last_seen).getTime();
|
|
13059
|
+
return Date.now() - lastSeen > thresholdMs;
|
|
13060
|
+
}
|
|
13061
|
+
function getActiveAgents(thresholdMs = 5 * 60 * 1000) {
|
|
13062
|
+
return listAgents().filter((a) => !isAgentStale(a, thresholdMs));
|
|
13063
|
+
}
|
|
12988
13064
|
var init_agents2 = __esm(() => {
|
|
12989
13065
|
init_agents();
|
|
12990
13066
|
});
|
|
@@ -13272,11 +13348,10 @@ __export(exports_profiles, {
|
|
|
13272
13348
|
deleteProfile: () => deleteProfile,
|
|
13273
13349
|
applyProfile: () => applyProfile
|
|
13274
13350
|
});
|
|
13275
|
-
import { mkdirSync as mkdirSync6, existsSync as
|
|
13351
|
+
import { mkdirSync as mkdirSync6, existsSync as existsSync4, readdirSync as readdirSync3, rmSync, readFileSync, writeFileSync } from "fs";
|
|
13276
13352
|
import { join as join6 } from "path";
|
|
13277
|
-
import { homedir as homedir6 } from "os";
|
|
13278
13353
|
function getProfilesDir() {
|
|
13279
|
-
const dataDir =
|
|
13354
|
+
const dataDir = getDataDir();
|
|
13280
13355
|
const dir = join6(dataDir, "profiles");
|
|
13281
13356
|
mkdirSync6(dir, { recursive: true });
|
|
13282
13357
|
return dir;
|
|
@@ -13315,17 +13390,17 @@ async function saveProfile(page, name) {
|
|
|
13315
13390
|
}
|
|
13316
13391
|
function loadProfile(name) {
|
|
13317
13392
|
const dir = getProfileDir2(name);
|
|
13318
|
-
if (!
|
|
13393
|
+
if (!existsSync4(dir)) {
|
|
13319
13394
|
throw new Error(`Profile not found: ${name}`);
|
|
13320
13395
|
}
|
|
13321
13396
|
const cookiesPath = join6(dir, "cookies.json");
|
|
13322
13397
|
const storagePath = join6(dir, "storage.json");
|
|
13323
13398
|
const metaPath = join6(dir, "meta.json");
|
|
13324
|
-
const cookies =
|
|
13325
|
-
const localStorage2 =
|
|
13399
|
+
const cookies = existsSync4(cookiesPath) ? JSON.parse(readFileSync(cookiesPath, "utf8")) : [];
|
|
13400
|
+
const localStorage2 = existsSync4(storagePath) ? JSON.parse(readFileSync(storagePath, "utf8")) : {};
|
|
13326
13401
|
let savedAt = new Date().toISOString();
|
|
13327
13402
|
let url;
|
|
13328
|
-
if (
|
|
13403
|
+
if (existsSync4(metaPath)) {
|
|
13329
13404
|
const meta = JSON.parse(readFileSync(metaPath, "utf8"));
|
|
13330
13405
|
savedAt = meta.saved_at ?? savedAt;
|
|
13331
13406
|
url = meta.url;
|
|
@@ -13353,9 +13428,9 @@ async function applyProfile(page, profileData) {
|
|
|
13353
13428
|
}
|
|
13354
13429
|
function listProfiles() {
|
|
13355
13430
|
const dir = getProfilesDir();
|
|
13356
|
-
if (!
|
|
13431
|
+
if (!existsSync4(dir))
|
|
13357
13432
|
return [];
|
|
13358
|
-
const entries =
|
|
13433
|
+
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
13359
13434
|
const profiles = [];
|
|
13360
13435
|
for (const entry of entries) {
|
|
13361
13436
|
if (!entry.isDirectory())
|
|
@@ -13368,18 +13443,18 @@ function listProfiles() {
|
|
|
13368
13443
|
let storageKeyCount = 0;
|
|
13369
13444
|
try {
|
|
13370
13445
|
const metaPath = join6(profileDir, "meta.json");
|
|
13371
|
-
if (
|
|
13446
|
+
if (existsSync4(metaPath)) {
|
|
13372
13447
|
const meta = JSON.parse(readFileSync(metaPath, "utf8"));
|
|
13373
13448
|
savedAt = meta.saved_at ?? "";
|
|
13374
13449
|
url = meta.url;
|
|
13375
13450
|
}
|
|
13376
13451
|
const cookiesPath = join6(profileDir, "cookies.json");
|
|
13377
|
-
if (
|
|
13452
|
+
if (existsSync4(cookiesPath)) {
|
|
13378
13453
|
const cookies = JSON.parse(readFileSync(cookiesPath, "utf8"));
|
|
13379
13454
|
cookieCount = Array.isArray(cookies) ? cookies.length : 0;
|
|
13380
13455
|
}
|
|
13381
13456
|
const storagePath = join6(profileDir, "storage.json");
|
|
13382
|
-
if (
|
|
13457
|
+
if (existsSync4(storagePath)) {
|
|
13383
13458
|
const storage = JSON.parse(readFileSync(storagePath, "utf8"));
|
|
13384
13459
|
storageKeyCount = Object.keys(storage).length;
|
|
13385
13460
|
}
|
|
@@ -13396,7 +13471,7 @@ function listProfiles() {
|
|
|
13396
13471
|
}
|
|
13397
13472
|
function deleteProfile(name) {
|
|
13398
13473
|
const dir = getProfileDir2(name);
|
|
13399
|
-
if (!
|
|
13474
|
+
if (!existsSync4(dir))
|
|
13400
13475
|
return false;
|
|
13401
13476
|
try {
|
|
13402
13477
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -13405,7 +13480,9 @@ function deleteProfile(name) {
|
|
|
13405
13480
|
return false;
|
|
13406
13481
|
}
|
|
13407
13482
|
}
|
|
13408
|
-
var init_profiles = () => {
|
|
13483
|
+
var init_profiles = __esm(() => {
|
|
13484
|
+
init_schema();
|
|
13485
|
+
});
|
|
13409
13486
|
|
|
13410
13487
|
// src/lib/auth.ts
|
|
13411
13488
|
var exports_auth = {};
|
|
@@ -13413,20 +13490,20 @@ __export(exports_auth, {
|
|
|
13413
13490
|
loginWithCredentials: () => loginWithCredentials,
|
|
13414
13491
|
getCredentials: () => getCredentials
|
|
13415
13492
|
});
|
|
13416
|
-
import { existsSync as
|
|
13493
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
13417
13494
|
import { join as join7 } from "path";
|
|
13418
|
-
import { homedir as
|
|
13495
|
+
import { homedir as homedir2 } from "os";
|
|
13419
13496
|
async function getCredentials(service) {
|
|
13420
13497
|
try {
|
|
13421
|
-
const { getSecret } = await import(`${
|
|
13498
|
+
const { getSecret } = await import(`${homedir2()}/Workspace/hasna/opensource/opensourcedev/open-secrets/src/store.js`);
|
|
13422
13499
|
const email = getSecret(`${service}_email`) ?? getSecret(`${service}_username`) ?? getSecret(`${service}_login`);
|
|
13423
13500
|
const password = getSecret(`${service}_password`) ?? getSecret(`${service}_pass`);
|
|
13424
13501
|
if (email?.value && password?.value) {
|
|
13425
13502
|
return { email: email.value, password: password.value };
|
|
13426
13503
|
}
|
|
13427
13504
|
} catch {}
|
|
13428
|
-
const secretsPath = join7(
|
|
13429
|
-
if (
|
|
13505
|
+
const secretsPath = join7(homedir2(), ".secrets");
|
|
13506
|
+
if (existsSync5(secretsPath)) {
|
|
13430
13507
|
const content = readFileSync2(secretsPath, "utf8");
|
|
13431
13508
|
const lines = content.split(`
|
|
13432
13509
|
`);
|
|
@@ -13511,13 +13588,9 @@ __export(exports_downloads, {
|
|
|
13511
13588
|
});
|
|
13512
13589
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
13513
13590
|
import { join as join8, basename, extname } from "path";
|
|
13514
|
-
import { mkdirSync as mkdirSync7, existsSync as
|
|
13515
|
-
import { homedir as homedir8 } from "os";
|
|
13516
|
-
function getDataDir3() {
|
|
13517
|
-
return process.env["BROWSER_DATA_DIR"] ?? join8(homedir8(), ".browser");
|
|
13518
|
-
}
|
|
13591
|
+
import { mkdirSync as mkdirSync7, existsSync as existsSync6, readdirSync as readdirSync4, statSync as statSync2, unlinkSync as unlinkSync2, copyFileSync as copyFileSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync3 } from "fs";
|
|
13519
13592
|
function getDownloadsDir(sessionId) {
|
|
13520
|
-
const base = join8(
|
|
13593
|
+
const base = join8(getDataDir(), "downloads");
|
|
13521
13594
|
const dir = sessionId ? join8(base, sessionId) : base;
|
|
13522
13595
|
mkdirSync7(dir, { recursive: true });
|
|
13523
13596
|
return dir;
|
|
@@ -13563,20 +13636,20 @@ function listDownloads(sessionId) {
|
|
|
13563
13636
|
const dir = getDownloadsDir(sessionId);
|
|
13564
13637
|
const results = [];
|
|
13565
13638
|
function scanDir(d) {
|
|
13566
|
-
if (!
|
|
13639
|
+
if (!existsSync6(d))
|
|
13567
13640
|
return;
|
|
13568
|
-
const entries =
|
|
13641
|
+
const entries = readdirSync4(d);
|
|
13569
13642
|
for (const entry of entries) {
|
|
13570
13643
|
if (entry.endsWith(".meta.json"))
|
|
13571
13644
|
continue;
|
|
13572
13645
|
const full = join8(d, entry);
|
|
13573
|
-
const stat =
|
|
13646
|
+
const stat = statSync2(full);
|
|
13574
13647
|
if (stat.isDirectory()) {
|
|
13575
13648
|
scanDir(full);
|
|
13576
13649
|
continue;
|
|
13577
13650
|
}
|
|
13578
13651
|
const mpath = metaPath(full);
|
|
13579
|
-
if (!
|
|
13652
|
+
if (!existsSync6(mpath))
|
|
13580
13653
|
continue;
|
|
13581
13654
|
try {
|
|
13582
13655
|
const meta = JSON.parse(readFileSync3(mpath, "utf8"));
|
|
@@ -13607,7 +13680,7 @@ function deleteDownload(id, sessionId) {
|
|
|
13607
13680
|
return false;
|
|
13608
13681
|
try {
|
|
13609
13682
|
unlinkSync2(file.path);
|
|
13610
|
-
if (
|
|
13683
|
+
if (existsSync6(file.meta_path))
|
|
13611
13684
|
unlinkSync2(file.meta_path);
|
|
13612
13685
|
return true;
|
|
13613
13686
|
} catch {
|
|
@@ -13631,7 +13704,7 @@ function exportToPath(id, targetPath, sessionId) {
|
|
|
13631
13704
|
const file = getDownload(id, sessionId);
|
|
13632
13705
|
if (!file)
|
|
13633
13706
|
throw new Error(`Download not found: ${id}`);
|
|
13634
|
-
|
|
13707
|
+
copyFileSync2(file.path, targetPath);
|
|
13635
13708
|
return targetPath;
|
|
13636
13709
|
}
|
|
13637
13710
|
function detectType(filename) {
|
|
@@ -13651,7 +13724,9 @@ function detectType(filename) {
|
|
|
13651
13724
|
};
|
|
13652
13725
|
return map[ext] ?? "file";
|
|
13653
13726
|
}
|
|
13654
|
-
var init_downloads = () => {
|
|
13727
|
+
var init_downloads = __esm(() => {
|
|
13728
|
+
init_schema();
|
|
13729
|
+
});
|
|
13655
13730
|
|
|
13656
13731
|
// src/lib/daemon-client.ts
|
|
13657
13732
|
var exports_daemon_client = {};
|
|
@@ -13662,9 +13737,8 @@ __export(exports_daemon_client, {
|
|
|
13662
13737
|
getDaemonPidFile: () => getDaemonPidFile,
|
|
13663
13738
|
getDaemonPid: () => getDaemonPid
|
|
13664
13739
|
});
|
|
13665
|
-
import { existsSync as
|
|
13740
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
13666
13741
|
import { join as join9 } from "path";
|
|
13667
|
-
import { homedir as homedir9 } from "os";
|
|
13668
13742
|
function getDaemonPidFile() {
|
|
13669
13743
|
return PID_FILE;
|
|
13670
13744
|
}
|
|
@@ -13672,7 +13746,7 @@ function getDaemonPort() {
|
|
|
13672
13746
|
return parseInt(process.env["BROWSER_DAEMON_PORT"] ?? String(DEFAULT_PORT), 10);
|
|
13673
13747
|
}
|
|
13674
13748
|
function isDaemonRunning() {
|
|
13675
|
-
if (!
|
|
13749
|
+
if (!existsSync7(PID_FILE))
|
|
13676
13750
|
return false;
|
|
13677
13751
|
try {
|
|
13678
13752
|
const pid = parseInt(readFileSync4(PID_FILE, "utf8").trim(), 10);
|
|
@@ -13683,7 +13757,7 @@ function isDaemonRunning() {
|
|
|
13683
13757
|
}
|
|
13684
13758
|
}
|
|
13685
13759
|
function getDaemonPid() {
|
|
13686
|
-
if (!
|
|
13760
|
+
if (!existsSync7(PID_FILE))
|
|
13687
13761
|
return null;
|
|
13688
13762
|
try {
|
|
13689
13763
|
return parseInt(readFileSync4(PID_FILE, "utf8").trim(), 10);
|
|
@@ -13706,7 +13780,8 @@ async function getDaemonStatus() {
|
|
|
13706
13780
|
}
|
|
13707
13781
|
var PID_FILE, DEFAULT_PORT = 7030;
|
|
13708
13782
|
var init_daemon_client = __esm(() => {
|
|
13709
|
-
|
|
13783
|
+
init_schema();
|
|
13784
|
+
PID_FILE = join9(getDataDir(), "daemon.pid");
|
|
13710
13785
|
});
|
|
13711
13786
|
|
|
13712
13787
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -17769,8 +17844,7 @@ async function setSessionStorage(page, key, value) {
|
|
|
17769
17844
|
|
|
17770
17845
|
// src/lib/files-integration.ts
|
|
17771
17846
|
import { join as join10 } from "path";
|
|
17772
|
-
import { mkdirSync as mkdirSync8, copyFileSync as
|
|
17773
|
-
import { homedir as homedir10 } from "os";
|
|
17847
|
+
import { mkdirSync as mkdirSync8, copyFileSync as copyFileSync3 } from "fs";
|
|
17774
17848
|
async function persistFile(localPath, opts) {
|
|
17775
17849
|
try {
|
|
17776
17850
|
const mod = await import("@hasna/files");
|
|
@@ -17779,13 +17853,13 @@ async function persistFile(localPath, opts) {
|
|
|
17779
17853
|
return { id: ref.id, path: ref.path ?? localPath, permanent: true, provider: "open-files" };
|
|
17780
17854
|
}
|
|
17781
17855
|
} catch {}
|
|
17782
|
-
const dataDir =
|
|
17856
|
+
const dataDir = getDataDir();
|
|
17783
17857
|
const date = new Date().toISOString().split("T")[0];
|
|
17784
17858
|
const dir = join10(dataDir, "persistent", date);
|
|
17785
17859
|
mkdirSync8(dir, { recursive: true });
|
|
17786
17860
|
const filename = localPath.split("/").pop() ?? "file";
|
|
17787
17861
|
const targetPath = join10(dir, filename);
|
|
17788
|
-
|
|
17862
|
+
copyFileSync3(localPath, targetPath);
|
|
17789
17863
|
return {
|
|
17790
17864
|
id: `local-${Date.now()}`,
|
|
17791
17865
|
path: targetPath,
|
|
@@ -17793,7 +17867,9 @@ async function persistFile(localPath, opts) {
|
|
|
17793
17867
|
provider: "local"
|
|
17794
17868
|
};
|
|
17795
17869
|
}
|
|
17796
|
-
var init_files_integration = () => {
|
|
17870
|
+
var init_files_integration = __esm(() => {
|
|
17871
|
+
init_schema();
|
|
17872
|
+
});
|
|
17797
17873
|
|
|
17798
17874
|
// src/db/timeline.ts
|
|
17799
17875
|
function logEvent(sessionId, eventType, details = {}) {
|
|
@@ -19201,16 +19277,22 @@ var init_capture = __esm(() => {
|
|
|
19201
19277
|
init_helpers();
|
|
19202
19278
|
});
|
|
19203
19279
|
|
|
19204
|
-
//
|
|
19280
|
+
// node_modules/@hasna/skills/dist/index.js
|
|
19205
19281
|
var exports_dist = {};
|
|
19206
19282
|
__export(exports_dist, {
|
|
19283
|
+
validateCron: () => validateCron,
|
|
19207
19284
|
skillExists: () => skillExists,
|
|
19285
|
+
setScheduleEnabled: () => setScheduleEnabled,
|
|
19208
19286
|
searchSkills: () => searchSkills,
|
|
19209
19287
|
saveConfig: () => saveConfig,
|
|
19210
19288
|
runSkill: () => runSkill,
|
|
19211
19289
|
removeSkillForAgent: () => removeSkillForAgent,
|
|
19212
19290
|
removeSkill: () => removeSkill,
|
|
19291
|
+
removeSchedule: () => removeSchedule,
|
|
19292
|
+
recordScheduleRun: () => recordScheduleRun,
|
|
19293
|
+
loadRegistry: () => loadRegistry,
|
|
19213
19294
|
loadConfig: () => loadConfig,
|
|
19295
|
+
listSchedules: () => listSchedules,
|
|
19214
19296
|
installSkills: () => installSkills,
|
|
19215
19297
|
installSkillForAgent: () => installSkillForAgent,
|
|
19216
19298
|
installSkill: () => installSkill,
|
|
@@ -19221,8 +19303,10 @@ __export(exports_dist, {
|
|
|
19221
19303
|
getSkillDocs: () => getSkillDocs,
|
|
19222
19304
|
getSkillBestDoc: () => getSkillBestDoc,
|
|
19223
19305
|
getSkill: () => getSkill,
|
|
19306
|
+
getNextRun: () => getNextRun,
|
|
19224
19307
|
getInstalledSkills: () => getInstalledSkills,
|
|
19225
19308
|
getInstallMeta: () => getInstallMeta,
|
|
19309
|
+
getDueSchedules: () => getDueSchedules,
|
|
19226
19310
|
getDisabledSkills: () => getDisabledSkills,
|
|
19227
19311
|
getConfigPath: () => getConfigPath,
|
|
19228
19312
|
getAllTags: () => getAllTags,
|
|
@@ -19230,23 +19314,111 @@ __export(exports_dist, {
|
|
|
19230
19314
|
getAgentSkillPath: () => getAgentSkillPath,
|
|
19231
19315
|
generateSkillMd: () => generateSkillMd,
|
|
19232
19316
|
generateEnvExample: () => generateEnvExample,
|
|
19317
|
+
findSimilarSkills: () => findSimilarSkills,
|
|
19233
19318
|
enableSkill: () => enableSkill,
|
|
19234
19319
|
disableSkill: () => disableSkill,
|
|
19320
|
+
clearRegistryCache: () => clearRegistryCache,
|
|
19321
|
+
addSchedule: () => addSchedule,
|
|
19235
19322
|
SKILLS: () => SKILLS,
|
|
19236
19323
|
CATEGORIES: () => CATEGORIES,
|
|
19237
19324
|
AGENT_TARGETS: () => AGENT_TARGETS
|
|
19238
19325
|
});
|
|
19239
|
-
import { existsSync as
|
|
19240
|
-
import { join as join11
|
|
19241
|
-
import { homedir as
|
|
19242
|
-
import {
|
|
19243
|
-
import {
|
|
19244
|
-
import { join as join22 } from "path";
|
|
19245
|
-
import { existsSync as existsSync32, readFileSync as readFileSync32, writeFileSync as writeFileSync22, mkdirSync as mkdirSync22 } from "fs";
|
|
19246
|
-
import { join as join32, dirname as dirname2 } from "path";
|
|
19326
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5, readdirSync as readdirSync5 } from "fs";
|
|
19327
|
+
import { join as join11 } from "path";
|
|
19328
|
+
import { homedir as homedir3 } from "os";
|
|
19329
|
+
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";
|
|
19330
|
+
import { join as join22, dirname } from "path";
|
|
19247
19331
|
import { homedir as homedir22 } from "os";
|
|
19332
|
+
import { fileURLToPath } from "url";
|
|
19333
|
+
import { existsSync as existsSync32, readFileSync as readFileSync32, readdirSync as readdirSync32 } from "fs";
|
|
19334
|
+
import { join as join32 } from "path";
|
|
19335
|
+
import { existsSync as existsSync42, readFileSync as readFileSync42, writeFileSync as writeFileSync22, mkdirSync as mkdirSync22 } from "fs";
|
|
19336
|
+
import { join as join42, dirname as dirname2 } from "path";
|
|
19337
|
+
import { homedir as homedir32 } from "os";
|
|
19338
|
+
import { existsSync as existsSync52, readFileSync as readFileSync52, writeFileSync as writeFileSync32, mkdirSync as mkdirSync32 } from "fs";
|
|
19339
|
+
import { join as join52 } from "path";
|
|
19340
|
+
function parseSkillMdFrontmatter(content) {
|
|
19341
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
19342
|
+
if (!match)
|
|
19343
|
+
return null;
|
|
19344
|
+
const result = {};
|
|
19345
|
+
for (const line of match[1].split(`
|
|
19346
|
+
`)) {
|
|
19347
|
+
const colon = line.indexOf(":");
|
|
19348
|
+
if (colon === -1)
|
|
19349
|
+
continue;
|
|
19350
|
+
const key = line.slice(0, colon).trim();
|
|
19351
|
+
const value = line.slice(colon + 1).trim();
|
|
19352
|
+
if (!key || !value)
|
|
19353
|
+
continue;
|
|
19354
|
+
if (key === "name")
|
|
19355
|
+
result.name = value;
|
|
19356
|
+
else if (key === "description")
|
|
19357
|
+
result.description = value;
|
|
19358
|
+
else if (key === "displayName" || key === "display_name")
|
|
19359
|
+
result.displayName = value;
|
|
19360
|
+
else if (key === "category")
|
|
19361
|
+
result.category = value;
|
|
19362
|
+
else if (key === "tags") {
|
|
19363
|
+
result.tags = value.replace(/[\[\]]/g, "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
19364
|
+
}
|
|
19365
|
+
}
|
|
19366
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
19367
|
+
}
|
|
19368
|
+
function discoverSkillsInDir(dir) {
|
|
19369
|
+
if (!existsSync8(dir))
|
|
19370
|
+
return [];
|
|
19371
|
+
const result = [];
|
|
19372
|
+
try {
|
|
19373
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
19374
|
+
for (const entry of entries) {
|
|
19375
|
+
if (!entry.isDirectory())
|
|
19376
|
+
continue;
|
|
19377
|
+
const skillMdPath = join11(dir, entry.name, "SKILL.md");
|
|
19378
|
+
if (!existsSync8(skillMdPath))
|
|
19379
|
+
continue;
|
|
19380
|
+
let content;
|
|
19381
|
+
try {
|
|
19382
|
+
content = readFileSync5(skillMdPath, "utf-8");
|
|
19383
|
+
} catch {
|
|
19384
|
+
continue;
|
|
19385
|
+
}
|
|
19386
|
+
const fm = parseSkillMdFrontmatter(content);
|
|
19387
|
+
if (!fm?.name)
|
|
19388
|
+
continue;
|
|
19389
|
+
const name = fm.name.replace(/^skill-/, "");
|
|
19390
|
+
result.push({
|
|
19391
|
+
name,
|
|
19392
|
+
displayName: fm.displayName || name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
19393
|
+
description: fm.description || "",
|
|
19394
|
+
category: fm.category || "Development Tools",
|
|
19395
|
+
tags: fm.tags || [],
|
|
19396
|
+
source: "custom"
|
|
19397
|
+
});
|
|
19398
|
+
}
|
|
19399
|
+
} catch {}
|
|
19400
|
+
return result;
|
|
19401
|
+
}
|
|
19402
|
+
function loadRegistry(cwd) {
|
|
19403
|
+
const now = Date.now();
|
|
19404
|
+
if (_registryCache && now - _registryCacheTime < REGISTRY_CACHE_TTL) {
|
|
19405
|
+
return _registryCache;
|
|
19406
|
+
}
|
|
19407
|
+
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
19408
|
+
const globalCustom = discoverSkillsInDir(join11(homedir3(), ".skills"));
|
|
19409
|
+
const projectCustom = discoverSkillsInDir(join11(cwd || process.cwd(), ".skills", "custom-skills"));
|
|
19410
|
+
const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
|
|
19411
|
+
const filtered = official.filter((s) => !customNames.has(s.name));
|
|
19412
|
+
_registryCache = [...filtered, ...globalCustom, ...projectCustom];
|
|
19413
|
+
_registryCacheTime = now;
|
|
19414
|
+
return _registryCache;
|
|
19415
|
+
}
|
|
19416
|
+
function clearRegistryCache() {
|
|
19417
|
+
_registryCache = null;
|
|
19418
|
+
_registryCacheTime = 0;
|
|
19419
|
+
}
|
|
19248
19420
|
function getSkillsByCategory(category) {
|
|
19249
|
-
return
|
|
19421
|
+
return loadRegistry().filter((s) => s.category === category);
|
|
19250
19422
|
}
|
|
19251
19423
|
function editDistance(a, b) {
|
|
19252
19424
|
if (a === b)
|
|
@@ -19292,7 +19464,7 @@ function searchSkills(query) {
|
|
|
19292
19464
|
if (words.length === 0)
|
|
19293
19465
|
return [];
|
|
19294
19466
|
const scored = [];
|
|
19295
|
-
for (const skill of
|
|
19467
|
+
for (const skill of loadRegistry()) {
|
|
19296
19468
|
const nameLower = skill.name.toLowerCase();
|
|
19297
19469
|
const displayNameLower = skill.displayName.toLowerCase();
|
|
19298
19470
|
const descriptionLower = skill.description.toLowerCase();
|
|
@@ -19328,56 +19500,71 @@ function searchSkills(query) {
|
|
|
19328
19500
|
return scored.map((s) => s.skill);
|
|
19329
19501
|
}
|
|
19330
19502
|
function getSkill(name) {
|
|
19331
|
-
return
|
|
19503
|
+
return loadRegistry().find((s) => s.name === name);
|
|
19332
19504
|
}
|
|
19333
19505
|
function getSkillsByTag(tag) {
|
|
19334
19506
|
const needle = tag.toLowerCase();
|
|
19335
|
-
return
|
|
19507
|
+
return loadRegistry().filter((s) => s.tags.some((t) => t.toLowerCase().includes(needle)));
|
|
19336
19508
|
}
|
|
19337
19509
|
function getAllTags() {
|
|
19338
19510
|
const tagSet = new Set;
|
|
19339
|
-
for (const skill of
|
|
19511
|
+
for (const skill of loadRegistry()) {
|
|
19340
19512
|
for (const tag of skill.tags) {
|
|
19341
19513
|
tagSet.add(tag.toLowerCase());
|
|
19342
19514
|
}
|
|
19343
19515
|
}
|
|
19344
19516
|
return Array.from(tagSet).sort();
|
|
19345
19517
|
}
|
|
19518
|
+
function levenshtein(a, b) {
|
|
19519
|
+
const m = a.length, n = b.length;
|
|
19520
|
+
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0));
|
|
19521
|
+
for (let i = 1;i <= m; i++) {
|
|
19522
|
+
for (let j = 1;j <= n; j++) {
|
|
19523
|
+
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]);
|
|
19524
|
+
}
|
|
19525
|
+
}
|
|
19526
|
+
return dp[m][n];
|
|
19527
|
+
}
|
|
19528
|
+
function findSimilarSkills(query, maxResults = 3) {
|
|
19529
|
+
const q = query.toLowerCase();
|
|
19530
|
+
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);
|
|
19531
|
+
return scored.slice(0, maxResults).map((s) => s.name);
|
|
19532
|
+
}
|
|
19346
19533
|
function normalizeSkillName(name) {
|
|
19347
19534
|
return name.startsWith("skill-") ? name : `skill-${name}`;
|
|
19348
19535
|
}
|
|
19349
19536
|
function findSkillsDir() {
|
|
19350
19537
|
let dir = __dirname2;
|
|
19351
19538
|
for (let i = 0;i < 5; i++) {
|
|
19352
|
-
const candidate =
|
|
19353
|
-
if (
|
|
19539
|
+
const candidate = join22(dir, "skills");
|
|
19540
|
+
if (existsSync22(candidate) && !dir.includes(".skills")) {
|
|
19354
19541
|
return candidate;
|
|
19355
19542
|
}
|
|
19356
19543
|
dir = dirname(dir);
|
|
19357
19544
|
}
|
|
19358
|
-
return
|
|
19545
|
+
return join22(__dirname2, "..", "skills");
|
|
19359
19546
|
}
|
|
19360
19547
|
function getSkillPath(name) {
|
|
19361
19548
|
const skillName = normalizeSkillName(name);
|
|
19362
|
-
return
|
|
19549
|
+
return join22(SKILLS_DIR, skillName);
|
|
19363
19550
|
}
|
|
19364
19551
|
function skillExists(name) {
|
|
19365
|
-
return
|
|
19552
|
+
return existsSync22(getSkillPath(name));
|
|
19366
19553
|
}
|
|
19367
19554
|
function installSkill(name, options = {}) {
|
|
19368
19555
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
19369
19556
|
const skillName = normalizeSkillName(name);
|
|
19370
19557
|
const sourcePath = getSkillPath(name);
|
|
19371
|
-
const destDir =
|
|
19372
|
-
const destPath =
|
|
19373
|
-
if (!
|
|
19558
|
+
const destDir = join22(targetDir, ".skills");
|
|
19559
|
+
const destPath = join22(destDir, skillName);
|
|
19560
|
+
if (!existsSync22(sourcePath)) {
|
|
19374
19561
|
return {
|
|
19375
19562
|
skill: name,
|
|
19376
19563
|
success: false,
|
|
19377
19564
|
error: `Skill '${name}' not found`
|
|
19378
19565
|
};
|
|
19379
19566
|
}
|
|
19380
|
-
if (
|
|
19567
|
+
if (existsSync22(destPath) && !overwrite) {
|
|
19381
19568
|
return {
|
|
19382
19569
|
skill: name,
|
|
19383
19570
|
success: false,
|
|
@@ -19386,10 +19573,10 @@ function installSkill(name, options = {}) {
|
|
|
19386
19573
|
};
|
|
19387
19574
|
}
|
|
19388
19575
|
try {
|
|
19389
|
-
if (!
|
|
19576
|
+
if (!existsSync22(destDir)) {
|
|
19390
19577
|
mkdirSync9(destDir, { recursive: true });
|
|
19391
19578
|
}
|
|
19392
|
-
if (
|
|
19579
|
+
if (existsSync22(destPath) && overwrite) {
|
|
19393
19580
|
rmSync2(destPath, { recursive: true, force: true });
|
|
19394
19581
|
}
|
|
19395
19582
|
cpSync(sourcePath, destPath, {
|
|
@@ -19428,10 +19615,10 @@ function installSkills(names, options = {}) {
|
|
|
19428
19615
|
return names.map((name) => installSkill(name, options));
|
|
19429
19616
|
}
|
|
19430
19617
|
function updateSkillsIndex(skillsDir) {
|
|
19431
|
-
const indexPath =
|
|
19618
|
+
const indexPath = join22(skillsDir, "index.ts");
|
|
19432
19619
|
const meta = loadMeta(skillsDir);
|
|
19433
19620
|
const disabledSet = new Set(meta.disabled || []);
|
|
19434
|
-
const skills =
|
|
19621
|
+
const skills = readdirSync22(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes(".") && !disabledSet.has(f.replace("skill-", "")));
|
|
19435
19622
|
const exports = skills.map((s) => {
|
|
19436
19623
|
const name = s.replace("skill-", "").replace(/-/g, "_");
|
|
19437
19624
|
return `export * as ${name} from './${s}/src/index.js';`;
|
|
@@ -19447,13 +19634,13 @@ ${exports}
|
|
|
19447
19634
|
writeFileSync3(indexPath, content);
|
|
19448
19635
|
}
|
|
19449
19636
|
function getMetaPath(skillsDir) {
|
|
19450
|
-
return
|
|
19637
|
+
return join22(skillsDir, ".meta.json");
|
|
19451
19638
|
}
|
|
19452
19639
|
function loadMeta(skillsDir) {
|
|
19453
19640
|
const metaPath2 = getMetaPath(skillsDir);
|
|
19454
|
-
if (
|
|
19641
|
+
if (existsSync22(metaPath2)) {
|
|
19455
19642
|
try {
|
|
19456
|
-
return JSON.parse(
|
|
19643
|
+
return JSON.parse(readFileSync22(metaPath2, "utf-8"));
|
|
19457
19644
|
} catch {}
|
|
19458
19645
|
}
|
|
19459
19646
|
return { skills: {} };
|
|
@@ -19466,9 +19653,9 @@ function recordInstall(skillsDir, name) {
|
|
|
19466
19653
|
const skillName = normalizeSkillName(name);
|
|
19467
19654
|
let version = "unknown";
|
|
19468
19655
|
try {
|
|
19469
|
-
const pkgPath =
|
|
19470
|
-
if (
|
|
19471
|
-
const pkg = JSON.parse(
|
|
19656
|
+
const pkgPath = join22(skillsDir, skillName, "package.json");
|
|
19657
|
+
if (existsSync22(pkgPath)) {
|
|
19658
|
+
const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
|
|
19472
19659
|
version = pkg.version || "unknown";
|
|
19473
19660
|
}
|
|
19474
19661
|
} catch {}
|
|
@@ -19481,12 +19668,12 @@ function recordRemove(skillsDir, name) {
|
|
|
19481
19668
|
saveMeta(skillsDir, meta);
|
|
19482
19669
|
}
|
|
19483
19670
|
function getInstallMeta(targetDir = process.cwd()) {
|
|
19484
|
-
return loadMeta(
|
|
19671
|
+
return loadMeta(join22(targetDir, ".skills"));
|
|
19485
19672
|
}
|
|
19486
19673
|
function disableSkill(name, targetDir = process.cwd()) {
|
|
19487
|
-
const skillsDir =
|
|
19674
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
19488
19675
|
const skillName = normalizeSkillName(name);
|
|
19489
|
-
if (!
|
|
19676
|
+
if (!existsSync22(join22(skillsDir, skillName)))
|
|
19490
19677
|
return false;
|
|
19491
19678
|
const meta = loadMeta(skillsDir);
|
|
19492
19679
|
const disabled = new Set(meta.disabled || []);
|
|
@@ -19499,7 +19686,7 @@ function disableSkill(name, targetDir = process.cwd()) {
|
|
|
19499
19686
|
return true;
|
|
19500
19687
|
}
|
|
19501
19688
|
function enableSkill(name, targetDir = process.cwd()) {
|
|
19502
|
-
const skillsDir =
|
|
19689
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
19503
19690
|
const meta = loadMeta(skillsDir);
|
|
19504
19691
|
const disabled = new Set(meta.disabled || []);
|
|
19505
19692
|
if (!disabled.has(name))
|
|
@@ -19511,24 +19698,24 @@ function enableSkill(name, targetDir = process.cwd()) {
|
|
|
19511
19698
|
return true;
|
|
19512
19699
|
}
|
|
19513
19700
|
function getDisabledSkills(targetDir = process.cwd()) {
|
|
19514
|
-
const meta = loadMeta(
|
|
19701
|
+
const meta = loadMeta(join22(targetDir, ".skills"));
|
|
19515
19702
|
return meta.disabled || [];
|
|
19516
19703
|
}
|
|
19517
19704
|
function getInstalledSkills(targetDir = process.cwd()) {
|
|
19518
|
-
const skillsDir =
|
|
19519
|
-
if (!
|
|
19705
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
19706
|
+
if (!existsSync22(skillsDir)) {
|
|
19520
19707
|
return [];
|
|
19521
19708
|
}
|
|
19522
|
-
return
|
|
19523
|
-
const fullPath =
|
|
19524
|
-
return f.startsWith("skill-") &&
|
|
19709
|
+
return readdirSync22(skillsDir).filter((f) => {
|
|
19710
|
+
const fullPath = join22(skillsDir, f);
|
|
19711
|
+
return f.startsWith("skill-") && statSync3(fullPath).isDirectory();
|
|
19525
19712
|
}).map((f) => f.replace("skill-", ""));
|
|
19526
19713
|
}
|
|
19527
19714
|
function removeSkill(name, targetDir = process.cwd()) {
|
|
19528
19715
|
const skillName = normalizeSkillName(name);
|
|
19529
|
-
const skillsDir =
|
|
19530
|
-
const skillPath =
|
|
19531
|
-
if (!
|
|
19716
|
+
const skillsDir = join22(targetDir, ".skills");
|
|
19717
|
+
const skillPath = join22(skillsDir, skillName);
|
|
19718
|
+
if (!existsSync22(skillPath)) {
|
|
19532
19719
|
return false;
|
|
19533
19720
|
}
|
|
19534
19721
|
rmSync2(skillPath, { recursive: true, force: true });
|
|
@@ -19537,27 +19724,31 @@ function removeSkill(name, targetDir = process.cwd()) {
|
|
|
19537
19724
|
return true;
|
|
19538
19725
|
}
|
|
19539
19726
|
function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
19540
|
-
const
|
|
19541
|
-
|
|
19542
|
-
|
|
19727
|
+
const base = projectDir || process.cwd();
|
|
19728
|
+
switch (agent) {
|
|
19729
|
+
case "pi":
|
|
19730
|
+
return scope === "project" ? join22(base, ".pi", "skills") : join22(homedir22(), ".pi", "agent", "skills");
|
|
19731
|
+
case "opencode":
|
|
19732
|
+
return scope === "project" ? join22(base, ".opencode", "skills") : join22(homedir22(), ".opencode", "skills");
|
|
19733
|
+
default:
|
|
19734
|
+
return scope === "project" ? join22(base, `.${agent}`, "skills") : join22(homedir22(), `.${agent}`, "skills");
|
|
19543
19735
|
}
|
|
19544
|
-
return join11(homedir11(), agentDir, "skills");
|
|
19545
19736
|
}
|
|
19546
19737
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
19547
19738
|
const skillName = normalizeSkillName(name);
|
|
19548
|
-
return
|
|
19739
|
+
return join22(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
19549
19740
|
}
|
|
19550
19741
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
19551
19742
|
const { agent, scope = "global", projectDir } = options;
|
|
19552
19743
|
const skillName = normalizeSkillName(name);
|
|
19553
19744
|
const sourcePath = getSkillPath(name);
|
|
19554
|
-
if (!
|
|
19745
|
+
if (!existsSync22(sourcePath)) {
|
|
19555
19746
|
return { skill: name, success: false, error: `Skill '${name}' not found` };
|
|
19556
19747
|
}
|
|
19557
19748
|
let skillMdContent = null;
|
|
19558
|
-
const skillMdPath =
|
|
19559
|
-
if (
|
|
19560
|
-
skillMdContent =
|
|
19749
|
+
const skillMdPath = join22(sourcePath, "SKILL.md");
|
|
19750
|
+
if (existsSync22(skillMdPath)) {
|
|
19751
|
+
skillMdContent = readFileSync22(skillMdPath, "utf-8");
|
|
19561
19752
|
} else if (generateSkillMd) {
|
|
19562
19753
|
skillMdContent = generateSkillMd(name);
|
|
19563
19754
|
}
|
|
@@ -19566,17 +19757,12 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
19566
19757
|
}
|
|
19567
19758
|
const destDir = getAgentSkillPath(name, agent, scope, projectDir);
|
|
19568
19759
|
if (scope === "global") {
|
|
19569
|
-
const agentBaseDir =
|
|
19570
|
-
if (!
|
|
19571
|
-
const agentLabels = {
|
|
19572
|
-
claude: "Claude Code",
|
|
19573
|
-
codex: "Codex CLI",
|
|
19574
|
-
gemini: "Gemini CLI"
|
|
19575
|
-
};
|
|
19760
|
+
const agentBaseDir = agent === "pi" ? join22(homedir22(), ".pi", "agent") : join22(homedir22(), `.${agent}`);
|
|
19761
|
+
if (!existsSync22(agentBaseDir)) {
|
|
19576
19762
|
return {
|
|
19577
19763
|
skill: name,
|
|
19578
19764
|
success: false,
|
|
19579
|
-
error: `Agent directory ${agentBaseDir} does not exist. Is ${
|
|
19765
|
+
error: `Agent directory ${agentBaseDir} does not exist. Is ${AGENT_LABELS[agent]} installed?`
|
|
19580
19766
|
};
|
|
19581
19767
|
}
|
|
19582
19768
|
try {
|
|
@@ -19591,7 +19777,7 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
19591
19777
|
}
|
|
19592
19778
|
try {
|
|
19593
19779
|
mkdirSync9(destDir, { recursive: true });
|
|
19594
|
-
writeFileSync3(
|
|
19780
|
+
writeFileSync3(join22(destDir, "SKILL.md"), skillMdContent);
|
|
19595
19781
|
return { skill: name, success: true, path: destDir };
|
|
19596
19782
|
} catch (error) {
|
|
19597
19783
|
return {
|
|
@@ -19604,7 +19790,7 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
19604
19790
|
function removeSkillForAgent(name, options) {
|
|
19605
19791
|
const { agent, scope = "global", projectDir } = options;
|
|
19606
19792
|
const destDir = getAgentSkillPath(name, agent, scope, projectDir);
|
|
19607
|
-
if (!
|
|
19793
|
+
if (!existsSync22(destDir)) {
|
|
19608
19794
|
return false;
|
|
19609
19795
|
}
|
|
19610
19796
|
rmSync2(destDir, { recursive: true, force: true });
|
|
@@ -19612,12 +19798,12 @@ function removeSkillForAgent(name, options) {
|
|
|
19612
19798
|
}
|
|
19613
19799
|
function getSkillDocs(name) {
|
|
19614
19800
|
const skillPath = getSkillPath(name);
|
|
19615
|
-
if (!
|
|
19801
|
+
if (!existsSync32(skillPath))
|
|
19616
19802
|
return null;
|
|
19617
19803
|
return {
|
|
19618
|
-
skillMd: readIfExists(
|
|
19619
|
-
readme: readIfExists(
|
|
19620
|
-
claudeMd: readIfExists(
|
|
19804
|
+
skillMd: readIfExists(join32(skillPath, "SKILL.md")),
|
|
19805
|
+
readme: readIfExists(join32(skillPath, "README.md")),
|
|
19806
|
+
claudeMd: readIfExists(join32(skillPath, "CLAUDE.md"))
|
|
19621
19807
|
};
|
|
19622
19808
|
}
|
|
19623
19809
|
function getSkillBestDoc(name) {
|
|
@@ -19628,11 +19814,11 @@ function getSkillBestDoc(name) {
|
|
|
19628
19814
|
}
|
|
19629
19815
|
function getSkillRequirements(name) {
|
|
19630
19816
|
const skillPath = getSkillPath(name);
|
|
19631
|
-
if (!
|
|
19817
|
+
if (!existsSync32(skillPath))
|
|
19632
19818
|
return null;
|
|
19633
19819
|
const texts = [];
|
|
19634
19820
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
19635
|
-
const content = readIfExists(
|
|
19821
|
+
const content = readIfExists(join32(skillPath, file));
|
|
19636
19822
|
if (content)
|
|
19637
19823
|
texts.push(content);
|
|
19638
19824
|
}
|
|
@@ -19659,10 +19845,10 @@ function getSkillRequirements(name) {
|
|
|
19659
19845
|
}
|
|
19660
19846
|
let cliCommand = null;
|
|
19661
19847
|
let dependencies = {};
|
|
19662
|
-
const pkgPath =
|
|
19663
|
-
if (
|
|
19848
|
+
const pkgPath = join32(skillPath, "package.json");
|
|
19849
|
+
if (existsSync32(pkgPath)) {
|
|
19664
19850
|
try {
|
|
19665
|
-
const pkg = JSON.parse(
|
|
19851
|
+
const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
|
|
19666
19852
|
if (pkg.bin) {
|
|
19667
19853
|
const binKeys = Object.keys(pkg.bin);
|
|
19668
19854
|
if (binKeys.length > 0)
|
|
@@ -19682,25 +19868,25 @@ async function runSkill(name, args, options = {}) {
|
|
|
19682
19868
|
const skillName = normalizeSkillName(name);
|
|
19683
19869
|
let skillPath;
|
|
19684
19870
|
if (options.installed) {
|
|
19685
|
-
skillPath =
|
|
19871
|
+
skillPath = join32(process.cwd(), ".skills", skillName);
|
|
19686
19872
|
} else {
|
|
19687
|
-
const installedPath =
|
|
19688
|
-
if (
|
|
19873
|
+
const installedPath = join32(process.cwd(), ".skills", skillName);
|
|
19874
|
+
if (existsSync32(installedPath)) {
|
|
19689
19875
|
skillPath = installedPath;
|
|
19690
19876
|
} else {
|
|
19691
19877
|
skillPath = getSkillPath(name);
|
|
19692
19878
|
}
|
|
19693
19879
|
}
|
|
19694
|
-
if (!
|
|
19880
|
+
if (!existsSync32(skillPath)) {
|
|
19695
19881
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
19696
19882
|
}
|
|
19697
|
-
const pkgPath =
|
|
19698
|
-
if (!
|
|
19883
|
+
const pkgPath = join32(skillPath, "package.json");
|
|
19884
|
+
if (!existsSync32(pkgPath)) {
|
|
19699
19885
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
19700
19886
|
}
|
|
19701
19887
|
let entryPoint;
|
|
19702
19888
|
try {
|
|
19703
|
-
const pkg = JSON.parse(
|
|
19889
|
+
const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
|
|
19704
19890
|
if (pkg.bin) {
|
|
19705
19891
|
const binValues = Object.values(pkg.bin);
|
|
19706
19892
|
entryPoint = binValues[0];
|
|
@@ -19714,12 +19900,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
19714
19900
|
} catch {
|
|
19715
19901
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
19716
19902
|
}
|
|
19717
|
-
const entryPath =
|
|
19718
|
-
if (!
|
|
19903
|
+
const entryPath = join32(skillPath, entryPoint);
|
|
19904
|
+
if (!existsSync32(entryPath)) {
|
|
19719
19905
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
19720
19906
|
}
|
|
19721
|
-
const nodeModules =
|
|
19722
|
-
if (!
|
|
19907
|
+
const nodeModules = join32(skillPath, "node_modules");
|
|
19908
|
+
if (!existsSync32(nodeModules)) {
|
|
19723
19909
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
19724
19910
|
cwd: skillPath,
|
|
19725
19911
|
stdout: "pipe",
|
|
@@ -19737,17 +19923,17 @@ async function runSkill(name, args, options = {}) {
|
|
|
19737
19923
|
return { exitCode };
|
|
19738
19924
|
}
|
|
19739
19925
|
function generateEnvExample(targetDir = process.cwd()) {
|
|
19740
|
-
const skillsDir =
|
|
19741
|
-
if (!
|
|
19926
|
+
const skillsDir = join32(targetDir, ".skills");
|
|
19927
|
+
if (!existsSync32(skillsDir))
|
|
19742
19928
|
return "";
|
|
19743
|
-
const dirs =
|
|
19929
|
+
const dirs = readdirSync32(skillsDir).filter((f) => f.startsWith("skill-") && existsSync32(join32(skillsDir, f, "package.json")));
|
|
19744
19930
|
const envMap = new Map;
|
|
19745
19931
|
for (const dir of dirs) {
|
|
19746
19932
|
const skillName = dir.replace("skill-", "");
|
|
19747
|
-
const skillPath =
|
|
19933
|
+
const skillPath = join32(skillsDir, dir);
|
|
19748
19934
|
const texts = [];
|
|
19749
19935
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example"]) {
|
|
19750
|
-
const content = readIfExists(
|
|
19936
|
+
const content = readIfExists(join32(skillPath, file));
|
|
19751
19937
|
if (content)
|
|
19752
19938
|
texts.push(content);
|
|
19753
19939
|
}
|
|
@@ -19792,7 +19978,7 @@ function generateSkillMd(name) {
|
|
|
19792
19978
|
if (!meta)
|
|
19793
19979
|
return null;
|
|
19794
19980
|
const skillPath = getSkillPath(name);
|
|
19795
|
-
if (!
|
|
19981
|
+
if (!existsSync32(skillPath))
|
|
19796
19982
|
return null;
|
|
19797
19983
|
const frontmatter = [
|
|
19798
19984
|
"---",
|
|
@@ -19801,13 +19987,13 @@ function generateSkillMd(name) {
|
|
|
19801
19987
|
"---"
|
|
19802
19988
|
].join(`
|
|
19803
19989
|
`);
|
|
19804
|
-
const readme = readIfExists(
|
|
19805
|
-
const claudeMd = readIfExists(
|
|
19990
|
+
const readme = readIfExists(join32(skillPath, "README.md"));
|
|
19991
|
+
const claudeMd = readIfExists(join32(skillPath, "CLAUDE.md"));
|
|
19806
19992
|
let cliCommand = null;
|
|
19807
|
-
const pkgPath =
|
|
19808
|
-
if (
|
|
19993
|
+
const pkgPath = join32(skillPath, "package.json");
|
|
19994
|
+
if (existsSync32(pkgPath)) {
|
|
19809
19995
|
try {
|
|
19810
|
-
const pkg = JSON.parse(
|
|
19996
|
+
const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
|
|
19811
19997
|
if (pkg.bin) {
|
|
19812
19998
|
const binKeys = Object.keys(pkg.bin);
|
|
19813
19999
|
if (binKeys.length > 0)
|
|
@@ -19880,23 +20066,23 @@ function extractEnvVars(text) {
|
|
|
19880
20066
|
}
|
|
19881
20067
|
function readIfExists(path) {
|
|
19882
20068
|
try {
|
|
19883
|
-
if (
|
|
19884
|
-
return
|
|
20069
|
+
if (existsSync32(path)) {
|
|
20070
|
+
return readFileSync32(path, "utf-8");
|
|
19885
20071
|
}
|
|
19886
20072
|
} catch {}
|
|
19887
20073
|
return null;
|
|
19888
20074
|
}
|
|
19889
20075
|
function getConfigPath(scope) {
|
|
19890
20076
|
if (scope === "global") {
|
|
19891
|
-
return
|
|
20077
|
+
return join42(homedir32(), ".skillsrc");
|
|
19892
20078
|
}
|
|
19893
|
-
return
|
|
20079
|
+
return join42(process.cwd(), "skills.config.json");
|
|
19894
20080
|
}
|
|
19895
20081
|
function readConfigFile(path) {
|
|
19896
|
-
if (!
|
|
20082
|
+
if (!existsSync42(path))
|
|
19897
20083
|
return {};
|
|
19898
20084
|
try {
|
|
19899
|
-
const raw =
|
|
20085
|
+
const raw = readFileSync42(path, "utf-8");
|
|
19900
20086
|
const parsed = JSON.parse(raw);
|
|
19901
20087
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
19902
20088
|
return {};
|
|
@@ -19927,9 +20113,9 @@ function saveConfig(key, value, scope = "project") {
|
|
|
19927
20113
|
}
|
|
19928
20114
|
const filePath = getConfigPath(scope);
|
|
19929
20115
|
let existing = {};
|
|
19930
|
-
if (
|
|
20116
|
+
if (existsSync42(filePath)) {
|
|
19931
20117
|
try {
|
|
19932
|
-
existing = JSON.parse(
|
|
20118
|
+
existing = JSON.parse(readFileSync42(filePath, "utf-8"));
|
|
19933
20119
|
if (typeof existing !== "object" || existing === null || Array.isArray(existing)) {
|
|
19934
20120
|
existing = {};
|
|
19935
20121
|
}
|
|
@@ -19938,7 +20124,7 @@ function saveConfig(key, value, scope = "project") {
|
|
|
19938
20124
|
}
|
|
19939
20125
|
} else {
|
|
19940
20126
|
const dir = dirname2(filePath);
|
|
19941
|
-
if (!
|
|
20127
|
+
if (!existsSync42(dir)) {
|
|
19942
20128
|
mkdirSync22(dir, { recursive: true });
|
|
19943
20129
|
}
|
|
19944
20130
|
}
|
|
@@ -19946,7 +20132,158 @@ function saveConfig(key, value, scope = "project") {
|
|
|
19946
20132
|
writeFileSync22(filePath, JSON.stringify(existing, null, 2) + `
|
|
19947
20133
|
`);
|
|
19948
20134
|
}
|
|
19949
|
-
|
|
20135
|
+
function getSchedulesPath(targetDir = process.cwd()) {
|
|
20136
|
+
return join52(targetDir, ".skills", "schedules.json");
|
|
20137
|
+
}
|
|
20138
|
+
function loadSchedules(targetDir = process.cwd()) {
|
|
20139
|
+
const path = getSchedulesPath(targetDir);
|
|
20140
|
+
if (existsSync52(path)) {
|
|
20141
|
+
try {
|
|
20142
|
+
return JSON.parse(readFileSync52(path, "utf-8"));
|
|
20143
|
+
} catch {}
|
|
20144
|
+
}
|
|
20145
|
+
return { version: 1, schedules: [] };
|
|
20146
|
+
}
|
|
20147
|
+
function saveSchedules(data, targetDir = process.cwd()) {
|
|
20148
|
+
const path = getSchedulesPath(targetDir);
|
|
20149
|
+
const dir = join52(targetDir, ".skills");
|
|
20150
|
+
if (!existsSync52(dir))
|
|
20151
|
+
mkdirSync32(dir, { recursive: true });
|
|
20152
|
+
writeFileSync32(path, JSON.stringify(data, null, 2));
|
|
20153
|
+
}
|
|
20154
|
+
function validateCron(expr) {
|
|
20155
|
+
const fields = expr.trim().split(/\s+/);
|
|
20156
|
+
if (fields.length !== 5) {
|
|
20157
|
+
return { valid: false, error: `Expected 5 fields, got ${fields.length}. Format: "minute hour day-of-month month day-of-week"` };
|
|
20158
|
+
}
|
|
20159
|
+
return { valid: true };
|
|
20160
|
+
}
|
|
20161
|
+
function getNextRun(cron, from = new Date) {
|
|
20162
|
+
const { valid } = validateCron(cron);
|
|
20163
|
+
if (!valid)
|
|
20164
|
+
return null;
|
|
20165
|
+
const [minuteF, hourF, domF, monthF, dowF] = cron.trim().split(/\s+/);
|
|
20166
|
+
function parseField(f, min, max) {
|
|
20167
|
+
if (f === "*")
|
|
20168
|
+
return Array.from({ length: max - min + 1 }, (_, i) => i + min);
|
|
20169
|
+
if (f.startsWith("*/")) {
|
|
20170
|
+
const step = parseInt(f.slice(2));
|
|
20171
|
+
if (isNaN(step))
|
|
20172
|
+
return [];
|
|
20173
|
+
const vals = [];
|
|
20174
|
+
for (let i = min;i <= max; i += step)
|
|
20175
|
+
vals.push(i);
|
|
20176
|
+
return vals;
|
|
20177
|
+
}
|
|
20178
|
+
return f.split(",").flatMap((part) => {
|
|
20179
|
+
if (part.includes("-")) {
|
|
20180
|
+
const [lo, hi] = part.split("-").map(Number);
|
|
20181
|
+
return Array.from({ length: hi - lo + 1 }, (_, i) => i + lo);
|
|
20182
|
+
}
|
|
20183
|
+
const n = parseInt(part);
|
|
20184
|
+
return isNaN(n) ? [] : [n];
|
|
20185
|
+
});
|
|
20186
|
+
}
|
|
20187
|
+
const minutes = parseField(minuteF, 0, 59);
|
|
20188
|
+
const hours = parseField(hourF, 0, 23);
|
|
20189
|
+
const doms = parseField(domF, 1, 31);
|
|
20190
|
+
const months = parseField(monthF, 1, 12);
|
|
20191
|
+
const dows = parseField(dowF, 0, 6);
|
|
20192
|
+
const candidate = new Date(from);
|
|
20193
|
+
candidate.setSeconds(0, 0);
|
|
20194
|
+
candidate.setMinutes(candidate.getMinutes() + 1);
|
|
20195
|
+
const limit = new Date(from);
|
|
20196
|
+
limit.setFullYear(limit.getFullYear() + 1);
|
|
20197
|
+
while (candidate < limit) {
|
|
20198
|
+
const month = candidate.getMonth() + 1;
|
|
20199
|
+
const dom = candidate.getDate();
|
|
20200
|
+
const dow = candidate.getDay();
|
|
20201
|
+
const hour = candidate.getHours();
|
|
20202
|
+
const minute = candidate.getMinutes();
|
|
20203
|
+
if (!months.includes(month)) {
|
|
20204
|
+
candidate.setMonth(candidate.getMonth() + 1, 1);
|
|
20205
|
+
candidate.setHours(0, 0, 0, 0);
|
|
20206
|
+
continue;
|
|
20207
|
+
}
|
|
20208
|
+
if (!doms.includes(dom) || !dows.includes(dow)) {
|
|
20209
|
+
candidate.setDate(candidate.getDate() + 1);
|
|
20210
|
+
candidate.setHours(0, 0, 0, 0);
|
|
20211
|
+
continue;
|
|
20212
|
+
}
|
|
20213
|
+
if (!hours.includes(hour)) {
|
|
20214
|
+
candidate.setHours(candidate.getHours() + 1, 0, 0, 0);
|
|
20215
|
+
continue;
|
|
20216
|
+
}
|
|
20217
|
+
if (!minutes.includes(minute)) {
|
|
20218
|
+
candidate.setMinutes(candidate.getMinutes() + 1, 0, 0);
|
|
20219
|
+
continue;
|
|
20220
|
+
}
|
|
20221
|
+
return new Date(candidate);
|
|
20222
|
+
}
|
|
20223
|
+
return null;
|
|
20224
|
+
}
|
|
20225
|
+
function addSchedule(skill, cron, options = {}) {
|
|
20226
|
+
const { valid, error } = validateCron(cron);
|
|
20227
|
+
if (!valid)
|
|
20228
|
+
return { schedule: null, error };
|
|
20229
|
+
const data = loadSchedules(options.targetDir);
|
|
20230
|
+
const id = `${skill}-${Date.now()}`;
|
|
20231
|
+
const now = new Date;
|
|
20232
|
+
const nextRun = getNextRun(cron, now);
|
|
20233
|
+
const schedule = {
|
|
20234
|
+
id,
|
|
20235
|
+
name: options.name || `${skill} (${cron})`,
|
|
20236
|
+
skill,
|
|
20237
|
+
cron,
|
|
20238
|
+
args: options.args,
|
|
20239
|
+
enabled: true,
|
|
20240
|
+
createdAt: now.toISOString(),
|
|
20241
|
+
nextRun: nextRun?.toISOString()
|
|
20242
|
+
};
|
|
20243
|
+
data.schedules.push(schedule);
|
|
20244
|
+
saveSchedules(data, options.targetDir);
|
|
20245
|
+
return { schedule };
|
|
20246
|
+
}
|
|
20247
|
+
function listSchedules(targetDir) {
|
|
20248
|
+
return loadSchedules(targetDir).schedules;
|
|
20249
|
+
}
|
|
20250
|
+
function removeSchedule(idOrName, targetDir) {
|
|
20251
|
+
const data = loadSchedules(targetDir);
|
|
20252
|
+
const before = data.schedules.length;
|
|
20253
|
+
data.schedules = data.schedules.filter((s) => s.id !== idOrName && s.name !== idOrName);
|
|
20254
|
+
if (data.schedules.length === before)
|
|
20255
|
+
return false;
|
|
20256
|
+
saveSchedules(data, targetDir);
|
|
20257
|
+
return true;
|
|
20258
|
+
}
|
|
20259
|
+
function setScheduleEnabled(idOrName, enabled, targetDir) {
|
|
20260
|
+
const data = loadSchedules(targetDir);
|
|
20261
|
+
const schedule = data.schedules.find((s) => s.id === idOrName || s.name === idOrName);
|
|
20262
|
+
if (!schedule)
|
|
20263
|
+
return false;
|
|
20264
|
+
schedule.enabled = enabled;
|
|
20265
|
+
if (enabled) {
|
|
20266
|
+
schedule.nextRun = getNextRun(schedule.cron)?.toISOString();
|
|
20267
|
+
}
|
|
20268
|
+
saveSchedules(data, targetDir);
|
|
20269
|
+
return true;
|
|
20270
|
+
}
|
|
20271
|
+
function getDueSchedules(targetDir) {
|
|
20272
|
+
const now = new Date;
|
|
20273
|
+
return listSchedules(targetDir).filter((s) => s.enabled && s.nextRun && new Date(s.nextRun) <= now);
|
|
20274
|
+
}
|
|
20275
|
+
function recordScheduleRun(id, status, targetDir) {
|
|
20276
|
+
const data = loadSchedules(targetDir);
|
|
20277
|
+
const schedule = data.schedules.find((s) => s.id === id);
|
|
20278
|
+
if (!schedule)
|
|
20279
|
+
return;
|
|
20280
|
+
const now = new Date;
|
|
20281
|
+
schedule.lastRun = now.toISOString();
|
|
20282
|
+
schedule.lastRunStatus = status;
|
|
20283
|
+
schedule.nextRun = getNextRun(schedule.cron, now)?.toISOString();
|
|
20284
|
+
saveSchedules(data, targetDir);
|
|
20285
|
+
}
|
|
20286
|
+
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;
|
|
19950
20287
|
var init_dist = __esm(() => {
|
|
19951
20288
|
CATEGORIES = [
|
|
19952
20289
|
"Development Tools",
|
|
@@ -20984,6 +21321,20 @@ var init_dist = __esm(() => {
|
|
|
20984
21321
|
category: "Design & Branding",
|
|
20985
21322
|
tags: ["testimonials", "graphics", "social-proof", "marketing"]
|
|
20986
21323
|
},
|
|
21324
|
+
{
|
|
21325
|
+
name: "colorextract",
|
|
21326
|
+
displayName: "Color Extract",
|
|
21327
|
+
description: "Extract complete color palettes from screenshots and images using Claude Vision. Outputs open-styles compatible profiles.",
|
|
21328
|
+
category: "Design & Branding",
|
|
21329
|
+
tags: ["colors", "palette", "design", "vision", "screenshot", "extract", "open-styles"]
|
|
21330
|
+
},
|
|
21331
|
+
{
|
|
21332
|
+
name: "siteanalyze",
|
|
21333
|
+
displayName: "Site Analyze",
|
|
21334
|
+
description: "Analyze any website's design system \u2014 detects shadcn/ui, Tailwind, extracts colors, typography, and components via Playwright + Claude Vision.",
|
|
21335
|
+
category: "Design & Branding",
|
|
21336
|
+
tags: ["design", "shadcn", "tailwind", "colors", "typography", "playwright", "analysis", "open-styles"]
|
|
21337
|
+
},
|
|
20987
21338
|
{
|
|
20988
21339
|
name: "browse",
|
|
20989
21340
|
displayName: "Browse",
|
|
@@ -21386,7 +21737,14 @@ var init_dist = __esm(() => {
|
|
|
21386
21737
|
];
|
|
21387
21738
|
__dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
21388
21739
|
SKILLS_DIR = findSkillsDir();
|
|
21389
|
-
AGENT_TARGETS = ["claude", "codex", "gemini"];
|
|
21740
|
+
AGENT_TARGETS = ["claude", "codex", "gemini", "pi", "opencode"];
|
|
21741
|
+
AGENT_LABELS = {
|
|
21742
|
+
claude: "Claude Code",
|
|
21743
|
+
codex: "Codex CLI",
|
|
21744
|
+
gemini: "Gemini CLI",
|
|
21745
|
+
pi: "pi.dev",
|
|
21746
|
+
opencode: "OpenCode"
|
|
21747
|
+
};
|
|
21390
21748
|
ENV_VAR_PATTERN = /\b([A-Z][A-Z0-9_]{2,}(?:_API_KEY|_KEY|_TOKEN|_SECRET|_URL|_ID|_PASSWORD|_ENDPOINT|_REGION|_BUCKET))\b/g;
|
|
21391
21749
|
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;
|
|
21392
21750
|
VALID_KEYS = {
|
|
@@ -21520,6 +21878,7 @@ var init_skills_runner = __esm(() => {
|
|
|
21520
21878
|
var exports_cron_manager = {};
|
|
21521
21879
|
__export(exports_cron_manager, {
|
|
21522
21880
|
runCronJobNow: () => runCronJobNow,
|
|
21881
|
+
pruneCronEvents: () => pruneCronEvents,
|
|
21523
21882
|
loadCronJobsOnStartup: () => loadCronJobsOnStartup,
|
|
21524
21883
|
listCronJobs: () => listCronJobs,
|
|
21525
21884
|
getCronJob: () => getCronJob,
|
|
@@ -21612,6 +21971,13 @@ function getCronEvents(jobId, limit = 10) {
|
|
|
21612
21971
|
const rows = db.query("SELECT * FROM cron_events WHERE job_id = ? ORDER BY started_at DESC LIMIT ?").all(jobId, limit);
|
|
21613
21972
|
return rows.map((r) => ({ ...r, success: r.success === 1, result: r.result ? JSON.parse(r.result) : undefined }));
|
|
21614
21973
|
}
|
|
21974
|
+
function pruneCronEvents(retentionDays = 7) {
|
|
21975
|
+
ensureCronTable();
|
|
21976
|
+
const db = getDatabase();
|
|
21977
|
+
const cutoff = new Date(Date.now() - retentionDays * 86400000).toISOString();
|
|
21978
|
+
const result = db.prepare("DELETE FROM cron_events WHERE started_at < ?").run(cutoff);
|
|
21979
|
+
return result.changes;
|
|
21980
|
+
}
|
|
21615
21981
|
async function executeCronJob(job) {
|
|
21616
21982
|
ensureCronTable();
|
|
21617
21983
|
const db = getDatabase();
|
|
@@ -21680,6 +22046,9 @@ function unregisterCronJob(id) {
|
|
|
21680
22046
|
}
|
|
21681
22047
|
function loadCronJobsOnStartup() {
|
|
21682
22048
|
try {
|
|
22049
|
+
const pruned = pruneCronEvents();
|
|
22050
|
+
if (pruned > 0)
|
|
22051
|
+
console.error(`[browser] Pruned ${pruned} old cron event(s)`);
|
|
21683
22052
|
const jobs = listCronJobs();
|
|
21684
22053
|
for (const job of jobs) {
|
|
21685
22054
|
if (job.enabled)
|
|
@@ -22263,8 +22632,8 @@ async function tryReplayAuth(page, domain) {
|
|
|
22263
22632
|
return { replayed: false };
|
|
22264
22633
|
if (flow.storage_state_path) {
|
|
22265
22634
|
try {
|
|
22266
|
-
const { existsSync:
|
|
22267
|
-
if (
|
|
22635
|
+
const { existsSync: existsSync9, readFileSync: readFileSync6 } = await import("fs");
|
|
22636
|
+
if (existsSync9(flow.storage_state_path)) {
|
|
22268
22637
|
const state = JSON.parse(readFileSync6(flow.storage_state_path, "utf8"));
|
|
22269
22638
|
if (state.cookies?.length) {
|
|
22270
22639
|
await page.context().addCookies(state.cookies);
|
|
@@ -22504,7 +22873,6 @@ __export(exports_datasets, {
|
|
|
22504
22873
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
22505
22874
|
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync10 } from "fs";
|
|
22506
22875
|
import { join as join12 } from "path";
|
|
22507
|
-
import { homedir as homedir12 } from "os";
|
|
22508
22876
|
function saveDataset(data) {
|
|
22509
22877
|
const db = getDatabase();
|
|
22510
22878
|
const id = randomUUID15();
|
|
@@ -22542,7 +22910,7 @@ function exportDataset(name, format) {
|
|
|
22542
22910
|
const dataset = getDatasetByName(name);
|
|
22543
22911
|
if (!dataset)
|
|
22544
22912
|
throw new Error(`Dataset '${name}' not found`);
|
|
22545
|
-
const dir = join12(
|
|
22913
|
+
const dir = join12(getDataDir(), "exports");
|
|
22546
22914
|
mkdirSync10(dir, { recursive: true });
|
|
22547
22915
|
const filename = `${name}.${format}`;
|
|
22548
22916
|
const path = join12(dir, filename);
|
|
@@ -22572,6 +22940,7 @@ function exportDataset(name, format) {
|
|
|
22572
22940
|
}
|
|
22573
22941
|
var init_datasets = __esm(() => {
|
|
22574
22942
|
init_schema();
|
|
22943
|
+
init_schema();
|
|
22575
22944
|
});
|
|
22576
22945
|
|
|
22577
22946
|
// src/mcp/scripts.ts
|
|
@@ -22713,7 +23082,7 @@ var init_scripts2 = __esm(() => {
|
|
|
22713
23082
|
init_helpers();
|
|
22714
23083
|
});
|
|
22715
23084
|
|
|
22716
|
-
//
|
|
23085
|
+
// node_modules/@hasna/mementos/dist/index.js
|
|
22717
23086
|
var exports_dist2 = {};
|
|
22718
23087
|
__export(exports_dist2, {
|
|
22719
23088
|
withMemoryLock: () => withMemoryLock,
|
|
@@ -22823,17 +23192,20 @@ __export(exports_dist2, {
|
|
|
22823
23192
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG
|
|
22824
23193
|
});
|
|
22825
23194
|
import { Database as Database2 } from "bun:sqlite";
|
|
22826
|
-
import { existsSync as
|
|
23195
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync11 } from "fs";
|
|
22827
23196
|
import { dirname as dirname3, join as join13, resolve as resolve2 } from "path";
|
|
22828
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync6, readdirSync as
|
|
22829
|
-
import { homedir as
|
|
23197
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync6, readdirSync as readdirSync6, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
23198
|
+
import { homedir as homedir4 } from "os";
|
|
22830
23199
|
import { basename as basename2, dirname as dirname22, join as join23, resolve as resolve22 } from "path";
|
|
22831
|
-
import { existsSync as existsSync33, mkdirSync as
|
|
23200
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync33, readFileSync as readFileSync23, writeFileSync as writeFileSync23 } from "fs";
|
|
22832
23201
|
import { homedir as homedir23 } from "os";
|
|
22833
23202
|
import { join as join33 } from "path";
|
|
22834
|
-
import { existsSync as
|
|
22835
|
-
import { homedir as
|
|
22836
|
-
import { join as
|
|
23203
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync42, readFileSync as readFileSync33, writeFileSync as writeFileSync33 } from "fs";
|
|
23204
|
+
import { homedir as homedir33 } from "os";
|
|
23205
|
+
import { join as join43 } from "path";
|
|
23206
|
+
function __exportSetter2(name, newValue) {
|
|
23207
|
+
this[name] = __returnValue2.bind(null, newValue);
|
|
23208
|
+
}
|
|
22837
23209
|
function isInMemoryDb(path) {
|
|
22838
23210
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
22839
23211
|
}
|
|
@@ -22841,7 +23213,7 @@ function findNearestMementosDb(startDir) {
|
|
|
22841
23213
|
let dir = resolve2(startDir);
|
|
22842
23214
|
while (true) {
|
|
22843
23215
|
const candidate = join13(dir, ".mementos", "mementos.db");
|
|
22844
|
-
if (
|
|
23216
|
+
if (existsSync9(candidate))
|
|
22845
23217
|
return candidate;
|
|
22846
23218
|
const parent = dirname3(dir);
|
|
22847
23219
|
if (parent === dir)
|
|
@@ -22853,7 +23225,7 @@ function findNearestMementosDb(startDir) {
|
|
|
22853
23225
|
function findGitRoot(startDir) {
|
|
22854
23226
|
let dir = resolve2(startDir);
|
|
22855
23227
|
while (true) {
|
|
22856
|
-
if (
|
|
23228
|
+
if (existsSync9(join13(dir, ".git")))
|
|
22857
23229
|
return dir;
|
|
22858
23230
|
const parent = dirname3(dir);
|
|
22859
23231
|
if (parent === dir)
|
|
@@ -22883,7 +23255,7 @@ function ensureDir2(filePath) {
|
|
|
22883
23255
|
if (isInMemoryDb(filePath))
|
|
22884
23256
|
return;
|
|
22885
23257
|
const dir = dirname3(resolve2(filePath));
|
|
22886
|
-
if (!
|
|
23258
|
+
if (!existsSync9(dir)) {
|
|
22887
23259
|
mkdirSync11(dir, { recursive: true });
|
|
22888
23260
|
}
|
|
22889
23261
|
}
|
|
@@ -24734,7 +25106,7 @@ function isValidCategory(value) {
|
|
|
24734
25106
|
return VALID_CATEGORIES.includes(value);
|
|
24735
25107
|
}
|
|
24736
25108
|
function loadConfig2() {
|
|
24737
|
-
const configPath = join23(
|
|
25109
|
+
const configPath = join23(homedir4(), ".mementos", "config.json");
|
|
24738
25110
|
let fileConfig = {};
|
|
24739
25111
|
if (existsSync23(configPath)) {
|
|
24740
25112
|
try {
|
|
@@ -24761,10 +25133,10 @@ function loadConfig2() {
|
|
|
24761
25133
|
return merged;
|
|
24762
25134
|
}
|
|
24763
25135
|
function profilesDir() {
|
|
24764
|
-
return join23(
|
|
25136
|
+
return join23(homedir4(), ".mementos", "profiles");
|
|
24765
25137
|
}
|
|
24766
25138
|
function globalConfigPath() {
|
|
24767
|
-
return join23(
|
|
25139
|
+
return join23(homedir4(), ".mementos", "config.json");
|
|
24768
25140
|
}
|
|
24769
25141
|
function readGlobalConfig() {
|
|
24770
25142
|
const p = globalConfigPath();
|
|
@@ -24801,7 +25173,7 @@ function listProfiles2() {
|
|
|
24801
25173
|
const dir = profilesDir();
|
|
24802
25174
|
if (!existsSync23(dir))
|
|
24803
25175
|
return [];
|
|
24804
|
-
return
|
|
25176
|
+
return readdirSync6(dir).filter((f) => f.endsWith(".db")).map((f) => basename2(f, ".db")).sort();
|
|
24805
25177
|
}
|
|
24806
25178
|
function deleteProfile2(name) {
|
|
24807
25179
|
const dbPath = join23(profilesDir(), `${name}.db`);
|
|
@@ -25163,7 +25535,7 @@ function runCleanup(config, db) {
|
|
|
25163
25535
|
function getAgentSyncDir(agentName) {
|
|
25164
25536
|
const dir = join33(homedir23(), ".mementos", "agents", agentName);
|
|
25165
25537
|
if (!existsSync33(dir)) {
|
|
25166
|
-
|
|
25538
|
+
mkdirSync33(dir, { recursive: true });
|
|
25167
25539
|
}
|
|
25168
25540
|
return dir;
|
|
25169
25541
|
}
|
|
@@ -25916,7 +26288,7 @@ ${matched.map((m) => `- ${m.key}: ${m.value.slice(0, 120)}${m.value.length > 120
|
|
|
25916
26288
|
};
|
|
25917
26289
|
}
|
|
25918
26290
|
function readConfig() {
|
|
25919
|
-
if (!
|
|
26291
|
+
if (!existsSync43(CONFIG_PATH))
|
|
25920
26292
|
return {};
|
|
25921
26293
|
try {
|
|
25922
26294
|
const raw = readFileSync33(CONFIG_PATH, "utf-8");
|
|
@@ -25926,10 +26298,10 @@ function readConfig() {
|
|
|
25926
26298
|
}
|
|
25927
26299
|
}
|
|
25928
26300
|
function writeConfig(config) {
|
|
25929
|
-
if (!
|
|
26301
|
+
if (!existsSync43(CONFIG_DIR)) {
|
|
25930
26302
|
mkdirSync42(CONFIG_DIR, { recursive: true });
|
|
25931
26303
|
}
|
|
25932
|
-
|
|
26304
|
+
writeFileSync33(CONFIG_PATH, JSON.stringify(config, null, 2) + `
|
|
25933
26305
|
`, "utf-8");
|
|
25934
26306
|
}
|
|
25935
26307
|
function getActiveModel() {
|
|
@@ -25946,13 +26318,13 @@ function clearActiveModel() {
|
|
|
25946
26318
|
delete config.activeModel;
|
|
25947
26319
|
writeConfig(config);
|
|
25948
26320
|
}
|
|
25949
|
-
var __defProp2, __export2 = (target, all) => {
|
|
26321
|
+
var __defProp2, __returnValue2 = (v) => v, __export2 = (target, all) => {
|
|
25950
26322
|
for (var name in all)
|
|
25951
26323
|
__defProp2(target, name, {
|
|
25952
26324
|
get: all[name],
|
|
25953
26325
|
enumerable: true,
|
|
25954
26326
|
configurable: true,
|
|
25955
|
-
set: (
|
|
26327
|
+
set: __exportSetter2.bind(all, name)
|
|
25956
26328
|
});
|
|
25957
26329
|
}, __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.
|
|
25958
26330
|
Given text, extract facts worth remembering as structured JSON.
|
|
@@ -27288,8 +27660,8 @@ Return only a number 0-10.`);
|
|
|
27288
27660
|
keepLonger: true
|
|
27289
27661
|
};
|
|
27290
27662
|
_stats = { checked: 0, skipped: 0, updated: 0 };
|
|
27291
|
-
CONFIG_DIR =
|
|
27292
|
-
CONFIG_PATH =
|
|
27663
|
+
CONFIG_DIR = join43(homedir33(), ".mementos");
|
|
27664
|
+
CONFIG_PATH = join43(CONFIG_DIR, "config.json");
|
|
27293
27665
|
});
|
|
27294
27666
|
|
|
27295
27667
|
// src/lib/page-memory.ts
|
|
@@ -27367,7 +27739,7 @@ var init_page_memory = __esm(() => {
|
|
|
27367
27739
|
inMemoryCache = new Map;
|
|
27368
27740
|
});
|
|
27369
27741
|
|
|
27370
|
-
//
|
|
27742
|
+
// node_modules/@hasna/conversations/dist/index.js
|
|
27371
27743
|
var exports_dist3 = {};
|
|
27372
27744
|
__export(exports_dist3, {
|
|
27373
27745
|
useSpaceMessages: () => useSpaceMessages,
|
|
@@ -27376,6 +27748,7 @@ __export(exports_dist3, {
|
|
|
27376
27748
|
updateProject: () => updateProject,
|
|
27377
27749
|
unpinMessage: () => unpinMessage,
|
|
27378
27750
|
unarchiveSpace: () => unarchiveSpace,
|
|
27751
|
+
tryBulkAcquireLock: () => tryBulkAcquireLock,
|
|
27379
27752
|
startPolling: () => startPolling,
|
|
27380
27753
|
sendMessage: () => sendMessage,
|
|
27381
27754
|
searchMessages: () => searchMessages,
|
|
@@ -27384,6 +27757,7 @@ __export(exports_dist3, {
|
|
|
27384
27757
|
renameAgent: () => renameAgent,
|
|
27385
27758
|
removeReaction: () => removeReaction,
|
|
27386
27759
|
removePresence: () => removePresence,
|
|
27760
|
+
releaseStaleAgentLocks: () => releaseStaleAgentLocks,
|
|
27387
27761
|
releaseLock: () => releaseLock2,
|
|
27388
27762
|
registerAgent: () => registerAgent4,
|
|
27389
27763
|
readMessages: () => readMessages,
|
|
@@ -27395,6 +27769,7 @@ __export(exports_dist3, {
|
|
|
27395
27769
|
listSpaces: () => listSpaces,
|
|
27396
27770
|
listSessions: () => listSessions3,
|
|
27397
27771
|
listProjects: () => listProjects3,
|
|
27772
|
+
listLocksEnriched: () => listLocksEnriched,
|
|
27398
27773
|
listLocks: () => listLocks,
|
|
27399
27774
|
listHotSessions: () => listHotSessions,
|
|
27400
27775
|
listAgents: () => listAgents3,
|
|
@@ -27446,22 +27821,28 @@ __export(exports_dist3, {
|
|
|
27446
27821
|
import { Database as Database3 } from "bun:sqlite";
|
|
27447
27822
|
import { mkdirSync as mkdirSync12 } from "fs";
|
|
27448
27823
|
import { join as join14, dirname as dirname5 } from "path";
|
|
27449
|
-
import { homedir as
|
|
27824
|
+
import { homedir as homedir5 } from "os";
|
|
27450
27825
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
27451
|
-
import { mkdirSync as mkdirSync24, copyFileSync as
|
|
27826
|
+
import { mkdirSync as mkdirSync24, copyFileSync as copyFileSync4, statSync as statSync4 } from "fs";
|
|
27452
27827
|
import { join as join34 } from "path";
|
|
27453
|
-
import { homedir as
|
|
27828
|
+
import { homedir as homedir34 } from "os";
|
|
27454
27829
|
import { readFileSync as readFileSync7 } from "fs";
|
|
27455
27830
|
import { join as join24 } from "path";
|
|
27456
27831
|
import { homedir as homedir24 } from "os";
|
|
27457
27832
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
27458
|
-
import { readFileSync as readFileSync24, writeFileSync as writeFileSync6, mkdirSync as
|
|
27459
|
-
import { join as
|
|
27833
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync6, mkdirSync as mkdirSync34 } from "fs";
|
|
27834
|
+
import { join as join44, dirname as dirname23 } from "path";
|
|
27460
27835
|
import { homedir as homedir42 } from "os";
|
|
27836
|
+
function __accessProp2(key) {
|
|
27837
|
+
return this[key];
|
|
27838
|
+
}
|
|
27839
|
+
function __exportSetter3(name, newValue) {
|
|
27840
|
+
this[name] = __returnValue3.bind(null, newValue);
|
|
27841
|
+
}
|
|
27461
27842
|
function getDbPath2() {
|
|
27462
27843
|
if (process.env.CONVERSATIONS_DB_PATH)
|
|
27463
27844
|
return process.env.CONVERSATIONS_DB_PATH;
|
|
27464
|
-
return join14(
|
|
27845
|
+
return join14(homedir5(), ".conversations", "messages.db");
|
|
27465
27846
|
}
|
|
27466
27847
|
function getDb() {
|
|
27467
27848
|
if (db)
|
|
@@ -27613,6 +27994,9 @@ function getDb() {
|
|
|
27613
27994
|
if (!spaceColNames.includes("archived_at")) {
|
|
27614
27995
|
db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
|
|
27615
27996
|
}
|
|
27997
|
+
if (!spaceColNames.includes("topic")) {
|
|
27998
|
+
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
27999
|
+
}
|
|
27616
28000
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
27617
28001
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
27618
28002
|
if (!colNames2.includes("edited_at")) {
|
|
@@ -27660,6 +28044,30 @@ function getDb() {
|
|
|
27660
28044
|
if (!presenceColNames.includes("project_id")) {
|
|
27661
28045
|
db.exec("ALTER TABLE agent_presence ADD COLUMN project_id TEXT");
|
|
27662
28046
|
}
|
|
28047
|
+
db.exec(`
|
|
28048
|
+
CREATE TABLE IF NOT EXISTS message_read_receipts (
|
|
28049
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
28050
|
+
agent TEXT NOT NULL,
|
|
28051
|
+
read_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
28052
|
+
PRIMARY KEY (message_id, agent)
|
|
28053
|
+
)
|
|
28054
|
+
`);
|
|
28055
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_read_receipts_message ON message_read_receipts(message_id)");
|
|
28056
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_read_receipts_agent ON message_read_receipts(agent)");
|
|
28057
|
+
db.exec(`
|
|
28058
|
+
CREATE TABLE IF NOT EXISTS message_mentions (
|
|
28059
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28060
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
28061
|
+
mentioned_agent TEXT NOT NULL,
|
|
28062
|
+
from_agent TEXT NOT NULL,
|
|
28063
|
+
space TEXT,
|
|
28064
|
+
notified_at TEXT,
|
|
28065
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))
|
|
28066
|
+
)
|
|
28067
|
+
`);
|
|
28068
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_mentions_agent ON message_mentions(mentioned_agent)");
|
|
28069
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_mentions_message ON message_mentions(message_id)");
|
|
28070
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_mentions_notified ON message_mentions(notified_at)");
|
|
27663
28071
|
const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
|
|
27664
28072
|
if (!ftsExists) {
|
|
27665
28073
|
db.exec(`
|
|
@@ -27795,7 +28203,7 @@ function parseMessage(row) {
|
|
|
27795
28203
|
function getAttachmentsDir() {
|
|
27796
28204
|
if (process.env.CONVERSATIONS_ATTACHMENTS_DIR)
|
|
27797
28205
|
return process.env.CONVERSATIONS_ATTACHMENTS_DIR;
|
|
27798
|
-
return join34(
|
|
28206
|
+
return join34(homedir34(), ".conversations", "attachments");
|
|
27799
28207
|
}
|
|
27800
28208
|
function guessMimeType(name) {
|
|
27801
28209
|
const ext = name.split(".").pop()?.toLowerCase();
|
|
@@ -27845,8 +28253,8 @@ function sendMessage(opts) {
|
|
|
27845
28253
|
const attachmentInfos = [];
|
|
27846
28254
|
for (const att of opts.attachments) {
|
|
27847
28255
|
const destPath = join34(attachmentsDir, att.name);
|
|
27848
|
-
|
|
27849
|
-
const stat =
|
|
28256
|
+
copyFileSync4(att.source_path, destPath);
|
|
28257
|
+
const stat = statSync4(destPath);
|
|
27850
28258
|
attachmentInfos.push({
|
|
27851
28259
|
name: att.name,
|
|
27852
28260
|
path: destPath,
|
|
@@ -27858,6 +28266,12 @@ function sendMessage(opts) {
|
|
|
27858
28266
|
db2.prepare("UPDATE messages SET attachments = ? WHERE id = ?").run(attachmentsJson, message.id);
|
|
27859
28267
|
message.attachments = attachmentInfos;
|
|
27860
28268
|
}
|
|
28269
|
+
if (opts.space) {
|
|
28270
|
+
const mentions = parseMentions(opts.content);
|
|
28271
|
+
if (mentions.length > 0) {
|
|
28272
|
+
processMentions(message.id, opts.from, opts.space, mentions, db2);
|
|
28273
|
+
}
|
|
28274
|
+
}
|
|
27861
28275
|
fireWebhooks(message);
|
|
27862
28276
|
return message;
|
|
27863
28277
|
}
|
|
@@ -27896,11 +28310,34 @@ function readMessages(opts = {}) {
|
|
|
27896
28310
|
if (opts.unread_only) {
|
|
27897
28311
|
conditions.push("read_at IS NULL");
|
|
27898
28312
|
}
|
|
28313
|
+
if (opts.threads_only) {
|
|
28314
|
+
conditions.push("reply_to IS NULL");
|
|
28315
|
+
}
|
|
28316
|
+
if (opts.mentions_only) {
|
|
28317
|
+
conditions.push(`id IN (SELECT message_id FROM message_mentions WHERE mentioned_agent = ?)`);
|
|
28318
|
+
params.push(opts.mentions_only.toLowerCase());
|
|
28319
|
+
}
|
|
28320
|
+
const isLatest = opts.latest && opts.latest > 0;
|
|
27899
28321
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
27900
|
-
const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
27901
|
-
const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
27902
|
-
const
|
|
27903
|
-
const
|
|
28322
|
+
const resolvedLimit = isLatest ? Math.floor(opts.latest) : Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
28323
|
+
const order = isLatest ? "DESC" : opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
28324
|
+
const resolvedOffset = opts.offset && opts.offset > 0 ? Math.floor(opts.offset) : 0;
|
|
28325
|
+
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit} OFFSET ${resolvedOffset}`).all(...params);
|
|
28326
|
+
let messages = rows.map(parseMessage);
|
|
28327
|
+
if (opts.include_reply_counts && messages.length > 0) {
|
|
28328
|
+
const db22 = getDb();
|
|
28329
|
+
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));
|
|
28330
|
+
const countMap = new Map(counts.map((r) => [r.reply_to, r.c]));
|
|
28331
|
+
messages = messages.map((m) => ({ ...m, reply_count: countMap.get(m.id) ?? 0 }));
|
|
28332
|
+
}
|
|
28333
|
+
if (opts.max_content_length && opts.max_content_length > 0) {
|
|
28334
|
+
messages = messages.map((m) => {
|
|
28335
|
+
if (m.content.length > opts.max_content_length) {
|
|
28336
|
+
return { ...m, content: m.content.slice(0, opts.max_content_length) + "\u2026", truncated: true };
|
|
28337
|
+
}
|
|
28338
|
+
return m;
|
|
28339
|
+
});
|
|
28340
|
+
}
|
|
27904
28341
|
if (opts.compact)
|
|
27905
28342
|
return messages.map(compactMessage);
|
|
27906
28343
|
return messages;
|
|
@@ -28081,6 +28518,14 @@ function searchMessages(opts) {
|
|
|
28081
28518
|
extraWhere += " AND m.to_agent = ?";
|
|
28082
28519
|
ftsParams.push(opts.to);
|
|
28083
28520
|
}
|
|
28521
|
+
if (opts.since) {
|
|
28522
|
+
extraWhere += " AND m.created_at >= ?";
|
|
28523
|
+
ftsParams.push(opts.since);
|
|
28524
|
+
}
|
|
28525
|
+
if (opts.until) {
|
|
28526
|
+
extraWhere += " AND m.created_at <= ?";
|
|
28527
|
+
ftsParams.push(opts.until);
|
|
28528
|
+
}
|
|
28084
28529
|
const orderClause = sortByRelevance ? "ORDER BY rank" : "ORDER BY m.created_at DESC, m.id DESC";
|
|
28085
28530
|
const rows2 = db2.prepare(`SELECT m.*, rank,
|
|
28086
28531
|
snippet(messages_fts, 0, '**', '**', '...', 20) as snippet
|
|
@@ -28113,6 +28558,14 @@ function searchMessages(opts) {
|
|
|
28113
28558
|
conditions.push("to_agent = ?");
|
|
28114
28559
|
params.push(opts.to);
|
|
28115
28560
|
}
|
|
28561
|
+
if (opts.since) {
|
|
28562
|
+
conditions.push("created_at >= ?");
|
|
28563
|
+
params.push(opts.since);
|
|
28564
|
+
}
|
|
28565
|
+
if (opts.until) {
|
|
28566
|
+
conditions.push("created_at <= ?");
|
|
28567
|
+
params.push(opts.until);
|
|
28568
|
+
}
|
|
28116
28569
|
const where = `WHERE ${conditions.join(" AND ")}`;
|
|
28117
28570
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
|
|
28118
28571
|
return rows.map((row) => {
|
|
@@ -28120,6 +28573,26 @@ function searchMessages(opts) {
|
|
|
28120
28573
|
return { ...msg, snippet: null, relevance_score: 0 };
|
|
28121
28574
|
});
|
|
28122
28575
|
}
|
|
28576
|
+
function parseMentions(content) {
|
|
28577
|
+
const matches = content.match(/@([a-zA-Z0-9_-]+)/g) ?? [];
|
|
28578
|
+
return [...new Set(matches.map((m) => m.slice(1).toLowerCase()))];
|
|
28579
|
+
}
|
|
28580
|
+
async function processMentions(messageId, fromAgent, space, mentionedAgents, db2) {
|
|
28581
|
+
const stmt = db2.prepare("INSERT INTO message_mentions (message_id, mentioned_agent, from_agent, space) VALUES (?, ?, ?, ?)");
|
|
28582
|
+
for (const agent of mentionedAgents) {
|
|
28583
|
+
try {
|
|
28584
|
+
stmt.run(messageId, agent, fromAgent, space);
|
|
28585
|
+
if (agent !== fromAgent.toLowerCase()) {
|
|
28586
|
+
sendMessage({
|
|
28587
|
+
from: fromAgent,
|
|
28588
|
+
to: agent,
|
|
28589
|
+
content: `You were mentioned in #${space} by ${fromAgent} (message #${messageId})`,
|
|
28590
|
+
metadata: { type: "mention_notification", source_message_id: messageId, space }
|
|
28591
|
+
});
|
|
28592
|
+
}
|
|
28593
|
+
} catch {}
|
|
28594
|
+
}
|
|
28595
|
+
}
|
|
28123
28596
|
function listSessions3(agent) {
|
|
28124
28597
|
const db2 = getDb();
|
|
28125
28598
|
const agentFilter = agent ? "WHERE from_agent = ? OR to_agent = ?" : "";
|
|
@@ -28654,7 +29127,7 @@ function getAutoName() {
|
|
|
28654
29127
|
}
|
|
28655
29128
|
cachedAutoName = name;
|
|
28656
29129
|
try {
|
|
28657
|
-
|
|
29130
|
+
mkdirSync34(dirname23(AGENT_ID_FILE), { recursive: true });
|
|
28658
29131
|
writeFileSync6(AGENT_ID_FILE, name + `
|
|
28659
29132
|
`, "utf-8");
|
|
28660
29133
|
} catch {}
|
|
@@ -28846,6 +29319,7 @@ function acquireLock2(resourceType, resourceId, agentId, lockType = "advisory",
|
|
|
28846
29319
|
const db2 = getDb();
|
|
28847
29320
|
return db2.transaction(() => {
|
|
28848
29321
|
cleanExpiredLocks2();
|
|
29322
|
+
releaseStaleAgentLocks();
|
|
28849
29323
|
const existing = db2.prepare(`
|
|
28850
29324
|
SELECT * FROM resource_locks
|
|
28851
29325
|
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
@@ -28872,6 +29346,55 @@ function acquireLock2(resourceType, resourceId, agentId, lockType = "advisory",
|
|
|
28872
29346
|
return { acquired: true, lock };
|
|
28873
29347
|
}).immediate();
|
|
28874
29348
|
}
|
|
29349
|
+
function bulkAcquireLock(resources, agentId) {
|
|
29350
|
+
const db2 = getDb();
|
|
29351
|
+
return db2.transaction(() => {
|
|
29352
|
+
cleanExpiredLocks2();
|
|
29353
|
+
releaseStaleAgentLocks();
|
|
29354
|
+
const acquired = [];
|
|
29355
|
+
for (const { resource_type, resource_id, lock_type = "advisory", expiry_ms = DEFAULT_LOCK_EXPIRY_MS } of resources) {
|
|
29356
|
+
const existing = db2.prepare(`
|
|
29357
|
+
SELECT * FROM resource_locks
|
|
29358
|
+
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
29359
|
+
`).get(resource_type, resource_id, lock_type);
|
|
29360
|
+
if (existing && existing.agent_id !== agentId) {
|
|
29361
|
+
throw { _bulkConflict: true, resource_type, resource_id, held_by: existing.agent_id };
|
|
29362
|
+
}
|
|
29363
|
+
const expiresAt = new Date(Date.now() + expiry_ms).toISOString().slice(0, -1);
|
|
29364
|
+
if (existing) {
|
|
29365
|
+
db2.prepare(`
|
|
29366
|
+
UPDATE resource_locks SET expires_at = ?, locked_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
|
|
29367
|
+
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
29368
|
+
`).run(expiresAt, resource_type, resource_id, lock_type);
|
|
29369
|
+
} else {
|
|
29370
|
+
db2.prepare(`
|
|
29371
|
+
INSERT INTO resource_locks (resource_type, resource_id, agent_id, lock_type, locked_at, expires_at)
|
|
29372
|
+
VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%f', 'now'), ?)
|
|
29373
|
+
`).run(resource_type, resource_id, agentId, lock_type, expiresAt);
|
|
29374
|
+
}
|
|
29375
|
+
const lock = db2.prepare(`
|
|
29376
|
+
SELECT * FROM resource_locks WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
29377
|
+
`).get(resource_type, resource_id, lock_type);
|
|
29378
|
+
acquired.push(lock);
|
|
29379
|
+
}
|
|
29380
|
+
return { acquired: true, locks: acquired };
|
|
29381
|
+
}).immediate();
|
|
29382
|
+
}
|
|
29383
|
+
function tryBulkAcquireLock(resources, agentId) {
|
|
29384
|
+
try {
|
|
29385
|
+
return bulkAcquireLock(resources, agentId);
|
|
29386
|
+
} catch (err2) {
|
|
29387
|
+
const e = err2;
|
|
29388
|
+
if (e?._bulkConflict) {
|
|
29389
|
+
return {
|
|
29390
|
+
acquired: false,
|
|
29391
|
+
locks: [],
|
|
29392
|
+
blocked_by: { resource_type: e.resource_type, resource_id: e.resource_id, held_by: e.held_by }
|
|
29393
|
+
};
|
|
29394
|
+
}
|
|
29395
|
+
throw err2;
|
|
29396
|
+
}
|
|
29397
|
+
}
|
|
28875
29398
|
function releaseLock2(resourceType, resourceId, agentId) {
|
|
28876
29399
|
const db2 = getDb();
|
|
28877
29400
|
const result = db2.prepare(`
|
|
@@ -28883,6 +29406,7 @@ function releaseLock2(resourceType, resourceId, agentId) {
|
|
|
28883
29406
|
function checkLock2(resourceType, resourceId) {
|
|
28884
29407
|
const db2 = getDb();
|
|
28885
29408
|
cleanExpiredLocks2();
|
|
29409
|
+
releaseStaleAgentLocks();
|
|
28886
29410
|
return db2.prepare(`
|
|
28887
29411
|
SELECT * FROM resource_locks
|
|
28888
29412
|
WHERE resource_type = ? AND resource_id = ?
|
|
@@ -28890,6 +29414,17 @@ function checkLock2(resourceType, resourceId) {
|
|
|
28890
29414
|
LIMIT 1
|
|
28891
29415
|
`).get(resourceType, resourceId);
|
|
28892
29416
|
}
|
|
29417
|
+
function releaseStaleAgentLocks() {
|
|
29418
|
+
const db2 = getDb();
|
|
29419
|
+
const result = db2.prepare(`
|
|
29420
|
+
DELETE FROM resource_locks
|
|
29421
|
+
WHERE LOWER(agent_id) IN (
|
|
29422
|
+
SELECT LOWER(agent) FROM agent_presence
|
|
29423
|
+
WHERE last_seen_at < strftime('%Y-%m-%dT%H:%M:%f', 'now', '-${STALE_HEARTBEAT_SECONDS} seconds')
|
|
29424
|
+
)
|
|
29425
|
+
`).run();
|
|
29426
|
+
return result.changes;
|
|
29427
|
+
}
|
|
28893
29428
|
function cleanExpiredLocks2() {
|
|
28894
29429
|
const db2 = getDb();
|
|
28895
29430
|
const result = db2.prepare(`
|
|
@@ -28900,6 +29435,7 @@ function cleanExpiredLocks2() {
|
|
|
28900
29435
|
function listLocks(opts) {
|
|
28901
29436
|
const db2 = getDb();
|
|
28902
29437
|
cleanExpiredLocks2();
|
|
29438
|
+
releaseStaleAgentLocks();
|
|
28903
29439
|
let query = "SELECT * FROM resource_locks WHERE 1=1";
|
|
28904
29440
|
const params = [];
|
|
28905
29441
|
if (opts?.resource_type) {
|
|
@@ -28913,6 +29449,31 @@ function listLocks(opts) {
|
|
|
28913
29449
|
query += " ORDER BY locked_at ASC";
|
|
28914
29450
|
return db2.prepare(query).all(...params);
|
|
28915
29451
|
}
|
|
29452
|
+
function listLocksEnriched(opts) {
|
|
29453
|
+
const locks = listLocks(opts);
|
|
29454
|
+
const db2 = getDb();
|
|
29455
|
+
const nowMs = Date.now();
|
|
29456
|
+
return locks.map((lock) => {
|
|
29457
|
+
const lockedMs = new Date(lock.locked_at + "Z").getTime();
|
|
29458
|
+
const expiresMs = new Date(lock.expires_at + "Z").getTime();
|
|
29459
|
+
const presenceRow = db2.prepare(`
|
|
29460
|
+
SELECT role, status, last_seen_at, project_id FROM agent_presence WHERE LOWER(agent) = LOWER(?)
|
|
29461
|
+
`).get(lock.agent_id);
|
|
29462
|
+
const agent = presenceRow ? {
|
|
29463
|
+
role: presenceRow.role ?? null,
|
|
29464
|
+
status: presenceRow.status ?? null,
|
|
29465
|
+
online: presenceRow.last_seen_at ? nowMs - new Date(presenceRow.last_seen_at + "Z").getTime() < 60000 : false,
|
|
29466
|
+
last_seen_at: presenceRow.last_seen_at ?? null,
|
|
29467
|
+
project_id: presenceRow.project_id ?? null
|
|
29468
|
+
} : null;
|
|
29469
|
+
return {
|
|
29470
|
+
...lock,
|
|
29471
|
+
locked_seconds_ago: Math.round((nowMs - lockedMs) / 1000),
|
|
29472
|
+
expires_in_seconds: Math.round((expiresMs - nowMs) / 1000),
|
|
29473
|
+
agent
|
|
29474
|
+
};
|
|
29475
|
+
});
|
|
29476
|
+
}
|
|
28916
29477
|
function computeHotness(sessionId) {
|
|
28917
29478
|
const db2 = getDb();
|
|
28918
29479
|
const base = db2.prepare(`
|
|
@@ -29261,37 +29822,49 @@ function getGraphStats() {
|
|
|
29261
29822
|
map[r.relation] = r.c;
|
|
29262
29823
|
return { total_edges: total, by_relation: map };
|
|
29263
29824
|
}
|
|
29264
|
-
var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2, __getOwnPropDesc2, __hasOwnProp2, __toESM2 = (mod, isNodeMode, target) => {
|
|
29825
|
+
var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2, __getOwnPropDesc2, __hasOwnProp2, __toESMCache_node2, __toESMCache_esm2, __toESM2 = (mod, isNodeMode, target) => {
|
|
29826
|
+
var canCache = mod != null && typeof mod === "object";
|
|
29827
|
+
if (canCache) {
|
|
29828
|
+
var cache = isNodeMode ? __toESMCache_node2 ??= new WeakMap : __toESMCache_esm2 ??= new WeakMap;
|
|
29829
|
+
var cached = cache.get(mod);
|
|
29830
|
+
if (cached)
|
|
29831
|
+
return cached;
|
|
29832
|
+
}
|
|
29265
29833
|
target = mod != null ? __create2(__getProtoOf2(mod)) : {};
|
|
29266
29834
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp3(target, "default", { value: mod, enumerable: true }) : target;
|
|
29267
29835
|
for (let key of __getOwnPropNames2(mod))
|
|
29268
29836
|
if (!__hasOwnProp2.call(to, key))
|
|
29269
29837
|
__defProp3(to, key, {
|
|
29270
|
-
get: (
|
|
29838
|
+
get: __accessProp2.bind(mod, key),
|
|
29271
29839
|
enumerable: true
|
|
29272
29840
|
});
|
|
29841
|
+
if (canCache)
|
|
29842
|
+
cache.set(mod, to);
|
|
29273
29843
|
return to;
|
|
29274
|
-
},
|
|
29275
|
-
var entry = __moduleCache2.get(from), desc;
|
|
29844
|
+
}, __toCommonJS2 = (from) => {
|
|
29845
|
+
var entry = (__moduleCache2 ??= new WeakMap).get(from), desc;
|
|
29276
29846
|
if (entry)
|
|
29277
29847
|
return entry;
|
|
29278
29848
|
entry = __defProp3({}, "__esModule", { value: true });
|
|
29279
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
29280
|
-
|
|
29281
|
-
|
|
29282
|
-
|
|
29283
|
-
|
|
29849
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
29850
|
+
for (var key of __getOwnPropNames2(from))
|
|
29851
|
+
if (!__hasOwnProp2.call(entry, key))
|
|
29852
|
+
__defProp3(entry, key, {
|
|
29853
|
+
get: __accessProp2.bind(from, key),
|
|
29854
|
+
enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
|
|
29855
|
+
});
|
|
29856
|
+
}
|
|
29284
29857
|
__moduleCache2.set(from, entry);
|
|
29285
29858
|
return entry;
|
|
29286
|
-
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __export3 = (target, all) => {
|
|
29859
|
+
}, __moduleCache2, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue3 = (v) => v, __export3 = (target, all) => {
|
|
29287
29860
|
for (var name in all)
|
|
29288
29861
|
__defProp3(target, name, {
|
|
29289
29862
|
get: all[name],
|
|
29290
29863
|
enumerable: true,
|
|
29291
29864
|
configurable: true,
|
|
29292
|
-
set: (
|
|
29865
|
+
set: __exportSetter3.bind(all, name)
|
|
29293
29866
|
});
|
|
29294
|
-
}, 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;
|
|
29867
|
+
}, 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;
|
|
29295
29868
|
var init_dist3 = __esm(() => {
|
|
29296
29869
|
__create2 = Object.create;
|
|
29297
29870
|
__getProtoOf2 = Object.getPrototypeOf;
|
|
@@ -29299,7 +29872,6 @@ var init_dist3 = __esm(() => {
|
|
|
29299
29872
|
__getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
29300
29873
|
__getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
29301
29874
|
__hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
29302
|
-
__moduleCache2 = /* @__PURE__ */ new WeakMap;
|
|
29303
29875
|
exports_db = {};
|
|
29304
29876
|
__export3(exports_db, {
|
|
29305
29877
|
getDbPath: () => getDbPath2,
|
|
@@ -31466,12 +32038,13 @@ Check the top-level render call using <` + parentName + ">.";
|
|
|
31466
32038
|
"zinc-eagle",
|
|
31467
32039
|
"zone-fox"
|
|
31468
32040
|
];
|
|
31469
|
-
AGENT_ID_FILE =
|
|
32041
|
+
AGENT_ID_FILE = join44(homedir42(), ".conversations", "agent-id");
|
|
31470
32042
|
init_db();
|
|
31471
32043
|
init_db();
|
|
31472
32044
|
CONFLICT_THRESHOLD_SECONDS = 30 * 60;
|
|
31473
32045
|
init_db();
|
|
31474
32046
|
DEFAULT_LOCK_EXPIRY_MS = 5 * 60 * 1000;
|
|
32047
|
+
STALE_HEARTBEAT_SECONDS = 30 * 60;
|
|
31475
32048
|
init_db();
|
|
31476
32049
|
init_db();
|
|
31477
32050
|
STOPWORDS = new Set([
|
|
@@ -31668,7 +32241,7 @@ var init_coordination = __esm(() => {
|
|
|
31668
32241
|
activeNavigations = new Map;
|
|
31669
32242
|
});
|
|
31670
32243
|
|
|
31671
|
-
//
|
|
32244
|
+
// node_modules/@hasna/todos/dist/index.js
|
|
31672
32245
|
var exports_dist4 = {};
|
|
31673
32246
|
__export(exports_dist4, {
|
|
31674
32247
|
uuid: () => uuid2,
|
|
@@ -31695,6 +32268,7 @@ __export(exports_dist4, {
|
|
|
31695
32268
|
setTaskStatus: () => setTaskStatus,
|
|
31696
32269
|
setTaskPriority: () => setTaskPriority,
|
|
31697
32270
|
setBudget: () => setBudget,
|
|
32271
|
+
setActiveModel: () => setActiveModel2,
|
|
31698
32272
|
searchTasks: () => searchTasks,
|
|
31699
32273
|
scoreTask: () => scoreTask,
|
|
31700
32274
|
saveSnapshot: () => saveSnapshot,
|
|
@@ -31794,6 +32368,8 @@ __export(exports_dist4, {
|
|
|
31794
32368
|
getAgentByName: () => getAgentByName2,
|
|
31795
32369
|
getAgent: () => getAgent3,
|
|
31796
32370
|
getActiveWork: () => getActiveWork,
|
|
32371
|
+
getActiveModel: () => getActiveModel2,
|
|
32372
|
+
gatherTrainingData: () => gatherTrainingData2,
|
|
31797
32373
|
findTasksByFile: () => findTasksByFile,
|
|
31798
32374
|
findRelatedTaskIds: () => findRelatedTaskIds,
|
|
31799
32375
|
findPath: () => findPath2,
|
|
@@ -31831,6 +32407,7 @@ __export(exports_dist4, {
|
|
|
31831
32407
|
closeDatabase: () => closeDatabase2,
|
|
31832
32408
|
cloneTask: () => cloneTask,
|
|
31833
32409
|
clearChecklist: () => clearChecklist,
|
|
32410
|
+
clearActiveModel: () => clearActiveModel2,
|
|
31834
32411
|
cleanExpiredLocks: () => cleanExpiredLocks3,
|
|
31835
32412
|
claimOrSteal: () => claimOrSteal,
|
|
31836
32413
|
claimNextTask: () => claimNextTask,
|
|
@@ -31865,22 +32442,26 @@ __export(exports_dist4, {
|
|
|
31865
32442
|
LockError: () => LockError,
|
|
31866
32443
|
EXTRACT_TAGS: () => EXTRACT_TAGS,
|
|
31867
32444
|
DependencyCycleError: () => DependencyCycleError,
|
|
32445
|
+
DEFAULT_MODEL: () => DEFAULT_MODEL3,
|
|
31868
32446
|
CompletionGuardError: () => CompletionGuardError,
|
|
31869
32447
|
AgentNotFoundError: () => AgentNotFoundError2
|
|
31870
32448
|
});
|
|
31871
32449
|
import { Database as Database4 } from "bun:sqlite";
|
|
31872
|
-
import { existsSync as
|
|
32450
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync13 } from "fs";
|
|
31873
32451
|
import { dirname as dirname6, join as join15, resolve as resolve3 } from "path";
|
|
31874
32452
|
import { existsSync as existsSync34 } from "fs";
|
|
31875
32453
|
import { join as join35 } from "path";
|
|
31876
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync25, readFileSync as readFileSync8, readdirSync as
|
|
32454
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync25, readFileSync as readFileSync8, readdirSync as readdirSync7, statSync as statSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
31877
32455
|
import { join as join25 } from "path";
|
|
31878
|
-
import { existsSync as
|
|
31879
|
-
import {
|
|
31880
|
-
import {
|
|
31881
|
-
import {
|
|
31882
|
-
import {
|
|
31883
|
-
import {
|
|
32456
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync35, readFileSync as readFileSync25, writeFileSync as writeFileSync24 } from "fs";
|
|
32457
|
+
import { homedir as homedir6 } from "os";
|
|
32458
|
+
import { join as join45 } from "path";
|
|
32459
|
+
import { existsSync as existsSync53, readFileSync as readFileSync34, readdirSync as readdirSync23, writeFileSync as writeFileSync34 } from "fs";
|
|
32460
|
+
import { join as join53 } from "path";
|
|
32461
|
+
import { existsSync as existsSync62 } from "fs";
|
|
32462
|
+
import { join as join62 } from "path";
|
|
32463
|
+
import { readFileSync as readFileSync43, statSync as statSync22 } from "fs";
|
|
32464
|
+
import { relative, resolve as resolve23, join as join72 } from "path";
|
|
31884
32465
|
import { execSync as execSync2 } from "child_process";
|
|
31885
32466
|
|
|
31886
32467
|
class TodosClient {
|
|
@@ -32104,7 +32685,7 @@ function findNearestTodosDb(startDir) {
|
|
|
32104
32685
|
let dir = resolve3(startDir);
|
|
32105
32686
|
while (true) {
|
|
32106
32687
|
const candidate = join15(dir, ".todos", "todos.db");
|
|
32107
|
-
if (
|
|
32688
|
+
if (existsSync10(candidate))
|
|
32108
32689
|
return candidate;
|
|
32109
32690
|
const parent = dirname6(dir);
|
|
32110
32691
|
if (parent === dir)
|
|
@@ -32116,7 +32697,7 @@ function findNearestTodosDb(startDir) {
|
|
|
32116
32697
|
function findGitRoot2(startDir) {
|
|
32117
32698
|
let dir = resolve3(startDir);
|
|
32118
32699
|
while (true) {
|
|
32119
|
-
if (
|
|
32700
|
+
if (existsSync10(join15(dir, ".git")))
|
|
32120
32701
|
return dir;
|
|
32121
32702
|
const parent = dirname6(dir);
|
|
32122
32703
|
if (parent === dir)
|
|
@@ -32146,7 +32727,7 @@ function ensureDir3(filePath) {
|
|
|
32146
32727
|
if (isInMemoryDb2(filePath))
|
|
32147
32728
|
return;
|
|
32148
32729
|
const dir = dirname6(resolve3(filePath));
|
|
32149
|
-
if (!
|
|
32730
|
+
if (!existsSync10(dir)) {
|
|
32150
32731
|
mkdirSync13(dir, { recursive: true });
|
|
32151
32732
|
}
|
|
32152
32733
|
}
|
|
@@ -32613,7 +33194,7 @@ function ensureDir23(dir) {
|
|
|
32613
33194
|
function listJsonFiles(dir) {
|
|
32614
33195
|
if (!existsSync24(dir))
|
|
32615
33196
|
return [];
|
|
32616
|
-
return
|
|
33197
|
+
return readdirSync7(dir).filter((f) => f.endsWith(".json"));
|
|
32617
33198
|
}
|
|
32618
33199
|
function readJsonFile(path) {
|
|
32619
33200
|
try {
|
|
@@ -32638,7 +33219,7 @@ function writeHighWaterMark(dir, value) {
|
|
|
32638
33219
|
}
|
|
32639
33220
|
function getFileMtimeMs(path) {
|
|
32640
33221
|
try {
|
|
32641
|
-
return
|
|
33222
|
+
return statSync5(path).mtimeMs;
|
|
32642
33223
|
} catch {
|
|
32643
33224
|
return null;
|
|
32644
33225
|
}
|
|
@@ -34611,6 +35192,91 @@ function deleteSession2(id, db2) {
|
|
|
34611
35192
|
const result = d.run("DELETE FROM sessions WHERE id = ?", [id]);
|
|
34612
35193
|
return result.changes > 0;
|
|
34613
35194
|
}
|
|
35195
|
+
function taskToCreateExample(task) {
|
|
35196
|
+
const userMsg = `Create a task: ${task.title}${task.description ? `
|
|
35197
|
+
|
|
35198
|
+
Description: ${task.description}` : ""}`;
|
|
35199
|
+
const taskDetails = {
|
|
35200
|
+
id: task.short_id ?? task.id,
|
|
35201
|
+
title: task.title,
|
|
35202
|
+
description: task.description ?? "",
|
|
35203
|
+
status: task.status,
|
|
35204
|
+
priority: task.priority,
|
|
35205
|
+
tags: task.tags,
|
|
35206
|
+
created_at: task.created_at
|
|
35207
|
+
};
|
|
35208
|
+
return {
|
|
35209
|
+
messages: [
|
|
35210
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
35211
|
+
{ role: "user", content: userMsg },
|
|
35212
|
+
{
|
|
35213
|
+
role: "assistant",
|
|
35214
|
+
content: `Created task: ${JSON.stringify(taskDetails, null, 2)}`
|
|
35215
|
+
}
|
|
35216
|
+
]
|
|
35217
|
+
};
|
|
35218
|
+
}
|
|
35219
|
+
function taskToStatusUpdateExample(task) {
|
|
35220
|
+
if (!task.completed_at && task.status === "pending")
|
|
35221
|
+
return null;
|
|
35222
|
+
const id = task.short_id ?? task.id;
|
|
35223
|
+
return {
|
|
35224
|
+
messages: [
|
|
35225
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
35226
|
+
{ role: "user", content: `Mark task ${id} as ${task.status}` },
|
|
35227
|
+
{
|
|
35228
|
+
role: "assistant",
|
|
35229
|
+
content: `Task ${id} has been updated to status: ${task.status}. ${task.completed_at ? `Completed at: ${task.completed_at}` : ""}`.trim()
|
|
35230
|
+
}
|
|
35231
|
+
]
|
|
35232
|
+
};
|
|
35233
|
+
}
|
|
35234
|
+
function taskToSearchExample(tasks, query) {
|
|
35235
|
+
const matched = tasks.filter((t) => t.title.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
|
|
35236
|
+
return {
|
|
35237
|
+
messages: [
|
|
35238
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
35239
|
+
{ role: "user", content: `Search tasks for: "${query}"` },
|
|
35240
|
+
{
|
|
35241
|
+
role: "assistant",
|
|
35242
|
+
content: matched.length > 0 ? `Found ${matched.length} task(s):
|
|
35243
|
+
${matched.map((t) => `- [${t.short_id ?? t.id}] ${t.title} (${t.status})`).join(`
|
|
35244
|
+
`)}` : `No tasks found matching "${query}".`
|
|
35245
|
+
}
|
|
35246
|
+
]
|
|
35247
|
+
};
|
|
35248
|
+
}
|
|
35249
|
+
function readConfig2() {
|
|
35250
|
+
if (!existsSync44(CONFIG_PATH2))
|
|
35251
|
+
return {};
|
|
35252
|
+
try {
|
|
35253
|
+
const raw = readFileSync25(CONFIG_PATH2, "utf-8");
|
|
35254
|
+
return JSON.parse(raw);
|
|
35255
|
+
} catch {
|
|
35256
|
+
return {};
|
|
35257
|
+
}
|
|
35258
|
+
}
|
|
35259
|
+
function writeConfig2(config) {
|
|
35260
|
+
if (!existsSync44(CONFIG_DIR2)) {
|
|
35261
|
+
mkdirSync35(CONFIG_DIR2, { recursive: true });
|
|
35262
|
+
}
|
|
35263
|
+
writeFileSync24(CONFIG_PATH2, JSON.stringify(config, null, 2) + `
|
|
35264
|
+
`, "utf-8");
|
|
35265
|
+
}
|
|
35266
|
+
function getActiveModel2() {
|
|
35267
|
+
const config = readConfig2();
|
|
35268
|
+
return config.activeModel ?? DEFAULT_MODEL3;
|
|
35269
|
+
}
|
|
35270
|
+
function setActiveModel2(modelId) {
|
|
35271
|
+
const config = readConfig2();
|
|
35272
|
+
config.activeModel = modelId;
|
|
35273
|
+
writeConfig2(config);
|
|
35274
|
+
}
|
|
35275
|
+
function clearActiveModel2() {
|
|
35276
|
+
const config = readConfig2();
|
|
35277
|
+
delete config.activeModel;
|
|
35278
|
+
writeConfig2(config);
|
|
35279
|
+
}
|
|
34614
35280
|
function createHandoff(input, db2) {
|
|
34615
35281
|
const d = db2 || getDatabase3();
|
|
34616
35282
|
const id = uuid2();
|
|
@@ -35425,13 +36091,13 @@ function searchTasks(options, projectId, taskListId, db2) {
|
|
|
35425
36091
|
return rows.map(rowToTask3);
|
|
35426
36092
|
}
|
|
35427
36093
|
function getTaskListDir(taskListId) {
|
|
35428
|
-
return
|
|
36094
|
+
return join53(HOME, ".claude", "tasks", taskListId);
|
|
35429
36095
|
}
|
|
35430
36096
|
function readClaudeTask(dir, filename) {
|
|
35431
|
-
return readJsonFile(
|
|
36097
|
+
return readJsonFile(join53(dir, filename));
|
|
35432
36098
|
}
|
|
35433
36099
|
function writeClaudeTask(dir, task) {
|
|
35434
|
-
writeJsonFile(
|
|
36100
|
+
writeJsonFile(join53(dir, `${task.id}.json`), task);
|
|
35435
36101
|
}
|
|
35436
36102
|
function toClaudeStatus(status) {
|
|
35437
36103
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -35443,14 +36109,14 @@ function toSqliteStatus(status) {
|
|
|
35443
36109
|
return status;
|
|
35444
36110
|
}
|
|
35445
36111
|
function readPrefixCounter(dir) {
|
|
35446
|
-
const path =
|
|
35447
|
-
if (!
|
|
36112
|
+
const path = join53(dir, ".prefix-counter");
|
|
36113
|
+
if (!existsSync53(path))
|
|
35448
36114
|
return 0;
|
|
35449
|
-
const val = parseInt(
|
|
36115
|
+
const val = parseInt(readFileSync34(path, "utf-8").trim(), 10);
|
|
35450
36116
|
return isNaN(val) ? 0 : val;
|
|
35451
36117
|
}
|
|
35452
36118
|
function writePrefixCounter(dir, value) {
|
|
35453
|
-
|
|
36119
|
+
writeFileSync34(join53(dir, ".prefix-counter"), String(value));
|
|
35454
36120
|
}
|
|
35455
36121
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
35456
36122
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -35477,7 +36143,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
35477
36143
|
}
|
|
35478
36144
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
35479
36145
|
const dir = getTaskListDir(taskListId);
|
|
35480
|
-
if (!
|
|
36146
|
+
if (!existsSync53(dir))
|
|
35481
36147
|
ensureDir23(dir);
|
|
35482
36148
|
const filter = {};
|
|
35483
36149
|
if (projectId)
|
|
@@ -35486,7 +36152,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
35486
36152
|
const existingByTodosId = new Map;
|
|
35487
36153
|
const files = listJsonFiles(dir);
|
|
35488
36154
|
for (const f of files) {
|
|
35489
|
-
const path =
|
|
36155
|
+
const path = join53(dir, f);
|
|
35490
36156
|
const ct = readClaudeTask(dir, f);
|
|
35491
36157
|
if (ct?.metadata?.["todos_id"]) {
|
|
35492
36158
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -35573,7 +36239,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
35573
36239
|
}
|
|
35574
36240
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
35575
36241
|
const dir = getTaskListDir(taskListId);
|
|
35576
|
-
if (!
|
|
36242
|
+
if (!existsSync53(dir)) {
|
|
35577
36243
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
35578
36244
|
}
|
|
35579
36245
|
const files = readdirSync23(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -35593,7 +36259,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
35593
36259
|
}
|
|
35594
36260
|
for (const f of files) {
|
|
35595
36261
|
try {
|
|
35596
|
-
const filePath =
|
|
36262
|
+
const filePath = join53(dir, f);
|
|
35597
36263
|
const ct = readClaudeTask(dir, f);
|
|
35598
36264
|
if (!ct)
|
|
35599
36265
|
continue;
|
|
@@ -35661,16 +36327,16 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
35661
36327
|
}
|
|
35662
36328
|
function agentBaseDir(agent) {
|
|
35663
36329
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
35664
|
-
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
36330
|
+
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join62(HOME, ".todos", "agents");
|
|
35665
36331
|
}
|
|
35666
36332
|
function getTaskListDir2(agent, taskListId) {
|
|
35667
|
-
return
|
|
36333
|
+
return join62(agentBaseDir(agent), agent, taskListId);
|
|
35668
36334
|
}
|
|
35669
36335
|
function readAgentTask(dir, filename) {
|
|
35670
|
-
return readJsonFile(
|
|
36336
|
+
return readJsonFile(join62(dir, filename));
|
|
35671
36337
|
}
|
|
35672
36338
|
function writeAgentTask(dir, task) {
|
|
35673
|
-
writeJsonFile(
|
|
36339
|
+
writeJsonFile(join62(dir, `${task.id}.json`), task);
|
|
35674
36340
|
}
|
|
35675
36341
|
function taskToAgentTask(task, externalId, existingMeta) {
|
|
35676
36342
|
return {
|
|
@@ -35695,7 +36361,7 @@ function metadataKey(agent) {
|
|
|
35695
36361
|
}
|
|
35696
36362
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
35697
36363
|
const dir = getTaskListDir2(agent, taskListId);
|
|
35698
|
-
if (!
|
|
36364
|
+
if (!existsSync62(dir))
|
|
35699
36365
|
ensureDir23(dir);
|
|
35700
36366
|
const filter = {};
|
|
35701
36367
|
if (projectId)
|
|
@@ -35704,7 +36370,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
35704
36370
|
const existingByTodosId = new Map;
|
|
35705
36371
|
const files = listJsonFiles(dir);
|
|
35706
36372
|
for (const f of files) {
|
|
35707
|
-
const path =
|
|
36373
|
+
const path = join62(dir, f);
|
|
35708
36374
|
const at = readAgentTask(dir, f);
|
|
35709
36375
|
if (at?.metadata?.["todos_id"]) {
|
|
35710
36376
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -35778,7 +36444,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
35778
36444
|
}
|
|
35779
36445
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
35780
36446
|
const dir = getTaskListDir2(agent, taskListId);
|
|
35781
|
-
if (!
|
|
36447
|
+
if (!existsSync62(dir)) {
|
|
35782
36448
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
35783
36449
|
}
|
|
35784
36450
|
const files = listJsonFiles(dir);
|
|
@@ -35797,7 +36463,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
35797
36463
|
}
|
|
35798
36464
|
for (const f of files) {
|
|
35799
36465
|
try {
|
|
35800
|
-
const filePath =
|
|
36466
|
+
const filePath = join62(dir, f);
|
|
35801
36467
|
const at = readAgentTask(dir, f);
|
|
35802
36468
|
if (!at)
|
|
35803
36469
|
continue;
|
|
@@ -36002,9 +36668,9 @@ function extractTodos(options, db2) {
|
|
|
36002
36668
|
const files = collectFiles(basePath, extensions);
|
|
36003
36669
|
const allComments = [];
|
|
36004
36670
|
for (const file of files) {
|
|
36005
|
-
const fullPath = statSync22(basePath).isFile() ? basePath :
|
|
36671
|
+
const fullPath = statSync22(basePath).isFile() ? basePath : join72(basePath, file);
|
|
36006
36672
|
try {
|
|
36007
|
-
const source =
|
|
36673
|
+
const source = readFileSync43(fullPath, "utf-8");
|
|
36008
36674
|
const relPath = statSync22(basePath).isFile() ? relative(resolve23(basePath, ".."), fullPath) : file;
|
|
36009
36675
|
const comments = extractFromSource(source, relPath, tags);
|
|
36010
36676
|
allComments.push(...comments);
|
|
@@ -36364,7 +37030,29 @@ function checkBudget(agentId, db2) {
|
|
|
36364
37030
|
}
|
|
36365
37031
|
return { allowed: true, current_concurrent: concurrent, max_concurrent: budget.max_concurrent };
|
|
36366
37032
|
}
|
|
36367
|
-
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,
|
|
37033
|
+
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 = {}) => {
|
|
37034
|
+
const allTasks = listTasks({});
|
|
37035
|
+
const filtered = options.since ? allTasks.filter((t) => new Date(t.created_at) >= options.since) : allTasks;
|
|
37036
|
+
const sorted = filtered.slice().sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
37037
|
+
const fetchSet = options.limit ? sorted.slice(0, options.limit * 2) : sorted;
|
|
37038
|
+
const examples = [];
|
|
37039
|
+
for (const task of fetchSet) {
|
|
37040
|
+
examples.push(taskToCreateExample(task));
|
|
37041
|
+
const statusEx = taskToStatusUpdateExample(task);
|
|
37042
|
+
if (statusEx)
|
|
37043
|
+
examples.push(statusEx);
|
|
37044
|
+
}
|
|
37045
|
+
const searchTerms = ["urgent", "fix", "implement", "create", "update", "review"];
|
|
37046
|
+
for (const term of searchTerms) {
|
|
37047
|
+
examples.push(taskToSearchExample(sorted, term));
|
|
37048
|
+
}
|
|
37049
|
+
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
37050
|
+
return {
|
|
37051
|
+
source: "todos",
|
|
37052
|
+
examples: finalExamples,
|
|
37053
|
+
count: finalExamples.length
|
|
37054
|
+
};
|
|
37055
|
+
}, DEFAULT_MODEL3 = "gpt-4o-mini", CONFIG_DIR2, CONFIG_PATH2, RELATIONSHIP_TYPES, EXTRACT_TAGS, DEFAULT_EXTENSIONS, SKIP_DIRS;
|
|
36368
37056
|
var init_dist4 = __esm(() => {
|
|
36369
37057
|
MIGRATIONS2 = [
|
|
36370
37058
|
`
|
|
@@ -37041,6 +37729,8 @@ var init_dist4 = __esm(() => {
|
|
|
37041
37729
|
saturday: 6,
|
|
37042
37730
|
sat: 6
|
|
37043
37731
|
};
|
|
37732
|
+
CONFIG_DIR2 = join45(homedir6(), ".todos");
|
|
37733
|
+
CONFIG_PATH2 = join45(CONFIG_DIR2, "config.json");
|
|
37044
37734
|
RELATIONSHIP_TYPES = [
|
|
37045
37735
|
"related_to",
|
|
37046
37736
|
"conflicts_with",
|
|
@@ -37364,7 +38054,7 @@ ${snap.tree.slice(0, 2000)}`;
|
|
|
37364
38054
|
const response = await client.messages.create({
|
|
37365
38055
|
model,
|
|
37366
38056
|
max_tokens: 512,
|
|
37367
|
-
system:
|
|
38057
|
+
system: SYSTEM_PROMPT3,
|
|
37368
38058
|
messages: [{
|
|
37369
38059
|
role: "user",
|
|
37370
38060
|
content: `Task: ${task}
|
|
@@ -37429,7 +38119,7 @@ What actions should I take next? Return JSON array.`
|
|
|
37429
38119
|
}
|
|
37430
38120
|
return { success: false, result: null, steps_taken: steps.length, steps, cost_estimate: totalTokens / 1000 * 0.00025, error: `Reached max steps (${maxSteps}) without completing task` };
|
|
37431
38121
|
}
|
|
37432
|
-
var
|
|
38122
|
+
var SYSTEM_PROMPT3 = `You are a browser automation agent. Given a task and the current page state, decide which browser actions to take.
|
|
37433
38123
|
|
|
37434
38124
|
Return a JSON array of at most 3 actions to execute next:
|
|
37435
38125
|
[{"tool": "navigate|click|type|scroll|evaluate|done", "args": {...}, "reason": "..."}]
|
|
@@ -37440,7 +38130,7 @@ var init_ai_task = () => {};
|
|
|
37440
38130
|
|
|
37441
38131
|
// src/mcp/meta.ts
|
|
37442
38132
|
function register10(server) {
|
|
37443
|
-
server.tool("
|
|
38133
|
+
server.tool("register_agent", "Register an agent session. Returns agent_id. Auto-triggers a heartbeat.", {
|
|
37444
38134
|
name: exports_external.string(),
|
|
37445
38135
|
description: exports_external.string().optional(),
|
|
37446
38136
|
session_id: exports_external.string().optional().optional(),
|
|
@@ -37454,7 +38144,7 @@ function register10(server) {
|
|
|
37454
38144
|
return err(e);
|
|
37455
38145
|
}
|
|
37456
38146
|
});
|
|
37457
|
-
server.tool("
|
|
38147
|
+
server.tool("heartbeat", "Update last_seen_at to signal agent is active.", { agent_id: exports_external.string() }, async ({ agent_id }) => {
|
|
37458
38148
|
try {
|
|
37459
38149
|
heartbeat2(agent_id);
|
|
37460
38150
|
return json({ ok: true, agent_id, timestamp: new Date().toISOString() });
|
|
@@ -37462,13 +38152,22 @@ function register10(server) {
|
|
|
37462
38152
|
return err(e);
|
|
37463
38153
|
}
|
|
37464
38154
|
});
|
|
37465
|
-
server.tool("
|
|
38155
|
+
server.tool("list_agents", "List all registered agents.", { project_id: exports_external.string().optional() }, async ({ project_id }) => {
|
|
37466
38156
|
try {
|
|
37467
38157
|
return json({ agents: listAgents(project_id) });
|
|
37468
38158
|
} catch (e) {
|
|
37469
38159
|
return err(e);
|
|
37470
38160
|
}
|
|
37471
38161
|
});
|
|
38162
|
+
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 }) => {
|
|
38163
|
+
try {
|
|
38164
|
+
const { updateAgent: update } = await Promise.resolve().then(() => (init_agents2(), exports_agents2));
|
|
38165
|
+
update(agent_id, { project_id: project_id ?? null });
|
|
38166
|
+
return json({ ok: true, agent_id, project_id });
|
|
38167
|
+
} catch (e) {
|
|
38168
|
+
return err(e);
|
|
38169
|
+
}
|
|
38170
|
+
});
|
|
37472
38171
|
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 }) => {
|
|
37473
38172
|
try {
|
|
37474
38173
|
const project = ensureProject(name, path, description);
|
|
@@ -37768,9 +38467,10 @@ function register10(server) {
|
|
|
37768
38467
|
{ tool: "browser_crawl", description: "Crawl a URL recursively" }
|
|
37769
38468
|
],
|
|
37770
38469
|
Agent: [
|
|
37771
|
-
{ tool: "
|
|
37772
|
-
{ tool: "
|
|
37773
|
-
{ tool: "
|
|
38470
|
+
{ tool: "register_agent", description: "Register an agent session" },
|
|
38471
|
+
{ tool: "heartbeat", description: "Update agent last_seen_at" },
|
|
38472
|
+
{ tool: "list_agents", description: "List registered agents" },
|
|
38473
|
+
{ tool: "set_focus", description: "Set active project context" }
|
|
37774
38474
|
],
|
|
37775
38475
|
Project: [
|
|
37776
38476
|
{ tool: "browser_project_create", description: "Create or ensure a project" },
|
|
@@ -37836,7 +38536,7 @@ function register10(server) {
|
|
|
37836
38536
|
});
|
|
37837
38537
|
server.tool("browser_version", "Get the running browser MCP version, tool count, and environment info. Use this to verify which binary is active.", {}, async () => {
|
|
37838
38538
|
try {
|
|
37839
|
-
const { getDataDir:
|
|
38539
|
+
const { getDataDir: getDataDir2 } = await Promise.resolve().then(() => (init_schema(), exports_schema));
|
|
37840
38540
|
const toolCount = Object.keys(server._registeredTools ?? {}).length;
|
|
37841
38541
|
const { readFileSync: readFileSync9 } = await import("fs");
|
|
37842
38542
|
const { join: join16 } = await import("path");
|
|
@@ -37845,7 +38545,7 @@ function register10(server) {
|
|
|
37845
38545
|
version: _pkg.version,
|
|
37846
38546
|
mcp_tools_count: toolCount,
|
|
37847
38547
|
bun_version: Bun.version,
|
|
37848
|
-
data_dir:
|
|
38548
|
+
data_dir: getDataDir2(),
|
|
37849
38549
|
node_env: process.env["NODE_ENV"] ?? "production"
|
|
37850
38550
|
});
|
|
37851
38551
|
} catch (e) {
|
|
@@ -38294,7 +38994,7 @@ var init_snapshots = __esm(() => {
|
|
|
38294
38994
|
// src/server/index.ts
|
|
38295
38995
|
var exports_server = {};
|
|
38296
38996
|
import { join as join17 } from "path";
|
|
38297
|
-
import { existsSync as
|
|
38997
|
+
import { existsSync as existsSync11 } from "fs";
|
|
38298
38998
|
function ok(data, status = 200) {
|
|
38299
38999
|
return new Response(JSON.stringify(data), {
|
|
38300
39000
|
status,
|
|
@@ -38553,14 +39253,14 @@ var init_server = __esm(() => {
|
|
|
38553
39253
|
if (path.match(/^\/api\/gallery\/([^/]+)\/thumbnail$/) && method === "GET") {
|
|
38554
39254
|
const id = path.split("/")[3];
|
|
38555
39255
|
const entry = getEntry(id);
|
|
38556
|
-
if (!entry?.thumbnail_path || !
|
|
39256
|
+
if (!entry?.thumbnail_path || !existsSync11(entry.thumbnail_path))
|
|
38557
39257
|
return notFound("Thumbnail not found");
|
|
38558
39258
|
return new Response(Bun.file(entry.thumbnail_path), { headers: { ...CORS_HEADERS } });
|
|
38559
39259
|
}
|
|
38560
39260
|
if (path.match(/^\/api\/gallery\/([^/]+)\/image$/) && method === "GET") {
|
|
38561
39261
|
const id = path.split("/")[3];
|
|
38562
39262
|
const entry = getEntry(id);
|
|
38563
|
-
if (!entry?.path || !
|
|
39263
|
+
if (!entry?.path || !existsSync11(entry.path))
|
|
38564
39264
|
return notFound("Image not found");
|
|
38565
39265
|
return new Response(Bun.file(entry.path), { headers: { ...CORS_HEADERS } });
|
|
38566
39266
|
}
|
|
@@ -38588,7 +39288,7 @@ var init_server = __esm(() => {
|
|
|
38588
39288
|
if (path.match(/^\/api\/downloads\/([^/]+)\/raw$/) && method === "GET") {
|
|
38589
39289
|
const id = path.split("/")[3];
|
|
38590
39290
|
const file = getDownload(id);
|
|
38591
|
-
if (!file || !
|
|
39291
|
+
if (!file || !existsSync11(file.path))
|
|
38592
39292
|
return notFound("Download not found");
|
|
38593
39293
|
return new Response(Bun.file(file.path), { headers: { ...CORS_HEADERS } });
|
|
38594
39294
|
}
|
|
@@ -38597,9 +39297,9 @@ var init_server = __esm(() => {
|
|
|
38597
39297
|
return ok({ deleted: deleteDownload(id) });
|
|
38598
39298
|
}
|
|
38599
39299
|
const dashboardDist = join17(import.meta.dir, "../../dashboard/dist");
|
|
38600
|
-
if (
|
|
39300
|
+
if (existsSync11(dashboardDist)) {
|
|
38601
39301
|
const filePath = path === "/" ? join17(dashboardDist, "index.html") : join17(dashboardDist, path);
|
|
38602
|
-
if (
|
|
39302
|
+
if (existsSync11(filePath)) {
|
|
38603
39303
|
return new Response(Bun.file(filePath), { headers: CORS_HEADERS });
|
|
38604
39304
|
}
|
|
38605
39305
|
return new Response(Bun.file(join17(dashboardDist, "index.html")), { headers: CORS_HEADERS });
|
|
@@ -39005,8 +39705,8 @@ function register3(program2) {
|
|
|
39005
39705
|
}
|
|
39006
39706
|
});
|
|
39007
39707
|
scriptCmd.command("import <file>").description("Import a script from a JSON file into SQLite").action(async (file) => {
|
|
39008
|
-
const { readFileSync, existsSync:
|
|
39009
|
-
if (!
|
|
39708
|
+
const { readFileSync, existsSync: existsSync4 } = await import("fs");
|
|
39709
|
+
if (!existsSync4(file)) {
|
|
39010
39710
|
console.log(chalk3.red(`File not found: ${file}`));
|
|
39011
39711
|
return;
|
|
39012
39712
|
}
|
|
@@ -39277,8 +39977,8 @@ ${entries.length} entries`));
|
|
|
39277
39977
|
}
|
|
39278
39978
|
const result = await diffImages2(e1.path, e2.path);
|
|
39279
39979
|
if (opts.output) {
|
|
39280
|
-
const { copyFileSync:
|
|
39281
|
-
|
|
39980
|
+
const { copyFileSync: copyFileSync5 } = await import("fs");
|
|
39981
|
+
copyFileSync5(result.diff_path, opts.output);
|
|
39282
39982
|
console.log(chalk4.green(`\u2713 Diff saved: ${opts.output}`));
|
|
39283
39983
|
}
|
|
39284
39984
|
console.log(chalk4.blue(`Changed pixels: ${result.changed_pixels} / ${result.total_pixels} (${result.changed_percent.toFixed(2)}%)`));
|
|
@@ -39294,11 +39994,11 @@ ${entries.length} entries`));
|
|
|
39294
39994
|
});
|
|
39295
39995
|
galleryCmd.command("clean").description("Delete gallery entries with missing files").action(async () => {
|
|
39296
39996
|
const { listEntries: listEntries2, deleteEntry: deleteEntry2 } = await Promise.resolve().then(() => (init_gallery(), exports_gallery));
|
|
39297
|
-
const { existsSync:
|
|
39997
|
+
const { existsSync: existsSync12 } = await import("fs");
|
|
39298
39998
|
const entries = listEntries2({ limit: 9999 });
|
|
39299
39999
|
let removed = 0;
|
|
39300
40000
|
for (const e of entries) {
|
|
39301
|
-
if (!
|
|
40001
|
+
if (!existsSync12(e.path)) {
|
|
39302
40002
|
deleteEntry2(e.id);
|
|
39303
40003
|
removed++;
|
|
39304
40004
|
}
|