@clinebot/core 0.0.11 → 0.0.13

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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/agent-config-loader.d.ts +1 -1
  3. package/dist/agents/agent-config-parser.d.ts +5 -2
  4. package/dist/agents/index.d.ts +1 -1
  5. package/dist/agents/plugin-config-loader.d.ts +4 -0
  6. package/dist/agents/plugin-loader.d.ts +1 -0
  7. package/dist/agents/plugin-sandbox-bootstrap.js +446 -0
  8. package/dist/agents/plugin-sandbox.d.ts +4 -0
  9. package/dist/index.node.d.ts +5 -0
  10. package/dist/index.node.js +685 -413
  11. package/dist/runtime/commands.d.ts +11 -0
  12. package/dist/runtime/sandbox/subprocess-sandbox.d.ts +8 -1
  13. package/dist/runtime/skills.d.ts +13 -0
  14. package/dist/session/default-session-manager.d.ts +5 -0
  15. package/dist/session/session-config-builder.d.ts +4 -1
  16. package/dist/session/session-manager.d.ts +1 -0
  17. package/dist/session/session-service.d.ts +22 -22
  18. package/dist/session/unified-session-persistence-service.d.ts +12 -6
  19. package/dist/session/utils/helpers.d.ts +2 -2
  20. package/dist/session/utils/types.d.ts +9 -0
  21. package/dist/tools/definitions.d.ts +2 -2
  22. package/dist/tools/presets.d.ts +3 -3
  23. package/dist/tools/schemas.d.ts +15 -14
  24. package/dist/types/config.d.ts +5 -0
  25. package/dist/types/events.d.ts +22 -0
  26. package/package.json +5 -4
  27. package/src/agents/agent-config-loader.test.ts +2 -0
  28. package/src/agents/agent-config-loader.ts +1 -0
  29. package/src/agents/agent-config-parser.ts +12 -5
  30. package/src/agents/index.ts +1 -0
  31. package/src/agents/plugin-config-loader.test.ts +49 -0
  32. package/src/agents/plugin-config-loader.ts +10 -73
  33. package/src/agents/plugin-loader.test.ts +127 -1
  34. package/src/agents/plugin-loader.ts +72 -5
  35. package/src/agents/plugin-sandbox-bootstrap.ts +445 -0
  36. package/src/agents/plugin-sandbox.test.ts +198 -1
  37. package/src/agents/plugin-sandbox.ts +223 -353
  38. package/src/index.node.ts +14 -0
  39. package/src/runtime/commands.test.ts +98 -0
  40. package/src/runtime/commands.ts +83 -0
  41. package/src/runtime/hook-file-hooks.test.ts +1 -1
  42. package/src/runtime/hook-file-hooks.ts +16 -6
  43. package/src/runtime/index.ts +10 -0
  44. package/src/runtime/runtime-builder.test.ts +67 -0
  45. package/src/runtime/runtime-builder.ts +70 -16
  46. package/src/runtime/sandbox/subprocess-sandbox.ts +35 -11
  47. package/src/runtime/skills.ts +44 -0
  48. package/src/runtime/workflows.ts +20 -29
  49. package/src/session/default-session-manager.e2e.test.ts +52 -33
  50. package/src/session/default-session-manager.test.ts +453 -1
  51. package/src/session/default-session-manager.ts +210 -12
  52. package/src/session/rpc-session-service.ts +14 -96
  53. package/src/session/session-config-builder.ts +2 -0
  54. package/src/session/session-manager.ts +1 -0
  55. package/src/session/session-service.ts +127 -64
  56. package/src/session/session-team-coordination.ts +30 -0
  57. package/src/session/unified-session-persistence-service.test.ts +3 -3
  58. package/src/session/unified-session-persistence-service.ts +159 -141
  59. package/src/session/utils/helpers.ts +22 -41
  60. package/src/session/utils/types.ts +10 -0
  61. package/src/storage/sqlite-team-store.ts +16 -5
  62. package/src/tools/definitions.test.ts +137 -8
  63. package/src/tools/definitions.ts +115 -70
  64. package/src/tools/presets.test.ts +2 -3
  65. package/src/tools/presets.ts +3 -3
  66. package/src/tools/schemas.ts +28 -28
  67. package/src/types/config.ts +5 -0
  68. package/src/types/events.ts +23 -0
