sync: update from private repo (2336949a)
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
oss-sync
2026-09-17 11:29:31 +00:00
parent 28f74c4e37
commit 57702b4f34
2139 changed files with 321270 additions and 17494 deletions
+194 -6
View File
@@ -1,5 +1,6 @@
// api.ts から分割(挙動不変): スペース(CRUD・メンバー・招待・ツールポリシー・Python パッケージ)。
import { BASE } from './client';
import type { SpaceTemplate } from '../../../src/spaces/space-templates';
// --- Spaces (個人/案件) ---------------------------------------------------
@@ -191,12 +192,36 @@ export interface ToolCategory {
export interface SpaceToolPolicy {
disabledSafe: string[];
enabledSensitive: string[];
/** 3 値: undefined = 未設定(全体設定を継承)/ true = 許可 / false = 遮断。 */
allowNetwork?: boolean;
}
/** サンドボックスから外部ネットワークへ出られるかの、いまの状態(issue #1015)。 */
export interface SandboxNetworkState {
/** ワークスペースの設定。null = 未設定(全体設定を継承)。 */
workspace: boolean | null;
/** 全体設定(config.yaml の safety.bash_allow_network)。 */
global: boolean;
/** 実際に適用される値。 */
effective: boolean;
/** effective がどちらの設定から来たか。 */
source: 'workspace' | 'global';
/** サンドボックス機構の選択。'off' のときこの切り替えは効かない。 */
sandboxMode: 'auto' | 'always' | 'off';
/**
* 隔離の下地(bwrap)が実際に動いたか(issue #1215)。
* サーバが 1 回だけ走らせた点検の結果。省略されるのは古いサーバの応答だけ。
*/
bwrapAvailable?: boolean;
/** Bash の制限を外す設定。true のときこの切り替えは効かない。 */
bashUnrestricted: boolean;
}
export interface SpaceToolPolicyResponse {
policy: SpaceToolPolicy;
categories: ToolCategory[];
sensitiveTools: { name: string; enabled: boolean }[];
sandboxNetwork?: SandboxNetworkState;
}
export async function fetchSpaceToolPolicy(spaceId: string): Promise<SpaceToolPolicyResponse> {
@@ -208,7 +233,8 @@ export async function fetchSpaceToolPolicy(spaceId: string): Promise<SpaceToolPo
export async function updateSpaceToolPolicy(
spaceId: string,
patch: { disabledSafe?: string[]; enabledSensitive?: string[] },
// allowNetwork: キーを送らなければ現状維持、null で未設定に戻す、boolean で設定。
patch: { disabledSafe?: string[]; enabledSensitive?: string[]; allowNetwork?: boolean | null },
): Promise<void> {
const res = await fetch(`${BASE}/local/spaces/${spaceId}/tool-policy`, {
method: 'PUT',
@@ -221,6 +247,118 @@ export async function updateSpaceToolPolicy(
}
}
// ─── Workspace Auto Prompter rules ───────────────────────────────────────
export type AutoPrompterTiming = 'always' | 'tool.before' | 'completion.before_accept';
export type AutoPrompterToolCategory =
| 'command_execution'
| 'internet_search'
| 'file_read'
| 'file_write'
| 'external_communication'
| 'browser'
| 'ssh';
export type AutoPrompterAction =
| { type: 'allow' }
| { type: 'deny'; reason: string }
| { type: 'advise'; instruction: string }
| { type: 'approval'; message: string };
export interface AutoPrompterRule {
id: string;
name?: string;
condition?: string;
version: number;
enabled: boolean;
timing: AutoPrompterTiming;
target?: {
toolNames?: string[];
toolCategories?: AutoPrompterToolCategory[];
};
scope?: {
pieces?: string[];
movements?: string[];
};
fireLimits?: {
perTask?: number;
perMovement?: number;
};
action: AutoPrompterAction;
}
export interface SpaceAutoPrompterResponse {
enabled: boolean;
rules: AutoPrompterRule[];
}
const autoPrompterBase = (spaceId: string): string =>
`${BASE}/local/spaces/${encodeURIComponent(spaceId)}/auto-prompter`;
const autoPrompterResponse = async (res: Response): Promise<SpaceAutoPrompterResponse> => {
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error ?? 'Failed to update Auto Prompter');
return data as SpaceAutoPrompterResponse;
};
export async function fetchSpaceAutoPrompter(spaceId: string): Promise<SpaceAutoPrompterResponse> {
return autoPrompterResponse(await fetch(autoPrompterBase(spaceId)));
}
export async function updateSpaceAutoPrompterEnabled(
spaceId: string,
enabled: boolean,
): Promise<SpaceAutoPrompterResponse> {
return autoPrompterResponse(await fetch(autoPrompterBase(spaceId), {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled }),
}));
}
export async function createSpaceAutoPrompterRule(
spaceId: string,
rule: AutoPrompterRule,
): Promise<AutoPrompterRule> {
const res = await fetch(`${autoPrompterBase(spaceId)}/rules`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(rule),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error ?? 'Failed to create Auto Prompter rule');
return data.rule as AutoPrompterRule;
}
export async function updateSpaceAutoPrompterRule(
spaceId: string,
rule: AutoPrompterRule,
): Promise<AutoPrompterRule> {
const res = await fetch(`${autoPrompterBase(spaceId)}/rules/${encodeURIComponent(rule.id)}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(rule),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error ?? 'Failed to update Auto Prompter rule');
return data.rule as AutoPrompterRule;
}
export async function deleteSpaceAutoPrompterRule(
spaceId: string,
ruleId: string,
version: number,
): Promise<void> {
const res = await fetch(`${autoPrompterBase(spaceId)}/rules/${encodeURIComponent(ruleId)}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ version }),
});
if (!res.ok) {
const data = await res.json().catch(() => ({}));
throw new Error(data?.error ?? 'Failed to delete Auto Prompter rule');
}
}
// ─── Per-space Python packages ────────────────────────────────────────────
export interface SpacePythonPackage {
name: string;
@@ -288,11 +426,27 @@ export interface SpaceWebhook {
// URL once saved (write-only secret).
}
export async function fetchSpaceWebhooks(spaceId: string): Promise<SpaceWebhook[]> {
export interface SpaceWebhookList {
webhooks: SpaceWebhook[];
/**
* Server-side master switch (`webhooks.enabled` in config.yaml). When
* false the delivery subsystem was never started, so a test send is
* refused before any connection is opened. The screen has to say so —
* without it the only feedback was a bare "送信失敗" (issue #1125).
*/
deliveryEnabled: boolean;
}
export async function fetchSpaceWebhooks(spaceId: string): Promise<SpaceWebhookList> {
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks`);
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error ?? 'Failed to fetch webhooks');
return (data?.webhooks ?? []) as SpaceWebhook[];
return {
webhooks: (data?.webhooks ?? []) as SpaceWebhook[],
// Absent field → treated as enabled. Blocking test sends on a server
// that is actually delivering would be the worse mistake of the two.
deliveryEnabled: data?.deliveryEnabled !== false,
};
}
export async function createSpaceWebhook(
@@ -347,14 +501,43 @@ export async function deleteSpaceWebhook(spaceId: string, webhookId: string): Pr
}
}
/**
* Why a test send failed, so the screen can word it differently (issue
* #1125): delivery is switched off server-side, the destination answered and
* refused (`status` carries its HTTP status), or nothing answered at all.
*/
export type SpaceWebhookTestFailureCode =
| 'delivery_disabled'
| 'rejected'
| 'network'
| 'blocked'
| 'invalid_url'
| 'not_found'
| 'not_implemented'
| 'internal';
export interface SpaceWebhookTestResult {
ok: boolean;
error?: string;
code?: SpaceWebhookTestFailureCode;
status?: number;
}
export async function testSendSpaceWebhook(
spaceId: string,
webhookId: string,
): Promise<{ ok: boolean; error?: string }> {
): Promise<SpaceWebhookTestResult> {
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks/${webhookId}/test`, { method: 'POST' });
const data = await res.json().catch(() => ({}));
if (!res.ok) return { ok: false, error: data?.error ?? 'Failed to send test notification' };
return data as { ok: boolean; error?: string };
if (!res.ok) {
return {
ok: false,
error: data?.error ?? 'Failed to send test notification',
code: data?.code,
status: data?.status,
};
}
return data as SpaceWebhookTestResult;
}
export async function createSpace(input: {
@@ -362,6 +545,11 @@ export async function createSpace(input: {
description?: string;
brandColor?: string | null;
visibility?: Space['visibility'];
/**
* 用途テンプレート(issue #993 S2-3)。差し替わるのは AGENTS.md の雛形だけで、
* ワークスペースの属性としては残らない。未指定なら従来どおりの雛形。
*/
template?: SpaceTemplate;
}): Promise<Space> {
const res = await fetch(`${BASE}/local/spaces`, {
method: 'POST',