my-durable 0.0.34 → 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.
- package/apps/dpi-backend/src/faux.ts +6 -0
- package/apps/dpi-backend/src/git.ts +75 -0
- package/apps/dpi-backend/src/store.ts +77 -17
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/{index-D6aUyqqF.css → index-BxJGBCW9.css} +1 -1
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/{index-DqUQknw8.js → index-DKJspajj.js} +22 -22
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/index.html +2 -2
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/git-store.ts +28 -1
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/GitPanel.vue +7 -4
- package/apps/dpi-sdk/src/api.ts +3 -0
- package/package.json +1 -1
|
@@ -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-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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
|
}
|
|
@@ -535,9 +536,11 @@ async function commit(thenPush = false) {
|
|
|
535
536
|
if (!chosen.length) return notify("check the files to commit — nothing is selected");
|
|
536
537
|
const client = deviceClient(devId.value);
|
|
537
538
|
try {
|
|
539
|
+
// During a merge git refuses path-limited commits ("cannot do a partial
|
|
540
|
+
// commit during a merge") — the changelist is everything staged anyway.
|
|
538
541
|
const r = await client.gitOp(cwd.value, "commit", {
|
|
539
542
|
message: commitMsg.value.trim(),
|
|
540
|
-
files: chosen,
|
|
543
|
+
...(status.value?.merge ? {} : { files: chosen }),
|
|
541
544
|
});
|
|
542
545
|
notify(r.text);
|
|
543
546
|
commitMsg.value = "";
|
|
@@ -959,7 +962,7 @@ const laneX = (lane: number) => lane * 12 + 7;
|
|
|
959
962
|
<div v-for="(t, ti) in turns" :key="ti" class="cp-row">
|
|
960
963
|
<code>t{{ turns.length - ti }}</code>
|
|
961
964
|
<span class="muted-line">{{ t.when.slice(0, 16).replace("T", " ") }}</span>
|
|
962
|
-
<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>
|
|
963
966
|
</div>
|
|
964
967
|
</div>
|
|
965
968
|
<p v-if="atCap" class="muted-line cap">showing the first 500 changed files — commit in smaller batches</p>
|
package/apps/dpi-sdk/src/api.ts
CHANGED
|
@@ -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.
|
|
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": {
|