Commit Graph

7470 Commits

Author SHA1 Message Date
Pleasurecruise
41c33d5bcd test(useCodeCli): add helpers for preference mock assertions
Add typed helper functions (lastWrite, lastToolState, providerConfig) to src/renderer/hooks/__tests__/useCodeCli.test.ts and import CodeCliToolState. Replace direct mockSetter.mock.calls accesses with these helpers to simplify and type-safe assertions, improving readability of the tests.
2026-07-06 16:09:55 +08:00
fullex
13c8f0f254 chore(lint): enforce 7 barrel boundary rules as errors
The barrel/module-boundary rules (naming-conventions.md §6.4) were warn-only
while the codebase was being brought into compliance. The full tree is now
barrel-clean (lint reports 0 barrel findings), so promote all seven rules —
no-export-star, index-no-impl, no-index-tsx, named-only, closed, no-nesting,
no-bucket-root — from warn to error to lock the boundary against regressions.
2026-07-06 01:06:09 -07:00
fullex
8487bb18f7 refactor(knowledge): route v1→v2 migrators through the barrel via a shared index-store factory
Close the last 14 barrel/closed (§6.4) violations in the knowledge feature: both
v1→v2 migrators deep-imported knowledge internals to rebuild a base's index.sqlite.

Extract the shared open sequence into createKnowledgeIndexStoreAtPath (also adopted
by KnowledgeVectorStoreService, deduping the runtime) and the snapshot assembly into
build{Url,Note}SnapshotFile (adopted by capture*SnapshotFile); add index-count reads
to KnowledgeIndexStore; re-export a curated rebuild surface from the knowledge barrel.
The migrators now import only @main/features/knowledge — the engine internals
(driver/schema/meta/vector index) stay private behind the factory.
2026-07-06 01:00:31 -07:00
Pleasurecruise
a54bf43217 fix(code-cli): address review feedback
Signed-off-by: Pleasurecruise <3196812536@qq.com>
2026-07-06 15:51:58 +08:00
eeee0717
a2cf91e1d3 Merge remote-tracking branch 'upstream/main' into refactor/code-cli
Resolve OpenClawService.ts import conflict: adopt upstream's moved
`@main/data/migration/legacyTypes` path and drop the `WindowType` import,
whose only consumer (the OpenClaw_InstallProgress broadcast) was removed on
this branch during the OpenClaw IPC migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-06 14:45:56 +08:00
eeee0717
46cf615dd1 fix(code-cli): resolve PR review — perms, dotenv, validation, concurrency, dead code
Address the review on #16491:

- i18n: restore `settings.models.manage.sync_apply_default_in_use`, net-deleted
  from en-us/zh-cn/zh-tw during a rebase yet still referenced by the model-list
  "in use as default" delete guard.
- FileStorage.writeFile: chmod an existing file to the requested mode BEFORE
  writing, so secret content never lands under the old (world-readable) mode;
  log + rethrow on chmod failure rather than falling through.
- cliConfig/dotenv: align parseDotenv with the real dotenv package — keep `\\`
  and `\"` literal inside double quotes (only expand `\n`/`\r`), so a hand-written
  KEY="C:\\path" no longer silently loses a backslash on rewrite.
- ipc/codeCli: drop the duplicated providerId/model validation; delegate to
  CodeCliService.run() as the single source of truth.
- useConfigPanelController: add a per-tool in-flight guard so a rapid re-toggle
  can't interleave the sequential, un-locked multi-file config writes.
- CLIIcon: use cn() so the fallback className never concatenates a literal
  "undefined".
- OpenClawService: delete the now-unreachable install/installInternal/
  installPromise/uninstall/checkInstalled methods and their stale tests/mocks
  (install/update routes through CodeCliService -> BinaryManager).

Tests cover each fix: chmod ordering, dotenv round-trip vs real dotenv,
validation single-source + login/providerless exemptions, the in-flight guard on
both toggle branches, and the CLIIcon fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-06 14:37:12 +08:00
fullex
dc3815e8df refactor(barrels): close 6 main barrel boundaries per naming §6.4
Every §6.4 `barrel/closed` warning on these six main barrels came from
external code deep-importing internals. Route each consumer through the
barrel, widening a door only with symbols that keep it one cohesive unit,
and trim dead re-exports.

- filesystem: export resolveFilesystemBaseDir
- observability: export the 3 lifecycle services (ClaudeCode/Node/TraceStorage)
- fileProcessing: export the job-result contract (artifact helpers + payload type)
- webSearch: export isPermanentWebSearchConfigError
- knowledge: export KnowledgeVectorStoreService; drop internal-only Lock/Workflow re-exports
- migration/v2: export isSchemaOutOfSyncError; drop dead BaseMigrator/reader re-exports;
  fold the gate's redundant versionPolicy deep-imports back through the barrel

Relocate two misplaced concerns the deep imports surfaced:
- isAbortError (generic) -> @main/utils/error, out of webSearch
- legacyTypes (v1 @deprecated) -> data/migration/, out of the v2 barrel; delete dead MistralClientManager

Update v2MigrationGate's barrel mock to match the consolidated import, and
fix a stale migrator-registration path in the migration README.

