@cjhyy/code-shell 0.1.7 → 0.3.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/CHANGELOG.md +108 -0
- package/README.md +35 -2
- package/dist/anthropic-DJXVKFMJ.js +1 -0
- package/dist/arena/index.js +1 -1
- package/dist/arena-MRBATZFD.js +3 -0
- package/dist/chunk-2OD6VR4N.js +2 -0
- package/dist/{chunk-RP26WO4R.js → chunk-5QIVXFCT.js} +1 -1
- package/dist/{chunk-NFH3UQ3E.js → chunk-AFMP73YP.js} +1 -1
- package/dist/{chunk-XDOWC7EG.js → chunk-D3TVASD2.js} +2 -2
- package/dist/chunk-DI26OUIU.js +2 -0
- package/dist/chunk-FZXY554D.js +2 -0
- package/dist/chunk-GGVAOPI7.js +1 -0
- package/dist/chunk-GKAQH2DG.js +2 -0
- package/dist/chunk-GYNO4R7R.js +2 -0
- package/dist/{chunk-Q4O2HGWS.js → chunk-K4HILJ6G.js} +3 -3
- package/dist/chunk-M7VU4YVY.js +49 -0
- package/dist/chunk-MLCTC53I.js +1 -0
- package/dist/{chunk-HIJ2XXGX.js → chunk-OWBYLMDD.js} +1 -1
- package/dist/chunk-SKIX2M5Z.js +4 -0
- package/dist/chunk-SV7H4FKT.js +3 -0
- package/dist/{chunk-Y2NS6HPO.js → chunk-WONQHE4P.js} +41 -41
- package/dist/{chunk-WOP6MJKW.js → chunk-X2S7ASQ2.js} +1 -1
- package/dist/chunk-Z5HKHAO7.js +336 -0
- package/dist/cli/commands/builtin/plugin-commands-registration.d.ts +12 -0
- package/dist/cli/commands/builtin/plugin-handler.d.ts +6 -0
- package/dist/cli/commands/registry.d.ts +9 -2
- package/dist/cli/main.js +140 -124
- package/dist/cli/onboarding.d.ts +7 -2
- package/dist/client-base-GSFXPP2Y.js +1 -0
- package/dist/compaction-L3Y6NG4N.js +1 -0
- package/dist/context/compaction.d.ts +2 -1
- package/dist/data/static-catalogs.d.ts +25 -0
- package/dist/devtools-FBX4HVVY.js +1 -0
- package/dist/engine/engine.d.ts +45 -0
- package/dist/engine/turn-loop.d.ts +45 -0
- package/dist/hooks/events.d.ts +84 -5
- package/dist/hooks/inject.d.ts +19 -0
- package/dist/hooks/shell-runner.d.ts +45 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/llm/api-key-sanitize.d.ts +22 -0
- package/dist/llm/capabilities/index.d.ts +20 -0
- package/dist/llm/capabilities/rules.d.ts +26 -0
- package/dist/llm/capabilities/types.d.ts +108 -0
- package/dist/llm/model-pool.d.ts +7 -0
- package/dist/llm/provider-catalog.d.ts +2 -0
- package/dist/llm/provider-kinds.d.ts +1 -1
- package/dist/llm/providers/openai.d.ts +45 -0
- package/dist/llm/retry.d.ts +12 -0
- package/dist/llm/stream-watchdog.d.ts +42 -0
- package/dist/llm/types.d.ts +8 -0
- package/dist/logging/logger.d.ts +24 -2
- package/dist/logging/session-recorder.d.ts +16 -3
- package/dist/manager-4XKLZHKE.js +1 -0
- package/dist/mcp-manager-3JGHEJO3.js +1 -0
- package/dist/model-fetcher-X5W5EASG.js +1 -0
- package/dist/openai-OQ6LLN5J.js +1 -0
- package/dist/{openrouter-models-AM6M52D6.js → openrouter-models-ZT4R2AE3.js} +1 -1
- package/dist/openrouter-sync-ARMVWY7S.js +1 -0
- package/dist/plugin-handler-GJISMH5Q.js +11 -0
- package/dist/plugins/gitOps.d.ts +23 -0
- package/dist/plugins/installedPlugins.d.ts +15 -0
- package/dist/plugins/knownMarketplaces.d.ts +10 -0
- package/dist/plugins/loadPluginHooks.d.ts +52 -0
- package/dist/plugins/marketplaceManager.d.ts +49 -0
- package/dist/plugins/parseMarketplaceInput.d.ts +16 -0
- package/dist/plugins/pluginCommandHook.d.ts +54 -0
- package/dist/plugins/pluginCommandsLoader.d.ts +25 -0
- package/dist/plugins/pluginInstaller.d.ts +36 -0
- package/dist/plugins/schemas.d.ts +9 -0
- package/dist/plugins/types.d.ts +73 -2
- package/dist/plugins/varRewrite.d.ts +42 -0
- package/dist/product/index.js +1 -1
- package/dist/protocol/client.d.ts +1 -1
- package/dist/protocol/helpers.d.ts +42 -0
- package/dist/render/clearTerminal.d.ts +9 -3
- package/dist/render/components/App.d.ts +1 -0
- package/dist/render/components/Static.d.ts +23 -0
- package/dist/render/devtools.d.ts +8 -4
- package/dist/render/dom.d.ts +2 -1
- package/dist/render/frame.d.ts +1 -0
- package/dist/render/index.d.ts +10 -0
- package/dist/render/ink.d.ts +24 -2
- package/dist/render/log-update.d.ts +12 -1
- package/dist/render/selection.d.ts +1 -1
- package/dist/run/index.js +1 -1
- package/dist/{seatbelt-WBYROQT6.js → seatbelt-L54CNI2Y.js} +5 -5
- package/dist/services/index.d.ts +1 -0
- package/dist/services/memory-orchestrator.d.ts +39 -0
- package/dist/settings/schema.d.ts +168 -21
- package/dist/skills/frontmatter.d.ts +13 -0
- package/dist/skills/index.d.ts +4 -4
- package/dist/skills/scanner.d.ts +11 -21
- package/dist/tool-summary-HJX6RHG4.js +2 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +55 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +35 -4
- package/dist/tool-system/builtin/agent-transcript-translator.d.ts +22 -0
- package/dist/tool-system/builtin/skill-prompt.d.ts +7 -0
- package/dist/tool-system/builtin/skill.d.ts +3 -1
- package/dist/tool-system/context.d.ts +23 -0
- package/dist/tool-system/executor.d.ts +5 -1
- package/dist/tool-system/permission.d.ts +1 -1
- package/dist/tool-system/sandbox/index.d.ts +7 -0
- package/dist/tool-system/task-guard.d.ts +30 -0
- package/dist/types.d.ts +48 -0
- package/dist/ui/components/AgentBlock.d.ts +5 -2
- package/dist/ui/components/AgentDock.d.ts +36 -0
- package/dist/ui/components/CommandInput.d.ts +12 -1
- package/dist/ui/components/MessageRow.d.ts +54 -0
- package/dist/ui/components/SpinnerWithVerb.d.ts +7 -1
- package/dist/ui/components/StatusLine.d.ts +5 -1
- package/dist/ui/components/TextInput.d.ts +9 -1
- package/dist/ui/components/VirtualMessageList.d.ts +30 -11
- package/dist/ui/dev-seed.d.ts +1 -0
- package/dist/ui/fullscreen-mode.d.ts +9 -0
- package/dist/ui/hooks/useVirtualScroll.d.ts +101 -0
- package/dist/ui/perf-probes.d.ts +22 -0
- package/dist/ui/query-guard.d.ts +35 -0
- package/dist/ui/slice-anchor.d.ts +44 -0
- package/dist/ui/store.d.ts +26 -1
- package/package.json +5 -3
- package/dist/anthropic-UBSB5AQH.js +0 -1
- package/dist/arena-OW55ZCHT.js +0 -3
- package/dist/chunk-2NS3JMNK.js +0 -1
- package/dist/chunk-B7K2OWKC.js +0 -2
- package/dist/chunk-EWWK56K6.js +0 -2
- package/dist/chunk-KCXSARAA.js +0 -1
- package/dist/chunk-NMBYBGC7.js +0 -250
- package/dist/chunk-NVAZJ5XS.js +0 -2
- package/dist/chunk-PGANL6F2.js +0 -3
- package/dist/chunk-UDPUTFQT.js +0 -2
- package/dist/chunk-W47Z7MGS.js +0 -33
- package/dist/client-base-6ZZJJYDY.js +0 -1
- package/dist/compaction-ECVQVOCT.js +0 -1
- package/dist/devtools-SGDUOOM4.js +0 -1
- package/dist/manager-C3TDN6MS.js +0 -1
- package/dist/mcp-manager-OP4XYV53.js +0 -1
- package/dist/model-fetcher-BJ64META.js +0 -1
- package/dist/openai-KEWQ54TM.js +0 -1
- package/dist/openrouter-sync-5JNBL3Z6.js +0 -1
- package/dist/plugins/loader.d.ts +0 -72
- package/dist/skills/matcher.d.ts +0 -21
- package/dist/tool-summary-5UE62VU4.js +0 -2
- package/skills-builtin/codeshell-help.md +0 -135
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (chat-completion only — embeddings / TTS / image generation are
|
|
7
7
|
* filtered out so they don't show up in the model picker).
|
|
8
8
|
*/
|
|
9
|
-
export type ProviderKindName = "openai" | "anthropic" | "deepseek" | "xai" | "mistral" | "groq" | "google" | "openrouter" | "ollama" | "custom";
|
|
9
|
+
export type ProviderKindName = "openai" | "anthropic" | "deepseek" | "zai" | "xai" | "mistral" | "groq" | "google" | "openrouter" | "ollama" | "custom";
|
|
10
10
|
export type ProviderProtocol = "openai-compat" | "anthropic-style" | "gemini" | "ollama";
|
|
11
11
|
export interface ProviderKindMeta {
|
|
12
12
|
label: string;
|
|
@@ -1,15 +1,59 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenAI GPT provider using openai SDK.
|
|
3
|
+
*
|
|
4
|
+
* Serves every OpenAI-compatible endpoint we support (OpenAI, DeepSeek,
|
|
5
|
+
* OpenRouter, Z.AI, xAI, Mistral, Groq, Gemini-OpenAI-compat, Ollama,
|
|
6
|
+
* custom). Per-(provider, model) request-shape divergence — token-limit
|
|
7
|
+
* field name, rejected sampling params, thinking knob, reasoning echo —
|
|
8
|
+
* is resolved through `capabilitiesFor()`, not hardcoded.
|
|
3
9
|
*/
|
|
4
10
|
import type { LLMConfig, LLMResponse } from "../../types.js";
|
|
5
11
|
import type { CreateMessageOptions } from "../types.js";
|
|
6
12
|
import { LLMClientBase } from "../client-base.js";
|
|
13
|
+
interface RunStreamOpts {
|
|
14
|
+
idleTimeoutMs?: number;
|
|
15
|
+
requestId?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Per-chunk handler — invoked synchronously with the raw chunk for the
|
|
18
|
+
* provider to do its own parsing. Returns the text delta (or "") for
|
|
19
|
+
* the watchdog-side text accumulator used in tests.
|
|
20
|
+
*/
|
|
21
|
+
onChunk?: (chunk: any) => string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Consume an async iterable of stream chunks with an idle watchdog.
|
|
25
|
+
* Returns the accumulated text — either from onChunk return values, or
|
|
26
|
+
* by extracting choices[0].delta.content from raw chunks (useful in tests
|
|
27
|
+
* that call runStreamWithWatchdog directly without an onChunk handler).
|
|
28
|
+
*
|
|
29
|
+
* The watchdog is active whenever opts.idleTimeoutMs is explicitly provided,
|
|
30
|
+
* or when STREAM_WATCHDOG_CONFIG.enabled is true. When active, each call to
|
|
31
|
+
* iterator.next() races against an idle deadline; if the deadline fires first
|
|
32
|
+
* the function rejects with StreamIdleTimeoutError.
|
|
33
|
+
*/
|
|
34
|
+
export declare function runStreamWithWatchdog<T = any>(stream: AsyncIterable<T>, opts?: RunStreamOpts): Promise<string>;
|
|
7
35
|
export declare class OpenAIClient extends LLMClientBase {
|
|
8
36
|
private _client;
|
|
37
|
+
private _forceMaxCompletionTokens;
|
|
9
38
|
constructor(config: LLMConfig);
|
|
10
39
|
protected initClient(): void;
|
|
11
40
|
private get client();
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the capability descriptor for the current (provider kind, model)
|
|
43
|
+
* pair. Cached for the lifetime of the client — model never changes
|
|
44
|
+
* mid-client. `providerKind` defaults to "openai" because legacy LLMConfig
|
|
45
|
+
* paths (arena, env-derived) don't always populate it; for those, the
|
|
46
|
+
* built-in rules table treats them as plain OpenAI.
|
|
47
|
+
*/
|
|
48
|
+
private _capability;
|
|
49
|
+
private get capability();
|
|
12
50
|
createMessage(options: CreateMessageOptions): Promise<LLMResponse>;
|
|
51
|
+
/**
|
|
52
|
+
* Build the request body honoring the model's capability descriptor.
|
|
53
|
+
* Centralized so both streaming and non-streaming paths agree on the
|
|
54
|
+
* exact shape.
|
|
55
|
+
*/
|
|
56
|
+
private buildRequestBody;
|
|
13
57
|
private nonStreamMessage;
|
|
14
58
|
private streamMessage;
|
|
15
59
|
private processChoice;
|
|
@@ -17,3 +61,4 @@ export declare class OpenAIClient extends LLMClientBase {
|
|
|
17
61
|
private convertTools;
|
|
18
62
|
private handleApiError;
|
|
19
63
|
}
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry classification — which errors trigger an automatic retry of the
|
|
3
|
+
* streaming LLM call?
|
|
4
|
+
*
|
|
5
|
+
* Stream-idle timeouts are retried — the upstream may have just recovered.
|
|
6
|
+
* User-initiated aborts (AbortError) are never retried — the user explicitly
|
|
7
|
+
* asked for the work to stop.
|
|
8
|
+
*
|
|
9
|
+
* Other transient errors (5xx, 429, ECONNRESET) are out of scope for this
|
|
10
|
+
* iteration; add them here as they become observed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isRetryable(err: unknown): boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream Idle Watchdog — guarantees an upper bound on the time a streaming
|
|
3
|
+
* LLM call can spend with no bytes arriving. Without this, a wedged HTTP/2
|
|
4
|
+
* connection can hang the session indefinitely; the SDK's request timeout
|
|
5
|
+
* only covers the initial fetch, not the streaming body.
|
|
6
|
+
*
|
|
7
|
+
* Disabled by default. Enabled via env CODESHELL_ENABLE_STREAM_WATCHDOG=1.
|
|
8
|
+
*/
|
|
9
|
+
export interface StreamWatchdogOptions {
|
|
10
|
+
/** Abort the stream when no chunks arrive within this window. */
|
|
11
|
+
idleTimeoutMs: number;
|
|
12
|
+
/** Called when the watchdog decides to abort. */
|
|
13
|
+
onTimeout: () => void;
|
|
14
|
+
/**
|
|
15
|
+
* Called at idleTimeoutMs/2 (or warningMs if provided). Logging only —
|
|
16
|
+
* the watchdog does not abort on warning. The argument is the configured
|
|
17
|
+
* warning threshold (NOT real-time elapsed) so callers can format the log
|
|
18
|
+
* without re-deriving it.
|
|
19
|
+
*/
|
|
20
|
+
onWarning?: (warnThresholdMs: number) => void;
|
|
21
|
+
/** Override the warning trigger; defaults to idleTimeoutMs / 2. */
|
|
22
|
+
warningMs?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface StreamWatchdog {
|
|
25
|
+
/** Re-arm both timers — call after every chunk. */
|
|
26
|
+
reset(): void;
|
|
27
|
+
/** Clear all timers permanently — call in finally. */
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
export declare class StreamIdleTimeoutError extends Error {
|
|
31
|
+
idleMs: number;
|
|
32
|
+
requestId?: string | undefined;
|
|
33
|
+
readonly kind = "stream-idle-timeout";
|
|
34
|
+
constructor(idleMs: number, requestId?: string | undefined);
|
|
35
|
+
}
|
|
36
|
+
export declare function createStreamWatchdog(opts: StreamWatchdogOptions): StreamWatchdog;
|
|
37
|
+
/** Environment-driven defaults. Read once at import time is fine — these never change inside a process. */
|
|
38
|
+
export declare const STREAM_WATCHDOG_CONFIG: {
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
idleTimeoutMs: number;
|
|
41
|
+
retries: number;
|
|
42
|
+
};
|
package/dist/llm/types.d.ts
CHANGED
|
@@ -19,6 +19,14 @@ export interface CreateMessageOptions {
|
|
|
19
19
|
* @default true
|
|
20
20
|
*/
|
|
21
21
|
recordUsage?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* DeepSeek V4 thinking-mode switch. "enabled" is the endpoint default;
|
|
24
|
+
* "disabled" turns reasoning off (faster, cheaper, no `reasoning_content`
|
|
25
|
+
* on the reply). Ignored by every provider except DeepSeek V4 — the OpenAI
|
|
26
|
+
* SDK forwards unknown top-level fields verbatim, so it's harmless on
|
|
27
|
+
* other compatible endpoints.
|
|
28
|
+
*/
|
|
29
|
+
thinking?: "enabled" | "disabled";
|
|
22
30
|
}
|
|
23
31
|
export interface LLMUsageTracker {
|
|
24
32
|
records: TokenUsage[];
|
package/dist/logging/logger.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unified file logger for code-shell.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Sinks (JSON Lines), routed by `cat`:
|
|
5
|
+
* ~/.code-shell/logs/ui-ink-YYYY-MM-DD.log
|
|
6
|
+
* — UI/ink chatter: stream events, ctx render, ink screen diffs.
|
|
7
|
+
* ~/.code-shell/logs/engine-YYYY-MM-DD.log
|
|
8
|
+
* — everything else: engine, llm, tool, context, mcp, sandbox, ...
|
|
9
|
+
*
|
|
10
|
+
* Routing is by entry `cat`: cat ∈ {ui, ink, render, stream} → ui-ink bucket;
|
|
11
|
+
* anything else → engine bucket. Run scripts/logs.sh to query both at once
|
|
12
|
+
* (merge sorted by timestamp, filter by sid, etc).
|
|
5
13
|
*
|
|
6
14
|
* Level defaults:
|
|
7
15
|
* - Local dev (CODE_SHELL_DEV=1, or running from src/, or --debug) → "debug"
|
|
@@ -9,13 +17,27 @@
|
|
|
9
17
|
* - CODE_SHELL_LOG_LEVEL overrides everything.
|
|
10
18
|
*
|
|
11
19
|
* Category filter (--debug=mcp,api or CODE_SHELL_DEBUG=mcp,api):
|
|
12
|
-
* When set, only logs whose `cat` matches are written.
|
|
20
|
+
* When set, only debug logs whose `cat` matches are written.
|
|
13
21
|
*
|
|
14
22
|
* Disable entirely: CODE_SHELL_LOG=0
|
|
15
23
|
*/
|
|
16
24
|
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
17
25
|
export declare function setCurrentSid(sid: string): void;
|
|
18
26
|
export declare function getCurrentSid(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Run `fn` inside an ALS scope tagged with `sid`. All log lines emitted
|
|
29
|
+
* synchronously or via `await` inside `fn` resolve `getCurrentSid()` to
|
|
30
|
+
* this `sid` — concurrent Engine.run invocations no longer race on a
|
|
31
|
+
* module global.
|
|
32
|
+
*/
|
|
33
|
+
export declare function runWithSid<T>(sid: string, fn: () => T | Promise<T>): T | Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Bind `sid` to the *current* async context without needing a callback.
|
|
36
|
+
* The binding lasts until the current async stack unwinds; concurrent
|
|
37
|
+
* sibling async chains keep their own bindings. Engine.run uses this so
|
|
38
|
+
* we don't have to indent the entire (long) method body into a callback.
|
|
39
|
+
*/
|
|
40
|
+
export declare function enterSid(sid: string): void;
|
|
19
41
|
export declare function getInMemoryErrors(): ReadonlyArray<{
|
|
20
42
|
msg: string;
|
|
21
43
|
t: string;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-session verbose recorder for local-dev runs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Layout (per day, split by bucket):
|
|
5
|
+
* <repo>/log/<YYYY-MM-DD>/engine/session-<sid>.jsonl
|
|
6
|
+
* — unified timeline: LLM, tools, session events, AND UI events
|
|
7
|
+
* (UI events are dual-written so this file is the full story.)
|
|
8
|
+
* <repo>/log/<YYYY-MM-DD>/ui/session-<sid>.jsonl
|
|
9
|
+
* — UI-only events (stream events received, ctx renders, chatStore
|
|
10
|
+
* mutations). Open when chasing a display bug.
|
|
11
|
+
*
|
|
12
|
+
* Same sid → same filename in both folders. Diff/merge by sid to align
|
|
13
|
+
* "what the model said" with "what the UI did about it."
|
|
7
14
|
*
|
|
8
15
|
* Why a separate sink from logger.ts?
|
|
9
16
|
* - logger.ts is the terse process-wide log (~/.code-shell/logs/) and stays
|
|
@@ -69,6 +76,12 @@ export declare function recordToolResult(sid: string, result: {
|
|
|
69
76
|
error?: string;
|
|
70
77
|
}): void;
|
|
71
78
|
export declare function recordEvent(sid: string, name: string, data?: Record<string, unknown>): void;
|
|
79
|
+
/**
|
|
80
|
+
* Record a UI-side event. Goes into both engine.jsonl (unified timeline) and
|
|
81
|
+
* ui.jsonl (focused view). Use from the UI when chasing display bugs — pass
|
|
82
|
+
* the current sessionId.
|
|
83
|
+
*/
|
|
84
|
+
export declare function recordUIEvent(sid: string | undefined, name: string, data?: Record<string, unknown>): void;
|
|
72
85
|
export declare function recordSessionEnd(sid: string, info: {
|
|
73
86
|
reason?: string;
|
|
74
87
|
turns?: number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{c as SettingsManager}from'./chunk-FZXY554D.js';import'./chunk-3QP5BQ3L.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{a as MCPManager}from'./chunk-D3TVASD2.js';import'./chunk-DI26OUIU.js';import'./chunk-3QP5BQ3L.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{b as fetchModelList}from'./chunk-2OD6VR4N.js';import'./chunk-P6JSTIFM.js';import'./chunk-3QP5BQ3L.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{b as OpenAIClient,a as runStreamWithWatchdog}from'./chunk-SV7H4FKT.js';import'./chunk-O5HFCH2U.js';import'./chunk-OWBYLMDD.js';import'./chunk-FU7AHZNN.js';import'./chunk-DI26OUIU.js';import'./chunk-3QP5BQ3L.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{d as findOpenRouterModel,c as getOpenRouterModels,b as getOpenRouterSnapshot,e as listOpenRouterModelsByVendor,a as setOpenRouterSnapshot}from'./chunk-
|
|
1
|
+
export{d as findOpenRouterModel,c as getOpenRouterModels,b as getOpenRouterSnapshot,e as listOpenRouterModelsByVendor,a as setOpenRouterSnapshot}from'./chunk-GKAQH2DG.js';import'./chunk-3QP5BQ3L.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{a as syncOpenRouterCatalog}from'./chunk-AFMP73YP.js';export{b as getOpenRouterSnapshot}from'./chunk-GKAQH2DG.js';import'./chunk-3QP5BQ3L.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {g,f,e,d,i}from'./chunk-SKIX2M5Z.js';import {h,a,b}from'./chunk-3QP5BQ3L.js';import {existsSync,readFileSync,mkdirSync,writeFileSync,rmSync,readdirSync,statSync,cpSync,mkdtempSync}from'fs';import {join,dirname,isAbsolute,resolve}from'path';import {homedir,tmpdir}from'os';import {spawn}from'child_process';h();h();function H(e){let r=e.trim();if(r==="")return null;if((r.startsWith("/")||/^[a-zA-Z]:[\\/]/.test(r))&&r.endsWith(".git"))return {source:"git",url:r};if(r.match(/^[a-zA-Z0-9._-]+@[^:\s]+:[^\s]+$/))return {source:"git",url:r};if(r.startsWith("https://")||r.startsWith("http://")){let i;try{i=new URL(r);}catch{return null}return i.hostname==="github.com"||i.hostname==="www.github.com"?i.pathname.match(/^\/([^/]+\/[^/]+?)(\/|\.git|$)/)?{source:"git",url:r.endsWith(".git")?r:`${r}.git`}:null:r.endsWith(".git")?{source:"git",url:r}:null}let n=r.match(/^([A-Za-z0-9][A-Za-z0-9._-]*)\/([A-Za-z0-9._-]+?)(\.git)?$/);if(n){let i=n[1],s=n[2];return {source:"github",repo:`${i}/${s}`}}return null}a(H,"parseMarketplaceInput");function q(e){if(e.source==="github"){let i=e.repo.split("/");return i[i.length-1].toLowerCase()}let t=e.url.replace(/\.git$/,"").split(/[/:]/).filter(Boolean);return (t[t.length-1]??"marketplace").toLowerCase()}a(q,"deriveMarketplaceName");h();h();async function x(e,r,t=6e4){return new Promise(n=>{let i=spawn("git",e,{cwd:r,stdio:["ignore","pipe","pipe"]}),s="",o="";i.stdout.on("data",l=>s+=l.toString()),i.stderr.on("data",l=>o+=l.toString());let a=setTimeout(()=>{i.kill("SIGKILL"),n({ok:false,error:`git ${e.join(" ")} timed out after ${t}ms`});},t);i.on("close",l=>{clearTimeout(a),n(l===0?{ok:true,stdout:s.trim()}:{ok:false,error:`git ${e.join(" ")} exited ${l}: ${o.trim()||"unknown error"}`});}),i.on("error",l=>{clearTimeout(a),n({ok:false,error:`git ${e.join(" ")} failed: ${l.message}`});});})}a(x,"runGit");async function $(e,r,t){let n=["clone","--depth","1"];return t?.ref&&n.push("--branch",t.ref),n.push("--",e,r),x(n)}a($,"gitClone");async function C(e){return x(["rev-parse","HEAD"],e)}a(C,"gitRevParseHead");async function z(e,r){let t=["fetch","--depth","1","origin"];r&&t.push(r);let n=await x(t,e);return n.ok?x(["reset","--hard",r?`origin/${r}`:"FETCH_HEAD"],e):n}a(z,"gitFetchAndReset");function j(e){return `https://github.com/${e}.git`}a(j,"githubRepoToCloneUrl");h();function Se(){return process.env.HOME??homedir()}a(Se,"userHome");function V(){return join(Se(),".code-shell","plugins","known_marketplaces.json")}a(V,"knownMarketplacesPath");function m(){let e=V();if(!existsSync(e))return {};try{let r=JSON.parse(readFileSync(e,"utf-8"));if(r&&typeof r=="object"&&!Array.isArray(r))return r}catch{}return {}}a(m,"readKnownMarketplaces");function J(e){let r=V();mkdirSync(dirname(r),{recursive:true}),writeFileSync(r,JSON.stringify(e,null,2)+`
|
|
2
|
+
`,"utf-8");}a(J,"writeKnownMarketplaces");function B(e,r){let t=m();t[e]=r,J(t);}a(B,"upsertKnownMarketplace");function N(e){let r=m();return e in r?(delete r[e],J(r),true):false}a(N,"removeKnownMarketplace");h();function S(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}a(S,"isObject");function Me(e,r){if(typeof e=="string")return e.length===0?{ok:false,error:`${r}: source string is empty`}:{ok:true,value:e};if(!S(e))return {ok:false,error:`${r}: source must be a string or object`};let t=e.source;return t==="git"?typeof e.url!="string"||!e.url?{ok:false,error:`${r}: git source requires url`}:{ok:true,value:{source:"git",url:e.url,ref:typeof e.ref=="string"?e.ref:void 0,sha:typeof e.sha=="string"?e.sha:void 0}}:t==="github"?typeof e.repo!="string"||!e.repo.includes("/")?{ok:false,error:`${r}: github source requires repo "owner/name"`}:{ok:true,value:{source:"github",repo:e.repo,ref:typeof e.ref=="string"?e.ref:void 0,sha:typeof e.sha=="string"?e.sha:void 0}}:t==="git-subdir"?typeof e.url!="string"||!e.url?{ok:false,error:`${r}: git-subdir source requires url`}:typeof e.path!="string"||!e.path?{ok:false,error:`${r}: git-subdir source requires path`}:{ok:true,value:{source:"git-subdir",url:e.url,path:e.path,ref:typeof e.ref=="string"?e.ref:void 0,sha:typeof e.sha=="string"?e.sha:void 0}}:{ok:false,error:`${r}: unsupported source type "${String(t)}" (MVP supports git, github, git-subdir, or a string path)`}}a(Me,"validatePluginEntrySource");function be(e,r){let t=`plugins[${r}]`;if(!S(e))return {ok:false,error:`${t}: must be an object`};if(typeof e.name!="string"||!e.name)return {ok:false,error:`${t}: name is required`};if(e.source===void 0)return {ok:false,error:`${t}: source is required`};let n=Me(e.source,`${t}.source`);if(!n.ok)return n;let i;if(e.author!==void 0){if(!S(e.author)||typeof e.author.name!="string")return {ok:false,error:`${t}.author: must be an object with name`};i={name:e.author.name,email:typeof e.author.email=="string"?e.author.email:void 0};}return {ok:true,value:{name:e.name,description:typeof e.description=="string"?e.description:void 0,author:i,category:typeof e.category=="string"?e.category:void 0,source:n.value,homepage:typeof e.homepage=="string"?e.homepage:void 0}}}a(be,"validatePluginEntry");function L(e){if(!S(e))return {ok:false,error:"marketplace.json: not an object"};if(typeof e.name!="string"||!e.name)return {ok:false,error:"marketplace.json: name is required"};if(!S(e.owner)||typeof e.owner.name!="string")return {ok:false,error:"marketplace.json: owner.name is required"};if(!Array.isArray(e.plugins))return {ok:false,error:"marketplace.json: plugins must be an array"};let r=[];for(let t=0;t<e.plugins.length;t++){let n=be(e.plugins[t],t);if(!n.ok)return n;r.push(n.value);}return {ok:true,value:{name:e.name,description:typeof e.description=="string"?e.description:void 0,owner:{name:e.owner.name,email:typeof e.owner.email=="string"?e.owner.email:void 0},plugins:r}}}a(L,"validateMarketplace");function Re(){return process.env.HOME??homedir()}a(Re,"userHome");function W(){return join(Re(),".code-shell","plugins","marketplaces")}a(W,"marketplacesRoot");function D(e){return join(W(),e)}a(D,"marketplaceDir");function Z(e){return join(D(e),".claude-plugin","marketplace.json")}a(Z,"marketplaceJsonPath");function xe(e){return e.source==="github"?j(e.repo):e.url}a(xe,"sourceToCloneUrl");async function Y(e,r){let t=D(e),i=m()[e];if(i&&JSON.stringify(i.source)===JSON.stringify(r)&&existsSync(t)){let g=(r.source==="git",void 0);await z(t,g);}else {existsSync(t)&&rmSync(t,{recursive:true,force:true}),mkdirSync(W(),{recursive:true});let g=await $(xe(r),t);if(!g.ok)return {ok:false,error:g.error}}let o=Z(e);if(!existsSync(o))return rmSync(t,{recursive:true,force:true}),{ok:false,error:`Marketplace ${e}: .claude-plugin/marketplace.json not found in the cloned repository.`};let a;try{a=JSON.parse(readFileSync(o,"utf-8"));}catch(g){return rmSync(t,{recursive:true,force:true}),{ok:false,error:`Marketplace ${e}: failed to parse marketplace.json: ${g.message}`}}let l=L(a);if(!l.ok)return rmSync(t,{recursive:true,force:true}),{ok:false,error:`Marketplace ${e}: ${l.error}`};let d={source:r,installLocation:t,lastUpdated:new Date().toISOString()};return B(e,d),{ok:true,name:e,marketplace:l.value,replaced:!!i}}a(Y,"addMarketplace");function Q(e){let r=N(e),t=D(e);return existsSync(t)&&rmSync(t,{recursive:true,force:true}),r}a(Q,"removeMarketplace");function F(e){if(!m()[e])return null;let t=Z(e);if(!existsSync(t))return null;let n;try{n=JSON.parse(readFileSync(t,"utf-8"));}catch{return null}let i=L(n);return i.ok?i.value:null}a(F,"loadMarketplace");function X(){let e=m(),r=[];for(let[t,n]of Object.entries(e)){let i=F(t);r.push({name:t,source:n.source,installLocation:n.installLocation,lastUpdated:n.lastUpdated,pluginCount:i?i.plugins.length:-1});}return r.sort((t,n)=>t.name.localeCompare(n.name))}a(X,"listMarketplaces");h();h();var K="CLAUDE_PLUGIN_ROOT",te="CODESHELL_PLUGIN_ROOT",Ie=8192;function Oe(e){let r=Math.min(e.length,Ie);for(let t=0;t<r;t++)if(e[t]===0)return true;return false}a(Oe,"isLikelyBinary");function ne(e,r){let t;try{t=readdirSync(e,{withFileTypes:!0});}catch{return}for(let n of t){let i=join(e,n.name);if(n.isSymbolicLink())continue;if(n.isDirectory()){if(n.name===".git")continue;ne(i,r);continue}if(!n.isFile())continue;let s;try{s=readFileSync(i);}catch{continue}if(r.filesScanned+=1,Oe(s))continue;let o=s.toString("utf8");if(!o.includes(K))continue;let a=o.split(K).join(te);try{writeFileSync(i,a,"utf8"),r.filesRewritten+=1,r.rewrittenPaths.push(i);}catch{}}}a(ne,"walkAndRewrite");function ie(e){let r={filesScanned:0,filesRewritten:0,rewrittenPaths:[]},t=false;try{t=statSync(e).isDirectory();}catch{t=false;}if(!t)return r;ne(e,r);let n={rewrittenAt:new Date().toISOString(),from:K,to:te,filesScanned:r.filesScanned,filesRewritten:r.filesRewritten,note:"codeshell rewrote plugin files at install time so ${CLAUDE_PLUGIN_ROOT} placeholders use codeshell's native env var. Upstream plugin sources are unchanged; only this local copy was modified."};try{writeFileSync(join(e,".code-shell-installed.json"),JSON.stringify(n,null,2)+`
|
|
3
|
+
`,"utf8");}catch{}return r}a(ie,"rewritePluginVars");function Ke(){return process.env.HOME??homedir()}a(Ke,"userHome");function se(){return join(Ke(),".code-shell","plugins","cache")}a(se,"pluginCacheRoot");function E(e,r,t){return join(se(),e,r,t)}a(E,"pluginCacheDir");async function _e(e,r,t){let n=isAbsolute(r)?r:resolve(e,r);return existsSync(n)?(mkdirSync(dirname(t),{recursive:true}),existsSync(t)&&rmSync(t,{recursive:true,force:true}),cpSync(n,t,{recursive:true}),{ok:true,sha:void 0}):{ok:false,error:`plugin source path "${r}" not found in marketplace`}}a(_e,"materializePath");async function Ge(e,r,t){mkdirSync(dirname(t),{recursive:true}),existsSync(t)&&rmSync(t,{recursive:true,force:true});let n=await $(e,t,r?{ref:r}:void 0);if(!n.ok)return {ok:false,error:n.error};let i=await C(t);return i.ok?{ok:true,sha:i.stdout}:{ok:false,error:i.error}}a(Ge,"materializeGit");async function He(e,r,t,n){let i=mkdtempSync(join(tmpdir(),"plugin-clone-"));try{let s=await $(e,i+"/repo",t?{ref:t}:void 0);if(!s.ok)return {ok:!1,error:s.error};let o=await C(i+"/repo");if(!o.ok)return {ok:!1,error:o.error};let a=join(i,"repo",r);return existsSync(a)?(mkdirSync(dirname(n),{recursive:!0}),existsSync(n)&&rmSync(n,{recursive:!0,force:!0}),cpSync(a,n,{recursive:!0}),{ok:!0,sha:o.stdout}):{ok:!1,error:`git-subdir path "${r}" not found in cloned repository`}}finally{rmSync(i,{recursive:true,force:true});}}a(He,"materializeGitSubdir");function oe(e){return e?e.slice(0,12):"unknown"}a(oe,"shortSha");async function qe(e,r,t,n){let i=E(t,n,"_pending_");if(typeof e=="string"){let s=await _e(r,e,i);if(!s.ok)return s;let o=E(t,n,"local");return existsSync(o)&&rmSync(o,{recursive:true,force:true}),mkdirSync(dirname(o),{recursive:true}),cpSync(i,o,{recursive:true}),rmSync(i,{recursive:true,force:true}),{ok:true,cacheDir:o,version:"local",sha:void 0}}if(e.source==="git"||e.source==="github"){let s=e.source==="github"?j(e.repo):e.url,o=await Ge(s,e.ref,i);if(!o.ok)return existsSync(i)&&rmSync(i,{recursive:true,force:true}),o;let a=oe(o.sha),l=E(t,n,a);return existsSync(l)&&rmSync(l,{recursive:true,force:true}),mkdirSync(dirname(l),{recursive:true}),cpSync(i,l,{recursive:true}),rmSync(i,{recursive:true,force:true}),{ok:true,cacheDir:l,version:a,sha:o.sha}}if(e.source==="git-subdir"){let s=await He(e.url,e.path,e.ref,i);if(!s.ok)return existsSync(i)&&rmSync(i,{recursive:true,force:true}),s;let o=oe(s.sha),a=E(t,n,o);return existsSync(a)&&rmSync(a,{recursive:true,force:true}),mkdirSync(dirname(a),{recursive:true}),cpSync(i,a,{recursive:true}),rmSync(i,{recursive:true,force:true}),{ok:true,cacheDir:a,version:o,sha:s.sha}}return {ok:false,error:`unsupported source type "${e.source}"`}}a(qe,"materialize");async function ue(e$1,r){let n=m()[r];if(!n)return {ok:false,error:`marketplace "${r}" not found. Run /plugin marketplace add first.`};let i=F(r);if(!i)return {ok:false,error:`marketplace "${r}" is registered but its manifest could not be loaded.`};let s=i.plugins.find(fe=>fe.name===e$1);if(!s)return {ok:false,error:`plugin "${e$1}" not found in marketplace "${r}".`};let o=await qe(s.source,n.installLocation,r,e$1);if(!o.ok)return o;let a=ie(o.cacheDir),l=g(e$1,r);f(l);let d=new Date().toISOString(),g$1={scope:"user",installPath:o.cacheDir,version:o.version,installedAt:d,lastUpdated:d,...o.sha?{gitCommitSha:o.sha}:{}};return e(l,g$1),{ok:true,entry:g$1,freshlyCloned:true,varRewrite:{filesScanned:a.filesScanned,filesRewritten:a.filesRewritten}}}a(ue,"installPlugin");function ae(e,r){let t=g(e,r),i=d().plugins[t],s=false;if(i){for(let l of i)l.installPath&&existsSync(l.installPath)&&(rmSync(l.installPath,{recursive:true,force:true}),s=true);let a=join(se(),r,e);try{b("fs").rmdirSync(a);}catch{}}let o=f(t);return {ok:o||s,removedFromManifest:o,removedFromDisk:s}}a(ae,"uninstallPlugin");function le(){let e=d(),r=[];for(let[t,n]of Object.entries(e.plugins))for(let i of n)r.push({key:t,entry:i});return r.sort((t,n)=>t.key.localeCompare(n.key)),r}a(le,"listInstalled");var _=["Usage:"," /plugin marketplace add <git-url-or-owner/repo>"," /plugin marketplace remove <name>"," /plugin marketplace list"," /plugin install <plugin>@<marketplace>"," /plugin uninstall <plugin>@<marketplace>"," /plugin list"].join(`
|
|
4
|
+
`);function ce(e){let r=e.lastIndexOf("@");return r<=0||r===e.length-1?null:{plugin:e.slice(0,r),marketplace:e.slice(r+1)}}a(ce,"splitInstallKey");async function Ar(e){let r=e.trim().split(/\s+/).filter(Boolean);if(r.length===0)return _;let t=r[0];if(t==="marketplace"){let n=r[1];if(n==="add"){let i=r.slice(2).join(" ").trim();if(!i)return "Usage: /plugin marketplace add <git-url-or-owner/repo>";let s=H(i);if(!s)return `Cannot parse "${i}" as a marketplace source.
|
|
5
|
+
Supported forms: owner/repo, https://...git, git@host:owner/repo[.git], /abs/path/to/repo.git`;let o=q(s),a=await Y(o,s);if(!a.ok)return `Failed to add marketplace "${o}": ${a.error}`;let l=[a.replaced?`Refreshed marketplace "${a.name}"`:`Added marketplace "${a.name}"`,` plugins available: ${a.marketplace.plugins.length}`];for(let d of a.marketplace.plugins.slice(0,10))l.push(` - ${d.name}${d.description?`: ${d.description}`:""}`);return a.marketplace.plugins.length>10&&l.push(` ... (${a.marketplace.plugins.length-10} more)`),l.join(`
|
|
6
|
+
`)}if(n==="remove"){let i$1=r[2];if(!i$1)return "Usage: /plugin marketplace remove <name>";let s=Q(i$1);return i(),s?`Removed marketplace "${i$1}"`:`Marketplace "${i$1}" not found`}if(n==="list"||n===void 0){let i=X();if(i.length===0)return "No marketplaces. Use /plugin marketplace add <url>.";let s=[`Marketplaces (${i.length}):`];for(let o of i){let a=o.source.source==="github"?`github:${o.source.repo}`:o.source.url,l=o.pluginCount>=0?`${o.pluginCount} plugins`:"manifest unreadable";s.push(` ${o.name} (${a}) \u2014 ${l}`);}return s.join(`
|
|
7
|
+
`)}return `Unknown subcommand "marketplace ${n}".
|
|
8
|
+
${_}`}if(t==="install"){let n=r[1];if(!n)return "Usage: /plugin install <plugin>@<marketplace>";let i$1=ce(n);if(!i$1)return `Expected <plugin>@<marketplace>, got "${n}"`;let s=await ue(i$1.plugin,i$1.marketplace);if(!s.ok)return `Failed to install ${n}: ${s.error}`;i();let o=[`Installed ${n}`,` version: ${s.entry.version}`,` path: ${s.entry.installPath}`];return s.varRewrite.filesRewritten>0&&o.push(` rewrote: ${s.varRewrite.filesRewritten} file(s) \u2014 \${CLAUDE_PLUGIN_ROOT} \u2192 \${CODESHELL_PLUGIN_ROOT}`),o.join(`
|
|
9
|
+
`)}if(t==="uninstall"){let n=r[1];if(!n)return "Usage: /plugin uninstall <plugin>@<marketplace>";let i$1=ce(n);if(!i$1)return `Expected <plugin>@<marketplace>, got "${n}"`;let s=ae(i$1.plugin,i$1.marketplace);if(i(),!s.removedFromManifest&&!s.removedFromDisk)return `${n} was not installed`;let o=[];return s.removedFromManifest&&o.push("manifest entry"),s.removedFromDisk&&o.push("cache dir"),`Uninstalled ${n} (removed ${o.join(" + ")})`}if(t==="list"){let n=le();if(n.length===0)return "No plugins installed.";let i=[`Installed plugins (${n.length}):`];for(let{key:s,entry:o}of n)i.push(` ${s} v${o.version} ${o.installPath}`);return i.join(`
|
|
10
|
+
`)}return `Unknown subcommand "${t}".
|
|
11
|
+
${_}`}a(Ar,"runPluginCommand");export{Ar as runPluginCommand};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `git` subprocess wrappers used by the plugin marketplace. Each
|
|
3
|
+
* function returns a discriminated union so callers can produce useful
|
|
4
|
+
* error messages without try/catching. Mirrors Claude Code's
|
|
5
|
+
* utils/plugins/marketplaceManager.ts:loadAndCacheMarketplace at the
|
|
6
|
+
* subset we need for the MVP.
|
|
7
|
+
*/
|
|
8
|
+
export type GitResult = {
|
|
9
|
+
ok: true;
|
|
10
|
+
stdout: string;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function gitClone(url: string, destDir: string, options?: {
|
|
16
|
+
ref?: string;
|
|
17
|
+
}): Promise<GitResult>;
|
|
18
|
+
export declare function gitRevParseHead(repoDir: string): Promise<GitResult>;
|
|
19
|
+
export declare function gitFetchAndReset(repoDir: string, ref?: string): Promise<GitResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Github source helper: convert "owner/repo" to an https clone URL.
|
|
22
|
+
*/
|
|
23
|
+
export declare function githubRepoToCloneUrl(repo: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read/write ~/.code-shell/plugins/installed_plugins.json (V2 format).
|
|
3
|
+
* Byte-compatible with Claude Code's analogous file.
|
|
4
|
+
*/
|
|
5
|
+
import type { InstalledPluginsV2, PluginInstallEntry } from "./types.js";
|
|
6
|
+
export declare function installedPluginsPath(): string;
|
|
7
|
+
export declare function readInstalledPlugins(): InstalledPluginsV2;
|
|
8
|
+
export declare function writeInstalledPlugins(data: InstalledPluginsV2): void;
|
|
9
|
+
/**
|
|
10
|
+
* Append an install entry for `<plugin>@<marketplace>`. Multiple entries
|
|
11
|
+
* for the same key are allowed (different scopes); MVP only writes scope:"user".
|
|
12
|
+
*/
|
|
13
|
+
export declare function appendInstallEntry(key: string, entry: PluginInstallEntry): void;
|
|
14
|
+
export declare function removeInstallEntries(key: string): boolean;
|
|
15
|
+
export declare function pluginInstallKey(plugin: string, marketplace: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read/write ~/.code-shell/plugins/known_marketplaces.json.
|
|
3
|
+
* File format is byte-compatible with Claude Code's analogous file.
|
|
4
|
+
*/
|
|
5
|
+
import type { KnownMarketplaces, KnownMarketplace } from "./types.js";
|
|
6
|
+
export declare function knownMarketplacesPath(): string;
|
|
7
|
+
export declare function readKnownMarketplaces(): KnownMarketplaces;
|
|
8
|
+
export declare function writeKnownMarketplaces(data: KnownMarketplaces): void;
|
|
9
|
+
export declare function upsertKnownMarketplace(name: string, entry: KnownMarketplace): void;
|
|
10
|
+
export declare function removeKnownMarketplace(name: string): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* loadPluginHooks — scan every installed plugin's hooks/hooks.json and
|
|
3
|
+
* register the command-type hooks with the engine's HookRegistry.
|
|
4
|
+
*
|
|
5
|
+
* Plugin hooks.json schema (Claude Code-compatible):
|
|
6
|
+
*
|
|
7
|
+
* {
|
|
8
|
+
* "hooks": {
|
|
9
|
+
* "<EventName>": [
|
|
10
|
+
* {
|
|
11
|
+
* "matcher": "<regex>", // optional; semantics depend on event
|
|
12
|
+
* "hooks": [
|
|
13
|
+
* {
|
|
14
|
+
* "type": "command",
|
|
15
|
+
* "command": "...", // ${CODESHELL_PLUGIN_ROOT} placeholder
|
|
16
|
+
* "async": false, // currently ignored (always sync await)
|
|
17
|
+
* "timeout_ms": 60000 // optional override
|
|
18
|
+
* }
|
|
19
|
+
* ]
|
|
20
|
+
* }
|
|
21
|
+
* ]
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* Event-name mapping (CC PascalCase → codeshell snake_case):
|
|
26
|
+
* SessionStart → on_session_start
|
|
27
|
+
* UserPromptSubmit → user_prompt_submit
|
|
28
|
+
* PreToolUse → pre_tool_use
|
|
29
|
+
* PostToolUse → post_tool_use
|
|
30
|
+
* PreCompact → pre_compact
|
|
31
|
+
* Notification → notification
|
|
32
|
+
* Stop → on_session_end
|
|
33
|
+
* SubagentStop → (skipped — codeshell sub-agents don't surface this event)
|
|
34
|
+
*
|
|
35
|
+
* matcher semantics:
|
|
36
|
+
* SessionStart — matches against ctx.data.source ("startup"|"resume"|"clear"|"compact")
|
|
37
|
+
* PreToolUse /
|
|
38
|
+
* PostToolUse — matches against ctx.data.toolName
|
|
39
|
+
* other events — matcher is currently ignored (the CC spec doesn't
|
|
40
|
+
* define matcher semantics for them either)
|
|
41
|
+
*
|
|
42
|
+
* Errors are swallowed per-plugin: a malformed hooks.json from one plugin
|
|
43
|
+
* must not block other plugins from loading.
|
|
44
|
+
*/
|
|
45
|
+
import type { HookRegistry } from "../hooks/registry.js";
|
|
46
|
+
/**
|
|
47
|
+
* Walk installed plugins and register their command hooks. Safe to call
|
|
48
|
+
* multiple times — the caller is responsible for not double-registering
|
|
49
|
+
* (HookRegistry has no de-dup; the engine constructor calls this exactly
|
|
50
|
+
* once after creating the registry).
|
|
51
|
+
*/
|
|
52
|
+
export declare function loadPluginHooks(registry: HookRegistry): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marketplace lifecycle: add (clone + validate + persist), remove
|
|
3
|
+
* (delete from disk + manifest), list, load (read marketplace.json on
|
|
4
|
+
* demand). Mirrors Claude Code's utils/plugins/marketplaceManager.ts
|
|
5
|
+
* at the MVP subset (github + git sources only, no auto-update,
|
|
6
|
+
* no policy blocking, no GCS mirror).
|
|
7
|
+
*/
|
|
8
|
+
import type { MarketplaceSource, PluginMarketplace } from "./types.js";
|
|
9
|
+
export declare function marketplacesRoot(): string;
|
|
10
|
+
export declare function marketplaceDir(name: string): string;
|
|
11
|
+
export type AddMarketplaceResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
name: string;
|
|
14
|
+
marketplace: PluginMarketplace;
|
|
15
|
+
replaced: boolean;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
error: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Adds a marketplace by cloning it (or refreshing if already present
|
|
22
|
+
* with the same source), validating its marketplace.json, and writing
|
|
23
|
+
* an entry into known_marketplaces.json.
|
|
24
|
+
*/
|
|
25
|
+
export declare function addMarketplace(name: string, source: MarketplaceSource): Promise<AddMarketplaceResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Removes a marketplace: deletes the cached clone and the manifest entry.
|
|
28
|
+
* Returns whether anything was actually removed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function removeMarketplace(name: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Loads a previously-added marketplace's manifest from disk. Returns null
|
|
33
|
+
* if the marketplace is unknown or the manifest is gone (caller can
|
|
34
|
+
* report to user).
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadMarketplace(name: string): PluginMarketplace | null;
|
|
37
|
+
export interface ListedMarketplace {
|
|
38
|
+
name: string;
|
|
39
|
+
source: MarketplaceSource;
|
|
40
|
+
installLocation: string;
|
|
41
|
+
lastUpdated: string;
|
|
42
|
+
pluginCount: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Lists all known marketplaces with a quick plugin count read from each
|
|
46
|
+
* cached manifest. Marketplaces whose manifest is missing or invalid
|
|
47
|
+
* show pluginCount: -1 so the caller can flag them.
|
|
48
|
+
*/
|
|
49
|
+
export declare function listMarketplaces(): ListedMarketplace[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a user-typed marketplace identifier into a MarketplaceSource.
|
|
3
|
+
* MVP subset of Claude Code's utils/plugins/parseMarketplaceInput.ts —
|
|
4
|
+
* local absolute paths, github shorthand, https git URLs, and ssh git URLs.
|
|
5
|
+
*/
|
|
6
|
+
import type { MarketplaceSource } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Returns the parsed source, or null when the input does not match any
|
|
9
|
+
* supported pattern. Callers should show a usage hint on null.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseMarketplaceInput(input: string): MarketplaceSource | null;
|
|
12
|
+
/**
|
|
13
|
+
* Derive a stable marketplace name from a source. Used as the filesystem
|
|
14
|
+
* directory and the key in known_marketplaces.json.
|
|
15
|
+
*/
|
|
16
|
+
export declare function deriveMarketplaceName(source: MarketplaceSource): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pluginCommandHook — execute a plugin's command-type hook as a child
|
|
3
|
+
* process and translate its stdout into a HookResult.
|
|
4
|
+
*
|
|
5
|
+
* This is the plugin-side analogue of `src/hooks/shell-runner.ts`. The two
|
|
6
|
+
* runners are intentionally separate because they speak different protocols:
|
|
7
|
+
*
|
|
8
|
+
* src/hooks/shell-runner.ts codeshell-native: stdout is a HookResult
|
|
9
|
+
* JSON envelope ({ messages, decision, ... }).
|
|
10
|
+
* Used by user-authored settings.hooks.
|
|
11
|
+
*
|
|
12
|
+
* this file CC plugin protocol: stdout is one of
|
|
13
|
+
* - { hookSpecificOutput: { hookEventName, additionalContext } }
|
|
14
|
+
* - { additional_context: "..." } (Cursor)
|
|
15
|
+
* - { additionalContext: "..." } (SDK)
|
|
16
|
+
* We normalize all three into HookResult.messages
|
|
17
|
+
* so downstream hook plumbing (inject.ts) is
|
|
18
|
+
* untouched.
|
|
19
|
+
*
|
|
20
|
+
* env contract:
|
|
21
|
+
* CODESHELL_PLUGIN_ROOT — set to installPath. Plugin command strings
|
|
22
|
+
* reference this via ${CODESHELL_PLUGIN_ROOT}
|
|
23
|
+
* (varRewrite.ts rewrites CC's CLAUDE_PLUGIN_ROOT
|
|
24
|
+
* to this name at install time).
|
|
25
|
+
* CODESHELL_HOOK_EVENT — the codeshell-side event name (snake_case)
|
|
26
|
+
*
|
|
27
|
+
* We deliberately do NOT set CLAUDE_PLUGIN_ROOT here. Plugin scripts that
|
|
28
|
+
* branch on which host they detect (e.g. superpowers' session-start checks
|
|
29
|
+
* `[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]`) get rewritten by varRewrite.ts at
|
|
30
|
+
* install time, so the branch they take after rewrite is the codeshell
|
|
31
|
+
* branch — not the CC one.
|
|
32
|
+
*/
|
|
33
|
+
import type { HookContext, HookResult } from "../hooks/events.js";
|
|
34
|
+
export interface PluginCommandHookSpec {
|
|
35
|
+
/** Shell command line, with ${CODESHELL_PLUGIN_ROOT} placeholder allowed. */
|
|
36
|
+
command: string;
|
|
37
|
+
/** Plugin install path; exported as CODESHELL_PLUGIN_ROOT for the child. */
|
|
38
|
+
installPath: string;
|
|
39
|
+
/** Plugin install key (`name@marketplace`), used for log lines. */
|
|
40
|
+
pluginKey: string;
|
|
41
|
+
/** Per-hook override; falls back to DEFAULT_TIMEOUT_MS. */
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Run one plugin hook command. Returns an empty HookResult on any failure
|
|
46
|
+
* (spawn error, timeout, non-zero exit, unparseable stdout) so the hook
|
|
47
|
+
* chain keeps moving — a misbehaving plugin must not wedge the engine.
|
|
48
|
+
*
|
|
49
|
+
* Stdin carries the same envelope shape the codeshell-native shell-runner
|
|
50
|
+
* uses (eventName + data) so plugin authors who want richer context can
|
|
51
|
+
* read it; CC plugins typically ignore stdin and emit context derived from
|
|
52
|
+
* their own state (e.g. reading a SKILL.md off disk via PLUGIN_ROOT).
|
|
53
|
+
*/
|
|
54
|
+
export declare function runPluginCommandHook(spec: PluginCommandHookSpec, ctx: HookContext): Promise<HookResult>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover plugin-provided slash commands. For each installed plugin,
|
|
3
|
+
* walks <installPath>/commands/*.md and returns one PluginCommand per
|
|
4
|
+
* markdown file. Mirrors Claude Code's loadPluginCommands.ts at the
|
|
5
|
+
* MVP subset (single-level commands directory, no nested subcommands,
|
|
6
|
+
* no inline-via-plugin.json commands).
|
|
7
|
+
*/
|
|
8
|
+
export interface PluginCommand {
|
|
9
|
+
/** Namespaced name, e.g. "superpowers:brainstorming" */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Plain command (without plugin prefix), e.g. "brainstorming" */
|
|
12
|
+
commandName: string;
|
|
13
|
+
/** Plugin id (without @marketplace), e.g. "superpowers" */
|
|
14
|
+
pluginName: string;
|
|
15
|
+
/** Frontmatter description, coerced. May be empty. */
|
|
16
|
+
description: string;
|
|
17
|
+
/** Frontmatter "argument-hint" if present. */
|
|
18
|
+
argumentHint?: string;
|
|
19
|
+
/** Body of the .md (frontmatter stripped). */
|
|
20
|
+
body: string;
|
|
21
|
+
/** Absolute path to the .md file. */
|
|
22
|
+
filePath: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function scanPluginCommands(): PluginCommand[];
|
|
25
|
+
export declare function invalidatePluginCommandsCache(): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install / uninstall plugins from a known marketplace. Mirrors Claude
|
|
3
|
+
* Code's installResolvedPlugin pattern at the MVP subset: four entry
|
|
4
|
+
* source types (path / git / github / git-subdir), no dependencies, no
|
|
5
|
+
* sparse-checkout, no npm/pip.
|
|
6
|
+
*/
|
|
7
|
+
import type { PluginInstallEntry } from "./types.js";
|
|
8
|
+
export interface VarRewriteReport {
|
|
9
|
+
filesScanned: number;
|
|
10
|
+
filesRewritten: number;
|
|
11
|
+
}
|
|
12
|
+
export type InstallResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
entry: PluginInstallEntry;
|
|
15
|
+
freshlyCloned: boolean;
|
|
16
|
+
varRewrite: VarRewriteReport;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Install a plugin from a previously-added marketplace into the user
|
|
23
|
+
* cache. Idempotent within a process: re-installing replaces the
|
|
24
|
+
* cached files and updates the manifest entry.
|
|
25
|
+
*/
|
|
26
|
+
export declare function installPlugin(pluginName: string, marketplaceName: string): Promise<InstallResult>;
|
|
27
|
+
export interface UninstallResult {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
removedFromManifest: boolean;
|
|
30
|
+
removedFromDisk: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare function uninstallPlugin(pluginName: string, marketplaceName: string): UninstallResult;
|
|
33
|
+
export declare function listInstalled(): {
|
|
34
|
+
key: string;
|
|
35
|
+
entry: PluginInstallEntry;
|
|
36
|
+
}[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight validators for plugin marketplace JSON shapes. Returns
|
|
3
|
+
* { ok, value } | { ok: false, error } so callers can use the error
|
|
4
|
+
* string in user-facing slash command output.
|
|
5
|
+
*/
|
|
6
|
+
import type { PluginMarketplace, PluginMarketplaceEntry, PluginEntrySource, ValidationResult } from "./types.js";
|
|
7
|
+
export declare function validatePluginEntrySource(raw: unknown, path: string): ValidationResult<PluginEntrySource>;
|
|
8
|
+
export declare function validatePluginEntry(raw: unknown, index: number): ValidationResult<PluginMarketplaceEntry>;
|
|
9
|
+
export declare function validateMarketplace(raw: unknown): ValidationResult<PluginMarketplace>;
|