@njeybe/nativ 2.1.0 → 2.3.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 +24 -1
- package/README.md +17 -0
- package/dist/server/studio-ui/document.d.ts +3 -0
- package/dist/server/studio-ui/document.js +22 -0
- package/dist/server/studio-ui/pages/benchmarks/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/benchmarks/index.js +11 -0
- package/dist/server/studio-ui/pages/benchmarks/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/benchmarks/script.js +104 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/benchmarks/styles.js +30 -0
- package/dist/server/studio-ui/pages/database/browser.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/browser.js +326 -0
- package/dist/server/studio-ui/pages/database/connection.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/connection.js +158 -0
- package/dist/server/studio-ui/pages/database/data-shell.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/data-shell.js +165 -0
- package/dist/server/studio-ui/pages/database/drift.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/drift.js +301 -0
- package/dist/server/studio-ui/pages/database/events.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/events.js +231 -0
- package/dist/server/studio-ui/pages/database/explorer.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/explorer.js +183 -0
- package/dist/server/studio-ui/pages/database/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/database/index.js +28 -0
- package/dist/server/studio-ui/pages/database/markup.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/markup.js +32 -0
- package/dist/server/studio-ui/pages/database/state.d.ts +2 -0
- package/dist/server/studio-ui/pages/database/state.js +57 -0
- package/dist/server/studio-ui/pages/database/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/database/styles.js +118 -0
- package/dist/server/studio-ui/pages/flow/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/flow/index.js +11 -0
- package/dist/server/studio-ui/pages/flow/layout.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/layout.js +105 -0
- package/dist/server/studio-ui/pages/flow/plan-view.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/plan-view.js +67 -0
- package/dist/server/studio-ui/pages/flow/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/script.js +61 -0
- package/dist/server/studio-ui/pages/flow/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/styles.js +59 -0
- package/dist/server/studio-ui/pages/flow/timeline-model.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/timeline-model.js +95 -0
- package/dist/server/studio-ui/pages/flow/timeline-view.d.ts +1 -0
- package/dist/server/studio-ui/pages/flow/timeline-view.js +92 -0
- package/dist/server/studio-ui/pages/home/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/home/index.js +11 -0
- package/dist/server/studio-ui/pages/home/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/home/script.js +160 -0
- package/dist/server/studio-ui/pages/home/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/home/styles.js +48 -0
- package/dist/server/studio-ui/pages/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/index.js +17 -0
- package/dist/server/studio-ui/pages/tasks/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/tasks/index.js +11 -0
- package/dist/server/studio-ui/pages/tasks/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/tasks/script.js +96 -0
- package/dist/server/studio-ui/pages/tasks/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/tasks/styles.js +37 -0
- package/dist/server/studio-ui/pages/team/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/team/index.js +11 -0
- package/dist/server/studio-ui/pages/team/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/team/script.js +112 -0
- package/dist/server/studio-ui/pages/team/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/team/styles.js +22 -0
- package/dist/server/studio-ui/pages/types.d.ts +13 -0
- package/dist/server/studio-ui/pages/types.js +1 -0
- package/dist/server/studio-ui/pages/worktrees/index.d.ts +2 -0
- package/dist/server/studio-ui/pages/worktrees/index.js +11 -0
- package/dist/server/studio-ui/pages/worktrees/script.d.ts +1 -0
- package/dist/server/studio-ui/pages/worktrees/script.js +104 -0
- package/dist/server/studio-ui/pages/worktrees/styles.d.ts +1 -0
- package/dist/server/studio-ui/pages/worktrees/styles.js +15 -0
- package/dist/server/studio-ui/shell/actions.d.ts +1 -0
- package/dist/server/studio-ui/shell/actions.js +49 -0
- package/dist/server/studio-ui/shell/boot.d.ts +2 -0
- package/dist/server/studio-ui/shell/boot.js +13 -0
- package/dist/server/studio-ui/shell/console.d.ts +1 -0
- package/dist/server/studio-ui/shell/console.js +194 -0
- package/dist/server/studio-ui/shell/core.d.ts +1 -0
- package/dist/server/studio-ui/shell/core.js +50 -0
- package/dist/server/studio-ui/shell/detail-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/detail-view.js +80 -0
- package/dist/server/studio-ui/shell/detail.d.ts +1 -0
- package/dist/server/studio-ui/shell/detail.js +83 -0
- package/dist/server/studio-ui/shell/dispatch.d.ts +1 -0
- package/dist/server/studio-ui/shell/dispatch.js +156 -0
- package/dist/server/studio-ui/shell/events-tools.d.ts +1 -0
- package/dist/server/studio-ui/shell/events-tools.js +94 -0
- package/dist/server/studio-ui/shell/format.d.ts +1 -0
- package/dist/server/studio-ui/shell/format.js +151 -0
- package/dist/server/studio-ui/shell/icons.d.ts +2 -0
- package/dist/server/studio-ui/shell/icons.js +20 -0
- package/dist/server/studio-ui/shell/markup-head.d.ts +1 -0
- package/dist/server/studio-ui/shell/markup-head.js +43 -0
- package/dist/server/studio-ui/shell/markup-panels.d.ts +2 -0
- package/dist/server/studio-ui/shell/markup-panels.js +7 -0
- package/dist/server/studio-ui/shell/markup-tools.d.ts +1 -0
- package/dist/server/studio-ui/shell/markup-tools.js +222 -0
- package/dist/server/studio-ui/shell/model.d.ts +1 -0
- package/dist/server/studio-ui/shell/model.js +192 -0
- package/dist/server/studio-ui/shell/paint.d.ts +1 -0
- package/dist/server/studio-ui/shell/paint.js +154 -0
- package/dist/server/studio-ui/shell/palette-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/palette-view.js +60 -0
- package/dist/server/studio-ui/shell/palette.d.ts +1 -0
- package/dist/server/studio-ui/shell/palette.js +80 -0
- package/dist/server/studio-ui/shell/pipeline-state.d.ts +1 -0
- package/dist/server/studio-ui/shell/pipeline-state.js +152 -0
- package/dist/server/studio-ui/shell/proposals.d.ts +1 -0
- package/dist/server/studio-ui/shell/proposals.js +197 -0
- package/dist/server/studio-ui/shell/pure.d.ts +3 -0
- package/dist/server/studio-ui/shell/pure.js +9 -0
- package/dist/server/studio-ui/shell/router.d.ts +1 -0
- package/dist/server/studio-ui/shell/router.js +95 -0
- package/dist/server/studio-ui/shell/sidebar-view.d.ts +1 -0
- package/dist/server/studio-ui/shell/sidebar-view.js +38 -0
- package/dist/server/studio-ui/shell/sync.d.ts +1 -0
- package/dist/server/studio-ui/shell/sync.js +120 -0
- package/dist/server/studio-ui/shell/toasts-format.d.ts +1 -0
- package/dist/server/studio-ui/shell/toasts-format.js +89 -0
- package/dist/server/studio-ui/shell/triage.d.ts +1 -0
- package/dist/server/studio-ui/shell/triage.js +210 -0
- package/dist/server/studio-ui/styles/console.d.ts +1 -0
- package/dist/server/studio-ui/styles/console.js +83 -0
- package/dist/server/studio-ui/styles/dialogs.d.ts +1 -0
- package/dist/server/studio-ui/styles/dialogs.js +118 -0
- package/dist/server/studio-ui/styles/responsive.d.ts +1 -0
- package/dist/server/studio-ui/styles/responsive.js +28 -0
- package/dist/server/studio-ui/styles/shell.d.ts +1 -0
- package/dist/server/studio-ui/styles/shell.js +117 -0
- package/dist/server/studio-ui/styles/strategist.d.ts +1 -0
- package/dist/server/studio-ui/styles/strategist.js +77 -0
- package/dist/server/studio-ui/styles/tokens-base.d.ts +1 -0
- package/dist/server/studio-ui/styles/tokens-base.js +131 -0
- package/dist/server/studio-ui.d.ts +1 -10
- package/dist/server/studio-ui.js +63 -5314
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/agents/architect.md +9 -5
- package/templates/GEMINI.md +12 -8
- package/templates/claude-agents/architect.md +9 -5
- package/templates/dot-ai/subagents/flutter-developer.md +10 -0
- package/templates/dot-ai/subagents/frontend.md +10 -0
- package/templates/dot-ai/ui_specs.md +36 -6
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ICON_PATHS } from './icons.js';
|
|
2
|
+
const svg = (name) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${ICON_PATHS[name]}</svg>`;
|
|
3
|
+
// Document head close, sidebar frame and top bar (needs version and project name).
|
|
4
|
+
export function markupHead(version, projectName, projectHidden) {
|
|
5
|
+
return String.raw `</head>
|
|
6
|
+
<body>
|
|
7
|
+
<div class="toast-host" id="toasts" role="status" aria-live="polite"></div>
|
|
8
|
+
|
|
9
|
+
<div class="app">
|
|
10
|
+
<aside class="side" aria-label="Studio navigation">
|
|
11
|
+
<div class="brand"><span class="logo">N</span><b>Nativ Studio</b><span class="ver">v${version}</span></div>
|
|
12
|
+
<div id="side-nav"></div>
|
|
13
|
+
<div class="side-foot">
|
|
14
|
+
<span class="foot-project" id="project-name"${projectHidden}>${projectName}</span>
|
|
15
|
+
<div id="side-foot"></div>
|
|
16
|
+
</div>
|
|
17
|
+
</aside>
|
|
18
|
+
|
|
19
|
+
<div class="main">
|
|
20
|
+
<header class="top">
|
|
21
|
+
<span class="crumb">Studio / <b id="crumb-view">Home</b></span>
|
|
22
|
+
<div class="top-right">
|
|
23
|
+
<button class="btn" id="btn-find" type="button" aria-keyshortcuts="Control+K Meta+K">${svg('search')}<span>Find task</span><span class="kbd">Ctrl K</span></button>
|
|
24
|
+
<div class="t1" id="t1">
|
|
25
|
+
<button class="t1-chip" id="t1-chip" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="t1-menu" data-state="idle" title="Tier 1 AI Strategist"><svg class="icon t1-spark" width="14" height="14" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 1.5l1.6 4.9 4.9 1.6-4.9 1.6L8 14.5l-1.6-4.9L1.5 8l4.9-1.6z"/></svg><span class="t1-chip-label">Tier 1 AI:</span><span class="t1-chip-model" id="t1-chip-model">Gemini 3.8 Flash</span><svg class="icon t1-caret" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg></button>
|
|
26
|
+
<div class="t1-menu" id="t1-menu" role="dialog" aria-label="Tier 1 AI Strategist" tabindex="-1" hidden>
|
|
27
|
+
<div class="t1-row"><span>Active model</span><code id="t1-model">gemini-3.8-flash</code></div>
|
|
28
|
+
<div class="t1-row"><span>Last evaluation</span><b id="t1-latency">No evaluations yet</b></div>
|
|
29
|
+
<div class="t1-row"><span>Gemini API key</span><b id="t1-key">Checking</b></div>
|
|
30
|
+
<div class="t1-row"><span id="t1-auto-label">Autonomous Auto-Triage</span><button class="t1-switch" id="t1-auto" type="button" role="switch" aria-checked="false" aria-labelledby="t1-auto-label" title="When on, fixes Tier 1 proves safe are applied without asking" disabled>OFF</button></div>
|
|
31
|
+
<p class="t1-policy"><svg class="icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 1.8l5.2 2.1v3.7c0 3.1-2.2 5.6-5.2 6.6-3-1-5.2-3.5-5.2-6.6V3.9z"/><path d="M5.6 8.1l1.7 1.7 3.2-3.3"/></svg>Always halts on destructive database operations & major API contract breaks.</p>
|
|
32
|
+
<dl class="t1-stats"><div><dt>Evaluated</dt><dd id="t1-evaluated">0</dd></div><div><dt>Auto-resolved</dt><dd id="t1-resolved">0</dd></div><div><dt>Human-escalated</dt><dd id="t1-human">0</dd></div></dl>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<button class="btn ghost" id="btn-theme" type="button" title="Switch light or dark" aria-label="Switch light or dark">${svg('sun')}</button>
|
|
36
|
+
<span class="live" id="live" data-state="connecting" role="status" aria-live="polite"><i class="live-dot" id="live-dot" aria-hidden="true"></i><span id="live-label">Connecting</span></span>
|
|
37
|
+
</div>
|
|
38
|
+
</header>
|
|
39
|
+
<p class="banner" id="banner" role="alert" hidden>Studio lost contact with nativ. Retrying. <button class="btn small" id="banner-retry" type="button">Retry</button></p>
|
|
40
|
+
|
|
41
|
+
<main class="page" id="main" tabindex="-1">
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { escapeHtml } from '../document.js';
|
|
2
|
+
// One hidden section per registered page; the shell fills them on first paint.
|
|
3
|
+
export function markupPanels(pages) {
|
|
4
|
+
return pages
|
|
5
|
+
.map((p) => ` <section class="page-view" id="panel-${p.id}" aria-label="${escapeHtml(p.label)}" hidden>\n${p.markup ?? ''} </section>\n`)
|
|
6
|
+
.join('');
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const markupTools: string;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// Console drawer, dialogs and other shell overlays.
|
|
2
|
+
export const markupTools = String.raw `</main>
|
|
3
|
+
</div>
|
|
4
|
+
</div>
|
|
5
|
+
<div class="scrim" id="scrim" hidden></div>
|
|
6
|
+
<aside class="drawer" id="task-drawer" role="dialog" aria-label="Task details" aria-modal="true" tabindex="-1" hidden></aside>
|
|
7
|
+
<div class="pal-wrap" id="pal" hidden></div>
|
|
8
|
+
|
|
9
|
+
<section id="runner-console-drawer" aria-labelledby="rc-task" hidden>
|
|
10
|
+
<header class="rc-head">
|
|
11
|
+
<code class="rc-task" id="rc-task">–</code>
|
|
12
|
+
<span class="rc-title" id="rc-title"></span>
|
|
13
|
+
<ol class="rc-steps" id="rc-steps" aria-label="Runner lifecycle"></ol>
|
|
14
|
+
<div class="rc-controls">
|
|
15
|
+
<button class="rc-btn" type="button" id="rc-autoscroll" aria-pressed="true" aria-label="Toggle console auto-scroll">Auto-scroll</button>
|
|
16
|
+
<button class="rc-btn" type="button" id="rc-clear" aria-label="Clear the console buffer">Clear</button>
|
|
17
|
+
<button class="rc-btn danger" type="button" id="rc-abort" aria-label="Abort the running agent">Abort</button>
|
|
18
|
+
<button class="rc-btn" type="button" id="rc-minimize" aria-expanded="true" aria-controls="rc-body">Minimize</button>
|
|
19
|
+
<button class="rc-btn" type="button" id="rc-close" aria-label="Close the runner console">Close</button>
|
|
20
|
+
</div>
|
|
21
|
+
</header>
|
|
22
|
+
<div class="rc-tabs" role="tablist" aria-label="Console views">
|
|
23
|
+
<button class="rc-tab" type="button" role="tab" id="rc-tab-logs" data-rc-tab="logs" aria-controls="rc-body" aria-selected="true"><svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4.5l3.5 3.5L3 11.5M8.5 12h4.5"/></svg>Live Logs</button>
|
|
24
|
+
<button class="rc-tab" type="button" role="tab" id="rc-tab-diff" data-rc-tab="diff" aria-controls="rc-diff" aria-selected="false" tabindex="-1"><svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M5 2.5v6M2 5.5h6M8.5 12.5h5.5"/></svg>Worktree Changes <span class="rc-count" id="rc-diff-count">–</span></button>
|
|
25
|
+
<button class="rc-tab" type="button" role="tab" id="rc-tab-heal" data-rc-tab="heal" aria-controls="rc-heal" aria-selected="false" tabindex="-1" hidden><svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 1.8l5.2 2.1v3.7c0 3.1-2.2 5.6-5.2 6.6-3-1-5.2-3.5-5.2-6.6V3.9z"/><path d="M5.6 8.1l1.7 1.7 3.2-3.3"/></svg>Self-Healing Proposal <span class="rc-count is-proposal" id="rc-heal-count">1</span></button>
|
|
26
|
+
</div>
|
|
27
|
+
<pre class="rc-body" id="rc-body" role="log" aria-live="polite" aria-label="Runner output" tabindex="0"></pre>
|
|
28
|
+
<div class="rc-diff" id="rc-diff" role="tabpanel" aria-labelledby="rc-tab-diff" hidden>
|
|
29
|
+
<div class="rc-diff-bar">
|
|
30
|
+
<span id="rc-diff-summary">Uncommitted changes in the task worktree</span>
|
|
31
|
+
<button class="rc-btn" type="button" id="rc-diff-refresh" aria-label="Reload the worktree diff">Reload Diff</button>
|
|
32
|
+
</div>
|
|
33
|
+
<ul class="rc-files" id="rc-diff-files" aria-label="Changed files"></ul>
|
|
34
|
+
<pre class="rc-diff-body" id="rc-diff-body" aria-label="Unified diff" tabindex="0"></pre>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="rc-heal" id="rc-heal" role="tabpanel" aria-labelledby="rc-tab-heal" tabindex="0" hidden></div>
|
|
37
|
+
<footer class="rc-foot">
|
|
38
|
+
<span>Elapsed <strong id="rc-elapsed">00:00</strong></span>
|
|
39
|
+
<span>Output <strong id="rc-bytes">0 B</strong></span>
|
|
40
|
+
<span id="rc-spend-wrap" hidden>Spend <strong id="rc-spend">$0.0000</strong></span>
|
|
41
|
+
<span id="rc-cache-wrap" hidden>Cache hit <strong id="rc-cache">0%</strong></span>
|
|
42
|
+
<span>Gatekeeper <strong id="rc-gate">Idle</strong></span>
|
|
43
|
+
<span id="rc-exit"></span>
|
|
44
|
+
</footer>
|
|
45
|
+
</section>
|
|
46
|
+
|
|
47
|
+
<dialog id="dispatch-dialog" aria-labelledby="dispatch-title" aria-describedby="dispatch-lead">
|
|
48
|
+
<form class="modal" method="dialog" id="dispatch-form">
|
|
49
|
+
<h2 id="dispatch-title">Dispatch Task</h2>
|
|
50
|
+
<p class="lead" id="dispatch-lead">Hands the task to an autonomous Claude runner. Output, token spend and gatekeeper results stream into the console drawer.</p>
|
|
51
|
+
<div class="dispatch-task">
|
|
52
|
+
<div class="dispatch-task-head"><code class="tcard-id" id="dispatch-task-id">task</code><span class="badge badge-agent" id="dispatch-agent">agent</span></div>
|
|
53
|
+
<h3 id="dispatch-task-title"></h3>
|
|
54
|
+
<ul class="file-list" id="dispatch-files" aria-label="Target files"></ul>
|
|
55
|
+
<code class="cmd" id="dispatch-verify"></code>
|
|
56
|
+
</div>
|
|
57
|
+
<fieldset class="choice-group">
|
|
58
|
+
<legend>Engine</legend>
|
|
59
|
+
<div class="engine-options">
|
|
60
|
+
<label class="engine-option"><input type="radio" name="dispatch-engine" id="dispatch-engine-native" value="native" checked><svg class="icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 1.5L3.5 9H8l-1 5.5L12.5 7H8z"/></svg><span><b>Native Engine</b><span>Direct API, Prompt Caching & Fast Streaming. Token spend is reported live.</span></span></label>
|
|
61
|
+
<label class="engine-option"><input type="radio" name="dispatch-engine" id="dispatch-engine-cli" value="cli"><svg class="icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="1.5" y="2.5" width="13" height="11" rx="1.5"/><path d="M4.5 6.5L6.5 8l-2 1.5M8.5 10h3"/></svg><span><b>CLI Terminal Pairing</b><span>Interactive Claude Code in a terminal shell, driven by the command below.</span></span></label>
|
|
62
|
+
</div>
|
|
63
|
+
</fieldset>
|
|
64
|
+
<fieldset class="choice-group">
|
|
65
|
+
<legend>Thinking Budget</legend>
|
|
66
|
+
<div class="budget-chips">
|
|
67
|
+
<label class="budget-chip"><input type="radio" name="dispatch-budget" id="dispatch-budget-none" value="0" checked>None<small>Fast / Deterministic</small></label>
|
|
68
|
+
<label class="budget-chip"><input type="radio" name="dispatch-budget" id="dispatch-budget-standard" value="2048">Standard<small>2,048 tokens</small></label>
|
|
69
|
+
<label class="budget-chip"><input type="radio" name="dispatch-budget" id="dispatch-budget-deep" value="4096">Deep<small>4,096 tokens</small></label>
|
|
70
|
+
</div>
|
|
71
|
+
<p class="field-hint" id="dispatch-budget-hint" aria-live="polite"></p>
|
|
72
|
+
</fieldset>
|
|
73
|
+
<div class="field" id="dispatch-command-field" hidden>
|
|
74
|
+
<label for="dispatch-command">Autonomous command</label>
|
|
75
|
+
<textarea class="input cmd-preview" id="dispatch-command" rows="4" spellcheck="false"></textarea>
|
|
76
|
+
<p class="field-hint" id="dispatch-command-hint">Leave unchanged to use the server's default runner (Claude Code unless <code>NATIV_RUNNER_COMMAND</code> is set). In a custom command, <code>{taskId}</code>, <code>{taskTitle}</code> and <code>{worktreeDir}</code> are filled in on launch.</p>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="switches" role="group" aria-label="Run options">
|
|
79
|
+
<label class="switch"><input type="checkbox" id="dispatch-worktree" checked><span class="switch-track" aria-hidden="true"></span><span class="switch-text"><b>Isolated Worktree</b><span>Run on branch agent/task-<id> in .worktrees/, away from your working copy.</span></span></label>
|
|
80
|
+
<label class="switch"><input type="checkbox" id="dispatch-verify-gate" checked><span class="switch-track" aria-hidden="true"></span><span class="switch-text"><b>Auto-verify Gatekeeper</b><span>Run the test command when the agent exits.</span></span></label>
|
|
81
|
+
<label class="switch"><input type="checkbox" id="dispatch-merge"><span class="switch-track" aria-hidden="true"></span><span class="switch-text"><b>Auto-merge on Pass</b><span>Merge the worktree branch into main once verification passes.</span></span></label>
|
|
82
|
+
</div>
|
|
83
|
+
<p class="field-error" id="dispatch-error" aria-live="polite"></p>
|
|
84
|
+
<div class="modal-foot">
|
|
85
|
+
<button class="btn" value="cancel" type="submit">Cancel</button>
|
|
86
|
+
<button class="btn primary" type="button" id="btn-launch-agent" aria-keyshortcuts="Control+Enter"><svg class="icon" width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M4.5 2.8v10.4L13 8z"/></svg>Launch Autonomous Runner <kbd>Ctrl+Enter</kbd></button>
|
|
87
|
+
</div>
|
|
88
|
+
</form>
|
|
89
|
+
</dialog>
|
|
90
|
+
|
|
91
|
+
<dialog id="confirm-dialog" class="narrow" aria-labelledby="confirm-title" aria-describedby="confirm-body">
|
|
92
|
+
<form class="modal" method="dialog">
|
|
93
|
+
<h2 id="confirm-title">Confirm</h2>
|
|
94
|
+
<p class="lead" id="confirm-body"></p>
|
|
95
|
+
<div class="modal-foot">
|
|
96
|
+
<button class="btn" value="cancel" type="submit">Cancel</button>
|
|
97
|
+
<button class="btn primary" type="button" id="btn-confirm-ok">Confirm</button>
|
|
98
|
+
</div>
|
|
99
|
+
</form>
|
|
100
|
+
</dialog>
|
|
101
|
+
|
|
102
|
+
<dialog id="conn-dialog" aria-labelledby="conn-title">
|
|
103
|
+
<form class="modal" method="dialog" id="conn-form">
|
|
104
|
+
<h2 id="conn-title">Connection Settings</h2>
|
|
105
|
+
<p class="lead">Connection strings stay in memory inside the local nativ process. They are never written to disk or shown to AI agents; only masked URLs are displayed.</p>
|
|
106
|
+
<div id="conn-template-chips" hidden></div>
|
|
107
|
+
<div class="field" data-env="dev">
|
|
108
|
+
<label for="engine-dev"><span class="dot" id="mdot-dev"></span> Dev / Staging</label>
|
|
109
|
+
<div class="field-row">
|
|
110
|
+
<select class="input" id="engine-dev" data-engine="dev" aria-label="Dev database type">
|
|
111
|
+
<option value="url">Connection URL (PostgreSQL, MySQL, SQLite, MongoDB)</option>
|
|
112
|
+
<option value="form">Connection Form (XAMPP / Parameters)</option>
|
|
113
|
+
<option value="firestore">Firebase Firestore</option>
|
|
114
|
+
</select>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="param-grid" id="params-dev" hidden>
|
|
117
|
+
<select class="input" id="pengine-dev" aria-label="Dev database engine">
|
|
118
|
+
<option value="mysql">MySQL</option>
|
|
119
|
+
<option value="postgresql">PostgreSQL</option>
|
|
120
|
+
</select>
|
|
121
|
+
<input class="input" id="phost-dev" type="text" autocomplete="off" spellcheck="false" aria-label="Dev host" placeholder="Host, e.g. 127.0.0.1">
|
|
122
|
+
<input class="input" id="pport-dev" type="text" inputmode="numeric" autocomplete="off" aria-label="Dev port" placeholder="Port">
|
|
123
|
+
<input class="input" id="puser-dev" type="text" autocomplete="off" spellcheck="false" aria-label="Dev user" placeholder="User">
|
|
124
|
+
<input class="input span-2" id="ppass-dev" type="password" autocomplete="new-password" aria-label="Dev password" placeholder="Password (empty for XAMPP root)">
|
|
125
|
+
<input class="input span-2" id="pdb-dev" type="text" autocomplete="off" spellcheck="false" aria-label="Dev database name" placeholder="Database name">
|
|
126
|
+
<button class="btn small" type="button" data-xampp="dev">Use XAMPP Defaults</button>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="field-row">
|
|
129
|
+
<input class="input" id="url-dev" type="password" autocomplete="off" spellcheck="false" aria-label="Dev connection string" placeholder="postgres://user:password@localhost:5432/app_dev or mongodb://localhost:27017/app">
|
|
130
|
+
<button class="btn small" type="button" data-toggle="dev" aria-controls="url-dev" aria-pressed="false">Show</button>
|
|
131
|
+
<input class="input" id="fsproject-dev" type="text" autocomplete="off" spellcheck="false" aria-label="Dev Firestore project ID" placeholder="Project ID" hidden>
|
|
132
|
+
<input class="input" id="fsemu-dev" type="text" autocomplete="off" spellcheck="false" aria-label="Dev Firestore emulator host" placeholder="Emulator host (optional), e.g. localhost:8080" hidden>
|
|
133
|
+
<button class="btn small" type="button" data-ping="dev">Test Ping</button>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="current" id="current-dev"></div>
|
|
136
|
+
<div class="result" id="result-dev" aria-live="polite"></div>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="field" data-env="prod">
|
|
139
|
+
<label for="engine-prod"><span class="dot" id="mdot-prod"></span> Production</label>
|
|
140
|
+
<div class="field-row">
|
|
141
|
+
<select class="input" id="engine-prod" data-engine="prod" aria-label="Production database type">
|
|
142
|
+
<option value="url">Connection URL (PostgreSQL, MySQL, SQLite, MongoDB)</option>
|
|
143
|
+
<option value="form">Connection Form (XAMPP / Parameters)</option>
|
|
144
|
+
<option value="firestore">Firebase Firestore</option>
|
|
145
|
+
</select>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="param-grid" id="params-prod" hidden>
|
|
148
|
+
<select class="input" id="pengine-prod" aria-label="Production database engine">
|
|
149
|
+
<option value="mysql">MySQL</option>
|
|
150
|
+
<option value="postgresql">PostgreSQL</option>
|
|
151
|
+
</select>
|
|
152
|
+
<input class="input" id="phost-prod" type="text" autocomplete="off" spellcheck="false" aria-label="Production host" placeholder="Host">
|
|
153
|
+
<input class="input" id="pport-prod" type="text" inputmode="numeric" autocomplete="off" aria-label="Production port" placeholder="Port">
|
|
154
|
+
<input class="input" id="puser-prod" type="text" autocomplete="off" spellcheck="false" aria-label="Production user" placeholder="User">
|
|
155
|
+
<input class="input span-2" id="ppass-prod" type="password" autocomplete="new-password" aria-label="Production password" placeholder="Password">
|
|
156
|
+
<input class="input span-2" id="pdb-prod" type="text" autocomplete="off" spellcheck="false" aria-label="Production database name" placeholder="Database name">
|
|
157
|
+
<button class="btn small" type="button" data-xampp="prod">Use XAMPP Defaults</button>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="field-row">
|
|
160
|
+
<input class="input" id="url-prod" type="password" autocomplete="off" spellcheck="false" aria-label="Production connection string" placeholder="postgres://user:password@db.example.com:5432/app or mongodb+srv://…">
|
|
161
|
+
<button class="btn small" type="button" data-toggle="prod" aria-controls="url-prod" aria-pressed="false">Show</button>
|
|
162
|
+
<input class="input" id="fsproject-prod" type="text" autocomplete="off" spellcheck="false" aria-label="Production Firestore project ID" placeholder="Project ID" hidden>
|
|
163
|
+
<input class="input" id="fsemu-prod" type="text" autocomplete="off" spellcheck="false" aria-label="Production Firestore emulator host" placeholder="Emulator host (optional)" hidden>
|
|
164
|
+
<button class="btn small" type="button" data-ping="prod">Test Ping</button>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="current" id="current-prod"></div>
|
|
167
|
+
<div class="result" id="result-prod" aria-live="polite"></div>
|
|
168
|
+
</div>
|
|
169
|
+
<p class="lead" style="margin:0 0 8px">Firestore uses your local Application Default Credentials (<code>gcloud auth application-default login</code>) or the emulator; no key file is ever uploaded here.</p>
|
|
170
|
+
<div class="modal-foot">
|
|
171
|
+
<button class="btn" value="cancel" type="submit">Close</button>
|
|
172
|
+
<button class="btn primary" type="button" id="btn-save-conn">Save to In-Memory Session</button>
|
|
173
|
+
</div>
|
|
174
|
+
</form>
|
|
175
|
+
</dialog>
|
|
176
|
+
|
|
177
|
+
<dialog id="media-dialog" aria-labelledby="media-title">
|
|
178
|
+
<form class="modal media-modal" method="dialog">
|
|
179
|
+
<h2 id="media-title">Image field</h2>
|
|
180
|
+
<p class="lead" id="media-sub"></p>
|
|
181
|
+
<div class="thumb-box" id="media-thumb"></div>
|
|
182
|
+
<dl id="media-details"></dl>
|
|
183
|
+
<p class="media-note">Only metadata from sampled documents is shown. Raw image bytes and full Base64 payloads are never sent to the browser or to AI agents.</p>
|
|
184
|
+
<div class="modal-foot"><button class="btn" value="close" type="submit">Close</button></div>
|
|
185
|
+
</form>
|
|
186
|
+
</dialog>
|
|
187
|
+
|
|
188
|
+
<dialog id="record-dialog" aria-labelledby="record-title">
|
|
189
|
+
<form class="modal" method="dialog" id="record-form">
|
|
190
|
+
<h2 id="record-title">Record</h2>
|
|
191
|
+
<p class="lead" id="record-lead">Insert or edit record.</p>
|
|
192
|
+
<div class="record-form-grid" id="record-fields"></div>
|
|
193
|
+
<div class="modal-foot">
|
|
194
|
+
<button class="btn" value="cancel" type="submit">Cancel</button>
|
|
195
|
+
<button class="btn primary" type="button" id="btn-save-record">Save Record</button>
|
|
196
|
+
</div>
|
|
197
|
+
</form>
|
|
198
|
+
</dialog>
|
|
199
|
+
|
|
200
|
+
<dialog id="challenge-dialog" aria-labelledby="challenge-title">
|
|
201
|
+
<form class="modal modal-prod-guard" method="dialog" id="challenge-form">
|
|
202
|
+
<span class="challenge-badge">PRODUCTION MUTATION SAFEGUARD</span>
|
|
203
|
+
<h2 id="challenge-title">Confirm Production Mutation</h2>
|
|
204
|
+
<div class="challenge-box">
|
|
205
|
+
<p>Target: <b>PRODUCTION ENVIRONMENT</b></p>
|
|
206
|
+
<p id="challenge-desc">You are about to modify live production data.</p>
|
|
207
|
+
<p>To proceed, type the target name exactly: <code id="challenge-target-name">entity</code></p>
|
|
208
|
+
</div>
|
|
209
|
+
<div class="field">
|
|
210
|
+
<label for="challenge-input">Confirmation phrase</label>
|
|
211
|
+
<input class="input" id="challenge-input" type="text" autocomplete="off" spellcheck="false" placeholder="Type name to confirm">
|
|
212
|
+
</div>
|
|
213
|
+
<div class="modal-foot">
|
|
214
|
+
<button class="btn" value="cancel" type="submit">Cancel</button>
|
|
215
|
+
<button class="btn btn-danger" type="button" id="btn-confirm-challenge" disabled>Execute Production Mutation</button>
|
|
216
|
+
</div>
|
|
217
|
+
</form>
|
|
218
|
+
</dialog>
|
|
219
|
+
|
|
220
|
+
<div class="thumb-pop" id="thumb-pop" role="tooltip" hidden></div>
|
|
221
|
+
|
|
222
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const modelScript: string;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Pure client model: joins plan, telemetry, runs and escalations into one object per refresh.
|
|
2
|
+
export const modelScript = String.raw ` // ─── Studio client model: buildModel(api) is pure ──────────────────────────
|
|
3
|
+
var RUN_ACTIVE = { spawning_worktree: 1, running: 1, verifying: 1, merging: 1 };
|
|
4
|
+
function isRunActive(run) { return !!run && !!RUN_ACTIVE[run.status]; }
|
|
5
|
+
|
|
6
|
+
/** Text before the first colon, at most 46 characters. */
|
|
7
|
+
function shortName(name) {
|
|
8
|
+
var head = String(name || '').split(':')[0].replace(/^\s+|\s+$/g, '');
|
|
9
|
+
if (head.length <= 46) return head;
|
|
10
|
+
return head.slice(0, 44).replace(/[\s,&]+\S*$/, '') + '…';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function toTime(value) {
|
|
14
|
+
var t = value ? Date.parse(value) : NaN;
|
|
15
|
+
return isNaN(t) ? null : t;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function positive(n) { return typeof n === 'number' && isFinite(n) && n > 0 ? n : null; }
|
|
19
|
+
|
|
20
|
+
/** Last non-empty line of a log tail, without colour codes. */
|
|
21
|
+
function lastLine(text) {
|
|
22
|
+
var lines = String(text || '').replace(/\x1b\[[0-9;?]*[A-Za-z]/g, '').split(/\r?\n/);
|
|
23
|
+
for (var i = lines.length - 1; i >= 0; i--) {
|
|
24
|
+
var line = lines[i].replace(/^\s+|\s+$/g, '');
|
|
25
|
+
if (line) return line.length > 240 ? line.slice(0, 240) + '…' : line;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function attemptsOf(task, running) {
|
|
31
|
+
var cb = task.circuitBreaker || {};
|
|
32
|
+
var attempt = (cb.consecutiveFailures || 0) + (running ? 1 : 0);
|
|
33
|
+
if (!attempt && task.status === 'blocked') {
|
|
34
|
+
var m = /(\d+)\s+(?:fix\s+)?attempts?/i.exec(task.notes || '');
|
|
35
|
+
attempt = m ? Number(m[1]) : 0;
|
|
36
|
+
}
|
|
37
|
+
return attempt || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildTask(t, milestoneId, index) {
|
|
41
|
+
var b = index.breakdown[t.id] || null;
|
|
42
|
+
var run = index.run[t.id] || null;
|
|
43
|
+
var esc1 = index.escalation[t.id] || null;
|
|
44
|
+
var running = t.status === 'in_progress';
|
|
45
|
+
var startT = b ? toTime(b.startedAt) : null;
|
|
46
|
+
if (startT == null && run && isRunActive(run)) startT = toTime(run.startedAt);
|
|
47
|
+
var cost = b && b.actual ? positive(b.actual.costUsd) : null;
|
|
48
|
+
if (cost == null && b && b.estimated) cost = positive(b.estimated.costUsd);
|
|
49
|
+
return {
|
|
50
|
+
id: t.id,
|
|
51
|
+
title: t.title || t.id,
|
|
52
|
+
description: t.description || '',
|
|
53
|
+
status: t.status,
|
|
54
|
+
agent: t.assignedSubagent || null,
|
|
55
|
+
deps: t.dependencies || [],
|
|
56
|
+
files: t.targetFiles || [],
|
|
57
|
+
verify: t.verificationCommand || '',
|
|
58
|
+
milestoneId: milestoneId,
|
|
59
|
+
children: [],
|
|
60
|
+
waitingOn: [],
|
|
61
|
+
isAvailable: !!t.isAvailable,
|
|
62
|
+
reason: t.status === 'blocked' && t.notes ? String(t.notes).replace(/^\s+|\s+$/g, '') || null : null,
|
|
63
|
+
attempt: attemptsOf(t, running),
|
|
64
|
+
maxAttempts: (t.circuitBreaker && t.circuitBreaker.maxThreshold) || 3,
|
|
65
|
+
startT: startT,
|
|
66
|
+
endT: t.status === 'completed' && b ? toTime(b.completedAt) : null,
|
|
67
|
+
durationMs: b ? positive(b.durationMs) : null,
|
|
68
|
+
checkMs: b && b.verification ? positive(b.verification.durationMs) : null,
|
|
69
|
+
costUsd: cost,
|
|
70
|
+
run: run,
|
|
71
|
+
latestLog: lastLine(index.logTail[t.id]),
|
|
72
|
+
escalation: esc1,
|
|
73
|
+
hasProposal: !!(esc1 && esc1.proposedPatch)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function indexApi(api) {
|
|
78
|
+
var index = { breakdown: {}, run: {}, escalation: {}, logTail: api.logTail || {} };
|
|
79
|
+
((api.telemetry && api.telemetry.taskBreakdowns) || []).forEach(function (b) {
|
|
80
|
+
if (b && b.taskId) index.breakdown[b.taskId] = b;
|
|
81
|
+
});
|
|
82
|
+
(api.runs || []).forEach(function (r) {
|
|
83
|
+
var have = r && index.run[r.taskId];
|
|
84
|
+
if (r && r.taskId && (!have || (isRunActive(r) && !isRunActive(have)))) index.run[r.taskId] = r;
|
|
85
|
+
});
|
|
86
|
+
(api.escalations || []).forEach(function (e) {
|
|
87
|
+
var pending = e && (!e.status || e.status === 'pending_review');
|
|
88
|
+
if (pending && e.taskId && !index.escalation[e.taskId]) index.escalation[e.taskId] = e;
|
|
89
|
+
});
|
|
90
|
+
return index;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function finishMilestone(m) {
|
|
94
|
+
m.total = m.tasks.length;
|
|
95
|
+
m.done = m.tasks.filter(function (t) { return t.status === 'completed'; }).length;
|
|
96
|
+
var ends = m.tasks.map(function (t) { return t.endT || 0; });
|
|
97
|
+
m.lastEndT = Math.max.apply(null, [0].concat(ends)) || null;
|
|
98
|
+
m.workMs = m.tasks.reduce(function (sum, t) { return sum + (t.durationMs || 0); }, 0);
|
|
99
|
+
var costs = m.tasks.filter(function (t) { return t.costUsd != null; });
|
|
100
|
+
m.costUsd = costs.length ? costs.reduce(function (sum, t) { return sum + t.costUsd; }, 0) : null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function linkTasks(tasks, byId) {
|
|
104
|
+
tasks.forEach(function (t) {
|
|
105
|
+
t.deps.forEach(function (d) {
|
|
106
|
+
var parent = byId[d];
|
|
107
|
+
if (parent && parent.children.indexOf(t.id) === -1) parent.children.push(t.id);
|
|
108
|
+
if (!parent || parent.status !== 'completed') t.waitingOn.push(d);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function needsYouItems(tasks, byId, escalations) {
|
|
114
|
+
var seen = {}, items = [];
|
|
115
|
+
var add = function (t) {
|
|
116
|
+
seen[t.id] = true;
|
|
117
|
+
items.push({ taskId: t.id, task: t, escalation: t.escalation, hasProposal: t.hasProposal,
|
|
118
|
+
kind: t.status === 'blocked' ? 'stuck' : 'question' });
|
|
119
|
+
};
|
|
120
|
+
tasks.forEach(function (t) { if (t.status === 'blocked') add(t); });
|
|
121
|
+
(escalations || []).forEach(function (e) {
|
|
122
|
+
var pending = e && (!e.status || e.status === 'pending_review');
|
|
123
|
+
if (pending && byId[e.taskId] && !seen[e.taskId]) add(byId[e.taskId]);
|
|
124
|
+
});
|
|
125
|
+
return items;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function summaryOf(api, milestones, tasks) {
|
|
129
|
+
var act = api.telemetry && api.telemetry.summary && api.telemetry.summary.actual;
|
|
130
|
+
var st = api.status && api.status.telemetry;
|
|
131
|
+
var pick = function (a, b) { return a != null && isFinite(a) ? a : (b != null && isFinite(b) ? b : null); };
|
|
132
|
+
var contracts = api.status && api.status.contracts;
|
|
133
|
+
var done = tasks.filter(function (t) { return t.status === 'completed'; }).length;
|
|
134
|
+
return {
|
|
135
|
+
spendUsd: pick(act && act.spendUsd, st && st.actualSpendUsd),
|
|
136
|
+
cacheHitRate: pick(act && act.cacheHitRate, st && st.cacheHitRate),
|
|
137
|
+
cacheSavingsUsd: pick(act && act.cacheSavingsUsd, null),
|
|
138
|
+
contractsPresent: contracts ? Object.keys(contracts).filter(function (k) { return contracts[k]; }).length : null,
|
|
139
|
+
contractsTotal: 5,
|
|
140
|
+
milestonesTotal: milestones.length,
|
|
141
|
+
milestonesDone: milestones.filter(function (m) { return m.total > 0 && m.done === m.total; }).length,
|
|
142
|
+
tasksTotal: tasks.length,
|
|
143
|
+
tasksDone: done,
|
|
144
|
+
tasksLeft: tasks.length - done
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** api = { milestones, status, telemetry, runs, escalations, logTail }, the raw slices from the server. */
|
|
149
|
+
function buildModel(api) {
|
|
150
|
+
api = api || {};
|
|
151
|
+
var index = indexApi(api);
|
|
152
|
+
var tasks = [], byId = {};
|
|
153
|
+
var milestones = (api.milestones || []).map(function (m, i) {
|
|
154
|
+
var list = (m.tasks || []).map(function (t) {
|
|
155
|
+
var task = buildTask(t, m.id, index);
|
|
156
|
+
byId[task.id] = task;
|
|
157
|
+
tasks.push(task);
|
|
158
|
+
return task;
|
|
159
|
+
});
|
|
160
|
+
return { id: m.id, name: m.name || m.id, short: shortName(m.name || m.id), status: m.status, idx: i, tasks: list };
|
|
161
|
+
});
|
|
162
|
+
linkTasks(tasks, byId);
|
|
163
|
+
milestones.forEach(finishMilestone);
|
|
164
|
+
var active = null;
|
|
165
|
+
milestones.some(function (m) {
|
|
166
|
+
var open = m.tasks.some(function (t) { return t.status !== 'completed'; });
|
|
167
|
+
if (open) active = m.id;
|
|
168
|
+
return open;
|
|
169
|
+
});
|
|
170
|
+
if (!active && milestones.length) active = milestones[milestones.length - 1].id;
|
|
171
|
+
return {
|
|
172
|
+
milestones: milestones,
|
|
173
|
+
tasks: tasks,
|
|
174
|
+
byId: byId,
|
|
175
|
+
activeMilestoneId: active,
|
|
176
|
+
running: tasks.filter(function (t) { return t.status === 'in_progress'; }),
|
|
177
|
+
stuck: tasks.filter(function (t) { return t.status === 'blocked'; }),
|
|
178
|
+
needsYou: needsYouItems(tasks, byId, api.escalations),
|
|
179
|
+
summary: summaryOf(api, milestones, tasks)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Stores the model and keeps the shared milestone selection valid. */
|
|
184
|
+
Studio.setModel = function (model) {
|
|
185
|
+
Studio.model = model;
|
|
186
|
+
var S = Studio.state;
|
|
187
|
+
var known = model.milestones.some(function (m) { return m.id === S.milestoneId; });
|
|
188
|
+
if (!known) S.milestoneId = model.activeMilestoneId;
|
|
189
|
+
};
|
|
190
|
+
Studio.buildModel = buildModel;
|
|
191
|
+
|
|
192
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const paintScript: string;
|