The remaining knowledge migrator coupling (KnowledgeVectorMigrator /
KnowledgeMigrator) is deferred to a fix-upstream follow-up.
2026-07-05 23:28:44 -07:00
fullex
74cba77fcd refactor(barrels): route or drop 5 barrel doors per naming §6.4
Clear all 8 `closed` deep-import warnings on five directories, applying the
topic-subdir-vs-type-bucket distinction (naming §6.4 / renderer §5):

- hooks/translate, hooks/command, components/ActionTools — cohesive topic
  subdirs / component framework: keep the curated door, route the stray deep
  imports through it.
- pages/knowledge/hooks — a page-internal type bucket (named `hooks`, not a
  topic): drop the barrel per rule 3/§4.8; four consumers deep-import the leaf
  hooks (matching the no-door home/notes/paintings siblings).
- components/composer/tokenView — heavy component + light vocab aggregator:
  keep the component door, move the token vocabulary out
  (tokenView.ts -> composer/chatTokenView.ts) so light consumers no longer
  pull the ComposerToken graph through the door.

Retarget the knowledge tests' barrel mocks to the leaf modules.
2026-07-05 23:10:42 -07:00
fullex
13b119e66f refactor(barrels): route command CommandId imports through barrel
Fix two barrel/closed violations where Shell and ResourceList deep-imported
CommandId from shared/utils/command/definitions instead of the barrel. The
command/ barrel is a cohesive subsystem (command/keybinding/menu/context-
expression); it stays as-is — only the two stray deep-import paths are corrected.
2026-07-05 23:08:28 -07:00
fullex
a42ce388af refactor(databases): demote v1 dexie index.ts to named db.ts
The `databases/index.ts` was implementation (the Dexie `db` instance and its version schema), not a re-export barrel, tripping `barrel/index-no-impl` (naming-conventions.md §6.4 rule 1). Since this v1 dexie residue is slated for removal, take the lightest §6.4 resolution: git mv the implementation to a named `db.ts` so `databases/` becomes a plain no-barrel container, and repoint consumers to deep-import `@renderer/databases/db`. No new barrel is built and no lint is suppressed; the warning is cleared structurally.
2026-07-05 22:35:15 -07:00
fullex
92408a125a refactor(barrels): dissolve CodeBlockView/Preview barrels, curate quickPanel/Sidebar doors
Clean up barrel boundaries per naming §6.4 across four renderer component
directories:

- CodeBlockView -> no-barrel container: a heavy main component plus
  independently consumed satellites (ViewMode type, constants config,
  HtmlPreviewFrame), with a latent CodeBlockView<->CodeToolbar cycle. Deep
  imports become legal; light consumers no longer drag the heavy graph through
  a door.
- Preview -> no-barrel container: an aggregator of four heavy, per-view
  lazy-loaded diagram previews. Removing the barrel preserves per-view code
  splitting -- routing the lazy imports through a door would merge the chunks.
- composer/quickPanel -> add ComposerPanelSymbol to the door; it is part of the
  quick-panel public API (used internally by unifiedPanel).
- Sidebar -> add UserAvatar/MiniAppIcon to the door, drop the dead
  SidebarTooltip export, route consumers through the door.

Removing the two barrels also required fixing their test deep-import surfaces
(MermaidPreview, CodeBlock vi.mock, Sidebar door mock) that the barrel lint
exempts but that break at runtime.

Additionally:
- Move the co-located ProviderSettings/utils tests into __tests__/ to match the
  convention used by every sibling directory.
- Fix a pre-existing AgentComposer test flake: it mocked the dialogs/edit leaf
  while the source lazy-imports the barrel, so the lazy import loaded the real
  barrel's heavy sibling dialogs and raced findByTestId's timeout under load.
  Mock the barrel instead.
2026-07-05 22:16:50 -07:00
fullex
88f141790c refactor(core): dissolve paths & application barrels, seal lifecycle (naming §6.4)
Three core barrels, three diagnoses under naming-conventions §6.4:

- paths: remove the barrel — it only re-exported types while the real entry
  is application.getPath(). constants.ts and pathRegistry.ts are independent
  building blocks deep-imported by their specific consumers (rules 2/3/4).
- lifecycle: keep the barrel (a cohesive framework consumed as a set by 80+
  services), route the last deep-import leaks through it, and prune 13
  framework-internal machinery exports (resolver, decorator getters, capability
  guards) that no consumer touches — tightening the door to its public surface.
- application: remove the barrel and repoint @application directly at
  Application.ts. The barrel bundled the hot `application` locator (~218
  consumers) with the bootstrap-only serviceRegistry, so every @application
  import dragged in the whole service graph — the root of the JobManager-to-
  serviceRegistry eval-time cycle. The locator now loads on its own.

Relocate SHUTDOWN_TIMEOUT_MS from an Application static into
lifecycle/constants.ts: a shared shutdown-grace policy honored by both
Application and JobManager, so JobManager no longer imports the Application
class at all.

