@pleri/olam-cli 0.1.145 → 0.1.146

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/commands/skills-doctor.d.ts +14 -0
  2. package/dist/commands/skills-doctor.d.ts.map +1 -0
  3. package/dist/commands/skills-doctor.js +126 -0
  4. package/dist/commands/skills-doctor.js.map +1 -0
  5. package/dist/commands/skills-hook.d.ts +19 -0
  6. package/dist/commands/skills-hook.d.ts.map +1 -0
  7. package/dist/commands/skills-hook.js +99 -0
  8. package/dist/commands/skills-hook.js.map +1 -0
  9. package/dist/commands/skills-migrate-back.d.ts +21 -0
  10. package/dist/commands/skills-migrate-back.d.ts.map +1 -0
  11. package/dist/commands/skills-migrate-back.js +222 -0
  12. package/dist/commands/skills-migrate-back.js.map +1 -0
  13. package/dist/commands/skills-migrate.d.ts +33 -0
  14. package/dist/commands/skills-migrate.d.ts.map +1 -0
  15. package/dist/commands/skills-migrate.js +216 -0
  16. package/dist/commands/skills-migrate.js.map +1 -0
  17. package/dist/commands/skills-onboard.d.ts +26 -0
  18. package/dist/commands/skills-onboard.d.ts.map +1 -0
  19. package/dist/commands/skills-onboard.js +227 -0
  20. package/dist/commands/skills-onboard.js.map +1 -0
  21. package/dist/commands/skills-shadow-backups.d.ts +15 -0
  22. package/dist/commands/skills-shadow-backups.d.ts.map +1 -0
  23. package/dist/commands/skills-shadow-backups.js +132 -0
  24. package/dist/commands/skills-shadow-backups.js.map +1 -0
  25. package/dist/commands/skills-source.d.ts +25 -0
  26. package/dist/commands/skills-source.d.ts.map +1 -1
  27. package/dist/commands/skills-source.js +305 -7
  28. package/dist/commands/skills-source.js.map +1 -1
  29. package/dist/commands/skills.d.ts.map +1 -1
  30. package/dist/commands/skills.js +13 -6
  31. package/dist/commands/skills.js.map +1 -1
  32. package/dist/commands/substrate-audit-log.d.ts +49 -0
  33. package/dist/commands/substrate-audit-log.d.ts.map +1 -0
  34. package/dist/commands/substrate-audit-log.js +148 -0
  35. package/dist/commands/substrate-audit-log.js.map +1 -0
  36. package/dist/commands/substrate.d.ts +60 -0
  37. package/dist/commands/substrate.d.ts.map +1 -0
  38. package/dist/commands/substrate.js +175 -0
  39. package/dist/commands/substrate.js.map +1 -0
  40. package/dist/commands/upgrade.d.ts +10 -0
  41. package/dist/commands/upgrade.d.ts.map +1 -1
  42. package/dist/commands/upgrade.js +30 -0
  43. package/dist/commands/upgrade.js.map +1 -1
  44. package/dist/image-digests.json +7 -7
  45. package/dist/index.js +5012 -1992
  46. package/dist/index.js.map +1 -1
  47. package/dist/lib/config.d.ts +69 -0
  48. package/dist/lib/config.d.ts.map +1 -0
  49. package/dist/lib/config.js +146 -0
  50. package/dist/lib/config.js.map +1 -0
  51. package/dist/lib/instrumentation.d.ts +85 -0
  52. package/dist/lib/instrumentation.d.ts.map +1 -0
  53. package/dist/lib/instrumentation.js +104 -0
  54. package/dist/lib/instrumentation.js.map +1 -0
  55. package/dist/lib/kubectl-wrap.d.ts +59 -0
  56. package/dist/lib/kubectl-wrap.d.ts.map +1 -0
  57. package/dist/lib/kubectl-wrap.js +130 -0
  58. package/dist/lib/kubectl-wrap.js.map +1 -0
  59. package/dist/lib/manifest-refresh.d.ts +95 -0
  60. package/dist/lib/manifest-refresh.d.ts.map +1 -0
  61. package/dist/lib/manifest-refresh.js +222 -0
  62. package/dist/lib/manifest-refresh.js.map +1 -0
  63. package/dist/lib/port-forward.d.ts +101 -0
  64. package/dist/lib/port-forward.d.ts.map +1 -0
  65. package/dist/lib/port-forward.js +240 -0
  66. package/dist/lib/port-forward.js.map +1 -0
  67. package/dist/lib/upgrade-kubernetes.d.ts +77 -0
  68. package/dist/lib/upgrade-kubernetes.d.ts.map +1 -0
  69. package/dist/lib/upgrade-kubernetes.js +277 -0
  70. package/dist/lib/upgrade-kubernetes.js.map +1 -0
  71. package/dist/mcp-server.js +19537 -18270
  72. package/host-cp/k8s/manifests/00-namespace.yaml +7 -0
  73. package/host-cp/k8s/manifests/10-serviceaccount.yaml +8 -0
  74. package/host-cp/k8s/manifests/20-rbac.yaml +34 -0
  75. package/host-cp/k8s/manifests/30-configmap.yaml +30 -0
  76. package/host-cp/k8s/manifests/45-pvc.yaml +27 -0
  77. package/host-cp/k8s/manifests/50-deployment.yaml +148 -0
  78. package/host-cp/k8s/manifests/60-service.yaml +22 -0
  79. package/host-cp/k8s/templates/40-secret-template.yaml +32 -0
  80. package/host-cp/src/plan-chat-service.mjs +31 -7
  81. package/host-cp/src/server.mjs +32 -7
  82. package/package.json +3 -2
