@serviceme/devtools-core 0.1.8 → 0.2.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/dist/auth.d.mts +590 -0
- package/dist/auth.d.ts +590 -0
- package/dist/auth.js +842 -0
- package/dist/auth.js.map +1 -0
- package/dist/auth.mjs +804 -0
- package/dist/auth.mjs.map +1 -0
- package/dist/device.d.mts +456 -0
- package/dist/device.d.ts +456 -0
- package/dist/device.js +696 -0
- package/dist/device.js.map +1 -0
- package/dist/device.mjs +647 -0
- package/dist/device.mjs.map +1 -0
- package/dist/index-CrNC-aao.d.ts +277 -0
- package/dist/index-Dmyy4urr.d.mts +277 -0
- package/dist/index.d.mts +1372 -27
- package/dist/index.d.ts +1372 -27
- package/dist/index.js +5125 -888
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5022 -906
- package/dist/index.mjs.map +1 -0
- package/dist/skill-linker.d.mts +188 -0
- package/dist/skill-linker.d.ts +188 -0
- package/dist/skill-linker.js +374 -0
- package/dist/skill-linker.js.map +1 -0
- package/dist/skill-linker.mjs +330 -0
- package/dist/skill-linker.mjs.map +1 -0
- package/dist/skill-store.d.mts +35 -0
- package/dist/skill-store.d.ts +35 -0
- package/dist/skill-store.js +291 -0
- package/dist/skill-store.js.map +1 -0
- package/dist/skill-store.mjs +254 -0
- package/dist/skill-store.mjs.map +1 -0
- package/dist/submit.d.mts +3 -0
- package/dist/submit.d.ts +3 -0
- package/dist/submit.js +166 -0
- package/dist/submit.js.map +1 -0
- package/dist/submit.mjs +130 -0
- package/dist/submit.mjs.map +1 -0
- package/dist/toolbox.d.mts +240 -0
- package/dist/toolbox.d.ts +240 -0
- package/dist/toolbox.js +530 -0
- package/dist/toolbox.js.map +1 -0
- package/dist/toolbox.mjs +482 -0
- package/dist/toolbox.mjs.map +1 -0
- package/dist/types-B9gk3dXH.d.mts +62 -0
- package/dist/types-B9gk3dXH.d.ts +62 -0
- package/package.json +50 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import * as _serviceme_devtools_protocol from '@serviceme/devtools-protocol';
|
|
2
|
-
import { AgentMarketplaceEntry, AgentMutationRequest, AgentPermissionSummary, CopilotDoctorResult, CopilotPromptOptions, CopilotPromptResult, EnvironmentCheckResult, KnownEnvironmentTool, ToolCheckResult, ServiceMeImageValidationResult, ServiceMeImageInfo, ServiceMeImageCompressOptions, ServiceMeImageCompressResult, JsonSortOptions, JsonValidationResult, AgentToolRiskLevel, AgentToolPermission, ServiceMeProjectExtractTemplateInput, ServiceMeProjectExtractTemplateResult, ServiceMeProjectInstallDepsResult, ServiceMeProjectMakeScriptsExecutableResult, ServiceMeProjectGitInitResult, ServiceMeProjectScaffoldPruneResult, TaskExecutionStatus, ScheduledTaskType, TaskPayload, ScheduledTasksConfig, ScheduledTask, TaskStartedEventParams, TaskOutputEventParams, TaskCompletedEventParams, TaskFailedEventParams, TaskCancelledEventParams, TaskExecutionSnapshot, RunningTaskInfo,
|
|
2
|
+
import { AgentMarketplaceEntry, AgentMutationRequest, AgentPermissionSummary, CopilotDoctorResult, CopilotPromptOptions, CopilotPromptResult, EnvironmentCheckResult, KnownEnvironmentTool, ToolCheckResult, ServiceMeImageValidationResult, ServiceMeImageInfo, ServiceMeImageCompressOptions, ServiceMeImageCompressResult, JsonSortOptions, JsonValidationResult, AgentToolRiskLevel, AgentToolPermission, ServiceMeProjectExtractTemplateInput, ServiceMeProjectExtractTemplateResult, ServiceMeProjectInstallDepsResult, ServiceMeProjectMakeScriptsExecutableResult, ServiceMeProjectGitInitResult, ServiceMeProjectScaffoldPruneResult, TaskExecutionStatus, ScheduledTaskType, TaskPayload, TaskWorkspaceRef, ScheduledTasksConfig, ScheduledTask, TaskExecutionLog, TaskStartedEventParams, TaskOutputEventParams, TaskCompletedEventParams, TaskFailedEventParams, TaskCancelledEventParams, TaskExecutionSnapshot, RunningTaskInfo, SkillMarketplaceEntry, SkillMutationRequest } from '@serviceme/devtools-protocol';
|
|
3
3
|
import * as fs from 'node:fs/promises';
|
|
4
|
+
export { AccessCheckResult, AccessControl, AccessControlOptions, AuthCore, AuthCoreOptions, AuthStateManager, AuthStateManagerOptions, CancellationCheck, DeviceFlowUiCallback, GitHubAuthProvider, GitHubAuthProviderConfig, IAuthProvider, IAuthProviderSession, IAuthProviderUserInfo, InMemoryKeychainAuthTokenStore, KeyValueStore, KeychainAccountKey, KeychainAuthTokenStore, KeychainTokenEnvelope, KeychainTokenMetadata, KeychainUnavailableError, MicrosoftAuthProvider, MicrosoftProviderNotHostedError, OrgMembershipFetcher, ProviderRegistry, buildGitHubLocalEmail, isGitHubLocalEmail, resolvePrimaryEmail } from './auth.mjs';
|
|
5
|
+
export { AtomicWriteResult, BuildSignedHeadersParams, DEVICE_JSON_SCHEMA_VERSION, DeviceAuthHeaders, DeviceCore, DeviceCoreOptions, DeviceReenrollRequiresAuthError, DeviceRequestSignatureParams, DeviceSecretVersionMismatchError, DeviceSignedHeaders, EnrollRequestFn, EnrollResponse, Enroller, EnrollerOptions, FsIdentityFileBackend, IdentityFileBackend, IdentityStore, IdentityStoreHooks, IdentityStoreOptions, PersistedDeviceIdentity, buildSignedHeaders, createDeviceRequestSignature, deriveInstallationId, fingerprintSource, randomInstallationId } from './device.mjs';
|
|
6
|
+
import { c as SkillKind, b as SkillFile } from './types-B9gk3dXH.mjs';
|
|
7
|
+
import { G as GitClient, P as PullResult } from './index-Dmyy4urr.mjs';
|
|
8
|
+
export { a as GitError, N as NodeGitSpawner, S as StubGitSpawner, b as SubmitClient, c as SubmitClientOptions, d as SubmitError, e as SubmitOptions, f as SubmitResult, t as toFileUrl } from './index-Dmyy4urr.mjs';
|
|
9
|
+
import * as fs$1 from 'node:fs';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
export { BUILTIN_DEFAULT_TOOLS, DefaultToolImmutableError, DefaultToolSeed, FsToolboxFileBackend, PersistedToolbox, ResolvedToolbox, TOOLBOX_JSON_SCHEMA_VERSION, ToolboxCore, ToolboxCoreOptions, ToolboxFileBackend, ToolboxPatch, ToolboxStore, ToolboxStoreHooks, ToolboxStoreOptions, WORKSPACE_TOOLBOX_RELATIVE_PATH, mergeWithDefaults, reindexOrder, sortByRecentFirst, sortByUserOrder, touchLastUsedAt } from './toolbox.mjs';
|
|
12
|
+
import 'node:child_process';
|
|
4
13
|
|
|
5
14
|
type AgentInstallScope = "workspace" | "user";
|
|
6
15
|
interface InstalledAgent {
|
|
@@ -91,6 +100,13 @@ declare class AgentStore {
|
|
|
91
100
|
listWorkspaceAgentIds(): Promise<string[]>;
|
|
92
101
|
listUserAgentIds(): Promise<string[]>;
|
|
93
102
|
readState(): Promise<AgentsStateFile | null>;
|
|
103
|
+
/**
|
|
104
|
+
* One-time migration: the workspace agents state file used to be named
|
|
105
|
+
* `.github/.ms-devtools-agents.yml`. If the new `.serviceme-agents.yml`
|
|
106
|
+
* doesn't exist yet but the legacy file does, copy its content forward
|
|
107
|
+
* so existing installed-agent state isn't silently lost.
|
|
108
|
+
*/
|
|
109
|
+
private migrateLegacyState;
|
|
94
110
|
writeState(state: AgentsStateFile): Promise<void>;
|
|
95
111
|
addInstalledAgent(entry: InstalledAgent): Promise<void>;
|
|
96
112
|
removeInstalledAgent(agentId: string): Promise<void>;
|
|
@@ -109,6 +125,107 @@ declare function createCopilotAuthRequiredError(): _serviceme_devtools_protocol.
|
|
|
109
125
|
|
|
110
126
|
declare function copilotPrompt(options: CopilotPromptOptions): Promise<CopilotPromptResult>;
|
|
111
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Skill & Agent v2 — Drafts (M4)
|
|
130
|
+
*
|
|
131
|
+
* Drafts are offline WIP copies of skills/agents that the user is
|
|
132
|
+
* editing locally before submitting. They live under
|
|
133
|
+
* `~/.serviceme/drafts/{skills,agents}/<draft-id>/` and have the same
|
|
134
|
+
* file layout as a published entry: SKILL.md (or AGENT.md) plus any
|
|
135
|
+
* extra files. The `SubmitClient` (also M4) reads a draft's files and
|
|
136
|
+
* sends them to the server's validate endpoint before pushing.
|
|
137
|
+
*
|
|
138
|
+
* Draft ids are short random hex strings (16 hex chars / 8 bytes of
|
|
139
|
+
* entropy) — long enough to be globally unique, short enough to be
|
|
140
|
+
* pasteable. They are NOT user-meaningful; clients surface a `name`
|
|
141
|
+
* from the draft's frontmatter instead.
|
|
142
|
+
*
|
|
143
|
+
* Persistence is atomic per-file (write to `.tmp-xxx` + rename).
|
|
144
|
+
* The whole draft directory is never partially committed — failed
|
|
145
|
+
* writes leave a `.tmp-xxx` orphan that the next save/cleanup can
|
|
146
|
+
* sweep.
|
|
147
|
+
*
|
|
148
|
+
* @see docs/architecture/skill-agent-v2-repo.md §2.1 (drafts layout),
|
|
149
|
+
* §5.7 SubmitClient (consumer).
|
|
150
|
+
*/
|
|
151
|
+
interface DraftSummary {
|
|
152
|
+
/** Random id (16 hex chars). */
|
|
153
|
+
id: string;
|
|
154
|
+
kind: SkillKind;
|
|
155
|
+
/** Path to the manifest file (SKILL.md or AGENT.md). */
|
|
156
|
+
manifestPath: string;
|
|
157
|
+
/** Path to the directory containing the draft's files. */
|
|
158
|
+
dir: string;
|
|
159
|
+
/** Best-effort name from the frontmatter (empty string when absent). */
|
|
160
|
+
name: string;
|
|
161
|
+
/** Best-effort description from the frontmatter (empty string when absent). */
|
|
162
|
+
description: string;
|
|
163
|
+
/** ISO timestamp of the manifest file's mtime. */
|
|
164
|
+
modifiedAt: string;
|
|
165
|
+
}
|
|
166
|
+
interface DraftDetail extends DraftSummary {
|
|
167
|
+
files: SkillFile[];
|
|
168
|
+
}
|
|
169
|
+
interface SaveDraftOptions {
|
|
170
|
+
kind: SkillKind;
|
|
171
|
+
/** Existing draft id; omit to create a new draft. */
|
|
172
|
+
id?: string;
|
|
173
|
+
/** Files to write. Must include a manifest (SKILL.md or AGENT.md). */
|
|
174
|
+
files: SkillFile[];
|
|
175
|
+
}
|
|
176
|
+
/** Sentinel errors. */
|
|
177
|
+
declare class DraftsError extends Error {
|
|
178
|
+
constructor(message: string);
|
|
179
|
+
}
|
|
180
|
+
declare class DraftNotFoundError extends DraftsError {
|
|
181
|
+
readonly kind: SkillKind;
|
|
182
|
+
readonly id: string;
|
|
183
|
+
constructor(kind: SkillKind, id: string);
|
|
184
|
+
}
|
|
185
|
+
declare class InvalidDraftError extends DraftsError {
|
|
186
|
+
constructor(message: string);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Generate a short random hex id. Uses Node's `crypto.randomBytes` so
|
|
190
|
+
* the output is unpredictable. 8 bytes = 16 hex chars = 64 bits of
|
|
191
|
+
* entropy. We don't promise uniqueness (collisions exist with
|
|
192
|
+
* astronomically low probability) — callers must treat ids as opaque.
|
|
193
|
+
*/
|
|
194
|
+
declare function generateDraftId(): string;
|
|
195
|
+
/**
|
|
196
|
+
* Resolve the on-disk directory for a draft of a given kind + id.
|
|
197
|
+
* Exported for tests + the SubmitClient which writes the committed
|
|
198
|
+
* files into the repo.
|
|
199
|
+
*/
|
|
200
|
+
declare function resolveDraftDir(kind: SkillKind, id: string): string;
|
|
201
|
+
/**
|
|
202
|
+
* Persistent draft store backed by the local filesystem. Pure local —
|
|
203
|
+
* no network, no git, no DB.
|
|
204
|
+
*/
|
|
205
|
+
declare class DraftsStore {
|
|
206
|
+
/**
|
|
207
|
+
* List every draft of the given kind. Returns [] when the drafts
|
|
208
|
+
* directory doesn't exist (cold start, never-saved state).
|
|
209
|
+
*/
|
|
210
|
+
list(kind: SkillKind): Promise<DraftSummary[]>;
|
|
211
|
+
/** Single draft summary (manifest + metadata). Returns null when missing. */
|
|
212
|
+
tryReadSummary(kind: SkillKind, id: string): Promise<DraftSummary | null>;
|
|
213
|
+
/** Single draft detail (summary + all files). Throws when missing. */
|
|
214
|
+
get(kind: SkillKind, id: string): Promise<DraftDetail>;
|
|
215
|
+
/** All files in a draft (manifest + extras), recursively. */
|
|
216
|
+
getFiles(kind: SkillKind, id: string): Promise<SkillFile[]>;
|
|
217
|
+
/**
|
|
218
|
+
* Create-or-update a draft. Returns the (possibly new) draft id.
|
|
219
|
+
* Throws `InvalidDraftError` when the file list does not include
|
|
220
|
+
* a manifest.
|
|
221
|
+
*/
|
|
222
|
+
save(opts: SaveDraftOptions): Promise<string>;
|
|
223
|
+
/** Delete a draft. ENOENT is silently ignored (idempotent). */
|
|
224
|
+
delete(kind: SkillKind, id: string): Promise<void>;
|
|
225
|
+
/** Best-effort cleanup of `.tmp-*` orphan files in the draft dir. */
|
|
226
|
+
private sweepTmp;
|
|
227
|
+
}
|
|
228
|
+
|
|
112
229
|
interface RunCommandOptions {
|
|
113
230
|
args?: string[];
|
|
114
231
|
cwd?: string;
|
|
@@ -190,9 +307,173 @@ interface ServiceMeLogger {
|
|
|
190
307
|
declare const noopLogger: ServiceMeLogger;
|
|
191
308
|
declare function createConsoleLogger(prefix?: string): ServiceMeLogger;
|
|
192
309
|
|
|
310
|
+
/**
|
|
311
|
+
* SERVICEME user home directory helpers.
|
|
312
|
+
*
|
|
313
|
+
* All paths resolve under {@link getServicemeHome}, which is either the
|
|
314
|
+
* `SERVICEME_HOME` environment variable (when set and non-empty) or
|
|
315
|
+
* `$HOME/.serviceme` on POSIX / `%USERPROFILE%\.serviceme` on Windows.
|
|
316
|
+
*
|
|
317
|
+
* Tests inject `homeDir` and `servicemeHomeEnv` overrides via
|
|
318
|
+
* {@link setUserHomeOverrides} / {@link resetUserHomeOverrides} so they can
|
|
319
|
+
* exercise the path logic without touching the real user environment.
|
|
320
|
+
*/
|
|
321
|
+
/** Layout constants — kept in one place so other modules can reuse them. */
|
|
322
|
+
declare const SERVICEME_DIR_NAME = ".serviceme";
|
|
323
|
+
declare const REPOS_SUBDIR = "repos";
|
|
324
|
+
declare const CACHE_SUBDIR = "cache";
|
|
325
|
+
declare const DRAFTS_SUBDIR = "drafts";
|
|
326
|
+
declare const SKILL_DRAFTS_SUBDIR = "skills";
|
|
327
|
+
declare const AGENT_DRAFTS_SUBDIR = "agents";
|
|
328
|
+
declare const REPOS_CONFIG_FILENAME = "repos.json";
|
|
329
|
+
/**
|
|
330
|
+
* Repo id regex — used to validate any `repoId` argument before it is joined
|
|
331
|
+
* into a filesystem path. Keeps path traversal attempts out and gives us a
|
|
332
|
+
* predictable on-disk shape.
|
|
333
|
+
*/
|
|
334
|
+
declare const SAFE_REPO_ID_PATTERN: RegExp;
|
|
335
|
+
/** Environment variable that overrides the user-home root directory. */
|
|
336
|
+
declare const SERVICEME_HOME_ENV = "SERVICEME_HOME";
|
|
337
|
+
/**
|
|
338
|
+
* Test seam: lets unit tests inject deterministic values for `os.homedir()`
|
|
339
|
+
* and the `SERVICEME_HOME` env override without actually mutating
|
|
340
|
+
* `process.env` (which would leak into other tests).
|
|
341
|
+
*/
|
|
342
|
+
interface UserHomeOverrides {
|
|
343
|
+
homeDir?: string | undefined;
|
|
344
|
+
servicemeHomeEnv?: string | undefined;
|
|
345
|
+
platform?: NodeJS.Platform | undefined;
|
|
346
|
+
}
|
|
347
|
+
declare function setUserHomeOverrides(overrides: UserHomeOverrides): void;
|
|
348
|
+
declare function resetUserHomeOverrides(): void;
|
|
349
|
+
declare function assertSafeRepoId(repoId: string): string;
|
|
350
|
+
/**
|
|
351
|
+
* The raw OS home directory (`os.homedir()`), honoring test overrides
|
|
352
|
+
* ({@link setUserHomeOverrides}). Exported for callers that need a
|
|
353
|
+
* home-relative path *outside* of `~/.serviceme` — e.g. the
|
|
354
|
+
* `~/.agents/{skills,agents}` convention used by `SkillLinker` for
|
|
355
|
+
* user-scope links.
|
|
356
|
+
*/
|
|
357
|
+
declare function getHomeDir(): string;
|
|
358
|
+
/**
|
|
359
|
+
* Root directory for all SERVICEME user-level state. Resolves to
|
|
360
|
+
* `${SERVICEME_HOME}` when that env var is set, otherwise `${HOME}/.serviceme`
|
|
361
|
+
* (POSIX) or `%USERPROFILE%\.serviceme` (Windows via `os.homedir`).
|
|
362
|
+
*/
|
|
363
|
+
declare function getServicemeHome(): string;
|
|
364
|
+
/** `$HOME/.serviceme/repos` (or `${SERVICEME_HOME}/repos`). */
|
|
365
|
+
declare function getReposDir(): string;
|
|
366
|
+
/** `$HOME/.serviceme/repos/<repoId>` — validates `repoId` first. */
|
|
367
|
+
declare function getRepoDir(repoId: string): string;
|
|
368
|
+
/** `$HOME/.serviceme/cache` — generic per-user cache. */
|
|
369
|
+
declare function getCacheDir(): string;
|
|
370
|
+
/** `$HOME/.serviceme/cache/<repoId>` — per-repo sync state lives here. */
|
|
371
|
+
declare function getRepoCacheDir(repoId: string): string;
|
|
372
|
+
/** `$HOME/.serviceme/drafts` — local edits not yet pushed upstream. */
|
|
373
|
+
declare function getDraftsDir(): string;
|
|
374
|
+
/** `$HOME/.serviceme/drafts/skills` — local skill drafts. */
|
|
375
|
+
declare function getSkillDraftsDir(): string;
|
|
376
|
+
/** `$HOME/.serviceme/drafts/agents` — local agent drafts. */
|
|
377
|
+
declare function getAgentDraftsDir(): string;
|
|
378
|
+
/**
|
|
379
|
+
* `$HOME/.serviceme/repos.json` — the single config entry point for repo
|
|
380
|
+
* metadata. Always under the resolved home root (i.e. follows
|
|
381
|
+
* `SERVICEME_HOME` overrides too).
|
|
382
|
+
*/
|
|
383
|
+
declare function getReposConfigPath(): string;
|
|
384
|
+
/**
|
|
385
|
+
* Convenience helper for callers that need to switch behaviour on platform
|
|
386
|
+
* (e.g. `SkillLinker` chooses symlink vs junction). Exported mostly so tests
|
|
387
|
+
* can pin the value without touching `process.platform` directly.
|
|
388
|
+
*/
|
|
389
|
+
declare function getHomePlatform(): NodeJS.Platform;
|
|
390
|
+
/** Layout constants for scheduled-tasks files. Kept here so other modules
|
|
391
|
+
* can reuse them and the names stay in sync with the design doc. */
|
|
392
|
+
declare const SCHEDULED_TASKS_CONFIG_FILENAME = "scheduled-tasks.json";
|
|
393
|
+
declare const SCHEDULED_TASKS_LOG_FILENAME = "scheduled-tasks-log.json";
|
|
394
|
+
declare const SCHEDULER_PID_FILENAME = "scheduler.pid";
|
|
395
|
+
declare const SCHEDULER_LOCK_FILENAME = "scheduler.lock";
|
|
396
|
+
declare const SCHEDULER_LOG_FILENAME = "scheduler.log";
|
|
397
|
+
declare const MIGRATION_FAILURES_FILENAME = "migration-failures.json";
|
|
398
|
+
declare const KNOWN_WORKSPACES_FILENAME = "known-workspaces.json";
|
|
399
|
+
/** `~/.serviceme/scheduled-tasks.json` — the global v2 task list. */
|
|
400
|
+
declare function getScheduledTasksConfigPath(): string;
|
|
401
|
+
/** `~/.serviceme/scheduled-tasks-log.json` — the global execution log (200 LRU). */
|
|
402
|
+
declare function getScheduledTasksLogPath(): string;
|
|
403
|
+
/** `~/.serviceme/scheduler.pid` — global daemon PID file. */
|
|
404
|
+
declare function getSchedulerPidPath(): string;
|
|
405
|
+
/** `~/.serviceme/scheduler.lock` — global daemon startup flock. */
|
|
406
|
+
declare function getSchedulerLockPath(): string;
|
|
407
|
+
/** `~/.serviceme/scheduler.log` — global daemon log (daemon lifecycle, not task execution). */
|
|
408
|
+
declare function getSchedulerLogPath(): string;
|
|
409
|
+
/** `~/.serviceme/migration-failures.json` — diagnostics for failed v1→v2 imports. */
|
|
410
|
+
declare function getMigrationFailuresPath(): string;
|
|
411
|
+
/** `~/.serviceme/known-workspaces.json` — workspace list the extension has seen. */
|
|
412
|
+
declare function getKnownWorkspacesPath(): string;
|
|
413
|
+
/** Layout constants for the Phase 5 client-side state files. The server
|
|
414
|
+
* already has the corresponding routes (`/api/v1/auth/...`,
|
|
415
|
+
* `/api/v1/device/...`, etc.) — the client just needs the on-disk
|
|
416
|
+
* file paths + a first-run bootstrap so the auth/device/toolbox
|
|
417
|
+
* services can open + read them without a per-call existence check. */
|
|
418
|
+
declare const CREDENTIALS_CONFIG_FILENAME = "credentials.json";
|
|
419
|
+
declare const DEVICE_JSON_FILENAME = "device.json";
|
|
420
|
+
declare const TOOLBOX_JSON_FILENAME = "toolbox.json";
|
|
421
|
+
declare const MACHINE_ID_FILENAME = "machine-id";
|
|
422
|
+
declare const PROFILES_JSON_FILENAME = "profiles.json";
|
|
423
|
+
/** `~/.serviceme/credentials.json` — better-auth session tokens + refresh state (client-side cache). */
|
|
424
|
+
declare function getCredentialsConfigPath(): string;
|
|
425
|
+
/** `~/.serviceme/device.json` — device enrollment payload (id, public key fingerprint, claimed-by). */
|
|
426
|
+
declare function getDeviceJsonPath(): string;
|
|
427
|
+
/** `~/.serviceme/toolbox.json` — local toolbox state (installed tool refs, per-user prefs). */
|
|
428
|
+
declare function getToolboxJsonPath(): string;
|
|
429
|
+
/** `~/.serviceme/machine-id` — opaque stable per-install id (uuid v4 string, no JSON wrapper). */
|
|
430
|
+
declare function getMachineIdPath(): string;
|
|
431
|
+
/** `~/.serviceme/profiles.json` — cached projection of server-side profile rows; refresh on demand. */
|
|
432
|
+
declare function getProfilesJsonPath(): string;
|
|
433
|
+
|
|
193
434
|
declare const TOOL_RISK_MAP: Record<string, AgentToolRiskLevel>;
|
|
194
435
|
declare function parseAgentToolPermissions(content: string): AgentToolPermission[];
|
|
195
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Spec §11.12 — Phase 5 client-side state bootstrap.
|
|
439
|
+
*
|
|
440
|
+
* The server already exposes the Phase 5 surface (better-auth session
|
|
441
|
+
* endpoints, device enrollment routes, toolbox + profile API). The
|
|
442
|
+
* client (extension + CLI) needs the on-disk files to exist on first
|
|
443
|
+
* run so that subsequent code can `readFile()` without an existence
|
|
444
|
+
* check, and so the user can grep `~/.serviceme/` and see the
|
|
445
|
+
* expected layout instead of an empty directory.
|
|
446
|
+
*
|
|
447
|
+
* Strategy: idempotently write the empty / default JSON for every
|
|
448
|
+
* Phase 5 file that doesn't already exist. Existing files are
|
|
449
|
+
* left untouched so the bootstrap can re-run on every extension
|
|
450
|
+
* activation without overwriting user state.
|
|
451
|
+
*
|
|
452
|
+
* All writes are `mkdir -p` + `writeFile` (no race), and failures
|
|
453
|
+
* are surfaced but never thrown — Phase 5 is auxiliary; the
|
|
454
|
+
* extension / CLI should keep working even if the user's home
|
|
455
|
+
* directory is read-only.
|
|
456
|
+
*
|
|
457
|
+
* @see docs/architecture/skill-agent-v2-repo.md §11.12
|
|
458
|
+
*/
|
|
459
|
+
interface BootstrapPhase5Result {
|
|
460
|
+
/** Files that were created by this run (already-existing files excluded). */
|
|
461
|
+
created: string[];
|
|
462
|
+
/** Files that were already present and left untouched. */
|
|
463
|
+
skipped: string[];
|
|
464
|
+
/** Files where the write attempt failed (e.g. read-only home). */
|
|
465
|
+
failed: Array<{
|
|
466
|
+
path: string;
|
|
467
|
+
reason: string;
|
|
468
|
+
}>;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Idempotently create the Phase 5 placeholder files under
|
|
472
|
+
* `~/.serviceme/`. Safe to call on every extension activation —
|
|
473
|
+
* existing files are detected via `access` and skipped.
|
|
474
|
+
*/
|
|
475
|
+
declare function bootstrapPhase5Placeholders(): Promise<BootstrapPhase5Result>;
|
|
476
|
+
|
|
196
477
|
declare class ProjectTools {
|
|
197
478
|
extractTemplate(zipPath: string, workspacePath: string, tempExtractDir: string, input: ServiceMeProjectExtractTemplateInput): Promise<ServiceMeProjectExtractTemplateResult>;
|
|
198
479
|
installDependencies(workspacePath: string, command?: string): Promise<ServiceMeProjectInstallDepsResult>;
|
|
@@ -207,17 +488,890 @@ declare class ProjectTools {
|
|
|
207
488
|
}
|
|
208
489
|
declare function createProjectTools(): ProjectTools;
|
|
209
490
|
|
|
491
|
+
/**
|
|
492
|
+
* `repos.json` schema — mirrors §3 of docs/architecture/skill-agent-v2-repo.md.
|
|
493
|
+
*
|
|
494
|
+
* The on-disk file lives at `${SERVICEME_HOME}/repos.json` (see
|
|
495
|
+
* `paths/userHome.getReposConfigPath`). It holds the user-visible catalog of
|
|
496
|
+
* skill/agent repositories (default + user-added) plus the currently-selected
|
|
497
|
+
* default.
|
|
498
|
+
*
|
|
499
|
+
* Two flavours of repo:
|
|
500
|
+
* - `DefaultRepoConfig` — hardcoded by SERVICEME; can only be disabled, not
|
|
501
|
+
* removed.
|
|
502
|
+
* - `UserRepoConfig` — added by the user via the "Add repository" flow;
|
|
503
|
+
* can be removed freely.
|
|
504
|
+
*
|
|
505
|
+
* Both extend `RepoConfig` and add a `source` discriminant so consumers can
|
|
506
|
+
* branch on `repo.source === 'default' | 'user'` without sniffing free-form
|
|
507
|
+
* fields.
|
|
508
|
+
*/
|
|
509
|
+
/** ISO 8601 timestamp. */
|
|
510
|
+
type IsoTimestamp = string;
|
|
511
|
+
/** Per-repo sync health — surfaced in the UI alongside the repo entry. */
|
|
512
|
+
type SyncStatus = "ok" | "error";
|
|
513
|
+
/** Discriminant on `RepoConfig.source` — narrow with a literal check. */
|
|
514
|
+
type RepoSource = "default" | "user";
|
|
515
|
+
/**
|
|
516
|
+
* Common shape shared by both default and user-added repos. Source lives on
|
|
517
|
+
* the type so we can keep the loader schema flat while still letting
|
|
518
|
+
* `DefaultRepoConfig` carry a `description`.
|
|
519
|
+
*/
|
|
520
|
+
interface RepoConfig {
|
|
521
|
+
/** Stable id used in on-disk paths (must match `SAFE_REPO_ID_PATTERN`). */
|
|
522
|
+
id: string;
|
|
523
|
+
/** Display name shown in UI. */
|
|
524
|
+
name: string;
|
|
525
|
+
/** Upstream git URL (typically github.com/<owner>/<repo>.git). */
|
|
526
|
+
url: string;
|
|
527
|
+
/** Default branch to track (e.g. "v2", "main"). */
|
|
528
|
+
branch: string;
|
|
529
|
+
/** Whether this repo participates in scheduled syncs. */
|
|
530
|
+
enabled: boolean;
|
|
531
|
+
/** Whether the user is allowed to push back to this repo. */
|
|
532
|
+
writeEnabled: boolean;
|
|
533
|
+
/** When the user (or first-run installer) added this repo. */
|
|
534
|
+
addedAt: IsoTimestamp;
|
|
535
|
+
/** Last successful sync timestamp. */
|
|
536
|
+
lastSyncAt?: IsoTimestamp;
|
|
537
|
+
/** Commit SHA at the time of the last successful sync. */
|
|
538
|
+
lastSyncCommitSha?: string;
|
|
539
|
+
/** Result of the most recent sync attempt. */
|
|
540
|
+
lastSyncStatus?: SyncStatus;
|
|
541
|
+
/** Error message from the most recent sync attempt (when `lastSyncStatus === 'error'`). */
|
|
542
|
+
lastSyncError?: string;
|
|
543
|
+
/** Whether this repo is a default or a user-added repo. */
|
|
544
|
+
source: RepoSource;
|
|
545
|
+
}
|
|
546
|
+
/** A default (bundled) repo — has a UI-facing description, cannot be removed. */
|
|
547
|
+
interface DefaultRepoConfig extends RepoConfig {
|
|
548
|
+
source: "default";
|
|
549
|
+
description: string;
|
|
550
|
+
}
|
|
551
|
+
/** A user-added repo — can be added, removed, disabled freely. */
|
|
552
|
+
interface UserRepoConfig extends RepoConfig {
|
|
553
|
+
source: "user";
|
|
554
|
+
}
|
|
555
|
+
/** Any repo, regardless of source. */
|
|
556
|
+
type AnyRepoConfig = DefaultRepoConfig | UserRepoConfig;
|
|
557
|
+
/**
|
|
558
|
+
* Root shape of `repos.json`. `version` lets us evolve the schema later
|
|
559
|
+
* without colliding with hand-edited files.
|
|
560
|
+
*/
|
|
561
|
+
interface ReposFile {
|
|
562
|
+
version: 1;
|
|
563
|
+
/** Id of the repo currently surfaced as the default selection in the UI. */
|
|
564
|
+
defaultRepoId: string;
|
|
565
|
+
repos: AnyRepoConfig[];
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Convenience type-guard — narrows to `DefaultRepoConfig`. Useful when callers
|
|
569
|
+
* want to render `repo.description` or reject `removeRepo(repo)` for defaults.
|
|
570
|
+
*/
|
|
571
|
+
declare function isDefaultRepo(repo: RepoConfig): repo is DefaultRepoConfig;
|
|
572
|
+
/** Convenience type-guard — narrows to `UserRepoConfig`. */
|
|
573
|
+
declare function isUserRepo(repo: RepoConfig): repo is UserRepoConfig;
|
|
574
|
+
|
|
575
|
+
declare const defaultRepoSchema: z.ZodObject<{
|
|
576
|
+
source: z.ZodLiteral<"default">;
|
|
577
|
+
description: z.ZodString;
|
|
578
|
+
id: z.ZodString;
|
|
579
|
+
name: z.ZodString;
|
|
580
|
+
url: z.ZodString;
|
|
581
|
+
branch: z.ZodString;
|
|
582
|
+
enabled: z.ZodBoolean;
|
|
583
|
+
writeEnabled: z.ZodBoolean;
|
|
584
|
+
addedAt: z.ZodString;
|
|
585
|
+
lastSyncAt: z.ZodOptional<z.ZodString>;
|
|
586
|
+
lastSyncCommitSha: z.ZodOptional<z.ZodString>;
|
|
587
|
+
lastSyncStatus: z.ZodOptional<z.ZodEnum<["ok", "error"]>>;
|
|
588
|
+
lastSyncError: z.ZodOptional<z.ZodString>;
|
|
589
|
+
}, "strip", z.ZodTypeAny, {
|
|
590
|
+
name: string;
|
|
591
|
+
id: string;
|
|
592
|
+
description: string;
|
|
593
|
+
source: "default";
|
|
594
|
+
url: string;
|
|
595
|
+
branch: string;
|
|
596
|
+
enabled: boolean;
|
|
597
|
+
writeEnabled: boolean;
|
|
598
|
+
addedAt: string;
|
|
599
|
+
lastSyncAt?: string | undefined;
|
|
600
|
+
lastSyncCommitSha?: string | undefined;
|
|
601
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
602
|
+
lastSyncError?: string | undefined;
|
|
603
|
+
}, {
|
|
604
|
+
name: string;
|
|
605
|
+
id: string;
|
|
606
|
+
description: string;
|
|
607
|
+
source: "default";
|
|
608
|
+
url: string;
|
|
609
|
+
branch: string;
|
|
610
|
+
enabled: boolean;
|
|
611
|
+
writeEnabled: boolean;
|
|
612
|
+
addedAt: string;
|
|
613
|
+
lastSyncAt?: string | undefined;
|
|
614
|
+
lastSyncCommitSha?: string | undefined;
|
|
615
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
616
|
+
lastSyncError?: string | undefined;
|
|
617
|
+
}>;
|
|
618
|
+
declare const userRepoSchema: z.ZodObject<{
|
|
619
|
+
source: z.ZodLiteral<"user">;
|
|
620
|
+
id: z.ZodString;
|
|
621
|
+
name: z.ZodString;
|
|
622
|
+
url: z.ZodString;
|
|
623
|
+
branch: z.ZodString;
|
|
624
|
+
enabled: z.ZodBoolean;
|
|
625
|
+
writeEnabled: z.ZodBoolean;
|
|
626
|
+
addedAt: z.ZodString;
|
|
627
|
+
lastSyncAt: z.ZodOptional<z.ZodString>;
|
|
628
|
+
lastSyncCommitSha: z.ZodOptional<z.ZodString>;
|
|
629
|
+
lastSyncStatus: z.ZodOptional<z.ZodEnum<["ok", "error"]>>;
|
|
630
|
+
lastSyncError: z.ZodOptional<z.ZodString>;
|
|
631
|
+
}, "strip", z.ZodTypeAny, {
|
|
632
|
+
name: string;
|
|
633
|
+
id: string;
|
|
634
|
+
source: "user";
|
|
635
|
+
url: string;
|
|
636
|
+
branch: string;
|
|
637
|
+
enabled: boolean;
|
|
638
|
+
writeEnabled: boolean;
|
|
639
|
+
addedAt: string;
|
|
640
|
+
lastSyncAt?: string | undefined;
|
|
641
|
+
lastSyncCommitSha?: string | undefined;
|
|
642
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
643
|
+
lastSyncError?: string | undefined;
|
|
644
|
+
}, {
|
|
645
|
+
name: string;
|
|
646
|
+
id: string;
|
|
647
|
+
source: "user";
|
|
648
|
+
url: string;
|
|
649
|
+
branch: string;
|
|
650
|
+
enabled: boolean;
|
|
651
|
+
writeEnabled: boolean;
|
|
652
|
+
addedAt: string;
|
|
653
|
+
lastSyncAt?: string | undefined;
|
|
654
|
+
lastSyncCommitSha?: string | undefined;
|
|
655
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
656
|
+
lastSyncError?: string | undefined;
|
|
657
|
+
}>;
|
|
658
|
+
declare const repoSchema: z.ZodDiscriminatedUnion<"source", [z.ZodObject<{
|
|
659
|
+
source: z.ZodLiteral<"default">;
|
|
660
|
+
description: z.ZodString;
|
|
661
|
+
id: z.ZodString;
|
|
662
|
+
name: z.ZodString;
|
|
663
|
+
url: z.ZodString;
|
|
664
|
+
branch: z.ZodString;
|
|
665
|
+
enabled: z.ZodBoolean;
|
|
666
|
+
writeEnabled: z.ZodBoolean;
|
|
667
|
+
addedAt: z.ZodString;
|
|
668
|
+
lastSyncAt: z.ZodOptional<z.ZodString>;
|
|
669
|
+
lastSyncCommitSha: z.ZodOptional<z.ZodString>;
|
|
670
|
+
lastSyncStatus: z.ZodOptional<z.ZodEnum<["ok", "error"]>>;
|
|
671
|
+
lastSyncError: z.ZodOptional<z.ZodString>;
|
|
672
|
+
}, "strip", z.ZodTypeAny, {
|
|
673
|
+
name: string;
|
|
674
|
+
id: string;
|
|
675
|
+
description: string;
|
|
676
|
+
source: "default";
|
|
677
|
+
url: string;
|
|
678
|
+
branch: string;
|
|
679
|
+
enabled: boolean;
|
|
680
|
+
writeEnabled: boolean;
|
|
681
|
+
addedAt: string;
|
|
682
|
+
lastSyncAt?: string | undefined;
|
|
683
|
+
lastSyncCommitSha?: string | undefined;
|
|
684
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
685
|
+
lastSyncError?: string | undefined;
|
|
686
|
+
}, {
|
|
687
|
+
name: string;
|
|
688
|
+
id: string;
|
|
689
|
+
description: string;
|
|
690
|
+
source: "default";
|
|
691
|
+
url: string;
|
|
692
|
+
branch: string;
|
|
693
|
+
enabled: boolean;
|
|
694
|
+
writeEnabled: boolean;
|
|
695
|
+
addedAt: string;
|
|
696
|
+
lastSyncAt?: string | undefined;
|
|
697
|
+
lastSyncCommitSha?: string | undefined;
|
|
698
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
699
|
+
lastSyncError?: string | undefined;
|
|
700
|
+
}>, z.ZodObject<{
|
|
701
|
+
source: z.ZodLiteral<"user">;
|
|
702
|
+
id: z.ZodString;
|
|
703
|
+
name: z.ZodString;
|
|
704
|
+
url: z.ZodString;
|
|
705
|
+
branch: z.ZodString;
|
|
706
|
+
enabled: z.ZodBoolean;
|
|
707
|
+
writeEnabled: z.ZodBoolean;
|
|
708
|
+
addedAt: z.ZodString;
|
|
709
|
+
lastSyncAt: z.ZodOptional<z.ZodString>;
|
|
710
|
+
lastSyncCommitSha: z.ZodOptional<z.ZodString>;
|
|
711
|
+
lastSyncStatus: z.ZodOptional<z.ZodEnum<["ok", "error"]>>;
|
|
712
|
+
lastSyncError: z.ZodOptional<z.ZodString>;
|
|
713
|
+
}, "strip", z.ZodTypeAny, {
|
|
714
|
+
name: string;
|
|
715
|
+
id: string;
|
|
716
|
+
source: "user";
|
|
717
|
+
url: string;
|
|
718
|
+
branch: string;
|
|
719
|
+
enabled: boolean;
|
|
720
|
+
writeEnabled: boolean;
|
|
721
|
+
addedAt: string;
|
|
722
|
+
lastSyncAt?: string | undefined;
|
|
723
|
+
lastSyncCommitSha?: string | undefined;
|
|
724
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
725
|
+
lastSyncError?: string | undefined;
|
|
726
|
+
}, {
|
|
727
|
+
name: string;
|
|
728
|
+
id: string;
|
|
729
|
+
source: "user";
|
|
730
|
+
url: string;
|
|
731
|
+
branch: string;
|
|
732
|
+
enabled: boolean;
|
|
733
|
+
writeEnabled: boolean;
|
|
734
|
+
addedAt: string;
|
|
735
|
+
lastSyncAt?: string | undefined;
|
|
736
|
+
lastSyncCommitSha?: string | undefined;
|
|
737
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
738
|
+
lastSyncError?: string | undefined;
|
|
739
|
+
}>]>;
|
|
740
|
+
declare const reposFileSchema: z.ZodEffects<z.ZodObject<{
|
|
741
|
+
version: z.ZodLiteral<1>;
|
|
742
|
+
defaultRepoId: z.ZodString;
|
|
743
|
+
repos: z.ZodArray<z.ZodDiscriminatedUnion<"source", [z.ZodObject<{
|
|
744
|
+
source: z.ZodLiteral<"default">;
|
|
745
|
+
description: z.ZodString;
|
|
746
|
+
id: z.ZodString;
|
|
747
|
+
name: z.ZodString;
|
|
748
|
+
url: z.ZodString;
|
|
749
|
+
branch: z.ZodString;
|
|
750
|
+
enabled: z.ZodBoolean;
|
|
751
|
+
writeEnabled: z.ZodBoolean;
|
|
752
|
+
addedAt: z.ZodString;
|
|
753
|
+
lastSyncAt: z.ZodOptional<z.ZodString>;
|
|
754
|
+
lastSyncCommitSha: z.ZodOptional<z.ZodString>;
|
|
755
|
+
lastSyncStatus: z.ZodOptional<z.ZodEnum<["ok", "error"]>>;
|
|
756
|
+
lastSyncError: z.ZodOptional<z.ZodString>;
|
|
757
|
+
}, "strip", z.ZodTypeAny, {
|
|
758
|
+
name: string;
|
|
759
|
+
id: string;
|
|
760
|
+
description: string;
|
|
761
|
+
source: "default";
|
|
762
|
+
url: string;
|
|
763
|
+
branch: string;
|
|
764
|
+
enabled: boolean;
|
|
765
|
+
writeEnabled: boolean;
|
|
766
|
+
addedAt: string;
|
|
767
|
+
lastSyncAt?: string | undefined;
|
|
768
|
+
lastSyncCommitSha?: string | undefined;
|
|
769
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
770
|
+
lastSyncError?: string | undefined;
|
|
771
|
+
}, {
|
|
772
|
+
name: string;
|
|
773
|
+
id: string;
|
|
774
|
+
description: string;
|
|
775
|
+
source: "default";
|
|
776
|
+
url: string;
|
|
777
|
+
branch: string;
|
|
778
|
+
enabled: boolean;
|
|
779
|
+
writeEnabled: boolean;
|
|
780
|
+
addedAt: string;
|
|
781
|
+
lastSyncAt?: string | undefined;
|
|
782
|
+
lastSyncCommitSha?: string | undefined;
|
|
783
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
784
|
+
lastSyncError?: string | undefined;
|
|
785
|
+
}>, z.ZodObject<{
|
|
786
|
+
source: z.ZodLiteral<"user">;
|
|
787
|
+
id: z.ZodString;
|
|
788
|
+
name: z.ZodString;
|
|
789
|
+
url: z.ZodString;
|
|
790
|
+
branch: z.ZodString;
|
|
791
|
+
enabled: z.ZodBoolean;
|
|
792
|
+
writeEnabled: z.ZodBoolean;
|
|
793
|
+
addedAt: z.ZodString;
|
|
794
|
+
lastSyncAt: z.ZodOptional<z.ZodString>;
|
|
795
|
+
lastSyncCommitSha: z.ZodOptional<z.ZodString>;
|
|
796
|
+
lastSyncStatus: z.ZodOptional<z.ZodEnum<["ok", "error"]>>;
|
|
797
|
+
lastSyncError: z.ZodOptional<z.ZodString>;
|
|
798
|
+
}, "strip", z.ZodTypeAny, {
|
|
799
|
+
name: string;
|
|
800
|
+
id: string;
|
|
801
|
+
source: "user";
|
|
802
|
+
url: string;
|
|
803
|
+
branch: string;
|
|
804
|
+
enabled: boolean;
|
|
805
|
+
writeEnabled: boolean;
|
|
806
|
+
addedAt: string;
|
|
807
|
+
lastSyncAt?: string | undefined;
|
|
808
|
+
lastSyncCommitSha?: string | undefined;
|
|
809
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
810
|
+
lastSyncError?: string | undefined;
|
|
811
|
+
}, {
|
|
812
|
+
name: string;
|
|
813
|
+
id: string;
|
|
814
|
+
source: "user";
|
|
815
|
+
url: string;
|
|
816
|
+
branch: string;
|
|
817
|
+
enabled: boolean;
|
|
818
|
+
writeEnabled: boolean;
|
|
819
|
+
addedAt: string;
|
|
820
|
+
lastSyncAt?: string | undefined;
|
|
821
|
+
lastSyncCommitSha?: string | undefined;
|
|
822
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
823
|
+
lastSyncError?: string | undefined;
|
|
824
|
+
}>]>, "many">;
|
|
825
|
+
}, "strip", z.ZodTypeAny, {
|
|
826
|
+
version: 1;
|
|
827
|
+
repos: ({
|
|
828
|
+
name: string;
|
|
829
|
+
id: string;
|
|
830
|
+
description: string;
|
|
831
|
+
source: "default";
|
|
832
|
+
url: string;
|
|
833
|
+
branch: string;
|
|
834
|
+
enabled: boolean;
|
|
835
|
+
writeEnabled: boolean;
|
|
836
|
+
addedAt: string;
|
|
837
|
+
lastSyncAt?: string | undefined;
|
|
838
|
+
lastSyncCommitSha?: string | undefined;
|
|
839
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
840
|
+
lastSyncError?: string | undefined;
|
|
841
|
+
} | {
|
|
842
|
+
name: string;
|
|
843
|
+
id: string;
|
|
844
|
+
source: "user";
|
|
845
|
+
url: string;
|
|
846
|
+
branch: string;
|
|
847
|
+
enabled: boolean;
|
|
848
|
+
writeEnabled: boolean;
|
|
849
|
+
addedAt: string;
|
|
850
|
+
lastSyncAt?: string | undefined;
|
|
851
|
+
lastSyncCommitSha?: string | undefined;
|
|
852
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
853
|
+
lastSyncError?: string | undefined;
|
|
854
|
+
})[];
|
|
855
|
+
defaultRepoId: string;
|
|
856
|
+
}, {
|
|
857
|
+
version: 1;
|
|
858
|
+
repos: ({
|
|
859
|
+
name: string;
|
|
860
|
+
id: string;
|
|
861
|
+
description: string;
|
|
862
|
+
source: "default";
|
|
863
|
+
url: string;
|
|
864
|
+
branch: string;
|
|
865
|
+
enabled: boolean;
|
|
866
|
+
writeEnabled: boolean;
|
|
867
|
+
addedAt: string;
|
|
868
|
+
lastSyncAt?: string | undefined;
|
|
869
|
+
lastSyncCommitSha?: string | undefined;
|
|
870
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
871
|
+
lastSyncError?: string | undefined;
|
|
872
|
+
} | {
|
|
873
|
+
name: string;
|
|
874
|
+
id: string;
|
|
875
|
+
source: "user";
|
|
876
|
+
url: string;
|
|
877
|
+
branch: string;
|
|
878
|
+
enabled: boolean;
|
|
879
|
+
writeEnabled: boolean;
|
|
880
|
+
addedAt: string;
|
|
881
|
+
lastSyncAt?: string | undefined;
|
|
882
|
+
lastSyncCommitSha?: string | undefined;
|
|
883
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
884
|
+
lastSyncError?: string | undefined;
|
|
885
|
+
})[];
|
|
886
|
+
defaultRepoId: string;
|
|
887
|
+
}>, {
|
|
888
|
+
version: 1;
|
|
889
|
+
repos: ({
|
|
890
|
+
name: string;
|
|
891
|
+
id: string;
|
|
892
|
+
description: string;
|
|
893
|
+
source: "default";
|
|
894
|
+
url: string;
|
|
895
|
+
branch: string;
|
|
896
|
+
enabled: boolean;
|
|
897
|
+
writeEnabled: boolean;
|
|
898
|
+
addedAt: string;
|
|
899
|
+
lastSyncAt?: string | undefined;
|
|
900
|
+
lastSyncCommitSha?: string | undefined;
|
|
901
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
902
|
+
lastSyncError?: string | undefined;
|
|
903
|
+
} | {
|
|
904
|
+
name: string;
|
|
905
|
+
id: string;
|
|
906
|
+
source: "user";
|
|
907
|
+
url: string;
|
|
908
|
+
branch: string;
|
|
909
|
+
enabled: boolean;
|
|
910
|
+
writeEnabled: boolean;
|
|
911
|
+
addedAt: string;
|
|
912
|
+
lastSyncAt?: string | undefined;
|
|
913
|
+
lastSyncCommitSha?: string | undefined;
|
|
914
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
915
|
+
lastSyncError?: string | undefined;
|
|
916
|
+
})[];
|
|
917
|
+
defaultRepoId: string;
|
|
918
|
+
}, {
|
|
919
|
+
version: 1;
|
|
920
|
+
repos: ({
|
|
921
|
+
name: string;
|
|
922
|
+
id: string;
|
|
923
|
+
description: string;
|
|
924
|
+
source: "default";
|
|
925
|
+
url: string;
|
|
926
|
+
branch: string;
|
|
927
|
+
enabled: boolean;
|
|
928
|
+
writeEnabled: boolean;
|
|
929
|
+
addedAt: string;
|
|
930
|
+
lastSyncAt?: string | undefined;
|
|
931
|
+
lastSyncCommitSha?: string | undefined;
|
|
932
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
933
|
+
lastSyncError?: string | undefined;
|
|
934
|
+
} | {
|
|
935
|
+
name: string;
|
|
936
|
+
id: string;
|
|
937
|
+
source: "user";
|
|
938
|
+
url: string;
|
|
939
|
+
branch: string;
|
|
940
|
+
enabled: boolean;
|
|
941
|
+
writeEnabled: boolean;
|
|
942
|
+
addedAt: string;
|
|
943
|
+
lastSyncAt?: string | undefined;
|
|
944
|
+
lastSyncCommitSha?: string | undefined;
|
|
945
|
+
lastSyncStatus?: "ok" | "error" | undefined;
|
|
946
|
+
lastSyncError?: string | undefined;
|
|
947
|
+
})[];
|
|
948
|
+
defaultRepoId: string;
|
|
949
|
+
}>;
|
|
950
|
+
/** Inferred Zod type — identical to our hand-written `ReposFile`. */
|
|
951
|
+
type ReposFileInput = z.infer<typeof reposFileSchema>;
|
|
952
|
+
/** Result of a load attempt — either a parsed file or a recovery notice. */
|
|
953
|
+
interface LoadResult {
|
|
954
|
+
/** Parsed + validated repos file (always populated, even on recovery). */
|
|
955
|
+
config: ReposFile;
|
|
956
|
+
/**
|
|
957
|
+
* Non-null when the existing file on disk was unreadable / invalid and
|
|
958
|
+
* was moved aside as a `.bak`. The store can use this to surface a
|
|
959
|
+
* warning in the UI.
|
|
960
|
+
*/
|
|
961
|
+
recoveredFromBackup: string | null;
|
|
962
|
+
}
|
|
963
|
+
/** Dependencies — defaults to the real fs, tests inject a fake. */
|
|
964
|
+
interface ReposLoaderFileSystem {
|
|
965
|
+
readFile: typeof fs.readFile;
|
|
966
|
+
writeFile: typeof fs.writeFile;
|
|
967
|
+
rename: typeof fs.rename;
|
|
968
|
+
mkdir: typeof fs.mkdir;
|
|
969
|
+
stat: typeof fs.stat;
|
|
970
|
+
unlink?: typeof fs.unlink;
|
|
971
|
+
}
|
|
972
|
+
interface ReposLoaderOptions {
|
|
973
|
+
/** Absolute path of the `repos.json` file. */
|
|
974
|
+
configPath: string;
|
|
975
|
+
/** Custom time provider — defaults to `() => new Date().toISOString()`. */
|
|
976
|
+
now?: () => string;
|
|
977
|
+
/** Random suffix provider for atomic-write temp files. */
|
|
978
|
+
randomSuffix?: () => string;
|
|
979
|
+
/** Filesystem shim for tests. */
|
|
980
|
+
fileSystem?: ReposLoaderFileSystem;
|
|
981
|
+
}
|
|
982
|
+
declare class ReposLoader {
|
|
983
|
+
private readonly configPath;
|
|
984
|
+
private readonly now;
|
|
985
|
+
private readonly randomSuffix;
|
|
986
|
+
private readonly fileSystem;
|
|
987
|
+
constructor(options: ReposLoaderOptions);
|
|
988
|
+
/** Absolute path of the file this loader reads/writes. */
|
|
989
|
+
getConfigPath(): string;
|
|
990
|
+
/**
|
|
991
|
+
* Read + validate the on-disk config. When the file is missing, returns a
|
|
992
|
+
* sentinel empty config (no backup is taken — that's expected on first
|
|
993
|
+
* run). When the file is corrupted, moves it to `<name>.<ts>.bak` and
|
|
994
|
+
* returns an empty config with `recoveredFromBackup` populated.
|
|
995
|
+
*/
|
|
996
|
+
load(): Promise<LoadResult>;
|
|
997
|
+
/**
|
|
998
|
+
* Write the config to disk atomically. Writes to
|
|
999
|
+
* `<target>.tmp-<random>` then `rename`s over the target. The parent
|
|
1000
|
+
* directory is created on demand.
|
|
1001
|
+
*/
|
|
1002
|
+
save(config: ReposFile): Promise<void>;
|
|
1003
|
+
/**
|
|
1004
|
+
* Move the existing file to a timestamped `.bak` sibling and return the
|
|
1005
|
+
* backup path. Used when we detect a corrupted / unparseable file and
|
|
1006
|
+
* need to make room for a fresh write.
|
|
1007
|
+
*/
|
|
1008
|
+
private quarantine;
|
|
1009
|
+
/**
|
|
1010
|
+
* Empty config used when no file exists or the existing file is corrupt.
|
|
1011
|
+
* The caller (e.g. `ensureDefaultsInstalled`) is expected to populate the
|
|
1012
|
+
* real default repo set before persisting.
|
|
1013
|
+
*/
|
|
1014
|
+
private buildEmptyConfig;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/** Helper: parse + validate a config object (e.g. freshly built in memory). */
|
|
1018
|
+
declare function validateReposFile(input: unknown): ReposFile;
|
|
1019
|
+
/** Helper: discriminate a `RepoConfig` between default and user flavours. */
|
|
1020
|
+
declare function narrowRepoConfig(repo: AnyRepoConfig): DefaultRepoConfig | UserRepoConfig;
|
|
1021
|
+
|
|
1022
|
+
/**
|
|
1023
|
+
* In-memory CRUD store for `repos.json`.
|
|
1024
|
+
*
|
|
1025
|
+
* Responsibilities:
|
|
1026
|
+
* - Hold the authoritative `ReposFile` state in memory.
|
|
1027
|
+
* - Re-load on `fs.watch` events so external writes (CLI edit, user edit)
|
|
1028
|
+
* propagate to in-process consumers (extension UI, bridge calls).
|
|
1029
|
+
* - Emit `change` events so consumers can re-render without polling.
|
|
1030
|
+
* - Validate every write through {@link ReposLoader} so a programmatic
|
|
1031
|
+
* `addRepo` cannot smuggle in a malformed entry.
|
|
1032
|
+
*
|
|
1033
|
+
* The store deliberately does **not** own `fs.watch` resources by default.
|
|
1034
|
+
* Callers opt in via {@link ReposStore.startWatching} / {@link stopWatching}
|
|
1035
|
+
* so tests can run without lingering watchers.
|
|
1036
|
+
*/
|
|
1037
|
+
/** Mutating event from the store. */
|
|
1038
|
+
type ReposStoreChange = {
|
|
1039
|
+
kind: "load";
|
|
1040
|
+
config: ReposFile;
|
|
1041
|
+
} | {
|
|
1042
|
+
kind: "add";
|
|
1043
|
+
repo: AnyRepoConfig;
|
|
1044
|
+
} | {
|
|
1045
|
+
kind: "update";
|
|
1046
|
+
repo: AnyRepoConfig;
|
|
1047
|
+
} | {
|
|
1048
|
+
kind: "remove";
|
|
1049
|
+
repoId: string;
|
|
1050
|
+
} | {
|
|
1051
|
+
kind: "default-change";
|
|
1052
|
+
defaultRepoId: string;
|
|
1053
|
+
} | {
|
|
1054
|
+
kind: "error";
|
|
1055
|
+
error: Error;
|
|
1056
|
+
};
|
|
1057
|
+
/** Subscriber callback. */
|
|
1058
|
+
type ReposStoreListener = (change: ReposStoreChange) => void;
|
|
1059
|
+
/** Dependencies — defaults to the real fs, tests inject a fake. */
|
|
1060
|
+
interface ReposStoreFileSystem {
|
|
1061
|
+
watch: typeof fs$1.watch;
|
|
1062
|
+
}
|
|
1063
|
+
interface ReposStoreOptions {
|
|
1064
|
+
/** Use an explicit loader (defaults to one wrapping the resolved configPath). */
|
|
1065
|
+
loader?: ReposLoader;
|
|
1066
|
+
/** File-system watch implementation — defaults to `fs.watch`. */
|
|
1067
|
+
fileSystem?: ReposStoreFileSystem;
|
|
1068
|
+
/** Time provider for `addedAt` stamping. */
|
|
1069
|
+
now?: () => string;
|
|
1070
|
+
/**
|
|
1071
|
+
* Debounce window for `fs.watch` callbacks. Editors sometimes emit
|
|
1072
|
+
* multiple `change` events for a single logical write — coalesce them.
|
|
1073
|
+
* Defaults to 50ms.
|
|
1074
|
+
*/
|
|
1075
|
+
debounceMs?: number;
|
|
1076
|
+
/**
|
|
1077
|
+
* Watch implementation factory — defaults to a no-deps wrapper around
|
|
1078
|
+
* `fs.watch`. Tests inject a fake watcher here. The store wires the
|
|
1079
|
+
* returned handle to its own schedule/error flow via the supplied
|
|
1080
|
+
* callbacks.
|
|
1081
|
+
*/
|
|
1082
|
+
createFsWatcher?: (configPath: string, callbacks: FsWatcherCallbacks) => FsWatcherHandle;
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Minimal subset of `fs.FSWatcher` that the store depends on. Defining our
|
|
1086
|
+
* own type lets tests inject a fake without dragging in real fs handles.
|
|
1087
|
+
*/
|
|
1088
|
+
interface FsWatcherHandle {
|
|
1089
|
+
close(): void;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Callbacks the store wires to a watcher. The default `fs.watch` factory
|
|
1093
|
+
* uses these to forward events into `scheduleReload` / `error` emission;
|
|
1094
|
+
* tests can ignore them when they only care about lifecycle.
|
|
1095
|
+
*/
|
|
1096
|
+
interface FsWatcherCallbacks {
|
|
1097
|
+
onChange?: () => void;
|
|
1098
|
+
onRename?: () => void;
|
|
1099
|
+
onError?: (err: Error) => void;
|
|
1100
|
+
}
|
|
1101
|
+
declare class ReposStore {
|
|
1102
|
+
private readonly loader;
|
|
1103
|
+
private readonly fileSystem;
|
|
1104
|
+
private readonly now;
|
|
1105
|
+
private readonly debounceMs;
|
|
1106
|
+
private readonly createFsWatcher;
|
|
1107
|
+
private config;
|
|
1108
|
+
private readonly emitter;
|
|
1109
|
+
private watcher;
|
|
1110
|
+
private reloadTimer;
|
|
1111
|
+
private lastLoadResult;
|
|
1112
|
+
constructor(options?: ReposStoreOptions);
|
|
1113
|
+
/** Currently held config, or `null` if `load()` has not been called yet. */
|
|
1114
|
+
getConfig(): ReposFile | null;
|
|
1115
|
+
/** Path of the underlying `repos.json` file (via the loader). */
|
|
1116
|
+
getConfigPath(): string;
|
|
1117
|
+
/** Subscribe to store mutations. Returns an unsubscribe function. */
|
|
1118
|
+
subscribe(listener: ReposStoreListener): () => void;
|
|
1119
|
+
/**
|
|
1120
|
+
* Read the config from disk (delegating to the loader) and seed the
|
|
1121
|
+
* in-memory state. Safe to call repeatedly.
|
|
1122
|
+
*/
|
|
1123
|
+
load(): Promise<LoadResult>;
|
|
1124
|
+
/** Convenience getter — wraps `load()` and returns the config. */
|
|
1125
|
+
ensureLoaded(): Promise<ReposFile>;
|
|
1126
|
+
/** The most recent `LoadResult`, useful for surfacing recovery warnings. */
|
|
1127
|
+
getLastLoadResult(): LoadResult | null;
|
|
1128
|
+
/**
|
|
1129
|
+
* Start watching the config file for external changes. Subsequent writes
|
|
1130
|
+
* (or edits from another process) trigger a debounced re-load.
|
|
1131
|
+
*
|
|
1132
|
+
* No-op when already watching.
|
|
1133
|
+
*/
|
|
1134
|
+
startWatching(): void;
|
|
1135
|
+
/** Stop watching and release any pending reload timers. */
|
|
1136
|
+
stopWatching(): void;
|
|
1137
|
+
list(): AnyRepoConfig[];
|
|
1138
|
+
listDefault(): AnyRepoConfig[];
|
|
1139
|
+
listUser(): UserRepoConfig[];
|
|
1140
|
+
get(repoId: string): AnyRepoConfig | undefined;
|
|
1141
|
+
/**
|
|
1142
|
+
* Add a user repo. Throws when the id already exists. The `addedAt`
|
|
1143
|
+
* timestamp defaults to `now()` when not provided. Persists to disk.
|
|
1144
|
+
*/
|
|
1145
|
+
addUserRepo(input: Omit<UserRepoConfig, "source">): Promise<UserRepoConfig>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Update an existing repo by id (partial). Throws when not found.
|
|
1148
|
+
* Persists to disk.
|
|
1149
|
+
*/
|
|
1150
|
+
updateRepo(repoId: string, patch: Partial<RepoConfig>): Promise<AnyRepoConfig>;
|
|
1151
|
+
/**
|
|
1152
|
+
* Remove a user repo. Throws when the repo is a default or does not exist.
|
|
1153
|
+
* Persists to disk.
|
|
1154
|
+
*/
|
|
1155
|
+
removeUserRepo(repoId: string): Promise<void>;
|
|
1156
|
+
/**
|
|
1157
|
+
* Disable a repo (any source). Useful for the "Disable" button on default
|
|
1158
|
+
* repos. Persists to disk.
|
|
1159
|
+
*/
|
|
1160
|
+
disableRepo(repoId: string): Promise<AnyRepoConfig>;
|
|
1161
|
+
/** Inverse of {@link disableRepo}. */
|
|
1162
|
+
enableRepo(repoId: string): Promise<AnyRepoConfig>;
|
|
1163
|
+
/** Change which repo the UI surfaces as the default. Persists to disk. */
|
|
1164
|
+
setDefaultRepoId(repoId: string): Promise<void>;
|
|
1165
|
+
getDefaultRepoId(): string | null;
|
|
1166
|
+
/** Returns the configured `now` provider — exposed for `bootstrapDefaults`. */
|
|
1167
|
+
getNow(): () => string;
|
|
1168
|
+
/**
|
|
1169
|
+
* Replace the in-memory config and persist it. Used by helpers like
|
|
1170
|
+
* `bootstrapDefaults` that build a new config wholesale (rather than
|
|
1171
|
+
* mutating a single field).
|
|
1172
|
+
*/
|
|
1173
|
+
replaceConfig(next: ReposFile): Promise<ReposFile>;
|
|
1174
|
+
private mutate;
|
|
1175
|
+
private emit;
|
|
1176
|
+
/**
|
|
1177
|
+
* Default `fs.watch` adapter. Public so tests can wrap a real watcher
|
|
1178
|
+
* with a debounce trampoline if they need to.
|
|
1179
|
+
*/
|
|
1180
|
+
private defaultCreateFsWatcher;
|
|
1181
|
+
private scheduleReload;
|
|
1182
|
+
}
|
|
1183
|
+
/** Factory: creates a `ReposStore` bound to a specific config path. */
|
|
1184
|
+
declare function createReposStore(configPath: string, options?: Omit<ReposStoreOptions, "loader">): ReposStore;
|
|
1185
|
+
/** Error: tried to add a repo whose id already exists. */
|
|
1186
|
+
declare class RepoAlreadyExistsError extends Error {
|
|
1187
|
+
readonly repoId: string;
|
|
1188
|
+
constructor(repoId: string);
|
|
1189
|
+
}
|
|
1190
|
+
/** Error: looked up a repo id that isn't present in the current config. */
|
|
1191
|
+
declare class RepoNotFoundError extends Error {
|
|
1192
|
+
readonly repoId: string;
|
|
1193
|
+
constructor(repoId: string);
|
|
1194
|
+
}
|
|
1195
|
+
/** Error: tried to remove a default repo (defaults are disable-only). */
|
|
1196
|
+
declare class CannotRemoveDefaultRepoError extends Error {
|
|
1197
|
+
readonly repoId: string;
|
|
1198
|
+
constructor(repoId: string);
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Bootstrap helper — invokes `ensureDefaultsInstalled` on the store to
|
|
1202
|
+
* guarantee that the 4 default repos are present. Returns the resulting
|
|
1203
|
+
* config. Lives here (not in `default-repos.ts`) to keep the default-repo
|
|
1204
|
+
* module free of store concerns.
|
|
1205
|
+
*/
|
|
1206
|
+
declare function bootstrapDefaults(store: ReposStore): Promise<ReposFile>;
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* Skill & Agent v2 — Client RepoManager (M3)
|
|
1210
|
+
*
|
|
1211
|
+
* RepoManager is the orchestrator for local git repo management. It
|
|
1212
|
+
* composes:
|
|
1213
|
+
* - {@link ReposStore} (in-memory CRUD over `~/.serviceme/repos.json`)
|
|
1214
|
+
* - {@link GitClient} (spawns `git` against the server proxy)
|
|
1215
|
+
* - the filesystem (clone targets live under `~/.serviceme/repos/<id>/`)
|
|
1216
|
+
*
|
|
1217
|
+
* Lifecycle responsibilities:
|
|
1218
|
+
* - **Bootstrap**: on first launch, clone all enabled default repos.
|
|
1219
|
+
* - **Sync**: pullOne / pullAll for periodic updates.
|
|
1220
|
+
* - **User repos**: addUserRepo validates URL, probes branch via
|
|
1221
|
+
* `git ls-remote`, writes the entry, and triggers an async clone.
|
|
1222
|
+
* - **Cleanup**: removeUserRepo deletes both the local clone AND the
|
|
1223
|
+
* `repos.json` entry. disableRepo / enableRepo only flip a flag.
|
|
1224
|
+
*
|
|
1225
|
+
* Default repos (`source === 'default'`) cannot be removed — only
|
|
1226
|
+
* disabled. The Store enforces this; RepoManager propagates the error.
|
|
1227
|
+
*
|
|
1228
|
+
* @see docs/architecture/skill-agent-v2-repo.md §5.3 RepoManager
|
|
1229
|
+
*/
|
|
1230
|
+
interface RepoManagerOptions {
|
|
1231
|
+
store: ReposStore;
|
|
1232
|
+
gitClient: GitClient;
|
|
1233
|
+
/** Override the clock for deterministic tests. */
|
|
1234
|
+
now?: () => string;
|
|
1235
|
+
/** Skip the actual git clone (used by tests). When true, the
|
|
1236
|
+
* filesystem-side mkdir is the only side effect. */
|
|
1237
|
+
skipClone?: boolean;
|
|
1238
|
+
}
|
|
1239
|
+
interface AddUserRepoInput {
|
|
1240
|
+
/** Upstream URL the user pasted in. */
|
|
1241
|
+
url: string;
|
|
1242
|
+
/** Branch to track. Auto-detected from upstream when omitted. */
|
|
1243
|
+
branch?: string;
|
|
1244
|
+
/** Optional display name (defaults to id). */
|
|
1245
|
+
name?: string;
|
|
1246
|
+
}
|
|
1247
|
+
interface AddUserRepoResult {
|
|
1248
|
+
repo: UserRepoConfig;
|
|
1249
|
+
branch: string;
|
|
1250
|
+
cloned: boolean;
|
|
1251
|
+
}
|
|
1252
|
+
/** Snapshot of a sync run, suitable for UI rendering. */
|
|
1253
|
+
interface SyncReport {
|
|
1254
|
+
pulls: Array<{
|
|
1255
|
+
repoId: string;
|
|
1256
|
+
status: "ok" | "error";
|
|
1257
|
+
result?: PullResult;
|
|
1258
|
+
error?: string;
|
|
1259
|
+
}>;
|
|
1260
|
+
}
|
|
1261
|
+
/** Sentinel errors. */
|
|
1262
|
+
declare class RepoManagerError extends Error {
|
|
1263
|
+
constructor(message: string);
|
|
1264
|
+
}
|
|
1265
|
+
declare class InvalidRepoUrlError extends RepoManagerError {
|
|
1266
|
+
}
|
|
1267
|
+
declare class RepoCloneConflictError extends RepoManagerError {
|
|
1268
|
+
}
|
|
1269
|
+
declare class RepoNotInStoreError extends RepoManagerError {
|
|
1270
|
+
}
|
|
1271
|
+
declare class RepoManager {
|
|
1272
|
+
private readonly store;
|
|
1273
|
+
private readonly git;
|
|
1274
|
+
private readonly now;
|
|
1275
|
+
private readonly skipClone;
|
|
1276
|
+
constructor(opts: RepoManagerOptions);
|
|
1277
|
+
/**
|
|
1278
|
+
* Clone every enabled default repo that doesn't have a local clone
|
|
1279
|
+
* yet. Failures on individual repos are recorded in `lastSyncStatus`
|
|
1280
|
+
* but do NOT abort the loop — the UI surfaces per-repo state and the
|
|
1281
|
+
* user can retry.
|
|
1282
|
+
*
|
|
1283
|
+
* Per spec §3.1: 4 default repos; the loop honors `enabled=false` and
|
|
1284
|
+
* disables (rather than removes) repos the user has turned off.
|
|
1285
|
+
*/
|
|
1286
|
+
ensureDefaults(): Promise<SyncReport>;
|
|
1287
|
+
/**
|
|
1288
|
+
* Pull a single repo. Updates `lastSync*` fields on success or failure.
|
|
1289
|
+
* Returns the raw `PullResult` so callers can surface fetch progress.
|
|
1290
|
+
*/
|
|
1291
|
+
pullOne(repoId: string): Promise<PullResult>;
|
|
1292
|
+
/** Pull every enabled repo. Per-repo failures don't abort the run. */
|
|
1293
|
+
pullAll(): Promise<SyncReport>;
|
|
1294
|
+
/**
|
|
1295
|
+
* Validate URL, derive an id, detect the branch via `git ls-remote`,
|
|
1296
|
+
* then add the entry to the store and trigger a clone.
|
|
1297
|
+
*
|
|
1298
|
+
* Spec §5.3 says "branch detection" happens BEFORE the store write so
|
|
1299
|
+
* the resulting `repos.json` is fully populated. The clone is async
|
|
1300
|
+
* but the function returns synchronously once the store is updated
|
|
1301
|
+
* (cloning happens via `ensureDefaults`-style background fire).
|
|
1302
|
+
*
|
|
1303
|
+
* For tests with `skipClone: true`, the clone is skipped entirely.
|
|
1304
|
+
*/
|
|
1305
|
+
addUserRepo(input: AddUserRepoInput): Promise<AddUserRepoResult>;
|
|
1306
|
+
/**
|
|
1307
|
+
* Remove a user-added repo. Throws when:
|
|
1308
|
+
* - the repo is unknown
|
|
1309
|
+
* - the repo is a default (use `disableRepo` instead — store enforces)
|
|
1310
|
+
*
|
|
1311
|
+
* The local clone is deleted via `fs.rm`. If the local dir is
|
|
1312
|
+
* already gone we silently succeed (idempotent re-remove).
|
|
1313
|
+
*/
|
|
1314
|
+
removeUserRepo(repoId: string): Promise<void>;
|
|
1315
|
+
disableRepo(repoId: string): Promise<AnyRepoConfig>;
|
|
1316
|
+
enableRepo(repoId: string): Promise<AnyRepoConfig>;
|
|
1317
|
+
/** `true` when `~/.serviceme/repos/<id>/` exists on disk. */
|
|
1318
|
+
hasLocalClone(repoId: string): Promise<boolean>;
|
|
1319
|
+
/** Force-create the SERVICEME home directory tree (idempotent). */
|
|
1320
|
+
ensureHome(): Promise<void>;
|
|
1321
|
+
private pathExists;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Hard-coded catalog of repositories SERVICEME ships with. The id, URL and
|
|
1326
|
+
* branch are pinned by the design doc (§12) and **must not** change without
|
|
1327
|
+
* an owner-approved migration. The order here mirrors the on-disk
|
|
1328
|
+
* `repos.json` order (§3.1) which the UI relies on.
|
|
1329
|
+
*/
|
|
1330
|
+
declare const DEFAULT_REPO_ID = "medalsoftchina-ms-skills";
|
|
1331
|
+
declare const FIXED_ADDED_AT = "2026-06-29T00:00:00.000Z";
|
|
1332
|
+
/** Returns a deep-ish clone of every default repo with a fresh `addedAt`. */
|
|
1333
|
+
declare function getAllDefaultRepoConfigs(now?: () => string): DefaultRepoConfig[];
|
|
1334
|
+
/** Returns a single default repo by id, or `undefined` when not in the catalog. */
|
|
1335
|
+
declare function getDefaultRepoConfig(id: string, now?: () => string): DefaultRepoConfig | undefined;
|
|
1336
|
+
/**
|
|
1337
|
+
* Idempotent: returns a fresh `ReposFile` containing the default set, or —
|
|
1338
|
+
* when `existing` already has all four — returns it untouched (still cloned
|
|
1339
|
+
* to keep callers from accidentally mutating shared state).
|
|
1340
|
+
*/
|
|
1341
|
+
declare function buildDefaultReposFile(now?: () => string, existing?: ReposFile): ReposFile;
|
|
1342
|
+
/**
|
|
1343
|
+
* `ensureDefaultsInstalled(existing)` — pure helper that returns either
|
|
1344
|
+
* `existing` (when defaults are already present) or a merged copy that
|
|
1345
|
+
* appends the missing defaults. The companion `ensureDefaultsInstalledInStore`
|
|
1346
|
+
* below is the mutating, store-bound counterpart.
|
|
1347
|
+
*/
|
|
1348
|
+
declare function ensureDefaultsInstalled(existing: ReposFile, now?: () => string): {
|
|
1349
|
+
config: ReposFile;
|
|
1350
|
+
installed: string[];
|
|
1351
|
+
};
|
|
1352
|
+
|
|
210
1353
|
declare class DaemonLogger {
|
|
211
1354
|
private readonly logPath;
|
|
212
|
-
constructor(workspacePath: string
|
|
1355
|
+
constructor(workspacePath: string, options?: {
|
|
1356
|
+
logPath?: string;
|
|
1357
|
+
});
|
|
213
1358
|
getLogPath(): string;
|
|
214
1359
|
log(level: "info" | "warn" | "error", message: string): void;
|
|
215
1360
|
private rotateIfNeeded;
|
|
216
1361
|
}
|
|
217
1362
|
|
|
1363
|
+
interface PidManagerOptions {
|
|
1364
|
+
/**
|
|
1365
|
+
* Override the on-disk PID path. Defaults to
|
|
1366
|
+
* `<workspacePath>/.serviceme/scheduler.pid` for backward compat.
|
|
1367
|
+
* V2 callers pass an absolute path (e.g. `getSchedulerPidPath()`)
|
|
1368
|
+
* to read the global daemon PID file.
|
|
1369
|
+
*/
|
|
1370
|
+
pidPath?: string;
|
|
1371
|
+
}
|
|
218
1372
|
declare class PidManager {
|
|
219
1373
|
private readonly pidPath;
|
|
220
|
-
constructor(workspacePath: string);
|
|
1374
|
+
constructor(workspacePath: string, options?: PidManagerOptions);
|
|
221
1375
|
getPidPath(): string;
|
|
222
1376
|
writePid(pid: number): void;
|
|
223
1377
|
readPid(): number | null;
|
|
@@ -269,6 +1423,12 @@ interface SchedulerDaemonOptions {
|
|
|
269
1423
|
*/
|
|
270
1424
|
getExecutor?: typeof getExecutor;
|
|
271
1425
|
}
|
|
1426
|
+
/**
|
|
1427
|
+
* @deprecated v1 per-workspace daemon. Superseded by `SchedulerDaemonV2` in
|
|
1428
|
+
* `daemon/SchedulerDaemonV2.ts` for the global single-instance model. Kept
|
|
1429
|
+
* temporarily so callers can roll back to v1 behaviour during the M1.5
|
|
1430
|
+
* transition. New code should use SchedulerDaemonV2.
|
|
1431
|
+
*/
|
|
272
1432
|
declare class SchedulerDaemon {
|
|
273
1433
|
private readonly workspacePath;
|
|
274
1434
|
private readonly configManager;
|
|
@@ -310,6 +1470,7 @@ interface CreateTaskInput {
|
|
|
310
1470
|
schedule: string;
|
|
311
1471
|
taskType: ScheduledTaskType;
|
|
312
1472
|
payload: TaskPayload;
|
|
1473
|
+
workspace: TaskWorkspaceRef;
|
|
313
1474
|
enabled?: boolean;
|
|
314
1475
|
}
|
|
315
1476
|
interface EditTaskInput {
|
|
@@ -319,13 +1480,45 @@ interface EditTaskInput {
|
|
|
319
1480
|
schedule?: string;
|
|
320
1481
|
taskType?: ScheduledTaskType;
|
|
321
1482
|
payload?: TaskPayload;
|
|
1483
|
+
workspace?: TaskWorkspaceRef;
|
|
322
1484
|
enabled?: boolean;
|
|
323
1485
|
}
|
|
1486
|
+
interface TaskConfigManagerOptions {
|
|
1487
|
+
/**
|
|
1488
|
+
* Override the on-disk config path. Defaults to the global
|
|
1489
|
+
* `~/.serviceme/scheduled-tasks.json`. Tests use this to point at a tmp
|
|
1490
|
+
* directory; production code should leave it unset.
|
|
1491
|
+
*/
|
|
1492
|
+
configPath?: string;
|
|
1493
|
+
/**
|
|
1494
|
+
* Workspace context used when a legacy v1 config is read. v1 tasks had no
|
|
1495
|
+
* per-task workspace, so the manager needs a fallback to attach when
|
|
1496
|
+
* auto-migrating. Required only if the underlying file might still be v1.
|
|
1497
|
+
*/
|
|
1498
|
+
workspaceContext?: TaskWorkspaceRef;
|
|
1499
|
+
/**
|
|
1500
|
+
* Override the path where malformed-config diagnostic entries are appended.
|
|
1501
|
+
* Defaults to `~/.serviceme/migration-failures.json`. Tests can point at a
|
|
1502
|
+
* tmp file to assert failures were recorded.
|
|
1503
|
+
*/
|
|
1504
|
+
migrationFailuresPath?: string;
|
|
1505
|
+
/**
|
|
1506
|
+
* Inject a logger for the manager's recovery / migration warnings. Defaults
|
|
1507
|
+
* to `console.warn`. Tests pass a `vi.fn`/`mock.fn` to assert the warnings
|
|
1508
|
+
* were emitted.
|
|
1509
|
+
*/
|
|
1510
|
+
logger?: (message: string) => void;
|
|
1511
|
+
}
|
|
324
1512
|
declare class TaskConfigManager {
|
|
325
1513
|
private readonly configPath;
|
|
326
|
-
|
|
1514
|
+
private readonly workspaceContext?;
|
|
1515
|
+
private readonly migrationFailuresPath?;
|
|
1516
|
+
private readonly logger?;
|
|
1517
|
+
constructor(options?: TaskConfigManagerOptions);
|
|
327
1518
|
getConfigPath(): string;
|
|
328
1519
|
readConfig(): ScheduledTasksConfig;
|
|
1520
|
+
private warn;
|
|
1521
|
+
private recordMalformedConfigFailure;
|
|
329
1522
|
private writeConfig;
|
|
330
1523
|
listTasks(): ScheduledTask[];
|
|
331
1524
|
getTask(id: string): ScheduledTask | undefined;
|
|
@@ -336,27 +1529,6 @@ declare class TaskConfigManager {
|
|
|
336
1529
|
toggleTask(id: string, enabled: boolean): ScheduledTask;
|
|
337
1530
|
}
|
|
338
1531
|
|
|
339
|
-
interface TaskEventListener {
|
|
340
|
-
onStarted(params: TaskStartedEventParams): void;
|
|
341
|
-
onOutput(params: TaskOutputEventParams): void;
|
|
342
|
-
onCompleted(params: TaskCompletedEventParams): void;
|
|
343
|
-
onFailed(params: TaskFailedEventParams): void;
|
|
344
|
-
onCancelled(params: TaskCancelledEventParams): void;
|
|
345
|
-
}
|
|
346
|
-
declare function resolveTaskExecutionPayload(taskType: ScheduledTaskType, payload: TaskPayload, workspacePath: string): TaskPayload;
|
|
347
|
-
declare class TaskExecutionEngine {
|
|
348
|
-
private readonly getExecutor;
|
|
349
|
-
private readonly running;
|
|
350
|
-
private readonly taskExecutions;
|
|
351
|
-
private listener;
|
|
352
|
-
constructor(getExecutor: (taskType: string) => TaskExecutor);
|
|
353
|
-
setListener(listener: TaskEventListener): void;
|
|
354
|
-
execute(snapshot: TaskExecutionSnapshot): Promise<void>;
|
|
355
|
-
cancel(executionId: string): boolean;
|
|
356
|
-
listRunning(): RunningTaskInfo[];
|
|
357
|
-
dispose(): void;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
1532
|
interface AppendLogInput {
|
|
361
1533
|
taskId: string;
|
|
362
1534
|
taskName: string;
|
|
@@ -366,9 +1538,17 @@ interface AppendLogInput {
|
|
|
366
1538
|
output?: string;
|
|
367
1539
|
error?: string;
|
|
368
1540
|
}
|
|
1541
|
+
interface TaskLogManagerOptions {
|
|
1542
|
+
/**
|
|
1543
|
+
* Override the on-disk log path. Defaults to the global
|
|
1544
|
+
* `~/.serviceme/scheduled-tasks-log.json`. Tests use this to point at a
|
|
1545
|
+
* tmp directory; production code should leave it unset.
|
|
1546
|
+
*/
|
|
1547
|
+
logPath?: string;
|
|
1548
|
+
}
|
|
369
1549
|
declare class TaskLogManager {
|
|
370
1550
|
private readonly logPath;
|
|
371
|
-
constructor(
|
|
1551
|
+
constructor(options?: TaskLogManagerOptions);
|
|
372
1552
|
getLogPath(): string;
|
|
373
1553
|
private readLogFile;
|
|
374
1554
|
private backupCorruptedFile;
|
|
@@ -384,6 +1564,164 @@ declare class TaskLogManager {
|
|
|
384
1564
|
clearLogs(taskId?: string): number;
|
|
385
1565
|
}
|
|
386
1566
|
|
|
1567
|
+
interface SchedulerDaemonV2Options {
|
|
1568
|
+
/**
|
|
1569
|
+
* Override the executor factory. Production callers should leave this
|
|
1570
|
+
* undefined; tests inject a fake to drive the execution branch without
|
|
1571
|
+
* spawning real subprocesses.
|
|
1572
|
+
*/
|
|
1573
|
+
getExecutor?: typeof getExecutor;
|
|
1574
|
+
/** Override the config manager. Tests inject a fake pointing at a tmp dir. */
|
|
1575
|
+
configManager?: TaskConfigManager;
|
|
1576
|
+
/** Override the log manager. */
|
|
1577
|
+
logManager?: TaskLogManager;
|
|
1578
|
+
/** Override the PID manager. */
|
|
1579
|
+
pidManager?: PidManager;
|
|
1580
|
+
/** Override the daemon logger (for tests; the default writes to ~/.serviceme/scheduler.log). */
|
|
1581
|
+
logger?: DaemonLogger;
|
|
1582
|
+
/** Override the startup lock acquisition (tests use this to inject "lock held" / "lock free"). */
|
|
1583
|
+
tryAcquireLock?: () => boolean;
|
|
1584
|
+
/** Override the startup lock release. */
|
|
1585
|
+
releaseLock?: () => void;
|
|
1586
|
+
/**
|
|
1587
|
+
* Override the PID file existence + process liveness check. Production
|
|
1588
|
+
* reads PID file + `process.kill(pid, 0)`; tests inject a stub.
|
|
1589
|
+
*/
|
|
1590
|
+
getRunningPid?: () => number | null;
|
|
1591
|
+
}
|
|
1592
|
+
declare class SchedulerDaemonV2 {
|
|
1593
|
+
private readonly configManager;
|
|
1594
|
+
private readonly logManager;
|
|
1595
|
+
private readonly pidManager;
|
|
1596
|
+
private readonly logger;
|
|
1597
|
+
private readonly getExecutor;
|
|
1598
|
+
private readonly tryAcquireLock;
|
|
1599
|
+
private readonly releaseLock;
|
|
1600
|
+
private readonly getRunningPid;
|
|
1601
|
+
private tickTimer;
|
|
1602
|
+
private running;
|
|
1603
|
+
private readonly sigtermHandler;
|
|
1604
|
+
private readonly sigintHandler;
|
|
1605
|
+
private startTime;
|
|
1606
|
+
private lastRun;
|
|
1607
|
+
private workspaceLocks;
|
|
1608
|
+
constructor(options?: SchedulerDaemonV2Options);
|
|
1609
|
+
start(): void;
|
|
1610
|
+
stop(): void;
|
|
1611
|
+
private tick;
|
|
1612
|
+
private disableTaskForMissingWorkspace;
|
|
1613
|
+
private shouldRun;
|
|
1614
|
+
private executeTask;
|
|
1615
|
+
getStatus(): {
|
|
1616
|
+
running: boolean;
|
|
1617
|
+
pid: number;
|
|
1618
|
+
uptimeSeconds: number | null;
|
|
1619
|
+
tasksRegistered: number;
|
|
1620
|
+
tasksEnabled: number;
|
|
1621
|
+
pidFile: string;
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
interface MigrateToGlobalOptions {
|
|
1626
|
+
/**
|
|
1627
|
+
* Workspace paths to scan for legacy v1 files. May include the current
|
|
1628
|
+
* workspace + any persisted in `~/.serviceme/known-workspaces.json`.
|
|
1629
|
+
*/
|
|
1630
|
+
workspacePaths: string[];
|
|
1631
|
+
/**
|
|
1632
|
+
* Workspace context to apply to each scanned file. The scanner calls the
|
|
1633
|
+
* probe for each candidate path to populate path/name/git metadata.
|
|
1634
|
+
* Tests can inject a stub that returns synthetic data.
|
|
1635
|
+
*/
|
|
1636
|
+
probe?: (workspacePath: string) => Promise<TaskWorkspaceRef> | TaskWorkspaceRef;
|
|
1637
|
+
/**
|
|
1638
|
+
* Override the global config path. Tests use this; production should
|
|
1639
|
+
* leave it unset to get the standard ~/.serviceme/scheduled-tasks.json.
|
|
1640
|
+
*/
|
|
1641
|
+
globalConfigPath?: string;
|
|
1642
|
+
/**
|
|
1643
|
+
* Override the migration-failures path. Same convention.
|
|
1644
|
+
*/
|
|
1645
|
+
migrationFailuresPath?: string;
|
|
1646
|
+
}
|
|
1647
|
+
interface MigrationResult {
|
|
1648
|
+
/** Number of v1 files successfully migrated into the global config. */
|
|
1649
|
+
migrated: number;
|
|
1650
|
+
/** Number of v1 files that failed to parse / migrate. */
|
|
1651
|
+
failed: number;
|
|
1652
|
+
/** Task names that had to be disambiguated because they appeared in multiple workspaces. */
|
|
1653
|
+
conflicts: string[];
|
|
1654
|
+
/** Soft issues surfaced by migrateV1ToV2 (e.g. unknown taskType). */
|
|
1655
|
+
issues: string[];
|
|
1656
|
+
}
|
|
1657
|
+
declare class MigrateToGlobal {
|
|
1658
|
+
/**
|
|
1659
|
+
* Run the migration. Idempotent: each v1 file is deleted after processing,
|
|
1660
|
+
* so re-running this method on a partially-migrated state is safe (the
|
|
1661
|
+
* already-migrated files no longer exist; only the remainder is processed).
|
|
1662
|
+
*/
|
|
1663
|
+
static run(options: MigrateToGlobalOptions): Promise<MigrationResult>;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
interface TaskEventListener {
|
|
1667
|
+
onStarted(params: TaskStartedEventParams): void;
|
|
1668
|
+
onOutput(params: TaskOutputEventParams): void;
|
|
1669
|
+
onCompleted(params: TaskCompletedEventParams): void;
|
|
1670
|
+
onFailed(params: TaskFailedEventParams): void;
|
|
1671
|
+
onCancelled(params: TaskCancelledEventParams): void;
|
|
1672
|
+
}
|
|
1673
|
+
declare function resolveTaskExecutionPayload(taskType: ScheduledTaskType, payload: TaskPayload, workspacePath: string): TaskPayload;
|
|
1674
|
+
declare class TaskExecutionEngine {
|
|
1675
|
+
private readonly getExecutor;
|
|
1676
|
+
private readonly running;
|
|
1677
|
+
private readonly taskExecutions;
|
|
1678
|
+
private listener;
|
|
1679
|
+
constructor(getExecutor: (taskType: string) => TaskExecutor);
|
|
1680
|
+
setListener(listener: TaskEventListener): void;
|
|
1681
|
+
execute(snapshot: TaskExecutionSnapshot): Promise<void>;
|
|
1682
|
+
cancel(executionId: string): boolean;
|
|
1683
|
+
listRunning(): RunningTaskInfo[];
|
|
1684
|
+
dispose(): void;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
/** Result of probing a single workspace. */
|
|
1688
|
+
interface ProbeResult {
|
|
1689
|
+
/** Always populated; empty fields are left undefined. */
|
|
1690
|
+
workspace: TaskWorkspaceRef;
|
|
1691
|
+
/** null on success; one of the {@link ProbeError} tags on failure. */
|
|
1692
|
+
error: ProbeError | null;
|
|
1693
|
+
}
|
|
1694
|
+
type ProbeError = "path-not-found" | "not-a-git-repo" | "git-timeout" | "git-error";
|
|
1695
|
+
interface ProbeOptions {
|
|
1696
|
+
/** Timeout for each git invocation in ms. Default: 2000. */
|
|
1697
|
+
timeoutMs?: number;
|
|
1698
|
+
/** Override the git binary (default: 'git'). Tests inject a stub. */
|
|
1699
|
+
gitBinary?: string;
|
|
1700
|
+
/**
|
|
1701
|
+
* Override the underlying runner. Receives the args + cwd and returns
|
|
1702
|
+
* { stdout, stderr, code } on success, or throws on timeout. The default
|
|
1703
|
+
* implementation spawns `gitBinary` with the given args.
|
|
1704
|
+
*/
|
|
1705
|
+
runGit?: (args: string[], cwd: string) => Promise<{
|
|
1706
|
+
stdout: string;
|
|
1707
|
+
stderr: string;
|
|
1708
|
+
code: number;
|
|
1709
|
+
}>;
|
|
1710
|
+
}
|
|
1711
|
+
/**
|
|
1712
|
+
* Probes a workspace for git metadata. Returns a {@link ProbeResult} with
|
|
1713
|
+
* `error: null` on success and an error tag on failure — the workspace
|
|
1714
|
+
* descriptor is always populated so callers can still surface a partial
|
|
1715
|
+
* record.
|
|
1716
|
+
*/
|
|
1717
|
+
declare class WorkspaceProbe {
|
|
1718
|
+
private readonly timeoutMs;
|
|
1719
|
+
private readonly gitBinary;
|
|
1720
|
+
private readonly runGitFn;
|
|
1721
|
+
constructor(options?: ProbeOptions);
|
|
1722
|
+
probe(workspacePath: string): Promise<ProbeResult>;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
387
1725
|
interface SkillDownloadFile {
|
|
388
1726
|
path: string;
|
|
389
1727
|
content: string;
|
|
@@ -465,10 +1803,17 @@ declare class SkillStore {
|
|
|
465
1803
|
listUserSkillIds(): Promise<string[]>;
|
|
466
1804
|
writeManagedUserSkillMarker(skillId: string): Promise<void>;
|
|
467
1805
|
isManagedUserSkill(skillId: string): Promise<boolean>;
|
|
1806
|
+
/**
|
|
1807
|
+
* One-time migration: the user-scope skill marker used to be named
|
|
1808
|
+
* `.ms-devtools-skill.json`. If the new `.serviceme-skill.json` doesn't
|
|
1809
|
+
* exist yet but the legacy marker does, copy it forward so an existing
|
|
1810
|
+
* skill doesn't lose its "managed" status.
|
|
1811
|
+
*/
|
|
1812
|
+
private migrateLegacyUserSkillMarker;
|
|
468
1813
|
writeSkillFiles(skillId: string, scope: "workspace" | "user", files: SkillDownloadFile[]): Promise<void>;
|
|
469
1814
|
}
|
|
470
1815
|
|
|
471
1816
|
declare const unzipFile: (zipPath: string, dest: string) => Promise<void>;
|
|
472
1817
|
declare const moveFiles: (sourceDir: string, destDir: string, overwrite?: boolean) => Promise<void>;
|
|
473
1818
|
|
|
474
|
-
export { type AgentCatalog, AgentCatalogClient, type AgentCatalogClientOptions, type AgentDownloadFile, type AgentInstallScope, type AgentMutateResult, AgentReconciler, type AgentReconcilerDependencies, AgentStore, type AgentStoreFileSystem, type AgentStoreOptions, type AgentsStateFile, type AppendLogInput, type CreateTaskInput, DaemonLogger, type EditTaskInput, EnvironmentInspector, type EnvironmentInspectorOptions, type ExecutorResult, GithubCopilotCliExecutor, HttpRequestExecutor, ImageTools, type InstalledAgent, type JsonTools, type OutputEventCallback, PidManager, ProjectTools, SchedulerDaemon, type ServiceMeLogger, ShellExecutor, type SkillCatalog, SkillCatalogClient, type SkillCatalogClientOptions, type SkillDownloadFile, type SkillMutateResult, SkillReconciler, type SkillReconcilerDependencies, SkillStore, type SkillStoreFileSystem, type SkillStoreOptions, type StreamingExecutorHandle, type StreamingTaskExecutor, TOOL_RISK_MAP, TaskConfigManager, type TaskEventListener, TaskExecutionEngine, type TaskExecutor, TaskLogManager, copilotDoctor, copilotPrompt, createConsoleLogger, createCopilotAuthRequiredError, createCopilotNotInstalledError, createImageTools, createJsonTools, createProjectTools, getExecutor, isCopilotAuthenticated, isStreamingTaskExecutor, matchesCron, moveFiles, noopLogger, parseAgentToolPermissions, parseIntervalMs, resolveTaskExecutionPayload, unzipFile, validateTaskPayload };
|
|
1819
|
+
export { AGENT_DRAFTS_SUBDIR, type AddUserRepoInput, type AddUserRepoResult, type AgentCatalog, AgentCatalogClient, type AgentCatalogClientOptions, type AgentDownloadFile, type AgentInstallScope, type AgentMutateResult, AgentReconciler, type AgentReconcilerDependencies, AgentStore, type AgentStoreFileSystem, type AgentStoreOptions, type AgentsStateFile, type AnyRepoConfig, type AppendLogInput, type BootstrapPhase5Result, CACHE_SUBDIR, CREDENTIALS_CONFIG_FILENAME, CannotRemoveDefaultRepoError, type CreateTaskInput, FIXED_ADDED_AT as DEFAULT_REPO_FIXED_ADDED_AT, DEFAULT_REPO_ID, DEVICE_JSON_FILENAME, DRAFTS_SUBDIR, DaemonLogger, type DefaultRepoConfig, type DraftDetail, DraftNotFoundError, type DraftSummary, DraftsError, DraftsStore, type EditTaskInput, EnvironmentInspector, type EnvironmentInspectorOptions, type ExecutorResult, type FsWatcherCallbacks, type FsWatcherHandle, GitClient, GithubCopilotCliExecutor, HttpRequestExecutor, ImageTools, type InstalledAgent, InvalidDraftError, InvalidRepoUrlError, type IsoTimestamp, type JsonTools, KNOWN_WORKSPACES_FILENAME, type LoadResult, MACHINE_ID_FILENAME, MIGRATION_FAILURES_FILENAME, MigrateToGlobal, type MigrateToGlobalOptions, type MigrationResult, type OutputEventCallback, PROFILES_JSON_FILENAME, PidManager, type ProbeError, type ProbeOptions, type ProbeResult, ProjectTools, REPOS_CONFIG_FILENAME, REPOS_SUBDIR, RepoAlreadyExistsError, RepoCloneConflictError, type RepoConfig, RepoManager, RepoManagerError, type RepoManagerOptions, RepoNotFoundError, RepoNotInStoreError, type RepoSource, type ReposFile, type ReposFileInput, ReposLoader, type ReposLoaderFileSystem, type ReposLoaderOptions, ReposStore, type ReposStoreChange, type ReposStoreFileSystem, type ReposStoreListener, type ReposStoreOptions, SAFE_REPO_ID_PATTERN, SCHEDULED_TASKS_CONFIG_FILENAME, SCHEDULED_TASKS_LOG_FILENAME, SCHEDULER_LOCK_FILENAME, SCHEDULER_LOG_FILENAME, SCHEDULER_PID_FILENAME, SERVICEME_DIR_NAME, SERVICEME_HOME_ENV, SKILL_DRAFTS_SUBDIR, type SaveDraftOptions, SchedulerDaemon, SchedulerDaemonV2, type SchedulerDaemonV2Options, type ServiceMeLogger, ShellExecutor, type SkillCatalog, SkillCatalogClient, type SkillCatalogClientOptions, type SkillDownloadFile, type SkillMutateResult, SkillReconciler, type SkillReconcilerDependencies, SkillStore, type SkillStoreFileSystem, type SkillStoreOptions, type StreamingExecutorHandle, type StreamingTaskExecutor, type SyncReport, type SyncStatus, TOOLBOX_JSON_FILENAME, TOOL_RISK_MAP, TaskConfigManager, type TaskEventListener, TaskExecutionEngine, type TaskExecutor, TaskLogManager, type UserRepoConfig, WorkspaceProbe, repoSchema as anyRepoConfigSchema, assertSafeRepoId, bootstrapDefaults, bootstrapPhase5Placeholders, buildDefaultReposFile, copilotDoctor, copilotPrompt, createConsoleLogger, createCopilotAuthRequiredError, createCopilotNotInstalledError, createImageTools, createJsonTools, createProjectTools, createReposStore, defaultRepoSchema as defaultRepoConfigSchema, ensureDefaultsInstalled, generateDraftId, getAgentDraftsDir, getAllDefaultRepoConfigs, getCacheDir, getCredentialsConfigPath, getDefaultRepoConfig, getDeviceJsonPath, getDraftsDir, getExecutor, getHomeDir, getHomePlatform, getKnownWorkspacesPath, getMachineIdPath, getMigrationFailuresPath, getProfilesJsonPath, getRepoCacheDir, getRepoDir, getReposConfigPath, getReposDir, getScheduledTasksConfigPath, getScheduledTasksLogPath, getSchedulerLockPath, getSchedulerLogPath, getSchedulerPidPath, getServicemeHome, getSkillDraftsDir, getToolboxJsonPath, isCopilotAuthenticated, isDefaultRepo, isStreamingTaskExecutor, isUserRepo, matchesCron, moveFiles, narrowRepoConfig, noopLogger, parseAgentToolPermissions, parseIntervalMs, reposFileSchema, resetUserHomeOverrides, resolveDraftDir, resolveTaskExecutionPayload, setUserHomeOverrides, unzipFile, userRepoSchema as userRepoConfigSchema, validateReposFile, validateTaskPayload };
|