@dv.nghiem/flowdeck 0.3.2 → 0.3.3

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import { readdirSync as readdirSync3, readFileSync as readFileSync22, existsSync as existsSync24 } from "fs";
3
- import { join as join23, basename } from "path";
2
+ import { readdirSync as readdirSync3, readFileSync as readFileSync22, existsSync as existsSync25 } from "fs";
3
+ import { join as join24, basename } from "path";
4
4
  import { dirname as dirname4 } from "path";
5
5
  import { fileURLToPath as fileURLToPath2 } from "url";
6
6
 
@@ -1731,6 +1731,76 @@ var memorySearchTool = tool16({
1731
1731
  }
1732
1732
  });
1733
1733
 
1734
+ // src/tools/memory-status.ts
1735
+ import { tool as tool17 } from "@opencode-ai/plugin";
1736
+ import { Database as Database2 } from "bun:sqlite";
1737
+ import { existsSync as existsSync14 } from "fs";
1738
+ import { join as join14 } from "path";
1739
+ import { homedir as homedir2 } from "os";
1740
+ var DB_PATH2 = join14(homedir2(), ".flowdeck-memory", "memory.db");
1741
+ var memoryStatusTool = tool17({
1742
+ description: "Check FlowDeck memory database status, statistics, and recent sessions",
1743
+ args: {},
1744
+ async execute(_args, _context) {
1745
+ try {
1746
+ const exists = existsSync14(DB_PATH2);
1747
+ const result = {
1748
+ database_exists: exists,
1749
+ path: DB_PATH2,
1750
+ status: exists ? "ACTIVE" : "NOT_INITIALIZED",
1751
+ statistics: null
1752
+ };
1753
+ if (exists) {
1754
+ try {
1755
+ const db2 = new Database2(DB_PATH2);
1756
+ const sessions = db2.prepare("SELECT COUNT(*) as count FROM sessions").get();
1757
+ const observations = db2.prepare("SELECT COUNT(*) as count FROM observations").get();
1758
+ const summaries = db2.prepare("SELECT COUNT(*) as count FROM summaries").get();
1759
+ const recentSessions = db2.prepare(`
1760
+ SELECT
1761
+ id,
1762
+ content_session_id,
1763
+ project,
1764
+ directory,
1765
+ created_at,
1766
+ last_active_at,
1767
+ prompt_count
1768
+ FROM sessions
1769
+ ORDER BY last_active_at DESC
1770
+ LIMIT 5
1771
+ `).all();
1772
+ result.statistics = {
1773
+ sessions: sessions.count,
1774
+ observations: observations.count,
1775
+ summaries: summaries.count,
1776
+ recent_sessions: recentSessions.map((s) => {
1777
+ const obsCount = db2.prepare("SELECT COUNT(*) as count FROM observations WHERE session_id = ?").get(s.id);
1778
+ return {
1779
+ project: s.project,
1780
+ directory: s.directory,
1781
+ observations_in_session: obsCount.count,
1782
+ last_active: s.last_active_at,
1783
+ prompt_count: s.prompt_count
1784
+ };
1785
+ })
1786
+ };
1787
+ db2.close();
1788
+ } catch (err) {
1789
+ result.status = "ERROR";
1790
+ result.statistics = { error: String(err) };
1791
+ }
1792
+ }
1793
+ return JSON.stringify(result, null, 2);
1794
+ } catch (err) {
1795
+ return JSON.stringify({
1796
+ status: "ERROR",
1797
+ error: String(err),
1798
+ path: DB_PATH2
1799
+ }, null, 2);
1800
+ }
1801
+ }
1802
+ });
1803
+
1734
1804
  // src/hooks/memory-hook.ts
1735
1805
  var MAX_TOOL_RESPONSE = 1e4;
1736
1806
  var MAX_PROMPT_LENGTH = 2000;
@@ -1830,13 +1900,13 @@ var memoryHook = {
1830
1900
  };
1831
1901
 
1832
1902
  // src/hooks/guard-rails.ts