@@ -0,0 +1,216 @@
1
+ /**
2
+ * `olam skills migrate-from-toolbox` — convert an existing toolbox-shaped
3
+ * skill source (e.g. atlas-toolbox, grain/ai-skills) installation to
4
+ * olam-managed skill distribution.
5
+ *
6
+ * Order of operations (atomic in spirit — snapshot first, mutations after):
7
+ * 1. detectToolboxState({ toolboxPath }) → MigrationSnapshot (or no-op when nothing detected)
8
+ * 2. writeMigrationSnapshot() → ~/.olam/state/migration-snapshots/<namespace>-<ISO>.json
9
+ * 3. addSkillSource() + cloneSkillSource() → register the toolbox as an olam source
10
+ * 4. uninstall legacy toolbox SessionStart hook entries (entries whose command
11
+ * references the toolbox repo path OR `./scripts/sync.sh`)
12
+ * 5. install the olam-skills SessionStart hook (via mergeHomeSettingsJson)
13
+ * 6. run `olam skills sync` to deploy artifacts under olam management
14
+ *
15
+ * Idempotent: re-running on an already-migrated host detects the olam
16
+ * hook sentinel and no-ops with an informative message.
17
+ */
18
+ import * as fs from 'node:fs';
19
+ import * as path from 'node:path';
20
+ import { addSkillSource, cloneSkillSource, detectToolboxState, writeMigrationSnapshot, OLAM_SKILLS_HOOK_SENTINEL, buildSkillsHookEntry, OLAM_SKILLS_HOOK_STAGE, syncSkills, } from '@olam/core/src/skill-sources/index.js';
21
+ import { mergeHomeSettingsJson } from '@olam/core/src/world/merge-settings.js';
22
+ import { claudeSettingsPath } from '@olam/core/src/skill-sources/index.js';
23
+ import { printError, printInfo, printSuccess, printWarning } from '../output.js';
24
+ /** Stable command identifier — referenced by tests to keep them rename-resilient. */
25
+ export const MIGRATE_FROM_TOOLBOX_COMMAND = 'migrate-from-toolbox';
26
+ function asMessage(err) {
27
+ return err instanceof Error ? err.message : String(err);
28
+ }
29
+ function isOlamSkillsHookPresent(filePath) {
30
+ if (!fs.existsSync(filePath))
31
+ return false;
32
+ try {
33
+ const raw = fs.readFileSync(filePath, 'utf-8');
34
+ return raw.includes(OLAM_SKILLS_HOOK_SENTINEL);
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ /**
41
+ * Surgically remove SessionStart hook entries that reference the toolbox
42
+ * repo path OR call `./scripts/sync.sh` (legacy atlas-toolbox sync entry —
43
+ * harmless no-op against non-atlas toolboxes). Leaves olam-skills entries
44
+ * and unrelated user hooks intact.
45
+ */
46
+ function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
47
+ if (!fs.existsSync(filePath))
48
+ return { removed: 0 };
49
+ const raw = fs.readFileSync(filePath, 'utf-8');
50
+ const settings = raw.trim() ? JSON.parse(raw) : {};
51
+ const ss = settings?.hooks?.SessionStart;
52
+ if (!Array.isArray(ss))
53
+ return { removed: 0 };
54
+ let removed = 0;
55
+ const filteredMatchers = [];
56
+ for (const matcher of ss) {
57
+ const innerHooks = Array.isArray(matcher?.hooks) ? matcher.hooks : [];
58
+ const keptInner = innerHooks.filter((h) => {
59
+ if (typeof h?.command !== 'string')
60
+ return true;
61
+ // Identify legacy-toolbox-shape entries by command content.
62
+ const looksLegacyToolbox = h.command.includes('./scripts/sync.sh') ||
63
+ (toolboxPath !== undefined && h.command.includes(toolboxPath));
64
+ // Never remove olam-skills entries here — install-skills-hook handles those.
65
+ const isOlam = h.command.includes(OLAM_SKILLS_HOOK_SENTINEL);
66
+ if (looksLegacyToolbox && !isOlam) {
67
+ removed += 1;
68
+ return false;
69
+ }
70
+ return true;
71
+ });
72
+ if (keptInner.length === 0 && innerHooks.length > 0)
73
+ continue;
74
+ if (keptInner.length === innerHooks.length)
75
+ filteredMatchers.push(matcher);
76
+ else
77
+ filteredMatchers.push({ ...matcher, hooks: keptInner });
78
+ }
79
+ if (removed === 0)
80
+ return { removed: 0 };
81
+ const next = { ...settings, hooks: { ...settings.hooks, SessionStart: filteredMatchers } };
82
+ if (filteredMatchers.length === 0) {
83
+ const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== 'SessionStart');
84
+ if (otherStages.length === 0)
85
+ delete next.hooks;
86
+ else
87
+ delete next.hooks.SessionStart;
88
+ }
89
+ fs.writeFileSync(filePath, JSON.stringify(next, null, 2) + '\n');
90
+ return { removed };
91
+ }
92
+ export function registerSkillsMigrate(program) {
93
+ const skills = program.commands.find((c) => c.name() === 'skills') ??
94
+ program.command('skills').description('Manage skill sources and synchronization');
95
+ skills
96
+ .command(MIGRATE_FROM_TOOLBOX_COMMAND)
97
+ .description('Convert an existing toolbox-shaped skill source (atlas-toolbox, grain/ai-skills, etc.) to olam-managed skill distribution')
98
+ .option('--path <path>', 'Absolute path to the source toolbox repo (e.g. /repos/atlas-toolbox, /repos/grain/ai-skills)')
99
+ .option('--namespace <name>', 'Source-identifying namespace used for the snapshot filename + default source name (default: basename of --path)')
100
+ .option('--source-name <name>', 'Display name for the registered olam source (default: --namespace)')
101
+ .option('--branch <branch>', 'Branch to track on the source', 'master')
102
+ .option('--scope <scope>', 'install-hook scope: project (default) or user', 'project')
103
+ .option('--no-clone', 'Skip clone step (register source state only — useful for tests)')
104
+ .action(async (opts) => {
105
+ // Idempotency: if olam-skills sentinel already present, no-op.
106
+ const settingsFile = claudeSettingsPath();
107
+ if (isOlamSkillsHookPresent(settingsFile)) {
108
+ printInfo(MIGRATE_FROM_TOOLBOX_COMMAND, `already migrated (olam-skills hook sentinel present in ${settingsFile})`);
109
+ return;
110
+ }
111
+ if (!opts.path) {
112
+ printError('--path <path> is required (absolute path to the source toolbox repo, e.g. /repos/atlas-toolbox)');
113
+ process.exitCode = 1;
114
+ return;
115
+ }
116
+ const toolboxPath = opts.path;
117
+ const namespace = opts.namespace ?? path.basename(toolboxPath);
118
+ const sourceName = opts.sourceName ?? namespace;
119
+ // 1. Detect.
120
+ const snapshot = detectToolboxState({ toolboxPath, namespace });
121
+ if (!snapshot) {
122
+ printInfo(MIGRATE_FROM_TOOLBOX_COMMAND, `no toolbox state detected at ${toolboxPath} (no ~/.claude/.atlas-user, no symlinks pointing at this path, no SessionStart hook block — nothing to migrate)`);
123
+ return;
124
+ }
125
+ // 2. Snapshot (ALWAYS — before any mutation).
126
+ let snapshotPath;
127
+ try {
128
+ snapshotPath = writeMigrationSnapshot(snapshot);
129
+ printInfo('snapshot', snapshotPath);
130
+ }
131
+ catch (err) {
132
+ printError(`snapshot write failed: ${asMessage(err)}`);
133
+ process.exitCode = 1;
134
+ return;
135
+ }
136
+ // 3. Register source + clone.
137
+ // `trustMethod: 'internal'` — migrate-from is an operator-explicit
138
+ // command (operator typed it). Bypasses the interactive trust
139
+ // gate but is structurally audit-logged via addSkillSource()
140
+ // itself; the trust-audit log records the bypass.
141
+ try {
142
+ const entry = addSkillSource({
143
+ name: sourceName,
144
+ gitUrl: toolboxPath,
145
+ branch: opts.branch,
146
+ trustMethod: 'internal',
147
+ });
148
+ printInfo('registered source', `${entry.name} (${entry.id})`);
149
+ if (opts.clone !== false) {
150
+ const cloneResult = cloneSkillSource({
151
+ gitUrl: entry.gitUrl,
152
+ branch: entry.branch,
153
+ id: entry.id,
154
+ });
155
+ printInfo('cloned to', cloneResult.clonePath);
156
+ }
157
+ else {
158
+ printInfo('clone skipped', '--no-clone passed');
159
+ }
160
+ }
161
+ catch (err) {
162
+ printError(`source registration failed: ${asMessage(err)}`);
163
+ printInfo('snapshot preserved', snapshotPath);
164
+ process.exitCode = 1;
165
+ return;
166
+ }
167
+ // 4. Uninstall legacy toolbox SessionStart hook.
168
+ try {
169
+ const surgery = uninstallLegacyToolboxSessionStartHook(settingsFile, toolboxPath);
170
+ if (surgery.removed > 0) {
171
+ printInfo('legacy hook', `removed ${surgery.removed} entry(ies) from ${settingsFile}`);
172
+ }
173
+ else {
174
+ printInfo('legacy hook', 'no legacy-toolbox-shape SessionStart hook entries found');
175
+ }
176
+ }
177
+ catch (err) {
178
+ printWarning(`legacy hook removal failed: ${asMessage(err)}; proceeding`);
179
+ }
180
+ // 5. Install olam-skills hook.
181
+ const scope = opts.scope === 'user' ? 'user' : 'project';
182
+ const olamHookPath = scope === 'user' ? settingsFile : path.join(process.cwd(), '.claude', 'settings.json');
183
+ try {
184
+ fs.mkdirSync(path.dirname(olamHookPath), { recursive: true });
185
+ const result = mergeHomeSettingsJson(olamHookPath, {
186
+ ensureHook: {
187
+ stage: OLAM_SKILLS_HOOK_STAGE,
188
+ sentinel: OLAM_SKILLS_HOOK_SENTINEL,
189
+ entry: buildSkillsHookEntry(),
190
+ },
191
+ });
192
+ printInfo('olam hook', `${result.status} at ${olamHookPath}`);
193
+ }
194
+ catch (err) {
195
+ printError(`olam hook install failed: ${asMessage(err)}`);
196
+ printInfo('snapshot preserved', snapshotPath);
197
+ process.exitCode = 1;
198
+ return;
199
+ }
200
+ // 6. Sync.
201
+ try {
202
+ const summary = await syncSkills({ atlasUser: snapshot.atlasUser });
203
+ printSuccess(`migrated — synced ${summary.sourceCount} source(s), deployed ${summary.deploy?.linked ?? 0} symlink(s)`);
204
+ printInfo('snapshot', snapshotPath);
205
+ printInfo('reverse', `run \`olam skills migrate-back-to-toolbox --path ${toolboxPath}\` to restore the original state`);
206
+ }
207
+ catch (err) {
208
+ printError(`sync failed: ${asMessage(err)}`);
209
+ printInfo('snapshot preserved', snapshotPath);
210
+ process.exitCode = 1;
211
+ }
212
+ });
213
+ }
214
+ // Export internal helper for tests + reverse-migration consumers.
215
+ export { uninstallLegacyToolboxSessionStartHook };
216
+ //# sourceMappingURL=skills-migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-migrate.js","sourceRoot":"","sources":["../../src/commands/skills-migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * olam skills onboard — fresh-install umbrella that composes the 3-step
3
+ * recipe into one operator-friendly verb.
4
+ *
5
+ * olam skills onboard --name <n> --git-url <url> [--branch main]
6
+ * [--trust] [--scope project|user]
7
+ *
8
+ * Pipeline:
9
+ * 1. addSkillSource({ trustMethod: 'flag' }) — `--trust` is the only
10
+ * sanctioned trust method here. Onboard is non-interactive by
11
+ * design (it composes 4 steps; an interactive picker mid-pipeline
12
+ * would be confusing). Operators who want the picker should run
13
+ * `olam skills source add` directly.
14
+ * 2. cloneSkillSource(...) — register + clone.
15
+ * 3. installSkillsHookToFile(...) at --scope (default project).
16
+ * 4. syncSkills() — first sync.
17
+ * 5. Print a single success summary covering all 4 steps.
18
+ *
19
+ * Failure rollback: any failure AFTER step 1 (clone, hook install,
20
+ * sync) unwinds the registered source so the operator can re-try
21
+ * cleanly. Each step appends an audit row so the trust-coverage gate
22
+ * stays accurate even when the umbrella partially fails.
23
+ */
24
+ import type { Command } from 'commander';
25
+ export declare function registerSkillsOnboard(program: Command): void;
26
+ //# sourceMappingURL=skills-onboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-onboard.d.ts","sourceRoot":"","sources":["../../src/commands/skills-onboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0M5D"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * olam skills onboard — fresh-install umbrella that composes the 3-step
3
+ * recipe into one operator-friendly verb.
4
+ *
5
+ * olam skills onboard --name <n> --git-url <url> [--branch main]
6
+ * [--trust] [--scope project|user]
7
+ *
8
+ * Pipeline:
9
+ * 1. addSkillSource({ trustMethod: 'flag' }) — `--trust` is the only
10
+ * sanctioned trust method here. Onboard is non-interactive by
11
+ * design (it composes 4 steps; an interactive picker mid-pipeline
12
+ * would be confusing). Operators who want the picker should run
13
+ * `olam skills source add` directly.
14
+ * 2. cloneSkillSource(...) — register + clone.
15
+ * 3. installSkillsHookToFile(...) at --scope (default project).
16
+ * 4. syncSkills() — first sync.
17
+ * 5. Print a single success summary covering all 4 steps.
18
+ *
19
+ * Failure rollback: any failure AFTER step 1 (clone, hook install,
20
+ * sync) unwinds the registered source so the operator can re-try
21
+ * cleanly. Each step appends an audit row so the trust-coverage gate
22
+ * stays accurate even when the umbrella partially fails.
23
+ */
24
+ import pc from 'picocolors';
25
+ import { addSkillSource, cloneSkillSource, installSkillsHookToFile, removeSkillSource, removeSkillSourceClone, skillsHookSettingsPathFor, syncSkills, updateSkillSource, appendTrustAudit, redactUrl, } from '@olam/core/src/skill-sources/index.js';
26
+ import { printError, printInfo, printSuccess, printHeader } from '../output.js';
27
+ function asMessage(err) {
28
+ return err instanceof Error ? err.message : String(err);
29
+ }
30
+ export function registerSkillsOnboard(program) {
31
+ const skills = program.commands.find((c) => c.name() === 'skills') ??
32
+ program.command('skills').description('Manage skill sources and synchronization');
33
+ skills
34
+ .command('onboard')
35
+ .description('Fresh-install umbrella: register + clone + install SessionStart hook + first sync, in one verb')
36
+ .requiredOption('--name <name>', 'Display name (lowercase, digits, dash)')
37
+ .requiredOption('--git-url <url>', 'git URL (https://, git@, ssh://, file://, or absolute path)')
38
+ .option('--branch <branch>', 'Branch to track', 'main')
39
+ .option('--trust', 'Acknowledge that registering grants symlink-into-~/.claude permission (required: onboard is non-interactive)')
40
+ .option('--scope <scope>', 'Hook install scope: project (<cwd>/.claude/settings.json) or user (~/.claude/settings.json)', 'project')
41
+ .action(async (opts) => {
42
+ const scope = opts.scope === 'user' ? 'user' : 'project';
43
+ // Onboard composes 4 steps end-to-end. Surfacing a TTY trust prompt
44
+ // mid-pipeline would split operator attention; require --trust as
45
+ // the only sanctioned path here. Operators who want the picker can
46
+ // run `olam skills source add` (then run install-hook + sync
47
+ // themselves) — same surface, different ergonomic.
48
+ if (opts.trust !== true) {
49
+ try {
50
+ appendTrustAudit({
51
+ gitUrl: redactUrl(opts.gitUrl),
52
+ action: 'auto-rejected',
53
+ trustMethod: 'auto-reject-tty',
54
+ note: 'onboard: --trust required (composed pipeline; no mid-flow picker)',
55
+ });
56
+ }
57
+ catch {
58
+ // best-effort audit
59
+ }
60
+ printError('`olam skills onboard` requires --trust. Registering a skill source grants ' +
61
+ 'symlink-into-~/.claude permission; onboard is non-interactive so the operator ' +
62
+ 'must acknowledge up front. (For the interactive picker use `olam skills source add`.)');
63
+ process.exitCode = 1;
64
+ return;
65
+ }
66
+ // ---------------------------------------------------------------
67
+ // Step 1: register the source (writes 'added' audit entry internally).
68
+ // ---------------------------------------------------------------
69
+ let entry;
70
+ try {
71
+ entry = addSkillSource({
72
+ name: opts.name,
73
+ gitUrl: opts.gitUrl,
74
+ branch: opts.branch ?? 'main',
75
+ trustMethod: 'flag',
76
+ });
77
+ }
78
+ catch (err) {
79
+ try {
80
+ appendTrustAudit({
81
+ gitUrl: redactUrl(opts.gitUrl),
82
+ action: 'failed',
83
+ trustMethod: 'flag',
84
+ note: `onboard step=add: ${asMessage(err)}`,
85
+ });
86
+ }
87
+ catch {
88
+ // best-effort
89
+ }
90
+ printError(asMessage(err));
91
+ process.exitCode = 1;
92
+ return;
93
+ }
94
+ // ---------------------------------------------------------------
95
+ // Step 2: clone the source. Rolls back step 1 on failure.
96
+ // ---------------------------------------------------------------
97
+ let headSha;
98
+ try {
99
+ const result = cloneSkillSource({
100
+ gitUrl: entry.gitUrl,
101
+ branch: entry.branch,
102
+ id: entry.id,
103
+ });
104
+ headSha = result.headSha;
105
+ updateSkillSource(entry.id, { lastPulledSha: result.headSha });
106
+ }
107
+ catch (err) {
108
+ try {
109
+ removeSkillSource(entry.id);
110
+ }
111
+ catch {
112
+ // best-effort
113
+ }
114
+ try {
115
+ appendTrustAudit({
116
+ gitUrl: redactUrl(entry.gitUrl),
117
+ action: 'failed',
118
+ trustMethod: 'flag',
119
+ sourceId: entry.id,
120
+ note: `onboard step=clone: ${asMessage(err)}`,
121
+ });
122
+ }
123
+ catch {
124
+ // best-effort
125
+ }
126
+ printError(asMessage(err));
127
+ process.exitCode = 1;
128
+ return;
129
+ }
130
+ // ---------------------------------------------------------------
131
+ // Step 3: install SessionStart hook. Rolls back clone + register
132
+ // on failure so the operator's state stays clean.
133
+ // ---------------------------------------------------------------
134
+ const hookFilePath = skillsHookSettingsPathFor(scope);
135
+ let hookStatus;
136
+ let hookBackupPath;
137
+ try {
138
+ const result = installSkillsHookToFile(hookFilePath);
139
+ hookStatus = result.status;
140
+ hookBackupPath = result.backupPath;
141
+ }
142
+ catch (err) {
143
+ try {
144
+ removeSkillSourceClone(entry.id);
145
+ removeSkillSource(entry.id);
146
+ }
147
+ catch {
148
+ // best-effort
149
+ }
150
+ try {
151
+ appendTrustAudit({
152
+ gitUrl: redactUrl(entry.gitUrl),
153
+ action: 'failed',
154
+ trustMethod: 'flag',
155
+ sourceId: entry.id,
156
+ note: `onboard step=install-hook: ${asMessage(err)}`,
157
+ });
158
+ }
159
+ catch {
160
+ // best-effort
161
+ }
162
+ printError(`install-hook failed: ${asMessage(err)}`);
163
+ process.exitCode = 1;
164
+ return;
165
+ }
166
+ // ---------------------------------------------------------------
167
+ // Step 4: first sync. Rolls back clone + register on failure so
168
+ // the operator can re-try cleanly. Leaves the hook in place — the
169
+ // hook is independently useful even if THIS source failed to
170
+ // deploy artifacts; uninstall-hook is its own surgical action.
171
+ // ---------------------------------------------------------------
172
+ let syncedArtifacts = 0;
173
+ try {
174
+ const summary = await syncSkills({});
175
+ syncedArtifacts = summary.artifactCount;
176
+ }
177
+ catch (err) {
178
+ try {
179
+ removeSkillSourceClone(entry.id);
180
+ removeSkillSource(entry.id);
181
+ }
182
+ catch {
183
+ // best-effort
184
+ }
185
+ try {
186
+ appendTrustAudit({
187
+ gitUrl: redactUrl(entry.gitUrl),
188
+ action: 'failed',
189
+ trustMethod: 'flag',
190
+ sourceId: entry.id,
191
+ note: `onboard step=sync: ${asMessage(err)}`,
192
+ });
193
+ }
194
+ catch {
195
+ // best-effort
196
+ }
197
+ printError(`sync failed: ${asMessage(err)}`);
198
+ process.exitCode = 1;
199
+ return;
200
+ }
201
+ // ---------------------------------------------------------------
202
+ // Single success summary covering all 4 steps.
203
+ // ---------------------------------------------------------------
204
+ printHeader('skills onboard — complete');
205
+ printSuccess(`registered "${entry.name}" (${entry.id}) @ ${headSha.slice(0, 8)}`);
206
+ printInfo('git url', entry.gitUrl);
207
+ printInfo('branch', entry.branch);
208
+ printInfo('clone', `(see ~/.olam/state/skill-sources/${entry.id})`);
209
+ switch (hookStatus) {
210
+ case 'installed':
211
+ printInfo('hook', `installed (${scope} scope) at ${hookFilePath}`);
212
+ if (hookBackupPath)
213
+ printInfo('backup', hookBackupPath);
214
+ break;
215
+ case 'already-present':
216
+ printInfo('hook', `already installed at ${hookFilePath}`);
217
+ break;
218
+ case 'no-op':
219
+ printInfo('hook', `no change at ${hookFilePath}`);
220
+ break;
221
+ }
222
+ printInfo('sync', `${syncedArtifacts} artifact(s) deployed`);
223
+ console.log();
224
+ console.log(pc.dim(' Open a new Claude Code session to pick up the deployed skills.'));
225
+ });
226
+ }
227
+ //# sourceMappingURL=skills-onboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-onboard.js","sourceRoot":"","sources":["../../src/commands/skills-onboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * olam skills shadow-backups — manage A4's quarantine files.
3
+ *
4
+ * olam skills shadow-backups list all backups + ages
5
+ * olam skills shadow-backups prune [--older-than=<dur>] delete old ones
6
+ * [--all --force] OR delete every one
7
+ * [--dry-run]
8
+ * olam skills shadow-backups restore <path> [--force] move back to original
9
+ *
10
+ * T2 mitigation: prevents unbounded backup growth without ever touching a
11
+ * non-shadow-backup file (strict `.shadow-backup-<digits>` suffix match).
12
+ */
13
+ import type { Command } from 'commander';
14
+ export declare function registerSkillsShadowBackups(program: Command): void;
15
+ //# sourceMappingURL=skills-shadow-backups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-shadow-backups.d.ts","sourceRoot":"","sources":["../../src/commands/skills-shadow-backups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0CzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsFlE"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * olam skills shadow-backups — manage A4's quarantine files.
3
+ *
4
+ * olam skills shadow-backups list all backups + ages
5
+ * olam skills shadow-backups prune [--older-than=<dur>] delete old ones
6
+ * [--all --force] OR delete every one
7
+ * [--dry-run]
8
+ * olam skills shadow-backups restore <path> [--force] move back to original
9
+ *
10
+ * T2 mitigation: prevents unbounded backup growth without ever touching a
11
+ * non-shadow-backup file (strict `.shadow-backup-<digits>` suffix match).
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import pc from 'picocolors';
15
+ import { listShadowBackups, pruneShadowBackups, restoreShadowBackup, parseDurationToMs, } from '@olam/core/src/skill-sources/index.js';
16
+ import { printError, printHeader, printSuccess } from '../output.js';
17
+ function asMessage(err) {
18
+ return err instanceof Error ? err.message : String(err);
19
+ }
20
+ function formatAge(ms) {
21
+ if (ms < 0)
22
+ return '<future>';
23
+ const d = Math.floor(ms / 86_400_000);
24
+ if (d >= 1)
25
+ return `${d}d`;
26
+ const h = Math.floor(ms / 3_600_000);
27
+ if (h >= 1)
28
+ return `${h}h`;
29
+ const m = Math.floor(ms / 60_000);
30
+ if (m >= 1)
31
+ return `${m}m`;
32
+ const s = Math.floor(ms / 1_000);
33
+ return `${s}s`;
34
+ }
35
+ function formatSize(bytes) {
36
+ if (bytes < 1024)
37
+ return `${bytes}B`;
38
+ if (bytes < 1024 * 1024)
39
+ return `${(bytes / 1024).toFixed(1)}KB`;
40
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
41
+ }
42
+ function printBackupRows(backups) {
43
+ for (const b of backups) {
44
+ const when = new Date(b.epochSeconds * 1000).toISOString().slice(0, 10);
45
+ console.log(` ${pc.dim(formatAge(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc.dim(when)} ${b.bucket}/${pc.bold(b.basename)}`);
46
+ }
47
+ }
48
+ export function registerSkillsShadowBackups(program) {
49
+ const skills = program.commands.find((c) => c.name() === 'skills') ??
50
+ program.command('skills').description('Manage skill sources and synchronization');
51
+ const sb = skills
52
+ .command('shadow-backups')
53
+ .description('Manage `.shadow-backup-<epoch>` quarantine files left by `olam skills sync`');
54
+ sb.command('list')
55
+ .description('List all shadow-backup files under ~/.claude/')
56
+ .action(() => {
57
+ const all = listShadowBackups();
58
+ if (all.length === 0) {
59
+ console.log(pc.dim('No shadow-backup files under ~/.claude/.'));
60
+ return;
61
+ }
62
+ printHeader(`${all.length} shadow backup(s)`);
63
+ console.log(pc.dim(' age size created bucket/basename'));
64
+ printBackupRows(all);
65
+ });
66
+ sb.command('prune')
67
+ .description('Delete shadow-backup files older than a duration (e.g. 30d) OR all of them with --all --force')
68
+ .option('--older-than <duration>', 'Delete backups older than this duration (e.g. 30d, 7d, 24h, 2w)', '30d')
69
+ .option('--all', 'Delete every shadow-backup file (requires --force)')
70
+ .option('--force', 'Confirm deletion when --all is used')
71
+ .option('--dry-run', 'Show what would be deleted without deleting')
72
+ .action((opts) => {
73
+ try {
74
+ let pruneOpts;
75
+ if (opts.all === true) {
76
+ if (opts.force !== true) {
77
+ printError('--all requires --force (refuses accidental wipes)');
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ pruneOpts = { all: true, dryRun: opts.dryRun };
82
+ }
83
+ else {
84
+ const olderThanMs = parseDurationToMs(opts.olderThan);
85
+ if (olderThanMs === undefined) {
86
+ printError(`unrecognized --older-than value "${opts.olderThan}" (expected like "30d", "7d", "24h", "2w")`);
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ pruneOpts = { olderThanMs, dryRun: opts.dryRun };
91
+ }
92
+ const result = pruneShadowBackups(pruneOpts);
93
+ const action = opts.dryRun ? 'would delete' : 'deleted';
94
+ if (result.deleted.length === 0) {
95
+ console.log(pc.dim(`No shadow-backups match — ${result.skipped.length} kept`));
96
+ return;
97
+ }
98
+ printHeader(`${action} ${result.deleted.length} shadow backup(s) (${result.skipped.length} kept)`);
99
+ printBackupRows(result.deleted);
100
+ if (opts.dryRun) {
101
+ console.log(pc.dim('\n(dry-run — re-run without --dry-run to delete)'));
102
+ }
103
+ else {
104
+ printSuccess(`pruned ${result.deleted.length} backup(s)`);
105
+ }
106
+ }
107
+ catch (err) {
108
+ printError(asMessage(err));
109
+ process.exitCode = 1;
110
+ }
111
+ });
112
+ sb.command('restore')
113
+ .description('Move a shadow-backup file back to its original path')
114
+ .argument('<path>', 'Absolute path to the .shadow-backup-<epoch> file')
115
+ .option('--force', 'Overwrite the original path if it already exists')
116
+ .action((p, opts) => {
117
+ try {
118
+ if (!fs.existsSync(p)) {
119
+ printError(`backup file not found: ${p}`);
120
+ process.exitCode = 1;
121
+ return;
122
+ }
123
+ const result = restoreShadowBackup({ backupPath: p, force: opts.force });
124
+ printSuccess(`restored → ${result.restoredTo}`);
125
+ }
126
+ catch (err) {
127
+ printError(asMessage(err));
128
+ process.exitCode = 1;
129
+ }
130
+ });
131
+ }
132
+ //# sourceMappingURL=skills-shadow-backups.js.map