@@ -0,0 +1,11 @@
1
+ import type { UserInstructionConfigWatcher } from "../agents";
2
+ export type RuntimeCommandKind = "skill" | "workflow";
3
+ export type AvailableRuntimeCommand = {
4
+ id: string;
5
+ name: string;
6
+ instructions: string;
7
+ kind: RuntimeCommandKind;
8
+ };
9
+ export declare function listAvailableRuntimeCommandsFromWatcher(watcher: UserInstructionConfigWatcher): AvailableRuntimeCommand[];
10
+ export declare function resolveRuntimeSlashCommandFromWatcher(input: string, watcher: UserInstructionConfigWatcher): string;
11
+ export declare function listAvailableRuntimeCommandsForKindFromWatcher(watcher: UserInstructionConfigWatcher, kind: RuntimeCommandKind): AvailableRuntimeCommand[];
@@ -1,6 +1,13 @@
1
1
  export interface SubprocessSandboxOptions {
2
- bootstrapScript: string;
2
+ /** Inline script to execute via `node -e`. Mutually exclusive with {@link bootstrapFile}. */
3
+ bootstrapScript?: string;
4
+ /** Path to a JavaScript file to execute via `node <file>`. Mutually exclusive with {@link bootstrapScript}. */
5
+ bootstrapFile?: string;
3
6
  name?: string;
7
+ onEvent?: (event: {
8
+ name: string;
9
+ payload?: unknown;
10
+ }) => void;
4
11
  }
