Merge origin/main and preserve nonblocking project entry
This commit is contained in:
@@ -80,9 +80,9 @@ function requireSuccess<T extends { success: boolean; error?: string }>(
|
||||
}
|
||||
|
||||
export async function getAgentBrowserState(
|
||||
projectPath: string,
|
||||
projectId: string,
|
||||
): Promise<AgentBrowserSnapshot> {
|
||||
const query = new URLSearchParams({ project_path: projectPath });
|
||||
const query = new URLSearchParams({ project_id: projectId });
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
`/api/agent-browser/state?${query.toString()}`,
|
||||
);
|
||||
@@ -90,14 +90,14 @@ export async function getAgentBrowserState(
|
||||
}
|
||||
|
||||
export async function openAgentBrowser(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
url: string;
|
||||
bounds?: AgentBrowserBounds;
|
||||
}): Promise<AgentBrowserSnapshot> {
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
'/api/agent-browser/open',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
url: input.url,
|
||||
visible: true,
|
||||
...(input.bounds ? { bounds: input.bounds } : {}),
|
||||
@@ -107,14 +107,14 @@ export async function openAgentBrowser(input: {
|
||||
}
|
||||
|
||||
export async function presentAgentBrowser(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
visible: boolean;
|
||||
bounds?: AgentBrowserBounds;
|
||||
}): Promise<AgentBrowserSnapshot> {
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
'/api/agent-browser/present',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
visible: input.visible,
|
||||
...(input.bounds ? { bounds: input.bounds } : {}),
|
||||
}),
|
||||
@@ -123,13 +123,13 @@ export async function presentAgentBrowser(input: {
|
||||
}
|
||||
|
||||
export async function setAgentBrowserDiagnostics(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
enabled: boolean;
|
||||
}): Promise<AgentBrowserSnapshot> {
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
'/api/agent-browser/diagnostics',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
enabled: input.enabled,
|
||||
}),
|
||||
);
|
||||
@@ -137,14 +137,14 @@ export async function setAgentBrowserDiagnostics(input: {
|
||||
}
|
||||
|
||||
export async function navigateAgentBrowser(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
action: AgentBrowserNavigateAction;
|
||||
url?: string;
|
||||
}): Promise<AgentBrowserSnapshot> {
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
'/api/agent-browser/navigate',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
action: input.action,
|
||||
...(input.url ? { url: input.url } : {}),
|
||||
}),
|
||||
@@ -153,7 +153,7 @@ export async function navigateAgentBrowser(input: {
|
||||
}
|
||||
|
||||
export async function sendAgentBrowserCdp(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
method: string;
|
||||
params?: Record<string, unknown>;
|
||||
sessionRef?: string;
|
||||
@@ -162,7 +162,7 @@ export async function sendAgentBrowserCdp(input: {
|
||||
const response = await hostApiFetch<CdpResultEnvelope>(
|
||||
'/api/agent-browser/cdp/send',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
method: input.method,
|
||||
...(input.params ? { params: input.params } : {}),
|
||||
...(input.sessionRef ? { session_ref: input.sessionRef } : {}),
|
||||
@@ -173,7 +173,7 @@ export async function sendAgentBrowserCdp(input: {
|
||||
}
|
||||
|
||||
export async function readAgentBrowserEvents(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
after?: number;
|
||||
methods?: string[];
|
||||
limit?: number;
|
||||
@@ -182,7 +182,7 @@ export async function readAgentBrowserEvents(input: {
|
||||
const response = await hostApiFetch<EventPageEnvelope>(
|
||||
'/api/agent-browser/cdp/events',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
...(input.after !== undefined ? { after: input.after } : {}),
|
||||
...(input.methods ? { methods: input.methods } : {}),
|
||||
...(input.limit !== undefined ? { limit: input.limit } : {}),
|
||||
@@ -193,7 +193,7 @@ export async function readAgentBrowserEvents(input: {
|
||||
}
|
||||
|
||||
export async function readAgentBrowserPayload(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
handle: string;
|
||||
offset?: number;
|
||||
maxBytes?: number;
|
||||
@@ -201,7 +201,7 @@ export async function readAgentBrowserPayload(input: {
|
||||
const response = await hostApiFetch<PayloadEnvelope>(
|
||||
'/api/agent-browser/payload/read',
|
||||
jsonBody({
|
||||
project_path: input.projectPath,
|
||||
project_id: input.projectId,
|
||||
handle: input.handle,
|
||||
...(input.offset !== undefined ? { offset: input.offset } : {}),
|
||||
...(input.maxBytes !== undefined ? { max_bytes: input.maxBytes } : {}),
|
||||
@@ -211,21 +211,21 @@ export async function readAgentBrowserPayload(input: {
|
||||
}
|
||||
|
||||
export async function closeAgentBrowser(
|
||||
projectPath: string,
|
||||
projectId: string,
|
||||
): Promise<AgentBrowserSnapshot> {
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
'/api/agent-browser/close',
|
||||
jsonBody({ project_path: projectPath }),
|
||||
jsonBody({ project_id: projectId }),
|
||||
);
|
||||
return requireSuccess(response).browser;
|
||||
}
|
||||
|
||||
export async function resetAgentBrowserProfile(
|
||||
projectPath: string,
|
||||
projectId: string,
|
||||
): Promise<AgentBrowserSnapshot> {
|
||||
const response = await hostApiFetch<BrowserEnvelope>(
|
||||
'/api/agent-browser/reset-profile',
|
||||
jsonBody({ project_path: projectPath }),
|
||||
jsonBody({ project_id: projectId }),
|
||||
);
|
||||
return requireSuccess(response).browser;
|
||||
}
|
||||
|
||||
24
src/lib/works-square-token-points.ts
Normal file
24
src/lib/works-square-token-points.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { WorksTokenPointBalance } from './works-square';
|
||||
|
||||
const TOKEN_POINT_VALUE_PATTERN = /^(0|[1-9]\d*)(?:\.(\d{1,2}))?$/u;
|
||||
|
||||
export function formatWorksTokenPointValue(value: string | null | undefined): string | null {
|
||||
if (typeof value !== 'string') return null;
|
||||
const match = TOKEN_POINT_VALUE_PATTERN.exec(value.trim());
|
||||
if (!match) return null;
|
||||
|
||||
const whole = match[1].replace(/\B(?=(\d{3})+(?!\d))/gu, ',');
|
||||
const fraction = (match[2] ?? '').replace(/0+$/u, '');
|
||||
return fraction ? `${whole}.${fraction}` : whole;
|
||||
}
|
||||
|
||||
export function isWorksTokenPointBalanceExhausted(
|
||||
balance: WorksTokenPointBalance | null | undefined,
|
||||
): boolean {
|
||||
if (!balance) return false;
|
||||
if (!balance.can_manage_membership && typeof balance.shared_available === 'boolean') {
|
||||
return !balance.shared_available;
|
||||
}
|
||||
const remaining = formatWorksTokenPointValue(balance.total_remaining);
|
||||
return remaining !== null && /^0(?:\.0+)?$/u.test(remaining);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { WorksTokenUsage } from './works-square';
|
||||
|
||||
function isRemainingPercentExhausted(value: number | null | undefined): boolean {
|
||||
return typeof value === 'number' && Number.isFinite(value) && value <= 0;
|
||||
}
|
||||
|
||||
export function isWorksTokenUsageExhausted(
|
||||
usage: WorksTokenUsage | null | undefined,
|
||||
): boolean {
|
||||
return Boolean(usage && (
|
||||
isRemainingPercentExhausted(usage.five_hour_remaining_percent)
|
||||
|| isRemainingPercentExhausted(usage.weekly_remaining_percent)
|
||||
));
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export const WORKS_SQUARE_TOKEN_USAGE_STALE_EVENT = 'works-square-token-usage:stale';
|
||||
|
||||
export function dispatchWorksSquareTokenUsageStale(): void {
|
||||
if (typeof window === 'undefined' || typeof window.dispatchEvent !== 'function') {
|
||||
return;
|
||||
}
|
||||
if (typeof Event !== 'function') {
|
||||
return;
|
||||
}
|
||||
window.dispatchEvent(new Event(WORKS_SQUARE_TOKEN_USAGE_STALE_EVENT));
|
||||
}
|
||||
@@ -187,13 +187,26 @@ export type WorksSpeechTranscriptionInput = {
|
||||
model?: string;
|
||||
};
|
||||
|
||||
export type WorksTokenUsage = {
|
||||
five_hour_remaining_percent: number | null;
|
||||
five_hour_refresh_at?: string | null;
|
||||
weekly_remaining_percent: number | null;
|
||||
weekly_refresh_at?: string | null;
|
||||
plan_code?: string | null;
|
||||
plan_name?: string | null;
|
||||
export type WorksTokenPointBalance = {
|
||||
plan_code: string | null;
|
||||
plan_name: string | null;
|
||||
cycle_start: string | null;
|
||||
cycle_end: string | null;
|
||||
next_refresh_at: string | null;
|
||||
weekly_allowance: string | null;
|
||||
weekly_used: string | null;
|
||||
weekly_reserved: string | null;
|
||||
weekly_remaining: string | null;
|
||||
permanent_total: string | null;
|
||||
permanent_used: string | null;
|
||||
permanent_reserved: string | null;
|
||||
permanent_remaining: string | null;
|
||||
total_remaining: string | null;
|
||||
entitlement_source: 'self' | 'family_owner' | 'shared_group';
|
||||
family_shared: boolean;
|
||||
can_manage_membership: boolean;
|
||||
upgrade_action: 'self_service' | 'contact_family_owner';
|
||||
shared_available: boolean | null;
|
||||
};
|
||||
|
||||
export type PlazaCard = {
|
||||
@@ -402,16 +415,16 @@ export async function fetchMyWorksProjects(
|
||||
return assertSuccess(response, 'page', 'Failed to load your Works Square projects');
|
||||
}
|
||||
|
||||
export async function fetchWorksTokenUsage(accessToken: string): Promise<WorksTokenUsage> {
|
||||
const response = await hostApiFetch<WorksActionResponse<'usage', WorksTokenUsage>>(
|
||||
'/api/works/billing/token-usage',
|
||||
export async function fetchWorksTokenPointBalance(accessToken: string): Promise<WorksTokenPointBalance> {
|
||||
const response = await hostApiFetch<WorksActionResponse<'points', WorksTokenPointBalance>>(
|
||||
'/api/works/billing/points',
|
||||
{
|
||||
headers: {
|
||||
'X-NianCode-Access-Token': accessToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
return assertSuccess(response, 'usage', 'Failed to load Works Square token usage');
|
||||
return assertSuccess(response, 'points', 'Failed to load Works Square token points');
|
||||
}
|
||||
|
||||
export async function fetchMyWorksProjectStatus(
|
||||
|
||||
Reference in New Issue
Block a user