@njeybe/nativ 2.6.0 → 2.7.0
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/CHANGELOG.md +35 -0
- package/README.md +71 -1
- package/dist/commands/design-check.d.ts +4 -0
- package/dist/commands/design-check.js +76 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +53 -1
- package/dist/commands/update.js +46 -0
- package/dist/core/design-rules.d.ts +23 -0
- package/dist/core/design-rules.js +115 -0
- package/dist/core/harness-integrity.js +26 -7
- package/dist/index.js +11 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.js +8 -5
- package/dist/server/studio-ui/pages/database/browser.js +1 -1
- package/dist/server/studio-ui/pages/database/connection.js +1 -1
- package/dist/server/studio-ui/pages/database/data-shell.js +5 -5
- package/dist/server/studio-ui/pages/database/drift.js +1 -1
- package/dist/server/studio-ui/pages/database/explorer.js +2 -2
- package/dist/server/studio-ui/pages/database/styles.js +5 -5
- package/dist/server/studio-ui/pages/flow/styles.js +3 -3
- package/dist/server/studio-ui/pages/home/script.js +110 -91
- package/dist/server/studio-ui/pages/home/styles.js +33 -45
- package/dist/server/studio-ui/pages/tasks/script.js +150 -3
- package/dist/server/studio-ui/pages/tasks/styles.js +63 -6
- package/dist/server/studio-ui/pages/team/script.js +49 -52
- package/dist/server/studio-ui/pages/team/styles.js +21 -20
- package/dist/server/studio-ui/pages/worktrees/script.js +47 -35
- package/dist/server/studio-ui/pages/worktrees/styles.js +12 -10
- package/dist/server/studio-ui/shell/brand.d.ts +4 -0
- package/dist/server/studio-ui/shell/brand.js +16 -0
- package/dist/server/studio-ui/shell/console.js +61 -2
- package/dist/server/studio-ui/shell/core.js +8 -8
- package/dist/server/studio-ui/shell/detail-view.js +1 -1
- package/dist/server/studio-ui/shell/dispatch.js +18 -0
- package/dist/server/studio-ui/shell/events-tools.js +5 -1
- package/dist/server/studio-ui/shell/format.js +5 -6
- package/dist/server/studio-ui/shell/icons.js +23 -15
- package/dist/server/studio-ui/shell/markup-head.js +11 -6
- package/dist/server/studio-ui/shell/markup-tools.js +19 -10
- package/dist/server/studio-ui/shell/paint.js +3 -0
- package/dist/server/studio-ui/shell/pipeline-state.js +1 -1
- package/dist/server/studio-ui/shell/proposals.js +6 -2
- package/dist/server/studio-ui/shell/pulse.d.ts +1 -0
- package/dist/server/studio-ui/shell/pulse.js +67 -0
- package/dist/server/studio-ui/shell/router.js +25 -0
- package/dist/server/studio-ui/shell/sidebar-view.js +6 -3
- package/dist/server/studio-ui/shell/toasts-format.js +4 -4
- package/dist/server/studio-ui/styles/console.js +33 -13
- package/dist/server/studio-ui/styles/dialogs.js +4 -4
- package/dist/server/studio-ui/styles/responsive.js +8 -0
- package/dist/server/studio-ui/styles/shell.js +24 -5
- package/dist/server/studio-ui/styles/strategist.js +10 -10
- package/dist/server/studio-ui/styles/tokens-base.js +23 -23
- package/dist/server/studio-ui.js +2 -0
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/agents/architect.md +10 -11
- package/templates/GEMINI.md +3 -2
- package/templates/claude-agents/architect.md +10 -11
- package/templates/design/taste/LICENSE +21 -0
- package/templates/design/taste/SOURCE.md +28 -0
- package/templates/design/taste/v1/DIGEST.md +57 -0
- package/templates/design/taste/v1/SKILL.md +226 -0
- package/templates/design/taste/v2/DIGEST.md +62 -0
- package/templates/design/taste/v2/SKILL.md +1206 -0
- package/templates/dot-ai/subagents/architect.md +6 -0
- package/templates/dot-ai/subagents/flutter-developer.md +2 -11
- package/templates/dot-ai/subagents/frontend.md +47 -44
- package/templates/dot-ai/ui_specs.md +15 -36
|
@@ -88,6 +88,31 @@ export const routerScript = String.raw ` // ─── Router and shell-wide eve
|
|
|
88
88
|
});
|
|
89
89
|
}, 1000);
|
|
90
90
|
|
|
91
|
+
// Active milestone: the one with running tasks, else the highest-index one.
|
|
92
|
+
Studio.activeMilestone = function (model) {
|
|
93
|
+
var list = (model && model.milestones) || [];
|
|
94
|
+
var run = list.filter(function (m) {
|
|
95
|
+
return m.tasks.some(function (t) { return t.status === 'in_progress'; });
|
|
96
|
+
});
|
|
97
|
+
var pool = run.length ? run : list;
|
|
98
|
+
return pool.length ? pool[pool.length - 1] : null;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
var autoNavDone = false;
|
|
102
|
+
Studio.autoNav = function () {
|
|
103
|
+
if (autoNavDone || !pipe.loaded.tasks || !Studio.model) return;
|
|
104
|
+
var ms = Studio.activeMilestone(Studio.model);
|
|
105
|
+
if (!ms) return;
|
|
106
|
+
autoNavDone = true;
|
|
107
|
+
var S = Studio.state;
|
|
108
|
+
var opts = { milestoneId: ms.id, keepDetail: true, scroll: false };
|
|
109
|
+
if (!S.view) Studio.go('tasks', opts);
|
|
110
|
+
else { S.milestoneId = ms.id; paintPage(S.view); }
|
|
111
|
+
var el = document.querySelector('[data-milestone="' + cssEsc(ms.id) + '"], [data-ms-group="' + cssEsc(ms.id) + '"]');
|
|
112
|
+
if (el && el.scrollIntoView) el.scrollIntoView({ block: 'start' });
|
|
113
|
+
};
|
|
114
|
+
if (typeof Studio.onPaint === 'function') { Studio.onPaint(function () { Studio.autoNav(); }); }
|
|
115
|
+
|
|
91
116
|
Studio.api = api;
|
|
92
117
|
Studio.postJson = postJson;
|
|
93
118
|
Studio.toast = function (message, kind) { toast(message, kind); };
|
|
@@ -5,7 +5,9 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
5
5
|
function navBadges(env) {
|
|
6
6
|
var badges = {}, model = env.model;
|
|
7
7
|
if (model && model.needsYou.length) badges.home = ['warn', model.needsYou.length];
|
|
8
|
-
|
|
8
|
+
var ready = model ? model.tasks.filter(function (t) { return t.status === 'pending' && t.isAvailable; }).length : 0;
|
|
9
|
+
var active = model ? model.running.length + ready : 0;
|
|
10
|
+
if (active) badges.tasks = [model.running.length ? 'run' : '', active];
|
|
9
11
|
if (env.worktreeCount != null) badges.worktrees = ['', env.worktreeCount];
|
|
10
12
|
if (env.benchmarkText) badges.benchmarks = ['', env.benchmarkText];
|
|
11
13
|
return badges;
|
|
@@ -17,7 +19,8 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
17
19
|
var item = function (p) {
|
|
18
20
|
var b = badges[p.id];
|
|
19
21
|
return '<button type="button" class="nav-item" data-go="' + esc(p.id) + '"' +
|
|
20
|
-
(env.view === p.id ? ' aria-current="page"' : '') +
|
|
22
|
+
(env.view === p.id ? ' aria-current="page"' : '') +
|
|
23
|
+
' aria-label="' + esc(p.label) + '" title="' + esc(p.label) + '"' + '>' + ui.svg(p.icon) +
|
|
21
24
|
'<span class="nav-text">' + esc(p.label) + '</span>' +
|
|
22
25
|
(b ? '<span class="nav-badge' + (b[0] ? ' ' + b[0] : '') + '">' + esc(b[1]) + '</span>' : '') + '</button>';
|
|
23
26
|
};
|
|
@@ -32,7 +35,7 @@ export const sidebarViewScript = String.raw ` // ─── Sidebar markup (pure
|
|
|
32
35
|
/** env = { root, branch }. */
|
|
33
36
|
Studio.sideFootHtml = function (env) {
|
|
34
37
|
return '<span>Workspace</span><span class="mono" id="sb-root" title="' + esc(env.root || '') + '">' +
|
|
35
|
-
esc(env.root || '
|
|
38
|
+
esc(env.root || '-') + '</span><span>branch <span class="mono" id="sb-branch-name">' + esc(env.branch || '-') + '</span></span>';
|
|
36
39
|
};
|
|
37
40
|
|
|
38
41
|
`;
|
|
@@ -48,16 +48,16 @@ export const toastsFormatScript = String.raw ` // ─── Toasts ────
|
|
|
48
48
|
|
|
49
49
|
// ─── Formatting ────────────────────────────────────────────────────────────
|
|
50
50
|
function num(n) {
|
|
51
|
-
if (n == null || n === '' || isNaN(n)) return '
|
|
51
|
+
if (n == null || n === '' || isNaN(n)) return '-';
|
|
52
52
|
return Number(n).toLocaleString('en-US', { maximumFractionDigits: 3 });
|
|
53
53
|
}
|
|
54
54
|
function usd(n) {
|
|
55
|
-
if (n == null || isNaN(n)) return '
|
|
55
|
+
if (n == null || isNaN(n)) return '-';
|
|
56
56
|
n = Number(n);
|
|
57
57
|
return '$' + (n >= 100 ? n.toFixed(0) : n >= 1 ? n.toFixed(2) : n.toFixed(3));
|
|
58
58
|
}
|
|
59
59
|
function fmtMs(ms) {
|
|
60
|
-
if (ms == null || isNaN(ms)) return '
|
|
60
|
+
if (ms == null || isNaN(ms)) return '-';
|
|
61
61
|
if (ms < 1000) return Math.round(ms) + ' ms';
|
|
62
62
|
if (ms < 60000) return (ms / 1000).toFixed(2) + ' s';
|
|
63
63
|
return Math.floor(ms / 60000) + 'm ' + Math.round((ms % 60000) / 1000) + 's';
|
|
@@ -83,7 +83,7 @@ export const toastsFormatScript = String.raw ` // ─── Toasts ────
|
|
|
83
83
|
if (typeof v === 'number') return num(v);
|
|
84
84
|
if (Array.isArray(v)) return v.map(String).join(', ');
|
|
85
85
|
if (v && typeof v === 'object') return JSON.stringify(v);
|
|
86
|
-
return String(v == null ? '
|
|
86
|
+
return String(v == null ? '-' : v);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
`;
|
|
@@ -1,20 +1,37 @@
|
|
|
1
1
|
// Runner console drawer and proposal review styles.
|
|
2
|
-
export const consoleCss = String.raw `/*
|
|
3
|
-
|
|
4
|
-
body.has-console-min { padding-bottom: 56px; }
|
|
5
|
-
#runner-console-drawer { position: fixed; inset: auto 0 0 var(--sidebar-w); z-index: 60; display: flex; flex-direction: column; max-height: min(58vh, 520px); background: var(--term-bg); color: var(--term-text); border-top: 1px solid var(--chip-border); box-shadow: var(--shadow-float); animation: rc-slide-up .28s cubic-bezier(.2, .8, .2, 1); }
|
|
2
|
+
export const consoleCss = String.raw `/* Runner inspector: right pane at 1024px and up, modal sheet below. */
|
|
3
|
+
#runner-console-drawer { position: fixed; top: var(--inspector-top, 96px); right: 0; bottom: 0; z-index: 30; width: 320px; display: flex; flex-direction: column; background: var(--term-bg); color: var(--term-text); border-left: 1px solid var(--line); transition: width .2s ease; }
|
|
6
4
|
#runner-console-drawer[hidden] { display: none; }
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.
|
|
5
|
+
/* Content reflows beside the pane instead of sitting under it. */
|
|
6
|
+
body.has-console main, body:has(#runner-console-drawer:not([hidden])) main { margin-right: 320px; }
|
|
7
|
+
body.has-console-min main { margin-right: 56px; }
|
|
8
|
+
@media (min-width: 1280px) {
|
|
9
|
+
#runner-console-drawer { width: 360px; }
|
|
10
|
+
body.has-console main, body:has(#runner-console-drawer:not([hidden])) main { margin-right: 360px; }
|
|
11
|
+
}
|
|
12
|
+
#runner-console-drawer.is-min { width: 56px; overflow: hidden; }
|
|
13
|
+
#runner-console-drawer.is-min .rc-body, #runner-console-drawer.is-min .rc-foot, #runner-console-drawer.is-min .rc-title, #runner-console-drawer.is-min .rc-steps, #runner-console-drawer.is-min .rc-status, #runner-console-drawer.is-min .rc-clock { display: none; }
|
|
14
|
+
@media (max-width: 1023px) {
|
|
15
|
+
#runner-console-drawer { top: 0; width: min(420px, 92vw); max-width: 92vw; z-index: 40; border-radius: 6px 0 0 6px; box-shadow: var(--shadow); }
|
|
16
|
+
body.has-console main, body.has-console-min main, body:has(#runner-console-drawer:not([hidden])) main { margin-right: 0; }
|
|
17
|
+
}
|
|
18
|
+
/* The task detail dialog stays modal above the inspector. */
|
|
19
|
+
#task-drawer { z-index: 45; }
|
|
20
|
+
.rc-id-row { display: flex; align-items: center; gap: 10px; width: 100%; }
|
|
21
|
+
.rc-status { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--term-muted); }
|
|
22
|
+
.rc-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--term-muted); }
|
|
23
|
+
.rc-status[data-tone="ok"] .rc-dot { background: var(--ok); }
|
|
24
|
+
.rc-status[data-tone="err"] .rc-dot { background: var(--danger); }
|
|
25
|
+
.rc-status[data-tone="run"] .rc-dot { background: var(--warn); }
|
|
26
|
+
.rc-clock { margin-left: auto; font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; color: var(--term-muted); }
|
|
10
27
|
.rc-task { font-family: var(--mono); font-size: 12.5px; font-weight: 600; }
|
|
11
|
-
.rc-title { font-size: 12.5px; color: var(--term-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width:
|
|
12
|
-
.rc-steps { display: flex; align-items: center; gap: 6px; margin: 0
|
|
28
|
+
.rc-title { font-size: 12.5px; color: var(--term-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; flex: 1 1 100%; }
|
|
29
|
+
.rc-steps { display: flex; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; flex-wrap: wrap; }
|
|
13
30
|
.rc-step { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; font-size: 11px; color: var(--term-muted); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
14
31
|
.rc-step.is-done { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 55%, transparent); }
|
|
15
32
|
.rc-step.is-active { color: var(--term-text); background: color-mix(in srgb, var(--primary) 32%, transparent); border-color: var(--primary); }
|
|
16
33
|
.rc-step.is-failed { color: var(--term-text); background: color-mix(in srgb, var(--danger) 32%, transparent); border-color: var(--danger); }
|
|
17
|
-
.rc-controls { display: flex; gap: 6px; flex:
|
|
34
|
+
.rc-controls { display: flex; gap: 6px; flex-wrap: wrap; }
|
|
18
35
|
.rc-btn { padding: 5px 9px; font: 500 11px/1 var(--font); color: var(--term-text); background: transparent; border: 1px solid var(--term-line); border-radius: var(--r-control); cursor: pointer; }
|
|
19
36
|
.rc-btn:hover { background: color-mix(in srgb, var(--term-muted) 22%, transparent); }
|
|
20
37
|
.rc-btn:disabled { opacity: .45; cursor: not-allowed; }
|
|
@@ -22,7 +39,7 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
22
39
|
.rc-btn.danger { color: var(--term-text); border-color: var(--danger); }
|
|
23
40
|
.rc-btn.danger:hover { background: color-mix(in srgb, var(--danger) 30%, transparent); }
|
|
24
41
|
.rc-btn:focus-visible { outline: 2px solid var(--term-text); outline-offset: 2px; }
|
|
25
|
-
.rc-body { flex: 1 1 auto; min-height: 120px; margin: 0; padding: 10px 14px; overflow: auto; font-family: var(--mono); font-size: 12.5px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
42
|
+
.rc-body { flex: 1 1 auto; min-height: 120px; margin: 0; padding: 10px 14px; overflow: auto; font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
26
43
|
.rc-body:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
27
44
|
.rc-empty { color: var(--term-muted); }
|
|
28
45
|
.rc-fg-muted { color: var(--term-muted); }
|
|
@@ -31,10 +48,10 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
31
48
|
.rc-fg-info { color: var(--accent); }
|
|
32
49
|
.rc-fg-danger { color: color-mix(in srgb, var(--danger) 55%, #fff); }
|
|
33
50
|
.rc-bold { font-weight: 700; }
|
|
34
|
-
.rc-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 7px 14px; font-size: 11.5px; color: var(--term-muted); border-top: 1px solid var(--term-line); }
|
|
51
|
+
.rc-foot { font-variant-numeric: tabular-nums; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 7px 14px; font-size: 11.5px; color: var(--term-muted); border-top: 1px solid var(--term-line); }
|
|
35
52
|
.rc-foot strong { font-family: var(--mono); font-weight: 600; color: var(--term-text); }
|
|
36
53
|
#runner-console-drawer.is-min .rc-tabs { display: none; }
|
|
37
|
-
.rc-tabs { display: flex; gap: 2px; padding: 0
|
|
54
|
+
.rc-tabs { display: flex; gap: 2px; padding: 0 10px; overflow-x: auto; border-bottom: 1px solid var(--line); }
|
|
38
55
|
.rc-tab { display: inline-flex; align-items: center; gap: 6px; padding: 8px 10px; font: 500 12px/1 var(--font); color: var(--term-muted); background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; }
|
|
39
56
|
.rc-tab:hover { color: var(--term-text); }
|
|
40
57
|
.rc-tab[aria-selected="true"] { color: var(--term-text); border-bottom-color: var(--primary); }
|
|
@@ -80,4 +97,7 @@ body.has-console-min { padding-bottom: 56px; }
|
|
|
80
97
|
.heal-result.is-error { color: color-mix(in srgb, var(--danger) 55%, #fff); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
81
98
|
.heal-skel { height: 12px; margin: 8px 0; border-radius: 4px; background: var(--term-line); animation: blink 1.4s ease-in-out infinite; }
|
|
82
99
|
@media (max-width: 768px) { .heal-grid { grid-template-columns: 1fr; } }
|
|
100
|
+
@media (prefers-reduced-motion: reduce) {
|
|
101
|
+
#runner-console-drawer, #runner-console-drawer * { transition: none !important; animation: none !important; }
|
|
102
|
+
}
|
|
83
103
|
`;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export const dialogsCss = String.raw `/* Toasts */
|
|
3
3
|
/* Bottom-right so notifications never cover the sticky header and navigation. */
|
|
4
4
|
.toast-host { position: fixed; right: 16px; bottom: 16px; z-index: 100; display: flex; flex-direction: column; gap: 8px; width: min(440px, calc(100vw - 32px)); pointer-events: none; }
|
|
5
|
-
.toast { pointer-events: auto; display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; font-size: 13.5px; background: var(--surface); border: 1px solid var(--
|
|
5
|
+
.toast { pointer-events: auto; display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; font-size: 13.5px; background: var(--surface); border: 1px solid var(--line-2); border-left: 3px solid var(--danger); border-radius: var(--r-card); box-shadow: var(--shadow); animation: toast-in .18s ease-out; }
|
|
6
6
|
.toast.ok { border-left-color: var(--success); }
|
|
7
7
|
.toast .t-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
8
8
|
.toast .t-hint { color: var(--muted); font-size: 12.5px; }
|
|
@@ -12,8 +12,8 @@ export const dialogsCss = String.raw `/* Toasts */
|
|
|
12
12
|
/* Dialogs */
|
|
13
13
|
dialog { border: none; padding: 0; background: transparent; color: var(--text); width: min(640px, calc(100vw - 32px)); max-height: calc(100vh - 32px); }
|
|
14
14
|
dialog.narrow { width: min(460px, calc(100vw - 32px)); }
|
|
15
|
-
dialog::backdrop { background:
|
|
16
|
-
.modal { padding: 22px; background: var(--surface); border: 1px solid var(--
|
|
15
|
+
dialog::backdrop { background: color-mix(in srgb, var(--text) 40%, transparent); backdrop-filter: blur(2px); }
|
|
16
|
+
.modal { padding: 22px; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-card); box-shadow: var(--shadow); }
|
|
17
17
|
.modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; }
|
|
18
18
|
.modal .lead { color: var(--muted); margin: 0 0 16px; font-size: 14px; line-height: 1.55; }
|
|
19
19
|
.field { margin-bottom: 16px; }
|
|
@@ -112,7 +112,7 @@ textarea.cmd-preview { min-height: 92px; font-family: var(--mono); font-size: 12
|
|
|
112
112
|
.switch-text { display: flex; flex-direction: column; font-size: 13.5px; }
|
|
113
113
|
.switch-text b { font-weight: 600; }
|
|
114
114
|
.switch-text span { font-size: 12.5px; color: var(--muted); }
|
|
115
|
-
kbd { padding: 0 5px; font-family: var(--mono); font-size: 11px; color: var(--muted); background: var(--chip); border: 1px solid var(--chip-border); border-radius:
|
|
115
|
+
kbd { padding: 0 5px; font-family: var(--mono); font-size: 11px; color: var(--muted); background: var(--chip); border: 1px solid var(--chip-border); border-radius: var(--r-control); }
|
|
116
116
|
.btn.primary kbd { color: var(--accent-fg); background: transparent; border-color: color-mix(in srgb, var(--accent-fg) 45%, transparent); }
|
|
117
117
|
|
|
118
118
|
`;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
// Responsive rules for the kept pages and dialogs.
|
|
2
2
|
export const responsiveCss = String.raw `/* Responsive */
|
|
3
|
+
@media (max-width: 1023px) and (min-width: 761px) {
|
|
4
|
+
:root { --sidebar-w: 56px; }
|
|
5
|
+
.side { padding: 16px 8px; align-items: center; }
|
|
6
|
+
.brand { padding: 0; justify-content: center; }
|
|
7
|
+
.brand .wordmark { height: 16px; width: 16px; overflow: hidden; }
|
|
8
|
+
.brand b, .brand .ver, .nav-glabel, .nav-text, .nav-badge, .side-foot { display: none; }
|
|
9
|
+
.nav-item { justify-content: center; padding: 6px; width: 40px; }
|
|
10
|
+
}
|
|
3
11
|
@media (max-width: 900px) {
|
|
4
12
|
#runner-console-drawer { inset: auto 0 0 0; }
|
|
5
13
|
.panes { grid-template-columns: 1fr; }
|
|
@@ -3,16 +3,17 @@ export const shellCss = String.raw `/* Layout */
|
|
|
3
3
|
.app { display: grid; grid-template-columns: var(--sidebar-w) minmax(0, 1fr); min-height: 100vh; }
|
|
4
4
|
.side { border-right: 1px solid var(--line); background: var(--surface); padding: 16px 12px; display: flex; flex-direction: column; gap: 20px; position: sticky; top: 0; height: 100vh; overflow-y: auto; }
|
|
5
5
|
.brand { display: flex; align-items: center; gap: 10px; padding: 0 6px; }
|
|
6
|
-
.
|
|
6
|
+
.wordmark { height: 18px; width: auto; color: var(--fg); display: block; flex: none; }
|
|
7
|
+
.wordmark.is-rail { height: 16px; }
|
|
7
8
|
.brand b { font-weight: 600; white-space: nowrap; }
|
|
8
|
-
.
|
|
9
|
+
.side-foot .ver { font: 11px var(--mono); color: var(--fg-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
9
10
|
.nav { display: flex; flex-direction: column; gap: 14px; }
|
|
10
11
|
.nav-group { display: flex; flex-direction: column; gap: 2px; }
|
|
11
12
|
.nav-glabel { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); padding: 0 8px 4px; }
|
|
12
13
|
.nav-item { display: flex; align-items: center; gap: 10px; min-height: 32px; padding: 7px 8px; border-radius: 7px; border: 0; background: none; text-align: left; color: var(--fg-2); width: 100%; cursor: pointer; transition: background .15s, color .15s; }
|
|
13
|
-
.nav-item svg { width:
|
|
14
|
+
.nav-item svg { width: 20px; height: 20px; flex: none; }
|
|
14
15
|
.nav-item:hover { background: var(--surface-2); color: var(--fg); }
|
|
15
|
-
.nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--
|
|
16
|
+
.nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--fg); font-weight: 600; }
|
|
16
17
|
.nav-badge { margin-left: auto; font: 500 11px var(--font); font-variant-numeric: tabular-nums; min-width: 20px; padding: 1px 6px; border-radius: 999px; background: var(--surface-2); color: var(--fg-2); text-align: center; }
|
|
17
18
|
.nav-badge.warn { background: var(--warn-soft); color: var(--warn); }
|
|
18
19
|
.nav-badge.run { background: var(--run-soft); color: var(--run); }
|
|
@@ -27,6 +28,24 @@ export const shellCss = String.raw `/* Layout */
|
|
|
27
28
|
.top-right { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
28
29
|
.btn.ghost { background: none; border-color: transparent; color: var(--fg-2); box-shadow: none; }
|
|
29
30
|
.btn.ghost:hover { background: var(--surface-2); }
|
|
31
|
+
#btn-dispatch-next[disabled] { opacity: .55; cursor: not-allowed; }
|
|
32
|
+
.spacer { flex: 1; }
|
|
33
|
+
.ic-sun, .ic-moon { display: inline-flex; }
|
|
34
|
+
.ic-moon { display: none; }
|
|
35
|
+
:root[data-theme="light"] .ic-sun { display: none; }
|
|
36
|
+
:root[data-theme="light"] .ic-moon { display: inline-flex; }
|
|
37
|
+
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .ic-sun { display: none; } :root:not([data-theme="dark"]) .ic-moon { display: inline-flex; } }
|
|
38
|
+
.pulse-strip { min-height: 32px; height: auto; width: auto; border-radius: 0; background: none; box-shadow: none; animation: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0 20px; padding: 0 24px; border-bottom: 1px solid var(--line); font: 12.5px var(--mono); color: var(--fg-2); }
|
|
39
|
+
#pulse .num { font-variant-numeric: tabular-nums; }
|
|
40
|
+
#pulse .pulse-ms { color: var(--fg); padding-right: 20px; border-right: 1px solid var(--line); }
|
|
41
|
+
#pulse .pulse-item { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
|
|
42
|
+
#pulse .pulse-item.zero, #pulse .pulse-note.loading { color: var(--fg-3); }
|
|
43
|
+
#pulse .pulse-item.run { color: var(--run); } #pulse .pulse-item.bad { color: var(--bad); } #pulse .pulse-item.warn, #pulse .pulse-note.offline { color: var(--warn); }
|
|
44
|
+
#pulse .pdot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
|
|
45
|
+
#pulse .pulse-item.run .pdot { animation: blink 1.6s infinite; }
|
|
46
|
+
@media (max-width: 1023px) { .pulse-strip { padding-top: 4px; padding-bottom: 4px; gap: 0 16px; } #pulse .pulse-ms { flex-basis: 100%; border-right: 0; padding-right: 0; } }
|
|
47
|
+
.wordmark.is-rail { display: none; }
|
|
48
|
+
@media (max-width: 1023px) { .wordmark { display: none; } .wordmark.is-rail { display: block; } }
|
|
30
49
|
.btn svg { width: 14px; height: 14px; }
|
|
31
50
|
.kbd { font: 11px var(--mono); padding: 0 5px; border: 1px solid var(--line); border-radius: 4px; color: var(--fg-3); }
|
|
32
51
|
.live { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--fg-2); }
|
|
@@ -113,5 +132,5 @@ export const shellCss = String.raw `/* Layout */
|
|
|
113
132
|
.drawer { width: 100%; }
|
|
114
133
|
#runner-console-drawer { inset: auto 0 0 0; }
|
|
115
134
|
}
|
|
116
|
-
@media (prefers-reduced-motion: reduce) { .pulse, .live-dot.flash { animation: none; } * { transition: none !important; } }
|
|
135
|
+
@media (prefers-reduced-motion: reduce) { .pulse, .live-dot.flash, #pulse .pdot { animation: none !important; } * { transition: none !important; } }
|
|
117
136
|
`;
|
|
@@ -12,30 +12,30 @@ export const strategistCss = String.raw `/* Tier 1 AI Strategist (ui_specs.md §
|
|
|
12
12
|
.t1-chip-label { color: var(--muted); }
|
|
13
13
|
.t1-caret { color: var(--muted); transition: transform .15s; }
|
|
14
14
|
.t1-chip[aria-expanded="true"] .t1-caret { transform: rotate(180deg); }
|
|
15
|
-
.t1-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 300px; padding: 12px; font-size: 12.5px; background: var(--surface); border: 1px solid var(--
|
|
15
|
+
.t1-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 300px; padding: 12px; font-size: 12.5px; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-card); box-shadow: var(--shadow); }
|
|
16
16
|
.t1-menu:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
|
|
17
17
|
.t1-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 28px; color: var(--muted); }
|
|
18
18
|
.t1-row b, .t1-row code { color: var(--text); font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
19
19
|
.t1-row code { font-family: var(--mono); font-size: 12px; }
|
|
20
|
-
.t1-switch { position: relative; width: 54px; height: 24px; padding: 0 8px; font: 600 10.5px/22px var(--mono); color: var(--muted); text-align: right; background: var(--chip); border: 1px solid var(--chip-border); border-radius:
|
|
20
|
+
.t1-switch { position: relative; width: 54px; height: 24px; padding: 0 8px; font: 600 10.5px/22px var(--mono); color: var(--muted); text-align: right; background: var(--chip); border: 1px solid var(--chip-border); border-radius: var(--r-control); cursor: pointer; transition: background .15s, border-color .15s; }
|
|
21
21
|
.t1-switch::before { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: var(--surface); box-shadow: var(--shadow); transition: transform .15s; }
|
|
22
|
-
.t1-switch[aria-checked="true"] { color:
|
|
22
|
+
.t1-switch[aria-checked="true"] { color: var(--accent-fg); text-align: left; background: var(--success); border-color: var(--success); }
|
|
23
23
|
.t1-switch[aria-checked="true"]::before { transform: translateX(30px); }
|
|
24
24
|
.t1-switch:disabled { opacity: .5; cursor: not-allowed; }
|
|
25
25
|
.t1-policy { display: flex; gap: 6px; margin: 8px 0; padding: 8px; line-height: 1.45; color: var(--muted); background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-control); }
|
|
26
26
|
.t1-policy .icon { flex: none; margin-top: 1px; color: var(--success); }
|
|
27
27
|
.t1-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin: 0; }
|
|
28
|
-
.t1-stats div { min-width: 0; padding: 6px 8px; border: 1px solid var(--
|
|
28
|
+
.t1-stats div { min-width: 0; padding: 6px 8px; border: 0; border-left: 1px solid var(--line); border-radius: 0; font-variant-numeric: tabular-nums; }
|
|
29
29
|
.t1-stats dt { font-size: 11px; color: var(--muted); }
|
|
30
30
|
.t1-stats dd { margin: 2px 0 0; font: 600 15px/1.2 var(--mono); font-variant-numeric: tabular-nums; color: var(--text); }
|
|
31
31
|
.t1-strip { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; color: var(--term-muted); border: 1px solid var(--term-line); border-radius: var(--r-control); }
|
|
32
32
|
.t1-strip > span { display: inline-flex; align-items: center; gap: 6px; }
|
|
33
33
|
.t1-strip strong { color: var(--term-text); font-weight: 600; }
|
|
34
34
|
.t1-strip.is-triaging { border-color: color-mix(in srgb, var(--active) 60%, transparent); background: color-mix(in srgb, var(--active) 14%, transparent); }
|
|
35
|
-
.rc-btn.t1-run { color:
|
|
36
|
-
.rc-btn.t1-run:hover:not(:disabled) { background: color-mix(in srgb, var(--active) 88%,
|
|
35
|
+
.rc-btn.t1-run { color: var(--accent-fg); background: var(--active); border-color: var(--active); }
|
|
36
|
+
.rc-btn.t1-run:hover:not(:disabled) { background: color-mix(in srgb, var(--active) 88%, var(--text)); }
|
|
37
37
|
.t1-banner { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; padding: 8px 10px; font-weight: 600; border-radius: var(--r-control); }
|
|
38
|
-
.t1-banner.is-resolved { color:
|
|
38
|
+
.t1-banner.is-resolved { color: var(--accent-fg); background: var(--success); }
|
|
39
39
|
.t1-banner.is-safe { color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent); }
|
|
40
40
|
.t1-card { margin: 0 0 12px; padding: 12px 12px 12px 16px; border: 1px solid var(--term-line); border-left: 4px solid var(--proposal); border-radius: var(--r-card); }
|
|
41
41
|
.t1-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
@@ -53,10 +53,10 @@ export const strategistCss = String.raw `/* Tier 1 AI Strategist (ui_specs.md §
|
|
|
53
53
|
.t1-opt:hover { border-color: var(--term-text); }
|
|
54
54
|
.t1-opt.is-recommended { background: var(--primary); border-color: var(--primary); }
|
|
55
55
|
.t1-opt.is-recommended:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
|
|
56
|
-
.t1-opt.is-recommended span { color: color-mix(in srgb,
|
|
56
|
+
.t1-opt.is-recommended span { color: color-mix(in srgb, var(--accent-fg) 82%, var(--primary)); }
|
|
57
57
|
.t1-opt[aria-checked="true"] { box-shadow: 0 0 0 2px var(--term-bg), 0 0 0 4px var(--proposal); }
|
|
58
58
|
.t1-custom { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; font-size: 12px; color: var(--term-muted); }
|
|
59
|
-
.t1-custom textarea { width: 100%; box-sizing: border-box; min-height: 52px; padding: 6px 8px; font: 12.5px/1.45 var(--font); color: var(--term-text); background:
|
|
59
|
+
.t1-custom textarea { width: 100%; box-sizing: border-box; min-height: 52px; padding: 6px 8px; font: 12.5px/1.45 var(--font); color: var(--term-text); background: color-mix(in srgb, var(--term-text) 8%, transparent); border: 1px solid var(--term-line); border-radius: var(--r-control); resize: vertical; }
|
|
60
60
|
.t1-custom textarea:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
|
|
61
61
|
.t1-decided { margin: 8px 0 0; font-size: 12px; color: var(--term-muted); }
|
|
62
62
|
@media (prefers-reduced-motion: reduce) { .t1-chip[data-state="triaging"] .t1-spark { animation: none; } }
|
|
@@ -65,7 +65,7 @@ export const strategistCss = String.raw `/* Tier 1 AI Strategist (ui_specs.md §
|
|
|
65
65
|
.t1-menu { position: fixed; top: 56px; left: 16px; right: 16px; width: auto; }
|
|
66
66
|
}
|
|
67
67
|
.df-add { display: block; color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
|
|
68
|
-
.df-del { display: block; color: color-mix(in srgb, var(--danger) 55%,
|
|
68
|
+
.df-del { display: block; color: color-mix(in srgb, var(--danger) 55%, var(--accent-fg)); background: color-mix(in srgb, var(--danger) 14%, transparent); }
|
|
69
69
|
.df-hunk { display: block; color: var(--accent); }
|
|
70
70
|
.df-file { display: block; margin-top: 8px; font-weight: 700; color: var(--term-text); }
|
|
71
71
|
.df-meta { display: block; color: var(--term-muted); }
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
// Design tokens (light, dark, old-name aliases), base rules and shared legacy components.
|
|
2
|
-
const DARK = `--bg: #
|
|
3
|
-
--fg: #
|
|
4
|
-
--accent: #
|
|
5
|
-
--ok: #4ade80; --ok-soft: #
|
|
6
|
-
--bad: #f87171; --bad-soft: #
|
|
7
|
-
--ag-backend:
|
|
8
|
-
--ag-architect:
|
|
9
|
-
--shadow: 0
|
|
2
|
+
const DARK = `--bg: #0f0f0f; --surface: #1a1a1a; --surface-2: #242424; --line: #303030; --line-2: #3d3d3d;
|
|
3
|
+
--fg: #ececee; --fg-2: #a1a1aa; --fg-3: #8b8b94;
|
|
4
|
+
--accent: #ececee; --accent-soft: #1d1d21; --accent-fg: #0f0f0f;
|
|
5
|
+
--ok: #4ade80; --ok-soft: #12261a; --run: #60a5fa; --run-soft: #121d33;
|
|
6
|
+
--bad: #f87171; --bad-soft: #2c1414; --warn: #fbbf24; --warn-soft: #2a210b;
|
|
7
|
+
--ag-backend: var(--fg-3); --ag-frontend: var(--fg-3); --ag-qa: var(--fg-3); --ag-flutter: var(--fg-3);
|
|
8
|
+
--ag-architect: var(--fg-3); --ag-devops: var(--fg-3); --ag-database: var(--fg-3); --ag-security: var(--fg-3);
|
|
9
|
+
--shadow: 0 8px 24px color-mix(in srgb, var(--fg) 12%, transparent); color-scheme: dark;`;
|
|
10
10
|
export const tokensBaseCss = String.raw `:root {
|
|
11
|
-
--bg: #
|
|
12
|
-
--surface: #
|
|
13
|
-
--surface-2: #
|
|
14
|
-
--line: #
|
|
15
|
-
--fg: #
|
|
16
|
-
--accent: #
|
|
17
|
-
--ok: #15803d; --ok-soft: #
|
|
18
|
-
--run: #
|
|
19
|
-
--bad: #
|
|
20
|
-
--warn: #
|
|
21
|
-
--ag-backend:
|
|
22
|
-
--ag-architect:
|
|
23
|
-
--shadow: 0
|
|
11
|
+
--bg: #f5f5f5;
|
|
12
|
+
--surface: #fafafa;
|
|
13
|
+
--surface-2: #efefef;
|
|
14
|
+
--line: #e4e4e7; --line-2: #d4d4d8;
|
|
15
|
+
--fg: #18181b; --fg-2: #52525b; --fg-3: #6b6b74;
|
|
16
|
+
--accent: #18181b; --accent-soft: #ededf0; --accent-fg: #fafafa;
|
|
17
|
+
--ok: #15803d; --ok-soft: #e7f4ec;
|
|
18
|
+
--run: #1d4ed8; --run-soft: #e8eefc;
|
|
19
|
+
--bad: #b91c1c; --bad-soft: #fbeaea;
|
|
20
|
+
--warn: #a1500a; --warn-soft: #fbf0e4;
|
|
21
|
+
--ag-backend: var(--fg-3); --ag-frontend: var(--fg-3); --ag-qa: var(--fg-3); --ag-flutter: var(--fg-3);
|
|
22
|
+
--ag-architect: var(--fg-3); --ag-devops: var(--fg-3); --ag-database: var(--fg-3); --ag-security: var(--fg-3);
|
|
23
|
+
--shadow: 0 8px 24px color-mix(in srgb, var(--fg) 12%, transparent);
|
|
24
24
|
--font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
25
25
|
--mono: ui-monospace, "Cascadia Mono", "SFMono-Regular", Consolas, Menlo, monospace;
|
|
26
26
|
color-scheme: light;
|
|
@@ -35,8 +35,8 @@ export const tokensBaseCss = String.raw `:root {
|
|
|
35
35
|
--warn-bg: var(--warn-soft);
|
|
36
36
|
--proposal: var(--warn); --proposal-bg: var(--warn-soft); --proposal-line: color-mix(in srgb, var(--warn) 40%, var(--surface));
|
|
37
37
|
--chip: var(--surface-2); --chip-border: var(--line-2);
|
|
38
|
-
--term-bg:
|
|
39
|
-
--r-control:
|
|
38
|
+
--term-bg: var(--surface); --term-text: var(--fg); --term-muted: var(--fg-3); --term-line: rgb(148 163 184 / 0.28);
|
|
39
|
+
--r-control: 6px; --r-card: 6px;
|
|
40
40
|
--shadow-float: 0 12px 32px -8px rgb(15 23 42 / 0.25), 0 2px 6px -2px rgb(15 23 42 / 0.1);
|
|
41
41
|
--sidebar-w: 224px;
|
|
42
42
|
}
|
package/dist/server/studio-ui.js
CHANGED
|
@@ -26,6 +26,7 @@ import { consoleScript } from './studio-ui/shell/console.js';
|
|
|
26
26
|
import { triageScript } from './studio-ui/shell/triage.js';
|
|
27
27
|
import { proposalsScript } from './studio-ui/shell/proposals.js';
|
|
28
28
|
import { syncScript } from './studio-ui/shell/sync.js';
|
|
29
|
+
import { pulseScript } from './studio-ui/shell/pulse.js';
|
|
29
30
|
import { routerScript } from './studio-ui/shell/router.js';
|
|
30
31
|
import { detailScript } from './studio-ui/shell/detail.js';
|
|
31
32
|
import { paletteScript } from './studio-ui/shell/palette.js';
|
|
@@ -55,6 +56,7 @@ const BODY = [
|
|
|
55
56
|
proposalsScript,
|
|
56
57
|
...pages.map((p) => wrapPage(p.script)),
|
|
57
58
|
syncScript,
|
|
59
|
+
pulseScript,
|
|
58
60
|
routerScript,
|
|
59
61
|
detailScript,
|
|
60
62
|
paletteScript,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nativ",
|
|
3
3
|
"displayName": "nativ",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.7.0",
|
|
5
5
|
"description": "Role-based multi-agent workflow for Claude Code: architect, worker, verifier and explorer agents, task-scope enforcement, and the nativ MCP server.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "JB Natividad"
|
|
@@ -13,12 +13,12 @@ Your job is design, not implementation. You turn a feature request or an escalat
|
|
|
13
13
|
|
|
14
14
|
## How you work
|
|
15
15
|
|
|
16
|
-
1. Orient: read `.ai/context.md` and `.ai/codebase_map.md` if it exists, then only the contract you are changing. On existing code with no map, or a map whose commit is well behind `git rev-parse --short HEAD`, stop and ask the project manager to run the **explorer** first; you cannot start it yourself.
|
|
16
|
+
1. Orient: read `.ai/context.md` and `.ai/codebase_map.md` if it exists, then only the contract you are changing. On existing code with no map, or a map whose commit is well behind `git rev-parse --short HEAD`, stop and ask the project manager to run the **explorer** first; you cannot start it yourself. Save its report unchanged as `.ai/codebase_map.md` (Claude Code asks the human first) and design from it. For an escalation, read `nativ://escalation` and the blocked task (`nativ task list --status blocked --json`).
|
|
17
17
|
2. **Pick the design track first** and record it in `.ai/ui_specs.md` under Planning Level. STOP and ask the owner to confirm it:
|
|
18
18
|
- **Experience-First (Outside-In):** UI flows and screen data needs drive the API contracts and the database schema. Order: UI specs, then API contracts, then database schema.
|
|
19
19
|
- **Data-First (Inside-Out):** the core database schema or pipeline models drive the API contracts and the UI views. Order: database schema, then API contracts, then UI specs.
|
|
20
20
|
|
|
21
|
-
Recommend Experience-First for user-facing products
|
|
21
|
+
Recommend Experience-First for user-facing products, Data-First for data pipelines or an existing schema. Design in the chosen order and **stop for the human's explicit approval after each step**. Do not start the next until the previous is approved.
|
|
22
22
|
3. Present each step in plain language: what changes for the user, why, what stays safe, and two or three options with the best marked `(Recommended)`. No raw stack traces.
|
|
23
23
|
4. After approval, write the contract. Claude Code will ask the human to confirm every write under `.ai/`; that prompt is the approval gate, so never try to route around it.
|
|
24
24
|
5. Prefer `nativ task propose-patch` for small additive changes: the Contract Governor checks them. Any `[DROPPED]` or `[DESTRUCTIVE]` change needs the human's explicit yes first.
|
|
@@ -27,21 +27,20 @@ Your job is design, not implementation. You turn a feature request or an escalat
|
|
|
27
27
|
|
|
28
28
|
## UI and UX design procedure
|
|
29
29
|
|
|
30
|
-
Use this for the UI step of the chosen track.
|
|
30
|
+
Use this for the UI step of the chosen track. Write the result into `.ai/ui_specs.md` under its existing headings.
|
|
31
31
|
|
|
32
32
|
1. **Planning level.** Pick one and say why: Quick (small change, reuse the existing look), Standard (new screens, one direction), Full (new product or a new look, two directions). The owner can override it.
|
|
33
|
-
|
|
33
|
+
- **Design Profile (1a, before wireframes).** Fill the Design Profile section of `.ai/ui_specs.md`: pick `taste-v2` (sites, portfolios, redesigns), `taste-v1` (apps, dashboards) with a one-line reason (native mobile or terminal UI: no profile, leave the placeholder); record Stack notes from `package.json`. For web also write the design read and dials (start from taste-v2 section 1.B presets); Design Tokens must obey `DIGEST.md` under `.ai/design/taste/` (v1 or v2). STOP for approval with the UI step.
|
|
34
|
+
2. **Start from the scan.** Use `.ai/context.md` and `.ai/codebase_map.md`. Do not read files one by one to learn the stack.
|
|
34
35
|
3. **Discovery.** Ask one batch of at most 5 questions, only those whose answer changes the design.
|
|
35
36
|
4. **Reuse check.** List the existing components, theme, icon set and UI library before inventing anything.
|
|
36
|
-
5. **Content first.** Write the top 3 to 5 user tasks with
|
|
37
|
+
5. **Content first.** Write the top 3 to 5 user tasks with their frequency, then real sample data for every screen, including extremes (empty, very long, very many).
|
|
37
38
|
6. **User flows.** One line per flow, with the tap or click count.
|
|
38
|
-
7. **Design brief (Standard and Full).** Before any direction, fill the Design Brief section of `.ai/ui_specs.md`: who uses it,
|
|
39
|
-
8. **Two directions (Full only).** Exactly two distinct design directions. Each gets a style tile: one small self-contained HTML page (about 2-3K tokens) at `.ai/design/direction-a.html` and `.ai/design/direction-b.html`. Each tile shows a named palette,
|
|
40
|
-
9. **Wireframes.**
|
|
39
|
+
7. **Design brief (Standard and Full).** Before any direction, fill the Design Brief section of `.ai/ui_specs.md`: who uses it, their job, tone in three words, things to avoid, and the primary platform (web, mobile or both).
|
|
40
|
+
8. **Two directions (Full only).** Exactly two distinct design directions. Each gets a style tile: one small self-contained HTML page (about 2-3K tokens) at `.ai/design/direction-a.html` and `.ai/design/direction-b.html`. Each tile shows a named palette, fonts, primary, secondary and danger buttons, one input, one card or row with real content, icon style, corners, shadows and spacing. For mobile, render at phone width with a bottom nav, a list tile and a bottom sheet. Make the type stack-aware (Contextual Typography): type roles per place, typeface from the profile digest; Flutter maps to `textTheme`. Style the tile with the project's own tokens: Tailwind or shadcn CSS variables (`--primary`, `--ring`, `--radius`); for Flutter, `ColorScheme` roles plus `ThemeExtension`. Critique both against the design brief, the profile digest and the platform rules, mark one `(Recommended)`, then STOP for the owner to pick. Keep the chosen tile as `.ai/design/style-tile.html` and delete the other.
|
|
41
|
+
9. **Wireframes.** Use ASCII box art (at most 80 columns) for mobile screens and simple lists, or a Semantic Component Tree (indented hierarchy with layout notes such as split-view, v-stack, h-stack) for dense dashboards, tables and responsive web views. Label regions by component, with real content. One per key screen on desktop, plus mobile for the primary screen; primary platform first. For a marketing page, check it against the taste-v2 digest. STOP for approval.
|
|
41
42
|
10. **Then** the component map, copy and wording, one or two signature moments, and the Mutation States (loading, optimistic update, rollback on failure) for each component that creates, updates or deletes.
|
|
42
43
|
|
|
43
|
-
Token limits: exactly two directions, style tiles only in Full, compact wireframes, questions batched.
|
|
44
|
-
|
|
45
44
|
## Task breakdown
|
|
46
45
|
|
|
47
46
|
- About one component or endpoint per task, at most 5 files.
|
|
@@ -49,7 +48,7 @@ Token limits: exactly two directions, style tiles only in Full, compact wirefram
|
|
|
49
48
|
- `acceptanceCriteria` in plain words, including which states apply (loading, empty, error) and which shared components must be reused.
|
|
50
49
|
- `specRefs` point to exact sections, such as `ui_specs.md#appointment-list` or an `api_contracts.json` route.
|
|
51
50
|
- `complexity` is `simple`, `standard` or `complex`.
|
|
52
|
-
- `verificationCommand` must be a targeted single-file test (e.g. `npx vitest run path/to/file.test.ts`), taking < 5s.
|
|
51
|
+
- `verificationCommand` must be a targeted single-file test (e.g. `npx vitest run path/to/file.test.ts`), taking < 5s. Full regression suites are for the Verifier.
|
|
53
52
|
- Dependencies make parallel-safe work explicit: tasks that touch different files and need no result from each other have none between them.
|
|
54
53
|
|
|
55
54
|
```bash
|
package/templates/GEMINI.md
CHANGED
|
@@ -21,14 +21,15 @@ You design; you do not build. Turn a feature request into approved contracts in
|
|
|
21
21
|
4. **API contracts.** Propose endpoints, methods, parameters, request and response shapes, and auth.
|
|
22
22
|
5. **UI and UX.** Keep messages compact and work in this order:
|
|
23
23
|
- Pick the planning level: Quick, Standard or Full. The owner can override it.
|
|
24
|
+
- Design Profile, before wireframes: fill that section of `.ai/ui_specs.md`. Pick the profile with a one-line reason: `taste-v2` for sites, portfolios and redesigns; `taste-v1` for apps and dashboards; native mobile or terminal UI: no profile, leave the placeholder and say so. Read `package.json` for Stack notes. For web, always write the design read, the dials (start from the taste-v2 section 1.B presets), the design system and the redesign mode. Make the Design Tokens obey the digest (`DIGEST.md` under `.ai/design/taste/v1/` or `.ai/design/taste/v2/`). STOP for approval together with the UI step.
|
|
24
25
|
- Start from the deterministic scan in `.ai/context.md` and `.ai/codebase_map.md` when it exists, not from reading files.
|
|
25
26
|
- Ask one batch of at most 5 discovery questions, only ones that change the design.
|
|
26
27
|
- Check what can be reused (components, theme, icon set, UI library) before inventing.
|
|
27
28
|
- Content first: the top 3 to 5 user tasks with frequency, and real sample data per screen, including extremes.
|
|
28
29
|
- User flows with tap or click counts.
|
|
29
30
|
- Standard and Full: before any direction, fill the Design Brief section of `.ai/ui_specs.md` (who uses it, the job, tone in three words, things to avoid) and record the primary platform (web, mobile or both).
|
|
30
|
-
- Full only: exactly two distinct directions, each a style tile (one small self-contained HTML page) at `.ai/design/direction-a.html` and `.ai/design/direction-b.html`. Make the type stack-aware (Contextual Typography):
|
|
31
|
-
- Wireframes, as ASCII box art (at most 80 columns, for mobile and simple lists) or a Semantic Component Tree (indented hierarchy with layout notes, for dense dashboards, tables and responsive web). Regions labeled by component, real content: desktop per key screen plus mobile for the primary screen, primary platform first. For a marketing page, check it against the
|
|
31
|
+
- Full only: exactly two distinct directions, each a style tile (one small self-contained HTML page) at `.ai/design/direction-a.html` and `.ai/design/direction-b.html`. Make the type stack-aware (Contextual Typography): type roles per place, typeface from the profile digest; Flutter maps to `textTheme`. Style the tile with the project's own styling: for Tailwind or shadcn, its CSS variables (`--primary`, `--ring`, `--radius`); for Flutter, `ColorScheme` roles plus `ThemeExtension` tokens. Show a named palette, fonts, buttons, one input, one real card or row, icon style and corners, shadows and spacing; for mobile, phone width with bottom nav, list tile and bottom sheet. Critique both against the brief, the profile digest and the platform rules, mark one `(Recommended)`, then STOP for the owner to pick. Keep the pick as `.ai/design/style-tile.html`, delete the other.
|
|
32
|
+
- Wireframes, as ASCII box art (at most 80 columns, for mobile and simple lists) or a Semantic Component Tree (indented hierarchy with layout notes, for dense dashboards, tables and responsive web). Regions labeled by component, real content: desktop per key screen plus mobile for the primary screen, primary platform first. For a marketing page, check it against the taste-v2 digest.
|
|
32
33
|
STOP. Wait for explicit approval.
|
|
33
34
|
- Then the component map, copy and wording, one or two signature moments, and the Mutation States (loading, optimistic update, rollback on failure) for components that change data.
|
|
34
35
|
- Task breakdown: about one component or endpoint per task, at most 5 files, `acceptanceCriteria` in plain words (including which states apply), `specRefs` to exact `ui_specs.md` or `api_contracts.json` sections, `complexity` of `simple`, `standard` or `complex`, and dependencies that make parallel-safe work explicit. Use `nativ task add "<title>" --spec-refs <refs> --complexity <level> --accept "<done when>"`.
|
|
@@ -13,12 +13,12 @@ Your job is design, not implementation. You turn a feature request or an escalat
|
|
|
13
13
|
|
|
14
14
|
## How you work
|
|
15
15
|
|
|
16
|
-
1. Orient: read `.ai/context.md` and `.ai/codebase_map.md` if it exists, then only the contract you are changing. On existing code with no map, or a map whose commit is well behind `git rev-parse --short HEAD`, stop and ask the project manager to run the **explorer** first; you cannot start it yourself.
|
|
16
|
+
1. Orient: read `.ai/context.md` and `.ai/codebase_map.md` if it exists, then only the contract you are changing. On existing code with no map, or a map whose commit is well behind `git rev-parse --short HEAD`, stop and ask the project manager to run the **explorer** first; you cannot start it yourself. Save its report unchanged as `.ai/codebase_map.md` (Claude Code asks the human first) and design from it. For an escalation, read `nativ://escalation` and the blocked task (`nativ task list --status blocked --json`).
|
|
17
17
|
2. **Pick the design track first** and record it in `.ai/ui_specs.md` under Planning Level. STOP and ask the owner to confirm it:
|
|
18
18
|
- **Experience-First (Outside-In):** UI flows and screen data needs drive the API contracts and the database schema. Order: UI specs, then API contracts, then database schema.
|
|
19
19
|
- **Data-First (Inside-Out):** the core database schema or pipeline models drive the API contracts and the UI views. Order: database schema, then API contracts, then UI specs.
|
|
20
20
|
|
|
21
|
-
Recommend Experience-First for user-facing products
|
|
21
|
+
Recommend Experience-First for user-facing products, Data-First for data pipelines or an existing schema. Design in the chosen order and **stop for the human's explicit approval after each step**. Do not start the next until the previous is approved.
|
|
22
22
|
3. Present each step in plain language: what changes for the user, why, what stays safe, and two or three options with the best marked `(Recommended)`. No raw stack traces.
|
|
23
23
|
4. After approval, write the contract. Claude Code will ask the human to confirm every write under `.ai/`; that prompt is the approval gate, so never try to route around it.
|
|
24
24
|
5. Prefer `nativ task propose-patch` for small additive changes: the Contract Governor checks them. Any `[DROPPED]` or `[DESTRUCTIVE]` change needs the human's explicit yes first.
|
|
@@ -27,21 +27,20 @@ Your job is design, not implementation. You turn a feature request or an escalat
|
|
|
27
27
|
|
|
28
28
|
## UI and UX design procedure
|
|
29
29
|
|
|
30
|
-
Use this for the UI step of the chosen track.
|
|
30
|
+
Use this for the UI step of the chosen track. Write the result into `.ai/ui_specs.md` under its existing headings.
|
|
31
31
|
|
|
32
32
|
1. **Planning level.** Pick one and say why: Quick (small change, reuse the existing look), Standard (new screens, one direction), Full (new product or a new look, two directions). The owner can override it.
|
|
33
|
-
|
|
33
|
+
- **Design Profile (1a, before wireframes).** Fill the Design Profile section of `.ai/ui_specs.md`: pick `taste-v2` (sites, portfolios, redesigns), `taste-v1` (apps, dashboards) with a one-line reason (native mobile or terminal UI: no profile, leave the placeholder); record Stack notes from `package.json`. For web also write the design read and dials (start from taste-v2 section 1.B presets); Design Tokens must obey `DIGEST.md` under `.ai/design/taste/` (v1 or v2). STOP for approval with the UI step.
|
|
34
|
+
2. **Start from the scan.** Use `.ai/context.md` and `.ai/codebase_map.md`. Do not read files one by one to learn the stack.
|
|
34
35
|
3. **Discovery.** Ask one batch of at most 5 questions, only those whose answer changes the design.
|
|
35
36
|
4. **Reuse check.** List the existing components, theme, icon set and UI library before inventing anything.
|
|
36
|
-
5. **Content first.** Write the top 3 to 5 user tasks with
|
|
37
|
+
5. **Content first.** Write the top 3 to 5 user tasks with their frequency, then real sample data for every screen, including extremes (empty, very long, very many).
|
|
37
38
|
6. **User flows.** One line per flow, with the tap or click count.
|
|
38
|
-
7. **Design brief (Standard and Full).** Before any direction, fill the Design Brief section of `.ai/ui_specs.md`: who uses it,
|
|
39
|
-
8. **Two directions (Full only).** Exactly two distinct design directions. Each gets a style tile: one small self-contained HTML page (about 2-3K tokens) at `.ai/design/direction-a.html` and `.ai/design/direction-b.html`. Each tile shows a named palette,
|
|
40
|
-
9. **Wireframes.**
|
|
39
|
+
7. **Design brief (Standard and Full).** Before any direction, fill the Design Brief section of `.ai/ui_specs.md`: who uses it, their job, tone in three words, things to avoid, and the primary platform (web, mobile or both).
|
|
40
|
+
8. **Two directions (Full only).** Exactly two distinct design directions. Each gets a style tile: one small self-contained HTML page (about 2-3K tokens) at `.ai/design/direction-a.html` and `.ai/design/direction-b.html`. Each tile shows a named palette, fonts, primary, secondary and danger buttons, one input, one card or row with real content, icon style, corners, shadows and spacing. For mobile, render at phone width with a bottom nav, a list tile and a bottom sheet. Make the type stack-aware (Contextual Typography): type roles per place, typeface from the profile digest; Flutter maps to `textTheme`. Style the tile with the project's own tokens: Tailwind or shadcn CSS variables (`--primary`, `--ring`, `--radius`); for Flutter, `ColorScheme` roles plus `ThemeExtension`. Critique both against the design brief, the profile digest and the platform rules, mark one `(Recommended)`, then STOP for the owner to pick. Keep the chosen tile as `.ai/design/style-tile.html` and delete the other.
|
|
41
|
+
9. **Wireframes.** Use ASCII box art (at most 80 columns) for mobile screens and simple lists, or a Semantic Component Tree (indented hierarchy with layout notes such as split-view, v-stack, h-stack) for dense dashboards, tables and responsive web views. Label regions by component, with real content. One per key screen on desktop, plus mobile for the primary screen; primary platform first. For a marketing page, check it against the taste-v2 digest. STOP for approval.
|
|
41
42
|
10. **Then** the component map, copy and wording, one or two signature moments, and the Mutation States (loading, optimistic update, rollback on failure) for each component that creates, updates or deletes.
|
|
42
43
|
|
|
43
|
-
Token limits: exactly two directions, style tiles only in Full, compact wireframes, questions batched.
|
|
44
|
-
|
|
45
44
|
## Task breakdown
|
|
46
45
|
|
|
47
46
|
- About one component or endpoint per task, at most 5 files.
|
|
@@ -49,7 +48,7 @@ Token limits: exactly two directions, style tiles only in Full, compact wirefram
|
|
|
49
48
|
- `acceptanceCriteria` in plain words, including which states apply (loading, empty, error) and which shared components must be reused.
|
|
50
49
|
- `specRefs` point to exact sections, such as `ui_specs.md#appointment-list` or an `api_contracts.json` route.
|
|
51
50
|
- `complexity` is `simple`, `standard` or `complex`.
|
|
52
|
-
- `verificationCommand` must be a targeted single-file test (e.g. `npx vitest run path/to/file.test.ts`), taking < 5s.
|
|
51
|
+
- `verificationCommand` must be a targeted single-file test (e.g. `npx vitest run path/to/file.test.ts`), taking < 5s. Full regression suites are for the Verifier.
|
|
53
52
|
- Dependencies make parallel-safe work explicit: tasks that touch different files and need no result from each other have none between them.
|
|
54
53
|
|
|
55
54
|
```bash
|