@monster-orange/den 0.2.8 → 0.4.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.
Files changed (158) hide show
  1. package/CHANGELOG.md +1731 -0
  2. package/README.md +4 -2
  3. package/bin/den +2 -1
  4. package/docs/distributions.md +730 -6
  5. package/make/den.mk +19 -4
  6. package/make/journeys.mk +2 -1
  7. package/make/local_dev.mk +6 -13
  8. package/make/secrets-1password.mk +18 -0
  9. package/make/test.mk +1 -1
  10. package/package.json +12 -2
  11. package/schemas/den.plugin.v1.json +156 -0
  12. package/schemas/den.theme.v1.json +269 -0
  13. package/scripts/auth-configure.ts +16 -8
  14. package/scripts/heal-config.ts +0 -5
  15. package/scripts/setup-1password.ts +41 -19
  16. package/scripts/setup-secrets.ts +67 -101
  17. package/src/pillars/api/global-setup.ts +1 -1
  18. package/src/pillars/journeys/sandbox.ts +23 -18
  19. package/src/pillars/journeys/tools/browser-session.ts +2 -2
  20. package/src/scripts/setup-default-workspace.ts +2 -2
  21. package/src/shared/agents/default-pack/be-dev.md +20 -0
  22. package/src/shared/agents/default-pack/devops.md +14 -0
  23. package/src/shared/agents/default-pack/fe-dev.md +20 -0
  24. package/src/shared/agents/default-pack/orchestrator.md +16 -0
  25. package/src/shared/agents/default-pack/planner.md +17 -0
  26. package/src/shared/agents/default-pack/reviewer.md +14 -0
  27. package/src/shared/agents/default-pack/ux-designer.md +15 -0
  28. package/src/shared/agents/den-claude.ts +173 -0
  29. package/src/shared/agents/generic.ts +52 -0
  30. package/src/shared/agents/personas.ts +218 -0
  31. package/src/shared/agents/records.ts +118 -0
  32. package/src/shared/agents/runtime.ts +192 -0
  33. package/src/shared/agents/runtimes.ts +47 -0
  34. package/src/shared/auth/headless-login.ts +1 -1
  35. package/src/shared/auth/sudo-vault.ts +93 -31
  36. package/src/shared/auth/token-providers/index.ts +7 -3
  37. package/src/shared/brand.ts +7 -0
  38. package/src/shared/config-error.ts +33 -3
  39. package/src/shared/constants.ts +3 -24
  40. package/src/shared/den-config.ts +257 -5
  41. package/src/shared/edge/config.ts +147 -21
  42. package/src/shared/edge/exec.ts +31 -0
  43. package/src/shared/edge/included.ts +169 -0
  44. package/src/shared/edge/render.ts +69 -14
  45. package/src/shared/edge/runtime.ts +128 -121
  46. package/src/shared/edge/status.ts +68 -8
  47. package/src/shared/edge/tls.ts +328 -0
  48. package/src/shared/edge/types.ts +25 -9
  49. package/src/shared/engine.ts +23 -0
  50. package/src/shared/environment-manager/default-workspace.ts +16 -1
  51. package/src/shared/environment-manager/health.ts +73 -38
  52. package/src/shared/environment-manager/scope.ts +168 -0
  53. package/src/shared/environment-manager/service-runner.ts +789 -43
  54. package/src/shared/environment-manager/up-targets.ts +132 -0
  55. package/src/shared/environment-manager/workspaces.ts +19 -0
  56. package/src/shared/health/rollup.ts +48 -0
  57. package/src/shared/open-url.ts +21 -2
  58. package/src/shared/org-sources.ts +78 -59
  59. package/src/shared/org.ts +53 -5
  60. package/src/shared/plugins/manifest.ts +406 -0
  61. package/src/shared/plugins/store.ts +358 -0
  62. package/src/shared/process/legacy-adopt.ts +285 -0
  63. package/src/shared/process/process-group.ts +202 -0
  64. package/src/shared/process/spawn-streaming.ts +7 -0
  65. package/src/shared/secret-env.ts +70 -0
  66. package/src/shared/secrets/doppler.ts +1 -1
  67. package/src/shared/secrets/index.ts +279 -50
  68. package/src/shared/secrets/none.ts +56 -0
  69. package/src/shared/secrets/strategies.ts +202 -0
  70. package/src/shared/secrets/types.ts +1 -1
  71. package/src/shared/sessions/client.ts +277 -0
  72. package/src/shared/sessions/den-pty.ts +97 -0
  73. package/src/shared/sessions/env.ts +79 -0
  74. package/src/shared/sessions/host.ts +667 -0
  75. package/src/shared/sessions/names.ts +85 -0
  76. package/src/shared/sessions/paths.ts +27 -0
  77. package/src/shared/sessions/protocol.ts +72 -0
  78. package/src/shared/sessions/pty.ts +141 -0
  79. package/src/shared/sessions/ring-buffer.ts +160 -0
  80. package/src/shared/sessions/types.ts +81 -0
  81. package/src/shared/smoke/git-remote.ts +40 -0
  82. package/src/shared/stacks/manifest-commands.ts +1 -1
  83. package/src/shared/stacks/namespace.ts +178 -0
  84. package/src/shared/stacks/owners.ts +303 -0
  85. package/src/shared/stacks/render.ts +8 -3
  86. package/src/shared/stacks/runtime.ts +100 -16
  87. package/src/shared/stacks/status.ts +63 -12
  88. package/src/shared/strategies/registry.ts +89 -0
  89. package/src/shared/theme/contract.ts +538 -0
  90. package/src/shared/types/index.ts +12 -3
  91. package/src/ui/cli/agents-command.ts +812 -0
  92. package/src/ui/cli/create.ts +24 -7
  93. package/src/ui/cli/doctor-command.ts +260 -0
  94. package/src/ui/cli/edge-command.ts +56 -10
  95. package/src/ui/cli/env-probe.ts +266 -0
  96. package/src/ui/cli/flag-parser.ts +18 -5
  97. package/src/ui/cli/health-display.ts +25 -0
  98. package/src/ui/cli/index.ts +580 -60
  99. package/src/ui/cli/notice.ts +20 -0
  100. package/src/ui/cli/plugin-command.ts +849 -0
  101. package/src/ui/cli/sessions-command.ts +718 -0
  102. package/src/ui/cli/stack-command.ts +63 -2
  103. package/src/ui/cli/test-runner.ts +11 -9
  104. package/src/ui/cli/theme-command.ts +136 -0
  105. package/src/ui/cli/web-command.ts +47 -23
  106. package/src/ui/mcp/api.ts +28 -2
  107. package/src/ui/mcp/scope.ts +145 -20
  108. package/src/ui/mcp/server.ts +27 -2
  109. package/src/ui/mcp/tools.ts +94 -12
  110. package/src/ui/server/appearance-prefs.ts +95 -0
  111. package/src/ui/server/audit.ts +35 -0
  112. package/src/ui/server/daemon-reaper.ts +29 -1
  113. package/src/ui/server/engine-stamp.ts +83 -0
  114. package/src/ui/server/github-service.ts +23 -44
  115. package/src/ui/server/graph-page.ts +20 -0
  116. package/src/ui/server/graph-prefs.ts +44 -1
  117. package/src/ui/server/http-errors.ts +293 -0
  118. package/src/ui/server/http-helpers.ts +22 -3
  119. package/src/ui/server/index.ts +539 -51
  120. package/src/ui/server/public/appearance.js +531 -0
  121. package/src/ui/server/public/edge-page.js +248 -0
  122. package/src/ui/server/public/edge.html +251 -0
  123. package/src/ui/server/public/environments.html +65 -83
  124. package/src/ui/server/public/error-page.js +247 -0
  125. package/src/ui/server/public/error.html +260 -0
  126. package/src/ui/server/public/graph-model.js +332 -14
  127. package/src/ui/server/public/graph.css +141 -47
  128. package/src/ui/server/public/graph.js +223 -44
  129. package/src/ui/server/public/header.js +396 -600
  130. package/src/ui/server/public/health-fit.js +248 -0
  131. package/src/ui/server/public/health-rollup.js +128 -0
  132. package/src/ui/server/public/i18n/es.js +287 -0
  133. package/src/ui/server/public/i18n/ja.js +276 -0
  134. package/src/ui/server/public/index.html +139 -438
  135. package/src/ui/server/public/local-dev.html +3468 -4044
  136. package/src/ui/server/public/logs.html +71 -208
  137. package/src/ui/server/public/panel.js +14 -2
  138. package/src/ui/server/public/release.html +175 -389
  139. package/src/ui/server/public/services.html +596 -770
  140. package/src/ui/server/public/settings-page.js +759 -0
  141. package/src/ui/server/public/settings-registry.js +521 -0
  142. package/src/ui/server/public/settings.html +590 -0
  143. package/src/ui/server/public/shell.js +3869 -0
  144. package/src/ui/server/public/topbar.js +1413 -0
  145. package/src/ui/server/public/version-label.js +12 -0
  146. package/src/ui/server/public/workspace-picker.js +74 -34
  147. package/src/ui/server/readonly-routes.ts +37 -3
  148. package/src/ui/server/services-list.ts +94 -17
  149. package/src/ui/server/settings-distribution.ts +74 -0
  150. package/src/ui/server/shell-prefs.ts +192 -0
  151. package/src/ui/server/theme-routes.ts +292 -0
  152. package/src/ui/server/theme-runtime.ts +407 -0
  153. package/src/ui/server/ui-assets.ts +16 -1
  154. package/src/ui/server/ui-language.ts +50 -0
  155. package/src/ui/server/workspace-routes.ts +48 -18
  156. package/themes/den/den-theme.json +72 -0
  157. package/themes/den/favicon.ico +0 -0
  158. package/themes/den/mark.svg +6 -0
