@kortix/ui 0.14.6 → 0.14.8
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/_vendor/kortix-shared.js +490 -382
- package/dist/_vendor/shared/runtime-versions.d.ts +4 -0
- package/dist/access/access/access-dialog-share.js +4 -7
- package/dist/access/access/access-dialog.js +2 -1
- package/dist/access/access/principal-picker.js +6 -5
- package/dist/customize/agents/agent-authority-card.js +1 -2
- package/dist/customize/agents/agent-cover-card.d.ts +17 -0
- package/dist/customize/agents/agent-cover-card.js +13 -0
- package/dist/customize/agents/agent-detail-aside.js +15 -14
- package/dist/customize/agents/agent-drives-section.js +5 -6
- package/dist/customize/agents/agent-grant-pages.js +68 -70
- package/dist/customize/agents/agent-page.js +27 -19
- package/dist/customize/agents/agent-people-section.js +18 -17
- package/dist/customize/agents/agent-triggers-section.js +6 -5
- package/dist/customize/agents/agents-page.js +43 -49
- package/dist/customize/connectors/catalog/catalog-entry.d.ts +14 -0
- package/dist/customize/connectors/catalog/catalog-entry.js +18 -1
- package/dist/customize/connectors/catalog/connector-browse.d.ts +28 -0
- package/dist/customize/connectors/catalog/connector-browse.js +18 -5
- package/dist/customize/connectors/detail/app-page.js +19 -5
- package/dist/customize/connectors/detail/connector-modal.d.ts +10 -13
- package/dist/customize/connectors/detail/connector-modal.js +18 -101
- package/dist/customize/connectors/detail/connector-notice.js +6 -2
- package/dist/customize/connectors/detail/connector-page.d.ts +30 -0
- package/dist/customize/connectors/detail/connector-page.js +26 -13
- package/dist/customize/migrate-to-v2/migration-prompt.d.ts +1 -0
- package/dist/customize/migrate-to-v2/migration-prompt.js +1 -0
- package/dist/customize/sections/llm-provider/custom-provider-form.js +24 -7
- package/dist/customize/sections/llm-provider/custom-provider-panel.js +44 -8
- package/dist/customize/sections/llm-provider/types.d.ts +3 -0
- package/dist/customize/sections/llm-provider/utils.js +2 -2
- package/dist/customize/sections/view/agent-editor-access-fields.d.ts +9 -16
- package/dist/customize/sections/view/agent-editor-access-fields.js +30 -30
- package/dist/customize/sections/view/agent-editor-basics-fields.js +3 -10
- package/dist/customize/sections/view/agent-editor-primitives.d.ts +28 -10
- package/dist/customize/sections/view/agent-editor-primitives.js +32 -19
- package/dist/customize/sections/view/agent-editor.js +3 -3
- package/dist/customize/sections/view/channels-view.js +2 -6
- package/dist/customize/sections/view/gateway/gateway-routing.js +3 -3
- package/dist/customize/sections/view/grant-mode-field.d.ts +2 -5
- package/dist/customize/sections/view/grant-mode-field.js +10 -18
- package/dist/customize/sections/view/permission-editor.js +11 -8
- package/dist/customize/sections/view/secrets-view.js +2 -1
- package/dist/customize/settings/tabs/general-tab.d.ts +9 -2
- package/dist/customize/settings/tabs/general-tab.js +33 -11
- package/dist/customize/settings/tabs/transfer-workspace-dialog.d.ts +4 -0
- package/dist/customize/settings/tabs/transfer-workspace-dialog.js +82 -0
- package/dist/customize/shared/new-entity-menu.js +4 -1
- package/dist/customize/skills/skills-page.js +4 -5
- package/dist/customize/triggers/schedule/then-fields.js +1 -5
- package/dist/customize/triggers/schedule-view.js +4 -2
- package/dist/files/project/api/runtime-files.js +3 -2
- package/dist/files/project/file-source.js +18 -1
- package/dist/files/project/hooks/use-file-content.js +2 -0
- package/dist/files/viewer/file-header.js +1 -1
- package/dist/files/viewer/file-preview-modal.d.ts +1 -1
- package/dist/files/viewer/file-preview-modal.js +12 -2
- package/dist/files/viewer/file-source.d.ts +3 -1
- package/dist/files/viewer/use-file-content-state.js +26 -7
- package/dist/files/viewer/viewer-actions.js +2 -2
- package/dist/i18n/en.d.ts +393 -12
- package/dist/i18n/en.js +400 -19
- package/dist/internal/components/agent-mark.d.ts +38 -0
- package/dist/internal/components/agent-mark.js +38 -0
- package/dist/internal/files/types.d.ts +2 -0
- package/dist/internal/goals/goal-meta.d.ts +30 -0
- package/dist/internal/goals/goal-meta.js +55 -0
- package/dist/internal/lib/pixel-mark.d.ts +33 -0
- package/dist/internal/lib/pixel-mark.js +152 -0
- package/dist/internal/lib/query-client-singleton.d.ts +9 -3
- package/dist/internal/lib/query-client-singleton.js +18 -12
- package/dist/internal/lib/use-project-feature-flags.js +3 -3
- package/dist/internal/share/session-shares-modal.js +3 -7
- package/dist/internal/stores/kortix-computer-store.js +14 -2
- package/dist/internal/stores/session-hover-store.d.ts +32 -0
- package/dist/internal/stores/session-hover-store.js +38 -0
- package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
- package/dist/internal/stores/sidebar-nav-store.js +3 -1
- package/dist/lib/routes.d.ts +2 -0
- package/dist/lib/routes.js +1 -0
- package/dist/markdown/genui/components/inline.d.ts +1 -1
- package/dist/markdown/setup-links/app-credentials-form.d.ts +12 -0
- package/dist/markdown/setup-links/app-credentials-form.js +115 -0
- package/dist/markdown/setup-links/secret-intake-form.d.ts +10 -0
- package/dist/markdown/setup-links/secret-intake-form.js +1 -1
- package/dist/primitives/entity-avatar.d.ts +4 -1
- package/dist/primitives/entity-avatar.js +4 -2
- package/dist/primitives/settings-section-header.d.ts +1 -1
- package/dist/primitives/user-avatar.d.ts +3 -1
- package/dist/primitives/user-avatar.js +4 -2
- package/dist/providers/ui-provider.d.ts +1 -1
- package/dist/session/composer/agent-selector.d.ts +7 -1
- package/dist/session/composer/agent-selector.js +20 -10
- package/dist/session/composer/attachment-tile.d.ts +0 -2
- package/dist/session/composer/attachment-tile.js +0 -8
- package/dist/session/composer/clipboard-files.d.ts +2 -1
- package/dist/session/composer/composer-draft-recovery.d.ts +1 -2
- package/dist/session/composer/composer-draft-recovery.js +0 -13
- package/dist/session/composer/context-ring.d.ts +1 -1
- package/dist/session/composer/context-ring.js +2 -2
- package/dist/session/composer/context-usage.d.ts +8 -6
- package/dist/session/composer/context-usage.js +9 -7
- package/dist/session/composer/inbox-row-claims.d.ts +2 -2
- package/dist/session/composer/inbox-row-claims.js +1 -1
- package/dist/session/composer/queue-projection.d.ts +3 -2
- package/dist/session/composer/queued-prompt-edit.d.ts +1 -1
- package/dist/session/composer/reasoning-effort-selector.d.ts +2 -1
- package/dist/session/composer/session-composer-readiness.d.ts +7 -22
- package/dist/session/composer/session-composer-readiness.js +12 -40
- package/dist/session/composer/token-progress.d.ts +1 -1
- package/dist/session/composer/token-progress.js +6 -6
- package/dist/session/header/export-transcript-modal.d.ts +3 -2
- package/dist/session/header/export-transcript-modal.js +6 -3
- package/dist/session/header/session-goal-indicator.d.ts +1 -0
- package/dist/session/header/session-goal-indicator.js +41 -0
- package/dist/session/header/session-site-header.js +2 -1
- package/dist/session/models/model-selector.d.ts +3 -1
- package/dist/session/models/model-selector.js +3 -2
- package/dist/session/panel/easy/plan-card.d.ts +2 -0
- package/dist/session/panel/easy/plan-card.js +2 -0
- package/dist/session/panel/session-action-panel-column.js +11 -1
- package/dist/session/panel/session-audit-shared.d.ts +0 -4
- package/dist/session/panel/session-audit-shared.js +1 -1
- package/dist/session/panel/session-changes-shared.d.ts +2 -1
- package/dist/session/prompts/session-permission-prompt.js +6 -3
- package/dist/session/status/provisioning-failure.d.ts +2 -1
- package/dist/session/status/session-error-banner.js +8 -6
- package/dist/session/status/session-starting-loader.d.ts +24 -31
- package/dist/session/status/session-starting-loader.js +32 -81
- package/dist/session/thread/chat-minimap-items.d.ts +4 -4
- package/dist/session/thread/first-prompt-handover.d.ts +3 -2
- package/dist/session/thread/message-parsing.d.ts +3 -3
- package/dist/session/thread/plan-surface.d.ts +1 -0
- package/dist/session/thread/plan-surface.js +1 -0
- package/dist/session/thread/session-chat.js +5 -12
- package/dist/session/thread/session-context-metrics.d.ts +15 -0
- package/dist/session/thread/session-context-metrics.js +10 -1
- package/dist/session/thread/session-context-modal.d.ts +4 -2
- package/dist/session/thread/session-context-modal.js +16 -9
- package/dist/session/thread/session-history-scroll.d.ts +2 -1
- package/dist/session/thread/session-thread.js +1 -1
- package/dist/session/thread/transcript.d.ts +4 -0
- package/dist/session/thread/transcript.js +18 -5
- package/dist/session/thread/turn-share.d.ts +16 -0
- package/dist/session/thread/turn-share.js +162 -0
- package/dist/session/tool/tools/apply-patch-tool.d.ts +1 -0
- package/dist/session/tool/tools/apply-patch-tool.js +1 -0
- package/dist/session/tool/tools/pty-kill-tool.d.ts +1 -0
- package/dist/session/tool/tools/pty-kill-tool.js +1 -0
- package/dist/session/tool/tools/pty-read-tool.d.ts +2 -0
- package/dist/session/tool/tools/pty-read-tool.js +2 -0
- package/dist/session/tool/tools/pty-spawn-tool.d.ts +1 -0
- package/dist/session/tool/tools/pty-spawn-tool.js +1 -0
- package/dist/session/tool/tools/pty-write-tool.d.ts +1 -0
- package/dist/session/tool/tools/pty-write-tool.js +1 -0
- package/dist/session/tool/tools/todo-write-tool.d.ts +1 -0
- package/dist/session/tool/tools/todo-write-tool.js +1 -0
- package/dist/session/turn/message-author-label.js +6 -2
- package/dist/session/turn/plan-anchor.d.ts +3 -0
- package/dist/session/turn/plan-anchor.js +3 -0
- package/dist/session/turn/plan-card.d.ts +7 -0
- package/dist/session/turn/plan-card.js +7 -0
- package/dist/styles.css +1 -1
- package/dist/terminal/pty-connection.d.ts +5 -4
- package/dist/terminal/session-terminal-connect-bar.js +2 -1
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/index.js +1 -0
- package/dist/workspace/saved-session-skeleton-shape.d.ts +4 -3
- package/dist/workspace/saved-session-skeleton.d.ts +5 -1
- package/dist/workspace/saved-session-skeleton.js +5 -4
- package/dist/workspace/session-workspace.js +4 -5
- package/dist/workspace/sidebar/footer/project-goals-nav.d.ts +6 -0
- package/dist/workspace/sidebar/footer/project-goals-nav.js +26 -0
- package/dist/workspace/sidebar/modal/session-embed-section.d.ts +25 -0
- package/dist/workspace/sidebar/modal/session-embed-section.js +71 -0
- package/dist/workspace/sidebar/modal/share-session-modal.js +2 -2
- package/dist/workspace/sidebar/nav-row-meta.js +14 -2
- package/dist/workspace/sidebar/project-nav-items.js +3 -0
- package/dist/workspace/sidebar/project-session-list.js +12 -3
- package/dist/workspace/sidebar/session-brief-hover-card.js +33 -9
- package/package.json +12 -4
- package/skills/kortix-ui/references/modules.md +2 -0
- package/dist/session/status/use-readiness-settling.d.ts +0 -18
- package/dist/session/status/use-readiness-settling.js +0 -43
- package/dist/workspace/sidebar/modal/session-public-link-section.d.ts +0 -13
- package/dist/workspace/sidebar/modal/session-public-link-section.js +0 -66
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** @internal Kortix apps only. No semver: it may change in any release. */
|
|
2
|
+
/**
|
|
3
|
+
* The shared vocabulary of the Goals surfaces (flag `goals`): the status chip,
|
|
4
|
+
* the health line, progress and "needs you". The Goals page, the sidebar row
|
|
5
|
+
* and the session header chip all read a goal through these, so a status or a
|
|
6
|
+
* health issue reads the same everywhere.
|
|
7
|
+
*/
|
|
8
|
+
import type { ProjectGoal, ProjectGoalDocument, ProjectGoalIssue, ProjectGoalItem, ProjectGoalStatus } from '@kortix/sdk';
|
|
9
|
+
export declare function GoalStatusBadge({ status }: {
|
|
10
|
+
status: ProjectGoalStatus | null | undefined;
|
|
11
|
+
}): import("react").JSX.Element | null;
|
|
12
|
+
/** Green: running. Orange: needs attention. Grey: closed. */
|
|
13
|
+
export declare function GoalHealthDot({ goal }: {
|
|
14
|
+
goal: Pick<ProjectGoal, 'health'>;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
/** One sentence per issue, for the health line and its tooltip. */
|
|
17
|
+
export declare function useGoalIssueText(): (issue: ProjectGoalIssue, goal: Pick<ProjectGoal, "heartbeat">) => string;
|
|
18
|
+
export declare function goalProgress(goal: ProjectGoalDocument | null): {
|
|
19
|
+
met: number;
|
|
20
|
+
total: number;
|
|
21
|
+
};
|
|
22
|
+
/** Open asks for a person (not the agent): what the goal waits on someone for. */
|
|
23
|
+
export declare function goalOpenAsks(goal: ProjectGoalDocument | null): ProjectGoalItem[];
|
|
24
|
+
/** The goal needs a person: an open ask, or a health issue. */
|
|
25
|
+
export declare function goalNeedsYou(goal: ProjectGoal): boolean;
|
|
26
|
+
/** "in 33 min", "2 hr ago", "Tue 09:00": the reminders time format. */
|
|
27
|
+
export declare function formatGoalTime(iso: string | null | undefined, locale: string, now: number): string;
|
|
28
|
+
export declare function goalHref(projectId: string, goal: Pick<ProjectGoal, 'scope' | 'slug'>): string | null;
|
|
29
|
+
/** The current time, re-read every 30 seconds: relative times and health stay current. */
|
|
30
|
+
export { useNow as useGoalClock } from '../reminders/use-refetch-after-fire.js';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { formatFireTime } from '../reminders/reminder-format.js';
|
|
4
|
+
import { useTranslations } from '../../i18n/index.js';
|
|
5
|
+
import { StatusBadge, StatusDot } from '../../primitives/status.js';
|
|
6
|
+
import { uiRoutes } from '../../lib/routes.js';
|
|
7
|
+
const STATUS_TONE = {
|
|
8
|
+
draft: 'neutral',
|
|
9
|
+
active: 'info',
|
|
10
|
+
waiting_on_user: 'warning',
|
|
11
|
+
waiting_external: 'neutral',
|
|
12
|
+
verifying: 'info',
|
|
13
|
+
done: 'success',
|
|
14
|
+
abandoned: 'neutral',
|
|
15
|
+
};
|
|
16
|
+
export function GoalStatusBadge({ status }) {
|
|
17
|
+
const t = useTranslations('goals');
|
|
18
|
+
if (!status)
|
|
19
|
+
return null;
|
|
20
|
+
return _jsx(StatusBadge, { tone: STATUS_TONE[status] ?? 'neutral', children: t(`status.${status}`) });
|
|
21
|
+
}
|
|
22
|
+
/** Green: running. Orange: needs attention. Grey: closed. */
|
|
23
|
+
export function GoalHealthDot({ goal }) {
|
|
24
|
+
const tone = goal.health.state === 'healthy' ? 'success' : goal.health.state === 'attention' ? 'warning' : 'neutral';
|
|
25
|
+
return _jsx(StatusDot, { tone: tone });
|
|
26
|
+
}
|
|
27
|
+
/** One sentence per issue, for the health line and its tooltip. */
|
|
28
|
+
export function useGoalIssueText() {
|
|
29
|
+
const t = useTranslations('goals');
|
|
30
|
+
return (issue, goal) => issue === 'heartbeat_failed'
|
|
31
|
+
? t('issue.heartbeat_failed', { error: goal.heartbeat?.last_error ?? '—' })
|
|
32
|
+
: t(`issue.${issue}`);
|
|
33
|
+
}
|
|
34
|
+
export function goalProgress(goal) {
|
|
35
|
+
const criteria = goal?.success_criteria ?? [];
|
|
36
|
+
return { met: criteria.filter((c) => c.met).length, total: criteria.length };
|
|
37
|
+
}
|
|
38
|
+
/** Open asks for a person (not the agent): what the goal waits on someone for. */
|
|
39
|
+
export function goalOpenAsks(goal) {
|
|
40
|
+
return (goal?.items ?? []).filter((i) => i.kind === 'ask' && i.status === 'open' && i.owner !== 'agent');
|
|
41
|
+
}
|
|
42
|
+
/** The goal needs a person: an open ask, or a health issue. */
|
|
43
|
+
export function goalNeedsYou(goal) {
|
|
44
|
+
return goal.health.state === 'attention' || (goal.health.state !== 'closed' && goalOpenAsks(goal.goal).length > 0);
|
|
45
|
+
}
|
|
46
|
+
/** "in 33 min", "2 hr ago", "Tue 09:00": the reminders time format. */
|
|
47
|
+
export function formatGoalTime(iso, locale, now) {
|
|
48
|
+
return iso ? formatFireTime(iso, locale, now) : '—';
|
|
49
|
+
}
|
|
50
|
+
export function goalHref(projectId, goal) {
|
|
51
|
+
const list = uiRoutes().goals(projectId);
|
|
52
|
+
return list ? `${list}/${goal.scope}/${encodeURIComponent(goal.slug)}` : null;
|
|
53
|
+
}
|
|
54
|
+
/** The current time, re-read every 30 seconds: relative times and health stay current. */
|
|
55
|
+
export { useNow as useGoalClock } from '../reminders/use-refetch-after-fire.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** @internal Kortix apps only. No semver: it may change in any release. */
|
|
2
|
+
/**
|
|
3
|
+
* An agent's pixel mark: a 7×7 mirrored pixel figure derived from its slug.
|
|
4
|
+
*
|
|
5
|
+
* Same slug, same mark, on every surface and every device. Nothing is stored:
|
|
6
|
+
* the slug is hashed (FNV-1a), the hash seeds a PRNG (mulberry32), the PRNG
|
|
7
|
+
* fills the left half of the grid against a density mask, and the half is
|
|
8
|
+
* mirrored. A draw that fails the quality gate is redrawn from a salted seed,
|
|
9
|
+
* so retries stay deterministic. The tone comes from a second hash.
|
|
10
|
+
*
|
|
11
|
+
* Changing SIZE, MASK, the gate or PALETTES changes every agent's mark — the
|
|
12
|
+
* golden test in `pixel-mark.test.ts` exists to make that a deliberate act.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PIXEL_MARK_SIZE = 7;
|
|
15
|
+
export interface PixelMarkTone {
|
|
16
|
+
name: string;
|
|
17
|
+
tile: string;
|
|
18
|
+
ink: string;
|
|
19
|
+
/** Dark theme: the pair inverts, so the tile stays visible on a dark page. */
|
|
20
|
+
tileDark: string;
|
|
21
|
+
inkDark: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const PIXEL_MARK_TONES: readonly PixelMarkTone[];
|
|
24
|
+
type Grid = boolean[][];
|
|
25
|
+
export declare function fnv1a(input: string): number;
|
|
26
|
+
/** Readable at 14px, fills the frame, one connected body. */
|
|
27
|
+
export declare function passesPixelMarkGate(grid: Grid): boolean;
|
|
28
|
+
export declare function pixelMark(slug: string): {
|
|
29
|
+
grid: Grid;
|
|
30
|
+
path: string;
|
|
31
|
+
tone: PixelMarkTone;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An agent's pixel mark: a 7×7 mirrored pixel figure derived from its slug.
|
|
3
|
+
*
|
|
4
|
+
* Same slug, same mark, on every surface and every device. Nothing is stored:
|
|
5
|
+
* the slug is hashed (FNV-1a), the hash seeds a PRNG (mulberry32), the PRNG
|
|
6
|
+
* fills the left half of the grid against a density mask, and the half is
|
|
7
|
+
* mirrored. A draw that fails the quality gate is redrawn from a salted seed,
|
|
8
|
+
* so retries stay deterministic. The tone comes from a second hash.
|
|
9
|
+
*
|
|
10
|
+
* Changing SIZE, MASK, the gate or PALETTES changes every agent's mark — the
|
|
11
|
+
* golden test in `pixel-mark.test.ts` exists to make that a deliberate act.
|
|
12
|
+
*/
|
|
13
|
+
export const PIXEL_MARK_SIZE = 7;
|
|
14
|
+
const HALF = 4;
|
|
15
|
+
const MAX_ATTEMPTS = 256;
|
|
16
|
+
// Fill chance per cell, outer edge → spine. Dense centre, sparse edges, so the
|
|
17
|
+
// mirrored result reads as one body.
|
|
18
|
+
const MASK = [
|
|
19
|
+
[0.15, 0.3, 0.45, 0.55],
|
|
20
|
+
[0.3, 0.5, 0.6, 0.7],
|
|
21
|
+
[0.4, 0.6, 0.65, 0.7],
|
|
22
|
+
[0.5, 0.65, 0.7, 0.75],
|
|
23
|
+
[0.4, 0.55, 0.6, 0.65],
|
|
24
|
+
[0.3, 0.45, 0.5, 0.5],
|
|
25
|
+
[0.2, 0.35, 0.4, 0.35],
|
|
26
|
+
];
|
|
27
|
+
const tone = (name, tile, ink) => ({
|
|
28
|
+
name,
|
|
29
|
+
tile,
|
|
30
|
+
ink,
|
|
31
|
+
tileDark: ink,
|
|
32
|
+
inkDark: tile,
|
|
33
|
+
});
|
|
34
|
+
export const PIXEL_MARK_TONES = [
|
|
35
|
+
tone('graphite', '#EDEDED', '#191919'),
|
|
36
|
+
tone('sand', '#F1EBDD', '#6B5A3A'),
|
|
37
|
+
tone('moss', '#E6EDE0', '#3F5A33'),
|
|
38
|
+
tone('sea', '#E2ECF0', '#2E5566'),
|
|
39
|
+
tone('blue', '#E6EEFF', '#2457C5'),
|
|
40
|
+
tone('plum', '#EEE6F0', '#5E3A68'),
|
|
41
|
+
tone('clay', '#F3E6E0', '#7A4532'),
|
|
42
|
+
tone('slate', '#E4E7EC', '#3B4656'),
|
|
43
|
+
];
|
|
44
|
+
/** The built-in agent and the platform's Meta agent keep the brand tile. */
|
|
45
|
+
const BRAND = {
|
|
46
|
+
name: 'brand',
|
|
47
|
+
tile: '#1F1F1F',
|
|
48
|
+
ink: '#FFFFFF',
|
|
49
|
+
tileDark: '#2C2C2C',
|
|
50
|
+
inkDark: '#FFFFFF',
|
|
51
|
+
};
|
|
52
|
+
const RESERVED = { kortix: BRAND, meta: BRAND };
|
|
53
|
+
export function fnv1a(input) {
|
|
54
|
+
let h = 0x811c9dc5;
|
|
55
|
+
for (let i = 0; i < input.length; i++) {
|
|
56
|
+
h ^= input.charCodeAt(i);
|
|
57
|
+
h = Math.imul(h, 0x01000193);
|
|
58
|
+
}
|
|
59
|
+
return h >>> 0;
|
|
60
|
+
}
|
|
61
|
+
function mulberry32(seed) {
|
|
62
|
+
let a = seed;
|
|
63
|
+
return () => {
|
|
64
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
65
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
66
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
67
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function draw(seed) {
|
|
71
|
+
const rand = mulberry32(seed);
|
|
72
|
+
return MASK.map((row) => {
|
|
73
|
+
const half = row.map((p) => rand() < p);
|
|
74
|
+
return [...half, half[2], half[1], half[0]];
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function largestComponent(grid) {
|
|
78
|
+
const seen = grid.map((row) => row.map(() => false));
|
|
79
|
+
let best = 0;
|
|
80
|
+
for (let r = 0; r < PIXEL_MARK_SIZE; r++)
|
|
81
|
+
for (let c = 0; c < PIXEL_MARK_SIZE; c++) {
|
|
82
|
+
if (!grid[r][c] || seen[r][c])
|
|
83
|
+
continue;
|
|
84
|
+
let size = 0;
|
|
85
|
+
const stack = [[r, c]];
|
|
86
|
+
seen[r][c] = true;
|
|
87
|
+
while (stack.length) {
|
|
88
|
+
const [y, x] = stack.pop();
|
|
89
|
+
size++;
|
|
90
|
+
for (const [ny, nx] of [[y + 1, x], [y - 1, x], [y, x + 1], [y, x - 1]]) {
|
|
91
|
+
if (grid[ny]?.[nx] && !seen[ny][nx]) {
|
|
92
|
+
seen[ny][nx] = true;
|
|
93
|
+
stack.push([ny, nx]);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
best = Math.max(best, size);
|
|
98
|
+
}
|
|
99
|
+
return best;
|
|
100
|
+
}
|
|
101
|
+
function hasIsolatedPixel(grid) {
|
|
102
|
+
return grid.some((row, r) => row.some((on, c) => {
|
|
103
|
+
if (!on)
|
|
104
|
+
return false;
|
|
105
|
+
for (let dy = -1; dy <= 1; dy++)
|
|
106
|
+
for (let dx = -1; dx <= 1; dx++)
|
|
107
|
+
if ((dy || dx) && grid[r + dy]?.[c + dx])
|
|
108
|
+
return false;
|
|
109
|
+
return true;
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
/** Readable at 14px, fills the frame, one connected body. */
|
|
113
|
+
export function passesPixelMarkGate(grid) {
|
|
114
|
+
const filled = grid.flat().filter(Boolean).length;
|
|
115
|
+
if (filled < 18 || filled > 30)
|
|
116
|
+
return false;
|
|
117
|
+
const rows = grid.filter((row) => row.some(Boolean)).length;
|
|
118
|
+
const cols = grid[0].filter((_, c) => grid.some((row) => row[c])).length;
|
|
119
|
+
if (rows < 5 || cols < 5)
|
|
120
|
+
return false;
|
|
121
|
+
if (grid.filter((row) => row.every(Boolean)).length > 1)
|
|
122
|
+
return false;
|
|
123
|
+
if (grid.filter((row) => row[HALF - 1]).length < 3)
|
|
124
|
+
return false;
|
|
125
|
+
if (hasIsolatedPixel(grid))
|
|
126
|
+
return false;
|
|
127
|
+
return largestComponent(grid) >= Math.ceil(filled * 0.85);
|
|
128
|
+
}
|
|
129
|
+
/** One SVG path, horizontal runs merged. Render in `viewBox="0 0 7 7"`. */
|
|
130
|
+
function toPath(grid) {
|
|
131
|
+
let d = '';
|
|
132
|
+
grid.forEach((row, y) => {
|
|
133
|
+
for (let x = 0; x < PIXEL_MARK_SIZE;) {
|
|
134
|
+
if (!row[x]) {
|
|
135
|
+
x++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const start = x;
|
|
139
|
+
while (x < PIXEL_MARK_SIZE && row[x])
|
|
140
|
+
x++;
|
|
141
|
+
d += `M${start} ${y}h${x - start}v1h-${x - start}z`;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return d;
|
|
145
|
+
}
|
|
146
|
+
export function pixelMark(slug) {
|
|
147
|
+
let grid = draw(fnv1a(slug));
|
|
148
|
+
for (let attempt = 1; !passesPixelMarkGate(grid) && attempt < MAX_ATTEMPTS; attempt++)
|
|
149
|
+
grid = draw(fnv1a(`${slug}:${attempt}`));
|
|
150
|
+
const tone = RESERVED[slug] ?? PIXEL_MARK_TONES[fnv1a(`${slug}#tone`) % PIXEL_MARK_TONES.length];
|
|
151
|
+
return { grid, path: toPath(grid), tone };
|
|
152
|
+
}
|
|
@@ -3,7 +3,13 @@ import type { QueryClient } from '@tanstack/react-query';
|
|
|
3
3
|
export declare function registerQueryClient(client: QueryClient): void;
|
|
4
4
|
export declare function getSharedQueryClient(): QueryClient | null;
|
|
5
5
|
/**
|
|
6
|
-
* Run `run` with the shared client
|
|
7
|
-
*
|
|
6
|
+
* Run `run` with the shared client now (if one is registered), and again with
|
|
7
|
+
* every DIFFERENT client registered later. Returns the unsubscribe.
|
|
8
|
+
*
|
|
9
|
+
* AuthProvider sits ABOVE ReactQueryProvider, and #10344 mounts the app shell
|
|
10
|
+
* one auth round trip sooner, so a caller can ask before any client exists.
|
|
11
|
+
* `ReactQueryProvider` registers during render, and React can discard that
|
|
12
|
+
* render (a hydration retry, a suspension, Strict Mode) and commit a second
|
|
13
|
+
* client: a caller that ran once would hold a client the app no longer reads.
|
|
8
14
|
*/
|
|
9
|
-
export declare function
|
|
15
|
+
export declare function onEachQueryClient(run: (client: QueryClient) => void): () => void;
|
|
@@ -8,27 +8,33 @@
|
|
|
8
8
|
* from the central reset helper.
|
|
9
9
|
*/
|
|
10
10
|
let sharedQueryClient = null;
|
|
11
|
-
|
|
11
|
+
/** `onEachQueryClient` subscribers. replica-local: one tab's app. */
|
|
12
|
+
const followers = new Set();
|
|
12
13
|
export function registerQueryClient(client) {
|
|
14
|
+
if (sharedQueryClient === client)
|
|
15
|
+
return;
|
|
13
16
|
sharedQueryClient = client;
|
|
14
|
-
|
|
15
|
-
// shell one auth round trip sooner, so `adoptDeviceCaches` can run before
|
|
16
|
-
// this registers. Flush anyone who asked for the client before it existed.
|
|
17
|
-
const pending = waiters;
|
|
18
|
-
waiters = [];
|
|
19
|
-
for (const run of pending)
|
|
17
|
+
for (const run of [...followers])
|
|
20
18
|
run(client);
|
|
21
19
|
}
|
|
22
20
|
export function getSharedQueryClient() {
|
|
23
21
|
return sharedQueryClient;
|
|
24
22
|
}
|
|
25
23
|
/**
|
|
26
|
-
* Run `run` with the shared client
|
|
27
|
-
*
|
|
24
|
+
* Run `run` with the shared client now (if one is registered), and again with
|
|
25
|
+
* every DIFFERENT client registered later. Returns the unsubscribe.
|
|
26
|
+
*
|
|
27
|
+
* AuthProvider sits ABOVE ReactQueryProvider, and #10344 mounts the app shell
|
|
28
|
+
* one auth round trip sooner, so a caller can ask before any client exists.
|
|
29
|
+
* `ReactQueryProvider` registers during render, and React can discard that
|
|
30
|
+
* render (a hydration retry, a suspension, Strict Mode) and commit a second
|
|
31
|
+
* client: a caller that ran once would hold a client the app no longer reads.
|
|
28
32
|
*/
|
|
29
|
-
export function
|
|
33
|
+
export function onEachQueryClient(run) {
|
|
34
|
+
followers.add(run);
|
|
30
35
|
if (sharedQueryClient)
|
|
31
36
|
run(sharedQueryClient);
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
return () => {
|
|
38
|
+
followers.delete(run);
|
|
39
|
+
};
|
|
34
40
|
}
|
|
@@ -30,7 +30,6 @@ export function useProjectFeatureFlags(projectId) {
|
|
|
30
30
|
const warmSessions = useFeatureFlag(projectId, 'warm_sessions');
|
|
31
31
|
const secretsEgress = useFeatureFlag(projectId, 'secrets_egress');
|
|
32
32
|
const pooledProviderSecrets = useFeatureFlag(projectId, 'pooled_provider_secrets');
|
|
33
|
-
const piHarness = useFeatureFlag(projectId, 'pi_harness');
|
|
34
33
|
const genui = useFeatureFlag(projectId, 'genui');
|
|
35
34
|
const usRegion = useFeatureFlag(projectId, 'us_region');
|
|
36
35
|
const eventTriggers = useFeatureFlag(projectId, 'event_triggers');
|
|
@@ -42,6 +41,7 @@ export function useProjectFeatureFlags(projectId) {
|
|
|
42
41
|
const connectorsV2 = useFeatureFlag(projectId, 'connectors_v2');
|
|
43
42
|
const agentRooms = useFeatureFlag(projectId, 'agent_rooms');
|
|
44
43
|
const goals = useFeatureFlag(projectId, 'goals');
|
|
44
|
+
const workspaceVolume = useFeatureFlag(projectId, 'workspace_volume');
|
|
45
45
|
return {
|
|
46
46
|
flags: {
|
|
47
47
|
marketplace: marketplace.enabled,
|
|
@@ -53,7 +53,6 @@ export function useProjectFeatureFlags(projectId) {
|
|
|
53
53
|
warm_sessions: warmSessions.enabled,
|
|
54
54
|
secrets_egress: secretsEgress.enabled,
|
|
55
55
|
pooled_provider_secrets: pooledProviderSecrets.enabled,
|
|
56
|
-
pi_harness: piHarness.enabled,
|
|
57
56
|
genui: genui.enabled,
|
|
58
57
|
us_region: usRegion.enabled,
|
|
59
58
|
event_triggers: eventTriggers.enabled,
|
|
@@ -65,8 +64,9 @@ export function useProjectFeatureFlags(projectId) {
|
|
|
65
64
|
connectors_v2: connectorsV2.enabled,
|
|
66
65
|
agent_rooms: agentRooms.enabled,
|
|
67
66
|
goals: goals.enabled,
|
|
67
|
+
workspace_volume: workspaceVolume.enabled,
|
|
68
68
|
},
|
|
69
69
|
// The trailing hook's loading state — keep this on the LAST hook above.
|
|
70
|
-
isLoading:
|
|
70
|
+
isLoading: workspaceVolume.isLoading,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
@@ -16,13 +16,13 @@ import { isShareLive, publicShareUrl, shareListState, useRevokePublicShare, useS
|
|
|
16
16
|
import { cn } from '../../lib/utils.js';
|
|
17
17
|
function ShareRow({ share, onRevoke, isRevoking, }) {
|
|
18
18
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
19
|
-
const tTranscript = useTranslations('hardcodedUi.publicTranscriptShare');
|
|
20
19
|
const [copied, setCopied] = useState(false);
|
|
21
20
|
const live = isShareLive(share);
|
|
22
21
|
// Read at render time: `publicShareUrl` is null outside a browser (SSR).
|
|
23
22
|
const url = publicShareUrl(share.public_path);
|
|
24
23
|
const isFile = share.resource_type === 'file';
|
|
25
|
-
// A transcript share
|
|
24
|
+
// A legacy transcript share (revoked; the feature is removed) still carries
|
|
25
|
+
// no port and no file: its label is the row's own meta.
|
|
26
26
|
const isTranscript = share.resource_type === 'transcript';
|
|
27
27
|
const Icon = isFile ? FileText : isTranscript ? ChatText : Globe;
|
|
28
28
|
const copy = async () => {
|
|
@@ -33,11 +33,7 @@ function ShareRow({ share, onRevoke, isRevoking, }) {
|
|
|
33
33
|
successToast(tI18nComplete.raw('textd0f24de8dbc6'));
|
|
34
34
|
setTimeout(() => setCopied(false), 2000);
|
|
35
35
|
};
|
|
36
|
-
return (_jsxs("li", { className: cn('group bg-popover flex items-center gap-3 rounded-md border px-4 py-2.5 transition-colors', !live && 'opacity-60'), children: [_jsx("span", { className: cn('flex size-9 shrink-0 items-center justify-center rounded-sm', live ? 'bg-kortix-green/15' : 'bg-muted'), children: _jsx(Icon, { className: cn('size-5', live ? 'text-kortix-green' : 'text-muted-foreground') }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "truncate text-sm font-medium", children: share.label }), !live && (_jsx(Badge, { variant: "outline", size: "xs", children: share.revoked_at ? 'Revoked' : 'Expired' }))] }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: isFile
|
|
37
|
-
? share.file_path
|
|
38
|
-
: isTranscript
|
|
39
|
-
? tTranscript('rowMeta')
|
|
40
|
-
: `Port ${share.port}${share.path}` })] }), live && (_jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [_jsx(Hint, { label: copied ? 'Copied' : tI18nComplete.raw('textdbf362d4f210'), side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": tI18nComplete.raw('textdbf362d4f210'), disabled: !url, onClick: () => void copy(), className: "size-8 active:scale-[0.96]", children: copied ? (_jsx(Check, { className: "text-kortix-green size-4" })) : (_jsx(Link2, { className: "size-4" })) }) }), _jsxs(Button, { variant: "ghost", size: "sm", onClick: onRevoke, disabled: isRevoking, children: [isRevoking ? _jsx(Loading, { className: "size-4 shrink-0" }) : null, tI18nComplete.raw('text87e6d00bbf53')] })] }))] }));
|
|
36
|
+
return (_jsxs("li", { className: cn('group bg-popover flex items-center gap-3 rounded-md border px-4 py-2.5 transition-colors', !live && 'opacity-60'), children: [_jsx("span", { className: cn('flex size-9 shrink-0 items-center justify-center rounded-sm', live ? 'bg-kortix-green/15' : 'bg-muted'), children: _jsx(Icon, { className: cn('size-5', live ? 'text-kortix-green' : 'text-muted-foreground') }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "truncate text-sm font-medium", children: share.label }), !live && (_jsx(Badge, { variant: "outline", size: "xs", children: share.revoked_at ? 'Revoked' : 'Expired' }))] }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: isFile ? share.file_path : isTranscript ? share.label : `Port ${share.port}${share.path}` })] }), live && (_jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [_jsx(Hint, { label: copied ? 'Copied' : tI18nComplete.raw('textdbf362d4f210'), side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": tI18nComplete.raw('textdbf362d4f210'), disabled: !url, onClick: () => void copy(), className: "size-8 active:scale-[0.96]", children: copied ? (_jsx(Check, { className: "text-kortix-green size-4" })) : (_jsx(Link2, { className: "size-4" })) }) }), _jsxs(Button, { variant: "ghost", size: "sm", onClick: onRevoke, disabled: isRevoking, children: [isRevoking ? _jsx(Loading, { className: "size-4 shrink-0" }) : null, tI18nComplete.raw('text87e6d00bbf53')] })] }))] }));
|
|
41
37
|
}
|
|
42
38
|
export function SessionSharesModal({ projectId, sessionId, open, onOpenChange, }) {
|
|
43
39
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
@@ -173,6 +173,20 @@ export const useKortixComputerStore = create()(devtools((set, get) => ({
|
|
|
173
173
|
get().setIsActionPanelOpen(true);
|
|
174
174
|
},
|
|
175
175
|
setActiveSession: (sessionId, continuity) => {
|
|
176
|
+
const nextProjectSessionId = continuity?.projectSessionId ?? null;
|
|
177
|
+
const nextIsTransient = continuity?.transient ?? false;
|
|
178
|
+
// The boot shell of the session whose real chat already owns the right
|
|
179
|
+
// side. The two layers mount in either order, and the chat holds the
|
|
180
|
+
// panel's content: a shell that took over kept the right side after it
|
|
181
|
+
// faded out, so ⌘I reopened the cards instead of the detail it had
|
|
182
|
+
// just hidden (KRTX-2944). Not a session change, so nothing moves.
|
|
183
|
+
if (nextIsTransient &&
|
|
184
|
+
nextProjectSessionId !== null &&
|
|
185
|
+
get()._activeSessionId !== null &&
|
|
186
|
+
!get()._activeIsTransient &&
|
|
187
|
+
get()._activeProjectSessionId === nextProjectSessionId) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
176
190
|
// A quick-view is an intent about the session it was made in — it must
|
|
177
191
|
// not replay when some other session mounts later. Cleared even on the
|
|
178
192
|
// no-op re-activation path below, or a request planted for another
|
|
@@ -182,8 +196,6 @@ export const useKortixComputerStore = create()(devtools((set, get) => ({
|
|
|
182
196
|
set({ pendingQuickView: null });
|
|
183
197
|
}
|
|
184
198
|
const prev = get()._activeSessionId;
|
|
185
|
-
const nextProjectSessionId = continuity?.projectSessionId ?? null;
|
|
186
|
-
const nextIsTransient = continuity?.transient ?? false;
|
|
187
199
|
if (prev === sessionId) {
|
|
188
200
|
// Same layout re-activating (e.g. the shell flipping transient→ready
|
|
189
201
|
// state, or a tab refocus): keep the continuity bookkeeping fresh so
|
|
@@ -59,6 +59,38 @@ interface SessionHoverState {
|
|
|
59
59
|
closeSession: (sessionId: string) => void;
|
|
60
60
|
/** Immediate, for a click that opens something else and for unmount. */
|
|
61
61
|
dismiss: () => void;
|
|
62
|
+
/**
|
|
63
|
+
* The row whose session a click just opened. Its card would only describe
|
|
64
|
+
* the page on screen, so it stays shut until the pointer leaves the row.
|
|
65
|
+
* Unselected, like `warm`.
|
|
66
|
+
*/
|
|
67
|
+
suppressedSessionId: string | null;
|
|
68
|
+
suppress: (sessionId: string) => void;
|
|
69
|
+
release: (sessionId: string) => void;
|
|
62
70
|
}
|
|
63
71
|
export declare const useSessionHoverStore: import("zustand").UseBoundStore<import("zustand").StoreApi<SessionHoverState>>;
|
|
72
|
+
type RowTarget = {
|
|
73
|
+
matches?: (selector: string) => boolean;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* A session row's hover wiring (KRTX-2847). The press focuses the row and the
|
|
77
|
+
* pointer rests on it, so without the click handler every switch showed the
|
|
78
|
+
* card of the session just opened, 200 ms later, until the page took focus.
|
|
79
|
+
* Focus leaving the row releases it only when the pointer is elsewhere: the
|
|
80
|
+
* new page takes focus while the pointer still rests on the row.
|
|
81
|
+
*/
|
|
82
|
+
export declare function sessionRowHoverHandlers(id: string): {
|
|
83
|
+
onPointerEnter: (event: {
|
|
84
|
+
pointerType: string;
|
|
85
|
+
currentTarget: RowTarget;
|
|
86
|
+
}) => void;
|
|
87
|
+
onPointerLeave: () => void;
|
|
88
|
+
onFocus: (event: {
|
|
89
|
+
currentTarget: RowTarget;
|
|
90
|
+
}) => void;
|
|
91
|
+
onBlur: (event: {
|
|
92
|
+
currentTarget: RowTarget;
|
|
93
|
+
}) => void;
|
|
94
|
+
onClick: () => void;
|
|
95
|
+
};
|
|
64
96
|
export {};
|
|
@@ -65,8 +65,11 @@ export const useSessionHoverStore = create((set, get) => ({
|
|
|
65
65
|
via: 'pointer',
|
|
66
66
|
slot: null,
|
|
67
67
|
warm: false,
|
|
68
|
+
suppressedSessionId: null,
|
|
68
69
|
setSlot: (slot) => set({ slot }),
|
|
69
70
|
openSession: (sessionId, anchor, via = 'pointer') => {
|
|
71
|
+
if (get().suppressedSessionId === sessionId)
|
|
72
|
+
return;
|
|
70
73
|
closeTimer = cancel(closeTimer);
|
|
71
74
|
warmTimer = cancel(warmTimer);
|
|
72
75
|
// A pending open belongs to whichever row the pointer has just left.
|
|
@@ -106,4 +109,39 @@ export const useSessionHoverStore = create((set, get) => ({
|
|
|
106
109
|
warmTimer = cancel(warmTimer);
|
|
107
110
|
set({ activeSessionId: null, warm: false });
|
|
108
111
|
},
|
|
112
|
+
suppress: (sessionId) => {
|
|
113
|
+
set({ suppressedSessionId: sessionId });
|
|
114
|
+
get().dismiss();
|
|
115
|
+
},
|
|
116
|
+
release: (sessionId) => {
|
|
117
|
+
if (get().suppressedSessionId === sessionId)
|
|
118
|
+
set({ suppressedSessionId: null });
|
|
119
|
+
},
|
|
109
120
|
}));
|
|
121
|
+
/**
|
|
122
|
+
* A session row's hover wiring (KRTX-2847). The press focuses the row and the
|
|
123
|
+
* pointer rests on it, so without the click handler every switch showed the
|
|
124
|
+
* card of the session just opened, 200 ms later, until the page took focus.
|
|
125
|
+
* Focus leaving the row releases it only when the pointer is elsewhere: the
|
|
126
|
+
* new page takes focus while the pointer still rests on the row.
|
|
127
|
+
*/
|
|
128
|
+
export function sessionRowHoverHandlers(id) {
|
|
129
|
+
const store = () => useSessionHoverStore.getState();
|
|
130
|
+
return {
|
|
131
|
+
onPointerEnter: (event) => {
|
|
132
|
+
if (event.pointerType !== 'touch')
|
|
133
|
+
store().openSession(id, event.currentTarget, 'pointer');
|
|
134
|
+
},
|
|
135
|
+
onPointerLeave: () => {
|
|
136
|
+
store().release(id);
|
|
137
|
+
store().closeSession(id);
|
|
138
|
+
},
|
|
139
|
+
onFocus: (event) => store().openSession(id, event.currentTarget, 'focus'),
|
|
140
|
+
onBlur: (event) => {
|
|
141
|
+
if (!event.currentTarget.matches?.(':hover'))
|
|
142
|
+
store().release(id);
|
|
143
|
+
store().closeSession(id);
|
|
144
|
+
},
|
|
145
|
+
onClick: () => store().suppress(id),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* (`customize-sidebar-modal.tsx` syncs it). A row a project does not offer (a flag is off, a permission is denied)
|
|
9
9
|
* keeps its place here and simply does not render.
|
|
10
10
|
*/
|
|
11
|
-
export declare const SIDEBAR_NAV_ITEM_IDS: readonly ["customize", "apps", "files", "rooms"];
|
|
11
|
+
export declare const SIDEBAR_NAV_ITEM_IDS: readonly ["customize", "apps", "files", "rooms", "goals"];
|
|
12
12
|
export type SidebarNavItemId = (typeof SIDEBAR_NAV_ITEM_IDS)[number];
|
|
13
13
|
/**
|
|
14
14
|
* `never` moves the row into the More menu (`project-nav-items.tsx`), so its
|
|
@@ -13,7 +13,7 @@ import { registerPersistedStore, resetPersistedStore } from './persisted-store-r
|
|
|
13
13
|
*/
|
|
14
14
|
// Review (2026-10-17) and Reminders (2026-10-19) left the sidebar for Customize
|
|
15
15
|
// tabs. A saved layout that still names one drops the id in `normalizeSidebarNav`.
|
|
16
|
-
export const SIDEBAR_NAV_ITEM_IDS = ['customize', 'apps', 'files', 'rooms'];
|
|
16
|
+
export const SIDEBAR_NAV_ITEM_IDS = ['customize', 'apps', 'files', 'rooms', 'goals'];
|
|
17
17
|
/** The layout before anyone customizes it. */
|
|
18
18
|
export const SIDEBAR_NAV_DEFAULTS = [
|
|
19
19
|
{ id: 'customize', visibility: 'always' },
|
|
@@ -22,6 +22,8 @@ export const SIDEBAR_NAV_DEFAULTS = [
|
|
|
22
22
|
// Rooms (2026-10-19, flag `agent_rooms`): chat rooms for sessions and people.
|
|
23
23
|
// In the More menu until the person pins it (2026-10-20).
|
|
24
24
|
{ id: 'rooms', visibility: 'never' },
|
|
25
|
+
// Goals (2026-10-21, flag `goals`): objectives agents own until verified done.
|
|
26
|
+
{ id: 'goals', visibility: 'always' },
|
|
25
27
|
];
|
|
26
28
|
function isItemId(value) {
|
|
27
29
|
return SIDEBAR_NAV_ITEM_IDS.includes(value);
|
package/dist/lib/routes.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface UiRoutes {
|
|
|
22
22
|
apps: (projectId: string) => string | null;
|
|
23
23
|
/** The project's chat rooms (flag `agent_rooms`). */
|
|
24
24
|
rooms: (projectId: string) => string | null;
|
|
25
|
+
/** The project's goals (flag `goals`); a goal is `<goals>/<scope>/<slug>`. */
|
|
26
|
+
goals: (projectId: string) => string | null;
|
|
25
27
|
members: (projectId: string) => string | null;
|
|
26
28
|
/** The project settings page, on its sandbox section. */
|
|
27
29
|
sandboxSettings: (projectId: string) => string | null;
|
package/dist/lib/routes.js
CHANGED
|
@@ -6,6 +6,7 @@ const DEFAULT_ROUTES = {
|
|
|
6
6
|
drive: (p) => `/projects/${p}/drive`,
|
|
7
7
|
apps: (p) => `/projects/${p}/apps`,
|
|
8
8
|
rooms: (p) => `/projects/${p}/rooms`,
|
|
9
|
+
goals: (p) => `/projects/${p}/goals`,
|
|
9
10
|
members: (p) => `/projects/${p}/members`,
|
|
10
11
|
sandboxSettings: (p) => `/projects/${p}/config?section=sandbox`,
|
|
11
12
|
customize: (p, path) => `/projects/${p}/customize${path ? `/${path}` : ''}`,
|
|
@@ -12,6 +12,6 @@ export declare const genuiBadgeClass: (tone: BadgeTone) => string;
|
|
|
12
12
|
export declare function GenuiBadge({ props }: GenuiComponentProps): import("react").JSX.Element;
|
|
13
13
|
export declare function GenuiCallout({ props }: GenuiComponentProps): import("react").JSX.Element;
|
|
14
14
|
/** Set inside an image gallery (layout.tsx): the tile sizes the image, which covers it. A `tile` shows its caption on hover. */
|
|
15
|
-
export declare const GenuiImageGridContext: import("react").Context<false | "
|
|
15
|
+
export declare const GenuiImageGridContext: import("react").Context<false | "tile" | "lead">;
|
|
16
16
|
export declare function GenuiImage({ props }: GenuiComponentProps): import("react").JSX.Element;
|
|
17
17
|
export declare function GenuiLink({ props }: GenuiComponentProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The form behind an own-app connect link (`/connect/app/[token]`): the app's
|
|
3
|
+
* client credentials and the store, for a Composio toolkit that runs on the
|
|
4
|
+
* customer's own app. Shopify is the one such app today.
|
|
5
|
+
*
|
|
6
|
+
* The page opens in the connect popup. The window that opened it polls the
|
|
7
|
+
* connection, so after a success this window only confirms and closes itself
|
|
8
|
+
* (or follows the native app's return link).
|
|
9
|
+
*/
|
|
10
|
+
export declare function AppCredentialsForm({ token }: {
|
|
11
|
+
token: string;
|
|
12
|
+
}): import("react").JSX.Element;
|