1833
- import { existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
1834
- import { join as join14 } from "path";
1903
+ import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
1904
+ import { join as join15 } from "path";
1835
1905
  var PLANNING_DIR2 = ".planning";
1836
1906
  var CONFIG_FILE = "config.json";
1837
1907
  var STATE_FILE2 = "STATE.md";
1838
1908
  function resolveExecutionMode(configPath, trustScore, volatility) {
1839
- if (existsSync14(configPath)) {
1909
+ if (existsSync15(configPath)) {
1840
1910
  try {
1841
1911
  const config = JSON.parse(readFileSync13(configPath, "utf-8"));
1842
1912
  if (config.execution_mode === "review-only")
@@ -1892,22 +1962,22 @@ async function guardRailsHook(ctx, input, _output) {
1892
1962
  if (!ENABLED)
1893
1963
  return;
1894
1964
  const dir = ctx.directory;
1895
- const planningDirPath = join14(dir, PLANNING_DIR2);
1965
+ const planningDirPath = join15(dir, PLANNING_DIR2);
1896
1966
  const codebaseDirectory = codebaseDir(dir);
1897
- const configPath = join14(planningDirPath, CONFIG_FILE);
1898
- const statePath2 = join14(planningDirPath, STATE_FILE2);
1967
+ const configPath = join15(planningDirPath, CONFIG_FILE);
1968
+ const statePath2 = join15(planningDirPath, STATE_FILE2);
1899
1969
  const workspaceRoot = findWorkspaceRoot(dir);
1900
1970
  if (workspaceRoot && dir !== workspaceRoot) {
1901
1971
  const config = getWorkspaceConfig(dir);
1902
- if (config && config.workspace_mode === "shared" && !existsSync14(planningDirPath)) {
1972
+ if (config && config.workspace_mode === "shared" && !existsSync15(planningDirPath)) {
1903
1973
  const msg = `No .planning/ in this sub-repo. Switch to workspace root: cd ${workspaceRoot}`;
1904
1974
  throw new Error(`[flowdeck] BLOCK: ${msg}`);
1905
1975
  }
1906
1976
  }
1907
1977
  if (input.tool === "write" || input.tool === "edit") {
1908
- if (!existsSync14(planningDirPath))
1978
+ if (!existsSync15(planningDirPath))
1909
1979
  return;
1910
- if (!existsSync14(codebaseDirectory)) {
1980
+ if (!existsSync15(codebaseDirectory)) {
1911
1981
  throw new Error(`[flowdeck] WARNING: .codebase/ not found. Run /map-codebase to map the codebase.`);
1912
1982
  }
1913
1983
  const execMode = resolveExecutionMode(configPath, null);
@@ -1940,7 +2010,7 @@ async function guardRailsHook(ctx, input, _output) {
1940
2010
  }
1941
2011
  }
1942
2012
  function effectiveSeverity(configPath, statePath2) {
1943
- if (existsSync14(configPath)) {
2013
+ if (existsSync15(configPath)) {
1944
2014
  try {
1945
2015
  const configContent = readFileSync13(configPath, "utf-8");
1946
2016
  const config = JSON.parse(configContent);
@@ -1958,7 +2028,7 @@ function getEffectiveSeverity(configPath, statePath2) {
1958
2028
  return effectiveSeverity(configPath, statePath2);
1959
2029
  }
1960
2030
  function getPlanConfirmed(statePath2) {
1961
- if (!existsSync14(statePath2))
2031
+ if (!existsSync15(statePath2))
1962
2032
  return false;
1963
2033
  try {
1964
2034
  const content = readFileSync13(statePath2, "utf-8");
@@ -1969,32 +2039,32 @@ function getPlanConfirmed(statePath2) {
1969
2039
  }
1970
2040
  }
1971
2041
  function getWarningMessage(planningDir2) {
1972
- if (!existsSync14(join14(planningDir2, STATE_FILE2))) {
2042
+ if (!existsSync15(join15(planningDir2, STATE_FILE2))) {
1973
2043
  return "No .planning/ found. Run /new-project first.";
1974
2044
  }
1975
2045
  return "Plan not confirmed. Run /plan and confirm to enable execution.";
1976
2046
  }
1977
2047
  function getBlockMessage(planningDir2) {
1978
- if (!existsSync14(join14(planningDir2, STATE_FILE2))) {
2048
+ if (!existsSync15(join15(planningDir2, STATE_FILE2))) {
1979
2049
  return "No .planning/ found. Run /new-project first.";
1980
2050
  }
1981
2051
  return "Plan not confirmed. Run /plan and confirm to enable execution.";
1982
2052
  }
1983
2053
 
1984
2054
  // src/hooks/tool-guard.ts
1985
- import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
1986
- import { join as join15 } from "path";
2055
+ import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
2056
+ import { join as join16 } from "path";
1987
2057
  var IS_ENABLED = () => process.env.FLOWDECK_TOOL_GUARD_ENABLED === "on";
1988
2058
  var BLOCKED_PATTERNS = {
1989
2059
  read: [".env", ".pem", ".key", ".secret"],
1990
2060
  write: ["node_modules"],
1991
2061
  bash: ["rm -rf"]
1992
2062
  };
1993
- function isBlocked(tool17, args) {
1994
- const patterns = BLOCKED_PATTERNS[tool17];
2063
+ function isBlocked(tool18, args) {
2064
+ const patterns = BLOCKED_PATTERNS[tool18];
1995
2065
  if (!patterns)
1996
2066
  return null;
1997
- if (tool17 === "bash") {
2067
+ if (tool18 === "bash") {
1998
2068
  const cmd = args.command;
1999
2069
  if (!cmd)
2000
2070
  return null;
@@ -2005,7 +2075,7 @@ function isBlocked(tool17, args) {
2005
2075
  }
2006
2076
  return null;
2007
2077
  }
2008
- if (tool17 === "read") {
2078
+ if (tool18 === "read") {
2009
2079
  const filePath = args.filePath;
2010
2080
  if (!filePath)
2011
2081
  return null;
@@ -2016,7 +2086,7 @@ function isBlocked(tool17, args) {
2016
2086
  }
2017
2087
  return null;
2018
2088
  }
2019
- if (tool17 === "write") {
2089
+ if (tool18 === "write") {
2020
2090
  const filePath = args.filePath;
2021
2091
  if (!filePath)
2022
2092
  return null;
@@ -2030,8 +2100,8 @@ function isBlocked(tool17, args) {
2030
2100
  return null;
2031
2101
  }
2032
2102
  function checkArchConstraint(directory, filePath) {
2033
- const constraintsPath = join15(codebaseDir(directory), "CONSTRAINTS.md");
2034
- if (!existsSync15(constraintsPath))
2103
+ const constraintsPath = join16(codebaseDir(directory), "CONSTRAINTS.md");
2104
+ if (!existsSync16(constraintsPath))
2035
2105
  return null;
2036
2106
  try {
2037
2107
  const content = readFileSync14(constraintsPath, "utf-8");
@@ -2081,18 +2151,18 @@ async function toolGuardHook(ctx, input, output) {
2081
2151
  }
2082
2152
 
2083
2153
  // src/hooks/session-start.ts
2084
- import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
2154
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
2085
2155
  async function sessionStartHook(ctx) {
2086
2156
  const planningDir2 = ctx.directory + "/.planning";
2087
2157
  const codebaseDirectory = codebaseDir(ctx.directory);
2088
2158
  const workspaceRoot = findWorkspaceRoot(ctx.directory);
2089
2159
  const config = workspaceRoot ? getWorkspaceConfig(ctx.directory) : null;
2090
- if (!existsSync16(planningDir2)) {
2160
+ if (!existsSync17(planningDir2)) {
2091
2161
  return {
2092
2162
  flowdeck_phase: null,
2093
2163
  flowdeck_status: "no_plan",
2094
2164
  flowdeck_warning: "Run /new-project or /map-codebase to initialize.",
2095
- flowdeck_has_codebase: existsSync16(codebaseDirectory),
2165
+ flowdeck_has_codebase: existsSync17(codebaseDirectory),
2096
2166
  ...workspaceRoot && config?.sub_repos ? {
2097
2167
  flowdeck_workspace_root: workspaceRoot,
2098
2168
  flowdeck_sub_repos: config.sub_repos,
@@ -2111,7 +2181,7 @@ async function sessionStartHook(ctx) {
2111
2181
  flowdeck_status: currentPhase["status"] ?? null,
2112
2182
  flowdeck_steps_pending: currentPhase["steps_pending"] ?? null,
2113
2183
  flowdeck_last_action: currentPhase["last_action"] ?? null,
2114
- flowdeck_has_codebase: existsSync16(codebaseDirectory)
2184
+ flowdeck_has_codebase: existsSync17(codebaseDirectory)
2115
2185
  };
2116
2186
  if (workspaceRoot && config?.sub_repos && config.sub_repos.length > 0) {
2117
2187
  result.flowdeck_workspace_root = workspaceRoot;
@@ -2126,7 +2196,7 @@ async function sessionStartHook(ctx) {
2126
2196
  flowdeck_phase: null,
2127
2197
  flowdeck_status: "error",
2128
2198
  flowdeck_warning: "State file unreadable. Continuing without flowdeck context.",
2129
- flowdeck_has_codebase: existsSync16(codebaseDirectory)
2199
+ flowdeck_has_codebase: existsSync17(codebaseDirectory)
2130
2200
  };
2131
2201
  if (workspaceRoot && config?.sub_repos && config.sub_repos.length > 0) {
2132
2202
  result.flowdeck_workspace_root = workspaceRoot;
@@ -2187,13 +2257,13 @@ function tryTerminalBell() {
2187
2257
  function notifySessionIdle() {
2188
2258
  notify("FlowDeck Task Completed", "Agent is idle and waiting for your next instruction", "info");
2189
2259
  }
2190
- function notifyPermissionNeeded(tool17) {
2191
- notify("FlowDeck Permission Required", `Agent needs approval to use tool: ${tool17}`, "critical");
2260
+ function notifyPermissionNeeded(tool18) {
2261
+ notify("FlowDeck Permission Required", `Agent needs approval to use tool: ${tool18}`, "critical");
2192
2262
  }
2193
2263
 
2194
2264
  // src/hooks/patch-trust.ts
2195
- import { existsSync as existsSync17, readFileSync as readFileSync16 } from "fs";
2196
- import { join as join16 } from "path";
2265
+ import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
2266
+ import { join as join17 } from "path";
2197
2267
  var HIGH_RISK_KEYWORDS = [
2198
2268
  "password",
2199
2269
  "secret",
@@ -2215,8 +2285,8 @@ var HIGH_RISK_KEYWORDS = [
2215
2285
  "privilege"
2216
2286
  ];
2217
2287
  function loadVolatility(directory) {
2218
- const p = join16(codebaseDir(directory), "VOLATILITY.json");
2219
- if (!existsSync17(p))
2288
+ const p = join17(codebaseDir(directory), "VOLATILITY.json");
2289
+ if (!existsSync18(p))
2220
2290
  return {};
2221
2291
  try {
2222
2292
  const data = JSON.parse(readFileSync16(p, "utf-8"));
@@ -2229,8 +2299,8 @@ function loadVolatility(directory) {
2229
2299
  }
2230
2300
  }
2231
2301
  function loadFailedPaths(directory) {
2232
- const p = join16(codebaseDir(directory), "FAILURES.json");
2233
- if (!existsSync17(p))
2302
+ const p = join17(codebaseDir(directory), "FAILURES.json");
2303
+ if (!existsSync18(p))
2234
2304
  return [];
2235
2305
  try {
2236
2306
  const data = JSON.parse(readFileSync16(p, "utf-8"));
@@ -2298,8 +2368,8 @@ async function patchTrustHook(ctx, input, output) {
2298
2368
  }
2299
2369
 
2300
2370
  // src/hooks/decision-trace-hook.ts
2301
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, appendFileSync as appendFileSync2 } from "fs";
2302
- import { join as join17 } from "path";
2371
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, appendFileSync as appendFileSync2 } from "fs";
2372
+ import { join as join18 } from "path";
2303
2373
  async function decisionTraceHook(ctx, input, output) {
2304
2374
  if (input.tool !== "write" && input.tool !== "edit")
2305
2375
  return;
@@ -2308,7 +2378,7 @@ async function decisionTraceHook(ctx, input, output) {
2308
2378
  return;
2309
2379
  const base = codebaseDir(ctx.directory);
2310
2380
  try {
2311
- if (!existsSync18(base))
2381
+ if (!existsSync19(base))
2312
2382
  mkdirSync9(base, { recursive: true });
2313
2383
  const entry = {
2314
2384
  timestamp: new Date().toISOString(),
@@ -2321,23 +2391,23 @@ async function decisionTraceHook(ctx, input, output) {
2321
2391
  risk_level: "unknown",
2322
2392
  auto_recorded: true
2323
2393
  };
2324
- appendFileSync2(join17(base, "DECISIONS.jsonl"), JSON.stringify(entry) + `
2394
+ appendFileSync2(join18(base, "DECISIONS.jsonl"), JSON.stringify(entry) + `
2325
2395
  `, "utf-8");
2326
2396
  } catch {}
2327
2397
  }
2328
2398
 
2329
2399
  // src/services/telemetry.ts
2330
- import { existsSync as existsSync19, readFileSync as readFileSync17, appendFileSync as appendFileSync3, mkdirSync as mkdirSync10 } from "fs";
2331
- import { join as join18 } from "path";
2400
+ import { existsSync as existsSync20, readFileSync as readFileSync17, appendFileSync as appendFileSync3, mkdirSync as mkdirSync10 } from "fs";
2401
+ import { join as join19 } from "path";
2332
2402
  import { randomUUID } from "crypto";
2333
2403
  function telemetryPath(dir) {
2334
- return join18(codebaseDir(dir), "TELEMETRY.jsonl");
2404
+ return join19(codebaseDir(dir), "TELEMETRY.jsonl");
2335
2405
  }
2336
2406
  function appendEvent(dir, partial) {
2337
2407
  if (process.env.TELEMETRY_ENABLED !== "true")
2338
2408
  return null;
2339
2409
  const cd = codebaseDir(dir);
2340
- if (!existsSync19(cd))
2410
+ if (!existsSync20(cd))
2341
2411
  mkdirSync10(cd, { recursive: true });
2342
2412
  const event = {
2343
2413
  id: randomUUID(),
@@ -2352,31 +2422,31 @@ function appendEvent(dir, partial) {
2352
2422
  // src/hooks/telemetry-hook.ts
2353
2423
  async function telemetryHook(context, toolInput, output) {
2354
2424
  const dir = context.directory ?? process.cwd();
2355
- const tool17 = toolInput.name ?? toolInput.tool ?? "unknown";
2425
+ const tool18 = toolInput.name ?? toolInput.tool ?? "unknown";
2356
2426
  appendEvent(dir, {
2357
2427
  session_id: process.env.OPENCODE_SESSION_ID ?? "session-0",
2358
2428
  run_id: process.env.OPENCODE_RUN_ID ?? "run-0",
2359
2429
  event: "tool.call",
2360
- tool: tool17,
2430
+ tool: tool18,
2361
2431
  status: "ok",
2362
2432
  meta: { parameters: output.args ?? {} }
2363
2433
  });
2364
2434
  }
2365
2435
  async function telemetryAfterHook(context, toolInput, _output) {
2366
2436
  const dir = context.directory ?? process.cwd();
2367
- const tool17 = toolInput.name ?? toolInput.tool ?? "unknown";
2437
+ const tool18 = toolInput.name ?? toolInput.tool ?? "unknown";
2368
2438
  appendEvent(dir, {
2369
2439
  session_id: process.env.OPENCODE_SESSION_ID ?? "session-0",
2370
2440
  run_id: process.env.OPENCODE_RUN_ID ?? "run-0",
2371
2441
  event: "tool.complete",
2372
- tool: tool17,
2442
+ tool: tool18,
2373
2443
  status: "ok"
2374
2444
  });
2375
2445
  }
2376
2446
 
2377
2447
  // src/services/approval-manager.ts
2378
- import { existsSync as existsSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync13, mkdirSync as mkdirSync11 } from "fs";
2379
- import { join as join19 } from "path";
2448
+ import { existsSync as existsSync21, readFileSync as readFileSync18, writeFileSync as writeFileSync13, mkdirSync as mkdirSync11 } from "fs";
2449
+ import { join as join20 } from "path";
2380
2450
  var APPROVAL_TTL_MS = 30 * 60 * 1000;
2381
2451
  var SENSITIVE_PATTERNS = [
2382
2452
  /auth/i,
@@ -2413,11 +2483,11 @@ function isSensitivePath(filePath) {
2413
2483
  return SENSITIVE_PATTERNS.some((p) => p.test(filePath));
2414
2484
  }
2415
2485
  function approvalsPath(dir) {
2416
- return join19(codebaseDir(dir), "APPROVALS.json");
2486
+ return join20(codebaseDir(dir), "APPROVALS.json");
2417
2487
  }
2418
2488
  function loadStore(dir) {
2419
2489
  const p = approvalsPath(dir);
2420
- if (!existsSync20(p))
2490
+ if (!existsSync21(p))
2421
2491
  return { requests: [] };
2422
2492
  try {
2423
2493
  return JSON.parse(readFileSync18(p, "utf-8"));
@@ -2438,8 +2508,8 @@ async function approvalHook(context, toolInput, output) {
2438
2508
  if (!ENABLED2)
2439
2509
  return;
2440
2510
  const dir = context.directory ?? process.cwd();
2441
- const tool17 = toolInput.name ?? toolInput.tool ?? "";
2442
- if (!WRITE_TOOLS.has(tool17))
2511
+ const tool18 = toolInput.name ?? toolInput.tool ?? "";
2512
+ if (!WRITE_TOOLS.has(tool18))
2443
2513
  return;
2444
2514
  const args = output.args ?? {};
2445
2515
  const filePath = String(args.path ?? args.file_path ?? args.filename ?? "");
@@ -2454,7 +2524,7 @@ async function approvalHook(context, toolInput, output) {
2454
2524
  session_id: process.env.OPENCODE_SESSION_ID ?? "session-0",
2455
2525
  run_id: process.env.OPENCODE_RUN_ID ?? "run-0",
2456
2526
  event: "approval.request",
2457
- tool: tool17,
2527
+ tool: tool18,
2458
2528
  status: "blocked",
2459
2529
  files: [filePath],
2460
2530
  meta: { trigger: "sensitive_file", file: filePath }
@@ -2515,8 +2585,8 @@ function createContextWindowMonitorHook() {
2515
2585
  }
2516
2586
 
2517
2587
  // src/hooks/shell-env-hook.ts
2518
- import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
2519
- import { join as join20 } from "path";
2588
+ import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
2589
+ import { join as join21 } from "path";
2520
2590
  import { createRequire } from "module";
2521
2591
  var _version;
2522
2592
  function getVersion() {
@@ -2552,7 +2622,7 @@ var MARKER_TO_LANG = {
2552
2622
  };
2553
2623
  function detectPackageManager(root) {
2554
2624
  for (const [lockfile, pm] of Object.entries(LOCKFILE_TO_PM)) {
2555
- if (existsSync21(join20(root, lockfile)))
2625
+ if (existsSync22(join21(root, lockfile)))
2556
2626
  return pm;
2557
2627
  }
2558
2628
  return;
@@ -2561,7 +2631,7 @@ function detectLanguages(root) {
2561
2631
  const langs = [];
2562
2632
  const seen = new Set;
2563
2633
  for (const [marker, lang] of Object.entries(MARKER_TO_LANG)) {
2564
- if (!seen.has(lang) && existsSync21(join20(root, marker))) {
2634
+ if (!seen.has(lang) && existsSync22(join21(root, marker))) {
2565
2635
  langs.push(lang);
2566
2636
  seen.add(lang);
2567
2637
  }
@@ -2569,8 +2639,8 @@ function detectLanguages(root) {
2569
2639
  return langs;
2570
2640
  }
2571
2641
  function readCurrentPhase(root) {
2572
- const statePath2 = join20(root, ".planning", "STATE.md");
2573
- if (!existsSync21(statePath2))
2642
+ const statePath2 = join21(root, ".planning", "STATE.md");
2643
+ if (!existsSync22(statePath2))
2574
2644
  return;
2575
2645
  try {
2576
2646
  const content = readFileSync19(statePath2, "utf-8");
@@ -2673,8 +2743,8 @@ function createSessionIdleHook(client, tracker) {
2673
2743
  }
2674
2744
 
2675
2745
  // src/hooks/compaction-hook.ts
2676
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
2677
- import { join as join21 } from "path";
2746
+ import { existsSync as existsSync23, readFileSync as readFileSync20 } from "fs";
2747
+ import { join as join22 } from "path";
2678
2748
  var STRUCTURED_SUMMARY_PROMPT = `
2679
2749
  When summarizing this session, you MUST include the following sections:
2680
2750
 
@@ -2713,8 +2783,8 @@ For each: agent name, status, description, session_id.
2713
2783
  **RESUME, DON'T RESTART.** Use session_id to continue existing sessions.
2714
2784
  `;
2715
2785
  function readPlanningState2(directory) {
2716
- const statePath2 = join21(directory, ".planning", "STATE.md");
2717
- if (!existsSync22(statePath2))
2786
+ const statePath2 = join22(directory, ".planning", "STATE.md");
2787
+ if (!existsSync23(statePath2))
2718
2788
  return null;
2719
2789
  try {
2720
2790
  const content = readFileSync20(statePath2, "utf-8");
@@ -5810,21 +5880,21 @@ function getAgentConfigs(agentModels) {
5810
5880
  }
5811
5881
 
5812
5882
  // src/config/loader.ts
5813
- import { existsSync as existsSync23, readFileSync as readFileSync21 } from "fs";
5814
- import { join as join22 } from "path";
5815
- import { homedir as homedir2 } from "os";
5883
+ import { existsSync as existsSync24, readFileSync as readFileSync21 } from "fs";
5884
+ import { join as join23 } from "path";
5885
+ import { homedir as homedir3 } from "os";
5816
5886
  var CONFIG_FILENAME = "flowdeck.json";
5817
5887
  function getGlobalConfigDir() {
5818
- return process.env.OPENCODE_CONFIG_DIR || (process.env.XDG_CONFIG_HOME ? join22(process.env.XDG_CONFIG_HOME, "opencode") : join22(homedir2(), ".config", "opencode"));
5888
+ return process.env.OPENCODE_CONFIG_DIR || (process.env.XDG_CONFIG_HOME ? join23(process.env.XDG_CONFIG_HOME, "opencode") : join23(homedir3(), ".config", "opencode"));
5819
5889
  }
5820
5890
  function loadFlowDeckConfig(directory) {
5821
5891
  const candidates = [];
5822
5892
  if (directory) {
5823
- candidates.push(join22(directory, ".opencode", CONFIG_FILENAME));
5893
+ candidates.push(join23(directory, ".opencode", CONFIG_FILENAME));
5824
5894
  }
5825
- candidates.push(join22(getGlobalConfigDir(), CONFIG_FILENAME));
5895
+ candidates.push(join23(getGlobalConfigDir(), CONFIG_FILENAME));
5826
5896
  for (const configPath of candidates) {
5827
- if (existsSync23(configPath)) {
5897
+ if (existsSync24(configPath)) {
5828
5898
  try {
5829
5899
  const content = readFileSync21(configPath, "utf-8");
5830
5900
  return JSON.parse(content);
@@ -5838,13 +5908,13 @@ function loadFlowDeckConfig(directory) {
5838
5908
  // src/index.ts
5839
5909
  function loadRulePaths() {
5840
5910
  const __dir = dirname4(fileURLToPath2(import.meta.url));
5841
- const rulesDir = join23(__dir, "..", "src", "rules");
5842
- if (!existsSync24(rulesDir))
5911
+ const rulesDir = join24(__dir, "..", "src", "rules");
5912
+ if (!existsSync25(rulesDir))
5843
5913
  return [];
5844
5914
  const paths = [];
5845
5915
  function walk(dir) {
5846
5916
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
5847
- const full = join23(dir, entry.name);
5917
+ const full = join24(dir, entry.name);
5848
5918
  if (entry.isDirectory()) {
5849
5919
  walk(full);
5850
5920
  } else if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== "README.md") {
@@ -5857,8 +5927,8 @@ function loadRulePaths() {
5857
5927
  }
5858
5928
  function loadCommands() {
5859
5929
  const __dir = dirname4(fileURLToPath2(import.meta.url));
5860
- const commandsDir = join23(__dir, "..", "src", "commands");
5861
- if (!existsSync24(commandsDir))
5930
+ const commandsDir = join24(__dir, "..", "src", "commands");
5931
+ if (!existsSync25(commandsDir))
5862
5932
  return {};
5863
5933
  const commands = {};
5864
5934
  try {
@@ -5866,7 +5936,7 @@ function loadCommands() {
5866
5936
  if (!file.endsWith(".md"))
5867
5937
  continue;
5868
5938
  const name = basename(file, ".md");
5869
- const raw = readFileSync22(join23(commandsDir, file), "utf-8");
5939
+ const raw = readFileSync22(join24(commandsDir, file), "utf-8");
5870
5940
  let description;
5871
5941
  let template = raw;
5872
5942
  const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
@@ -5943,8 +6013,8 @@ var plugin = async (input, _options) => {
5943
6013
  }
5944
6014
  }
5945
6015
  }
5946
- const skillsDir = join23(dirname4(fileURLToPath2(import.meta.url)), "..", "src", "skills");
5947
- if (existsSync24(skillsDir)) {
6016
+ const skillsDir = join24(dirname4(fileURLToPath2(import.meta.url)), "..", "src", "skills");
6017
+ if (existsSync25(skillsDir)) {
5948
6018
  const cfgAny = cfg;
5949
6019
  if (!cfgAny.skills || typeof cfgAny.skills !== "object") {
5950
6020
  cfgAny.skills = { paths: [] };
@@ -5985,7 +6055,8 @@ var plugin = async (input, _options) => {
5985
6055
  "context-generator": contextGeneratorTool,
5986
6056
  "create-skill": createSkillTool,
5987
6057
  reflect: reflectTool,
5988
- "memory-search": memorySearchTool
6058
+ "memory-search": memorySearchTool,
6059
+ "memory-status": memoryStatusTool
5989
6060
  },
5990
6061
  "shell.env": shellEnvHook,
5991
6062
  "todo.updated": todoHook,
@@ -5997,30 +6068,34 @@ var plugin = async (input, _options) => {
5997
6068
  },
5998
6069
  event: async ({ event }) => {
5999
6070
  const type = event?.type ?? "";
6000
- if (type === "session.created" || type === "session.started") {
6001
- const sessionId = event?.sessionID ?? event?.sessionId ?? "";
6002
- if (sessionId) {
6003
- memoryHook.onSessionCreated(directory, sessionId, event?.prompt);
6004
- }
6005
- await sessionStartHook({ directory });
6006
- } else if (type === "message.updated" && event?.event) {
6007
- const msgEvent = event.event;
6008
- const sessionId = msgEvent?.sessionID ?? msgEvent?.sessionId ?? "";
6009
- if (sessionId) {
6010
- memoryHook.onMessageUpdated(sessionId, msgEvent.role, msgEvent.content, directory);
6011
- }
6012
- } else if (type === "session.compacted" && event?.event) {
6013
- const compactEvent = event.event;
6014
- const sessionId = compactEvent?.sessionID ?? compactEvent?.sessionId ?? "";
6015
- if (sessionId) {
6016
- memoryHook.onSessionCompact(sessionId, compactEvent.summary ?? "");
6017
- }
6018
- } else if (type === "session.deleted" && event?.event) {
6019
- const delEvent = event.event;
6020
- const sessionId = delEvent?.sessionID ?? delEvent?.sessionId ?? "";
6021
- if (sessionId) {
6022
- memoryHook.clearSession(sessionId);
6071
+ try {
6072
+ if (type === "session.created" || type === "session.started") {
6073
+ const sessionId = event?.sessionID ?? event?.sessionId ?? "";
6074
+ if (sessionId) {
6075
+ memoryHook.onSessionCreated(directory, sessionId, event?.prompt);
6076
+ }
6077
+ await sessionStartHook({ directory });
6078
+ } else if (type === "message.updated") {
6079
+ const msgEvent = event?.event ?? event;
6080
+ const sessionId = msgEvent?.sessionID ?? msgEvent?.sessionId ?? "";
6081
+ if (sessionId) {
6082
+ memoryHook.onMessageUpdated(sessionId, msgEvent.role, msgEvent.content, directory);
6083
+ }
6084
+ } else if (type === "session.compacted") {
6085
+ const compactEvent = event?.event ?? event;
6086
+ const sessionId = compactEvent?.sessionID ?? compactEvent?.sessionId ?? "";
6087
+ if (sessionId) {
6088
+ memoryHook.onSessionCompact(sessionId, compactEvent.summary ?? "");
6089
+ }
6090
+ } else if (type === "session.deleted") {
6091
+ const delEvent = event?.event ?? event;
6092
+ const sessionId = delEvent?.sessionID ?? delEvent?.sessionId ?? "";
6093
+ if (sessionId) {
6094
+ memoryHook.clearSession(sessionId);
6095
+ }
6023
6096
  }
6097
+ } catch (err) {
6098
+ console.error("[FlowDeck Memory] Event handler error:", err);
6024
6099
  }
6025
6100
  await contextMonitor.event({ event });
6026
6101
  orchestratorGuard.onEvent(event);
@@ -6050,9 +6125,13 @@ var plugin = async (input, _options) => {
6050
6125
  },
6051
6126
  "tool.execute.after": async (toolInput, toolOutput) => {
6052
6127
  await telemetryAfterHook({ directory }, toolInput, toolOutput);
6053
- const sessionId = toolInput?.sessionID ?? toolInput?.sessionId ?? "";
6054
- if (sessionId && toolInput?.tool) {
6055
- memoryHook.onToolExecuted(sessionId, toolInput.tool, toolInput, toolOutput?.output ?? null, directory);
6128
+ try {
6129
+ const sessionId = toolInput?.sessionID ?? toolInput?.sessionId ?? "";
6130
+ if (sessionId && toolInput?.tool) {
6131
+ memoryHook.onToolExecuted(sessionId, toolInput.tool, toolInput, toolOutput?.output ?? null, directory);
6132
+ }
6133
+ } catch (err) {
6134
+ console.error("[FlowDeck Memory] Tool execution error:", err);
6056
6135
  }
6057
6136
  await contextMonitor["tool.execute.after"](toolInput, toolOutput);
6058
6137
  }
@@ -0,0 +1,3 @@
1
+ import { type ToolDefinition } from "@opencode-ai/plugin";
2
+ export declare const memoryStatusTool: ToolDefinition;
3
+ //# sourceMappingURL=memory-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-status.d.ts","sourceRoot":"","sources":["../../src/tools/memory-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAQ/D,eAAO,MAAM,gBAAgB,EAAE,cAoE7B,CAAA"}