portable-agent-layer 0.10.0 → 0.12.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/assets/skills/{analyze-pdf.md → analyze-pdf/SKILL.md} +4 -4
- package/{src → assets/skills/analyze-pdf}/tools/pdf-download.ts +3 -3
- package/assets/skills/{analyze-youtube.md → analyze-youtube/SKILL.md} +4 -4
- package/{src → assets/skills/analyze-youtube}/tools/youtube-analyze.ts +2 -2
- package/assets/skills/{council.md → council/SKILL.md} +3 -2
- package/assets/skills/{create-skill.md → create-skill/SKILL.md} +2 -1
- package/assets/skills/{extract-entities.md → extract-entities/SKILL.md} +4 -5
- package/{src → assets/skills/extract-entities}/tools/entity-save.ts +3 -3
- package/assets/skills/{extract-wisdom.md → extract-wisdom/SKILL.md} +3 -2
- package/assets/skills/{first-principles.md → first-principles/SKILL.md} +3 -2
- package/assets/skills/{fyzz-chat-api.md → fyzz-chat-api/SKILL.md} +6 -6
- package/{src → assets/skills/fyzz-chat-api}/tools/fyzz-api.ts +6 -6
- package/assets/skills/{reflect.md → reflect/SKILL.md} +2 -1
- package/assets/skills/{research.md → research/SKILL.md} +2 -1
- package/assets/skills/{review.md → review/SKILL.md} +2 -1
- package/assets/skills/{summarize.md → summarize/SKILL.md} +3 -2
- package/assets/skills/telos/SKILL.md +94 -0
- package/assets/skills/telos/tools/update-telos.ts +100 -0
- package/assets/skills/think/SKILL.md +47 -0
- package/assets/templates/AGENTS.md.template +51 -32
- package/assets/templates/PAL/ALGORITHM.md +120 -0
- package/assets/templates/PAL/CONTEXT_ROUTING.md +28 -0
- package/assets/templates/PAL/MEMORY_SYSTEM.md +26 -0
- package/assets/templates/PAL/OPINION_TRACKING.md +3 -0
- package/assets/templates/PAL/STEERING_RULES.md +43 -0
- package/assets/templates/PAL/WORK_TRACKING.md +14 -0
- package/assets/templates/pal-settings.json +32 -0
- package/assets/templates/settings.claude.json +80 -0
- package/package.json +4 -7
- package/src/cli/index.ts +7 -0
- package/src/cli/setup-identity.ts +119 -0
- package/src/hooks/lib/claude-md.ts +52 -26
- package/src/hooks/lib/context.ts +49 -25
- package/src/hooks/lib/paths.ts +2 -0
- package/src/hooks/lib/security.ts +2 -0
- package/src/hooks/lib/setup.ts +4 -16
- package/src/targets/claude/install.ts +20 -93
- package/src/targets/claude/uninstall.ts +22 -47
- package/src/targets/lib.ts +207 -48
- package/src/targets/opencode/install.ts +13 -2
- package/src/targets/opencode/uninstall.ts +4 -1
- package/assets/templates/STEERING-RULES.md +0 -23
- package/assets/templates/telos/IDENTITY.md +0 -4
- package/src/cli/install.ts +0 -86
- package/src/cli/uninstall.ts +0 -45
package/src/targets/lib.ts
CHANGED
|
@@ -41,6 +41,101 @@ export function writeJson(path: string, data: unknown): void {
|
|
|
41
41
|
writeFileSync(path, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// --- Settings template merge/unmerge ---
|
|
45
|
+
|
|
46
|
+
type HookEntry = { matcher?: string; hooks?: Array<{ type: string; command: string }> };
|
|
47
|
+
type Settings = Record<string, unknown> & {
|
|
48
|
+
hooks?: Record<string, HookEntry[]>;
|
|
49
|
+
permissions?: { allow?: string[]; deny?: string[]; ask?: string[] };
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load a settings template, replacing {{PKG_ROOT}} with the actual path.
|
|
54
|
+
*/
|
|
55
|
+
export function loadSettingsTemplate(templatePath: string, pkgRoot: string): Settings {
|
|
56
|
+
const raw = readFileSync(templatePath, "utf-8");
|
|
57
|
+
const resolved = raw.replaceAll("{{PKG_ROOT}}", pkgRoot);
|
|
58
|
+
return JSON.parse(resolved) as Settings;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Merge a PAL settings template into existing settings.
|
|
63
|
+
* - hooks: deduplicate by command string
|
|
64
|
+
* - permissions.allow: deduplicate by value
|
|
65
|
+
* - other keys: template values are added if not already present
|
|
66
|
+
*/
|
|
67
|
+
export function mergeSettings(existing: Settings, template: Settings): Settings {
|
|
68
|
+
const result = { ...existing };
|
|
69
|
+
|
|
70
|
+
// Merge hooks (deduplicate by command)
|
|
71
|
+
if (template.hooks) {
|
|
72
|
+
if (!result.hooks) result.hooks = {};
|
|
73
|
+
for (const [event, entries] of Object.entries(template.hooks)) {
|
|
74
|
+
const current = result.hooks[event] ?? [];
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
const cmd = entry.hooks?.[0]?.command;
|
|
77
|
+
if (cmd && !current.some((e) => e.hooks?.[0]?.command === cmd)) {
|
|
78
|
+
current.push(entry);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
result.hooks[event] = current;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Merge permissions.allow (deduplicate)
|
|
86
|
+
if (template.permissions?.allow) {
|
|
87
|
+
if (!result.permissions) result.permissions = {};
|
|
88
|
+
if (!result.permissions.allow) result.permissions.allow = [];
|
|
89
|
+
for (const perm of template.permissions.allow) {
|
|
90
|
+
if (!result.permissions.allow.includes(perm)) {
|
|
91
|
+
result.permissions.allow.push(perm);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Remove everything a PAL settings template added from existing settings.
|
|
101
|
+
* - hooks: remove entries whose command matches any template command
|
|
102
|
+
* - permissions.allow: remove entries that appear in the template
|
|
103
|
+
* - cleans up empty arrays/objects
|
|
104
|
+
*/
|
|
105
|
+
export function unmergeSettings(existing: Settings, template: Settings): Settings {
|
|
106
|
+
const result = { ...existing };
|
|
107
|
+
|
|
108
|
+
// Collect all PAL hook commands from template
|
|
109
|
+
if (template.hooks && result.hooks) {
|
|
110
|
+
const palCommands = new Set<string>();
|
|
111
|
+
for (const entries of Object.values(template.hooks)) {
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
const cmd = entry.hooks?.[0]?.command;
|
|
114
|
+
if (cmd) palCommands.add(cmd);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (const [event, entries] of Object.entries(result.hooks)) {
|
|
119
|
+
result.hooks[event] = entries.filter((e) => {
|
|
120
|
+
const cmd = e.hooks?.[0]?.command;
|
|
121
|
+
return !cmd || !palCommands.has(cmd);
|
|
122
|
+
});
|
|
123
|
+
if (result.hooks[event].length === 0) delete result.hooks[event];
|
|
124
|
+
}
|
|
125
|
+
if (Object.keys(result.hooks).length === 0) delete result.hooks;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Remove PAL permissions
|
|
129
|
+
if (template.permissions?.allow && result.permissions?.allow) {
|
|
130
|
+
const palPerms = new Set(template.permissions.allow);
|
|
131
|
+
result.permissions.allow = result.permissions.allow.filter((p) => !palPerms.has(p));
|
|
132
|
+
if (result.permissions.allow.length === 0) delete result.permissions.allow;
|
|
133
|
+
if (Object.keys(result.permissions).length === 0) delete result.permissions;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
44
139
|
// --- TELOS scaffolding ---
|
|
45
140
|
|
|
46
141
|
/** Copy template files into telos/ without overwriting existing ones */
|
|
@@ -60,14 +155,82 @@ export function scaffoldTelos(): void {
|
|
|
60
155
|
}
|
|
61
156
|
}
|
|
62
157
|
|
|
158
|
+
// --- PAL settings scaffolding ---
|
|
159
|
+
|
|
160
|
+
/** Copy pal-settings.json template to memory/ without overwriting */
|
|
161
|
+
export function scaffoldPalSettings(): void {
|
|
162
|
+
const src = resolve(assets.skills(), "..", "templates", "pal-settings.json");
|
|
163
|
+
if (!existsSync(src)) return;
|
|
164
|
+
|
|
165
|
+
const memDir = resolve(palHome(), "memory");
|
|
166
|
+
mkdirSync(memDir, { recursive: true });
|
|
167
|
+
|
|
168
|
+
const dst = resolve(memDir, "pal-settings.json");
|
|
169
|
+
if (!existsSync(dst)) {
|
|
170
|
+
copyFileSync(src, dst);
|
|
171
|
+
log.info("Created pal-settings.json from template");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// --- PAL docs (modular context routing files) ---
|
|
176
|
+
|
|
177
|
+
const PAL_DOCS_DIR = resolve(platform.agentsDir(), "PAL");
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Install PAL system docs into ~/.agents/PAL/.
|
|
181
|
+
* Always overwrites — these are engine-managed, not user-editable.
|
|
182
|
+
*/
|
|
183
|
+
export function copyPalDocs(): number {
|
|
184
|
+
const srcDir = assets.palDocs();
|
|
185
|
+
if (!existsSync(srcDir)) return 0;
|
|
186
|
+
|
|
187
|
+
mkdirSync(PAL_DOCS_DIR, { recursive: true });
|
|
188
|
+
let count = 0;
|
|
189
|
+
|
|
190
|
+
for (const file of readdirSync(srcDir).filter((f) => f.endsWith(".md"))) {
|
|
191
|
+
const src = resolve(srcDir, file);
|
|
192
|
+
const dst = resolve(PAL_DOCS_DIR, file);
|
|
193
|
+
copyFileSync(src, dst);
|
|
194
|
+
count++;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Symlink ~/.agents/PAL/telos and ~/.agents/PAL/memory → <palHome>/...
|
|
198
|
+
const linkType = process.platform === "win32" ? "junction" : "dir";
|
|
199
|
+
ensureSymlink(resolve(PAL_DOCS_DIR, "telos"), resolve(palHome(), "telos"), linkType);
|
|
200
|
+
ensureSymlink(resolve(PAL_DOCS_DIR, "memory"), resolve(palHome(), "memory"), linkType);
|
|
201
|
+
|
|
202
|
+
return count;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Remove PAL system docs from ~/.agents/PAL/ */
|
|
206
|
+
export function removePalDocs(): void {
|
|
207
|
+
if (!existsSync(PAL_DOCS_DIR)) return;
|
|
208
|
+
for (const file of readdirSync(PAL_DOCS_DIR).filter((f) => f.endsWith(".md"))) {
|
|
209
|
+
try {
|
|
210
|
+
unlinkSync(resolve(PAL_DOCS_DIR, file));
|
|
211
|
+
} catch {
|
|
212
|
+
/* gone */
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
rmSync(PAL_DOCS_DIR, { recursive: true });
|
|
217
|
+
log.info("Removed ~/.agents/PAL/");
|
|
218
|
+
} catch {
|
|
219
|
+
/* gone */
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
63
223
|
// --- Skills ---
|
|
64
224
|
|
|
65
225
|
const AGENTS_SKILLS_DIR = resolve(platform.agentsDir(), "skills");
|
|
66
226
|
|
|
67
227
|
/**
|
|
68
|
-
* Install PAL skills
|
|
69
|
-
*
|
|
70
|
-
*
|
|
228
|
+
* Install PAL skills by symlinking:
|
|
229
|
+
* ~/.agents/skills/<name> → <repo>/assets/skills/<name> (source of truth)
|
|
230
|
+
* ~/.claude/skills/<name> → ~/.agents/skills/<name> (Claude Code discovery)
|
|
231
|
+
*
|
|
232
|
+
* Symlinks mean tools inside skills can import from the repo (src/hooks/lib/*)
|
|
233
|
+
* and everything resolves naturally. Additive — skips skills already installed.
|
|
71
234
|
*/
|
|
72
235
|
export function copySkills(claudeSkillsDir: string): number {
|
|
73
236
|
const skillsDir = assets.skills();
|
|
@@ -75,69 +238,65 @@ export function copySkills(claudeSkillsDir: string): number {
|
|
|
75
238
|
|
|
76
239
|
mkdirSync(AGENTS_SKILLS_DIR, { recursive: true });
|
|
77
240
|
mkdirSync(claudeSkillsDir, { recursive: true });
|
|
241
|
+
const linkType = process.platform === "win32" ? "junction" : "dir";
|
|
78
242
|
let count = 0;
|
|
79
243
|
|
|
80
|
-
for (const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
244
|
+
for (const name of readdirSync(skillsDir)) {
|
|
245
|
+
const srcDir = resolve(skillsDir, name);
|
|
246
|
+
if (!existsSync(resolve(srcDir, "SKILL.md"))) continue;
|
|
247
|
+
|
|
248
|
+
// ~/.agents/skills/<name> → <repo>/assets/skills/<name>
|
|
249
|
+
const agentLink = resolve(AGENTS_SKILLS_DIR, name);
|
|
250
|
+
ensureSymlink(agentLink, srcDir, linkType);
|
|
251
|
+
|
|
252
|
+
// ~/.claude/skills/<name> → ~/.agents/skills/<name>
|
|
85
253
|
const claudeLink = resolve(claudeSkillsDir, name);
|
|
254
|
+
ensureSymlink(claudeLink, agentLink, linkType);
|
|
86
255
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
count++;
|
|
93
|
-
} else {
|
|
94
|
-
log.warn(`Skill exists, skipping: ${name}`);
|
|
95
|
-
}
|
|
256
|
+
log.info(`Linked skill: ${name}`);
|
|
257
|
+
count++;
|
|
258
|
+
}
|
|
259
|
+
return count;
|
|
260
|
+
}
|
|
96
261
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
262
|
+
/** Create or update a symlink/junction, replacing any non-symlink entry. */
|
|
263
|
+
function ensureSymlink(link: string, target: string, type: "dir" | "junction"): void {
|
|
264
|
+
try {
|
|
265
|
+
const st = lstatSync(link);
|
|
266
|
+
if (st.isSymbolicLink()) return; // already a symlink, leave it
|
|
267
|
+
rmSync(link, { recursive: true, force: true });
|
|
268
|
+
} catch {
|
|
269
|
+
// doesn't exist or broken — clean up just in case
|
|
100
270
|
try {
|
|
101
|
-
|
|
102
|
-
if (!st.isSymbolicLink()) {
|
|
103
|
-
rmSync(claudeLink, { recursive: true, force: true });
|
|
104
|
-
symlinkSync(`../../.agents/skills/${name}`, claudeLink, linkType);
|
|
105
|
-
}
|
|
271
|
+
rmSync(link, { recursive: true, force: true });
|
|
106
272
|
} catch {
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
rmSync(claudeLink, { recursive: true, force: true });
|
|
110
|
-
} catch {
|
|
111
|
-
/* gone */
|
|
112
|
-
}
|
|
113
|
-
symlinkSync(`../../.agents/skills/${name}`, claudeLink, linkType);
|
|
273
|
+
/* gone */
|
|
114
274
|
}
|
|
115
275
|
}
|
|
116
|
-
|
|
276
|
+
symlinkSync(target, link, type);
|
|
117
277
|
}
|
|
118
278
|
|
|
119
|
-
/** Remove PAL
|
|
279
|
+
/** Remove PAL skill symlinks from ~/.agents/skills/ and ~/.claude/skills/ */
|
|
120
280
|
export function removeSkills(claudeSkillsDir: string): string[] {
|
|
121
281
|
const skillsDir = assets.skills();
|
|
122
282
|
if (!existsSync(skillsDir)) return [];
|
|
123
283
|
|
|
124
284
|
const removed: string[] = [];
|
|
125
|
-
for (const
|
|
126
|
-
|
|
285
|
+
for (const name of readdirSync(skillsDir)) {
|
|
286
|
+
if (!existsSync(resolve(skillsDir, name, "SKILL.md"))) continue;
|
|
127
287
|
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
unlinkSync(claudeLink);
|
|
138
|
-
} catch {
|
|
139
|
-
/* already gone */
|
|
288
|
+
for (const link of [
|
|
289
|
+
resolve(AGENTS_SKILLS_DIR, name),
|
|
290
|
+
resolve(claudeSkillsDir, name),
|
|
291
|
+
]) {
|
|
292
|
+
try {
|
|
293
|
+
unlinkSync(link);
|
|
294
|
+
} catch {
|
|
295
|
+
/* already gone */
|
|
296
|
+
}
|
|
140
297
|
}
|
|
298
|
+
removed.push(name);
|
|
299
|
+
log.info(`Removed skill: ${name}`);
|
|
141
300
|
}
|
|
142
301
|
return removed;
|
|
143
302
|
}
|
|
@@ -7,7 +7,14 @@ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "
|
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
import { regenerateIfNeeded } from "../../hooks/lib/claude-md";
|
|
9
9
|
import { palPkg, platform } from "../../hooks/lib/paths";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
copyAgentsForOpencode,
|
|
12
|
+
copyPalDocs,
|
|
13
|
+
copySkills,
|
|
14
|
+
countSkills,
|
|
15
|
+
log,
|
|
16
|
+
writeJson,
|
|
17
|
+
} from "../lib";
|
|
11
18
|
|
|
12
19
|
const PKG_ROOT = palPkg();
|
|
13
20
|
const OC_GLOBAL_DIR = platform.opencodeDir();
|
|
@@ -53,7 +60,11 @@ log.success("Installed skills to ~/.agents/skills/");
|
|
|
53
60
|
const ocAgentsDir = resolve(OC_GLOBAL_DIR, "agents");
|
|
54
61
|
copyAgentsForOpencode(ocAgentsDir);
|
|
55
62
|
|
|
56
|
-
// --- 5.
|
|
63
|
+
// --- 5. Copy PAL system docs ---
|
|
64
|
+
const palDocsCount = copyPalDocs();
|
|
65
|
+
log.success(`Installed ${palDocsCount} PAL docs to ~/.agents/PAL/`);
|
|
66
|
+
|
|
67
|
+
// --- 6. Generate ~/.config/opencode/AGENTS.md ---
|
|
57
68
|
regenerateIfNeeded();
|
|
58
69
|
log.success("Generated ~/.config/opencode/AGENTS.md");
|
|
59
70
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { unlinkSync } from "node:fs";
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
import { platform } from "../../hooks/lib/paths";
|
|
9
|
-
import { log, removeAgentsFromOpencode, removeSkills } from "../lib";
|
|
9
|
+
import { log, removeAgentsFromOpencode, removePalDocs, removeSkills } from "../lib";
|
|
10
10
|
|
|
11
11
|
const OC_GLOBAL_DIR = platform.opencodeDir() || "";
|
|
12
12
|
|
|
@@ -38,6 +38,9 @@ if (removedAgents.length > 0)
|
|
|
38
38
|
`Removed ${removedAgents.length} opencode agent(s): ${removedAgents.join(", ")}`
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
+
// --- Remove PAL system docs ---
|
|
42
|
+
removePalDocs();
|
|
43
|
+
|
|
41
44
|
// --- Remove AGENTS.md and CLAUDE.md symlink ---
|
|
42
45
|
const agentsMd = resolve(OC_GLOBAL_DIR, "AGENTS.md");
|
|
43
46
|
const claudeMd = resolve(PAL_CLAUDE_DIR, "CLAUDE.md");
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
## Steering Rules
|
|
2
|
-
|
|
3
|
-
Behavioral directives — act on these, don't just know them.
|
|
4
|
-
|
|
5
|
-
**Surgical fixes only.** When debugging, make precise corrections to the broken behavior. Never delete or rearchitect components as a fix. If you believe a component is the root cause, explain your reasoning and ask before removing it.
|
|
6
|
-
|
|
7
|
-
**Never assert without verification.** Don't say something "is" a certain way unless you've verified it with your tools. After making changes, verify the result before claiming success. Evidence required — tests, diffs, tool output. Never "Done!" without proof.
|
|
8
|
-
|
|
9
|
-
**First principles over bolt-ons.** Most problems are symptoms. Understand → Simplify → Reduce → Add (last resort). Don't accrue technical debt through band-aid solutions.
|
|
10
|
-
|
|
11
|
-
**Read before modifying.** Understand existing code, imports, and patterns before suggesting changes.
|
|
12
|
-
|
|
13
|
-
**One change when debugging.** Isolate, verify, proceed. Don't change multiple things at once.
|
|
14
|
-
|
|
15
|
-
**Minimal scope.** Only change what was asked. No bonus refactoring, no extra cleanup, no unsolicited improvements.
|
|
16
|
-
|
|
17
|
-
**Ask before destructive actions.** Deletes, force pushes, production deploys — always ask first.
|
|
18
|
-
|
|
19
|
-
**Plan means stop.** "Create a plan" = present and STOP. No execution without approval.
|
|
20
|
-
|
|
21
|
-
**Error recovery.** When told you did something wrong — review the session, identify the violation, fix it, then explain what happened and capture the learning. Don't ask "What did I do wrong?"
|
|
22
|
-
|
|
23
|
-
**Act on what you know.** When tracked opinions or relationship notes reveal user preferences, apply them to your behavior. If you know the user prefers concise responses, be concise. If they prefer manual commits, never offer to commit.
|
package/src/cli/install.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PAL — main installer entry point (TypeScript)
|
|
3
|
-
* Usage: bun run install.ts [--claude] [--opencode] [--all]
|
|
4
|
-
* Default: installs for both targets.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { ensureSetupState, isSetupComplete } from "../hooks/lib/setup";
|
|
8
|
-
import { log, scaffoldTelos } from "../targets/lib";
|
|
9
|
-
|
|
10
|
-
// --- Parse args ---
|
|
11
|
-
const args = process.argv.slice(2);
|
|
12
|
-
let installClaude = false;
|
|
13
|
-
let installOpencode = false;
|
|
14
|
-
|
|
15
|
-
if (args.length === 0) {
|
|
16
|
-
installClaude = true;
|
|
17
|
-
installOpencode = true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
for (const arg of args) {
|
|
21
|
-
if (arg === "--claude") installClaude = true;
|
|
22
|
-
else if (arg === "--opencode") installOpencode = true;
|
|
23
|
-
else if (arg === "--all") {
|
|
24
|
-
installClaude = true;
|
|
25
|
-
installOpencode = true;
|
|
26
|
-
} else if (arg === "--help" || arg === "-h") {
|
|
27
|
-
console.log("Usage: bun run install.ts [--claude] [--opencode] [--all]");
|
|
28
|
-
console.log("");
|
|
29
|
-
console.log(" --claude Install hooks/skills for Claude Code");
|
|
30
|
-
console.log(" --opencode Install context/skills for opencode");
|
|
31
|
-
console.log(" --all Install for both (default)");
|
|
32
|
-
process.exit(0);
|
|
33
|
-
} else {
|
|
34
|
-
log.error(`Unknown option: ${arg}`);
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// --- Check bun ---
|
|
40
|
-
if (installClaude) {
|
|
41
|
-
try {
|
|
42
|
-
Bun.version; // always available in bun
|
|
43
|
-
} catch {
|
|
44
|
-
log.error("bun is required: curl -fsSL https://bun.sh/install | bash");
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.log("");
|
|
50
|
-
console.log(" ╔═══════════════════════════════════╗");
|
|
51
|
-
console.log(" ║ PAL — Portable Agent Layer ║");
|
|
52
|
-
console.log(" ║ Non-destructive · Modular ║");
|
|
53
|
-
console.log(" ╚═══════════════════════════════════╝");
|
|
54
|
-
console.log("");
|
|
55
|
-
|
|
56
|
-
// --- Scaffold TELOS + seed setup state ---
|
|
57
|
-
scaffoldTelos();
|
|
58
|
-
ensureSetupState();
|
|
59
|
-
|
|
60
|
-
// --- Run target installers ---
|
|
61
|
-
if (installClaude) {
|
|
62
|
-
console.log("━━━ Claude Code ━━━");
|
|
63
|
-
await import("../targets/claude/install");
|
|
64
|
-
console.log("");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (installOpencode) {
|
|
68
|
-
console.log("━━━ opencode ━━━");
|
|
69
|
-
await import("../targets/opencode/install");
|
|
70
|
-
console.log("");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
log.success("Done. Existing config was preserved — only new entries were added.");
|
|
74
|
-
console.log("");
|
|
75
|
-
log.info("Next steps:");
|
|
76
|
-
|
|
77
|
-
const state = ensureSetupState();
|
|
78
|
-
if (!isSetupComplete(state)) {
|
|
79
|
-
log.info(" 1. Start a session — PAL will guide you through first-run setup");
|
|
80
|
-
log.info(" 2. Or fill in telos/*.md manually, then re-run install.ts");
|
|
81
|
-
} else {
|
|
82
|
-
log.info(" 1. Fill in telos/*.md with your info (if not already done)");
|
|
83
|
-
log.info(" 2. Re-run install.ts to regenerate context files");
|
|
84
|
-
}
|
|
85
|
-
log.info(" 3. Add skills by dropping .md files into skills/");
|
|
86
|
-
log.info(" 4. Uninstall: bun run uninstall.ts [--claude] [--opencode]");
|
package/src/cli/uninstall.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PAL — main uninstaller entry point (TypeScript)
|
|
3
|
-
* Usage: bun run uninstall.ts [--claude] [--opencode] [--all]
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { palHome } from "../hooks/lib/paths";
|
|
7
|
-
import { log } from "../targets/lib";
|
|
8
|
-
|
|
9
|
-
const args = process.argv.slice(2);
|
|
10
|
-
let removeClaude = false;
|
|
11
|
-
let removeOpencode = false;
|
|
12
|
-
|
|
13
|
-
if (args.length === 0) {
|
|
14
|
-
removeClaude = true;
|
|
15
|
-
removeOpencode = true;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
for (const arg of args) {
|
|
19
|
-
if (arg === "--claude") removeClaude = true;
|
|
20
|
-
else if (arg === "--opencode") removeOpencode = true;
|
|
21
|
-
else if (arg === "--all") {
|
|
22
|
-
removeClaude = true;
|
|
23
|
-
removeOpencode = true;
|
|
24
|
-
} else if (arg === "--help" || arg === "-h") {
|
|
25
|
-
console.log("Usage: bun run uninstall.ts [--claude] [--opencode] [--all]");
|
|
26
|
-
process.exit(0);
|
|
27
|
-
} else {
|
|
28
|
-
log.error(`Unknown option: ${arg}`);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (removeClaude) {
|
|
34
|
-
console.log("━━━ Claude Code ━━━");
|
|
35
|
-
await import("../targets/claude/uninstall");
|
|
36
|
-
console.log("");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (removeOpencode) {
|
|
40
|
-
console.log("━━━ opencode ━━━");
|
|
41
|
-
await import("../targets/opencode/uninstall");
|
|
42
|
-
console.log("");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
log.success(`PAL uninstalled. Your TELOS, skills, and memory are still in ${palHome()}.`);
|