This commit is contained in:
@@ -2,3 +2,4 @@ VITE_GITEA_BASE_URL=http://gitea.orson.tealthrone
|
||||
VITE_GITEA_TOKEN=
|
||||
VITE_GITEA_REPO_OWNER=jacob-mathison
|
||||
VITE_GITEA_REPO_NAME=mp-silma-ai-aide
|
||||
VITE_LOCAL_CONTEXT_URL=http://127.0.0.1:23873/local-context.json
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
- Codex setup: `npm run codex:setup`
|
||||
- Run local Vite dev server: `npm run dev`
|
||||
- Run app in Codex: `npm run dev:codex`
|
||||
- Run live local context server: `npm run context:serve`
|
||||
- Build extension: `npm run build`
|
||||
- Build extension in Codex: `npm run build:codex`
|
||||
- Preview build output: `npm run preview`
|
||||
@@ -28,6 +29,7 @@ Configuration is read from Vite environment variables:
|
||||
- `VITE_GITEA_TOKEN`: Gitea API token.
|
||||
- `VITE_GITEA_REPO_OWNER`: Target Gitea owner. Default: `jacob-mathison`.
|
||||
- `VITE_GITEA_REPO_NAME`: Target Gitea repository. Default: `mp-silma-ai-aide`.
|
||||
- `VITE_LOCAL_CONTEXT_URL`: Optional live local context endpoint. Default: `http://127.0.0.1:23873/local-context.json`.
|
||||
|
||||
Use `.env.local` for local secrets. Keep `.env.local` and any real token-bearing env files out of git. Update `.env.example` when adding new required variables.
|
||||
|
||||
@@ -39,6 +41,8 @@ Use `.env.local` for local secrets. Keep `.env.local` and any real token-bearing
|
||||
- Static extension assets live in `public/`; extension icon sources live under `public/icons/`.
|
||||
- `scripts/generate-local-context.mjs` generates `public/local-context.json` from `/Users/Tabitha/.openclaw/workspace_Father` and configured local folder search roots before builds.
|
||||
- `public/local-context.json` is a committed fallback snapshot so CI builds can still produce a self-contained `dist/` if the local workspace root is unavailable. It includes generated workspaces, Gitea worktrees, known URLs, and searchable folder candidates for workspace selection.
|
||||
- `scripts/serve-local-context.mjs` serves a live local context endpoint that rescans workspaces on each request. Run `npm run context:serve` while using the extension locally when new projects should appear without rebuilding/reloading the bundled snapshot.
|
||||
- The side panel tries `VITE_LOCAL_CONTEXT_URL` first, falls back to bundled `/local-context.json`, and polls live local context every 10 seconds while URLs, Prompts, Workspaces, Add URL, or Add Workspace are active.
|
||||
- `npm run build` runs `scripts/verify-dist.mjs` after Vite to ensure the generated output has the required extension files.
|
||||
- Host permissions include `<all_urls>` for Chrome visible-tab screenshot capture plus the Gitea host derived from `VITE_GITEA_BASE_URL`. Rebuild after changing the base URL.
|
||||
- Runtime API calls are centralized in `src/api.ts`.
|
||||
|
||||
@@ -16,6 +16,12 @@ Run the Vite dev server:
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Run the live local context server when you want newly added local projects to appear in the side panel without rebuilding:
|
||||
|
||||
```bash
|
||||
npm run context:serve
|
||||
```
|
||||
|
||||
Build the Chrome extension:
|
||||
|
||||
```bash
|
||||
@@ -28,7 +34,7 @@ Static assets, including the extension icon assets, live in `public/` and are co
|
||||
|
||||
The app opens in the Chrome side panel. The top toolbar includes URLs, Gitea repos, Issues, Add Issue, and a management dropdown for Agents, Prompts, and Workspaces. URLs and Workspaces each have a first-row Add button that opens a modal dialog. Add URL is enabled only for an active tab base URL that is not already in the URLs list. URLs can be deleted from the list. Workspaces includes generated `workspace_Father` entries plus user-added absolute local paths stored in `chrome.storage.local`; workspace creation uses a searchable generated folder index instead of copy/paste path entry. The Prompts view manages workspace-scoped default prompts in `chrome.storage.local`; new prompt workspace selection defaults to the active known URL's workspace when available, and Add Issue shows matching prompts above Content and copies the selected prompt into the editable content field. The Agents view manages persisted agent files, starting with `GLOBAL AGENT` from `AGENTS.md`; agents can use variables such as `{{git}}`, `{{workspace}}`, and `{{url}}` in their markdown content. The default global agent tells downstream agents to close the Gitea issue after pushing the implementation and to comment when delivery is blocked, partial, or risky. Add Issue is enabled when the active tab base URL is already linked to a Gitea repo; it shows the active URL being attached, creates an issue with the selected agent and selected labels, writes requirements under `# Requirements` and metadata under `# References`, and uploads the rendered agent file plus accumulated screenshots and files as issue assets. Captured screenshots can be expanded, removed, or cropped with a wider no-horizontal-scroll crop panel. Issues lists recent issues by creation time, defaults to open issues for the current repo, can expand to all loaded repos, has Open/Closed status checkboxes plus an empty-by-default label filter, and lets a selected issue open directly in Gitea, log a placeholder Send to Codex payload, edit subject/content/labels against that issue's repo with content-version readback verification, view attachments and comments, upload more screenshots/files directly to the issue, and add a comment with screenshots and file attachments. Clicking the selected issue row again or the detail close control collapses the detail panel. Rows can be deleted, and existing issue attachments can be deleted. Gitea API errors include the failed operation and network-level failures identify the configured API base plus common checks.
|
||||
|
||||
Builds generate `public/local-context.json` from `/Users/Tabitha/.openclaw/workspace_Father` plus searchable local folder candidates. That snapshot links known workspaces to local Gitea repos and is copied into `dist/` so the built extension is self-contained.
|
||||
Builds generate `public/local-context.json` from `/Users/Tabitha/.openclaw/workspace_Father` plus searchable local folder candidates. That snapshot links known workspaces to local Gitea repos and is copied into `dist/` so the built extension is self-contained. At runtime, the side panel first tries the live local context endpoint at `VITE_LOCAL_CONTEXT_URL` or `http://127.0.0.1:23873/local-context.json`, then falls back to the bundled snapshot. Workspace-sensitive views poll live local context every 10 seconds while the side panel is open.
|
||||
|
||||
## Extension Management
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ This rule applies to:
|
||||
## Build Output
|
||||
|
||||
- Build command: `npm run build`
|
||||
- Live local context command: `npm run context:serve`
|
||||
- Deployable/load-unpacked directory: `dist/`
|
||||
- Manifest path: `dist/manifest.json`
|
||||
|
||||
@@ -35,6 +36,13 @@ Required variables:
|
||||
- `VITE_GITEA_REPO_OWNER`
|
||||
- `VITE_GITEA_REPO_NAME`
|
||||
|
||||
Optional variables:
|
||||
|
||||
- `VITE_LOCAL_CONTEXT_URL`, defaulting to `http://127.0.0.1:23873/local-context.json`.
|
||||
- `LOCAL_CONTEXT_PORT`, used by `npm run context:serve`; default `23873`.
|
||||
- `WORKSPACE_FOLDER_SEARCH_ROOTS`, comma-separated roots used by local context generation and serving.
|
||||
- `WORKSPACE_FOLDER_SEARCH_MAX_DEPTH`, default `3`.
|
||||
|
||||
## Issue Creation
|
||||
|
||||
- Add Issue is enabled only when the active tab's base URL is already in the URLs list and that URL is linked to a Gitea repo.
|
||||
@@ -85,6 +93,7 @@ Required variables:
|
||||
- User-added workspaces require an absolute local path selected from searchable generated folder candidates in `local-context.json`; do not require copy/paste path entry.
|
||||
- User-added workspaces can be deleted from the side panel.
|
||||
- Add URL workspace selection should include both generated and user-added workspaces.
|
||||
- For live local workspace updates, run `npm run context:serve`. The side panel should prefer `VITE_LOCAL_CONTEXT_URL`, fall back to bundled `/local-context.json`, and poll live local context every 10 seconds while workspace-sensitive views or dialogs are active.
|
||||
|
||||
## Gitea Error Reporting
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@ Important files:
|
||||
- `public/icons/`: Extension icon source and generated PNG sizes copied into `dist/` by Vite.
|
||||
- `public/local-context.json`: Generated workspace/repo/URL context copied into `dist/`.
|
||||
- `scripts/generate-local-context.mjs`: Scans `/Users/Tabitha/.openclaw/workspace_Father` plus configured local folder search roots and writes `public/local-context.json`.
|
||||
- `scripts/serve-local-context.mjs`: Serves live local context at `http://127.0.0.1:23873/local-context.json` by default and rescans on each request.
|
||||
|
||||
Build with `npm run build`. The deployable output directory is `dist/`; load that folder in Chrome as an unpacked extension or point deployment tooling at it. Do not edit `dist/` directly.
|
||||
|
||||
UI behavior: the app renders as a Chrome side panel, not a draggable window. The top toolbar items are URLs, Gitea Repos, Issues, Add Issue, and a management dropdown for Agents, Prompts, and Workspaces. Add URL lives inside the URLs view as a first-row button that opens a modal dialog; it is enabled only when the active tab base URL is not already known. The user must choose either a workspace or a Gitea repo, and the app infers the linked counterpart. URLs can be deleted from the list; user-added URLs are removed from storage, while generated known URLs are hidden through stored deleted bases. Workspaces combines generated `workspace_Father` entries with user-added absolute local paths stored under `silmaAide.userWorkspaces`; workspace creation uses a first-row Add workspace button, a modal dialog, and searchable generated folder candidates instead of copy/paste path entry. The Prompts view manages workspace-scoped default prompts in `chrome.storage.local` under `silmaAide.prompts`; new prompt workspace selection defaults to the active known URL's workspace/site when available, and Add Issue shows prompts matching the active URL workspace above Content and copies the selected prompt into the editable Content field for human adjustment. The Agents view manages persisted agent files and starts with `GLOBAL AGENT` backed by `AGENTS.md`; agent markdown can use `{{git}}`, `{{repo}}`, `{{workspace}}`, `{{url}}`, `{{baseUrl}}`, `{{profile}}`, and `{{issue}}` template variables. The default global agent tells downstream agents to close the Gitea issue after pushing the implementation and to leave a Gitea issue comment when delivery is blocked, partial, or risky. Add Issue is enabled only when the active tab base URL is known and linked to a Gitea repo. It shows the target repo and active URL, captures visible-tab screenshots with thumbnails, accepts accumulated file attachments, lets the user select an agent file and issue labels, creates the Gitea issue with the selected labels, and uploads the rendered agent file plus all screenshots/files. The label options are Change Request, Idea, Tabitha, Orson, Belisarius, Ozymandias, and Ready; new issues default to Change Request. Captured screenshots can be expanded, removed, or cropped with a wider no-horizontal-scroll draggable/resizable crop panel. Created issue bodies put the human-entered idea/change request under `# Requirements` and generated metadata under `# References`, including `Chrome profile: Silma` and the selected agent. Issues lists recent issues by creation time, defaults to open issues for the active URL's linked repo through an `Only current repo` checkbox, can load recent issues across all loaded repos, supports Open/Closed status multiselect filtering, has an empty-by-default label filter, and shows selected issue subject/content/label edit fields that save against the selected issue repo with Gitea content-version readback verification, a direct Open in Gitea link, a placeholder Send to Codex console log action, attachments, comment chains, direct selected-issue screenshot/file attachment uploads, and a comment form with text, screenshots, and file attachments. Clicking the selected issue row again or the detail close control collapses the detail panel. Existing issue rows can be deleted after confirmation, and existing issue attachments can be deleted. Text-entry state updates must not blur focused Add Issue, selected issue edit, Issues comment, Agents editor controls, Prompts editor controls, or workspace folder search controls. Gitea API errors include the failed operation and network-level failures identify the configured API base with env, permissions, network/VPN, token scope, and attachment-size checks. Gitea repos are ordered by latest default-branch commit. Workspace and URL views show established links between local workspaces, known URLs, and Gitea repos.
|
||||
UI behavior: the app renders as a Chrome side panel, not a draggable window. The top toolbar items are URLs, Gitea Repos, Issues, Add Issue, and a management dropdown for Agents, Prompts, and Workspaces. Add URL lives inside the URLs view as a first-row button that opens a modal dialog; it is enabled only when the active tab base URL is not already known. The user must choose either a workspace or a Gitea repo, and the app infers the linked counterpart. URLs can be deleted from the list; user-added URLs are removed from storage, while generated known URLs are hidden through stored deleted bases. Workspaces combines generated `workspace_Father` entries with user-added absolute local paths stored under `silmaAide.userWorkspaces`; workspace creation uses a first-row Add workspace button, a modal dialog, and searchable generated folder candidates instead of copy/paste path entry. Run `npm run context:serve` to make new local projects appear without rebuilding; the side panel prefers `VITE_LOCAL_CONTEXT_URL`, falls back to bundled `/local-context.json`, and polls live local context every 10 seconds on workspace-sensitive screens. The Prompts view manages workspace-scoped default prompts in `chrome.storage.local` under `silmaAide.prompts`; new prompt workspace selection defaults to the active known URL's workspace/site when available, and Add Issue shows prompts matching the active URL workspace above Content and copies the selected prompt into the editable Content field for human adjustment. The Agents view manages persisted agent files and starts with `GLOBAL AGENT` backed by `AGENTS.md`; agent markdown can use `{{git}}`, `{{repo}}`, `{{workspace}}`, `{{url}}`, `{{baseUrl}}`, `{{profile}}`, and `{{issue}}` template variables. The default global agent tells downstream agents to close the Gitea issue after pushing the implementation and to leave a Gitea issue comment when delivery is blocked, partial, or risky. Add Issue is enabled only when the active tab base URL is known and linked to a Gitea repo. It shows the target repo and active URL, captures visible-tab screenshots with thumbnails, accepts accumulated file attachments, lets the user select an agent file and issue labels, creates the Gitea issue with the selected labels, and uploads the rendered agent file plus all screenshots/files. The label options are Change Request, Idea, Tabitha, Orson, Belisarius, Ozymandias, and Ready; new issues default to Change Request. Captured screenshots can be expanded, removed, or cropped with a wider no-horizontal-scroll draggable/resizable crop panel. Created issue bodies put the human-entered idea/change request under `# Requirements` and generated metadata under `# References`, including `Chrome profile: Silma` and the selected agent. Issues lists recent issues by creation time, defaults to open issues for the active URL's linked repo through an `Only current repo` checkbox, can load recent issues across all loaded repos, supports Open/Closed status multiselect filtering, has an empty-by-default label filter, and shows selected issue subject/content/label edit fields that save against the selected issue repo with Gitea content-version readback verification, a direct Open in Gitea link, a placeholder Send to Codex console log action, attachments, comment chains, direct selected-issue screenshot/file attachment uploads, and a comment form with text, screenshots, and file attachments. Clicking the selected issue row again or the detail close control collapses the detail panel. Existing issue rows can be deleted after confirmation, and existing issue attachments can be deleted. Text-entry state updates must not blur focused Add Issue, selected issue edit, Issues comment, Agents editor controls, Prompts editor controls, or workspace folder search controls. Gitea API errors include the failed operation and network-level failures identify the configured API base with env, permissions, network/VPN, token scope, and attachment-size checks. Gitea repos are ordered by latest default-branch commit. Workspace and URL views show established links between local workspaces, known URLs, and Gitea repos.
|
||||
|
||||
Extension management rule: use the Codex Chrome extension with the Chrome profile named `Silma`. Do not use `Profile 1`.
|
||||
|
||||
@@ -27,6 +28,7 @@ Codex commands:
|
||||
|
||||
- Setup: `npm run codex:setup`
|
||||
- Dev: `npm run dev:codex`
|
||||
- Live context: `npm run context:serve`
|
||||
- Build: `npm run build:codex`
|
||||
- Verify output: `npm run verify:dist`
|
||||
|
||||
|
||||
+27
-1
@@ -22,6 +22,7 @@
|
||||
"local_context": "public/local-context.json",
|
||||
"local_context_folder_candidates": "public/local-context.json#folderCandidates",
|
||||
"local_context_generator": "scripts/generate-local-context.mjs",
|
||||
"local_context_server": "scripts/serve-local-context.mjs",
|
||||
"generated_manifest": "dist/manifest.json"
|
||||
},
|
||||
"ui": {
|
||||
@@ -54,7 +55,7 @@
|
||||
"repo_ordering": "Gitea repos are ordered by latest default-branch commit timestamp.",
|
||||
"agents_behavior": "The Agents view manages persisted agent files. The initial agent is GLOBAL AGENT backed by AGENTS.md, and agent markdown supports {{git}}, {{repo}}, {{workspace}}, {{url}}, {{baseUrl}}, {{profile}}, and {{issue}} template variables. The default global agent tells downstream agents to close the Gitea issue after pushing the implementation and to leave a Gitea issue comment when delivery is blocked, partial, or risky; persisted built-in global agents should pick up these required completion rules without replacing unrelated custom text.",
|
||||
"prompts_behavior": "The Prompts view is selected from the Management dropdown and manages workspace-scoped prompt records persisted in chrome.storage.local under silmaAide.prompts. Each prompt has a name, workspace path, and content. New prompt workspace selection defaults to the active known URL's workspace/site when available. Add Issue shows prompts matching the active known URL's workspace path immediately above Content, and selecting one copies prompt content into the editable Content field for human adjustment.",
|
||||
"workspaces_behavior": "The Workspaces view is selected from the Management dropdown and combines generated workspace_Father entries with user-added absolute local paths persisted in chrome.storage.local under silmaAide.userWorkspaces. Workspace creation uses a first-row Add workspace button, a modal dialog, and searchable generated folder candidates from local-context.json instead of copy/paste path entry. User-added workspaces can be deleted from the side panel.",
|
||||
"workspaces_behavior": "The Workspaces view is selected from the Management dropdown and combines generated workspace_Father entries with user-added absolute local paths persisted in chrome.storage.local under silmaAide.userWorkspaces. Workspace creation uses a first-row Add workspace button, a modal dialog, and searchable generated folder candidates from local-context.json instead of copy/paste path entry. User-added workspaces can be deleted from the side panel. For live updates after new local projects are added, run npm run context:serve; the side panel prefers VITE_LOCAL_CONTEXT_URL, falls back to bundled /local-context.json, and polls live local context every 10 seconds while workspace-sensitive views or dialogs are active.",
|
||||
"add_url_behavior": "Add URL lives inside the URLs view as a first-row button that opens a modal dialog. The user must pick either a workspace or a Gitea repo. The app infers the linked counterpart from generated and user-added workspace context and stores the URL link in chrome.storage.local.",
|
||||
"delete_url_behavior": "URLs can be deleted from the list. User-added URLs are removed from chrome.storage.local; generated known URLs are hidden by storing their base URL in silmaAide.deletedUrlBases.",
|
||||
"add_issue_behavior": "The form shows the target repo and active URL for the active known URL, lets the user select a workspace prompt, agent file, and issue labels, captures visible-tab screenshots with thumbnails, accepts accumulated file attachments, creates a Gitea issue with the selected labels, and uploads the rendered agent file plus all screenshots/files as issue assets. Label options are Change Request, Idea, Tabitha, Orson, Belisarius, Ozymandias, and Ready; new issues default to Change Request. Captured screenshots can be expanded, removed, or cropped with a wider no-horizontal-scroll draggable/resizable crop panel. Issue bodies put human-entered idea/change request content under # Requirements and generated metadata under # References, including Chrome profile: Silma and the selected agent. The view intentionally omits the redundant Add Issue header copy.",
|
||||
@@ -97,6 +98,7 @@
|
||||
"codex_setup": "npm run codex:setup",
|
||||
"dev": "npm run dev",
|
||||
"codex_dev": "npm run dev:codex",
|
||||
"context_serve": "npm run context:serve",
|
||||
"build": "npm run build",
|
||||
"codex_build": "npm run build:codex",
|
||||
"preview": "npm run preview",
|
||||
@@ -129,6 +131,30 @@
|
||||
"required": true,
|
||||
"secret": false,
|
||||
"description": "Name of the target Gitea repository."
|
||||
},
|
||||
{
|
||||
"name": "VITE_LOCAL_CONTEXT_URL",
|
||||
"required": false,
|
||||
"secret": false,
|
||||
"description": "Live local context endpoint. Defaults to http://127.0.0.1:23873/local-context.json."
|
||||
},
|
||||
{
|
||||
"name": "LOCAL_CONTEXT_PORT",
|
||||
"required": false,
|
||||
"secret": false,
|
||||
"description": "Port used by npm run context:serve. Defaults to 23873."
|
||||
},
|
||||
{
|
||||
"name": "WORKSPACE_FOLDER_SEARCH_ROOTS",
|
||||
"required": false,
|
||||
"secret": false,
|
||||
"description": "Comma-separated roots scanned for folder candidates."
|
||||
},
|
||||
{
|
||||
"name": "WORKSPACE_FOLDER_SEARCH_MAX_DEPTH",
|
||||
"required": false,
|
||||
"secret": false,
|
||||
"description": "Folder candidate scan depth. Defaults to 3."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"codex:setup": "npm ci",
|
||||
"dev": "vite --host 0.0.0.0",
|
||||
"dev:codex": "npm run dev",
|
||||
"context:serve": "node scripts/serve-local-context.mjs",
|
||||
"prebuild": "node scripts/generate-local-context.mjs",
|
||||
"build": "tsc --noEmit && vite build && npm run verify:dist",
|
||||
"build:codex": "npm run build",
|
||||
|
||||
@@ -74,6 +74,30 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mp-ai-module-controller",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-ai-module-controller",
|
||||
"linkedRepos": [
|
||||
{
|
||||
"worktreePath": "/Users/Tabitha/.openclaw/workspace_Father/mp-ai-module-controller",
|
||||
"worktreeRelativePath": "mp-ai-module-controller",
|
||||
"fullName": "jacob-mathison/mp-ai-module-controller",
|
||||
"webUrl": "http://gitea.orson.tealthrone/jacob-mathison/mp-ai-module-controller"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mp-california-bluebird",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-california-bluebird",
|
||||
"linkedRepos": [
|
||||
{
|
||||
"worktreePath": "/Users/Tabitha/.openclaw/workspace_Father/mp-california-bluebird",
|
||||
"worktreeRelativePath": "mp-california-bluebird",
|
||||
"fullName": "jacob-mathison/mp-california-bluebird",
|
||||
"webUrl": "http://gitea.orson.tealthrone/jacob-mathison/mp-california-bluebird"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mp-silma-ai-aide",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-silma-ai-aide",
|
||||
@@ -220,6 +244,34 @@
|
||||
"cloneUrl": "http://100.79.253.19:3000/jacob-mathison/midnights-eclipse-migration.git"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mp-ai-module-controller",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-ai-module-controller",
|
||||
"relativePath": "mp-ai-module-controller",
|
||||
"topWorkspaceName": "mp-ai-module-controller",
|
||||
"branch": "main",
|
||||
"giteaRepo": {
|
||||
"fullName": "jacob-mathison/mp-ai-module-controller",
|
||||
"owner": "jacob-mathison",
|
||||
"name": "mp-ai-module-controller",
|
||||
"webUrl": "http://gitea.orson.tealthrone/jacob-mathison/mp-ai-module-controller",
|
||||
"cloneUrl": "http://100.79.253.19:3000/jacob-mathison/mp-ai-module-controller.git"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mp-california-bluebird",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-california-bluebird",
|
||||
"relativePath": "mp-california-bluebird",
|
||||
"topWorkspaceName": "mp-california-bluebird",
|
||||
"branch": "main",
|
||||
"giteaRepo": {
|
||||
"fullName": "jacob-mathison/mp-california-bluebird",
|
||||
"owner": "jacob-mathison",
|
||||
"name": "mp-california-bluebird",
|
||||
"webUrl": "http://gitea.orson.tealthrone/jacob-mathison/mp-california-bluebird",
|
||||
"cloneUrl": "http://100.79.253.19:3000/jacob-mathison/mp-california-bluebird.git"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mp-silma-ai-aide",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-silma-ai-aide",
|
||||
@@ -1820,6 +1872,11 @@
|
||||
"path": "/Users/Tabitha/.codex/ambient-suggestions/64cea9b7588cfc38a39b06c13b7472f24692e4a8",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "770e25c2020e46ae5d5f2e972625a5bc6ca5db3b",
|
||||
"path": "/Users/Tabitha/.codex/ambient-suggestions/770e25c2020e46ae5d5f2e972625a5bc6ca5db3b",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "7c046d95257c305f197b68b2110bb1b9f1b12343",
|
||||
"path": "/Users/Tabitha/.codex/ambient-suggestions/7c046d95257c305f197b68b2110bb1b9f1b12343",
|
||||
@@ -1875,6 +1932,11 @@
|
||||
"path": "/Users/Tabitha/.codex/ambient-suggestions/d6b1b7791c1d0c58757e6ae125fbf61e3ed009d5",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "daf2afc6ba91f65e019a8afbbb876da476627b6e",
|
||||
"path": "/Users/Tabitha/.codex/ambient-suggestions/daf2afc6ba91f65e019a8afbbb876da476627b6e",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "f7c796c4e0fbaf97644a0dbec74b13425f8bac96",
|
||||
"path": "/Users/Tabitha/.codex/ambient-suggestions/f7c796c4e0fbaf97644a0dbec74b13425f8bac96",
|
||||
@@ -2545,6 +2607,16 @@
|
||||
"path": "/Users/Tabitha/.cursor/extensions/anysphere.remote-ssh-1.1.11",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "anysphere.remote-ssh-1.1.12",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/anysphere.remote-ssh-1.1.12",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "anysphere.remote-ssh-1.1.13",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/anysphere.remote-ssh-1.1.13",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "anysphere.remote-ssh-1.1.4",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/anysphere.remote-ssh-1.1.4",
|
||||
@@ -2690,6 +2762,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/extensions/mermaidchart.vscode-mermaid-chart-2.7.2-universal",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "mermaidchart.vscode-mermaid-chart-2.7.4-universal",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/mermaidchart.vscode-mermaid-chart-2.7.4-universal",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "mquandalle.graphql-0.1.2",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/mquandalle.graphql-0.1.2",
|
||||
@@ -2820,6 +2897,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/extensions/vue.volar-3.3.6-universal",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "vue.volar-3.3.8-universal",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/vue.volar-3.3.8-universal",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "wholroyd.jinja-0.0.8",
|
||||
"path": "/Users/Tabitha/.cursor/extensions/wholroyd.jinja-0.0.8",
|
||||
@@ -2860,6 +2942,21 @@
|
||||
"path": "/Users/Tabitha/.cursor/projects/1782840332829",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "1784650488164",
|
||||
"path": "/Users/Tabitha/.cursor/projects/1784650488164",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "1784729994064",
|
||||
"path": "/Users/Tabitha/.cursor/projects/1784729994064",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "1784806891199",
|
||||
"path": "/Users/Tabitha/.cursor/projects/1784806891199",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "empty-window",
|
||||
"path": "/Users/Tabitha/.cursor/projects/empty-window",
|
||||
@@ -3005,6 +3102,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/projects/Users-Tabitha-openclaw-workspace-Father-blb-throne-of-the-bone-king",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "Users-Tabitha-openclaw-workspace-Father-mp-ai-module-controller",
|
||||
"path": "/Users/Tabitha/.cursor/projects/Users-Tabitha-openclaw-workspace-Father-mp-ai-module-controller",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-0d9ed627-cc81-4847-9287-8d348fbeeba6",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-0d9ed627-cc81-4847-9287-8d348fbeeba6",
|
||||
@@ -3015,6 +3117,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-1db40ed5-49f6-4047-a101-d25e568453a3",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-26d201a5-5c59-4f0c-967d-1d9207d84163",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-26d201a5-5c59-4f0c-967d-1d9207d84163",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-2ad243a9-f2ce-4b91-a819-fad92aa35e8f",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-2ad243a9-f2ce-4b91-a819-fad92aa35e8f",
|
||||
@@ -3085,6 +3192,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-c96c2222-8131-4f62-9b5b-7d36891a0e53",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-cdbb5a29-29e5-4b1b-9928-b3806f56374e",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-cdbb5a29-29e5-4b1b-9928-b3806f56374e",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-da2c03f6-a10c-4a08-974e-3250baf7064c",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-da2c03f6-a10c-4a08-974e-3250baf7064c",
|
||||
@@ -3100,6 +3212,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-e23931b3-1135-40d9-90e0-81145d4c91c0",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-ed514203-e15c-4718-a9fc-eb1e4b864a3f",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-ed514203-e15c-4718-a9fc-eb1e4b864a3f",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-fb48bd39-a251-44b0-975b-b0f68091c5ce",
|
||||
"path": "/Users/Tabitha/.cursor/projects/var-folders-2l-5tz4dbps7hvclxwyrbw51d3m0000gn-T-fb48bd39-a251-44b0-975b-b0f68091c5ce",
|
||||
@@ -3155,6 +3272,11 @@
|
||||
"path": "/Users/Tabitha/.cursor/skills-cursor/create-subagent",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "env-setup",
|
||||
"path": "/Users/Tabitha/.cursor/skills-cursor/env-setup",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "loop",
|
||||
"path": "/Users/Tabitha/.cursor/skills-cursor/loop",
|
||||
@@ -4365,6 +4487,11 @@
|
||||
"path": "/Users/Tabitha/.npm/_npx/94207acffe67148d",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "96a8727b140d6939",
|
||||
"path": "/Users/Tabitha/.npm/_npx/96a8727b140d6939",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "a712338f43e79bae",
|
||||
"path": "/Users/Tabitha/.npm/_npx/a712338f43e79bae",
|
||||
@@ -5240,6 +5367,11 @@
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp3ao2la3_",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmp3dmsku9t",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp3dmsku9t",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmp42rjaq23",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp42rjaq23",
|
||||
@@ -5255,6 +5387,11 @@
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp4szv35km",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmp5nczz6ae",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp5nczz6ae",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmp5nuc1iht",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp5nuc1iht",
|
||||
@@ -5300,6 +5437,11 @@
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmp9m0kjeqt",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmpa6oy9a88",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmpa6oy9a88",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmpak1e9sws",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmpak1e9sws",
|
||||
@@ -5435,6 +5577,11 @@
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmptf33bdgc",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmptps4oymq",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmptps4oymq",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "tmpuk8y4udi",
|
||||
"path": "/Users/Tabitha/.openclaw/tmp/tmpuk8y4udi",
|
||||
@@ -5540,6 +5687,16 @@
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/midnights-eclipse-migration",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "mp-ai-module-controller",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-ai-module-controller",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "mp-california-bluebird",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-california-bluebird",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "mp-silma-ai-aide",
|
||||
"path": "/Users/Tabitha/.openclaw/workspace_Father/mp-silma-ai-aide",
|
||||
@@ -6505,6 +6662,11 @@
|
||||
"path": "/Users/Tabitha/Downloads/hoss-call-reference-screenshots",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "padu-translation-review-20260721-screenshots",
|
||||
"path": "/Users/Tabitha/Downloads/padu-translation-review-20260721-screenshots",
|
||||
"source": "folder-search"
|
||||
},
|
||||
{
|
||||
"name": "go",
|
||||
"path": "/Users/Tabitha/go",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
||||
import { basename, join, relative } from "node:path";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const workspaceRoot =
|
||||
export const workspaceRoot =
|
||||
process.env.WORKSPACE_FATHER_PATH || "/Users/Tabitha/.openclaw/workspace_Father";
|
||||
const outputPath = join(process.cwd(), "public", "local-context.json");
|
||||
const giteaBaseUrl = "http://gitea.orson.tealthrone";
|
||||
@@ -149,7 +150,7 @@ function repoForWorktree(path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildContext() {
|
||||
export function buildContext() {
|
||||
const topLevelWorkspaces = readdirSync(workspaceRoot, { withFileTypes: true })
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => ({
|
||||
@@ -208,16 +209,22 @@ function buildContext() {
|
||||
};
|
||||
}
|
||||
|
||||
mkdirSync(join(process.cwd(), "public"), { recursive: true });
|
||||
export function writeLocalContext() {
|
||||
mkdirSync(join(process.cwd(), "public"), { recursive: true });
|
||||
|
||||
if (!existsSync(workspaceRoot)) {
|
||||
if (existsSync(outputPath)) {
|
||||
console.log(`Workspace root missing; preserving ${outputPath}`);
|
||||
process.exit(0);
|
||||
if (!existsSync(workspaceRoot)) {
|
||||
if (existsSync(outputPath)) {
|
||||
console.log(`Workspace root missing; preserving ${outputPath}`);
|
||||
return;
|
||||
}
|
||||
throw new Error(`Workspace root does not exist: ${workspaceRoot}`);
|
||||
}
|
||||
throw new Error(`Workspace root does not exist: ${workspaceRoot}`);
|
||||
|
||||
const context = buildContext();
|
||||
writeFileSync(outputPath, `${JSON.stringify(context, null, 2)}\n`);
|
||||
console.log(`Wrote ${outputPath} with ${context.workspaces.length} workspaces`);
|
||||
}
|
||||
|
||||
const context = buildContext();
|
||||
writeFileSync(outputPath, `${JSON.stringify(context, null, 2)}\n`);
|
||||
console.log(`Wrote ${outputPath} with ${context.workspaces.length} workspaces`);
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
writeLocalContext();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { createServer } from "node:http";
|
||||
import { buildContext, workspaceRoot } from "./generate-local-context.mjs";
|
||||
|
||||
const host = process.env.LOCAL_CONTEXT_HOST || "127.0.0.1";
|
||||
const port = Number(process.env.LOCAL_CONTEXT_PORT || 23873);
|
||||
|
||||
function sendJson(response, status, payload) {
|
||||
response.writeHead(status, {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "Content-Type",
|
||||
"Cache-Control": "no-store",
|
||||
"Content-Type": "application/json; charset=utf-8"
|
||||
});
|
||||
response.end(`${JSON.stringify(payload, null, 2)}\n`);
|
||||
}
|
||||
|
||||
const server = createServer((request, response) => {
|
||||
if (request.method === "OPTIONS") {
|
||||
response.writeHead(204, {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "Content-Type"
|
||||
});
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method !== "GET") {
|
||||
sendJson(response, 405, { error: "Method not allowed" });
|
||||
return;
|
||||
}
|
||||
|
||||
const url = new URL(request.url || "/", `http://${host}:${port}`);
|
||||
|
||||
if (url.pathname === "/health") {
|
||||
sendJson(response, 200, { ok: true, workspaceRoot });
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.pathname !== "/local-context.json") {
|
||||
sendJson(response, 404, { error: "Not found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
sendJson(response, 200, buildContext());
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : "Could not build local context"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(port, host, () => {
|
||||
console.log(`Serving live local context for ${workspaceRoot} at http://${host}:${port}/local-context.json`);
|
||||
});
|
||||
+40
-6
@@ -47,12 +47,46 @@ export interface LocalContext {
|
||||
knownUrls: KnownUrl[];
|
||||
}
|
||||
|
||||
export async function loadLocalContext(): Promise<LocalContext> {
|
||||
const response = await fetch("/local-context.json", { cache: "no-store" });
|
||||
const liveLocalContextUrl =
|
||||
import.meta.env.VITE_LOCAL_CONTEXT_URL?.trim() || "http://127.0.0.1:23873/local-context.json";
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not load local context (${response.status}). Run npm run build.`);
|
||||
async function fetchLocalContext(url: string, timeoutMs?: number): Promise<LocalContext> {
|
||||
const controller = timeoutMs ? new AbortController() : null;
|
||||
const timeoutId = controller
|
||||
? window.setTimeout(() => {
|
||||
controller.abort();
|
||||
}, timeoutMs)
|
||||
: undefined;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
cache: "no-store",
|
||||
signal: controller?.signal
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not load local context (${response.status}).`);
|
||||
}
|
||||
|
||||
return response.json() as Promise<LocalContext>;
|
||||
} finally {
|
||||
if (timeoutId !== undefined) {
|
||||
window.clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadLocalContext(): Promise<LocalContext> {
|
||||
try {
|
||||
return await fetchLocalContext(liveLocalContextUrl, 500);
|
||||
} catch {
|
||||
try {
|
||||
return await fetchLocalContext("/local-context.json");
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`${error.message} Run npm run build, or run npm run context:serve for live workspace updates.`);
|
||||
}
|
||||
throw new Error("Could not load local context. Run npm run build, or run npm run context:serve for live workspace updates.");
|
||||
}
|
||||
}
|
||||
|
||||
return response.json() as Promise<LocalContext>;
|
||||
}
|
||||
|
||||
+25
@@ -1876,7 +1876,32 @@ function setupActiveTabTracking(): void {
|
||||
window.addEventListener("focus", scheduleRefresh);
|
||||
}
|
||||
|
||||
function setupLocalContextAutoRefresh(): void {
|
||||
let isRefreshing = false;
|
||||
window.setInterval(() => {
|
||||
const state = appStore.getState();
|
||||
const shouldRefresh =
|
||||
!document.hidden &&
|
||||
!state.isLoadingData &&
|
||||
(state.activeView === "workspaces" ||
|
||||
state.activeView === "prompts" ||
|
||||
state.activeView === "urls" ||
|
||||
state.activeDialog === "add-workspace" ||
|
||||
state.activeDialog === "add-url");
|
||||
|
||||
if (!shouldRefresh || isRefreshing) {
|
||||
return;
|
||||
}
|
||||
|
||||
isRefreshing = true;
|
||||
appStore.getState().refreshLocalContext().finally(() => {
|
||||
isRefreshing = false;
|
||||
});
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
setupActiveTabTracking();
|
||||
setupLocalContextAutoRefresh();
|
||||
appStore.subscribe(render);
|
||||
render();
|
||||
void appStore.getState().loadData();
|
||||
|
||||
+35
-7
@@ -285,6 +285,7 @@ interface AppState {
|
||||
captureScreenshot: () => Promise<void>;
|
||||
createIssue: () => Promise<void>;
|
||||
refreshActiveTab: () => Promise<void>;
|
||||
refreshLocalContext: () => Promise<void>;
|
||||
loadData: () => Promise<void>;
|
||||
saveCurrentUrlLink: () => Promise<void>;
|
||||
deleteUrlLink: (url: string) => Promise<void>;
|
||||
@@ -710,6 +711,16 @@ function getPromptById(id: string, prompts: WorkspacePrompt[]): WorkspacePrompt
|
||||
return prompts.find((prompt) => prompt.id === id) ?? null;
|
||||
}
|
||||
|
||||
function normalizeUserWorkspaces(workspaces: LocalWorkspace[]): LocalWorkspace[] {
|
||||
return workspaces
|
||||
.map((workspace) => ({
|
||||
name: workspace.name?.trim() || workspace.path.split("/").filter(Boolean).slice(-1)[0] || "workspace",
|
||||
path: workspace.path?.trim().replace(/\/+$/, "") || "",
|
||||
linkedRepos: workspace.linkedRepos ?? []
|
||||
}))
|
||||
.filter((workspace) => workspace.path);
|
||||
}
|
||||
|
||||
function normalizeIssueLabels(labels: string[]): IssueLabelOption[] {
|
||||
return ISSUE_LABEL_OPTIONS.filter((option) => labels.some((label) => label.toLowerCase() === option.toLowerCase()));
|
||||
}
|
||||
@@ -2169,6 +2180,29 @@ export const appStore = createStore<AppState>()((set, get) => ({
|
||||
: get().promptDraft
|
||||
});
|
||||
},
|
||||
refreshLocalContext: async () => {
|
||||
try {
|
||||
const [localContext, userWorkspaces, userUrls, deletedUrlBases] = await Promise.all([
|
||||
loadLocalContext(),
|
||||
storageGet<LocalWorkspace[]>(USER_WORKSPACES_STORAGE_KEY, []),
|
||||
storageGet<KnownUrl[]>(USER_URLS_STORAGE_KEY, []),
|
||||
storageGet<string[]>(DELETED_URL_BASES_STORAGE_KEY, [])
|
||||
]);
|
||||
const normalizedUserWorkspaces = normalizeUserWorkspaces(userWorkspaces);
|
||||
|
||||
set({
|
||||
localContext,
|
||||
userWorkspaces: normalizedUserWorkspaces,
|
||||
userUrls: userUrls.filter((url) => !deletedUrlBases.includes(getBaseUrl(url.url))),
|
||||
deletedUrlBases
|
||||
});
|
||||
} catch (error) {
|
||||
if (!get().localContext) {
|
||||
const message = error instanceof Error ? error.message : "Could not refresh local workspace context.";
|
||||
setStatus(set, message, "error");
|
||||
}
|
||||
}
|
||||
},
|
||||
loadData: async () => {
|
||||
set({
|
||||
isLoadingData: true
|
||||
@@ -2188,13 +2222,7 @@ export const appStore = createStore<AppState>()((set, get) => ({
|
||||
]);
|
||||
const activeBaseUrl = getBaseUrl(activeTabUrl);
|
||||
const normalizedAgents = normalizeAgents(agents);
|
||||
const normalizedUserWorkspaces = userWorkspaces
|
||||
.map((workspace) => ({
|
||||
name: workspace.name?.trim() || workspace.path.split("/").filter(Boolean).slice(-1)[0] || "workspace",
|
||||
path: workspace.path?.trim().replace(/\/+$/, "") || "",
|
||||
linkedRepos: workspace.linkedRepos ?? []
|
||||
}))
|
||||
.filter((workspace) => workspace.path);
|
||||
const normalizedUserWorkspaces = normalizeUserWorkspaces(userWorkspaces);
|
||||
const activeKnownUrl = findKnownUrlByBase(
|
||||
{
|
||||
...get(),
|
||||
|
||||
Reference in New Issue
Block a user