@shepai/cli 1.135.1 → 1.135.2-pr437.64c56e0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/json-schema/FeatureFlags.yaml +5 -0
- package/dist/packages/core/src/application/ports/output/services/coasts-service.interface.d.ts +132 -0
- package/dist/packages/core/src/application/ports/output/services/coasts-service.interface.d.ts.map +1 -0
- package/dist/packages/core/src/application/ports/output/services/coasts-service.interface.js +12 -0
- package/dist/packages/core/src/application/ports/output/services/index.d.ts +1 -0
- package/dist/packages/core/src/application/ports/output/services/index.d.ts.map +1 -1
- package/dist/packages/core/src/domain/factories/settings-defaults.factory.d.ts.map +1 -1
- package/dist/packages/core/src/domain/factories/settings-defaults.factory.js +1 -0
- package/dist/packages/core/src/domain/generated/output.d.ts +4 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +10 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/settings.mapper.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/settings.mapper.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/settings.mapper.js +2 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/044-add-feature-flag-coasts-dev-server.d.ts +11 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/044-add-feature-flag-coasts-dev-server.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/044-add-feature-flag-coasts-dev-server.js +17 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-settings.repository.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-settings.repository.js +3 -2
- package/dist/packages/core/src/infrastructure/services/coasts.service.d.ts +42 -0
- package/dist/packages/core/src/infrastructure/services/coasts.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/coasts.service.js +185 -0
- package/dist/src/presentation/web/coasts-dev-server.d.ts +34 -0
- package/dist/src/presentation/web/coasts-dev-server.d.ts.map +1 -0
- package/dist/src/presentation/web/coasts-dev-server.js +68 -0
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +3 -2
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.js +3 -0
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.stories.js +3 -0
- package/dist/src/presentation/web/components/features/settings/settings-page-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/settings-page-client.js +5 -0
- package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.js +1 -0
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.stories.js +1 -0
- package/dist/src/presentation/web/dev-server.js +62 -1
- package/dist/src/presentation/web/hooks/feature-flags-context.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/feature-flags-context.js +1 -0
- package/dist/src/presentation/web/lib/feature-flags.d.ts +2 -0
- package/dist/src/presentation/web/lib/feature-flags.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/feature-flags.js +5 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +24 -24
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +24 -24
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +24 -24
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__c6e32a23._.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__31bc28da._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__31bc28da._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__32ecbed9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__32ecbed9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7894f27f._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7894f27f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__90ce4b6d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__90ce4b6d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__90f9ae71._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__90f9ae71._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__96670392._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__96670392._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9c45d070._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0020fddd._.js +1 -1
- package/web/.next/server/chunks/ssr/_0020fddd._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_02ec1aea._.js +1 -1
- package/web/.next/server/chunks/ssr/_02ec1aea._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_7dca1882._.js +1 -1
- package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_76c02473._.js → _8b23e6e2._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_76c02473._.js.map → _8b23e6e2._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_a37f5f18._.js +1 -1
- package/web/.next/server/chunks/ssr/_a37f5f18._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_a9f57758._.js +1 -1
- package/web/.next/server/chunks/ssr/_a9f57758._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_b6960ca0._.js +2 -2
- package/web/.next/server/chunks/ssr/_d4b20e29._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
- package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_dc7a5354._.js +3 -0
- package/web/.next/server/chunks/ssr/{_f4036c66._.js.map → _dc7a5354._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_f39a1adb._.js +1 -1
- package/web/.next/server/chunks/ssr/_f39a1adb._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_36c89258._.js +3 -0
- package/web/.next/server/chunks/ssr/{src_presentation_web_7f2bd8b5._.js.map → src_presentation_web_36c89258._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +38 -38
- package/web/.next/static/chunks/{3e2d7d07926b05bf.css → 1547f0a22212eeb3.css} +1 -1
- package/web/.next/static/chunks/17fa4fac14853191.js +1 -0
- package/web/.next/static/chunks/{0b7fe2ac4f078f54.js → 18616dda443b7ed1.js} +7 -7
- package/web/.next/static/chunks/{fc30f9f869b6d879.js → 1ca8c882e9cf102c.js} +1 -1
- package/web/.next/static/chunks/{fbcce031d4f6a933.js → 30bd89fd01b119a2.js} +1 -1
- package/web/.next/static/chunks/{7c62d50a59d1296b.js → 3159d1f9416e896d.js} +1 -1
- package/web/.next/static/chunks/{7c858879658287c9.js → 4b0275fb3340cd3e.js} +1 -1
- package/web/.next/static/chunks/{4d4a06751c4a6dc5.js → 5a01342d617cd58f.js} +1 -1
- package/web/.next/static/chunks/{e804b8565e41d2d0.js → 636fe3836aae4006.js} +1 -1
- package/web/.next/static/chunks/{2b2bcf845ca00af0.js → 6ed7881d7545daae.js} +1 -1
- package/web/.next/static/chunks/7661244c2b96e166.js +2 -0
- package/web/.next/static/chunks/{7ad0e3ee269e90ca.js → 86e23100e2c7061e.js} +1 -1
- package/web/.next/static/chunks/{b6117e16e4642568.js → b739a4f78673e414.js} +1 -1
- package/web/.next/static/chunks/{c4dc75f937edf746.js → dc04db51bba7bd03.js} +1 -1
- package/web/.next/server/chunks/ssr/_f4036c66._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_7f2bd8b5._.js +0 -3
- package/web/.next/static/chunks/56ce7ec52973f61f.js +0 -2
- package/web/.next/static/chunks/5dbecf32f1f3b9aa.js +0 -1
- /package/web/.next/static/{eTSgKFGuzFHv4FcGxc30f → QoGS79JLywbDT2qUt3YvL}/_buildManifest.js +0 -0
- /package/web/.next/static/{eTSgKFGuzFHv4FcGxc30f → QoGS79JLywbDT2qUt3YvL}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{eTSgKFGuzFHv4FcGxc30f → QoGS79JLywbDT2qUt3YvL}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coasts Service Implementation
|
|
3
|
+
*
|
|
4
|
+
* Infrastructure adapter wrapping the coast CLI binary for containerized
|
|
5
|
+
* runtime isolation. Uses constructor-injected ExecFunction for subprocess
|
|
6
|
+
* invocation and IStructuredAgentCaller for AI-powered Coastfile generation.
|
|
7
|
+
*
|
|
8
|
+
* Following Clean Architecture:
|
|
9
|
+
* - Implements the ICoastsService application port
|
|
10
|
+
* - Lives in the infrastructure layer
|
|
11
|
+
* - No direct child_process imports (injected via ExecFunction)
|
|
12
|
+
*/
|
|
13
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
14
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
16
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
17
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
18
|
+
};
|
|
19
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
21
|
+
};
|
|
22
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
23
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
24
|
+
};
|
|
25
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import path from 'node:path';
|
|
27
|
+
import { injectable, inject } from 'tsyringe';
|
|
28
|
+
import { IS_WINDOWS } from '../platform.js';
|
|
29
|
+
/** Timeout for coast build (may need to pull Docker images). */
|
|
30
|
+
const BUILD_TIMEOUT_MS = 30_000;
|
|
31
|
+
/** Timeout for all other coast CLI commands. */
|
|
32
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
33
|
+
/** JSON schema for Coastfile generation via structured agent caller. */
|
|
34
|
+
const COASTFILE_SCHEMA = {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
content: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'The complete Coastfile content in TOML format',
|
|
40
|
+
},
|
|
41
|
+
warnings: {
|
|
42
|
+
type: 'array',
|
|
43
|
+
items: { type: 'string' },
|
|
44
|
+
description: 'Any warnings or notes about the generated Coastfile',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
required: ['content'],
|
|
48
|
+
additionalProperties: false,
|
|
49
|
+
};
|
|
50
|
+
let CoastsService = class CoastsService {
|
|
51
|
+
execFile;
|
|
52
|
+
structuredCaller;
|
|
53
|
+
cachedInstallationPrompt = null;
|
|
54
|
+
isWindows;
|
|
55
|
+
constructor(execFile, structuredCaller, isWindows) {
|
|
56
|
+
this.execFile = execFile;
|
|
57
|
+
this.structuredCaller = structuredCaller;
|
|
58
|
+
this.isWindows = isWindows ?? IS_WINDOWS;
|
|
59
|
+
}
|
|
60
|
+
async checkPrerequisites(workDir) {
|
|
61
|
+
if (this.isWindows) {
|
|
62
|
+
return {
|
|
63
|
+
coastBinary: false,
|
|
64
|
+
docker: false,
|
|
65
|
+
coastdRunning: false,
|
|
66
|
+
allMet: false,
|
|
67
|
+
missingMessages: [
|
|
68
|
+
'Coasts dev server is not supported on Windows. See https://coasts.dev/docs for platform support.',
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const [coastResult, dockerResult, coastdResult] = await Promise.allSettled([
|
|
73
|
+
this.checkCoastBinary(),
|
|
74
|
+
this.checkDocker(),
|
|
75
|
+
this.checkCoastdRunning(workDir),
|
|
76
|
+
]);
|
|
77
|
+
const coastBinary = coastResult.status === 'fulfilled';
|
|
78
|
+
const docker = dockerResult.status === 'fulfilled';
|
|
79
|
+
const coastdRunning = coastdResult.status === 'fulfilled';
|
|
80
|
+
const missingMessages = [];
|
|
81
|
+
if (!coastBinary) {
|
|
82
|
+
missingMessages.push('coast binary not found on PATH. Install it with: curl -fsSL https://coasts.dev/install | sh. See https://coasts.dev/docs');
|
|
83
|
+
}
|
|
84
|
+
if (!docker) {
|
|
85
|
+
missingMessages.push('Docker daemon is not reachable. Start Docker Desktop or run: sudo systemctl start docker');
|
|
86
|
+
}
|
|
87
|
+
if (!coastdRunning) {
|
|
88
|
+
missingMessages.push('coastd daemon is not running. Start it with: coastd &. See https://coasts.dev/docs/daemon');
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
coastBinary,
|
|
92
|
+
docker,
|
|
93
|
+
coastdRunning,
|
|
94
|
+
allMet: coastBinary && docker && coastdRunning,
|
|
95
|
+
missingMessages,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async build(workDir) {
|
|
99
|
+
await this.execCoast(['build'], workDir, BUILD_TIMEOUT_MS);
|
|
100
|
+
}
|
|
101
|
+
async run(workDir) {
|
|
102
|
+
const { stdout } = await this.execCoast(['run'], workDir);
|
|
103
|
+
return this.parseCoastInstance(stdout);
|
|
104
|
+
}
|
|
105
|
+
async stop(workDir) {
|
|
106
|
+
try {
|
|
107
|
+
await this.execCoast(['stop'], workDir);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// No-op if no instance is running
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async lookup(workDir) {
|
|
114
|
+
try {
|
|
115
|
+
const { stdout } = await this.execCoast(['lookup'], workDir);
|
|
116
|
+
return this.parseCoastInstance(stdout);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async isRunning(workDir) {
|
|
123
|
+
const instance = await this.lookup(workDir);
|
|
124
|
+
return instance !== null;
|
|
125
|
+
}
|
|
126
|
+
async checkout(workDir) {
|
|
127
|
+
await this.execCoast(['checkout'], workDir);
|
|
128
|
+
}
|
|
129
|
+
async getInstallationPrompt() {
|
|
130
|
+
if (this.cachedInstallationPrompt !== null) {
|
|
131
|
+
return this.cachedInstallationPrompt;
|
|
132
|
+
}
|
|
133
|
+
const { stdout } = await this.execFile('coast', ['installation-prompt'], {
|
|
134
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
135
|
+
});
|
|
136
|
+
this.cachedInstallationPrompt = stdout;
|
|
137
|
+
return stdout;
|
|
138
|
+
}
|
|
139
|
+
async generateCoastfile(workDir) {
|
|
140
|
+
const installationPrompt = await this.getInstallationPrompt();
|
|
141
|
+
const prompt = `${installationPrompt}\n\nAnalyze the project at the working directory and generate a Coastfile.\nReturn the complete Coastfile content as valid TOML in the "content" field.`;
|
|
142
|
+
const result = await this.structuredCaller.call(prompt, COASTFILE_SCHEMA, {
|
|
143
|
+
allowedTools: [],
|
|
144
|
+
silent: true,
|
|
145
|
+
maxTurns: 10,
|
|
146
|
+
});
|
|
147
|
+
const coastfilePath = path.join(workDir, 'Coastfile');
|
|
148
|
+
writeFileSync(coastfilePath, result.content, 'utf-8');
|
|
149
|
+
return coastfilePath;
|
|
150
|
+
}
|
|
151
|
+
async hasCoastfile(workDir) {
|
|
152
|
+
return existsSync(path.join(workDir, 'Coastfile'));
|
|
153
|
+
}
|
|
154
|
+
// --- Private helpers ---
|
|
155
|
+
async checkCoastBinary() {
|
|
156
|
+
await this.execFile('coast', ['--version'], { timeout: 500 });
|
|
157
|
+
}
|
|
158
|
+
async checkDocker() {
|
|
159
|
+
await this.execFile('docker', ['info'], { timeout: 500 });
|
|
160
|
+
}
|
|
161
|
+
async checkCoastdRunning(workDir) {
|
|
162
|
+
await this.execFile('coast', ['ls'], { cwd: workDir, timeout: 500 });
|
|
163
|
+
}
|
|
164
|
+
async execCoast(args, workDir, timeout = DEFAULT_TIMEOUT_MS) {
|
|
165
|
+
return this.execFile('coast', args, { cwd: workDir, timeout });
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Parse coast CLI output to extract port and URL from stdout.
|
|
169
|
+
* Looks for patterns like "port 3000" and "http://localhost:3000".
|
|
170
|
+
*/
|
|
171
|
+
parseCoastInstance(stdout) {
|
|
172
|
+
const portMatch = stdout.match(/port\s+(\d+)/i);
|
|
173
|
+
const urlMatch = stdout.match(/(https?:\/\/[^\s]+)/i);
|
|
174
|
+
const port = portMatch ? parseInt(portMatch[1], 10) : 3000;
|
|
175
|
+
const url = urlMatch ? urlMatch[1] : `http://localhost:${port}`;
|
|
176
|
+
return { port, url };
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
CoastsService = __decorate([
|
|
180
|
+
injectable(),
|
|
181
|
+
__param(0, inject('ExecFunction')),
|
|
182
|
+
__param(1, inject('IStructuredAgentCaller')),
|
|
183
|
+
__metadata("design:paramtypes", [Function, Object, Boolean])
|
|
184
|
+
], CoastsService);
|
|
185
|
+
export { CoastsService };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coasts Dev Server Startup & Shutdown
|
|
3
|
+
*
|
|
4
|
+
* Extracted from dev-server.ts for testability. Provides the Coasts startup
|
|
5
|
+
* sequence (prerequisite checks, Coastfile generation, build, run) and
|
|
6
|
+
* graceful shutdown logic.
|
|
7
|
+
*
|
|
8
|
+
* All log messages use [dev-server:coasts] prefix per NFR-10.
|
|
9
|
+
*/
|
|
10
|
+
import type { ICoastsService, CoastInstance } from '../../../packages/core/src/application/ports/output/services/coasts-service.interface.js';
|
|
11
|
+
/**
|
|
12
|
+
* Start the dev server in Coasts mode.
|
|
13
|
+
*
|
|
14
|
+
* Sequence:
|
|
15
|
+
* 1. Check prerequisites (coast binary, Docker, coastd daemon)
|
|
16
|
+
* 2. Check for Coastfile — generate if missing
|
|
17
|
+
* 3. Build the coast container image
|
|
18
|
+
* 4. Run the coast instance
|
|
19
|
+
*
|
|
20
|
+
* @param coastsService - Resolved ICoastsService from the DI container
|
|
21
|
+
* @param workDir - Working directory (repo/worktree root)
|
|
22
|
+
* @returns The running CoastInstance with port and URL
|
|
23
|
+
* @throws Error if prerequisites are not met or any step fails
|
|
24
|
+
*/
|
|
25
|
+
export declare function startCoastsDevServer(coastsService: ICoastsService, workDir: string): Promise<CoastInstance>;
|
|
26
|
+
/**
|
|
27
|
+
* Gracefully shut down the Coasts instance.
|
|
28
|
+
* Catches and logs errors to prevent shutdown failures.
|
|
29
|
+
*
|
|
30
|
+
* @param coastsService - The ICoastsService instance, or null if not in Coasts mode
|
|
31
|
+
* @param workDir - Working directory for the coast instance
|
|
32
|
+
*/
|
|
33
|
+
export declare function shutdownCoasts(coastsService: ICoastsService | null, workDir: string): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=coasts-dev-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coasts-dev-server.d.ts","sourceRoot":"","sources":["../../../../src/presentation/web/coasts-dev-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACd,MAAM,yEAAyE,CAAC;AAEjF;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,cAAc,EAC7B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,CA8BxB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,cAAc,GAAG,IAAI,EACpC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAUf"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coasts Dev Server Startup & Shutdown
|
|
3
|
+
*
|
|
4
|
+
* Extracted from dev-server.ts for testability. Provides the Coasts startup
|
|
5
|
+
* sequence (prerequisite checks, Coastfile generation, build, run) and
|
|
6
|
+
* graceful shutdown logic.
|
|
7
|
+
*
|
|
8
|
+
* All log messages use [dev-server:coasts] prefix per NFR-10.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Start the dev server in Coasts mode.
|
|
12
|
+
*
|
|
13
|
+
* Sequence:
|
|
14
|
+
* 1. Check prerequisites (coast binary, Docker, coastd daemon)
|
|
15
|
+
* 2. Check for Coastfile — generate if missing
|
|
16
|
+
* 3. Build the coast container image
|
|
17
|
+
* 4. Run the coast instance
|
|
18
|
+
*
|
|
19
|
+
* @param coastsService - Resolved ICoastsService from the DI container
|
|
20
|
+
* @param workDir - Working directory (repo/worktree root)
|
|
21
|
+
* @returns The running CoastInstance with port and URL
|
|
22
|
+
* @throws Error if prerequisites are not met or any step fails
|
|
23
|
+
*/
|
|
24
|
+
export async function startCoastsDevServer(coastsService, workDir) {
|
|
25
|
+
// Step 1: Check prerequisites
|
|
26
|
+
console.log('[dev-server:coasts] Checking prerequisites...');
|
|
27
|
+
const prereqs = await coastsService.checkPrerequisites(workDir);
|
|
28
|
+
if (!prereqs.allMet) {
|
|
29
|
+
const messages = prereqs.missingMessages.map((m) => ` - ${m}`).join('\n');
|
|
30
|
+
throw new Error(`[dev-server:coasts] Prerequisites not met:\n${messages}`);
|
|
31
|
+
}
|
|
32
|
+
console.log('[dev-server:coasts] All prerequisites met.');
|
|
33
|
+
// Step 2: Check for Coastfile — generate if missing
|
|
34
|
+
const hasCoastfile = await coastsService.hasCoastfile(workDir);
|
|
35
|
+
if (!hasCoastfile) {
|
|
36
|
+
console.log('[dev-server:coasts] No Coastfile found. Generating via AI agent...');
|
|
37
|
+
const coastfilePath = await coastsService.generateCoastfile(workDir);
|
|
38
|
+
console.log(`[dev-server:coasts] Coastfile generated at ${coastfilePath}`);
|
|
39
|
+
}
|
|
40
|
+
// Step 3: Build the coast container image
|
|
41
|
+
console.log('[dev-server:coasts] Building coast container...');
|
|
42
|
+
await coastsService.build(workDir);
|
|
43
|
+
console.log('[dev-server:coasts] Build complete.');
|
|
44
|
+
// Step 4: Run the coast instance
|
|
45
|
+
console.log('[dev-server:coasts] Starting coast instance...');
|
|
46
|
+
const instance = await coastsService.run(workDir);
|
|
47
|
+
console.log(`[dev-server:coasts] Ready at ${instance.url}`);
|
|
48
|
+
return instance;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Gracefully shut down the Coasts instance.
|
|
52
|
+
* Catches and logs errors to prevent shutdown failures.
|
|
53
|
+
*
|
|
54
|
+
* @param coastsService - The ICoastsService instance, or null if not in Coasts mode
|
|
55
|
+
* @param workDir - Working directory for the coast instance
|
|
56
|
+
*/
|
|
57
|
+
export async function shutdownCoasts(coastsService, workDir) {
|
|
58
|
+
if (!coastsService)
|
|
59
|
+
return;
|
|
60
|
+
try {
|
|
61
|
+
console.log('[dev-server:coasts] Stopping coast instance...');
|
|
62
|
+
await coastsService.stop(workDir);
|
|
63
|
+
console.log('[dev-server:coasts] Coast instance stopped.');
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.warn('[dev-server:coasts] Failed to stop coast instance:', error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,2CAimB1F"}
|
package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js
CHANGED
|
@@ -169,8 +169,9 @@ export function FeatureDrawerClient({ view: initialView, urlTab }) {
|
|
|
169
169
|
if (result.productDecisions)
|
|
170
170
|
setTechProductData(result.productDecisions);
|
|
171
171
|
}, () => setTechProductData(undefined), undefined, artifactRefreshKey);
|
|
172
|
-
const mergeFeatureId = featureNode?.lifecycle === 'review' &&
|
|
173
|
-
(featureNode?.state === 'action-required' || featureNode?.state === 'error')
|
|
172
|
+
const mergeFeatureId = (featureNode?.lifecycle === 'review' &&
|
|
173
|
+
(featureNode?.state === 'action-required' || featureNode?.state === 'error')) ||
|
|
174
|
+
(featureNode?.lifecycle === 'maintain' && featureNode?.pr)
|
|
174
175
|
? featureNode.featureId
|
|
175
176
|
: null;
|
|
176
177
|
const isLoadingMerge = useArtifactFetch(mergeFeatureId, getMergeReviewData, (result) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-flags-settings-section.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/feature-flags-settings-section.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-flags-settings-section.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/feature-flags-settings-section.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAkCzE,MAAM,WAAW,gCAAgC;IAC/C,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,wBAAgB,2BAA2B,CAAC,EAAE,YAAY,EAAE,EAAE,gCAAgC,2CAgE7F"}
|
package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.js
CHANGED
|
@@ -14,6 +14,7 @@ const FLAG_DESCRIPTIONS = {
|
|
|
14
14
|
githubImport: 'Enable GitHub repository import in the web UI',
|
|
15
15
|
adoptBranch: 'Enable the ability to adopt existing branches as tracked features',
|
|
16
16
|
reactFileManager: 'Use the built-in React file manager instead of the native OS folder picker. Also serves as automatic fallback when the native picker is unavailable.',
|
|
17
|
+
coastsDevServer: 'Enable Coasts containerized runtime isolation for the dev server, providing per-worktree isolation via Docker containers',
|
|
17
18
|
};
|
|
18
19
|
const FLAG_LABELS = {
|
|
19
20
|
skills: 'Skills',
|
|
@@ -22,6 +23,7 @@ const FLAG_LABELS = {
|
|
|
22
23
|
githubImport: 'GitHub Import',
|
|
23
24
|
adoptBranch: 'Adopt Branch',
|
|
24
25
|
reactFileManager: 'React File Manager',
|
|
26
|
+
coastsDevServer: 'Coasts Dev Server',
|
|
25
27
|
};
|
|
26
28
|
const FLAG_KEYS = [
|
|
27
29
|
'skills',
|
|
@@ -30,6 +32,7 @@ const FLAG_KEYS = [
|
|
|
30
32
|
'githubImport',
|
|
31
33
|
'adoptBranch',
|
|
32
34
|
'reactFileManager',
|
|
35
|
+
'coastsDevServer',
|
|
33
36
|
];
|
|
34
37
|
export function FeatureFlagsSettingsSection({ featureFlags }) {
|
|
35
38
|
const [flags, setFlags] = useState({ ...featureFlags });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-flags-settings-section.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/feature-flags-settings-section.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAE/E,QAAA,MAAM,IAAI;;;;;;;CAO0C,CAAC;AAErD,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"feature-flags-settings-section.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/feature-flags-settings-section.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAE/E,QAAA,MAAM,IAAI;;;;;;;CAO0C,CAAC;AAErD,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAYrB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAYxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAYzB,CAAC"}
|
|
@@ -17,6 +17,7 @@ export const Default = {
|
|
|
17
17
|
githubImport: false,
|
|
18
18
|
adoptBranch: false,
|
|
19
19
|
reactFileManager: false,
|
|
20
|
+
coastsDevServer: false,
|
|
20
21
|
},
|
|
21
22
|
},
|
|
22
23
|
};
|
|
@@ -29,6 +30,7 @@ export const AllEnabled = {
|
|
|
29
30
|
githubImport: true,
|
|
30
31
|
adoptBranch: true,
|
|
31
32
|
reactFileManager: true,
|
|
33
|
+
coastsDevServer: true,
|
|
32
34
|
},
|
|
33
35
|
},
|
|
34
36
|
};
|
|
@@ -41,6 +43,7 @@ export const AllDisabled = {
|
|
|
41
43
|
githubImport: false,
|
|
42
44
|
adoptBranch: false,
|
|
43
45
|
reactFileManager: false,
|
|
46
|
+
coastsDevServer: false,
|
|
44
47
|
},
|
|
45
48
|
},
|
|
46
49
|
};
|
package/dist/src/presentation/web/components/features/settings/settings-page-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-page-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/settings-page-client.tsx"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AA2B/E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC1C;AA6QD,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,kBAAkB,GACnB,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"settings-page-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/settings-page-client.tsx"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AA2B/E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC1C;AA6QD,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,kBAAkB,GACnB,EAAE,uBAAuB,2CA6pCzB"}
|
|
@@ -122,6 +122,7 @@ export function SettingsPageClient({ settings, shepHome, dbFileSize, availableTe
|
|
|
122
122
|
githubImport: false,
|
|
123
123
|
adoptBranch: false,
|
|
124
124
|
reactFileManager: false,
|
|
125
|
+
coastsDevServer: false,
|
|
125
126
|
};
|
|
126
127
|
// Agent state
|
|
127
128
|
const [agentType, setAgentType] = useState(settings.agent.type);
|
|
@@ -501,6 +502,10 @@ export function SettingsPageClient({ settings, shepHome, dbFileSize, availableTe
|
|
|
501
502
|
const newFlags = { ...flags, reactFileManager: v };
|
|
502
503
|
setFlags(newFlags);
|
|
503
504
|
save({ featureFlags: newFlags });
|
|
505
|
+
} }), _jsx(SwitchRow, { label: "Coasts Dev Server", description: "Enable Coasts containerized runtime isolation for the dev server", id: "flag-coastsDevServer", testId: "switch-flag-coastsDevServer", checked: flags.coastsDevServer, onChange: (v) => {
|
|
506
|
+
const newFlags = { ...flags, coastsDevServer: v };
|
|
507
|
+
setFlags(newFlags);
|
|
508
|
+
save({ featureFlags: newFlags });
|
|
504
509
|
} })] }), _jsx(SectionHint, { children: "Experimental features that are still under development. Enable at your own risk \u2014 they may change or be removed in future versions. Debug mode adds verbose logging useful for troubleshooting." })] }), _jsxs("div", { id: "section-database", className: "grid scroll-mt-18 grid-cols-1 gap-x-5 rounded-lg lg:grid-cols-[1fr_280px]", children: [_jsxs(SettingsSection, { icon: Database, title: "Database", description: "Local storage information", testId: "database-settings-section", children: [_jsx(SettingsRow, { label: "Location", description: "Path to the local SQLite database", children: _jsx("span", { className: "text-muted-foreground max-w-50 truncate font-mono text-xs", "data-testid": "shep-home-path", children: shepHome }) }), _jsx(SettingsRow, { label: "Size", children: _jsx("span", { className: "text-muted-foreground text-xs", "data-testid": "db-file-size", children: dbFileSize }) })] }), _jsx(SectionHint, { links: [
|
|
505
510
|
{
|
|
506
511
|
label: 'Settings service',
|
package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-page-client.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/settings-page-client.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAM5D,QAAA,MAAM,IAAI;;;;;;;CAOiC,CAAC;AAE5C,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"settings-page-client.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/settings/settings-page-client.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAM5D,QAAA,MAAM,IAAI;;;;;;;CAOiC,CAAC;AAE5C,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAqBzB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAa7B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAsB5B,CAAC"}
|
package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-sidebar.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/layouts/app-sidebar/app-sidebar.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"app-sidebar.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/layouts/app-sidebar/app-sidebar.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAyBjC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAmDnC,eAAO,MAAM,OAAO,EAAE,KAIrB,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,KAIlC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAOvB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAInB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAiB3B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAQrB,CAAC"}
|
|
@@ -20,6 +20,8 @@ import { initializeSettings } from '../../../packages/core/src/infrastructure/se
|
|
|
20
20
|
import { initializeNotificationWatcher, getNotificationWatcher, } from '../../../packages/core/src/infrastructure/services/notifications/notification-watcher.service.js';
|
|
21
21
|
import { initializePrSyncWatcher, getPrSyncWatcher, } from '../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js';
|
|
22
22
|
import { getExistingConnection } from '../../../packages/core/src/infrastructure/persistence/sqlite/connection.js';
|
|
23
|
+
import { getFeatureFlags } from './lib/feature-flags.js';
|
|
24
|
+
import { startCoastsDevServer, shutdownCoasts } from './coasts-dev-server.js';
|
|
23
25
|
const DEFAULT_PORT = 3000;
|
|
24
26
|
async function isPortAvailable(port) {
|
|
25
27
|
return new Promise((resolve) => {
|
|
@@ -47,6 +49,9 @@ async function findAvailablePort(startPort) {
|
|
|
47
49
|
async function main() {
|
|
48
50
|
const basePort = process.env.PORT !== undefined ? parseInt(process.env.PORT, 10) : DEFAULT_PORT;
|
|
49
51
|
const port = await findAvailablePort(basePort);
|
|
52
|
+
// Track Coasts mode state for shutdown handler
|
|
53
|
+
let coastsService = null;
|
|
54
|
+
let coastsWorkDir = null;
|
|
50
55
|
// Step 1: Initialize DI container (database + migrations)
|
|
51
56
|
// Same as CLI bootstrap (src/presentation/cli/index.ts:52-58)
|
|
52
57
|
try {
|
|
@@ -72,7 +77,63 @@ async function main() {
|
|
|
72
77
|
catch (error) {
|
|
73
78
|
console.warn('[dev-server] DI initialization failed — features will be empty:', error);
|
|
74
79
|
}
|
|
75
|
-
// Step 2:
|
|
80
|
+
// Step 2: Check coastsDevServer feature flag — branch to Coasts mode or bare Next.js
|
|
81
|
+
const flags = getFeatureFlags();
|
|
82
|
+
if (flags.coastsDevServer) {
|
|
83
|
+
// --- Coasts mode: containerized runtime isolation ---
|
|
84
|
+
const workDir = process.cwd();
|
|
85
|
+
try {
|
|
86
|
+
const service = container.resolve('ICoastsService');
|
|
87
|
+
const instance = await startCoastsDevServer(service, workDir);
|
|
88
|
+
coastsService = service;
|
|
89
|
+
coastsWorkDir = workDir;
|
|
90
|
+
console.log(`[dev-server:coasts] Dev server running in Coasts mode at ${instance.url}`);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error('[dev-server:coasts] Failed to start Coasts dev server:', error);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
// Graceful shutdown for Coasts mode
|
|
97
|
+
let isShuttingDown = false;
|
|
98
|
+
const shutdown = async () => {
|
|
99
|
+
if (isShuttingDown)
|
|
100
|
+
return;
|
|
101
|
+
isShuttingDown = true;
|
|
102
|
+
console.log('\n[dev-server:coasts] Shutting down...');
|
|
103
|
+
const forceExit = setTimeout(() => process.exit(0), 2000);
|
|
104
|
+
try {
|
|
105
|
+
await shutdownCoasts(coastsService, coastsWorkDir);
|
|
106
|
+
try {
|
|
107
|
+
const deploymentService = container.resolve('IDeploymentService');
|
|
108
|
+
deploymentService.stopAll();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* not initialized */
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
getNotificationWatcher().stop();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
/* not initialized */
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
getPrSyncWatcher().stop();
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
/* not initialized */
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
clearTimeout(forceExit);
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
process.on('SIGINT', shutdown);
|
|
132
|
+
process.on('SIGTERM', shutdown);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// --- Bare mode: standard Next.js dev server (default, unchanged) ---
|
|
136
|
+
// Clean up lock file to allow multiple dev instances
|
|
76
137
|
const lockPath = path.join(import.meta.dirname, '.next', 'dev', 'lock');
|
|
77
138
|
try {
|
|
78
139
|
fs.rmSync(lockPath, { force: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-flags-context.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/feature-flags-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-flags-context.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/feature-flags-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAc7D,UAAU,yBAAyB;IACjC,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,yBAAyB,2CAElF;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,iBAAiB,CAEnD"}
|
|
@@ -12,6 +12,7 @@ export interface FeatureFlagsState {
|
|
|
12
12
|
githubImport: boolean;
|
|
13
13
|
adoptBranch: boolean;
|
|
14
14
|
reactFileManager: boolean;
|
|
15
|
+
coastsDevServer: boolean;
|
|
15
16
|
}
|
|
16
17
|
export declare function getFeatureFlags(): FeatureFlagsState;
|
|
17
18
|
/**
|
|
@@ -25,5 +26,6 @@ export declare const featureFlags: {
|
|
|
25
26
|
readonly githubImport: boolean;
|
|
26
27
|
readonly adoptBranch: boolean;
|
|
27
28
|
readonly reactFileManager: boolean;
|
|
29
|
+
readonly coastsDevServer: boolean;
|
|
28
30
|
};
|
|
29
31
|
//# sourceMappingURL=feature-flags.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/feature-flags.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/feature-flags.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,eAAe,IAAI,iBAAiB,CAgCnD;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;CAsBf,CAAC"}
|
|
@@ -21,6 +21,7 @@ export function getFeatureFlags() {
|
|
|
21
21
|
githubImport: flags.githubImport,
|
|
22
22
|
adoptBranch: flags.adoptBranch,
|
|
23
23
|
reactFileManager: flags.reactFileManager,
|
|
24
|
+
coastsDevServer: flags.coastsDevServer,
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
}
|
|
@@ -37,6 +38,7 @@ export function getFeatureFlags() {
|
|
|
37
38
|
githubImport: false,
|
|
38
39
|
adoptBranch: false,
|
|
39
40
|
reactFileManager: isEnabled(process.env.NEXT_PUBLIC_FLAG_REACT_FILE_MANAGER),
|
|
41
|
+
coastsDevServer: isEnabled(process.env.NEXT_PUBLIC_FLAG_COASTS_DEV_SERVER),
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
@@ -62,4 +64,7 @@ export const featureFlags = {
|
|
|
62
64
|
get reactFileManager() {
|
|
63
65
|
return getFeatureFlags().reactFileManager;
|
|
64
66
|
},
|
|
67
|
+
get coastsDevServer() {
|
|
68
|
+
return getFeatureFlags().coastsDevServer;
|
|
69
|
+
},
|
|
65
70
|
};
|