@halyard/cli 0.1.2 → 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/README.md +88 -1
- package/dist/cli.js +27 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/api-keys.d.ts +3 -0
- package/dist/commands/api-keys.d.ts.map +1 -0
- package/dist/commands/api-keys.js +90 -0
- package/dist/commands/api-keys.js.map +1 -0
- package/dist/commands/hook.d.ts +6 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +106 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/login.d.ts +17 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +111 -14
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/orgs.d.ts +3 -0
- package/dist/commands/orgs.d.ts.map +1 -0
- package/dist/commands/orgs.js +102 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +29 -6
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/sessions.d.ts +3 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +139 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +28 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skills.d.ts +12 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +171 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +51 -49
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/users.d.ts +13 -0
- package/dist/commands/users.d.ts.map +1 -0
- package/dist/commands/users.js +205 -0
- package/dist/commands/users.js.map +1 -0
- package/dist/commands/whoami.d.ts +21 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +77 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/lib/api-client.d.ts +64 -2
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +32 -7
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/auth.d.ts +42 -6
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +101 -27
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/config-files.d.ts +6 -0
- package/dist/lib/config-files.d.ts.map +1 -0
- package/dist/lib/config-files.js +27 -0
- package/dist/lib/config-files.js.map +1 -0
- package/dist/lib/config.d.ts +13 -7
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +22 -8
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/copilot-export.d.ts +31 -0
- package/dist/lib/copilot-export.d.ts.map +1 -0
- package/dist/lib/copilot-export.js +129 -0
- package/dist/lib/copilot-export.js.map +1 -0
- package/dist/lib/discovery.d.ts +60 -2
- package/dist/lib/discovery.d.ts.map +1 -1
- package/dist/lib/discovery.js +187 -15
- package/dist/lib/discovery.js.map +1 -1
- package/dist/lib/hook-discovery.d.ts +43 -0
- package/dist/lib/hook-discovery.d.ts.map +1 -0
- package/dist/lib/hook-discovery.js +90 -0
- package/dist/lib/hook-discovery.js.map +1 -0
- package/dist/lib/hook-input.d.ts +36 -0
- package/dist/lib/hook-input.d.ts.map +1 -0
- package/dist/lib/hook-input.js +161 -0
- package/dist/lib/hook-input.js.map +1 -0
- package/dist/lib/hook-runner.d.ts +48 -0
- package/dist/lib/hook-runner.d.ts.map +1 -0
- package/dist/lib/hook-runner.js +306 -0
- package/dist/lib/hook-runner.js.map +1 -0
- package/dist/lib/http.d.ts +18 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +54 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/opencode-export.d.ts +22 -0
- package/dist/lib/opencode-export.d.ts.map +1 -0
- package/dist/lib/opencode-export.js +53 -0
- package/dist/lib/opencode-export.js.map +1 -0
- package/dist/lib/output.d.ts +27 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +74 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/preflight.d.ts +35 -0
- package/dist/lib/preflight.d.ts.map +1 -0
- package/dist/lib/preflight.js +54 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/repo-binding.d.ts +43 -0
- package/dist/lib/repo-binding.d.ts.map +1 -0
- package/dist/lib/repo-binding.js +158 -0
- package/dist/lib/repo-binding.js.map +1 -0
- package/dist/lib/repo-identity.d.ts +29 -0
- package/dist/lib/repo-identity.d.ts.map +1 -0
- package/dist/lib/repo-identity.js +113 -0
- package/dist/lib/repo-identity.js.map +1 -0
- package/dist/lib/setup-hooks.d.ts +41 -0
- package/dist/lib/setup-hooks.d.ts.map +1 -0
- package/dist/lib/setup-hooks.js +276 -0
- package/dist/lib/setup-hooks.js.map +1 -0
- package/dist/lib/setup.d.ts +4 -1
- package/dist/lib/setup.d.ts.map +1 -1
- package/dist/lib/setup.js +20 -31
- package/dist/lib/setup.js.map +1 -1
- package/dist/lib/skill-batches.d.ts +16 -0
- package/dist/lib/skill-batches.d.ts.map +1 -0
- package/dist/lib/skill-batches.js +35 -0
- package/dist/lib/skill-batches.js.map +1 -0
- package/dist/lib/skill-files.d.ts +4 -0
- package/dist/lib/skill-files.d.ts.map +1 -0
- package/dist/lib/skill-files.js +36 -0
- package/dist/lib/skill-files.js.map +1 -0
- package/dist/lib/skill-fingerprint.d.ts +55 -0
- package/dist/lib/skill-fingerprint.d.ts.map +1 -0
- package/dist/lib/skill-fingerprint.js +204 -0
- package/dist/lib/skill-fingerprint.js.map +1 -0
- package/dist/lib/skills-discovery.d.ts +57 -0
- package/dist/lib/skills-discovery.d.ts.map +1 -0
- package/dist/lib/skills-discovery.js +157 -0
- package/dist/lib/skills-discovery.js.map +1 -0
- package/dist/lib/skills-sync.d.ts +66 -0
- package/dist/lib/skills-sync.d.ts.map +1 -0
- package/dist/lib/skills-sync.js +251 -0
- package/dist/lib/skills-sync.js.map +1 -0
- package/dist/lib/sync-runner.d.ts +56 -0
- package/dist/lib/sync-runner.d.ts.map +1 -0
- package/dist/lib/sync-runner.js +106 -0
- package/dist/lib/sync-runner.js.map +1 -0
- package/dist/lib/sync-state.d.ts +36 -6
- package/dist/lib/sync-state.d.ts.map +1 -1
- package/dist/lib/sync-state.js +41 -11
- package/dist/lib/sync-state.js.map +1 -1
- package/package.json +10 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-discovery.js","sourceRoot":"","sources":["../../src/lib/skills-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type SkillSyncResult, type SkillUpload } from './api-client.js';
|
|
2
|
+
import { type DiscoveredSkill, type SkillScope } from './skills-discovery.js';
|
|
3
|
+
/**
|
|
4
|
+
* The "discover, fingerprint, upload what changed" pipeline behind
|
|
5
|
+
* `halyard skills sync` and the session-start hook. Change detection is
|
|
6
|
+
* two-tier: the org-keyed ledger in ~/.halyard/sync-state.json skips
|
|
7
|
+
* unchanged skills with no network at all, and the server compares the
|
|
8
|
+
* fingerprint again for anything the ledger missed (fresh machine, --force).
|
|
9
|
+
*/
|
|
10
|
+
export type SkillScopeSelection = SkillScope | 'all';
|
|
11
|
+
export interface SkillsSyncOptions {
|
|
12
|
+
homeDir: string;
|
|
13
|
+
/** Repository root for project-scope discovery; omit when not in a repo. */
|
|
14
|
+
projectRoot?: string;
|
|
15
|
+
scope: SkillScopeSelection;
|
|
16
|
+
/** Org bucket for the ledger (orgId, or `api-key:<id>`). */
|
|
17
|
+
stateKey: string;
|
|
18
|
+
authHeaders: Record<string, string>;
|
|
19
|
+
apiUrl: string;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
/** Ignore the local ledger and let the server decide what changed. */
|
|
22
|
+
force: boolean;
|
|
23
|
+
log: (line: string) => void;
|
|
24
|
+
fetchImpl?: typeof fetch;
|
|
25
|
+
}
|
|
26
|
+
export interface PreparedSkill {
|
|
27
|
+
skill: DiscoveredSkill;
|
|
28
|
+
upload: SkillUpload;
|
|
29
|
+
/** Ledger key: `<scope>:<scopeKey>:<relativePath>`. */
|
|
30
|
+
ledgerKey: string;
|
|
31
|
+
/** Non-fatal problems worth telling the author about. */
|
|
32
|
+
warnings: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface SkillsSyncSummary {
|
|
35
|
+
found: number;
|
|
36
|
+
created: number;
|
|
37
|
+
updated: number;
|
|
38
|
+
unchanged: number;
|
|
39
|
+
/** Skipped by the local ledger (already synced at this fingerprint). */
|
|
40
|
+
skipped: number;
|
|
41
|
+
/** Unreadable locally, rejected by the server, or lost to a request failure. */
|
|
42
|
+
failed: number;
|
|
43
|
+
results: SkillSyncResult[];
|
|
44
|
+
}
|
|
45
|
+
/** Discover every skill in the selected scopes. */
|
|
46
|
+
export declare function discoverSelectedSkills(options: {
|
|
47
|
+
scope: SkillScopeSelection;
|
|
48
|
+
homeDir: string;
|
|
49
|
+
projectRoot?: string;
|
|
50
|
+
}): DiscoveredSkill[];
|
|
51
|
+
/**
|
|
52
|
+
* Identity of a repo for project-scope skills: the normalized origin remote
|
|
53
|
+
* (`github.com/owner/repo`) so the same skill synced from two machines is one
|
|
54
|
+
* entry. A repo with no remote has no shared identity, so it gets a
|
|
55
|
+
* machine-local one — `local:<basename>:<hash of the real path>` — rather
|
|
56
|
+
* than a bare basename that every other remote-less `api` repo would share.
|
|
57
|
+
*/
|
|
58
|
+
export declare function projectScopeKey(projectRoot: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Read, parse and fingerprint one discovered skill into its upload payload.
|
|
61
|
+
* Throws when the skill cannot be uploaded at all (unreadable, or a body the
|
|
62
|
+
* server would reject); softer problems come back as `warnings`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function prepareSkill(skill: DiscoveredSkill, scopeKey: string): PreparedSkill;
|
|
65
|
+
export declare function runSkillsSync(options: SkillsSyncOptions): Promise<SkillsSyncSummary>;
|
|
66
|
+
//# sourceMappingURL=skills-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-sync.d.ts","sourceRoot":"","sources":["../../src/lib/skills-sync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAMpF,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAA;AAS9B;;;;;;GAMG;AAEH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,KAAK,CAAA;AAEpD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,mBAAmB,CAAA;IAC1B,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,WAAW,CAAA;IACnB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,eAAe,EAAE,CAAA;CAC3B;AAUD,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,KAAK,EAAE,mBAAmB,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,eAAe,EAAE,CASpB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAsDpF;AAuID,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuC1F"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
|
+
import { syncSkills } from './api-client.js';
|
|
5
|
+
import { ApiError } from './http.js';
|
|
6
|
+
import { resolveRepoIdentity } from './repo-identity.js';
|
|
7
|
+
import { encodedBytes, planBatches } from './skill-batches.js';
|
|
8
|
+
import { toSkillFileUpload } from './skill-files.js';
|
|
9
|
+
import { fingerprintSkillDir, parseSkillMarkdown } from './skill-fingerprint.js';
|
|
10
|
+
import { discoverSkills, SKILL_FILE, } from './skills-discovery.js';
|
|
11
|
+
import { isSkillSynced, markSkillSynced, readSyncState, writeSyncState, } from './sync-state.js';
|
|
12
|
+
/** Server-side limits mirrored here so an oversized skill is named locally instead of failing a batch. */
|
|
13
|
+
const MAX_NAME_CHARS = 128;
|
|
14
|
+
const MAX_DESCRIPTION_CHARS = 2000;
|
|
15
|
+
const MAX_BODY_CHARS = 512 * 1024;
|
|
16
|
+
const MAX_FRONTMATTER_KEYS = 50;
|
|
17
|
+
const MAX_FRONTMATTER_VALUE_CHARS = 4000;
|
|
18
|
+
const MAX_FRONTMATTER_RAW_CHARS = 64 * 1024;
|
|
19
|
+
/** Discover every skill in the selected scopes. */
|
|
20
|
+
export function discoverSelectedSkills(options) {
|
|
21
|
+
const skills = [];
|
|
22
|
+
if (options.scope !== 'project') {
|
|
23
|
+
skills.push(...discoverSkills({ scope: 'user', rootDir: options.homeDir }));
|
|
24
|
+
}
|
|
25
|
+
if (options.scope !== 'user' && options.projectRoot) {
|
|
26
|
+
skills.push(...discoverSkills({ scope: 'project', rootDir: options.projectRoot }));
|
|
27
|
+
}
|
|
28
|
+
return skills;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Identity of a repo for project-scope skills: the normalized origin remote
|
|
32
|
+
* (`github.com/owner/repo`) so the same skill synced from two machines is one
|
|
33
|
+
* entry. A repo with no remote has no shared identity, so it gets a
|
|
34
|
+
* machine-local one — `local:<basename>:<hash of the real path>` — rather
|
|
35
|
+
* than a bare basename that every other remote-less `api` repo would share.
|
|
36
|
+
*/
|
|
37
|
+
export function projectScopeKey(projectRoot) {
|
|
38
|
+
const remote = resolveRepoIdentity(projectRoot)?.remote;
|
|
39
|
+
if (remote)
|
|
40
|
+
return remote;
|
|
41
|
+
let real = projectRoot;
|
|
42
|
+
try {
|
|
43
|
+
real = realpathSync(projectRoot);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// keep the given path
|
|
47
|
+
}
|
|
48
|
+
const digest = createHash('sha256').update(real).digest('hex').slice(0, 8);
|
|
49
|
+
return `local:${basename(real)}:${digest}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Read, parse and fingerprint one discovered skill into its upload payload.
|
|
53
|
+
* Throws when the skill cannot be uploaded at all (unreadable, or a body the
|
|
54
|
+
* server would reject); softer problems come back as `warnings`.
|
|
55
|
+
*/
|
|
56
|
+
export function prepareSkill(skill, scopeKey) {
|
|
57
|
+
const raw = readFileSync(join(skill.dir, SKILL_FILE), 'utf-8');
|
|
58
|
+
const parsed = parseSkillMarkdown(raw);
|
|
59
|
+
const fingerprint = fingerprintSkillDir(skill.dir);
|
|
60
|
+
const warnings = [...parsed.warnings];
|
|
61
|
+
const name = parsed.name ?? skill.folderName;
|
|
62
|
+
if (name.length > MAX_NAME_CHARS) {
|
|
63
|
+
throw new Error(`skill name exceeds ${MAX_NAME_CHARS} characters`);
|
|
64
|
+
}
|
|
65
|
+
if (parsed.body.length > MAX_BODY_CHARS) {
|
|
66
|
+
throw new Error(`SKILL.md body exceeds ${MAX_BODY_CHARS} characters`);
|
|
67
|
+
}
|
|
68
|
+
let description = parsed.description;
|
|
69
|
+
if (description && description.length > MAX_DESCRIPTION_CHARS) {
|
|
70
|
+
description = description.slice(0, MAX_DESCRIPTION_CHARS);
|
|
71
|
+
warnings.push(`description truncated to ${MAX_DESCRIPTION_CHARS} characters`);
|
|
72
|
+
}
|
|
73
|
+
const frontmatter = boundedFrontmatter(parsed.frontmatter, warnings);
|
|
74
|
+
const frontmatterRaw = boundedFrontmatterRaw(parsed.frontmatterRaw, warnings);
|
|
75
|
+
if (fingerprint.skippedPaths.length > 0) {
|
|
76
|
+
warnings.push(`${fingerprint.skippedPaths.length} file(s) over 1 MiB not uploaded: ` +
|
|
77
|
+
fingerprint.skippedPaths.join(', '));
|
|
78
|
+
}
|
|
79
|
+
if (fingerprint.truncated) {
|
|
80
|
+
warnings.push('tree is too large to fingerprint completely; the hash covers a prefix of it');
|
|
81
|
+
}
|
|
82
|
+
else if (fingerprint.fileCount > fingerprint.files.length) {
|
|
83
|
+
warnings.push(`manifest lists the first ${fingerprint.files.length} of ${fingerprint.fileCount} files`);
|
|
84
|
+
}
|
|
85
|
+
const upload = {
|
|
86
|
+
name,
|
|
87
|
+
description,
|
|
88
|
+
frontmatter,
|
|
89
|
+
frontmatterRaw,
|
|
90
|
+
body: parsed.body,
|
|
91
|
+
scope: skill.scope,
|
|
92
|
+
scopeKey,
|
|
93
|
+
relativePath: skill.relativePath,
|
|
94
|
+
harnesses: skill.harnesses,
|
|
95
|
+
locations: skill.locations,
|
|
96
|
+
treeHash: fingerprint.treeHash,
|
|
97
|
+
files: fingerprint.files.map(toSkillFileUpload),
|
|
98
|
+
fileCount: fingerprint.fileCount,
|
|
99
|
+
modifiedAt: fingerprint.modifiedAt.toISOString(),
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
skill,
|
|
103
|
+
upload,
|
|
104
|
+
ledgerKey: `${skill.scope}:${scopeKey}:${skill.relativePath}`,
|
|
105
|
+
warnings,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Keep front-matter within what the server stores: a nested `metadata:` block can run to kilobytes. */
|
|
109
|
+
function boundedFrontmatter(frontmatter, warnings) {
|
|
110
|
+
const out = {};
|
|
111
|
+
for (const [key, value] of Object.entries(frontmatter).slice(0, MAX_FRONTMATTER_KEYS)) {
|
|
112
|
+
if (value.length > MAX_FRONTMATTER_VALUE_CHARS) {
|
|
113
|
+
out[key] = value.slice(0, MAX_FRONTMATTER_VALUE_CHARS);
|
|
114
|
+
warnings.push(`front-matter \`${key}\` truncated to ${MAX_FRONTMATTER_VALUE_CHARS} characters`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
out[key] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (Object.keys(frontmatter).length > MAX_FRONTMATTER_KEYS) {
|
|
121
|
+
warnings.push(`front-matter has more than ${MAX_FRONTMATTER_KEYS} keys; extra keys dropped`);
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
/** The verbatim block has its own server cap; the parsed map still goes up in full when it is cut. */
|
|
126
|
+
function boundedFrontmatterRaw(raw, warnings) {
|
|
127
|
+
if (raw === undefined || raw.length <= MAX_FRONTMATTER_RAW_CHARS)
|
|
128
|
+
return raw;
|
|
129
|
+
warnings.push(`raw front-matter truncated to ${MAX_FRONTMATTER_RAW_CHARS} characters`);
|
|
130
|
+
return raw.slice(0, MAX_FRONTMATTER_RAW_CHARS);
|
|
131
|
+
}
|
|
132
|
+
function describe(prepared) {
|
|
133
|
+
const { upload, skill } = prepared;
|
|
134
|
+
return `${upload.name} [${skill.scope}] ${skill.relativePath} (${upload.treeHash.slice(0, 12)})`;
|
|
135
|
+
}
|
|
136
|
+
function errorMessage(err) {
|
|
137
|
+
return err instanceof Error ? err.message : String(err);
|
|
138
|
+
}
|
|
139
|
+
/** Prepare every skill; unreadable ones are counted as failed, not dropped. */
|
|
140
|
+
function prepareAll(skills, options, summary) {
|
|
141
|
+
const projectKey = options.projectRoot ? projectScopeKey(options.projectRoot) : '';
|
|
142
|
+
const prepared = [];
|
|
143
|
+
for (const skill of skills) {
|
|
144
|
+
try {
|
|
145
|
+
const item = prepareSkill(skill, skill.scope === 'project' ? projectKey : '');
|
|
146
|
+
for (const warning of item.warnings) {
|
|
147
|
+
options.log(` warning: ${skill.relativePath}: ${warning}`);
|
|
148
|
+
}
|
|
149
|
+
prepared.push(item);
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
summary.failed++;
|
|
153
|
+
options.log(` failed to read: ${skill.dir} - ${errorMessage(err)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return prepared;
|
|
157
|
+
}
|
|
158
|
+
function recordResults(batch, results, state, options, summary) {
|
|
159
|
+
const byKey = new Map(results.map((r) => [`${r.scope}:${r.relativePath}`, r]));
|
|
160
|
+
for (const prepared of batch) {
|
|
161
|
+
const result = byKey.get(`${prepared.skill.scope}:${prepared.skill.relativePath}`);
|
|
162
|
+
if (!result) {
|
|
163
|
+
summary.failed++;
|
|
164
|
+
options.log(` failed: ${describe(prepared)} - no result returned`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
summary[result.status]++;
|
|
168
|
+
summary.results.push(result);
|
|
169
|
+
markSkillSynced(state, options.stateKey, prepared.ledgerKey, {
|
|
170
|
+
hash: prepared.upload.treeHash,
|
|
171
|
+
syncedAt: new Date().toISOString(),
|
|
172
|
+
knowledgeEntryId: result.knowledgeEntryId,
|
|
173
|
+
});
|
|
174
|
+
const stored = result.storedFiles === undefined ? '' : ` - ${result.storedFiles} file(s) stored`;
|
|
175
|
+
options.log(` ${result.status}: ${describe(prepared)}${stored}`);
|
|
176
|
+
for (const warning of result.warnings ?? []) {
|
|
177
|
+
options.log(` warning: ${prepared.skill.relativePath}: ${warning}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Ledger progress survives a later batch failing (or the process dying).
|
|
181
|
+
writeSyncState(state);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Send one batch. Returns false when syncing should stop altogether (bad
|
|
185
|
+
* credentials). A multi-skill batch that fails is retried one skill at a
|
|
186
|
+
* time so a single rejected skill is named and the rest still land.
|
|
187
|
+
*/
|
|
188
|
+
async function sendBatch(batch, state, options, summary) {
|
|
189
|
+
try {
|
|
190
|
+
const response = await syncSkills(batch.map((p) => p.upload), options.authHeaders, options.apiUrl, options.fetchImpl);
|
|
191
|
+
recordResults(batch, response.results, state, options, summary);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
const message = errorMessage(err);
|
|
196
|
+
if (err instanceof ApiError && err.status === 401) {
|
|
197
|
+
summary.failed += batch.length;
|
|
198
|
+
options.log(` failed: ${message}`);
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
if (batch.length > 1) {
|
|
202
|
+
options.log(` batch of ${batch.length} failed (${message}); retrying one skill at a time`);
|
|
203
|
+
for (const one of batch) {
|
|
204
|
+
if (!(await sendBatch([one], state, options, summary)))
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
summary.failed++;
|
|
210
|
+
options.log(` failed: ${describe(batch[0])} - ${message}`);
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
export async function runSkillsSync(options) {
|
|
215
|
+
const skills = discoverSelectedSkills(options);
|
|
216
|
+
const summary = {
|
|
217
|
+
found: skills.length,
|
|
218
|
+
created: 0,
|
|
219
|
+
updated: 0,
|
|
220
|
+
unchanged: 0,
|
|
221
|
+
skipped: 0,
|
|
222
|
+
failed: 0,
|
|
223
|
+
results: [],
|
|
224
|
+
};
|
|
225
|
+
const state = readSyncState();
|
|
226
|
+
const pending = [];
|
|
227
|
+
for (const prepared of prepareAll(skills, options, summary)) {
|
|
228
|
+
if (!options.force &&
|
|
229
|
+
isSkillSynced(state, options.stateKey, prepared.ledgerKey, prepared.upload.treeHash)) {
|
|
230
|
+
summary.skipped++;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
pending.push(prepared);
|
|
234
|
+
}
|
|
235
|
+
if (options.dryRun) {
|
|
236
|
+
for (const prepared of pending)
|
|
237
|
+
options.log(` [dry-run] would sync: ${describe(prepared)}`);
|
|
238
|
+
return summary;
|
|
239
|
+
}
|
|
240
|
+
// Batches are bounded by count and by encoded size, since file bytes ride inline.
|
|
241
|
+
let sent = 0;
|
|
242
|
+
for (const batch of planBatches(pending, (p) => encodedBytes(p.upload))) {
|
|
243
|
+
if (!(await sendBatch(batch, state, options, summary))) {
|
|
244
|
+
summary.failed += pending.length - sent - batch.length;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
sent += batch.length;
|
|
248
|
+
}
|
|
249
|
+
return summary;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=skills-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-sync.js","sourceRoot":"","sources":["../../src/lib/skills-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type DiscoveredSession } from './discovery.js';
|
|
2
|
+
import { type SyncState } from './sync-state.js';
|
|
3
|
+
/**
|
|
4
|
+
* The "discover, scope, upload everything new" pipeline shared by
|
|
5
|
+
* `halyard sync` and `halyard hook`. Sync state is org-keyed (`stateKey`
|
|
6
|
+
* from the upload preflight), so a session synced to org A still uploads to
|
|
7
|
+
* org B.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sizeSuffix(bytes: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Keep only sessions whose cwd resolves to the same repository as `rootDir`.
|
|
12
|
+
* Sessions whose cwd/repo cannot be resolved are counted as unresolved (the
|
|
13
|
+
* caller reports them once); sessions from other repos are silently excluded.
|
|
14
|
+
*/
|
|
15
|
+
export declare function scopeSessionsToRepo(sessions: DiscoveredSession[], rootDir: string): {
|
|
16
|
+
sessions: DiscoveredSession[];
|
|
17
|
+
unresolved: number;
|
|
18
|
+
};
|
|
19
|
+
export interface DiscoverOptions {
|
|
20
|
+
providerFilter?: string;
|
|
21
|
+
/** Restrict to sessions whose cwd resolves to this repo; omit for machine-wide. */
|
|
22
|
+
scopeRootDir?: string;
|
|
23
|
+
/** Drop sessions the caller must not upload yet (e.g. the live one). */
|
|
24
|
+
exclude?: (session: DiscoveredSession) => boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface DiscoverResult {
|
|
27
|
+
sessions: DiscoveredSession[];
|
|
28
|
+
/** Sessions found before scoping. */
|
|
29
|
+
found: number;
|
|
30
|
+
/** Sessions dropped because their repo could not be determined. */
|
|
31
|
+
unresolved: number;
|
|
32
|
+
}
|
|
33
|
+
export declare function discoverScopedSessions(options: DiscoverOptions): DiscoverResult;
|
|
34
|
+
export interface UploadOptions {
|
|
35
|
+
/** Org bucket for sync state (orgId, or `api-key:<id>`). */
|
|
36
|
+
stateKey: string;
|
|
37
|
+
authHeaders: Record<string, string>;
|
|
38
|
+
apiUrl: string;
|
|
39
|
+
dryRun: boolean;
|
|
40
|
+
log: (line: string) => void;
|
|
41
|
+
}
|
|
42
|
+
export interface UploadTotals {
|
|
43
|
+
uploaded: number;
|
|
44
|
+
skipped: number;
|
|
45
|
+
failed: number;
|
|
46
|
+
}
|
|
47
|
+
export declare function uploadSessions(sessions: DiscoveredSession[], syncState: SyncState, options: UploadOptions): Promise<UploadTotals>;
|
|
48
|
+
export type SyncRunOptions = DiscoverOptions & UploadOptions;
|
|
49
|
+
export type SyncRunSummary = UploadTotals & {
|
|
50
|
+
found: number;
|
|
51
|
+
matched: number;
|
|
52
|
+
unresolved: number;
|
|
53
|
+
};
|
|
54
|
+
/** Discover, scope and upload in one go (what `halyard hook` runs in the background). */
|
|
55
|
+
export declare function runSync(options: SyncRunOptions): Promise<SyncRunSummary>;
|
|
56
|
+
//# sourceMappingURL=sync-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-runner.d.ts","sourceRoot":"","sources":["../../src/lib/sync-runner.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAML,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAA;AAExB;;;;;GAKG;AAEH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAoBvD;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAA;CAClD;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,iBAAiB,EAAE,CAAA;IAC7B,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CAW/E;AAED,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAgDvB;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,aAAa,CAAA;AAC5D,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAA;AAElG,yFAAyF;AACzF,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAW9E"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { uploadSession } from './api-client.js';
|
|
3
|
+
import { discoverAllSessions, loadSessionContent, uploadFileName, } from './discovery.js';
|
|
4
|
+
import { resolveRepoIdentity, sameRepo } from './repo-identity.js';
|
|
5
|
+
import { hashFileContents, isUploaded, markUploaded, readSyncState, writeSyncState, } from './sync-state.js';
|
|
6
|
+
/**
|
|
7
|
+
* The "discover, scope, upload everything new" pipeline shared by
|
|
8
|
+
* `halyard sync` and `halyard hook`. Sync state is org-keyed (`stateKey`
|
|
9
|
+
* from the upload preflight), so a session synced to org A still uploads to
|
|
10
|
+
* org B.
|
|
11
|
+
*/
|
|
12
|
+
export function sizeSuffix(bytes) {
|
|
13
|
+
if (bytes <= 0)
|
|
14
|
+
return '';
|
|
15
|
+
return ` (${(bytes / 1024).toFixed(1)} KB)`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Keep only sessions whose cwd resolves to the same repository as `rootDir`.
|
|
19
|
+
* Sessions whose cwd/repo cannot be resolved are counted as unresolved (the
|
|
20
|
+
* caller reports them once); sessions from other repos are silently excluded.
|
|
21
|
+
*/
|
|
22
|
+
export function scopeSessionsToRepo(sessions, rootDir) {
|
|
23
|
+
// The binding root is normally a git toplevel; if git can't resolve it,
|
|
24
|
+
// fall back to matching by the binding directory itself.
|
|
25
|
+
const repoIdentity = resolveRepoIdentity(rootDir) ?? { rootDir, remote: null };
|
|
26
|
+
const matched = [];
|
|
27
|
+
let unresolved = 0;
|
|
28
|
+
for (const session of sessions) {
|
|
29
|
+
if (!session.cwd) {
|
|
30
|
+
unresolved++;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const sessionIdentity = resolveRepoIdentity(session.cwd);
|
|
34
|
+
if (!sessionIdentity) {
|
|
35
|
+
unresolved++;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (sameRepo(sessionIdentity, repoIdentity))
|
|
39
|
+
matched.push(session);
|
|
40
|
+
}
|
|
41
|
+
return { sessions: matched, unresolved };
|
|
42
|
+
}
|
|
43
|
+
export function discoverScopedSessions(options) {
|
|
44
|
+
let sessions = discoverAllSessions(options.providerFilter);
|
|
45
|
+
const found = sessions.length;
|
|
46
|
+
let unresolved = 0;
|
|
47
|
+
if (options.scopeRootDir) {
|
|
48
|
+
const scoped = scopeSessionsToRepo(sessions, options.scopeRootDir);
|
|
49
|
+
sessions = scoped.sessions;
|
|
50
|
+
unresolved = scoped.unresolved;
|
|
51
|
+
}
|
|
52
|
+
if (options.exclude)
|
|
53
|
+
sessions = sessions.filter((session) => !options.exclude?.(session));
|
|
54
|
+
return { sessions, found, unresolved };
|
|
55
|
+
}
|
|
56
|
+
export async function uploadSessions(sessions, syncState, options) {
|
|
57
|
+
const { stateKey, authHeaders, apiUrl, dryRun, log } = options;
|
|
58
|
+
const totals = { uploaded: 0, skipped: 0, failed: 0 };
|
|
59
|
+
for (const session of sessions) {
|
|
60
|
+
// Store-backed sessions hash a freshness marker so unchanged sessions
|
|
61
|
+
// skip without being exported; file-backed sessions hash their bytes.
|
|
62
|
+
const hash = hashFileContents(session.freshness ? Buffer.from(session.freshness) : readFileSync(session.filePath));
|
|
63
|
+
if (isUploaded(syncState, stateKey, session.filePath, hash)) {
|
|
64
|
+
totals.skipped++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (dryRun) {
|
|
68
|
+
log(` [dry-run] Would upload: ${session.filePath}${sizeSuffix(session.sizeBytes)}`);
|
|
69
|
+
totals.uploaded++;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const content = await loadSessionContent(session);
|
|
74
|
+
const result = await uploadSession(content, uploadFileName(session), session.provider, session.sessionId, authHeaders, apiUrl);
|
|
75
|
+
markUploaded(syncState, stateKey, session.filePath, {
|
|
76
|
+
sessionId: result.sessionId,
|
|
77
|
+
uploadedAt: new Date().toISOString(),
|
|
78
|
+
size: content.length,
|
|
79
|
+
hash,
|
|
80
|
+
});
|
|
81
|
+
const status = result.status === 'duplicate' ? 'already exists' : 'uploaded';
|
|
82
|
+
log(` ${status}: ${session.filePath}${sizeSuffix(content.length)}`);
|
|
83
|
+
totals.uploaded++;
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
log(` failed: ${session.filePath} - ${err instanceof Error ? err.message : String(err)}`);
|
|
87
|
+
totals.failed++;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return totals;
|
|
91
|
+
}
|
|
92
|
+
/** Discover, scope and upload in one go (what `halyard hook` runs in the background). */
|
|
93
|
+
export async function runSync(options) {
|
|
94
|
+
const discovered = discoverScopedSessions(options);
|
|
95
|
+
const syncState = readSyncState();
|
|
96
|
+
const totals = await uploadSessions(discovered.sessions, syncState, options);
|
|
97
|
+
if (!options.dryRun)
|
|
98
|
+
writeSyncState(syncState);
|
|
99
|
+
return {
|
|
100
|
+
...totals,
|
|
101
|
+
found: discovered.found,
|
|
102
|
+
matched: discovered.sessions.length,
|
|
103
|
+
unresolved: discovered.unresolved,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=sync-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-runner.js","sourceRoot":"","sources":["../../src/lib/sync-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/sync-state.d.ts
CHANGED
|
@@ -4,12 +4,38 @@ export interface SyncEntry {
|
|
|
4
4
|
size: number;
|
|
5
5
|
hash: string;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* What a skill upload carries. Bumped when the payload gains something the
|
|
9
|
+
* server cannot recover from an older upload (v2: file contents + raw
|
|
10
|
+
* front-matter), so every machine re-sends each skill exactly once after
|
|
11
|
+
* upgrading — the server still answers `unchanged` when nothing moved.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SKILL_PAYLOAD_VERSION = 2;
|
|
14
|
+
export interface SkillSyncEntry {
|
|
15
|
+
/** Tree fingerprint the skill was last synced at (see skill-fingerprint.ts). */
|
|
16
|
+
hash: string;
|
|
17
|
+
syncedAt: string;
|
|
18
|
+
knowledgeEntryId: string;
|
|
19
|
+
/** Absent on rows written before payload versioning; treated as stale. */
|
|
20
|
+
payloadVersion?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface OrgSyncLedger {
|
|
9
23
|
files: Record<string, SyncEntry>;
|
|
24
|
+
/** Skill ledger keyed by `<scope>:<scopeKey>:<relativePath>`; absent on pre-skills state files. */
|
|
25
|
+
skills?: Record<string, SkillSyncEntry>;
|
|
26
|
+
}
|
|
27
|
+
export interface SyncState {
|
|
28
|
+
version: 2;
|
|
29
|
+
/** Per-org upload ledgers, keyed by orgId (or `api-key:<id>` for sk_ keys). */
|
|
30
|
+
orgs: Record<string, OrgSyncLedger>;
|
|
10
31
|
}
|
|
11
32
|
/**
|
|
12
33
|
* Read the current sync state from disk.
|
|
34
|
+
*
|
|
35
|
+
* A legacy v1 file (top-level `files`, no org keying) is discarded and
|
|
36
|
+
* replaced with an empty v2 state. This is safe because server ingest
|
|
37
|
+
* dedupes on the unique (orgId, source, localSessionId) tuple - re-uploading
|
|
38
|
+
* a previously synced file just returns 'duplicate' and re-marks it here.
|
|
13
39
|
*/
|
|
14
40
|
export declare function readSyncState(): SyncState;
|
|
15
41
|
/**
|
|
@@ -17,13 +43,17 @@ export declare function readSyncState(): SyncState;
|
|
|
17
43
|
*/
|
|
18
44
|
export declare function writeSyncState(state: SyncState): void;
|
|
19
45
|
/**
|
|
20
|
-
* Check if a file has already been uploaded (by content hash).
|
|
46
|
+
* Check if a file has already been uploaded to an org (by content hash).
|
|
21
47
|
*/
|
|
22
|
-
export declare function isUploaded(state: SyncState, filePath: string, hash: string): boolean;
|
|
48
|
+
export declare function isUploaded(state: SyncState, orgKey: string, filePath: string, hash: string): boolean;
|
|
23
49
|
/**
|
|
24
|
-
* Mark a file as uploaded in the sync state.
|
|
50
|
+
* Mark a file as uploaded to an org in the sync state.
|
|
25
51
|
*/
|
|
26
|
-
export declare function markUploaded(state: SyncState, filePath: string, info: SyncEntry): void;
|
|
52
|
+
export declare function markUploaded(state: SyncState, orgKey: string, filePath: string, info: SyncEntry): void;
|
|
53
|
+
/** Has a skill already been synced to an org at this fingerprint, with the current payload shape? */
|
|
54
|
+
export declare function isSkillSynced(state: SyncState, orgKey: string, ledgerKey: string, hash: string): boolean;
|
|
55
|
+
/** Record a skill as synced to an org with the current payload shape. */
|
|
56
|
+
export declare function markSkillSynced(state: SyncState, orgKey: string, ledgerKey: string, info: Omit<SkillSyncEntry, 'payloadVersion'>): void;
|
|
27
57
|
/**
|
|
28
58
|
* Compute a hash of a file's contents for change detection.
|
|
29
59
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-state.d.ts","sourceRoot":"","sources":["../../src/lib/sync-state.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"sync-state.d.ts","sourceRoot":"","sources":["../../src/lib/sync-state.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAA;AAEtC,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,MAAM,CAAA;IACxB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAChC,mGAAmG;IACnG,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,SAAS,CAWzC;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAGrD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAGT;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,GACd,IAAI,CAGN;AAED,qGAAqG;AACrG,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAGT;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,GAC3C,IAAI,CAGN;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD"}
|