Docs (paths/README, application/README, application-overview) and per-file
test mocks (vi.mock('@main/core/application') to '@application';
Application.getPath vi.unmock) are updated in lockstep.
2026-07-05 22:06:52 -07:00
fullex
c80849b0f4 refactor(provider-settings): clean up barrel boundaries per naming §6.4
Hoist page-shared model-sync logic (modelSync, buildModelListSyncPreview,
providerModelSyncRequirements, modelSyncPreviewTypes) out of the ModelList
component directory into the page-level utils/ and types/ buckets so
ModelList becomes a cleanly-closable door; expose the ModelList health
context through the ModelList barrel; surface MODEL_ENDPOINT_OPTIONS on the
ModelDrawer barrel; and drop the dead ProviderList re-export from the root
barrel. Clears all ProviderSettings barrel warnings.
2026-07-05 21:39:58 -07:00
eeee0717
f3790f4b65 fix(code-cli): resolve a fallback Gemini base URL for aggregators without a native endpoint
Selecting CherryIN's agent/deepseek-v4-flash for Gemini CLI showed "unknown
provider" (未知供应商) after enabling it. CLI_TOOL_PROVIDER_MAP allow-lists
CherryIN/DMXAPI as Gemini CLI providers even though neither exposes a
google-generate-content endpoint, and GEMINI_AGGREGATOR_BASE_URLS only had an
override for aihubmix. resolveGeminiBaseUrl fell through to '', so
GOOGLE_GEMINI_BASE_URL was never written to ~/.gemini/.env — not just a
cosmetic mismatch, the CLI tool itself was left pointed at Google's real API
instead of the aggregator. The readback in providerMatching.ts then correctly
flagged the empty base URL as a non-match and surfaced the "unknown provider"
badge.

resolveGeminiBaseUrl now falls back to the provider's default-chat-endpoint
base URL when there's no dedicated Gemini endpoint or override, mirroring the
identical fallback buildCherryinConfig/dmxapiProvider.ts already use for real
chat requests to these same providers — both proxy every protocol off one
shared host, so this fixes CherryIN and DMXAPI generically without a guessed,
hardcoded per-provider URL. new-api (has a native google-generate-content
endpoint) and aihubmix (already overridden) are unaffected.

Checked the other file-configured CLI tools for the same allow-list/resolver
mismatch: none exists — Claude Code/Codex/Qwen/Kimi's provider filters check
the exact endpoint their resolver reads, and OpenCode's resolver dynamically
picks whichever endpoint the provider actually has. Gemini CLI is the only
tool whose filter carries a hardcoded aggregator allow-list independent of
real endpoint presence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-06 11:53:32 +08:00
fullex
b5a54f90de refactor(bootConfig): drop dead shared barrel per naming §6.4
The src/shared/data/bootConfig/index.ts barrel had zero consumers — every
importer already deep-imports bootConfigSchemas/bootConfigTypes — while
imposing a hand-sync burden against the auto-generated bootConfigSchemas.ts.
Per §6.4 rule 2 (enforced sole entry, or no barrel) and matching the sibling
api/preference/cache no-barrel containers, remove it. Clears 11 barrel/closed
warnings with no consumer changes.
2026-07-05 20:53:07 -07:00
fullex
28af4b6d85 docs(file): fix broken source links after barrel refactor
The FileHandle type union moved to src/shared/data/types/file.ts and the
watcher/ directory was flattened to watcher.ts during the naming §6.4
barrel refactor, leaving two dead links caught by docs:check-links.
2026-07-05 20:39:51 -07:00
eeee0717
774bcb6678 fix(code-cli): also exempt OpenCode from the Ollama API-key requirement
Ollama's real endpointConfigs only expose an anthropic-messages endpoint
(no openai-chat-completions/openai-responses), so CLI_TOOL_PROVIDER_MAP
lets it be selected as a provider for exactly two file-configured tools:
Claude Code and OpenCode (routed through @ai-sdk/anthropic). OpenCode hit
the same "missing required fields (apiKey/baseUrl)" failure the previous
commit fixed for Claude Code, since assertCliConfigCredentials only
special-cased Claude Code.

Extended the placeholder-token fallback to OpenCode and renamed the shared
constant from OLLAMA_CLAUDE_CODE_AUTH_TOKEN to OLLAMA_PLACEHOLDER_AUTH_TOKEN
now that it backs two tools. Codex/Gemini CLI/Qwen Code/Kimi Code require
openai-chat-completions, openai-responses, or google-generate-content
endpoints that Ollama never exposes, so they can't reach this bug — their
existing API-key checks are correct as-is and were left untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-06 11:30:29 +08:00
fullex
c739c0876a refactor(barrels): move implementation out of index-no-impl barrels (naming §6.4)
Batch D of the §6.4 barrel cleanup: an index.ts must be a pure re-export, so
implementation, side effects, and local declarations move to named files.

- i18n: demote to a no-barrel container (index.ts -> resolver.ts); label.ts
  stays as a sibling deep-import. The directory holds two orthogonal concerns
  (the heavy i18next engine + pure label-key resolvers), so a single barrel
  would drag the engine into label's pure consumers -> no barrel per rule 4.
- ipc: keep a cohesive barrel (index.ts -> ipcApi.ts) re-exporting both ipcApi
  and useIpcOn -- the request and event halves of one IpcApi surface.
- composer/tools: eliminate import-for-side-effect registration. Each definition
  exports its tool; an explicit BUILTIN_COMPOSER_TOOLS array replaces the
  module-scope registry Map, and the barrel is dropped.
- transport / tags-Model / migrationV2-i18n: mechanical barrel cleanup.
- import/importers: inline availableImporters into its sole consumer.
- databases (v1 Dexie) is left as-is; it is throwaway code with live v2
  consumers and belongs to the dexie-deletion effort.
