zigmini 0.8.0-beta.6 → 0.9.0-beta.1
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/README.ko.md +90 -19
- package/README.md +91 -19
- package/assets/agent/gateway-request-rules.md +3 -0
- package/assets/agent/gateway-rules.md +6 -0
- package/assets/android/zigmini.apk +0 -0
- package/assets/android/zigmini.apk.json +3 -3
- package/assets/build.json +1 -1
- package/docs/manual.ko.md +69 -1
- package/docs/manual.md +67 -1
- package/host/omo-bridge/task-control.ts +4 -0
- package/host/omo-check/patches/omo-5.1.35-compaction-idle.patch +77 -0
- package/host/omo-check/patches/omo-5.1.35-compaction-intent.patch +212 -0
- package/host/omo-check/patches/omo-5.1.35-compaction-model.patch +299 -0
- package/host/omo-check/patches/omo-5.1.35-compaction-preservation.patch +1063 -0
- package/host/omo-check/patches/omo-5.1.35-compaction-refusal.patch +83 -0
- package/host/omo-check/patches/omo-5.1.35-gateway-port.manifest.json +169 -7
- package/host/omo-check/patches/omo-5.1.35-request-rules.patch +109 -0
- package/host/omo-check/patches/omo-5.1.35-turn-stats.patch +76 -0
- package/host/omo-check/patches/omo-5.1.44-compaction-port.patch +2630 -0
- package/host/omo-check/patches/omo-5.1.44-gateway-port.manifest.json +329 -0
- package/host/omo-check/patches/omo-5.1.44-provider-port.patch +440 -0
- package/host/omo-check/patches/omo-5.1.44-rpc-port.patch +778 -0
- package/package.json +4 -1
- package/scripts/secret-rules.ts +101 -0
- package/scripts/secret-scan.allow.json +155 -0
- package/scripts/secret-scan.rules.json +30 -0
- package/src/agent-request-rules.ts +82 -0
- package/src/cli/access.ts +31 -34
- package/src/cli/launchd.ts +30 -4
- package/src/cli/main.ts +3 -43
- package/src/cli/messages.ts +160 -0
- package/src/cli/pair.ts +32 -25
- package/src/cli/setup.ts +164 -75
- package/src/decisions.ts +48 -10
- package/src/engine/compat.json +3 -3
- package/src/hub.ts +183 -47
- package/src/main.ts +60 -4
- package/src/notification-history.ts +56 -0
- package/src/omo/client.ts +28 -0
- package/src/protocol.ts +32 -2
- package/src/reply-notifications.ts +144 -0
- package/src/runtime/paths.ts +2 -0
- package/src/security-allow.ts +126 -0
- package/src/security-check.ts +559 -0
- package/src/store.ts +236 -6
- package/src/turn-stats.ts +49 -0
- package/src/work-watch.ts +36 -10
- package/src/work.ts +45 -6
- package/web/DESIGN.md +39 -0
- package/web/app.js +289 -2
- package/web/decisions.d.ts +1 -1
- package/web/decisions.js +6 -0
- package/web/diagram.d.ts +28 -0
- package/web/diagram.js +228 -0
- package/web/index.html +29 -0
- package/web/notifications.d.ts +25 -0
- package/web/notifications.js +118 -0
- package/web/security-inbox.d.ts +35 -0
- package/web/security-inbox.js +237 -0
- package/web/style.css +43 -1
- package/web/turn-stats.d.ts +26 -0
- package/web/turn-stats.js +58 -0
package/web/style.css
CHANGED
|
@@ -99,7 +99,7 @@ button { font: inherit; color: inherit; cursor: pointer; }
|
|
|
99
99
|
.text-btn[hidden] { display: none; }
|
|
100
100
|
.text-btn[aria-expanded="true"] { background: var(--accent); color: #fff; }
|
|
101
101
|
.messages-wrap { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
|
102
|
-
.messages { position: relative; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 16px 0; }
|
|
102
|
+
.messages { position: relative; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 16px 0; margin-right: 64px; }
|
|
103
103
|
.memo { position: absolute; left: 16px; bottom: 8px; z-index: 5; width: 400px; height: 400px; min-width: 220px; min-height: 160px; max-width: calc(100% - 80px); max-height: calc(100% - 16px); display: flex; flex-direction: column; background: #2b2d31; border: 1px solid #4e5058; border-radius: 8px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45); }
|
|
104
104
|
.memo[hidden] { display: none; }
|
|
105
105
|
.memo-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; font-size: 12px; font-weight: 700; color: var(--muted); border-bottom: 1px solid var(--border); }
|
|
@@ -126,6 +126,8 @@ button { font: inherit; color: inherit; cursor: pointer; }
|
|
|
126
126
|
.msg-name { font-weight: 600; }
|
|
127
127
|
.msg-name.bot { color: #a3acff; }
|
|
128
128
|
.msg-time { font-size: 12px; color: var(--muted); }
|
|
129
|
+
.turn-stats { margin-top: 4px; margin-right: 48px; font-size: 12px; line-height: 1.5; color: var(--muted); font-variant-numeric: tabular-nums; user-select: none; }
|
|
130
|
+
.turn-stats::before { content: attr(data-label); }
|
|
129
131
|
.msg-tag { font-size: 11px; color: var(--muted); border: 1px solid #4e5058; border-radius: 4px; padding: 0 4px; }
|
|
130
132
|
.msg-read { font-size: 11px; color: var(--muted); }
|
|
131
133
|
.msg.precomment .msg-body { opacity: 0.72; font-size: 0.9em; }
|
|
@@ -144,6 +146,21 @@ button { font: inherit; color: inherit; cursor: pointer; }
|
|
|
144
146
|
.msg-text code { font-family: ui-monospace, monospace; font-size: 13px; color: var(--warn); background: #1e1f22; border-radius: 3px; padding: 1px 4px; }
|
|
145
147
|
.msg-text pre { background: #1e1f22; border: 1px solid #1a1b1e; border-radius: 4px; padding: 8px 10px; overflow-x: auto; }
|
|
146
148
|
.msg-text pre code { color: var(--text); background: none; padding: 0; white-space: pre; }
|
|
149
|
+
.chat-diagram { margin: 8px 0; min-width: 0; max-width: 100%; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-card); }
|
|
150
|
+
@media (max-width: 640px) {
|
|
151
|
+
/* Keep this component's source and scroll controls clear of the existing chat navigation. */
|
|
152
|
+
.chat-diagram { margin-right: 48px; }
|
|
153
|
+
}
|
|
154
|
+
.diagram-title { padding: 8px 12px; font-weight: 600; overflow-wrap: anywhere; }
|
|
155
|
+
.diagram-viewport { max-width: 100%; max-height: 24rem; overflow: auto; padding: 12px; }
|
|
156
|
+
.diagram-viewport:focus-visible, .diagram-source summary:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }
|
|
157
|
+
.diagram-stage { position: relative; display: grid; grid-auto-columns: max-content; gap: 48px 24px; width: max-content; min-width: 100%; padding-right: 24px; isolation: isolate; }
|
|
158
|
+
.diagram-node { width: max-content; justify-self: center; align-self: start; padding: 8px 12px; border: 1px solid var(--border); border-radius: 4px; background: var(--bg-input); color: var(--text); white-space: pre; font: inherit; }
|
|
159
|
+
.diagram-edges { position: absolute; top: 0; left: 0; z-index: -1; pointer-events: none; overflow: visible; }
|
|
160
|
+
.diagram-edges path { fill: none; stroke: var(--muted); stroke-width: 1.5; }
|
|
161
|
+
.diagram-source { border-top: 1px solid var(--border); min-width: 0; }
|
|
162
|
+
.diagram-source summary { min-height: 44px; padding: 12px; color: var(--text); cursor: pointer; }
|
|
163
|
+
.msg-text .diagram-source pre { margin: 0; max-height: 24rem; overflow: auto; border: 0; border-radius: 0 0 8px 8px; background: var(--bg-input); }
|
|
147
164
|
.msg-text blockquote { border-left: 4px solid #4e5058; padding-left: 10px; color: #b5bac1; }
|
|
148
165
|
.msg-text table { border-collapse: collapse; display: block; overflow-x: auto; }
|
|
149
166
|
.msg-text th, .msg-text td { border: 1px solid #4e5058; padding: 4px 8px; text-align: left; }
|
|
@@ -569,3 +586,28 @@ button { font: inherit; color: inherit; cursor: pointer; }
|
|
|
569
586
|
/* Bug 90: the page-drawn tooltip (web/tooltip.js). */
|
|
570
587
|
.zgw-tip { position: fixed; z-index: 10000; max-width: min(360px, calc(100vw - 16px)); padding: 6px 9px; border-radius: 6px; background: #111214; color: var(--text); border: 1px solid #3f4147; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45); font-size: 12px; line-height: 1.45; white-space: pre-line; overflow-wrap: anywhere; pointer-events: none; }
|
|
571
588
|
.zgw-tip[hidden] { display: none; }
|
|
589
|
+
|
|
590
|
+
/* Improvement 165: the security check card (values the user decides to send or drop). */
|
|
591
|
+
.security-card { display: block; margin: 8px 0; border: 1px solid #4e5058; border-left: 4px solid var(--warn); background: var(--bg-card); border-radius: 6px; padding: 12px; max-width: 640px; }
|
|
592
|
+
.security-card .security-title { font-weight: 600; margin-bottom: 6px; }
|
|
593
|
+
.security-card .security-list { margin: 0 0 8px; padding-left: 18px; }
|
|
594
|
+
.security-card .security-value { word-break: break-all; }
|
|
595
|
+
.security-card .security-place { opacity: 0.7; font-size: 0.9em; }
|
|
596
|
+
.security-card .security-actions { display: flex; gap: 8px; }
|
|
597
|
+
.security-card .security-actions .btn { white-space: nowrap; writing-mode: horizontal-tb; }
|
|
598
|
+
.security-card.done { opacity: 0.75; }
|
|
599
|
+
.security-inbox-item .security-value, .security-allowed-item .security-value { white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-all; }
|
|
600
|
+
.security-inbox-item .security-list { margin: 0; padding-left: 18px; }
|
|
601
|
+
.security-inbox-item .security-question { font-size: 12px; color: var(--muted); }
|
|
602
|
+
.security-actions { flex-wrap: wrap; gap: 8px; }
|
|
603
|
+
.security-actions .text-btn { white-space: normal; }
|
|
604
|
+
.security-status { font-size: 12px; color: var(--muted); }
|
|
605
|
+
.security-status.confirmed { color: var(--ok); }
|
|
606
|
+
.security-allowed-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
|
|
607
|
+
.security-allowed-item { padding: 8px; border: 1px solid var(--border); border-radius: 4px; min-width: 0; }
|
|
608
|
+
.security-allowed-item .security-value { display: block; font-size: 12px; }
|
|
609
|
+
#security-allowed-confirm[hidden] { display: none; }
|
|
610
|
+
@media (max-width: 640px) {
|
|
611
|
+
.security-actions .text-btn, .security-inbox-item .text-btn, #security-check .text-btn { min-height: 44px; }
|
|
612
|
+
}
|
|
613
|
+
.security-card .security-value { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface TurnStatsEvent {
|
|
2
|
+
readonly conv?: string;
|
|
3
|
+
readonly type: string;
|
|
4
|
+
readonly seq?: number;
|
|
5
|
+
readonly data?: {
|
|
6
|
+
readonly itemId?: unknown;
|
|
7
|
+
readonly messageSeq?: unknown;
|
|
8
|
+
readonly turnId?: unknown;
|
|
9
|
+
readonly stats?: unknown;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface StatsBody {
|
|
13
|
+
readonly ownerDocument: { createElement(tag: string): StatsLine };
|
|
14
|
+
querySelector(selector: string): unknown;
|
|
15
|
+
appendChild(line: StatsLine): unknown;
|
|
16
|
+
}
|
|
17
|
+
export interface StatsLine {
|
|
18
|
+
className: string;
|
|
19
|
+
readonly dataset: Record<string, string | undefined>;
|
|
20
|
+
setAttribute(name: string, value: string): void;
|
|
21
|
+
}
|
|
22
|
+
export function turnStatsLabel(stats: unknown): string;
|
|
23
|
+
export function createTurnStats(): {
|
|
24
|
+
reset(conv: string): void;
|
|
25
|
+
accept(event: TurnStatsEvent, body?: StatsBody): void;
|
|
26
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Unknown fields are omitted, not rendered as zero. Model time excludes tools and wall time. */
|
|
2
|
+
export function turnStatsLabel(stats) {
|
|
3
|
+
if (!stats || typeof stats !== "object") return "";
|
|
4
|
+
const parts = [];
|
|
5
|
+
if (Number.isFinite(stats.tokensPerSecond) && stats.tokensPerSecond > 0) parts.push(`TPS ${stats.tokensPerSecond.toFixed(1)} tok/s`);
|
|
6
|
+
if (Number.isFinite(stats.modelDurationMs) && stats.modelDurationMs > 0) parts.push(`모델 처리 ${(stats.modelDurationMs / 1000).toFixed(1)}초`);
|
|
7
|
+
if (Number.isFinite(stats.cacheHitPercent) && stats.cacheHitPercent >= 0 && stats.cacheHitPercent <= 100) parts.push(`캐시 적중 ${stats.cacheHitPercent.toFixed(1)}%`);
|
|
8
|
+
return parts.join(" · ");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* One transcript in one gateway origin. Nothing is shared in storage or across app instances.
|
|
13
|
+
* Keep unmatched stats until their final's older page arrives; never fall back to the latest row.
|
|
14
|
+
*/
|
|
15
|
+
export function createTurnStats() {
|
|
16
|
+
let conv = null;
|
|
17
|
+
const rows = new Map();
|
|
18
|
+
const labels = new Map();
|
|
19
|
+
function draw(key) {
|
|
20
|
+
const body = rows.get(key);
|
|
21
|
+
const label = labels.get(key);
|
|
22
|
+
if (!body || !label || body.querySelector(".turn-stats")) return;
|
|
23
|
+
const line = body.ownerDocument.createElement("div");
|
|
24
|
+
line.className = "turn-stats";
|
|
25
|
+
// Generated content stays out of selection text and ordinary transcript text exports.
|
|
26
|
+
// The accessible name still exposes the same metadata to assistive technology.
|
|
27
|
+
line.dataset.label = label;
|
|
28
|
+
line.setAttribute("role", "note");
|
|
29
|
+
line.setAttribute("aria-label", label);
|
|
30
|
+
body.appendChild(line);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
reset(nextConv) {
|
|
34
|
+
conv = nextConv;
|
|
35
|
+
rows.clear();
|
|
36
|
+
labels.clear();
|
|
37
|
+
},
|
|
38
|
+
accept(event, body) {
|
|
39
|
+
if (!event || event.conv !== conv || !event.data) return;
|
|
40
|
+
const data = event.data;
|
|
41
|
+
if (typeof data.itemId !== "string" || !data.itemId) return;
|
|
42
|
+
const seq = event.type === "message.final" ? event.seq : data.messageSeq;
|
|
43
|
+
if (!Number.isInteger(seq) || seq <= 0) return;
|
|
44
|
+
const key = JSON.stringify([data.itemId, seq]);
|
|
45
|
+
if (event.type === "message.final") {
|
|
46
|
+
if (!body) return;
|
|
47
|
+
rows.set(key, body);
|
|
48
|
+
draw(key);
|
|
49
|
+
} else if (event.type === "message.stats") {
|
|
50
|
+
if (typeof data.turnId !== "string" || !data.turnId) return;
|
|
51
|
+
const label = turnStatsLabel(data.stats);
|
|
52
|
+
if (!label) return;
|
|
53
|
+
if (!labels.has(key)) labels.set(key, label);
|
|
54
|
+
draw(key);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|