@@ -0,0 +1,248 @@
1
+ /**
2
+ * The health poll's model, shared by the rail and the top bar's status chip
3
+ * and drawer (0.3.0-dev.20 retired the header's dot row and its "+N" chip).
4
+ *
5
+ * Each repo's state comes from health-rollup.js, the rule the graph and
6
+ * `<cli> status` use too: "down", "degraded", "unknown" (nothing checked)
7
+ * or "ok".
8
+ *
9
+ * buildRow(rows, groups) the model: application units, and every repo
10
+ * flat, each in problem-first order
11
+ * paintGate(…) when health data repaints: once per first
12
+ * cycle, then debounced
13
+ * healthCycle(…) one poll: the stream, completed by /api/health
14
+ * when it breaks, painted through the gate
15
+ * shellHealth(row) the rail's Services badge and pinned dots
16
+ *
17
+ * The pure parts take plain data, so tests need no browser.
18
+ */
19
+ import { compareRepos, rollupRepo } from "./health-rollup.js";
20
+
21
+ /**
22
+ * The row's model from /api/health rows and the application grouping
23
+ * (`[{ app, repos }]`, app null for repos with no box of their own).
24
+ * Repos sort down, degraded, ok, then unknown; within a state the
25
+ * focused workspace's first, then by name. A box sorts by its worst repo.
26
+ */
27
+ export function buildRow(rows, groups) {
28
+ const byRepo = new Map();
29
+ for (const r of rows || []) {
30
+ if (!byRepo.has(r.repo)) byRepo.set(r.repo, []);
31
+ byRepo.get(r.repo).push(r);
32
+ }
33
+ const repoOf = new Map(
34
+ [...byRepo].map(([repo, signals]) => {
35
+ const rollup = rollupRepo(repo, signals);
36
+ return [
37
+ repo,
38
+ {
39
+ repo,
40
+ state: rollup.state,
41
+ rollup,
42
+ focused: signals.some((s) => s.focused),
43
+ items: signals,
44
+ },
45
+ ];
46
+ }),
47
+ );
48
+ const flat = [...repoOf.values()].sort(compareRepos);
49
+ const units = [];
50
+ for (const { app, repos } of groups || [
51
+ { app: null, repos: [...repoOf.keys()] },
52
+ ]) {
53
+ const members = repos
54
+ .map((r) => repoOf.get(r))
55
+ .filter(Boolean)
56
+ .sort(compareRepos);
57
+ if (!members.length) continue;
58
+ if (!app)
59
+ for (const m of members) units.push({ app: null, repos: [m], ...key(m) });
60
+ else
61
+ units.push({
62
+ app,
63
+ repos: members,
64
+ ...key({
65
+ state: members[0].state,
66
+ focused: members.some((m) => m.focused),
67
+ repo: app.name,
68
+ }),
69
+ });
70
+ }
71
+ units.sort(compareRepos);
72
+ return { units, flat };
73
+ }
74
+
75
+ const key = (x) => ({ state: x.state, focused: x.focused, repo: x.repo });
76
+
77
+ /**
78
+ * When health data repaints (0.3.0-dev.13; the status chip since dev.20).
79
+ * A fresh load streamed results in batches and the old row reshuffled with
80
+ * each one, three or four times in as many seconds. Now:
81
+ * - `hold()` starts a first cycle (a page load, an environment switch):
82
+ * data paints nothing (the chip stays "Checking…") until `done()`
83
+ * ends the cycle, or `cap` ms pass with a slow probe still out;
84
+ * - after that, data paints at most once per `delay` ms of quiet (a
85
+ * trailing debounce), and so does the end of a later cycle.
86
+ * Each call hands in the latest paint; only the last one runs.
87
+ * `timers` is `{ setTimeout, clearTimeout }`, globalThis by default, so
88
+ * tests can use a fake clock.
89
+ */
90
+ export function paintGate({
91
+ delay = 300,
92
+ cap = 8000,
93
+ timers = globalThis,
94
+ } = {}) {
95
+ let ready = true;
96
+ let pending = null;
97
+ let timer = null;
98
+ let capTimer = null;
99
+ const stop = (t) => t !== null && timers.clearTimeout(t);
100
+ const fire = () => {
101
+ stop(timer);
102
+ timer = null;
103
+ const paint = pending;
104
+ pending = null;
105
+ paint?.();
106
+ };
107
+ const settle = () => {
108
+ stop(capTimer);
109
+ capTimer = null;
110
+ ready = true;
111
+ fire();
112
+ };
113
+ return {
114
+ get ready() {
115
+ return ready;
116
+ },
117
+ hold() {
118
+ ready = false;
119
+ stop(timer);
120
+ timer = null;
121
+ stop(capTimer);
122
+ capTimer = timers.setTimeout(settle, cap);
123
+ },
124
+ data(paint) {
125
+ pending = paint;
126
+ if (!ready) return;
127
+ stop(timer);
128
+ timer = timers.setTimeout(fire, delay);
129
+ },
130
+ done(paint) {
131
+ if (paint) pending = paint;
132
+ if (!ready) return settle();
133
+ if (!pending) return;
134
+ stop(timer);
135
+ timer = timers.setTimeout(fire, delay);
136
+ },
137
+ };
138
+ }
139
+
140
+ /**
141
+ * One health poll, painted through `gate` (0.3.0-dev.14).
142
+ *
143
+ * - `seed`: the last poll's rows (`[key, row]` pairs); empty on a first
144
+ * cycle, which `hold()`s the gate so nothing paints until it completes.
145
+ * - `stream(onResult)`: /api/health/stream. Resolves "done" when the server
146
+ * said so (every check answered), "partial" when it broke after some
147
+ * results, "none" when it gave nothing.
148
+ * - `fetchAll()`: /api/health, every row or null. Only a "done" stream is a
149
+ * complete cycle: a broken one is completed from here, never painted as
150
+ * if it were whole (dev.13 painted a stream that broke after 0.6s).
151
+ * - `paint(map)`: draw these rows. `current()`: false once a newer poll
152
+ * owns the row.
153
+ * A cycle that never completes paints only by the gate's cap, with the rows
154
+ * that did land; a check with no result has no row, so it is never shown
155
+ * as down. Resolves with the cycle's rows, or null when incomplete.
156
+ */
157
+ export async function healthCycle({
158
+ seed = [],
159
+ last = null,
160
+ gate,
161
+ stream,
162
+ fetchAll,
163
+ paint,
164
+ current = () => true,
165
+ }) {
166
+ const keyOf = (r) => `${r.repo}/${r.service}`;
167
+ const acc = new Map(seed);
168
+ if (acc.size === 0) gate.hold();
169
+ const paintOf = (m) => () => {
170
+ if (current()) paint(m);
171
+ };
172
+ // A paint before the cycle completes (0.3.0-dev.17). The rows that last
173
+ // painted (`last()`, read at paint time: a poll that overlapped the first
174
+ // started with nothing seeded) stand for checks not answered yet; a repo
175
+ // they don't describe gets an `awaiting` row, so health-rollup.js holds it
176
+ // at unknown: one answered down service must not paint its app down
177
+ // while the app's other checks are still out.
178
+ const partialOf = (m) => () => {
179
+ if (!current()) return;
180
+ const known = (last ? last() : null) ?? new Map();
181
+ const out = new Map(known);
182
+ for (const [k, r] of m) out.set(k, r);
183
+ const described = new Set([...known.values()].map((r) => r.repo));
184
+ for (const r of [...out.values()])
185
+ if (!described.has(r.repo)) {
186
+ described.add(r.repo);
187
+ out.set(`${r.repo}/…`, {
188
+ repo: r.repo,
189
+ service: "…",
190
+ ok: null,
191
+ awaiting: true,
192
+ idx: r.idx,
193
+ focused: r.focused,
194
+ });
195
+ }
196
+ paint(out);
197
+ };
198
+ const fresh = new Map();
199
+ const end = await stream((r) => {
200
+ acc.set(keyOf(r), r);
201
+ fresh.set(keyOf(r), r);
202
+ gate.data(partialOf(acc));
203
+ });
204
+ let complete = end === "done";
205
+ if (!complete) {
206
+ const rows = await fetchAll();
207
+ if (Array.isArray(rows)) {
208
+ fresh.clear();
209
+ for (const r of rows) fresh.set(keyOf(r), r);
210
+ complete = true;
211
+ }
212
+ }
213
+ if (!current() || !complete) return null;
214
+ // Settle on exactly what this poll returned, so a service removed from
215
+ // the workspace disappears. A first cycle that answered with nothing
216
+ // paints too ("no services").
217
+ if (fresh.size > 0 || !gate.ready) gate.done(paintOf(fresh));
218
+ else gate.done();
219
+ return fresh;
220
+ }
221
+
222
+ /**
223
+ * The rail's share of the health row (R13, R14): `down` for the Services
224
+ * badge and `health` for the pinned rows' dots (`repo` and `repo/service`
225
+ * → down | degraded | ok | unknown). Both read the rollup: a down service
226
+ * counts only once every check of its repo has answered, so a cold load
227
+ * never badges a service the row still shows as unknown. `row` is
228
+ * buildRow's.
229
+ */
230
+ export function shellHealth(row) {
231
+ let down = 0;
232
+ const health = {};
233
+ for (const r of row.flat) {
234
+ health[r.repo] = r.state;
235
+ down += r.rollup.down.length;
236
+ for (const i of r.items) {
237
+ if (i.awaiting) continue;
238
+ health[`${r.repo}/${i.service}`] = r.rollup.awaiting
239
+ ? "unknown"
240
+ : i.ok === true
241
+ ? "ok"
242
+ : i.ok === false
243
+ ? "down"
244
+ : "unknown";
245
+ }
246
+ }
247
+ return { down, health };
248
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * One repo's health from its services' checks: the single rule the header
3
+ * row, its "+N" chip, the graph's repo cards and `<cli> status` all use, so
4
+ * they never disagree (0.3.0-dev.10).
5
+ *
6
+ * A signal is one service's check: `ok` true (up), false (down or failing)
7
+ * or null (not checked: no probe, not probed yet, or nothing to say). Only
8
+ * checked signals count, so a repo of 26 remote services with one probe is
9
+ * judged by that one probe.
10
+ *
11
+ * down the entry service (the repo's own health URL) is down
12
+ * degraded another checked service is down
13
+ * ok at least one signal is checked and none fails
14
+ * unknown nothing about the repo is checked (neutral, never green), or
15
+ * a check hasn't answered yet (`awaiting`, 0.3.0-dev.17): until
16
+ * every check has answered (a pending one has), one answered
17
+ * down service never paints the repo down or degraded
18
+ *
19
+ * The entry service is the one marked `isEntrypoint` (the manifest's
20
+ * `entrypoint`), else the service named like the repo, else the only one.
21
+ *
22
+ * Plain ES module with no imports: the browser loads it as /health-rollup.js,
23
+ * and the server and CLI import it from TypeScript.
24
+ */
25
+
26
+ /** Sort rank: problems first, then healthy, then unknown (nothing checked). */
27
+ export const STATE_RANK = { down: 0, degraded: 1, ok: 2, unknown: 3 };
28
+
29
+ /**
30
+ * @typedef {{ service: string, ok: boolean | null | undefined, isEntrypoint?: boolean, awaiting?: boolean }} HealthSignal
31
+ * @typedef {"down" | "degraded" | "ok" | "unknown"} RepoState
32
+ * @typedef {{ state: RepoState, entry: string | null, down: string[], checked: number, unchecked: number, awaiting: number }} RepoRollup
33
+ */
34
+
35
+ /**
36
+ * The entry service among `signals`, or null.
37
+ * @param {string} repo
38
+ * @param {HealthSignal[]} signals
39
+ * @returns {HealthSignal | null}
40
+ */
41
+ export function entrySignal(repo, signals) {
42
+ return (
43
+ signals.find((s) => s.isEntrypoint) ??
44
+ signals.find((s) => s.service === repo) ??
45
+ (signals.length === 1 ? signals[0] : null)
46
+ );
47
+ }
48
+
49
+ /**
50
+ * Roll one repo's signals up to its state.
51
+ * @param {string} repo
52
+ * @param {HealthSignal[]} signals
53
+ * @returns {RepoRollup}
54
+ */
55
+ export function rollupRepo(repo, signals) {
56
+ // A check that hasn't answered yet (`awaiting`) holds the whole repo at
57
+ // unknown: with only some answers in, the one that did can't be judged
58
+ // (a lone down sidecar would even read as the entry service).
59
+ const awaiting = signals.filter((s) => s.awaiting).length;
60
+ const answered = signals.filter((s) => !s.awaiting);
61
+ const entry = entrySignal(repo, answered);
62
+ const checked = answered.filter((s) => s.ok === true || s.ok === false);
63
+ const down = awaiting
64
+ ? []
65
+ : checked.filter((s) => s.ok === false).map((s) => s.service);
66
+ const state = awaiting
67
+ ? "unknown"
68
+ : entry && entry.ok === false
69
+ ? "down"
70
+ : down.length > 0
71
+ ? "degraded"
72
+ : checked.length > 0
73
+ ? "ok"
74
+ : "unknown";
75
+ return {
76
+ state,
77
+ entry: entry ? entry.service : null,
78
+ down,
79
+ checked: checked.length,
80
+ unchecked: answered.length - checked.length,
81
+ awaiting,
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Every repo's rollup from flat per-service rows (as /api/health sends
87
+ * them), in first-seen order.
88
+ * @param {Array<HealthSignal & { repo: string }>} rows
89
+ * @returns {Map<string, RepoRollup>}
90
+ */
91
+ export function rollupRows(rows) {
92
+ const by = new Map();
93
+ for (const r of rows || []) {
94
+ if (!by.has(r.repo)) by.set(r.repo, []);
95
+ by.get(r.repo).push(r);
96
+ }
97
+ return new Map([...by].map(([repo, s]) => [repo, rollupRepo(repo, s)]));
98
+ }
99
+
100
+ /**
101
+ * "down (web down)", "degraded (mailpit down)", "healthy",
102
+ * "healthy, 25 not checked", "unknown (not checked)".
103
+ * @param {RepoRollup} r
104
+ * @returns {string}
105
+ */
106
+ export function describeRollup(r) {
107
+ const notChecked = r.unchecked > 0 ? `${r.unchecked} not checked` : "";
108
+ if (r.awaiting) return "unknown (still checking)";
109
+ if (r.state === "unknown") return "unknown (not checked)";
110
+ if (r.state === "ok")
111
+ return notChecked ? `healthy, ${notChecked}` : "healthy";
112
+ return `${r.state} (${r.down.join(", ")} down)`;
113
+ }
114
+
115
+ /**
116
+ * Order repos: down, degraded, ok, then unknown; within a state
117
+ * the focused workspace's repos first, then by name.
118
+ * @param {{ state: RepoState, repo: string, focused?: boolean }} a
119
+ * @param {{ state: RepoState, repo: string, focused?: boolean }} b
120
+ * @returns {number}
121
+ */
122
+ export function compareRepos(a, b) {
123
+ return (
124
+ (STATE_RANK[a.state] ?? 3) - (STATE_RANK[b.state] ?? 3) ||
125
+ Number(!!b.focused) - Number(!!a.focused) ||
126
+ String(a.repo).localeCompare(String(b.repo))
127
+ );
128
+ }
@@ -0,0 +1,287 @@
1
+ /**
2
+ * The UI's Spanish catalog (R19, 0.3.0-dev.39). A classic script the
3
+ * server loads before shell.js for a page in Spanish (ui-language.ts); it
4
+ * adds its table to window.denMessages, and shell.js's t() reads it. Every
5
+ * key of shell.js's en is here (tests/unit/server/i18n.test.ts). A `.one`
6
+ * key is the form for n = 1 (Intl.PluralRules("es")).
7
+ */
8
+ (function (m) {
9
+ m.es = {
10
+ "g.pinned": "Fijados",
11
+ "g.develop": "Desarrollo",
12
+ "g.verify": "Verificación",
13
+ "g.ship": "Entrega",
14
+ "n.workspaces": "Espacios de trabajo",
15
+ "n.graph": "Grafo",
16
+ "n.services": "Servicios",
17
+ "n.logs": "Registros",
18
+ "n.tests": "Pruebas",
19
+ "n.environments": "Entornos",
20
+ "n.releases": "Versiones",
21
+ "n.edge": "Edge",
22
+ "n.settings": "Ajustes",
23
+ "k.org": "Org",
24
+ "k.ws": "Espacio",
25
+ "k.env": "Entorno",
26
+ scope: "Ámbito",
27
+ "org.title": "Org: {title}",
28
+ "org.titleId": "Org: {title} ({id})",
29
+ "ws.all": "Todos los activos",
30
+ "ws.focus": "foco",
31
+ "ws.none": "No hay espacios de trabajo activos",
32
+ "ws.manage": "Gestionar espacios de trabajo…",
33
+ "ws.allN": "Todos los activos ({n})",
34
+ "ws.allTip":
35
+ "Todos los espacios de trabajo activos; un servicio que definen varios aparece una sola vez",
36
+ "ws.noneLabel": "ninguno",
37
+ "ws.viewTitle":
38
+ "Vista: lo que muestra cada página ({ws}). Es solo un filtro: no inicia, detiene ni enruta nada.",
39
+ "ws.viewTitleFocus":
40
+ "Vista: lo que muestra cada página ({ws}). Es solo un filtro: no inicia, detiene ni enruta nada, y el foco ({focus}) sigue siendo el destino de los comandos.",
41
+ "ws.setFocus": "Poner el foco en {ws}",
42
+ "ws.setFocusTip":
43
+ "Lo convierte en el destino por defecto de los comandos (escribe workspaces.yml)",
44
+ "ws.viewFailed": "No se pudo cambiar la vista: {msg}",
45
+ "ws.focusFailed": "No se pudo poner el foco: {msg}",
46
+ "org.n": "{n} espacios de trabajo",
47
+ "org.n.one": "{n} espacio de trabajo",
48
+ from: "de {d}",
49
+ "b.logs": "{n} abiertos",
50
+ "b.logs.one": "{n} abierto",
51
+ "b.down": "{n} caídos",
52
+ "b.down.one": "{n} caído",
53
+ "act.pin": "Fijar",
54
+ "act.unpin": "Quitar",
55
+ "act.pinX": "Fijar {s}",
56
+ "act.unpinX": "Quitar {s}",
57
+ "toast.pinned": "{s} fijado",
58
+ "toast.unpinned": "{s} ya no está fijado",
59
+ collapse: "Contraer",
60
+ expand: "Expandir",
61
+ menu: "Menú",
62
+ skip: "Saltar al contenido",
63
+ pages: "Páginas",
64
+ "search.ph": "Buscar páginas, servicios, acciones…",
65
+ "status.checking": "Comprobando…",
66
+ "status.none": "Sin servicios",
67
+ "status.unchecked": "{n} sin comprobar",
68
+ "status.all": "Los {n} en buen estado",
69
+ "status.all.one": "{n} en buen estado",
70
+ "status.some": "{ok}/{n} en buen estado",
71
+ "status.down": "{n} caídos",
72
+ "status.down.one": "{n} caído",
73
+ "status.title": "{n} comprobados",
74
+ "status.title.one": "{n} comprobado",
75
+ "status.pending": "{n} pendientes",
76
+ "status.pending.one": "{n} pendiente",
77
+ "status.awaiting": "{n} aún comprobándose",
78
+ "status.unknown": "Estado desconocido",
79
+ "status.unknownTip":
80
+ "El servidor de Den no responde, así que no se sabe el estado de los servicios",
81
+ "chk.awaiting": "aún comprobándose",
82
+ "chk.pending": "{what} — pendiente",
83
+ "chk.check": "comprobación",
84
+ "chk.unchecked": "sin comprobar",
85
+ "chk.healthy": "en buen estado",
86
+ "chk.down": "caído",
87
+ "chk.pendingWord": "pendiente",
88
+ "chk.checking": "comprobando…",
89
+ ms: "{n} ms",
90
+ "fix.failedAt": "{line} · falló a las {at}",
91
+ "fix.start": "Iniciar",
92
+ "fix.startX": "Iniciar {s}",
93
+ "fix.logs": "Registros",
94
+ "fix.logsX": "Registros de {s}",
95
+ "row.name": "{id}, {state}",
96
+ "row.nameMs": "{id}, {state}, {ms}",
97
+ "drawer.title": "Estado",
98
+ "drawer.refresh": "Comprobar de nuevo",
99
+ "drawer.close": "Cerrar",
100
+ "drawer.attention": "Requiere atención",
101
+ "drawer.nothing": "Nada requiere atención.",
102
+ "drawer.everything": "Todo",
103
+ "drawer.okTip": "{ok} de {n} servicios comprobados en buen estado",
104
+ "drawer.okTip.one": "{ok} de {n} servicio comprobado en buen estado",
105
+ "toast.openWs": "Abre Espacios de trabajo para ejecutarlo",
106
+ "kind.page": "Página",
107
+ "kind.service": "Servicio",
108
+ "kind.app": "App",
109
+ "kind.action": "Acción",
110
+ "kind.setting": "Ajuste",
111
+ "pal.repos": "{n} repositorios",
112
+ "pal.repos.one": "{n} repositorio",
113
+ "pal.restart": "Reiniciar {s}",
114
+ "pal.results": "Resultados",
115
+ "pal.move": "↑↓ para moverte",
116
+ "pal.open": "↵ para abrir",
117
+ "pal.close": "esc para cerrar",
118
+ "pal.none": "Sin coincidencias",
119
+ "pal.count": "{n} resultados",
120
+ "pal.count.one": "{n} resultado",
121
+ "runs.title": "Ejecuciones",
122
+ "runs.n": "{n} en ejecución",
123
+ "runs.aria": "Ejecuciones, {n} en ejecución",
124
+ "runs.last": "Última ejecución: {s}",
125
+ "runs.none": "Sin ejecuciones",
126
+ "runs.empty":
127
+ "Aún no se ha ejecutado nada. La salida de cualquier página aparece aquí.",
128
+ "runs.toast":
129
+ "Aún no se ha ejecutado nada. La salida de una página aparece aquí.",
130
+ "runs.all": "Todas",
131
+ "runs.allTip": "Se muestran las ejecuciones de {ws}; pulsa para ver todas",
132
+ "runs.allOn":
133
+ "Se muestran todas las ejecuciones; pulsa para ver solo las de {ws}",
134
+ "dock.done": "terminó en {s} s",
135
+ "dock.failed": "falló en {s} s",
136
+ "dock.close": "Ocultar ejecuciones",
137
+ "dock.show": "Mostrar ejecuciones",
138
+ "dock.copy": "Copiar",
139
+ "dock.copied": "¡Copiado!",
140
+ "dock.clear": "Borrar",
141
+ "dock.closeRun": "Cerrar {s}",
142
+ "dock.err": "falló",
143
+ "dock.last": "Última ejecución: {s} ↗",
144
+ "dock.resize": "Arrastra para cambiar el tamaño",
145
+ "lock.locked": "Bloqueado",
146
+ "lock.unlocked": "Desbloqueado",
147
+ "lock.title": "Desbloquea para iniciar, detener y reiniciar servicios",
148
+ "lock.nopw":
149
+ "sudo sin contraseña (NOPASSWD): no hace falta la contraseña de administrador",
150
+ "lock.session": "Desbloqueado durante esta sesión",
151
+ "lock.sessionDesc":
152
+ "Desbloqueado durante esta sesión: iniciar, detener y reiniciar funcionan en todas las páginas.",
153
+ "lock.cfg":
154
+ "Guardar la contraseña está desactivado: define secrets.provider y secrets.refs.sudo en {file}.",
155
+ "lock.update": "Actualizar la contraseña guardada",
156
+ "lock.saveTo": "Guardar en {s}",
157
+ "lock.pw": "Contraseña de administrador",
158
+ "lock.go": "Desbloquear",
159
+ "lock.checking": "Comprobando…",
160
+ "lock.note":
161
+ "Den la pide una vez por sesión. Los agentes no pueden desbloquear.",
162
+ "lock.again": "Escribir la contraseña de nuevo…",
163
+ "lock.saveFailed": "Desbloqueado, pero no se pudo guardar en {s}: {err}",
164
+ "lock.wrong": "Contraseña incorrecta; inténtalo de nuevo",
165
+ "lock.reqFailed": "La solicitud falló: ¿está en marcha el servidor?",
166
+ "v.title": "Ver el registro de cambios",
167
+ "cl.title": "Novedades",
168
+ "cl.close": "Cerrar",
169
+ "cl.gotIt": "Entendido",
170
+ "cl.none": "No hay entradas.",
171
+ "cl.copyMd": "Copiar como Markdown",
172
+ "cl.copyMdX": "Copiar v{v} como Markdown",
173
+ "cl.copySlack": "Copiar para Slack",
174
+ "cl.copySlackX": "Copiar v{v} para Slack",
175
+ "cl.copyFailed": "No se pudo copiar; inténtalo de nuevo",
176
+ "cl.latest": "Mostrar solo la última",
177
+ "cl.all": "Mostrar todas las versiones ({n} anteriores)",
178
+ "cl.all.one": "Mostrar todas las versiones ({n} anterior)",
179
+ "stale.title":
180
+ "Este servidor web de {cli} ejecuta código más antiguo que tu copia de trabajo: haz clic para reiniciarlo y cargar tus cambios. Los despliegues en curso siguen en GitHub; un registro de despliegue abierto se reconecta tras recargar.",
181
+ "stale.aria": "Servidor desactualizado: reiniciar",
182
+ "stale.label": "servidor desactualizado",
183
+ "stale.restart": "Reiniciar",
184
+ "restart.msg": "Reiniciando {cli} web…",
185
+ "restart.hint": "Reconectando: esta página se recargará sola.",
186
+ "restart.still":
187
+ "Sigue reiniciándose… si persiste, ejecuta {cmd} en una terminal y recarga.",
188
+ "um.label": "Apariencia",
189
+ "um.title": "Apariencia y tema",
190
+ "um.appearance": "Apariencia",
191
+ "um.system": "Sistema",
192
+ "um.dark": "Oscuro",
193
+ "um.light": "Claro",
194
+ "um.theme": "Tema",
195
+ "um.language": "Idioma",
196
+ "um.all": "Todos los ajustes",
197
+ "cmd.appearance": "Apariencia: {mode}",
198
+ "cmd.theme": "Tema: {name}",
199
+ "cmd.language": "Idioma: {name}",
200
+ "theme.orgDefault": "Predeterminado de la org ({name})",
201
+ "theme.pinned": "{name} (fijado)",
202
+ "theme.notInstalled":
203
+ "Tu tema {id} no está instalado, así que se usa {inUse}",
204
+ "theme.invalid":
205
+ "Tu tema {id} no es válido ({why}), así que se usa {inUse}",
206
+ "theme.invalidBare": "Tu tema {id} no es válido, así que se usa {inUse}",
207
+ "api.network": "El servidor de Den no respondió a {what}",
208
+ "api.failed": "{what} falló",
209
+ "api.request": "Solicitud {id}",
210
+ "api.retry": "Reintentar",
211
+ "api.copy": "Copiar detalles",
212
+ "api.copied": "Copiado",
213
+ "api.close": "Descartar",
214
+ "api.retried": "Hecho",
215
+ "net.down": "El servidor de Den no responde; reintentando",
216
+ "net.next": "próximo intento en {s} s",
217
+ "net.now": "Reintentar ahora",
218
+ "engine.stale":
219
+ "Den se actualizó a {onDisk}. Este servidor sigue ejecutando {loaded}. Reinícialo: {cli} web restart (o el reinicio de tu servicio).",
220
+ "engine.title": "Hay que reiniciar",
221
+ "err.404.title": "Página no encontrada",
222
+ "err.404.sub": "No hay nada en {path}",
223
+ "err.404.lead": "No hay ninguna página en esta dirección.",
224
+ "err.404.mean": "¿Querías decir {page}?",
225
+ "err.404.stale":
226
+ "Puede que esta página sea nueva en Den {onDisk}: el servidor sigue ejecutando {loaded}.",
227
+ "err.404.plugin":
228
+ "Esta página pertenece al plugin {name}, que no está instalado en esta distribución.",
229
+ "err.404.pluginLocked":
230
+ "Esta página pertenece al plugin {name}. Está en plugins.lock.json, pero faltan sus archivos.",
231
+ "err.404.pluginNoPage":
232
+ "El plugin {name} está instalado, pero no tiene ninguna página aquí.",
233
+ "err.404.workspaces": "Ir a Espacios de trabajo",
234
+ "err.404.search": "Buscar",
235
+ "err.404.pages": "Páginas",
236
+ "err.500.title": "Algo salió mal",
237
+ "err.500.sub": "{what} falló en el servidor",
238
+ "err.500.lead":
239
+ "El servidor tuvo un error al responder a esta página. Reintenta o copia los detalles para un informe: el registro del servidor tiene el error completo con el mismo id de solicitud.",
240
+ "err.500.what": "Qué falló",
241
+ "err.500.time": "Hora",
242
+ "err.500.id": "Id de solicitud",
243
+ "err.500.version": "Versión",
244
+ "err.422.title": "La configuración no es válida",
245
+ "err.422.sub": "La configuración de la distribución no pasa la validación",
246
+ "err.422.lead":
247
+ "Las páginas que leen la configuración esperan hasta que sea válida. Corrige cada clave de abajo; mientras tanto, Ajustes y Registros siguen funcionando.",
248
+ "err.422.file": "Archivo",
249
+ "err.422.key": "Clave",
250
+ "err.422.problem": "Problema",
251
+ "err.422.cmd": "Para ver lo mismo en una terminal, ejecuta:",
252
+ "err.422.reload": "Recargar cuando esté corregido",
253
+ "err.422.logs": "Abrir Registros",
254
+ "err.422.settings": "Abrir Ajustes",
255
+ "set.appearance.mode": "Modo",
256
+ "set.appearance.theme": "Tema",
257
+ "set.language": "Idioma",
258
+ "set.appearance.org-theme": "Tema predeterminado de la org",
259
+ "set.editor": "IDE predeterminado",
260
+ "set.editor_overrides": "IDE por lenguaje",
261
+ "set.terminal": "Terminal predeterminada",
262
+ "set.shell.pages": "Páginas",
263
+ "set.shell.pins": "Fijados",
264
+ "set.shell.collapsed": "Contraer la barra lateral",
265
+ "set.shell.dock": "Abrir el panel de ejecuciones",
266
+ "set.graph.workspaces": "Lista de espacios de trabajo",
267
+ "set.graph.groupBy": "Agrupar repositorios por",
268
+ "set.graph.direction": "Dirección",
269
+ "set.graph.group": "Marcos",
270
+ "set.graph.density": "Tarjetas",
271
+ "set.graph.panelWidth": "Panel de detalles",
272
+ "set.workspace.editor": "IDE de este espacio de trabajo",
273
+ "set.cli.local_dev": "Entorno local",
274
+ "set.cli.cli_tabs": "Pestañas de terminal",
275
+ "set.cli.log_window_lines": "Líneas del panel de registros",
276
+ "set.cli.web_port": "Tu puerto web",
277
+ "set.distribution.brand": "Nombre del producto",
278
+ "set.distribution.github_org": "Org de GitHub",
279
+ "set.distribution.orgs": "Etiquetas de org",
280
+ "set.distribution.web_port": "Puerto web",
281
+ "set.distribution.environments": "Entornos",
282
+ "set.distribution.domain": "Dominio de edge",
283
+ "err.retry": "Reintentar",
284
+ "err.copy": "Copiar detalles",
285
+ "err.copied": "Copiado",
286
+ };
287
+ })((window.denMessages = window.denMessages || {}));