2026-07-05 20:28:51 -07:00
fullex
d0f36c10cd refactor(ai): seal runtime/channels/types barrels per naming §6.4
- runtime: dissolve container barrel; aiSdk and claudeCode each own a door
- channels: single door, internalize security satellite
- types: complete the barrel surface (AiBaseRequest et al.)
2026-07-05 20:20:29 -07:00
fullex
2d677c8204 refactor(api-gateway): dissolve adapters sub-barrels, curate root barrel (naming §6.4)
The adapters/ root barrel deep-imported leaves inside four sub-barrels
(stream/converters/formatters/factory), tripping both no-nesting and closed.
The sub-barrels were themselves dead — incomplete and imported by nobody: the
root barrel, the factories, and the tests all bypassed them for leaves.

- Delete the four internal sub-barrels; the subdirs become plain folders, so
  the factory/formatter/root leaf imports are now legal (no barrel to bypass).
- Curate adapters/index.ts to the real public surface — the two factories plus
  the interface/format types actually consumed by proxyStream and errors. The
  concrete stream adapters, converters, and formatters have zero external
  consumers and stay internal.
- Move openrouter.ts up to apiGateway/, next to its sole consumer
  reasoningCache.ts — it is a reasoning-cache type contract, not adapter
  machinery — clearing the last closed violation.
- Document openrouter.ts's new home in the api-gateway README tree.

apiGateway barrel warnings: ~38 -> 0.
2026-07-05 20:17:47 -07:00
eeee0717
0b03b99d29 fix(code-cli): allow Claude Code to enable Ollama without an API key
`assertCliConfigCredentials` unconditionally required an API key for every
CLI tool, so enabling Claude Code with an Ollama provider (which needs no
real credential) failed with "Claude Code config is missing the API key" —
both from the config dialog's save path and from the plain enable-toggle
path, since both funnel through the same `writeCliConfigDraft`.

The in-app agent runtime (agentSessionWarmup.ts) already special-cases this:
Ollama gets a placeholder auth token ('ollama') when no real key is
configured, since Ollama's server doesn't validate credentials but Claude
Code's SDK still requires a non-empty token. That fallback was never ported
to the renderer's external-CLI config injection path. Applied the same
fallback in `resolveContext` and moved the shared constant into
`@shared/utils/provider.ts` so both call sites stay in sync.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-06 10:33:05 +08:00
eeee0717
06526863e1 Merge remote-tracking branch 'upstream/main' into refactor/code-cli
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-06 10:32:38 +08:00
fullex
d9475b2562 refactor(stream-manager): make root barrel the public surface, drop internal sub-barrels
Rewrite streamManager/index.ts to export the full consumed surface (all
listeners, startAgentSessionRun, PersistenceBackend contract, TranslationBackend,
stream types); route all 15 external deep imports through it. Remove the
internal-only context/ and lifecycle/ sub-barrels so internal siblings import
directly. Expose AiStreamRequest/CallOverrides on the ai/types barrel and route
ChannelAdapter through the channels barrel.

Two deep imports remain, blocked by nested sub-barrels in sibling dirs
(runtime/claudeCode, channels/security) — deferred to those dirs' cleanup.
2026-07-05 10:59:09 -07:00
fullex
1a8dcc17b7 refactor(icons): demote icons barrel to no-barrel bucket per naming §6.4
icons/ is a bucket of independently-consumed icon components, not a
cohesive API taken as a set — §6.4 rule 4 (aggregator) + §4.9 (plural
bucket) both point to no barrel. Delete index.ts; consumers deep-import
the specific file, so the 22 pre-existing deep imports become legal and
the ~24 barrel/closed lint warnings clear.

Rename SvgSpinners180Ring.tsx -> LoadingIcon.tsx so the deep import
reads naturally (the barrel had aliased its default as LoadingIcon).
Re-point 18 barrel-mock tests to the deep paths (default-export files
wrap the stub in { default: ... }).

Deferred (flagged, out of scope): splitting the 36KB SvgIcon.tsx
grab-bag; moving miniAppsLogo.ts to utils/.
2026-07-05 10:59:09 -07:00
fullex
1e8ec7b713 refactor(resource-catalog): rename resource→resourceCatalog and split dialogs into per-family doors (naming §6.4)
- Rename components/resource → components/resourceCatalog (align with hooks/resourceCatalog, types/resourceCatalog)
- Demote resourceCatalog/ and dialogs/ to no-barrel containers (§6.4 rule 4); each cohesive unit owns its door
- Sink the 5 selectors into selectors/ behind their own barrel
- Extract cross-cluster shared logic (form state/diff, model filter, constants) to utils/resourceCatalog/
- Split dialogs into per-family barrels (create/edit/delete/detail/import/manage); move shared EditDialogShared scaffolding to dialogs/components
- Route consumers through the family doors, restoring the selectors' create-eager / edit-lazy code-split that a single dialogs door had defeated
- Complete hooks/resourceCatalog barrel (add useResourceCatalogController)

Clears 11 §6.4 rule-2 deep-import warnings; typecheck + 14398 tests green.
2026-07-05 10:52:52 -07:00
fullex
840f812690 refactor(barrels): move impl out of index barrels per naming §6.4
Clear all `barrel/index-no-impl` violations in src/main (14 barrels) by
turning each index.ts into a pure re-export or dissolving it:

- Aggregation buckets → drop the barrel, move the assembled object/array/fn
  to a named file, deep-import at the sole consumer: data/api/handlers →
  apiHandlers.ts, ipc/handlers → ipcHandlers.ts, migrators → migratorRegistry.ts,
  params/features → internalFeatures.ts, browser/tools → registry.ts,
  builtin → registerBuiltinTools.ts, db/seeding → seederRegistry.ts.
- Single-impl dirs flattened: provider/extensions.ts, provider/cherryai.ts.
- Barrel kept, impl extracted to a named file: i18n/resolver.ts,
  ai/types/providerConfig.ts.
- Route subdir flattened to match its flat siblings: routes/knowledge.ts +
  routes/knowledgeSchemas.ts.
- runtime: replace the import-time `claudeCode/register` side effect with an
  explicit registerRuntimeDrivers() invoked from AgentSessionRuntimeService.onInit,
  so runtime/index.ts stays a pure re-export.
- loop: dissolve the non-enforced barrel into loop/types.ts + loop/hookRunner.ts.

Also route DataApiService's apiHandlers import through the data/api barrel,
and expose ClaudeCodeRuntimeDriver via the claudeCode barrel, clearing the two
deep-import warnings this batch touched. Docs and comments updated to the new paths.
2026-07-05 09:48:02 -07:00
fullex
6103232f5f refactor(barrels): split no-index-tsx implementation files into named files (naming §6.4)
Resolve all 25 no-index-tsx violations across components/ and pages/ per
naming-conventions.md §6.4 (the `index` filename is reserved for re-export
barrels, so an `index.tsx` is always a violation).

- Single-file components -> flat `Foo.tsx` (no directory, no barrel):
  AppModal, HorizontalScrollContainer, ListItem, MarkdownEditor,
  ProviderLogoPicker, Scrollbar, home ChatNavbar, AgentChatNavbar/Tools.
- Multi-file components with private satellites -> named impl + enforced
  index.ts barrel (default re-exported as a named export):
  EmojiPicker, ErrorDetailModal, WindowControls, LanTransferPopup,
  AgentChatNavbar, WebSearch CompressionSettings.
- Route-bound pages -> named file, route deep-imports, no barrel:
  paintings (PaintingPage); settings ChannelsSettings, CommonSettings,
  FileProcessingSettings, IntegrationSettings, WebSearchSettings; home Tabs
  (HomeTabs, whose internals are already deep-imported).
- settings/index.tsx (a styles + SettingsPrimitives passthrough masquerading
  as a barrel) -> settingsStyles.ts for the layout class-name constants; drop
  the redundant primitives passthrough and repoint 53 consumers straight to
  @renderer/components/SettingsPrimitives.
- McpSettings shell index.tsx -> McpSettingsPage.tsx (avoids colliding with
  the sibling McpSettings.tsx form).
- TopView index.tsx -> TopView.tsx; toast stays a separately deep-imported
  surface (no barrel, since its internals are consumed externally).
- RichEditor index.tsx -> RichEditor.tsx with no barrel: its light satellites
  (useRichTextEditorKernel, the Placeholder extension) are consumed standalone
  and must not drag the 569-line editor through a barrel.

Consumers, tests, and vi.mock factories updated for the default->named
conversions and path changes. Renderer typecheck + full test suite (14398
tests) green.
2026-07-05 09:39:16 -07:00
fullex
42f51b43f6 refactor(code): split code page barrel into cliTools + toolEnvironment
src/renderer/pages/code/index.ts was a barrel carrying ~280 lines of
implementation plus a dead `export { default } from './CodeCliPage'`: the
route deep-imports CodeCliPage.tsx, so nothing consumed the barrel default.
This violates naming conventions §6.4 (the index filename is reserved for
re-export-only barrels, and an unenforced/unused door should not exist).

Dissolve the barrel and route the implementation into two named modules by
concern:
- cliTools.ts        -> CLI_TOOLS catalog + provider eligibility
                        (CLI_TOOL_PROVIDER_MAP, isOpenCodeProvider, *_SUPPORTED_PROVIDERS)
- toolEnvironment.ts -> launch env synthesis
                        (generateToolEnvironment, parseEnvironmentVariables,
                         getCodeCliApiBaseUrl, ToolEnvironmentConfig)

pages/code/ now has no index.ts; the route entry stays CodeCliPage.tsx, in
line with the majority of sibling page directories. Also drops the dead
LaunchValidationResult export (zero consumers) and the hidden
CodeCliPage -> index -> CodeCliPage import cycle.

Split the test file to match. toolEnvironment.test.ts no longer needs the
four mocks (CodeCliPage, useCodeCli, LoggerService, react-i18next) that
existed only to survive the barrel pulling CodeCliPage's dependency graph
into a pure-function import.

