my-durable 0.0.35 → 0.0.36

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.
@@ -7,8 +7,8 @@
7
7
  <meta name="referrer" content="no-referrer" />
8
8
  <link rel="icon" type="image/svg+xml" href="/icons/durable-pi.svg" />
9
9
  <title>Durable Pi | Network</title>
10
- <script type="module" crossorigin src="/assets/index-W7_6LpLB.js"></script>
11
- <link rel="stylesheet" crossorigin href="/assets/index-CpTBG0M5.css">
10
+ <script type="module" crossorigin src="/assets/index-DKJspajj.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-BxJGBCW9.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="app"></div>
@@ -2,9 +2,10 @@
2
2
  // something actually looks at it, kept across tab switches, never re-fetched
3
3
  // while fresh. In-flight calls are shared so chip + panel + re-entry of either
4
4
  // cost ONE device round-trip.
5
- import { reactive } from "vue";
5
+ import { reactive, watch } from "vue";
6
6
  import type { GitStatus } from "@sdk/client";
7
7
  import { deviceClient } from "./hub";
8
+ import { network } from "./store";
8
9
 
9
10
  export interface GitEntry {
10
11
  at: number; // last settled fetch (0 = never)
@@ -37,6 +38,32 @@ export async function ensureGitBatch(deviceId: string, paths: string[]) {
37
38
  }
38
39
  const staleMsForBatch = 60_000;
39
40
 
41
+ /** fs-auto-refresh, FE side: the device's tree carries dirty marks for repos
42
+ * its watcher saw change — refresh exactly those entries, still lazy (never
43
+ * an interval), throttled per entry. */
44
+ let wired = false;
45
+ export function wireGitAutoRefresh() {
46
+ if (wired || import.meta.env.SSR) return;
47
+ wired = true;
48
+ watch(() => network.devices.value, (devices) => {
49
+ const now = Date.now();
50
+ for (const d of devices) {
51
+ const marks = ((d as { tree?: { git?: { root: string; at: number }[] } }).tree?.git ?? []).filter(
52
+ (m) => now - m.at < 60_000,
53
+ );
54
+ if (!marks.length) continue;
55
+ for (const key of [...entries.keys()]) {
56
+ const [devId, cwd] = key.split("::");
57
+ if (devId !== d.id || !cwd) continue;
58
+ const e = entries.get(key)!;
59
+ if (!marks.some((m) => cwd === m.root || cwd.startsWith(m.root + "/") || cwd.startsWith(m.root + "\\"))) continue;
60
+ if (e.loading || now - e.at < 4000) continue; // throttle: bursts coalesce
61
+ void ensureGit(devId, cwd, { force: true });
62
+ }
63
+ }
64
+ });
65
+ }
66
+
40
67
  /** Test hook: the store is module-global on purpose (tab switches must not
41
68
  * refetch) — tests reset it so entries never leak between cases. */
42
69
  export function clearGitCache() {
@@ -34,7 +34,7 @@ import {
34
34
  } from "lucide-vue-next";
35
35
  import { deviceId, network, sessionSummary, notify, select } from "../client/store";
36
36
  import { deviceClient } from "../client/hub";
37
- import { ensureGit, gitEntry } from "../client/git-store";
37
+ import { ensureGit, gitEntry, wireGitAutoRefresh } from "../client/git-store";
38
38
  import type { GitStatus } from "@sdk/client";
39
39
 
40
40
  const props = defineProps<{ deviceId?: string; cwd?: string }>();
@@ -201,7 +201,7 @@ async function prCommentNow(n: number, text: string) {
201
201
  }
202
202
 
203
203
  /** Per-turn summaries (zcode taskChangeSummary) under the session chip. */
204
- const turns = ref<{ when: string; files: { path: string; writes: number }[] }[]>([]);
204
+ const turns = ref<{ when: string; files: { path: string; writes: number; a?: number; d?: number }[] }[]>([]);
205
205
  const turnsOpen = ref(false);
206
206
  const loadTurns = async () => {
207
207
  if (!devId.value || !sessionId.value) return;
@@ -233,6 +233,7 @@ const draftLoad = () => {
233
233
  commitMsg.value = localStorage.getItem(draftKey.value) ?? "";
234
234
  };
235
235
  if (!import.meta.env.SSR) {
236
+ wireGitAutoRefresh();
236
237
  void ensureGit(devId.value || "?", cwd.value || "?");
237
238
  draftLoad();
238
239
  }
@@ -961,7 +962,7 @@ const laneX = (lane: number) => lane * 12 + 7;
961
962
  <div v-for="(t, ti) in turns" :key="ti" class="cp-row">
962
963
  <code>t{{ turns.length - ti }}</code>
963
964
  <span class="muted-line">{{ t.when.slice(0, 16).replace("T", " ") }}</span>
964
- <span class="cp-subj">{{ t.files.map((f) => `${f.path}×${f.writes}`).join(", ") || "(no file writes)" }}</span>
965
+ <span class="cp-subj">{{ t.files.map((f) => `${f.path}×${f.writes}${f.a !== undefined || f.d !== undefined ? ` (+${f.a ?? 0} −${f.d ?? 0})` : ""}`).join(", ") || "(no file writes)" }}</span>
965
966
  </div>
966
967
  </div>
967
968
  <p v-if="atCap" class="muted-line cap">showing the first 500 changed files — commit in smaller batches</p>
@@ -194,6 +194,9 @@ export interface DeviceTree {
194
194
  name: string;
195
195
  sessions: SessionSummary[];
196
196
  at: number;
197
+ /** Repos that changed on-device recently (fs watcher) — the cue for
198
+ * connected UIs to refresh their cached git status. */
199
+ git?: { root: string; at: number }[];
197
200
  }
198
201
 
199
202
  export interface AgentConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-durable",
3
- "version": "0.0.35",
3
+ "version": "0.0.36",
4
4
  "description": "Durable Pi \u2014 the durable agent network: hub web UI, device backend daemon, TUI admin and the shared SDK, packaged as one runnable monorepo install",
5
5
  "license": "MIT",
6
6
  "repository": {