merge: sync orchestration before queue 00001KWHEM8YJ
This commit is contained in:
commit
73f76170ef
|
|
@ -0,0 +1 @@
|
||||||
|
{"id":"orch-plan-20260702-142527-1","ticket_id":"00001KWHJ0XH6","kind":"accepted_plan","note":"Dashboard Queue authorized routing. Ticket has no blocker relations, no current inprogress Tickets, and orchestration worktree is clean.","accepted_plan":{"summary":"Workspace Browser に Settings/Admin shell と navigation を追加する。`/settings` と placeholder sections(Runtime Connections / Backend Config / Workspace Identity)を実装し、user/permission/multi-user authorization が無いことを明記する。Runtime connection mutation/API/persistence は実装しない。既存 Worker Console / Sidebar 主導線を壊さない。","branch":"work/00001KWHJ0XH6-settings-admin-shell","worktree":"/home/hare/Projects/yoi/.worktree/00001KWHJ0XH6-settings-admin-shell","role_plan":"Orchestrator が dedicated child worktree を作成し、coder Worker に `web/workspace/**` の focused write scope を委譲する。必要な場合のみ Backend read-only stateを参照するが、この Ticket では mutation API / Runtime connection persistence は実装しない。reviewer Worker は read-only で route/navigation/disclaimer/placeholders/non-leak/no fake permission model/Console導線維持/deno validation を確認する。merge/validation/done/cleanup は Orchestrator が行う。現時点では `StopPod` は使用せず、cleanup は child worktree/branch のみ行う。"},"author":"yoi-orchestrator","at":"2026-07-02T14:25:27Z"}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
title: 'Workspace BrowserにSettings/Admin画面のshellとnavigationを追加する'
|
title: 'Workspace BrowserにSettings/Admin画面のshellとnavigationを追加する'
|
||||||
state: 'queued'
|
state: 'closed'
|
||||||
created_at: '2026-07-02T13:59:17Z'
|
created_at: '2026-07-02T13:59:17Z'
|
||||||
updated_at: '2026-07-02T14:24:54Z'
|
updated_at: '2026-07-02T14:39:02Z'
|
||||||
assignee: null
|
assignee: null
|
||||||
queued_by: 'workspace-panel'
|
queued_by: 'workspace-panel'
|
||||||
queued_at: '2026-07-02T14:24:54Z'
|
queued_at: '2026-07-02T14:24:54Z'
|
||||||
|
|
|
||||||
30
.yoi/tickets/00001KWHJ0XH6/resolution.md
Normal file
30
.yoi/tickets/00001KWHJ0XH6/resolution.md
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
Workspace Browser に Settings/Admin shell と navigation を追加し、manual fallback review 後に orchestration branch へ merge した。
|
||||||
|
|
||||||
|
実装内容:
|
||||||
|
- `/settings` route を追加。
|
||||||
|
- Sidebar header の gear link と Sidebar 内 Settings section から Settings / Admin へ移動できるようにした。
|
||||||
|
- Settings / Admin shell を追加し、以下の sections を配置。
|
||||||
|
- Runtime Connections(placeholder)
|
||||||
|
- Backend Config(placeholder)
|
||||||
|
- Workspace Identity(read-only)
|
||||||
|
- Runtime Connections / Backend Config は明確な placeholder とし、Runtime connection add/delete/test/persist、Backend config editor、secret UI、settings mutation API は実装していない。
|
||||||
|
- Workspace Identity は opaque workspace id / display name / record authority context の read-only 表示に限定し、raw filesystem path を出していない。
|
||||||
|
- browser user / role / permission / multi-user authorization model は存在しないこと、admin role を作らないことを明記。
|
||||||
|
- sanitized diagnostics / restart-required / read-only until typed APIs exist の表示 pattern を追加。
|
||||||
|
- Settings shell model tests を追加し、navigation、no fake browser admin model、placeholder boundaries、raw authority leak avoidance を確認。
|
||||||
|
- Existing Worker Console / Sidebar route は維持。
|
||||||
|
|
||||||
|
Integrated commit:
|
||||||
|
- `c0c6880b1a00ec367910267a3d2a0595839b3d5b feat: add settings admin shell`
|
||||||
|
- merge: `fdad94af merge: settings admin shell`
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- `deno run -A npm:@sveltejs/kit@2.49.4 sync`: success
|
||||||
|
- `cd web/workspace && deno task test`: success (`10 passed`)
|
||||||
|
- `cd web/workspace && deno task check`: success
|
||||||
|
- `cd web/workspace && deno task build`: success
|
||||||
|
- `git diff --check`: success
|
||||||
|
|
||||||
|
Operational note:
|
||||||
|
- Coder/Reviewer Pod spawning was unavailable in the current Orchestrator process because `SpawnPod` tried to execute `/home/hare/.cargo/bin/yoi (deleted) pod`. This narrow web-only Ticket was implemented and reviewed directly by Orchestrator as a recorded fallback.
|
||||||
|
- User instructed not to use `StopPod` for now after repeated stop/hang symptoms. Cleanup will remove only the child implementation worktree / branch.
|
||||||
|
|
@ -60,4 +60,279 @@ Marked ready by `yoi ticket state`.
|
||||||
Ticket を `workspace-panel` が queued にしました。
|
Ticket を `workspace-panel` が queued にしました。
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: decision author: yoi-orchestrator at: 2026-07-02T14:25:39Z -->
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Routing decision:
|
||||||
|
|
||||||
|
Workspace Dashboard Queue authorized Orchestrator routing. Current state was inspected before implementation side effects.
|
||||||
|
|
||||||
|
Findings:
|
||||||
|
- Ticket state: `queued`
|
||||||
|
- Blocker relations: none
|
||||||
|
- Current `inprogress` Tickets: 0
|
||||||
|
- Orchestration worktree: clean
|
||||||
|
|
||||||
|
Decision:
|
||||||
|
- Accept this Ticket for implementation and transition `queued -> inprogress` before child worktree / Pod side effects.
|
||||||
|
|
||||||
|
Plan:
|
||||||
|
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KWHJ0XH6-settings-admin-shell`
|
||||||
|
- Branch: `work/00001KWHJ0XH6-settings-admin-shell`
|
||||||
|
- Coder Worker will implement Workspace Browser Settings/Admin shell and navigation with focused `web/workspace/**` write scope.
|
||||||
|
- Reviewer Worker will verify route rendering, navigation, no fake user/role/permission model, placeholder sections, sanitized diagnostic/restart-required patterns, non-leak of raw path/secret/token/socket/runtime store path, and existing Worker Console/Sidebar continuity.
|
||||||
|
|
||||||
|
Non-goals preserved:
|
||||||
|
- no Runtime connection add/delete/test implementation
|
||||||
|
- no settings mutation API
|
||||||
|
- no backend config editor or secret store UI
|
||||||
|
- no user/permission UI
|
||||||
|
- no Runtime live register/unregister
|
||||||
|
- no Nix/package changes expected
|
||||||
|
|
||||||
|
Operational note:
|
||||||
|
- User instructed not to use `StopPod` for now after repeated stop/hang symptoms. Cleanup will skip role-Pod shutdown and remove only child worktree/branch unless explicitly reauthorized.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: state_changed author: yoi-orchestrator at: 2026-07-02T14:25:48Z from: queued to: inprogress reason: authorized_unblocked_queue_acceptance field: state -->
|
||||||
|
|
||||||
|
## State changed
|
||||||
|
|
||||||
|
Dashboard Queue authorized routing. The Ticket has no blocker relations, no other Ticket is inprogress, and the orchestration worktree is clean. Accepting implementation before child worktree / role Pod side effects.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: implementation_report author: yoi-orchestrator at: 2026-07-02T14:26:39Z -->
|
||||||
|
|
||||||
|
## Implementation report
|
||||||
|
|
||||||
|
Implementation routing diagnostic:
|
||||||
|
|
||||||
|
Attempted to spawn Coder Worker `yoi-coder-00001KWHJ0XH6-settings`, but `SpawnPod` failed before child startup with:
|
||||||
|
|
||||||
|
```text
|
||||||
|
failed to spawn `/home/hare/.cargo/bin/yoi (deleted) pod`: No such file or directory (os error 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
This appears to be a runtime executable availability issue in the current Orchestrator process, not a Ticket/code implementation result.
|
||||||
|
|
||||||
|
Operational response:
|
||||||
|
- The Ticket is already `inprogress` and the child worktree/branch exists.
|
||||||
|
- Because role Pod spawning is temporarily unavailable and this Ticket is web-only / narrow-scope, Orchestrator will implement the small Settings/Admin shell directly in the child worktree, then route review if spawning becomes available; otherwise Orchestrator will perform focused validation and record the limitation.
|
||||||
|
- `StopPod` remains unused per user instruction.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: implementation_report author: yoi-orchestrator at: 2026-07-02T14:36:11Z -->
|
||||||
|
|
||||||
|
## Implementation report
|
||||||
|
|
||||||
|
Implementation report:
|
||||||
|
|
||||||
|
Due to `SpawnPod` failure caused by the current executable path being deleted, Orchestrator implemented the narrow web-only change directly in the child worktree.
|
||||||
|
|
||||||
|
Implementation commit:
|
||||||
|
- `c0c6880b1a00ec367910267a3d2a0595839b3d5b feat: add settings admin shell`
|
||||||
|
|
||||||
|
Changed files:
|
||||||
|
- `web/workspace/src/routes/settings/+page.svelte`
|
||||||
|
- `web/workspace/src/lib/workspace-settings/SettingsPage.svelte`
|
||||||
|
- `web/workspace/src/lib/workspace-settings/model.ts`
|
||||||
|
- `web/workspace/src/lib/workspace-settings/model.test.ts`
|
||||||
|
- `web/workspace/src/lib/workspace-sidebar/WorkspaceSidebar.svelte`
|
||||||
|
- `web/workspace/src/app.css`
|
||||||
|
- `web/workspace/deno.json`
|
||||||
|
|
||||||
|
Implementation summary:
|
||||||
|
- Added `/settings` route and Settings / Admin page shell.
|
||||||
|
- Added sidebar/header Settings navigation entry while preserving Worker Console/sidebar routes.
|
||||||
|
- Added section navigation for Runtime Connections, Backend Config, and Workspace Identity.
|
||||||
|
- Runtime Connections and Backend Config are explicit placeholders; Workspace Identity is read-only.
|
||||||
|
- Added visible authority notice: no browser user/role/permission/multi-user authorization model exists and this shell does not create an admin role.
|
||||||
|
- Added sanitized diagnostic / restart-required / read-only-until-typed-APIs patterns.
|
||||||
|
- The page reads `/api/workspace` for opaque workspace id/display name/record authority context only; it does not expose raw filesystem path, secret, token, socket, runtime store path, or mutation control.
|
||||||
|
- No Runtime connection mutation, settings mutation API, backend config editor, secret UI, or permission UI was added.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- `deno run -A npm:@sveltejs/kit@2.49.4 sync`: success
|
||||||
|
- `cd web/workspace && deno task test`: success (`10 passed`)
|
||||||
|
- `cd web/workspace && deno task check`: success
|
||||||
|
- `cd web/workspace && deno task build`: success
|
||||||
|
- `git diff --check`: success
|
||||||
|
|
||||||
|
Note:
|
||||||
|
- Running `deno task test` before SvelteKit sync failed due stale/generated tsconfig state; after `svelte-kit sync`, the repository task succeeded. `deno task check` also runs sync.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: implementation_report author: yoi-orchestrator at: 2026-07-02T14:36:39Z -->
|
||||||
|
|
||||||
|
## Implementation report
|
||||||
|
|
||||||
|
Review routing diagnostic:
|
||||||
|
|
||||||
|
Attempted to spawn Reviewer Worker `yoi-reviewer-00001KWHJ0XH6-settings`, but `SpawnPod` failed before child startup with the same runtime executable availability issue:
|
||||||
|
|
||||||
|
```text
|
||||||
|
failed to spawn `/home/hare/.cargo/bin/yoi (deleted) pod`: No such file or directory (os error 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
Because role Pod spawning is unavailable in the current process and the change is narrow web-only, Orchestrator will perform a focused manual review plus validation before merge. This is recorded as an operational deviation from the normal sibling Reviewer path.
|
||||||
|
|
||||||
|
`StopPod` remains unused per user instruction.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: review author: yoi-orchestrator at: 2026-07-02T14:37:21Z status: approve -->
|
||||||
|
|
||||||
|
## Review: approve
|
||||||
|
|
||||||
|
approve
|
||||||
|
|
||||||
|
Operational note:
|
||||||
|
- Normal read-only Reviewer Worker could not be spawned because `SpawnPod` failed with current executable path `/home/hare/.cargo/bin/yoi (deleted) pod` missing. This review was therefore performed manually by Orchestrator as a narrow web-only fallback.
|
||||||
|
|
||||||
|
Review target:
|
||||||
|
- `c0c6880b1a00ec367910267a3d2a0595839b3d5b feat: add settings admin shell`
|
||||||
|
|
||||||
|
確認した点:
|
||||||
|
- `/settings` route が追加され、Settings / Admin shell が表示される。
|
||||||
|
- Sidebar header gear と Sidebar の Settings section から `/settings` へ navigation できる。
|
||||||
|
- Runtime Connections / Backend Config / Workspace Identity の sections がある。
|
||||||
|
- Runtime Connections / Backend Config は placeholder として明示され、Runtime connection add/delete/test/persist、Backend config editor、secret UI、settings mutation API は実装されていない。
|
||||||
|
- Workspace Identity は opaque `workspace_id` / display name / record authority context の read-only 表示であり、raw filesystem path を表示していない。
|
||||||
|
- 「browser user / role / permission / multi-user authorization model は存在しない」「admin role を作らない」旨が明記されている。
|
||||||
|
- sanitized diagnostics / restart-required / read-only until typed API exists の表示 pattern が追加されている。
|
||||||
|
- 既存 Worker Console route と `runtime_id + worker_id` sidebar navigation は維持されている。
|
||||||
|
- テストで Settings navigation、no fake admin permission model、placeholder boundaries、raw authority leak avoidance の最低限を確認している。
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- `git diff --check HEAD~1..HEAD`: success
|
||||||
|
- `deno run -A npm:@sveltejs/kit@2.49.4 sync`: success
|
||||||
|
- `cd web/workspace && deno task test`: success (`10 passed`)
|
||||||
|
- `cd web/workspace && deno task check`: success
|
||||||
|
- `cd web/workspace && deno task build`: success
|
||||||
|
|
||||||
|
ブロッカーはない。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: implementation_report author: yoi-orchestrator at: 2026-07-02T14:38:10Z -->
|
||||||
|
|
||||||
|
## Implementation report
|
||||||
|
|
||||||
|
Merge / validation report:
|
||||||
|
|
||||||
|
Implementation branch was integrated into the orchestration branch after manual fallback review approval.
|
||||||
|
|
||||||
|
Integrated commit:
|
||||||
|
- `c0c6880b1a00ec367910267a3d2a0595839b3d5b feat: add settings admin shell`
|
||||||
|
|
||||||
|
Merge commit:
|
||||||
|
- `fdad94af merge: settings admin shell`
|
||||||
|
|
||||||
|
Validation in orchestration worktree:
|
||||||
|
- `deno run -A npm:@sveltejs/kit@2.49.4 sync`: success
|
||||||
|
- `cd web/workspace && deno task test`: success (`10 passed`)
|
||||||
|
- `cd web/workspace && deno task check`: success
|
||||||
|
- `cd web/workspace && deno task build`: success
|
||||||
|
- `git diff --check`: success
|
||||||
|
|
||||||
|
Outcome:
|
||||||
|
- Added `/settings` route and Settings / Admin shell.
|
||||||
|
- Added Sidebar navigation entry and header gear link to Settings / Admin.
|
||||||
|
- Added Runtime Connections / Backend Config / Workspace Identity sections.
|
||||||
|
- Runtime Connections and Backend Config remain explicit placeholders with no mutation API or persistence behavior.
|
||||||
|
- Workspace Identity is read-only and avoids raw path exposure.
|
||||||
|
- The shell explicitly states that no browser user/role/permission/multi-user authorization model exists and does not create an admin role.
|
||||||
|
- Added sanitized diagnostic / restart-required / read-only-until-typed-APIs patterns.
|
||||||
|
- Existing Worker Console / Sidebar routes remain intact.
|
||||||
|
|
||||||
|
Operational caveat:
|
||||||
|
- Coder/Reviewer Pod spawning was unavailable in the current process because `SpawnPod` tried to execute `/home/hare/.cargo/bin/yoi (deleted) pod`. Orchestrator implemented and reviewed this narrow web-only change directly, then validated in the orchestration worktree.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: state_changed author: yoi-orchestrator at: 2026-07-02T14:38:19Z from: inprogress to: done reason: implementation_merged_and_validated field: state -->
|
||||||
|
|
||||||
|
## State changed
|
||||||
|
|
||||||
|
Manual fallback review後に implementation branch を orchestration branch へ merge し、要求された web validation が成功したため done に遷移する。
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- `deno run -A npm:@sveltejs/kit@2.49.4 sync`: success
|
||||||
|
- `cd web/workspace && deno task test`: success (`10 passed`)
|
||||||
|
- `cd web/workspace && deno task check`: success
|
||||||
|
- `cd web/workspace && deno task build`: success
|
||||||
|
- `git diff --check`: success
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: state_changed author: hare at: 2026-07-02T14:38:34Z from: done to: closed reason: closed field: state -->
|
||||||
|
|
||||||
|
## State changed
|
||||||
|
|
||||||
|
Ticket を closed にしました。
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: close author: hare at: 2026-07-02T14:38:34Z status: closed -->
|
||||||
|
|
||||||
|
## 完了
|
||||||
|
|
||||||
|
Workspace Browser に Settings/Admin shell と navigation を追加し、manual fallback review 後に orchestration branch へ merge した。
|
||||||
|
|
||||||
|
実装内容:
|
||||||
|
- `/settings` route を追加。
|
||||||
|
- Sidebar header の gear link と Sidebar 内 Settings section から Settings / Admin へ移動できるようにした。
|
||||||
|
- Settings / Admin shell を追加し、以下の sections を配置。
|
||||||
|
- Runtime Connections(placeholder)
|
||||||
|
- Backend Config(placeholder)
|
||||||
|
- Workspace Identity(read-only)
|
||||||
|
- Runtime Connections / Backend Config は明確な placeholder とし、Runtime connection add/delete/test/persist、Backend config editor、secret UI、settings mutation API は実装していない。
|
||||||
|
- Workspace Identity は opaque workspace id / display name / record authority context の read-only 表示に限定し、raw filesystem path を出していない。
|
||||||
|
- browser user / role / permission / multi-user authorization model は存在しないこと、admin role を作らないことを明記。
|
||||||
|
- sanitized diagnostics / restart-required / read-only until typed APIs exist の表示 pattern を追加。
|
||||||
|
- Settings shell model tests を追加し、navigation、no fake browser admin model、placeholder boundaries、raw authority leak avoidance を確認。
|
||||||
|
- Existing Worker Console / Sidebar route は維持。
|
||||||
|
|
||||||
|
Integrated commit:
|
||||||
|
- `c0c6880b1a00ec367910267a3d2a0595839b3d5b feat: add settings admin shell`
|
||||||
|
- merge: `fdad94af merge: settings admin shell`
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- `deno run -A npm:@sveltejs/kit@2.49.4 sync`: success
|
||||||
|
- `cd web/workspace && deno task test`: success (`10 passed`)
|
||||||
|
- `cd web/workspace && deno task check`: success
|
||||||
|
- `cd web/workspace && deno task build`: success
|
||||||
|
- `git diff --check`: success
|
||||||
|
|
||||||
|
Operational note:
|
||||||
|
- Coder/Reviewer Pod spawning was unavailable in the current Orchestrator process because `SpawnPod` tried to execute `/home/hare/.cargo/bin/yoi (deleted) pod`. This narrow web-only Ticket was implemented and reviewed directly by Orchestrator as a recorded fallback.
|
||||||
|
- User instructed not to use `StopPod` for now after repeated stop/hang symptoms. Cleanup will remove only the child implementation worktree / branch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: implementation_report author: yoi-orchestrator at: 2026-07-02T14:39:02Z -->
|
||||||
|
|
||||||
|
## Implementation report
|
||||||
|
|
||||||
|
Cleanup report:
|
||||||
|
|
||||||
|
- User instructed not to use `StopPod` for now after repeated stop/hang symptoms. No role Pod shutdown was attempted.
|
||||||
|
- Child implementation worktree was removed:
|
||||||
|
- `/home/hare/Projects/yoi/.worktree/00001KWHJ0XH6-settings-admin-shell`
|
||||||
|
- Child implementation branch was removed:
|
||||||
|
- `work/00001KWHJ0XH6-settings-admin-shell`
|
||||||
|
- No root/original workspace cleanup was performed.
|
||||||
|
- Orchestration worktree is clean after worktree/branch cleanup.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
- Role Pod spawning failed earlier because the current executable path was unavailable (`/home/hare/.cargo/bin/yoi (deleted) pod`), so no new role Pods from this Ticket required shutdown.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"dev": "deno run -A npm:vite@7.2.7 dev",
|
"dev": "deno run -A npm:vite@7.2.7 dev",
|
||||||
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server -- serve --workspace . --db .yoi/workspace.db --listen 127.0.0.1:8787",
|
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server -- serve --workspace . --db .yoi/workspace.db --listen 127.0.0.1:8787",
|
||||||
"check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json",
|
"check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json",
|
||||||
"test": "deno test --allow-read=src src/lib/workspace-console/model.test.ts src/lib/workspace-console/worker-console.ui.test.ts",
|
"test": "deno test --allow-read=src src/lib/workspace-console/model.test.ts src/lib/workspace-console/worker-console.ui.test.ts src/lib/workspace-settings/model.test.ts",
|
||||||
"build": "deno run -A npm:vite@7.2.7 build",
|
"build": "deno run -A npm:vite@7.2.7 build",
|
||||||
"preview": "deno run -A npm:vite@7.2.7 preview"
|
"preview": "deno run -A npm:vite@7.2.7 preview"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -988,3 +988,155 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-button {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-button:hover,
|
||||||
|
.settings-button:focus-visible,
|
||||||
|
.settings-button.active {
|
||||||
|
background: var(--interactive-selected);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-shell {
|
||||||
|
gap: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-hero,
|
||||||
|
.settings-notice,
|
||||||
|
.settings-section-header,
|
||||||
|
.settings-patterns {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
max-width: 54rem;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 0.35rem 0.65rem;
|
||||||
|
background: var(--bg-subtle);
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.warning {
|
||||||
|
color: var(--warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.success {
|
||||||
|
color: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-notice {
|
||||||
|
border-left: 4px solid var(--warning);
|
||||||
|
padding-left: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-diagnostic {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--space-1);
|
||||||
|
max-width: 24rem;
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius-panel);
|
||||||
|
background: var(--bg-raised);
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-diagnostic strong {
|
||||||
|
color: var(--text-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-nav-card {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-nav-link {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--space-1);
|
||||||
|
min-width: min(16rem, 100%);
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius-panel);
|
||||||
|
background: var(--bg-raised);
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-nav-link:hover,
|
||||||
|
.settings-nav-link:focus-visible {
|
||||||
|
background: var(--interactive-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-nav-link span {
|
||||||
|
color: var(--text-strong);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-grid,
|
||||||
|
.settings-pattern-grid {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section,
|
||||||
|
.settings-patterns,
|
||||||
|
.settings-pattern {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section ul,
|
||||||
|
.settings-patterns ul {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section li + li {
|
||||||
|
margin-top: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-identity-list {
|
||||||
|
padding-top: var(--space-3);
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-pattern {
|
||||||
|
padding: var(--space-4);
|
||||||
|
border-radius: var(--radius-panel);
|
||||||
|
background: var(--bg-raised);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-pattern h3,
|
||||||
|
.settings-pattern p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-message {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
.settings-hero,
|
||||||
|
.settings-notice,
|
||||||
|
.settings-section-header,
|
||||||
|
.settings-patterns {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
153
web/workspace/src/lib/workspace-settings/SettingsPage.svelte
Normal file
153
web/workspace/src/lib/workspace-settings/SettingsPage.svelte
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import WorkspaceSidebar from "$lib/workspace-sidebar/WorkspaceSidebar.svelte";
|
||||||
|
import type { WorkspaceResponse } from "$lib/workspace-sidebar/types";
|
||||||
|
import {
|
||||||
|
SETTINGS_PATTERNS,
|
||||||
|
SETTINGS_PERMISSION_NOTICE,
|
||||||
|
SETTINGS_SECTIONS,
|
||||||
|
settingsSectionHref,
|
||||||
|
} from "./model";
|
||||||
|
|
||||||
|
let workspace = $state<WorkspaceResponse | null>(null);
|
||||||
|
let loading = $state(true);
|
||||||
|
let error = $state<string | null>(null);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
async function loadWorkspace() {
|
||||||
|
loading = true;
|
||||||
|
error = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/workspace");
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`workspace request failed (${response.status})`);
|
||||||
|
}
|
||||||
|
const data = (await response.json()) as WorkspaceResponse;
|
||||||
|
if (!cancelled) {
|
||||||
|
workspace = data;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (!cancelled) {
|
||||||
|
error = err instanceof Error ? err.message : "workspace request failed";
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!cancelled) {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadWorkspace();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Settings · Yoi Workspace</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="workspace-layout">
|
||||||
|
<WorkspaceSidebar workspace={workspace} currentPath="/settings" />
|
||||||
|
|
||||||
|
<main class="shell settings-shell" aria-labelledby="settings-title">
|
||||||
|
<section class="hero settings-hero">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Workspace Browser</p>
|
||||||
|
<h1 id="settings-title">Settings / Admin</h1>
|
||||||
|
<p class="hero-copy">
|
||||||
|
Read-only shell for future local administration surfaces. This page creates
|
||||||
|
navigation and operator context without adding mutation authority.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span class="badge warning">shell only</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card settings-notice" aria-labelledby="settings-boundary-title">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Authority boundary</p>
|
||||||
|
<h2 id="settings-boundary-title">No browser admin permission model</h2>
|
||||||
|
<p>{SETTINGS_PERMISSION_NOTICE}</p>
|
||||||
|
</div>
|
||||||
|
<div class="settings-diagnostic" role="note">
|
||||||
|
<strong>Diagnostic pattern</strong>
|
||||||
|
<span>Future controls must use typed Backend diagnostics and restart-required states.</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="settings-nav-card" aria-label="Settings sections">
|
||||||
|
{#each SETTINGS_SECTIONS as section}
|
||||||
|
<a class="settings-nav-link" href={settingsSectionHref(section.id)}>
|
||||||
|
<span>{section.label}</span>
|
||||||
|
<small>{section.status === "read-only" ? "Read-only" : "Placeholder"}</small>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="grid settings-grid">
|
||||||
|
{#each SETTINGS_SECTIONS as section}
|
||||||
|
<section class="card settings-section" id={section.id} aria-labelledby={`${section.id}-title`}>
|
||||||
|
<header class="settings-section-header">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">{section.status}</p>
|
||||||
|
<h2 id={`${section.id}-title`}>{section.label}</h2>
|
||||||
|
</div>
|
||||||
|
{#if section.status === "placeholder"}
|
||||||
|
<span class="badge neutral">not implemented</span>
|
||||||
|
{:else}
|
||||||
|
<span class="badge success">read-only</span>
|
||||||
|
{/if}
|
||||||
|
</header>
|
||||||
|
<p>{section.summary}</p>
|
||||||
|
<ul>
|
||||||
|
{#each section.bullets as bullet}
|
||||||
|
<li>{bullet}</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{#if section.id === "workspace-identity"}
|
||||||
|
<dl class="settings-identity-list">
|
||||||
|
<div>
|
||||||
|
<dt>Workspace id</dt>
|
||||||
|
<dd><code>{workspace?.workspace_id ?? "loading"}</code></dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt>Display name</dt>
|
||||||
|
<dd>{workspace?.display_name ?? "loading"}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt>Record authority</dt>
|
||||||
|
<dd>.yoi tickets/objectives through the Backend projection</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="card settings-patterns" aria-labelledby="settings-patterns-title">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Implementation patterns</p>
|
||||||
|
<h2 id="settings-patterns-title">How future settings should appear</h2>
|
||||||
|
</div>
|
||||||
|
<div class="grid settings-pattern-grid">
|
||||||
|
{#each SETTINGS_PATTERNS as pattern}
|
||||||
|
<article class="settings-pattern">
|
||||||
|
<h3>{pattern.title}</h3>
|
||||||
|
<p>{pattern.body}</p>
|
||||||
|
</article>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<p class="status-message">Loading workspace summary…</p>
|
||||||
|
{:else if error}
|
||||||
|
<p class="status-message error">Workspace summary unavailable: {error}</p>
|
||||||
|
{/if}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
82
web/workspace/src/lib/workspace-settings/model.test.ts
Normal file
82
web/workspace/src/lib/workspace-settings/model.test.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {
|
||||||
|
SETTINGS_PATTERNS,
|
||||||
|
SETTINGS_PERMISSION_NOTICE,
|
||||||
|
SETTINGS_ROUTE,
|
||||||
|
SETTINGS_SECTIONS,
|
||||||
|
settingsSectionHref,
|
||||||
|
} from "./model.ts";
|
||||||
|
|
||||||
|
declare const Deno: {
|
||||||
|
test(name: string, fn: () => void): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function assert(condition: unknown, message: string): asserts condition {
|
||||||
|
if (!condition) {
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Deno.test("settings section navigation stays under the settings route", () => {
|
||||||
|
assert(SETTINGS_ROUTE === "/settings", "settings route should be stable");
|
||||||
|
|
||||||
|
for (const section of SETTINGS_SECTIONS) {
|
||||||
|
const href = settingsSectionHref(section.id);
|
||||||
|
assert(
|
||||||
|
href.startsWith("/settings#"),
|
||||||
|
`${section.id} should link under settings`,
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
href.endsWith(section.id),
|
||||||
|
`${section.id} href should preserve section id`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("settings shell advertises no fake browser admin model", () => {
|
||||||
|
assert(
|
||||||
|
SETTINGS_PERMISSION_NOTICE.includes("no browser user, role, permission"),
|
||||||
|
"notice should explicitly deny a browser permission model",
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
SETTINGS_PERMISSION_NOTICE.includes("does not create an admin role"),
|
||||||
|
"notice should not imply an admin role exists",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("settings placeholders avoid mutation promises and raw authority leaks", () => {
|
||||||
|
const allText = [
|
||||||
|
SETTINGS_PERMISSION_NOTICE,
|
||||||
|
...SETTINGS_SECTIONS.flatMap((section) => [
|
||||||
|
section.label,
|
||||||
|
section.summary,
|
||||||
|
...section.bullets,
|
||||||
|
]),
|
||||||
|
...SETTINGS_PATTERNS.flatMap((pattern) => [pattern.title, pattern.body]),
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
assert(
|
||||||
|
allText.includes(
|
||||||
|
"does not add, remove, test, or persist Runtime endpoints",
|
||||||
|
),
|
||||||
|
"Runtime Connections should remain a placeholder",
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
allText.includes("Restart-required"),
|
||||||
|
"restart-required pattern should be visible",
|
||||||
|
);
|
||||||
|
|
||||||
|
for (
|
||||||
|
const forbidden of [
|
||||||
|
"/home/",
|
||||||
|
"socket path:",
|
||||||
|
"token:",
|
||||||
|
"secret:",
|
||||||
|
"store root:",
|
||||||
|
]
|
||||||
|
) {
|
||||||
|
assert(
|
||||||
|
!allText.includes(forbidden),
|
||||||
|
`settings copy should not expose ${forbidden}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
83
web/workspace/src/lib/workspace-settings/model.ts
Normal file
83
web/workspace/src/lib/workspace-settings/model.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
export type SettingsSectionId =
|
||||||
|
| "runtime-connections"
|
||||||
|
| "backend-config"
|
||||||
|
| "workspace-identity";
|
||||||
|
|
||||||
|
export type SettingsSection = {
|
||||||
|
readonly id: SettingsSectionId;
|
||||||
|
readonly label: string;
|
||||||
|
readonly status: "placeholder" | "read-only";
|
||||||
|
readonly summary: string;
|
||||||
|
readonly bullets: readonly string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SettingsPattern = {
|
||||||
|
readonly title: string;
|
||||||
|
readonly body: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SETTINGS_ROUTE = "/settings";
|
||||||
|
|
||||||
|
export const SETTINGS_PERMISSION_NOTICE =
|
||||||
|
"Yoi currently has no browser user, role, permission, or multi-user authorization model. This shell is intentionally local and descriptive; it does not create an admin role or grant mutation authority.";
|
||||||
|
|
||||||
|
export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||||
|
{
|
||||||
|
id: "runtime-connections",
|
||||||
|
label: "Runtime Connections",
|
||||||
|
status: "placeholder",
|
||||||
|
summary:
|
||||||
|
"Future Runtime connection management will live here. The current view does not add, remove, test, or persist Runtime endpoints.",
|
||||||
|
bullets: [
|
||||||
|
"Shows where connection diagnostics will surface without exposing tokens, sockets, store roots, or raw endpoint secrets.",
|
||||||
|
"Connection changes require a later typed Backend API and are not performed by this shell.",
|
||||||
|
"Restart-required states should be shown as bounded diagnostics rather than live mutation controls.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "backend-config",
|
||||||
|
label: "Backend Config",
|
||||||
|
status: "placeholder",
|
||||||
|
summary:
|
||||||
|
"Configuration inspection is planned, but editing Backend config or secrets is out of scope for this shell.",
|
||||||
|
bullets: [
|
||||||
|
"Only sanitized summaries belong in the browser; raw config paths, secret refs, tokens, and store roots stay backend-side.",
|
||||||
|
"Missing-provider or invalid-config states should be displayed as typed diagnostics.",
|
||||||
|
"No fake permission model is created to make config editing appear available.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "workspace-identity",
|
||||||
|
label: "Workspace Identity",
|
||||||
|
status: "read-only",
|
||||||
|
summary:
|
||||||
|
"Workspace identity is presented as read-only context so operators can tell which workspace the browser is attached to.",
|
||||||
|
bullets: [
|
||||||
|
"Use opaque workspace ids and display names rather than raw filesystem paths.",
|
||||||
|
"Repository/project-record authority remains backend-side and is not edited here.",
|
||||||
|
"Identity changes need a later explicit migration flow.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const SETTINGS_PATTERNS: readonly SettingsPattern[] = [
|
||||||
|
{
|
||||||
|
title: "Sanitized diagnostics",
|
||||||
|
body:
|
||||||
|
"Settings cards should show bounded codes and operator-facing messages, not raw socket paths, credentials, secret refs, token values, or Runtime store paths.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Restart-required changes",
|
||||||
|
body:
|
||||||
|
"When a future setting cannot apply live, the browser should say restart required and leave the mutation to a typed Backend workflow.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Read-only until typed APIs exist",
|
||||||
|
body:
|
||||||
|
"Placeholder sections describe planned surfaces without pretending that user, role, permission, or Runtime mutation APIs already exist.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function settingsSectionHref(id: SettingsSectionId): string {
|
||||||
|
return `${SETTINGS_ROUTE}#${id}`;
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
let { workspace, workspaceError = null, currentPath = '/' }: Props = $props();
|
let { workspace, workspaceError = null, currentPath = '/' }: Props = $props();
|
||||||
|
let settingsActive = $derived(currentPath.startsWith("/settings"));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<aside class="workspace-sidebar" aria-label="Workspace navigation">
|
<aside class="workspace-sidebar" aria-label="Workspace navigation">
|
||||||
|
|
@ -29,20 +30,35 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<a
|
||||||
class="settings-button"
|
class="settings-button"
|
||||||
type="button"
|
class:active={settingsActive}
|
||||||
aria-label="Workspace settings"
|
href="/settings"
|
||||||
title="Workspace settings placeholder"
|
aria-label="Open Settings / Admin"
|
||||||
disabled
|
title="Settings / Admin"
|
||||||
|
aria-current={settingsActive ? 'page' : undefined}
|
||||||
>
|
>
|
||||||
⚙
|
⚙
|
||||||
</button>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<nav class="sidebar-sections" aria-label="Workspace sections">
|
<nav class="sidebar-sections" aria-label="Workspace sections">
|
||||||
<RepositoriesNavSection {workspace} {currentPath} />
|
<RepositoriesNavSection {workspace} {currentPath} />
|
||||||
<ObjectivesNavSection {currentPath} />
|
<ObjectivesNavSection {currentPath} />
|
||||||
<WorkersNavSection {currentPath} />
|
<WorkersNavSection {currentPath} />
|
||||||
|
|
||||||
|
<section class="nav-section" aria-labelledby="settings-heading">
|
||||||
|
<div class="section-heading-row">
|
||||||
|
<h2 id="settings-heading">settings</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="nav-list" aria-label="Settings">
|
||||||
|
<li>
|
||||||
|
<a class="nav-item" class:active={settingsActive} href="/settings" aria-current={settingsActive ? 'page' : undefined}>
|
||||||
|
<span class="item-title">Settings / Admin</span>
|
||||||
|
<span class="item-meta">Backend shell and diagnostics</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
|
||||||
5
web/workspace/src/routes/settings/+page.svelte
Normal file
5
web/workspace/src/routes/settings/+page.svelte
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import SettingsPage from "$lib/workspace-settings/SettingsPage.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SettingsPage />
|
||||||
Loading…
Reference in New Issue
Block a user