All import sites updated; full lint + 14398 tests green.
2026-07-05 07:41:40 -07:00
fullex
f952e6c7fb refactor(file): consolidate file types and fix §6.4 barrel violations
Merge the split src/shared/data/types/file/ tree (fileEntry + ref/* + the
relocated FileHandle) into a single src/shared/data/types/file.ts, matching
the one-module-per-domain convention for data-layer types. Co-locating the
FileHandle addressing types with FileEntry also removes the module-eval cycle
that previously forced eslint-disable barrel/closed pragmas.

Rename the v1 metadata modules to legacyFile for symmetry across layers
(shared/data/types/legacyFile.ts and main/utils/legacyFile.ts).

Dissolve the enforced-barrel violations flagged by naming conventions §6.4
across the five file-related paths, replacing parent-door-over-child-door
barrels with flat named re-exports:
- shared/data/types/file  -> single flat module
- shared/types/file       -> pure vocabulary (drop handle re-export)
- shared/utils/file       -> named door only
- main/utils/file         -> clean named door, hoist legacyFile out
- main/services/file      -> single facade, flatten tree/ and watcher/

All import sites updated; behavior unchanged (14398 tests green, barrel lint 0).
2026-07-05 07:10:53 -07:00
fullex
9f54c4857a refactor(barrels): convert export* to named re-exports per naming §6.4 (batch B)
Replace `export *` with explicit named/type re-exports across the renderer,
main, and shared barrels flagged by the naming §6.4 lint, and give five
`named-only` barrels an explicit named export in place of a forwarded bare
`default` (updating their default-import consumers).

Dissolve two mis-classified bucket barrels instead of enumerating them:
- components/CodeToolbar/hooks: a `hooks/` bucket that fed a nested `export *`
  from the component root; the root now re-exports the eight tool-hook leaves.
- pages/knowledge/utils: an aggregator over four unrelated topics; consumers
  now deep-import the specific error/group/rag/validate module.

Deferred to their own batches (untouched here): the file-quartet barrels
(shared/data/types/file, main/utils/file) and pages/code/index.ts.

no-export-star 51->4, named-only 6->1; no-nesting 18->17, closed 301->299;
no other barrel rule regressed. typecheck (node/web/aicore) and the full test
suite pass.
2026-07-05 04:09:42 -07:00
fullex
4e54651eef refactor(chat-components): enforce naming §6.4 barrel contract in chat subtree
Dissolve the aggregator and nested barrels under src/renderer/components/chat
that forced deep-import (rule 2) and nesting (rule 3) violations, and split the
resource-list family so its two layers stop sharing one bucket.

Barrels:
- Delete chat/index.ts and messages/index.ts aggregator doors; both become
  no-door containers reached by file path.
- Relocate misfiled units to chat-level siblings: flow/ (home topic graph) and
  editing/ (MessageEditingContext), which never belonged to message display.
- Keep the cohesive sub-doors: tools/agent (expanded to cover its cross-door
  consumers), primitives (export-* replaced with named re-exports), and
  resources (drop the variants nesting).

Resource lists (resources -> resourceList):
- Rename the mislabeled resources/ dir to resourceList/; its contents are
  uniformly a ResourceList engine, not "resources".
- Move the generic engine into resourceList/base/ (single door) and leave the
  concrete entity lists loose at resourceList/ root with no door. resourceList/
  is itself a no-door container, so base/ keeps one clean door with no
  parent-over-sub-door conflict.
- Route all consumers through the base door or the loose list files and drop
  the dead variants/index.ts door.

The public engine API is unchanged; consumer edits are path-only. Verified with
typecheck, the full renderer test suite (5548 tests), and lint (chat subtree
barrel deep-import warnings now 0).
2026-07-05 03:12:44 -07:00
eeee0717
e97806af16 fix(code-cli): fix dotenv escaping and redaction gaps found in re-review of 4fc8948
Re-review of the previous CLI-config fix batch (4fc8948) surfaced three
regressions introduced by that batch itself, plus two sinks the secret
redaction still missed:

- dotenv.ts: quoting a value that needed escaping (contains #, quotes, or
  leading/trailing whitespace) injected \\ and \" escapes that the real
  `dotenv` package (used by gemini-cli to read the file back) never
  unescapes — it only re-expands \n/\r inside double-quoted values. This
  silently corrupted Windows-style paths (doubled backslashes) and any
  value containing a literal double quote. Fixed by preferring a
  single-quoted value (read back 100% literally) whenever it has no
  embedded single quote, and only escaping \n/\r in the double-quote
  fallback.
- redact.ts: the value-matching regex stopped at the first embedded
  apostrophe in a double-quoted value, or at an already-broken/empty
  quoted pair, leaving the real secret exposed as an unredacted trailing
  fragment in both cases. Fixed by matching the rest of the source line
  (smol-toml embeds raw source lines verbatim in its own error messages)
  instead of a single quoted token.
- Centralized secret redaction inside parseTomlOrThrow/parseJsonOrThrow
  themselves (instead of only at the two call sites that remembered to
  wrap it), closing two previously-unredacted sinks:
  validateCliConfigDraftForWrite (manual config-text editing) and
  draftUpdater.ts's direct parse calls.
- Added missing assertCliConfigCredentials coverage for the
  missing-base-URL branches of OpenCode/Qwen/Kimi (only the missing-API-key
  branch had a test before).

Every fix has a regression test verified to fail without it; the dotenv
and redact tests exercise the real `dotenv`/`smol-toml` packages directly
rather than hand-crafted strings, to catch this class of drift going
forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 17:54:14 +08:00
eeee0717
4fc8948ab0 fix(code-cli): resolve data-loss, credential-leak, and behavior-regression findings from PR review
Addresses a local code review of the CLI-config subsystem covering 18 findings
across 2 CRITICAL, 9 IMPORTANT, and 7 SUGGESTION items:

- Distinguish missing-file from read-error in readExternal/snapshotFile so a
  transient read failure (EACCES/EBUSY) no longer gets misread as "file
  doesn't exist," which previously caused the build path to wipe unmanaged
  config keys and the rollback path to trash real user config files.
- Stop using the MANAGED (full-wipe) key set on incremental build paths for
  Gemini/Qwen/Kimi, which was silently deleting fields Cherry has no UI for.
- Quote dotenv values containing `#` or leading/trailing whitespace so
  Gemini's .env file survives round-tripping through external parsers.
- Fail closed (instead of silently defaulting) when OpenCode provider
  resolution fails, and when Claude Code is enabled without an API key.
- Restore the custom OpenClaw gateway port preference and fix an initial-load
  race in the config draft controller that could misclassify a foreign
  config as managed before apiKeys finished loading.
- Redact likely secrets (including multiline TOML triple-quoted values and
  Bearer tokens) from parser error messages before they reach logs/UI.
- Write CLI config files with 0600 permissions instead of the platform
  default, since they contain credentials.
- Avoid a Codex provider display-name collision with the literal "OpenAI"
  sentinel used to encode remoteCompaction.
- Remove the dead Codex "Write Common Config" toggle and its dead OpenClaw
  IPC routes (check_health/get_channels/check_update/perform_update), which
  had no consumers.
- Harden rollback error logging (don't mask the original write error with a
  restore error) and null out empty-shell connection objects instead of
  treating them as valid foreign configs.

Each fix ships with a regression test verified to fail without its
corresponding change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 17:05:11 +08:00
eeee0717
32202e4650 fix(code-cli): match OpenClaw dashboard button style to Launch/Stop
The dashboard-reopen button was icon-only, inconsistent with the
Launch/Stop buttons next to it. Switch it to the same outline
icon+label style and relabel it "Open OpenClaw" instead of the more
generic "Open Dashboard".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 15:02:45 +08:00
eeee0717
3353057a3c fix(code-cli): trust workspace when launching gemini-cli
gemini-cli only loads ~/.gemini/.env (where GEMINI_API_KEY lives) for
directories it considers "trusted", which a freshly launched project
folder never is. Even with security.auth.selectedType configured
correctly, this left users staring at an interactive "Enter Gemini API
Key" prompt instead of a working session. Inject gemini-cli's own
GEMINI_CLI_TRUST_WORKSPACE bypass env var when spawning it, scoped to
this one launched session so it doesn't touch the user's global
gemini-cli trust settings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 15:02:33 +08:00
fullex
5ce7ede45b refactor(components): dissolve Selector aggregate and enforce barrel end-state per naming §6.4
Split components/Selector/ into three §4.2-conformant units (flat Selector.tsx,
ModelSelector/ with an enforced door, flat SelectorShell.tsx), relocate the
tools-wide shared primitives (GenericTools, ClickableFilePath, agent tool types)
from tools/agent/ to tools/shared/, lift the message-parts context API from the
blocks shim barrel into the messages door, delete the EditableNumber forwarding
shim, and rename the remaining pure re-export index.tsx barrels to index.ts.
2026-07-04 23:54:25 -07:00
eeee0717
995f62f86e feat(code-cli): add button to reopen the OpenClaw gateway dashboard
Launching OpenClaw auto-opens its control dashboard as a miniapp, but
that only happens once at launch time. Closing the miniapp window left
no way back in even though the gateway kept running in the background
(the tool card still showed a Stop button). Add an icon button next to
Stop, shown only while the gateway is running, that re-fetches the
dashboard URL and reopens the miniapp.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 13:55:26 +08:00
eeee0717
92ef64b713 fix(cli-config): sync security.auth.selectedType for gemini and qwen
gemini-cli and qwen-code both gate API-key auth behind
security.auth.selectedType in settings.json. The Gemini config writer
never set it, so gemini-cli couldn't recognize the configured key even
though provider/model sync succeeded. Qwen wrote it on connect but
never cleared it on disconnect, leaving a stale auth type behind after
removing the provider. Add the missing write for Gemini and a shared
cleanup helper used by both CLIs' disconnect paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 13:55:12 +08:00
fullex
1bac7ac18c refactor(shared-ipc): flatten schemas/errors impl-indexes to named modules per naming §6.4
schemas/index.ts and errors/index.ts carried real local declarations — the
`ipcRequestSchemas` runtime registry plus composed types, and the `IpcError`
class plus `IpcErrorCode` — yet sat under the index.ts name, tripping
barrel/index-no-impl (§6.4 rule 1: an index must be a pure re-export barrel).
Unlike the api barrel there is no outer barrel to remove — ipc/ is already an
open namespace — so this is a straight rename to named modules.

- schemas/index.ts -> schemas/ipcSchemas.ts; errors/index.ts -> errors/IpcError.ts.
- Repoint all consumers (18 deep imports + one intra-package import), including
  directory-form relative imports (./schemas, ../errors) that resolved via Node's
  index lookup.
- Sync the ipc docs: rename path references and reword the "no errors/index.ts
  aggregation" prose, since errors/ now has no index at all.
2026-07-04 22:23:29 -07:00
fullex
35256975e3 refactor(shared-data-api): drop the api barrel and flatten module names per naming §6.4
The api/index.ts barrel re-exported only infra types yet required domain DTOs
to deep-import schemas/<domain>, colliding with naming §6.4 rule 2
(enforced-or-no-barrel) and accounting for the bulk of barrel/closed lint
violations. Because schema files carry zod runtime values, any aggregating
barrel drags all 24 domains in on a single import — exactly what the barrel
reform removes.

- Remove api/index.ts; api/ is now an open namespace.
- Flatten infra file names: apiTypes/apiErrors/apiPaths -> types/errors/paths;
  schemas/index.ts -> schemas/apiSchemas.ts.
- Rewrite all consumers: 71 deep-import path renames + 106 barrel imports split
  to their owning module (types/paths/errors), including two dynamic imports and
  the tests/__mocks__ fixtures.
- Sync data docs and codify the schemas/ `_xxx.ts` = cross-resource construct
  convention in naming-conventions §3.2.
2026-07-04 21:51:21 -07:00
eeee0717
9083b9291a fix(code-cli): disable current provider when its CLI tool is removed
Uninstalling a CLI tool left its previously enabled provider marked as
current, so the config panel still showed it as active for a tool that
was no longer installed. Clear the CLI config and unset the current
provider once removal succeeds.

Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 12:38:46 +08:00
eeee0717
dcc7c8b356 fix(code-cli): use semantic foreground/destructive colors for launch button
The launch/stop button was hardcoded to text-muted-foreground, only
turning full-opacity on hover. Use text-foreground while idle and
text-destructive while running so the button state is visible at rest.

Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 12:38:38 +08:00
eeee0717
ec5311e5cb Merge upstream/main into refactor/code-cli 2026-07-05 11:21:02 +08:00
eeee0717
bfa9077453 refactor(code-cli): dedupe cliConfig helpers
Extract shared isCherryManagedModel / findCherryProviderKey helpers and route CHERRY_-prefixed env filtering through the existing omitKeysByPrefix, replacing duplicated predicates across builders/clear/parser/draftUpdater. Pure refactor; behavior unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 11:19:42 +08:00
fullex
49df4c7aa6 feat(lint): enforce naming §6.4 barrel contract with warn-level rules
Add an inline `barrel` ESLint plugin (same pattern as the lifecycle plugin) implementing §6.4 rules 1-3: no-export-star; index-no-impl (a barrel is pure re-export — no default/local exports, no side-effect imports, no top-level logic); no-index-tsx (no exceptions — index routes use the flat dot form); named-only; closed (sole-entry boundary, judged against the outermost crossed barrel dir so a nested barrel's index cannot bypass its parent's door); no-nesting; no-bucket-root. Barrel discovery classifies pure re-export index.ts files once at config load; import resolution covers relative specs plus @renderer/@main/@shared/@data, with deliberately-unresolved single-file aliases documented inline. All rules start at warn and tests are exempt by design; a full-src sweep reports 0 errors, with warnings matching the audited migration backlog.
2026-07-04 20:18:30 -07:00
fullex
87b2b64ba5 refactor(process-entry): rename main/preload entries to named files per naming §6.4
src/main/index.ts → main.ts and src/preload/index.ts → preload.ts, so the process entries stop occupying the barrel-reserved index filename (§6.4) without needing an exemption list. The rename is wired through electron.vite (main build.lib.entry — rollupOptions.input would bypass electron-vite's output-format detection — and the preload input key), package.json main (out/main/main.js), WindowManager's default preload filename, MainWindowService's webview preload path, and DbService's slow-query stack filter, which matches the bundled artifact name. preload.d.ts becomes globals.d.ts: sharing preload.ts's basename makes TypeScript drop the .d.ts as that file's presumed output declaration, and tsgo only applies its global Window augmentation when the declaration sorts before its importer, so the file keeps a distinct, alphabetically-early name. Entry-path mentions in code comments and reference docs follow.
2026-07-04 20:18:14 -07:00
fullex
c5342b29f4 refactor(routes): adopt flat dot-form index routes, closing naming §6.4's last exception
Rename the four directory-form index routes (settings/, settings/mcp/, app/mini-app/, app/paintings/) to TanStack's default-supported flat dot form (settings.index.tsx, …) so no file under routes/ is named index.* and the §6.4 iron rule — the index filename is reserved for barrels — holds across src with no exceptions. URLs and route ids are unchanged; routeTree.gen.ts regenerates with only the four import paths moved. Naming §6.4 drops the routes/ carve-out, §6.6 documents the dot-form token, and the routes READMEs replace a stale bare-index example.
2026-07-04 20:17:54 -07:00
eeee0717
657f0943ed refactor(cli-config): use i18n keys for CLI tool display labels
CLI_TOOLS.label was a hardcoded English string rendered directly in the
sidebar. Store an i18n key instead and resolve it with t() at the point
of use, matching the existing convention for provider display names.

Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 11:05:26 +08:00
eeee0717
51171c1343 refactor(cli-config): consolidate inject/draft pipelines and dedupe helpers
Merges the inject.ts and draft.ts write pipelines (removing the circular
fallback between them), dedupes small helper functions repeated across
builders/clear/parser/values, unifies sanitizeProviderName between the
renderer and main process to remove a cross-process drift risk, and
consolidates the OpenCode npm mapping and per-tool baseUrl resolution
into single-source-of-truth tables in resolvers.ts.

Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 11:05:13 +08:00
eeee0717
d627c7a214 refactor(code-cli): split page controllers by responsibility
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
2026-07-05 09:55:51 +08:00