aimeat 1.16.2 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.env.example +6 -1
- package/dist/locales/en.json +166 -4
- package/dist/locales/fi.json +166 -4
- package/dist/public/components/Card.js +17 -3
- package/dist/public/components/Collapsible.js +39 -0
- package/dist/public/components/CopyButton.js +55 -24
- package/dist/public/components/DataTable.js +57 -0
- package/dist/public/components/EmptyState.js +28 -0
- package/dist/public/components/KeyValueRow.js +37 -0
- package/dist/public/components/Modal.js +22 -5
- package/dist/public/components/Pagination.js +70 -0
- package/dist/public/components/SearchBar.js +44 -0
- package/dist/public/components/StatusDot.js +29 -0
- package/dist/public/components/TagList.js +53 -0
- package/dist/public/components/ToggleSwitch.js +28 -0
- package/dist/public/components/index.js +41 -1
- package/dist/public/css/components/tags.css +24 -0
- package/dist/public/css/style-testbed.css +135 -0
- package/dist/public/css/theme.css +556 -34
- package/dist/public/css/views/admin-agent-integration.css +2 -33
- package/dist/public/css/views/admin.css +730 -686
- package/dist/public/css/views/agents-detail.css +402 -14
- package/dist/public/css/views/help.css +2 -1
- package/dist/public/css/views/hobbies.css +53 -33
- package/dist/public/css/views/marketplace.css +73 -60
- package/dist/public/css/views/openclaw.css +12 -6
- package/dist/public/css/views/portal-classic.css +34 -26
- package/dist/public/css/views/portal-dev.css +41 -32
- package/dist/public/css/views/portal.css +14 -18
- package/dist/public/css/views/profile.css +252 -164
- package/dist/public/css/views/public-knowledge-viewer.css +18 -6
- package/dist/public/css/views/scheduler.css +100 -0
- package/dist/public/js/format.js +41 -0
- package/dist/public/js/services/agent-tasks.js +14 -1
- package/dist/public/js/services/generator-spec-validate.js +5 -1
- package/dist/public/js/services/schedules.js +53 -0
- package/dist/public/js/style-testbed.js +170 -0
- package/dist/public/js/theme.js +114 -0
- package/dist/public/spa.html +74 -16
- package/dist/public/style-testbed.html +420 -0
- package/dist/public/views/admin/agent-integration-tab.js +23 -38
- package/dist/public/views/admin/agent-tasks-tab.js +14 -21
- package/dist/public/views/admin/chat-instances-tab.js +1 -1
- package/dist/public/views/admin/config-tab.js +7 -2
- package/dist/public/views/admin/cortex-tab.js +20 -14
- package/dist/public/views/admin/csm-tab.js +22 -18
- package/dist/public/views/admin/directory-tab.js +3 -3
- package/dist/public/views/admin/email-tab.js +23 -28
- package/dist/public/views/admin/federation-tab.js +15 -5
- package/dist/public/views/admin/generator-debug-tab.js +10 -8
- package/dist/public/views/admin/genesis-tab.js +4 -4
- package/dist/public/views/admin/ghii-tab.js +3 -3
- package/dist/public/views/admin/knowledge-tab.js +15 -5
- package/dist/public/views/admin/matching-tab.js +3 -3
- package/dist/public/views/admin/memory-tab.js +16 -20
- package/dist/public/views/admin/msm-tab.js +30 -17
- package/dist/public/views/admin/overview-tab.js +7 -7
- package/dist/public/views/admin/packages-tab.js +10 -9
- package/dist/public/views/admin/portal-tab.js +14 -4
- package/dist/public/views/admin/prompts-tab.js +5 -5
- package/dist/public/views/admin/push-tab.js +15 -4
- package/dist/public/views/admin/realtime-tab.js +3 -3
- package/dist/public/views/admin/services-tab.js +18 -27
- package/dist/public/views/admin/shared.js +48 -58
- package/dist/public/views/admin/sharing-groups-tab.js +5 -10
- package/dist/public/views/admin/stats-tab.js +3 -3
- package/dist/public/views/guides.js +9 -13
- package/dist/public/views/help.js +3 -24
- package/dist/public/views/hobbies.js +47 -41
- package/dist/public/views/marketplace.js +42 -34
- package/dist/public/views/openclaw.js +0 -1
- package/dist/public/views/portal-classic.js +4 -15
- package/dist/public/views/portal-dev.js +28 -30
- package/dist/public/views/portal.js +16 -21
- package/dist/public/views/portfolio.js +11 -12
- package/dist/public/views/profile/access-tab.js +250 -1
- package/dist/public/views/profile/agents/agent-card.js +75 -4
- package/dist/public/views/profile/agents/tab-activity.js +15 -13
- package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
- package/dist/public/views/profile/agents/tab-integration.js +37 -60
- package/dist/public/views/profile/agents/tab-messages.js +10 -1
- package/dist/public/views/profile/agents/tab-quality.js +25 -19
- package/dist/public/views/profile/agents/tab-schedules.js +110 -0
- package/dist/public/views/profile/agents-activity-subtab.js +4 -4
- package/dist/public/views/profile/agents-services-subtab.js +5 -4
- package/dist/public/views/profile/agents-tab.js +141 -37
- package/dist/public/views/profile/agents-tasks-subtab.js +221 -26
- package/dist/public/views/profile/calibrator-batch.js +5 -11
- package/dist/public/views/profile/calibrator-tab.js +4 -9
- package/dist/public/views/profile/chat-sessions-tab.js +9 -5
- package/dist/public/views/profile/email-tab.js +2 -2
- package/dist/public/views/profile/extensions-tab.js +27 -22
- package/dist/public/views/profile/federation-tab.js +4 -1
- package/dist/public/views/profile/foundry-detail.js +22 -23
- package/dist/public/views/profile/foundry-tab.js +12 -13
- package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
- package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
- package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
- package/dist/public/views/profile/generator-detail.js +26 -30
- package/dist/public/views/profile/generator-tab.js +5 -5
- package/dist/public/views/profile/knowledge-tab.js +12 -12
- package/dist/public/views/profile/landing-page.js +100 -149
- package/dist/public/views/profile/memory-tab.js +15 -11
- package/dist/public/views/profile/node-stats-tab.js +3 -3
- package/dist/public/views/profile/nodes-tab.js +10 -3
- package/dist/public/views/profile/notifications-tab.js +3 -3
- package/dist/public/views/profile/packages-tab.js +14 -14
- package/dist/public/views/profile/scheduler-tab.js +340 -0
- package/dist/public/views/profile/services-tab.js +1 -1
- package/dist/public/views/profile/shared.js +16 -12
- package/dist/public/views/profile/wallet-tab.js +27 -50
- package/dist/public/views/profile/work-tab.js +29 -31
- package/dist/public/views/profile.js +24 -0
- package/dist/public/views/public-knowledge-viewer.js +9 -18
- package/dist/src/auth/middleware.d.ts +3 -2
- package/dist/src/auth/middleware.d.ts.map +1 -1
- package/dist/src/auth/middleware.js +78 -3
- package/dist/src/auth/middleware.js.map +1 -1
- package/dist/src/cli/init-wizard.d.ts.map +1 -1
- package/dist/src/cli/init-wizard.js +13 -1
- package/dist/src/cli/init-wizard.js.map +1 -1
- package/dist/src/config.d.ts +6 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +12 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +708 -8
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/mcp/agent-schedules.d.ts +23 -0
- package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
- package/dist/src/mcp/agent-schedules.js +175 -0
- package/dist/src/mcp/agent-schedules.js.map +1 -0
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +6 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions.js +55 -0
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +12 -0
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +2 -0
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +2 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/models/agent-task-schemas.d.ts +6 -0
- package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-task-schemas.js +6 -0
- package/dist/src/models/agent-task-schemas.js.map +1 -1
- package/dist/src/models/schemas.d.ts +1 -0
- package/dist/src/models/schemas.d.ts.map +1 -1
- package/dist/src/models/schemas.js +4 -0
- package/dist/src/models/schemas.js.map +1 -1
- package/dist/src/routes/access-tokens.d.ts +17 -0
- package/dist/src/routes/access-tokens.d.ts.map +1 -0
- package/dist/src/routes/access-tokens.js +164 -0
- package/dist/src/routes/access-tokens.js.map +1 -0
- package/dist/src/routes/agent-tasks.d.ts +2 -0
- package/dist/src/routes/agent-tasks.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks.js +118 -23
- package/dist/src/routes/agent-tasks.js.map +1 -1
- package/dist/src/routes/agents.d.ts.map +1 -1
- package/dist/src/routes/agents.js +46 -0
- package/dist/src/routes/agents.js.map +1 -1
- package/dist/src/routes/ai.d.ts +6 -9
- package/dist/src/routes/ai.d.ts.map +1 -1
- package/dist/src/routes/ai.js +26 -175
- package/dist/src/routes/ai.js.map +1 -1
- package/dist/src/routes/apps.d.ts.map +1 -1
- package/dist/src/routes/apps.js +104 -34
- package/dist/src/routes/apps.js.map +1 -1
- package/dist/src/routes/auth.d.ts.map +1 -1
- package/dist/src/routes/auth.js +77 -4
- package/dist/src/routes/auth.js.map +1 -1
- package/dist/src/routes/cortex.d.ts +2 -1
- package/dist/src/routes/cortex.d.ts.map +1 -1
- package/dist/src/routes/cortex.js +13 -8
- package/dist/src/routes/cortex.js.map +1 -1
- package/dist/src/routes/extensions.d.ts.map +1 -1
- package/dist/src/routes/extensions.js +85 -51
- package/dist/src/routes/extensions.js.map +1 -1
- package/dist/src/routes/generator.d.ts.map +1 -1
- package/dist/src/routes/generator.js +109 -43
- package/dist/src/routes/generator.js.map +1 -1
- package/dist/src/routes/ghii.d.ts.map +1 -1
- package/dist/src/routes/ghii.js +34 -13
- package/dist/src/routes/ghii.js.map +1 -1
- package/dist/src/routes/libs.d.ts +15 -0
- package/dist/src/routes/libs.d.ts.map +1 -1
- package/dist/src/routes/libs.js +178 -55
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +1 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/schedules.d.ts +33 -0
- package/dist/src/routes/schedules.d.ts.map +1 -0
- package/dist/src/routes/schedules.js +380 -0
- package/dist/src/routes/schedules.js.map +1 -0
- package/dist/src/server-bootstrap/config-init.js +2 -2
- package/dist/src/server-bootstrap/config-init.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +7 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +2 -1
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/services/access-token.d.ts +28 -0
- package/dist/src/services/access-token.d.ts.map +1 -0
- package/dist/src/services/access-token.js +37 -0
- package/dist/src/services/access-token.js.map +1 -0
- package/dist/src/services/ai-completion.d.ts +83 -0
- package/dist/src/services/ai-completion.d.ts.map +1 -0
- package/dist/src/services/ai-completion.js +187 -0
- package/dist/src/services/ai-completion.js.map +1 -0
- package/dist/src/services/config-schema.d.ts.map +1 -1
- package/dist/src/services/config-schema.js +3 -0
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
- package/dist/src/services/generator-prompt-seeds.js +6 -3
- package/dist/src/services/generator-prompt-seeds.js.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.js +6 -2
- package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
- package/dist/src/services/generator-registration.d.ts +12 -4
- package/dist/src/services/generator-registration.d.ts.map +1 -1
- package/dist/src/services/generator-registration.js +71 -0
- package/dist/src/services/generator-registration.js.map +1 -1
- package/dist/src/services/generator-validate.d.ts +10 -0
- package/dist/src/services/generator-validate.d.ts.map +1 -1
- package/dist/src/services/generator-validate.js +180 -36
- package/dist/src/services/generator-validate.js.map +1 -1
- package/dist/src/services/owner-session.d.ts +43 -0
- package/dist/src/services/owner-session.d.ts.map +1 -0
- package/dist/src/services/owner-session.js +175 -0
- package/dist/src/services/owner-session.js.map +1 -0
- package/dist/src/services/schedule-constraints.d.ts +65 -0
- package/dist/src/services/schedule-constraints.d.ts.map +1 -0
- package/dist/src/services/schedule-constraints.js +106 -0
- package/dist/src/services/schedule-constraints.js.map +1 -0
- package/dist/src/services/scheduler.d.ts +34 -0
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +266 -22
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +19 -0
- package/dist/src/services/skill-bundle/generator.js.map +1 -1
- package/dist/src/storage/interface.d.ts +48 -4
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/interface.js.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +187 -9
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +131 -8
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.js +6 -4
- package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +79 -8
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
- package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/pat.repository.js +14 -0
- package/dist/src/storage/repositories/pat.repository.js.map +1 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.d.ts +51 -0
- package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.js +12 -0
- package/dist/src/storage/repositories/session.repository.js.map +1 -1
- package/dist/src/utils/env-config.d.ts.map +1 -1
- package/dist/src/utils/env-config.js +25 -1
- package/dist/src/utils/env-config.js.map +1 -1
- package/dist/src/utils/env-validator.d.ts.map +1 -1
- package/dist/src/utils/env-validator.js +4 -0
- package/dist/src/utils/env-validator.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +48 -0
|
@@ -14,6 +14,15 @@
|
|
|
14
14
|
* @version-history
|
|
15
15
|
* v1.0.0 — 2026-03-10 — Initial implementation with Cortex + Server extension management
|
|
16
16
|
* v1.1.0 — 2026-03-17 — Refactor: replace all inline style="" attributes with CSS classes
|
|
17
|
+
* v1.2.0 — 2026-06-02 — Component unification (#2): both install modals use the
|
|
18
|
+
* canonical <Modal> component (className="ext-modal-narrow" preserves width).
|
|
19
|
+
* v1.3.0 — 2026-06-02 — Component unification (#1): the five tier-2 clipboard
|
|
20
|
+
* buttons (copy prompt / script tag / API surface / instance ID / endpoint) now
|
|
21
|
+
* use the canonical <CopyButton> with onCopied toasts. The two "Create with AI"
|
|
22
|
+
* hero CTAs keep their labeled buttons + copyToClipboard (not copy buttons).
|
|
23
|
+
* v1.4.0 — 2026-06-02 — Component unification (#11): all six extension/instance
|
|
24
|
+
* status dots use the canonical <StatusDot> instead of bespoke .ext-status-dot
|
|
25
|
+
* (which had hardcoded #4ade80/#9ca3af — now tokenized via the component).
|
|
17
26
|
*/
|
|
18
27
|
import { h } from 'preact';
|
|
19
28
|
import { useState, useEffect } from 'preact/hooks';
|
|
@@ -22,7 +31,9 @@ const html = htm.bind(h);
|
|
|
22
31
|
import { t } from '/js/i18n.js';
|
|
23
32
|
import { escHtml, copyToClipboard } from '/js/utils.js';
|
|
24
33
|
import { Spinner } from './shared.js';
|
|
25
|
-
import { useConfirm } from '/components/Modal.js';
|
|
34
|
+
import { Modal, useConfirm } from '/components/Modal.js';
|
|
35
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
36
|
+
import { StatusDot } from '/components/StatusDot.js';
|
|
26
37
|
import * as cortexService from '/js/services/cortex.js';
|
|
27
38
|
import * as v8Ext from '/js/services/extensions.js';
|
|
28
39
|
import { getNodeUrl, getSession } from '/js/services/auth.js';
|
|
@@ -648,7 +659,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
648
659
|
<div class="ext-meta-row">
|
|
649
660
|
<span>${t('profile.extensions.detail.author')}: ${ext.author || '?'}</span>
|
|
650
661
|
${ext.license ? html`<span>${t('profile.extensions.detail.license')}: ${ext.license}</span>` : null}
|
|
651
|
-
<span
|
|
662
|
+
<span><${StatusDot} status=${ext.status} /> ${t('profile.extensions.status.' + ext.status)}</span>
|
|
652
663
|
<span>${t('profile.extensions.detail.tags')}: ${(ext.tags || []).join(', ')}</span>
|
|
653
664
|
</div>
|
|
654
665
|
</div>
|
|
@@ -662,7 +673,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
662
673
|
const content = p._content || p.content || '';
|
|
663
674
|
return html`
|
|
664
675
|
<div class="ext-detail-section">
|
|
665
|
-
<div class="ext-detail-section-title">${'\u{1F4AC}'} Prompt: ${p.name}
|
|
676
|
+
<div class="ext-detail-section-title">${'\u{1F4AC}'} Prompt: ${p.name} <${CopyButton} text=${content} label=${t('profile.extensions.detail.copyPrompt')} className="btn-primary btn-sm" onCopied=${() => showToast(t('profile.extensions.detail.copied'))} /></div>
|
|
666
677
|
<div class="ext-detail-code">${content.substring(0, 500)}${content.length > 500 ? '...' : ''}</div>
|
|
667
678
|
</div>`;
|
|
668
679
|
})}
|
|
@@ -674,10 +685,10 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
674
685
|
<div class="ext-detail-section">
|
|
675
686
|
<div class="ext-detail-section-title">${'\u{1F4E6}'} Library: ${lib.filename}</div>
|
|
676
687
|
<div class="ext-lib-meta">${t('profile.extensions.detail.exports')}: ${(lib.exports || []).join(', ')}</div>
|
|
677
|
-
<div class="ext-lib-label">${t('profile.extensions.detail.scriptTag')}
|
|
688
|
+
<div class="ext-lib-label">${t('profile.extensions.detail.scriptTag')} <${CopyButton} text=${scriptTag} label=${t('profile.extensions.detail.copyUrl')} className="btn-primary btn-sm" onCopied=${() => showToast(t('profile.extensions.detail.copied'))} /></div>
|
|
678
689
|
<div class="ext-detail-code">${scriptTag}</div>
|
|
679
690
|
${lib.api_surface ? html`<div>
|
|
680
|
-
<div class="ext-lib-label-spaced">${t('profile.extensions.detail.apiSurface')}
|
|
691
|
+
<div class="ext-lib-label-spaced">${t('profile.extensions.detail.apiSurface')} <${CopyButton} text=${lib.api_surface} label=${t('profile.extensions.detail.copyApi')} className="btn-primary btn-sm" onCopied=${() => showToast(t('profile.extensions.detail.copied'))} /></div>
|
|
681
692
|
<div class="ext-detail-code">${lib.api_surface}</div>
|
|
682
693
|
</div>` : null}
|
|
683
694
|
</div>`;
|
|
@@ -726,7 +737,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
726
737
|
<div class="ext-description">${ext.description || ''}</div>
|
|
727
738
|
<div class="ext-meta-row-sm">
|
|
728
739
|
<span>${t('profile.v8ext.author')}: ${ext.author || '?'}</span>
|
|
729
|
-
<span
|
|
740
|
+
<span><${StatusDot} status=${ext.status} /> ${isActive ? t('profile.v8ext.statusActive') : t('profile.v8ext.statusInactive')}</span>
|
|
730
741
|
<span>${t('profile.v8ext.actions')}: ${actions.length}</span>
|
|
731
742
|
</div>
|
|
732
743
|
</div>
|
|
@@ -829,9 +840,9 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
829
840
|
: srvInstances.map(inst => html`
|
|
830
841
|
<div class="ext-instance-row">
|
|
831
842
|
<span class="ext-instance-name">${inst.id}</span>
|
|
832
|
-
|
|
843
|
+
<${StatusDot} status=${inst.status} />
|
|
833
844
|
<span class="ext-instance-status">${inst.status}</span>
|
|
834
|
-
|
|
845
|
+
<${CopyButton} text=${inst.id} label=${t('profile.v8ext.copyId')} className="btn-outline btn-sm" onCopied=${() => showToast(t('profile.v8ext.instanceIdCopied'))} />
|
|
835
846
|
<button class="btn-danger-solid btn-sm" onClick=${() => handleDeleteInstance(ext.name, inst.id)}>${t('profile.v8ext.deleteInstance')}</button>
|
|
836
847
|
</div>`)}
|
|
837
848
|
${isActive ? html`
|
|
@@ -845,7 +856,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
845
856
|
<div class="ext-endpoint-box">
|
|
846
857
|
POST ${NODE_URL}/v1/ext/${ext.name}/{actionId}
|
|
847
858
|
</div>
|
|
848
|
-
|
|
859
|
+
<${CopyButton} text=${NODE_URL + '/v1/ext/' + ext.name + '/'} label=${t('profile.v8ext.copyEndpoint')} className="btn-primary btn-sm ext-btn-copy-spaced" onCopied=${() => showToast(t('profile.v8ext.copied'))} />
|
|
849
860
|
</div>`}
|
|
850
861
|
|
|
851
862
|
<div class="ext-actions-bar">
|
|
@@ -893,7 +904,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
893
904
|
${(ext.actions || []).map(a => html`<span class="ext-comp-tag ext-comp-tag-action">${a.id}</span>`)}
|
|
894
905
|
</div>
|
|
895
906
|
<div class="ext-card-footer">
|
|
896
|
-
<span class="ext-status"
|
|
907
|
+
<span class="ext-status"><${StatusDot} status=${ext.status} /> ${isActive ? t('profile.v8ext.statusActive') : t('profile.v8ext.statusInactive')}</span>
|
|
897
908
|
<span class="ext-card-actions">
|
|
898
909
|
${isActive
|
|
899
910
|
? html`<button onClick=${(e) => { e.stopPropagation(); handleSrvDeactivate(ext.name); }}>${t('profile.v8ext.deactivate')}</button>`
|
|
@@ -935,7 +946,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
935
946
|
${types.map(ct => html`<span class="ext-comp-tag ${COMP_TAG_CLASSES[ct] || ''}">${t('profile.extensions.components.' + ct) || ct}</span>`)}
|
|
936
947
|
</div>
|
|
937
948
|
<div class="ext-card-footer">
|
|
938
|
-
<span class="ext-status"
|
|
949
|
+
<span class="ext-status"><${StatusDot} status=${ext.status} /> ${t('profile.extensions.status.' + ext.status)}</span>
|
|
939
950
|
</div>
|
|
940
951
|
</div>`;
|
|
941
952
|
})}
|
|
@@ -961,7 +972,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
961
972
|
${types.map(ct => html`<span class="ext-comp-tag ${COMP_TAG_CLASSES[ct] || ''}">${t('profile.extensions.components.' + ct) || ct}</span>`)}
|
|
962
973
|
</div>
|
|
963
974
|
<div class="ext-card-footer">
|
|
964
|
-
<span class="ext-status"
|
|
975
|
+
<span class="ext-status"><${StatusDot} status=${ext.status} /> ${t('profile.extensions.status.' + ext.status)}</span>
|
|
965
976
|
<span class="ext-card-actions">
|
|
966
977
|
${isActive
|
|
967
978
|
? html`<button onClick=${(e) => { e.stopPropagation(); deactivateExt(ext.name); }}>${t('profile.extensions.deactivate')}</button>`
|
|
@@ -995,9 +1006,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
995
1006
|
</div>` : null}
|
|
996
1007
|
|
|
997
1008
|
${showInstall ? html`
|
|
998
|
-
|
|
999
|
-
<div class="modal ext-modal-narrow">
|
|
1000
|
-
<h3>${t('profile.extensions.installModal.title')}</h3>
|
|
1009
|
+
<${Modal} open=${true} onClose=${() => setShowInstall(false)} title=${t('profile.extensions.installModal.title')} className="ext-modal-narrow">
|
|
1001
1010
|
<form onSubmit=${handleInstall}>
|
|
1002
1011
|
<div class="ext-modal-section">
|
|
1003
1012
|
<label>${t('profile.extensions.installModal.manifestLabel')}</label>
|
|
@@ -1033,13 +1042,10 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
1033
1042
|
<button type="submit" class="btn-primary">${t('profile.extensions.installModal.installBtn')}</button>
|
|
1034
1043
|
</div>
|
|
1035
1044
|
</form>
|
|
1036
|
-
|
|
1037
|
-
</div>` : null}
|
|
1045
|
+
<//>` : null}
|
|
1038
1046
|
|
|
1039
1047
|
${showSrvInstall ? html`
|
|
1040
|
-
|
|
1041
|
-
<div class="modal ext-modal-narrow">
|
|
1042
|
-
<h3>Install Server Extension</h3>
|
|
1048
|
+
<${Modal} open=${true} onClose=${() => setShowSrvInstall(false)} title="Install Server Extension" className="ext-modal-narrow">
|
|
1043
1049
|
<div class="ext-modal-section">
|
|
1044
1050
|
<label>YAML Manifest</label>
|
|
1045
1051
|
<textarea rows="12" class="ext-modal-textarea" placeholder="metadata:\n name: my-extension\n version: 1.0.0\n description: ...\n\nactions:\n - id: my-action\n ..." value=${srvManifestText} onInput=${(e) => onSrvManifestChange(e.target.value)}></textarea>
|
|
@@ -1057,8 +1063,7 @@ export default function ExtensionsTab({ session, showToast }) {
|
|
|
1057
1063
|
<button class="btn-outline" onClick=${() => setShowSrvInstall(false)}>Cancel</button>
|
|
1058
1064
|
<button class="btn-primary" onClick=${handleSrvInstall}>Install</button>
|
|
1059
1065
|
</div>
|
|
1060
|
-
|
|
1061
|
-
</div>` : null}
|
|
1066
|
+
<//>` : null}
|
|
1062
1067
|
|
|
1063
1068
|
<${ConfirmUI} />
|
|
1064
1069
|
</div>`;
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @version-history
|
|
5
5
|
* v1.0.0 — 2026-03-16 — Initial federation tab
|
|
6
6
|
* v1.1.0 — 2026-03-17 — Replace inline styles with CSS classes
|
|
7
|
+
* v1.2.0 — 2026-06-02 — Component unification (#11): peer online/offline dot
|
|
8
|
+
* uses canonical <StatusDot> (alive/dead) instead of bespoke .peer-dot.
|
|
7
9
|
*/
|
|
8
10
|
import { h } from 'preact';
|
|
9
11
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
|
@@ -12,6 +14,7 @@ const html = htm.bind(h);
|
|
|
12
14
|
import { t } from '/js/i18n.js';
|
|
13
15
|
import { escHtml } from '/js/utils.js';
|
|
14
16
|
import { Spinner } from './shared.js';
|
|
17
|
+
import { StatusDot } from '/components/StatusDot.js';
|
|
15
18
|
import { listPeers } from '/js/services/federation.js';
|
|
16
19
|
|
|
17
20
|
export default function FederationTab({ session, showToast }) {
|
|
@@ -53,7 +56,7 @@ export default function FederationTab({ session, showToast }) {
|
|
|
53
56
|
<div class="card-subtitle">${escHtml(p.url || '')}</div>
|
|
54
57
|
</div>
|
|
55
58
|
<div class="peer-status">
|
|
56
|
-
|
|
59
|
+
<${StatusDot} status=${alive ? 'alive' : 'dead'} />
|
|
57
60
|
<span class="fed-status-text ${alive ? 'online' : 'offline'}">${alive ? t('profile.federation.online') : t('profile.federation.offline')}</span>
|
|
58
61
|
</div>
|
|
59
62
|
</div>
|
|
@@ -28,6 +28,8 @@ import htm from 'htm';
|
|
|
28
28
|
const html = htm.bind(h);
|
|
29
29
|
import { t } from '/js/i18n.js';
|
|
30
30
|
import { apiPost } from '/js/api.js';
|
|
31
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
32
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
31
33
|
import {
|
|
32
34
|
saveComponent, registerComponent, reregisterComponent, writeProjectLog, writeDebugArtifact,
|
|
33
35
|
getNextPass, MULTI_PASS_TYPES, saveSkeleton, saveUnit, saveTestCode,
|
|
@@ -637,7 +639,7 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
637
639
|
interviewSpec,
|
|
638
640
|
);
|
|
639
641
|
try {
|
|
640
|
-
await
|
|
642
|
+
await copyToClipboard(fresh);
|
|
641
643
|
const updated = addHistory(component, 'prompt_copied');
|
|
642
644
|
await saveComponent(projectId, { ...updated, status: 'waiting_user', prompt: fresh });
|
|
643
645
|
showToast?.(t('profile.foundry.promptCopied'));
|
|
@@ -719,7 +721,7 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
719
721
|
async function handleCopyTestPrompt() {
|
|
720
722
|
if (!currentTestPrompt) return;
|
|
721
723
|
try {
|
|
722
|
-
await
|
|
724
|
+
await copyToClipboard(currentTestPrompt);
|
|
723
725
|
showToast?.(t('profile.foundry.test_prompt_copied'));
|
|
724
726
|
await writeProjectLog(projectId, 'test_prompt_copied', { meta: { component: component.label, by: 'user' } });
|
|
725
727
|
} catch { /* clipboard fallback */ }
|
|
@@ -817,14 +819,6 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
817
819
|
// Multi-pass: current pass and submit handler
|
|
818
820
|
const currentPass = isMultiPass && component.passes ? getNextPass(component.passes) : null;
|
|
819
821
|
|
|
820
|
-
async function handlePassCopy() {
|
|
821
|
-
if (!passPrompt) return;
|
|
822
|
-
try {
|
|
823
|
-
await navigator.clipboard.writeText(passPrompt);
|
|
824
|
-
showToast?.(t('profile.foundry.promptCopied'));
|
|
825
|
-
} catch { /* clipboard fallback */ }
|
|
826
|
-
}
|
|
827
|
-
|
|
828
822
|
async function handlePassRunWithAi() {
|
|
829
823
|
if (!currentPass || !passPrompt) return;
|
|
830
824
|
setAiRunning(true);
|
|
@@ -899,9 +893,11 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
899
893
|
<label>${t('profile.foundry.passProgress')} — ${t('profile.foundry.' + (({'test':'passTest','skeleton':'passSkeleton','unit':'passUnit','assembly':'passAssembly','reflection':'passReflection'})[currentPass.type] || currentPass.type))}${currentPass.unitLabel ? ': ' + currentPass.unitLabel : ''}</label>
|
|
900
894
|
<pre class="fnd-prompt-box">${passPrompt}</pre>
|
|
901
895
|
<div class="flex-row-wrap">
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
896
|
+
<${CopyButton}
|
|
897
|
+
text=${passPrompt}
|
|
898
|
+
label=${t('profile.foundry.copyPrompt')}
|
|
899
|
+
className="btn-outline btn-sm"
|
|
900
|
+
onCopied=${() => showToast?.(t('profile.foundry.promptCopied'))} />
|
|
905
901
|
${orSettings?.hasApiKey && html`
|
|
906
902
|
<button class="btn-outline btn-sm fnd-or-run-btn ${aiRunning ? 'fnd-or-running' : ''}"
|
|
907
903
|
onClick=${handlePassRunWithAi}
|
|
@@ -982,10 +978,11 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
982
978
|
/>
|
|
983
979
|
<div class="fnd-actions">
|
|
984
980
|
${explainPrompt && html`
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
Explain
|
|
988
|
-
|
|
981
|
+
<${CopyButton}
|
|
982
|
+
text=${explainPrompt}
|
|
983
|
+
label="Explain"
|
|
984
|
+
className="btn-ghost btn-sm"
|
|
985
|
+
title="Copy explain prompt — ask AI to describe what it built before validating" />
|
|
989
986
|
`}
|
|
990
987
|
${workflowStep === 'validate' && html`<${StepArrow} />`}
|
|
991
988
|
<button class="btn-primary btn-sm" onClick=${handleValidate} disabled=${!result.trim()}
|
|
@@ -1017,17 +1014,19 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
1017
1014
|
</ul>
|
|
1018
1015
|
${reflectionPrompt && html`
|
|
1019
1016
|
<div class="flex-row" style="margin-bottom: 0.5rem">
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1017
|
+
<${CopyButton}
|
|
1018
|
+
text=${reflectionPrompt}
|
|
1019
|
+
label="1. Copy Reflection (diagnose first)"
|
|
1020
|
+
className="btn-outline btn-sm" />
|
|
1023
1021
|
</div>
|
|
1024
1022
|
`}
|
|
1025
1023
|
${fixPrompt && html`
|
|
1026
1024
|
<div class="flex-row">
|
|
1027
1025
|
${workflowStep === 'fix' && html`<${StepArrow} />`}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1026
|
+
<${CopyButton}
|
|
1027
|
+
text=${fixPrompt}
|
|
1028
|
+
label=${'2. ' + t('profile.foundry.copyFixPrompt')}
|
|
1029
|
+
className="btn-primary btn-sm" />
|
|
1031
1030
|
</div>
|
|
1032
1031
|
`}
|
|
1033
1032
|
</div>
|
|
@@ -52,6 +52,8 @@ import htm from 'htm';
|
|
|
52
52
|
const html = htm.bind(h);
|
|
53
53
|
import { t, getLocale } from '/js/i18n.js';
|
|
54
54
|
import { apiGet } from '/js/api.js';
|
|
55
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
56
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
55
57
|
import {
|
|
56
58
|
listProjects, createProject, updateProject, archiveProject,
|
|
57
59
|
loadAllComponents, saveComponent,
|
|
@@ -168,7 +170,7 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
168
170
|
}
|
|
169
171
|
} catch { /* proceed without catalog */ }
|
|
170
172
|
const prompt = buildBlueprintPrompt(description, interviewParsed, cortexLibs);
|
|
171
|
-
|
|
173
|
+
await copyToClipboard(prompt);
|
|
172
174
|
showToast?.(t('profile.foundry.blueprintPromptCopied'));
|
|
173
175
|
}
|
|
174
176
|
|
|
@@ -200,12 +202,6 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
200
202
|
}
|
|
201
203
|
|
|
202
204
|
if (phase === 'interview') {
|
|
203
|
-
function handleCopyInterviewPrompt() {
|
|
204
|
-
const prompt = buildInterviewPrompt(description, getLocale());
|
|
205
|
-
navigator.clipboard.writeText(prompt).catch(() => {});
|
|
206
|
-
showToast?.(t('profile.foundry.interviewPromptCopied'));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
205
|
async function handleRunInterviewAi() {
|
|
210
206
|
if (!project) return;
|
|
211
207
|
setAiRunning('interview');
|
|
@@ -289,9 +285,11 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
289
285
|
<div class="fnd-section">
|
|
290
286
|
<label>${t('profile.foundry.interviewPrompt')}</label>
|
|
291
287
|
<div class="fnd-or-btn-row">
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
288
|
+
<${CopyButton}
|
|
289
|
+
text=${buildInterviewPrompt(description, getLocale())}
|
|
290
|
+
label=${t('profile.foundry.copyPrompt')}
|
|
291
|
+
className="btn-primary"
|
|
292
|
+
onCopied=${() => showToast?.(t('profile.foundry.interviewPromptCopied'))} />
|
|
295
293
|
${orSettings?.hasApiKey && html`
|
|
296
294
|
<button class="btn-outline fnd-or-run-btn ${aiRunning === 'interview' ? 'fnd-or-running' : ''}"
|
|
297
295
|
onClick=${handleRunInterviewAi}
|
|
@@ -430,9 +428,10 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
430
428
|
<label>${t('profile.foundry.errors')}</label>
|
|
431
429
|
<ul>${blueprintErrors.map(e => html`<li>${e}</li>`)}</ul>
|
|
432
430
|
${fixPrompt && html`
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
431
|
+
<${CopyButton}
|
|
432
|
+
text=${fixPrompt}
|
|
433
|
+
label=${t('profile.foundry.copyFixPrompt')}
|
|
434
|
+
className="btn-primary btn-sm" />
|
|
436
435
|
`}
|
|
437
436
|
</div>
|
|
438
437
|
`}
|
|
@@ -22,6 +22,8 @@ import htm from 'htm';
|
|
|
22
22
|
const html = htm.bind(h);
|
|
23
23
|
import { t } from '/js/i18n.js';
|
|
24
24
|
import { apiGet, apiDelete } from '/js/api.js';
|
|
25
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
26
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
25
27
|
|
|
26
28
|
export function DebugPanel({ projectId }) {
|
|
27
29
|
const [files, setFiles] = useState([]);
|
|
@@ -105,7 +107,7 @@ export function DebugPanel({ projectId }) {
|
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
await
|
|
110
|
+
await copyToClipboard(parts.join('\n'));
|
|
109
111
|
// Brief visual feedback
|
|
110
112
|
setCopying('done');
|
|
111
113
|
setTimeout(() => setCopying(false), 2000);
|
|
@@ -175,12 +177,7 @@ export function DebugPanel({ projectId }) {
|
|
|
175
177
|
${selectedFile ? html`
|
|
176
178
|
<div class="pf-gen-debug-content-header">
|
|
177
179
|
<span class="pf-gen-debug-path">${selectedFile}</span>
|
|
178
|
-
|
|
179
|
-
if (fileContent) {
|
|
180
|
-
navigator.clipboard.writeText(fileContent);
|
|
181
|
-
// TODO: visual feedback
|
|
182
|
-
}
|
|
183
|
-
}}>Copy File</button>
|
|
180
|
+
<${CopyButton} text=${fileContent || ''} label="Copy File" copiedLabel="Copied!" className="btn-outline btn-sm pf-gen-debug-copy-file" />
|
|
184
181
|
</div>
|
|
185
182
|
${loadingFile
|
|
186
183
|
? html`<p>${t('profile.loading')}</p>`
|
|
@@ -78,7 +78,10 @@ export function useDashboardCore(projectId, onBack, showToast) {
|
|
|
78
78
|
// Blueprint exists but no component records yet — initialize them
|
|
79
79
|
const initialized = [];
|
|
80
80
|
for (const c of p.blueprint.components) {
|
|
81
|
-
|
|
81
|
+
// Preserve subtype (data|component|app-domain) on cortex records — the spec/code prompt
|
|
82
|
+
// selectors and the spec validators dispatch on it. Dropping it here was the single hop
|
|
83
|
+
// where subtype was lost end-to-end, forcing every downstream picker onto a wrong guess.
|
|
84
|
+
const comp = { id: c.id, type: c.type, label: c.label, ...(c.subtype ? { subtype: c.subtype } : {}), status: 'not_started', prompt: null, result: null, validationErrors: [], registeredAs: null, history: [], _version: 0 };
|
|
82
85
|
await saveComponent(projectId, comp);
|
|
83
86
|
initialized.push(comp);
|
|
84
87
|
}
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { useState, useEffect } from 'preact/hooks';
|
|
32
32
|
import { t } from '/js/i18n.js';
|
|
33
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
33
34
|
import {
|
|
34
35
|
loadAllComponents, saveComponent, registerComponent, writeProjectLog,
|
|
35
36
|
savePendingEdit, clearPendingEdit,
|
|
@@ -80,7 +81,7 @@ export function useEditMode(core, autopilotState, projectId, orSettings, session
|
|
|
80
81
|
|
|
81
82
|
function handleCopyImpactPrompt() {
|
|
82
83
|
const prompt = buildImpactPrompt(changeRequest, core.project?.blueprint);
|
|
83
|
-
|
|
84
|
+
copyToClipboard(prompt).catch(() => {});
|
|
84
85
|
showToast?.(t('profile.generator.impactPromptCopied'));
|
|
85
86
|
setEditMode('impact');
|
|
86
87
|
}
|
|
@@ -225,7 +226,7 @@ export function useEditMode(core, autopilotState, projectId, orSettings, session
|
|
|
225
226
|
suggestedChange || changeRequest,
|
|
226
227
|
upstream || null,
|
|
227
228
|
);
|
|
228
|
-
|
|
229
|
+
copyToClipboard(prompt).catch(() => {});
|
|
229
230
|
showToast?.(t('profile.generator.editPromptCopied').replace('{name}', comp.label));
|
|
230
231
|
}
|
|
231
232
|
|
|
@@ -26,6 +26,8 @@ import htm from 'htm';
|
|
|
26
26
|
const html = htm.bind(h);
|
|
27
27
|
import { t } from '/js/i18n.js';
|
|
28
28
|
import { apiPost } from '/js/api.js';
|
|
29
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
30
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
29
31
|
import {
|
|
30
32
|
saveComponent, saveSpec, registerComponent, reregisterComponent, writeProjectLog, writeDebugArtifact,
|
|
31
33
|
} from '/js/services/generator.js';
|
|
@@ -431,7 +433,7 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
431
433
|
async function handleCopyPrompt() {
|
|
432
434
|
const fresh = await loadPromptFromBackend(projectId, component.id, 'code');
|
|
433
435
|
try {
|
|
434
|
-
await
|
|
436
|
+
await copyToClipboard(fresh);
|
|
435
437
|
const updated = addHistory(component, 'prompt_copied');
|
|
436
438
|
await saveComponent(projectId, { ...updated, status: 'waiting_user', prompt: fresh });
|
|
437
439
|
showToast?.(t('profile.generator.promptCopied'));
|
|
@@ -498,6 +500,14 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
498
500
|
? buildExplainPrompt(component.type, result, bpComp)
|
|
499
501
|
: null;
|
|
500
502
|
|
|
503
|
+
// Spec fix prompt — derived from current spec validation errors + spec result (shared by Copy and Fix-with-AI buttons)
|
|
504
|
+
const specFixPrompt = specValidation && !specValidation.valid
|
|
505
|
+
? 'Fix the following spec JSON. It has validation errors.\n\n'
|
|
506
|
+
+ '## Errors\n' + specValidation.errors.map((e, i) => (i + 1) + '. ' + e).join('\n')
|
|
507
|
+
+ '\n\n## Current Spec\n```json\n' + specResult + '\n```\n\n'
|
|
508
|
+
+ '## Rules\n- Fix ONLY the listed errors\n- Do NOT remove existing actions\n- Return the COMPLETE fixed JSON'
|
|
509
|
+
: null;
|
|
510
|
+
|
|
501
511
|
// Test prompt for testable component types
|
|
502
512
|
const testableTypes = ['extension', 'cortex', 'app'];
|
|
503
513
|
const isTestable = testableTypes.includes(component.type) && component.registeredAs;
|
|
@@ -518,7 +528,7 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
518
528
|
async function handleCopyTestPrompt() {
|
|
519
529
|
if (!currentTestPrompt) return;
|
|
520
530
|
try {
|
|
521
|
-
await
|
|
531
|
+
await copyToClipboard(currentTestPrompt);
|
|
522
532
|
showToast?.(t('profile.generator.test_prompt_copied'));
|
|
523
533
|
await writeProjectLog(projectId, 'test_prompt_copied', { meta: { component: component.label, by: 'user' } });
|
|
524
534
|
} catch { /* clipboard fallback */ }
|
|
@@ -633,9 +643,8 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
633
643
|
<label>SPEC PROMPT</label>
|
|
634
644
|
<pre class="pf-gen-prompt-box" style="max-height:200px;overflow:auto;font-size:11px">${specPrompt || 'Loading spec prompt...'}</pre>
|
|
635
645
|
<div class="flex-row-wrap">
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
</button>
|
|
646
|
+
<${CopyButton} text=${specPrompt} label="Copy Spec Prompt" className="btn-outline btn-sm"
|
|
647
|
+
onCopied=${() => showToast?.('Spec prompt copied')} />
|
|
639
648
|
${orSettings?.hasApiKey && html`
|
|
640
649
|
<button class="btn-outline btn-sm pf-gen-or-run-btn ${specAiRunning ? 'pf-gen-or-running' : ''}"
|
|
641
650
|
onClick=${async () => {
|
|
@@ -676,7 +685,11 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
676
685
|
else if (component.subtype === 'data') sv = validateDataApiSpec(parsed);
|
|
677
686
|
else if (component.subtype === 'component') sv = validateComponentSpec(parsed);
|
|
678
687
|
else if (component.subtype === 'app-domain') sv = validateAppDomainSpec(parsed);
|
|
679
|
-
|
|
688
|
+
// FAIL LOUD: a cortex must declare its subtype. A silent fallback to a default
|
|
689
|
+
// validator (previously validateDataApiSpec) masked the real bug — a missing subtype —
|
|
690
|
+
// as a confusing "Missing wrapsExtension" error on a component cortex. Name the real cause.
|
|
691
|
+
else if (component.type === 'cortex') sv = { valid: false, errors: ['Cortex component "' + component.id + '" has no subtype (expected data | component | app-domain) — this is an upstream blueprint/init bug; fix the subtype, do not guess a validator'] };
|
|
692
|
+
else sv = { valid: false, errors: ['Cannot select a spec validator for component "' + component.id + '" (type=' + component.type + ', subtype=' + component.subtype + ')'] };
|
|
680
693
|
// Also check blueprint action IDs
|
|
681
694
|
const bp = project?.blueprint;
|
|
682
695
|
if (bp && component.type === 'extension') {
|
|
@@ -730,23 +743,12 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
730
743
|
<strong>Spec Validation Errors</strong>
|
|
731
744
|
<ul>${specValidation.errors.map(e => html`<li>${e}</li>`)}</ul>
|
|
732
745
|
<div class="flex-row-wrap" style="margin-top:8px">
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
+ '## Errors\n' + specValidation.errors.map((e, i) => (i + 1) + '. ' + e).join('\n')
|
|
736
|
-
+ '\n\n## Current Spec\n```json\n' + specResult + '\n```\n\n'
|
|
737
|
-
+ '## Rules\n- Fix ONLY the listed errors\n- Do NOT remove existing actions\n- Return the COMPLETE fixed JSON';
|
|
738
|
-
navigator.clipboard.writeText(fixPrompt);
|
|
739
|
-
showToast?.('Fix prompt copied');
|
|
740
|
-
}}>
|
|
741
|
-
Copy Fix Prompt
|
|
742
|
-
</button>
|
|
746
|
+
<${CopyButton} text=${specFixPrompt} label="Copy Fix Prompt" className="btn-outline btn-sm"
|
|
747
|
+
onCopied=${() => showToast?.('Fix prompt copied')} />
|
|
743
748
|
${orSettings?.hasApiKey && html`
|
|
744
749
|
<button class="btn-outline btn-sm pf-gen-or-run-btn ${specAiRunning ? 'pf-gen-or-running' : ''}"
|
|
745
750
|
onClick=${async () => {
|
|
746
|
-
const fixPrompt =
|
|
747
|
-
+ '## Errors\n' + specValidation.errors.map((e, i) => (i + 1) + '. ' + e).join('\n')
|
|
748
|
-
+ '\n\n## Current Spec\n```json\n' + specResult + '\n```\n\n'
|
|
749
|
-
+ '## Rules\n- Fix ONLY the listed errors\n- Do NOT remove existing actions\n- Return the COMPLETE fixed JSON';
|
|
751
|
+
const fixPrompt = specFixPrompt;
|
|
750
752
|
setSpecAiRunning(true);
|
|
751
753
|
try {
|
|
752
754
|
const fixed = await runWithAi(projectId, fixPrompt);
|
|
@@ -819,10 +821,8 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
819
821
|
/>
|
|
820
822
|
<div class="pf-gen-actions">
|
|
821
823
|
${explainPrompt && html`
|
|
822
|
-
|
|
823
|
-
title="Copy explain prompt — ask AI to describe what it built before validating"
|
|
824
|
-
Explain
|
|
825
|
-
</button>
|
|
824
|
+
<${CopyButton} text=${explainPrompt} label="Explain" className="btn-ghost btn-sm"
|
|
825
|
+
title="Copy explain prompt — ask AI to describe what it built before validating" />
|
|
826
826
|
`}
|
|
827
827
|
${workflowStep === 'validate' && html`<${StepArrow} />`}
|
|
828
828
|
<button class="btn-primary btn-sm" onClick=${handleValidate} disabled=${!result.trim()}
|
|
@@ -854,17 +854,13 @@ export function ComponentDetail({ component, project, components, projectId, int
|
|
|
854
854
|
</ul>
|
|
855
855
|
${reflectionPrompt && html`
|
|
856
856
|
<div class="flex-row" style="margin-bottom: 0.5rem">
|
|
857
|
-
|
|
858
|
-
1. Copy Reflection (diagnose first)
|
|
859
|
-
</button>
|
|
857
|
+
<${CopyButton} text=${reflectionPrompt} label="1. Copy Reflection (diagnose first)" className="btn-outline btn-sm" />
|
|
860
858
|
</div>
|
|
861
859
|
`}
|
|
862
860
|
${fixPrompt && html`
|
|
863
861
|
<div class="flex-row">
|
|
864
862
|
${workflowStep === 'fix' && html`<${StepArrow} />`}
|
|
865
|
-
|
|
866
|
-
2. ${t('profile.generator.copyFixPrompt')}
|
|
867
|
-
</button>
|
|
863
|
+
<${CopyButton} text=${fixPrompt} label=${'2. ' + t('profile.generator.copyFixPrompt')} className="btn-primary btn-sm" />
|
|
868
864
|
</div>
|
|
869
865
|
`}
|
|
870
866
|
</div>
|
|
@@ -52,6 +52,8 @@ import htm from 'htm';
|
|
|
52
52
|
const html = htm.bind(h);
|
|
53
53
|
import { t, getLocale } from '/js/i18n.js';
|
|
54
54
|
import { apiGet } from '/js/api.js';
|
|
55
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
56
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
55
57
|
import {
|
|
56
58
|
listProjects, createProject, updateProject, archiveProject,
|
|
57
59
|
loadAllComponents, saveComponent,
|
|
@@ -168,7 +170,7 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
168
170
|
async function handleCopyBlueprintPrompt() {
|
|
169
171
|
try {
|
|
170
172
|
const prompt = await loadGeneratorPrompt(project.projectId, 'blueprint');
|
|
171
|
-
|
|
173
|
+
copyToClipboard(prompt).catch(() => {});
|
|
172
174
|
showToast?.(t('profile.generator.blueprintPromptCopied'));
|
|
173
175
|
} catch (e) {
|
|
174
176
|
showToast?.(e.message, true);
|
|
@@ -206,7 +208,7 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
206
208
|
async function handleCopyInterviewPrompt() {
|
|
207
209
|
try {
|
|
208
210
|
const prompt = await loadGeneratorPrompt(project.projectId, 'interview', getLocale());
|
|
209
|
-
|
|
211
|
+
copyToClipboard(prompt).catch(() => {});
|
|
210
212
|
showToast?.(t('profile.generator.interviewPromptCopied'));
|
|
211
213
|
} catch (e) {
|
|
212
214
|
showToast?.(e.message, true);
|
|
@@ -428,9 +430,7 @@ function NewProjectView({ onBack, onCreated, showToast, orSettings }) {
|
|
|
428
430
|
<label>${t('profile.generator.errors')}</label>
|
|
429
431
|
<ul>${blueprintErrors.map(e => html`<li>${e}</li>`)}</ul>
|
|
430
432
|
${fixPrompt && html`
|
|
431
|
-
|
|
432
|
-
${t('profile.generator.copyFixPrompt')}
|
|
433
|
-
</button>
|
|
433
|
+
<${CopyButton} text=${fixPrompt} label=${t('profile.generator.copyFixPrompt')} className="btn-primary btn-sm" />
|
|
434
434
|
`}
|
|
435
435
|
</div>
|
|
436
436
|
`}
|