5
12
  export interface SandboxCallOptions {
6
13
  timeoutMs?: number;
@@ -0,0 +1,13 @@
1
+ import type { UserInstructionConfigWatcher } from "../agents";
2
+ export type AvailableSkill = {
3
+ id: string;
4
+ name: string;
5
+ instructions: string;
6
+ };
7
+ export declare function listAvailableSkillsFromWatcher(watcher: UserInstructionConfigWatcher): AvailableSkill[];
8
+ /**
9
+ * Expands a leading slash command (e.g. "/release") to skill instructions.
10
+ * If the input starts with "/<skill-name>", that prefix is replaced and the
11
+ * remaining input is preserved unchanged.
12
+ */
13
+ export declare function resolveSkillsSlashCommandFromWatcher(input: string, watcher: UserInstructionConfigWatcher): string;
@@ -60,7 +60,12 @@ export declare class DefaultSessionManager implements SessionManager {
60
60
  private failSession;
61
61
  private shutdownSession;
62
62
  private updateStatus;
63
+ private handlePluginEvent;
64
+ private enqueuePendingPrompt;
65
+ private drainPendingPrompts;
63
66
  private onAgentEvent;
67
+ private emitPendingPrompts;
68
+ private emitPendingPromptSubmitted;
64
69
  private createSpawnTool;
65
70
  private handleTeamEvent;
66
71
  private runWithAuthRetry;
@@ -5,7 +5,10 @@ import type { CoreSessionConfig } from "../types/config";
5
5
  import { type ProviderSettings } from "../types/provider-settings";
6
6
  import type { StartSessionInput } from "./session-manager";
7
7
  export declare function resolveWorkspacePath(config: CoreSessionConfig): string;
8
- export declare function buildEffectiveConfig(input: StartSessionInput, hookPath: string, sessionId: string, defaultTelemetry: ITelemetryService | undefined): Promise<{
8
+ export declare function buildEffectiveConfig(input: StartSessionInput, hookPath: string, sessionId: string, defaultTelemetry: ITelemetryService | undefined, onPluginEvent?: (event: {
9
+ name: string;
10
+ payload?: unknown;
11
+ }) => void): Promise<{
9
12
  config: CoreSessionConfig;
10
13
  pluginSandboxShutdown?: () => Promise<void>;
11
14
  }>;
@@ -33,6 +33,7 @@ export interface SendSessionInput {
33
33
  prompt: string;
34
34
  userImages?: string[];
35
35
  userFiles?: string[];
36
+ delivery?: "queue" | "steer";
36
37
  }
37
38
  export interface SessionAccumulatedUsage {
38
39
  inputTokens: number;
@@ -3,35 +3,35 @@ import type { SqliteSessionStore } from "../storage/sqlite-session-store";
3
3
  import type { SessionSource, SessionStatus } from "../types/common";
4
4
  import type { SessionManifest } from "./session-manifest";
5
5
  import { UnifiedSessionPersistenceService } from "./unified-session-persistence-service";
6
- export interface SessionRowShape {
7
- session_id: string;
6
+ export interface SessionRow {
7
+ sessionId: string;
8
8
  source: string;
9
9
  pid: number;
10
- started_at: string;
11
- ended_at?: string | null;
12
- exit_code?: number | null;
10
+ startedAt: string;
11
+ endedAt?: string | null;
12
+ exitCode?: number | null;
13
13
  status: SessionStatus;
14
- status_lock?: number;
15
- interactive: number;
14
+ statusLock: number;
15
+ interactive: boolean;
16
16
  provider: string;
17
17
  model: string;
18
18
  cwd: string;
19
- workspace_root: string;
20
- team_name?: string | null;
21
- enable_tools: number;
22
- enable_spawn: number;
23
- enable_teams: number;
24
- parent_session_id?: string | null;
25
- parent_agent_id?: string | null;
26
- agent_id?: string | null;
27
- conversation_id?: string | null;
28
- is_subagent: number;
19
+ workspaceRoot: string;
20
+ teamName?: string | null;
21
+ enableTools: boolean;
22
+ enableSpawn: boolean;
23
+ enableTeams: boolean;
24
+ parentSessionId?: string | null;
25
+ parentAgentId?: string | null;
26
+ agentId?: string | null;
27
+ conversationId?: string | null;
28
+ isSubagent: boolean;
29
29
  prompt?: string | null;
30
- metadata_json?: string | null;
31
- transcript_path: string;
32
- hook_path: string;
33
- messages_path?: string | null;
34
- updated_at?: string;
30
+ metadata?: Record<string, unknown> | null;
31
+ transcriptPath: string;
32
+ hookPath: string;
33
+ messagesPath?: string | null;
34
+ updatedAt: string;
35
35
  }
36
36
  export interface CreateRootSessionInput {
37
37
  sessionId: string;
@@ -3,7 +3,7 @@ import type { LlmsProviders } from "@clinebot/llms";
3
3
  import type { SessionStatus } from "../types/common";
4
4
  import { SessionArtifacts } from "./session-artifacts";
5
5
  import { type SessionManifest } from "./session-manifest";
6
- import type { CreateRootSessionWithArtifactsInput, RootSessionArtifacts, SessionRowShape, UpsertSubagentInput } from "./session-service";
6
+ import type { CreateRootSessionWithArtifactsInput, RootSessionArtifacts, SessionRow, UpsertSubagentInput } from "./session-service";
7
7
  export interface PersistedSessionUpdateInput {
8
8
  sessionId: string;
9
9
  expectedStatusLock?: number;
@@ -11,7 +11,7 @@ export interface PersistedSessionUpdateInput {
11
11
  endedAt?: string | null;
12
12
  exitCode?: number | null;
13
13
  prompt?: string | null;
14
- metadataJson?: string | null;
14
+ metadata?: Record<string, unknown> | null;
15
15
  title?: string | null;
16
16
  parentSessionId?: string | null;
17
17
  parentAgentId?: string | null;
@@ -21,13 +21,13 @@ export interface PersistedSessionUpdateInput {
21
21
  }
22
22
  export interface SessionPersistenceAdapter {
23
23
  ensureSessionsDir(): string;
24
- upsertSession(row: SessionRowShape): Promise<void>;
25
- getSession(sessionId: string): Promise<SessionRowShape | undefined>;
24
+ upsertSession(row: SessionRow): Promise<void>;
25
+ getSession(sessionId: string): Promise<SessionRow | undefined>;
26
26
  listSessions(options: {
27
27
  limit: number;
28
28
  parentSessionId?: string;
29
29
  status?: string;
30
- }): Promise<SessionRowShape[]>;
30
+ }): Promise<SessionRow[]>;
31
31
  updateSession(input: PersistedSessionUpdateInput): Promise<{
32
32
  updated: boolean;
33
33
  statusLock: number;
@@ -44,9 +44,12 @@ export interface SessionPersistenceAdapter {
44
44
  export declare class UnifiedSessionPersistenceService {
45
45
  private readonly adapter;
46
46
  private readonly teamTaskSessionsByAgent;
47
+ private readonly teamTaskLastHeartbeatBySession;
48
+ private readonly teamTaskLastProgressLineBySession;
47
49
  protected readonly artifacts: SessionArtifacts;
48
50
  private static readonly STALE_REASON;
49
51
  private static readonly STALE_SOURCE;
52
+ private static readonly TEAM_HEARTBEAT_LOG_INTERVAL_MS;
50
53
  constructor(adapter: SessionPersistenceAdapter);
51
54
  ensureSessionsDir(): string;
52
55
  private writeManifestFile;
@@ -81,11 +84,14 @@ export declare class UnifiedSessionPersistenceService {
81
84
  applyStatusToRunningChildSessions(parentSessionId: string, status: Exclude<SessionStatus, "running">): Promise<void>;
82
85
  onTeamTaskStart(rootSessionId: string, agentId: string, message: string): Promise<void>;
83
86
  onTeamTaskEnd(rootSessionId: string, agentId: string, status: SessionStatus, summary?: string, messages?: LlmsProviders.Message[]): Promise<void>;
87
+ onTeamTaskProgress(rootSessionId: string, agentId: string, progress: string, options?: {
88
+ kind?: "heartbeat" | "progress" | "text";
89
+ }): Promise<void>;
84
90
  handleSubAgentStart(rootSessionId: string, context: SubAgentStartContext): Promise<void>;
85
91
  handleSubAgentEnd(rootSessionId: string, context: SubAgentEndContext): Promise<void>;
86
92
  private isPidAlive;
87
93
  private reconcileDeadRunningSession;
88
- listSessions(limit?: number): Promise<SessionRowShape[]>;
94
+ listSessions(limit?: number): Promise<SessionRow[]>;
89
95
  reconcileDeadSessions(limit?: number): Promise<number>;
90
96
  deleteSession(sessionId: string): Promise<{
91
97
  deleted: boolean;
@@ -1,11 +1,11 @@
1
1
  import type { AgentConfig, AgentEvent, AgentResult } from "@clinebot/agents";
2
2
  import type { LlmsProviders } from "@clinebot/llms";
3
3
  import type { SessionRecord } from "../../types/sessions";
4
- import type { SessionRowShape } from "../session-service";
4
+ import type { SessionRow } from "../session-service";
5
5
  import type { StoredMessageWithMetadata } from "./types";
6
6
  export declare function extractWorkspaceMetadataFromSystemPrompt(systemPrompt: string): string | undefined;
7
7
  export declare function hasRuntimeHooks(hooks: AgentConfig["hooks"]): boolean;
8
8
  export declare function mergeAgentExtensions(explicitExtensions: AgentConfig["extensions"] | undefined, loadedExtensions: AgentConfig["extensions"] | undefined): AgentConfig["extensions"];
9
9
  export declare function serializeAgentEvent(event: AgentEvent): string;
10
10
  export declare function withLatestAssistantTurnMetadata(messages: LlmsProviders.Message[], result: AgentResult, previousMessages?: LlmsProviders.MessageWithMetadata[]): StoredMessageWithMetadata[];
11
- export declare function toSessionRecord(row: SessionRowShape): SessionRecord;
11
+ export declare function toSessionRecord(row: SessionRow): SessionRecord;
@@ -21,9 +21,18 @@ export type ActiveSession = {
21
21
  activeTeamRunIds: Set<string>;
22
22
  pendingTeamRunUpdates: TeamRunUpdate[];
23
23
  teamRunWaiters: Array<() => void>;
24
+ pendingPrompts: PendingPrompt[];
25
+ drainingPendingPrompts: boolean;
24
26
  pluginSandboxShutdown?: () => Promise<void>;
25
27
  turnUsageBaseline?: SessionAccumulatedUsage;
26
28
  };
29
+ export type PendingPrompt = {
30
+ id: string;
31
+ prompt: string;
32
+ delivery: "queue" | "steer";
33
+ userImages?: string[];
34
+ userFiles?: string[];
35
+ };
27
36
  export type TeamRunUpdate = {
28
37
  runId: string;
29
38
  agentId: string;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { type Tool } from "@clinebot/agents";
7
7
  import { type ApplyPatchInput, type AskQuestionInput, type EditFileInput, type FetchWebContentInput, type ReadFilesInput, type RunCommandsInput, type SearchCodebaseInput, type SkillsInput } from "./schemas.js";
8
- import type { ApplyPatchExecutor, AskQuestionExecutor, BashExecutor, CreateDefaultToolsOptions, DefaultToolsConfig, EditorExecutor, FileReadExecutor, SearchExecutor, SkillsExecutor, ToolOperationResult, WebFetchExecutor } from "./types.js";
8
+ import type { ApplyPatchExecutor, AskQuestionExecutor, BashExecutor, CreateDefaultToolsOptions, DefaultToolsConfig, EditorExecutor, FileReadExecutor, SearchExecutor, SkillsExecutorWithMetadata, ToolOperationResult, WebFetchExecutor } from "./types.js";
9
9
  /**
10
10
  * Create the read_files tool
11
11
  *
@@ -47,7 +47,7 @@ export declare function createEditorTool(executor: EditorExecutor, config?: Pick
47
47
  *
48
48
  * Invokes a configured skill by name and optional arguments.
49
49
  */
50
- export declare function createSkillsTool(executor: SkillsExecutor, config?: Pick<DefaultToolsConfig, "skillsTimeoutMs">): Tool<SkillsInput, string>;
50
+ export declare function createSkillsTool(executor: SkillsExecutorWithMetadata, config?: Pick<DefaultToolsConfig, "skillsTimeoutMs">): Tool<SkillsInput, string>;
51
51
  /**
52
52
  * Create the ask_question tool
53
53
  *
@@ -79,7 +79,7 @@ export declare const ToolPresets: {
79
79
  readonly enableAskQuestion: true;
80
80
  };
81
81
  /**
82
- * YOLO mode (everything enabled + no approval required)
82
+ * YOLO mode (automation-focused tools + no approval required)
83
83
  * Good for trusted local automation workflows.
84
84
  */
85
85
  readonly yolo: {
@@ -90,7 +90,7 @@ export declare const ToolPresets: {
90
90
  readonly enableApplyPatch: false;
91
91
  readonly enableEditor: true;
92
92
  readonly enableSkills: true;
93
- readonly enableAskQuestion: true;
93
+ readonly enableAskQuestion: false;
94
94
  };
95
95
  };
96
96
  /**
@@ -103,7 +103,7 @@ export type ToolPresetName = keyof typeof ToolPresets;
103
103
  export type ToolPolicyPresetName = "default" | "yolo";
104
104
  /**
105
105
  * Build tool policies for a preset.
106
- * `yolo` guarantees all tools are enabled and auto-approved.
106
+ * `yolo` guarantees tool policies are enabled and auto-approved.
107
107
  */
108
108
  export declare function createToolPoliciesWithPreset(presetName: ToolPolicyPresetName): Record<string, ToolPolicy>;
109
109
  /**
@@ -5,14 +5,15 @@
5
5
  * and are used for both validation and JSON Schema generation.
6
6
  */
7
7
  import { z } from "zod";
8
+ export declare const INPUT_ARG_CHAR_LIMIT = 6000;
8
9
  export declare const ReadFileLineRangeSchema: z.ZodObject<{
9
- start_line: z.ZodOptional<z.ZodNumber>;
10
- end_line: z.ZodOptional<z.ZodNumber>;
10
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
11
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
11
12
  }, z.core.$strip>;
12
13
  export declare const ReadFileRequestSchema: z.ZodObject<{
13
14
  path: z.ZodString;
14
- start_line: z.ZodOptional<z.ZodNumber>;
15
- end_line: z.ZodOptional<z.ZodNumber>;
15
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
16
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
16
17
  }, z.core.$strip>;
17
18
  /**
18
19
  * Schema for read_files tool input
@@ -20,8 +21,8 @@ export declare const ReadFileRequestSchema: z.ZodObject<{
20
21
  export declare const ReadFilesInputSchema: z.ZodObject<{
21
22
  files: z.ZodArray<z.ZodObject<{
22
23
  path: z.ZodString;
23
- start_line: z.ZodOptional<z.ZodNumber>;
24
- end_line: z.ZodOptional<z.ZodNumber>;
24
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
25
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
25
26
  }, z.core.$strip>>;
26
27
  }, z.core.$strip>;
27
28
  /**
@@ -30,22 +31,22 @@ export declare const ReadFilesInputSchema: z.ZodObject<{
30
31
  export declare const ReadFilesInputUnionSchema: z.ZodUnion<readonly [z.ZodObject<{
31
32
  files: z.ZodArray<z.ZodObject<{
32
33
  path: z.ZodString;
33
- start_line: z.ZodOptional<z.ZodNumber>;
34
- end_line: z.ZodOptional<z.ZodNumber>;
34
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
35
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
35
36
  }, z.core.$strip>>;
36
37
  }, z.core.$strip>, z.ZodObject<{
37
38
  path: z.ZodString;
38
- start_line: z.ZodOptional<z.ZodNumber>;
39
- end_line: z.ZodOptional<z.ZodNumber>;
39
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
40
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
40
41
  }, z.core.$strip>, z.ZodArray<z.ZodObject<{
41
42
  path: z.ZodString;
42
- start_line: z.ZodOptional<z.ZodNumber>;
43
- end_line: z.ZodOptional<z.ZodNumber>;
43
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
44
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
44
45
  }, z.core.$strip>>, z.ZodArray<z.ZodString>, z.ZodString, z.ZodObject<{
45
46
  files: z.ZodObject<{
46
47
  path: z.ZodString;
47
- start_line: z.ZodOptional<z.ZodNumber>;
48
- end_line: z.ZodOptional<z.ZodNumber>;
48
+ start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
49
+ end_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
49
50
  }, z.core.$strip>;
50
51
  }, z.core.$strip>, z.ZodObject<{
51
52
  file_paths: z.ZodArray<z.ZodString>;
@@ -42,4 +42,9 @@ export interface CoreSessionConfig extends CoreModelConfig, CoreRuntimeFeatures,
42
42
  onTeamEvent?: (event: TeamEvent) => void;
43
43
  onConsecutiveMistakeLimitReached?: (context: ConsecutiveMistakeLimitContext) => Promise<ConsecutiveMistakeLimitDecision> | ConsecutiveMistakeLimitDecision;
44
44
  toolRoutingRules?: ToolRoutingRule[];
45
+ /**
46
+ * Optional skill allowlist for the `skills` tool. When provided, only these
47
+ * skills are surfaced in tool metadata and invocable by name.
48
+ */
49
+ skills?: string[];
45
50
  }
@@ -27,6 +27,22 @@ export interface SessionTeamProgressEvent {
27
27
  lifecycle: import("@clinebot/shared").TeamProgressLifecycleEvent;
28
28
  summary: import("@clinebot/shared").TeamProgressSummary;
29
29
  }
30
+ export interface SessionPendingPromptsEvent {
31
+ sessionId: string;
32
+ prompts: Array<{
33
+ id: string;
34
+ prompt: string;
35
+ delivery: "queue" | "steer";
36
+ attachmentCount: number;
37
+ }>;
38
+ }
39
+ export interface SessionPendingPromptSubmittedEvent {
40
+ sessionId: string;
41
+ id: string;
42
+ prompt: string;
43
+ delivery: "queue" | "steer";
44
+ attachmentCount: number;
45
+ }
30
46
  export type CoreSessionEvent = {
31
47
  type: "chunk";
32
48
  payload: SessionChunkEvent;
@@ -39,6 +55,12 @@ export type CoreSessionEvent = {
39
55
  } | {
40
56
  type: "team_progress";
41
57
  payload: SessionTeamProgressEvent;
58
+ } | {
59
+ type: "pending_prompts";
60
+ payload: SessionPendingPromptsEvent;
61
+ } | {
62
+ type: "pending_prompt_submitted";
63
+ payload: SessionPendingPromptSubmittedEvent;
42
64
  } | {
43
65
  type: "ended";
44
66
  payload: SessionEndedEvent;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@clinebot/core",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "main": "./dist/index.node.js",
5
5
  "dependencies": {
6
- "@clinebot/agents": "0.0.11",
7
- "@clinebot/llms": "0.0.11",
8
- "@clinebot/shared": "0.0.11",
6
+ "@clinebot/agents": "0.0.13",
7
+ "@clinebot/llms": "0.0.13",
8
+ "@clinebot/shared": "0.0.13",
9
9
  "@opentelemetry/api": "^1.9.0",
10
10
  "@opentelemetry/api-logs": "^0.56.0",
11
11
  "@opentelemetry/exporter-logs-otlp-http": "^0.56.0",
@@ -15,6 +15,7 @@
15
15
  "@opentelemetry/sdk-metrics": "^1.30.1",
16
16
  "@opentelemetry/semantic-conventions": "^1.37.0",
17
17
  "better-sqlite3": "^11.10.0",
18
+ "jiti": "^1.21.7",
18
19
  "nanoid": "^5.1.7",
19
20
  "simple-git": "^3.32.3",
20
21
  "yaml": "^2.8.2",
@@ -139,6 +139,7 @@ name: Reader
139
139
  description: Reads files
140
140
  modelId: claude-sonnet-4-6
141
141
  tools: read_files
142
+ skills: commit, review
142
143
  ---
143
144
  Be precise.`);
144
145
 
@@ -149,6 +150,7 @@ Be precise.`);
149
150
  expect(partial.modelId).toBe("claude-sonnet-4-6");
150
151
  expect(partial.systemPrompt).toBe("Be precise.");
151
152
  expect(partial.tools).toEqual([readFiles]);
153
+ expect(partial.skills).toEqual(["commit", "review"]);
152
154
  });
153
155
 
154
156
  it("throws when tool overrides are configured without available tools", () => {
@@ -20,6 +20,7 @@ export type {
20
20
  AgentYamlConfig,
21
21
  BuildAgentConfigOverridesOptions,
22
22
  ParseYamlFrontmatterResult,
23
+ PartialAgentConfigOverrides,
23
24
  } from "./agent-config-parser";
24
25
  export {
25
26
  parseAgentConfigFromYaml,
@@ -33,6 +33,11 @@ export interface BuildAgentConfigOverridesOptions {
33
33
  availableTools?: ReadonlyArray<Tool>;
34
34
  }
35
35
 
36
+ export interface PartialAgentConfigOverrides
37
+ extends Partial<Pick<AgentConfig, "modelId" | "systemPrompt" | "tools">> {
38
+ skills?: string[];
39
+ }
40
+
36
41
  export function isAgentConfigYamlFile(fileName: string): boolean {
37
42
  return /\.(yaml|yml)$/i.test(fileName);
38
43
  }
@@ -159,10 +164,8 @@ export function resolveAgentTools(
159
164
  export function toPartialAgentConfig(
160
165
  config: AgentYamlConfig,
161
166
  options?: BuildAgentConfigOverridesOptions,
162
- ): Partial<Pick<AgentConfig, "modelId" | "systemPrompt" | "tools">> {
163
- const partial: Partial<
164
- Pick<AgentConfig, "modelId" | "systemPrompt" | "tools">
165
- > = {
167
+ ): PartialAgentConfigOverrides {
168
+ const partial: PartialAgentConfigOverrides = {
166
169
  systemPrompt: config.systemPrompt,
167
170
  };
168
171
 
@@ -179,13 +182,17 @@ export function toPartialAgentConfig(
179
182
  partial.tools = resolveAgentTools(config.tools, options.availableTools);
180
183
  }
181
184
 
185
+ if (config.skills !== undefined) {
186
+ partial.skills = [...config.skills];
187
+ }
188
+
182
189
  return partial;
183
190
  }
184
191
 
185
192
  export function parsePartialAgentConfigFromYaml(
186
193
  content: string,
187
194
  options?: BuildAgentConfigOverridesOptions,
188
- ): Partial<Pick<AgentConfig, "modelId" | "systemPrompt" | "tools">> {
195
+ ): PartialAgentConfigOverrides {
189
196
  const parsed = parseAgentConfigFromYaml(content);
190
197
  return toPartialAgentConfig(parsed, options);
191
198
  }
@@ -5,6 +5,7 @@ export type {
5
5
  BuildAgentConfigOverridesOptions,
6
6
  CreateAgentConfigWatcherOptions,
7
7
  ParseYamlFrontmatterResult,
8
+ PartialAgentConfigOverrides,
8
9
  } from "./agent-config-loader";
9
10
  export {
10
11
  AGENT_CONFIG_DIRECTORY_NAME,
@@ -26,6 +26,11 @@ describe("plugin-config-loader", () => {
26
26
  await mkdir(nested, { recursive: true });
27
27
  await writeFile(join(root, "a.mjs"), "export default {}", "utf8");
28
28
  await writeFile(join(nested, "b.ts"), "export default {}", "utf8");
29
+ await writeFile(
30
+ join(root, ".a.mjs.cline-plugin.mjs"),
31
+ "export default {}",
32
+ "utf8",
33
+ );
29
34
  await writeFile(join(root, "ignore.txt"), "noop", "utf8");
30
35
 
31
36
  const discovered = discoverPluginModulePaths(root);
@@ -38,6 +43,8 @@ describe("plugin-config-loader", () => {
38
43
  it("resolves plugin paths from explicit files/directories", async () => {
39
44
  const root = await mkdtemp(join(tmpdir(), "core-plugin-config-loader-"));
40
45
  try {
46
+ process.env.HOME = root;
47
+ setHomeDir(root);
41
48
  const pluginsDir = join(root, "plugins");
42
49
  await mkdir(pluginsDir, { recursive: true });
43
50
  const filePath = join(root, "direct.mjs");
@@ -57,6 +64,41 @@ describe("plugin-config-loader", () => {
57
64
  }
58
65
  });
59
66
 
67
+ it("prefers package manifest plugin entries for configured directories", async () => {
68
+ const root = await mkdtemp(join(tmpdir(), "core-plugin-config-loader-"));
69
+ try {
70
+ const pluginDir = join(root, "plugin-package");
71
+ const srcDir = join(pluginDir, "src");
72
+ await mkdir(srcDir, { recursive: true });
73
+ const declaredEntry = join(srcDir, "index.ts");
74
+ const ignoredEntry = join(pluginDir, "ignored.mjs");
75
+ await writeFile(
76
+ join(pluginDir, "package.json"),
77
+ JSON.stringify({
78
+ name: "plugin-package",
79
+ private: true,
80
+ cline: {
81
+ plugins: ["./src/index.ts"],
82
+ },
83
+ }),
84
+ "utf8",
85
+ );
86
+ await writeFile(declaredEntry, "export default {}", "utf8");
87
+ await writeFile(ignoredEntry, "export default {}", "utf8");
88
+
89
+ const resolved = resolveAgentPluginPaths({
90
+ pluginPaths: ["./plugin-package"],
91
+ cwd: root,
92
+ workspacePath: join(root, "workspace"),
93
+ });
94
+
95
+ expect(resolved).toContain(declaredEntry);
96
+ expect(resolved).not.toContain(ignoredEntry);
97
+ } finally {
98
+ await rm(root, { recursive: true, force: true });
99
+ }
100
+ });
101
+
60
102
  it("includes shared search-path plugins", async () => {
61
103
  const home = await mkdtemp(
62
104
  join(tmpdir(), "core-plugin-config-loader-home-"),
@@ -69,20 +111,27 @@ describe("plugin-config-loader", () => {
69
111
  setHomeDir(home);
70
112
  const workspacePlugins = join(workspace, ".clinerules", "plugins");
71
113
  const userPlugins = join(home, ".cline", "plugins");
114
+ const documentsPlugins = join(home, "Documents", "Plugins");
72
115
  await mkdir(workspacePlugins, { recursive: true });
73
116
  await mkdir(userPlugins, { recursive: true });
117
+ await mkdir(documentsPlugins, { recursive: true });
74
118
  const workspacePlugin = join(workspacePlugins, "workspace.mjs");
75
119
  const userPlugin = join(userPlugins, "user.mjs");
120
+ const documentsPlugin = join(documentsPlugins, "documents.mjs");
76
121
  await writeFile(workspacePlugin, "export default {}", "utf8");
77
122
  await writeFile(userPlugin, "export default {}", "utf8");
123
+ await writeFile(documentsPlugin, "export default {}", "utf8");
78
124
 
79
125
  const searchPaths = resolvePluginConfigSearchPaths(workspace);
126
+ expect(searchPaths).toHaveLength(3);
80
127
  expect(searchPaths).toContain(workspacePlugins);
81
128
  expect(searchPaths).toContain(userPlugins);
129
+ expect(searchPaths).toContain(documentsPlugins);
82
130
 
83
131
  const resolved = resolveAgentPluginPaths({ workspacePath: workspace });
84
132
  expect(resolved).toContain(workspacePlugin);
85
133
  expect(resolved).toContain(userPlugin);
134
+ expect(resolved).toContain(documentsPlugin);
86
135
  } finally {
87
136
  await rm(home, { recursive: true, force: true });
88
137
  await rm(workspace, { recursive: true, force: true });