portable-agent-layer 0.91.2 → 0.91.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portable-agent-layer",
3
- "version": "0.91.2",
3
+ "version": "0.91.4",
4
4
  "description": "PAL — Portable Agent Layer: persistent personal context for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,10 +57,10 @@ try {
57
57
  process.exit(0);
58
58
  }
59
59
 
60
- // The reminder is built for one of three targets; every other agent reads the
60
+ // The reminder is built for one of four targets; every other agent reads the
61
61
  // same shape Claude Code does.
62
62
  const target: AgentTarget =
63
- active === "copilot" || active === "cursor" ? active : "claude";
63
+ active === "copilot" || active === "cursor" || active === "codex" ? active : "claude";
64
64
  const reminder = buildSystemReminder({
65
65
  agent: target,
66
66
  withoutHandoff: wanted === "without-handoff",
@@ -13,7 +13,7 @@ import { loadOpinionContext } from "./opinions";
13
13
  import { paths, toPath } from "./paths";
14
14
  import { loadActiveProjectsContext } from "./projects";
15
15
  import { loadRecentNotes } from "./relationship";
16
- import { loadFailurePatterns } from "./semi-static";
16
+ import { loadFailurePatterns, loadSteeringRules } from "./semi-static";
17
17
  import { sessionDir } from "./session-dir";
18
18
  import * as settings from "./settings";
19
19
  import { readFramePrinciples } from "./wisdom";
@@ -173,10 +173,13 @@ function capSection(text: string, maxChars: number): string {
173
173
  return kept.join("\n");
174
174
  }
175
175
 
176
- /** Agent targets — determines which context sections are skipped due to native loading. */
176
+ /**
177
+ * Agent targets — determines which context sections are skipped due to native loading.
178
+ * Codex has no native include for them, so its reminder carries them.
179
+ */
177
180
  export type AgentTarget = Extract<
178
181
  AgentName,
179
- "claude" | "opencode" | "cursor" | "copilot"
182
+ "claude" | "opencode" | "cursor" | "copilot" | "codex"
180
183
  >;
181
184
 
182
185
  /**
@@ -215,6 +218,7 @@ export function buildSystemReminder(
215
218
  !skipSemiStatic && settings.isEnabled("opinions") ? loadOpinionContext() : "";
216
219
  const selfModel =
217
220
  !skipSemiStatic && settings.isEnabled("selfModel") ? loadSelfModel() : "";
221
+ const steering = skipSemiStatic ? "" : loadSteeringRules();
218
222
  const handoff =
219
223
  !opts.withoutHandoff && settings.isEnabled("handoff")
220
224
  ? loadHandoffContext(sessionDir())
@@ -230,6 +234,7 @@ export function buildSystemReminder(
230
234
  if (relationship) parts.push(relationship);
231
235
  if (activeProjects) parts.push(activeProjects);
232
236
  if (failures) parts.push(failures);
237
+ if (steering) parts.push(steering);
233
238
  if (parts.length === 0) return "";
234
239
 
235
240
  const now = new Date();
@@ -104,13 +104,20 @@ export function loadFailurePatterns(): string {
104
104
  }
105
105
  }
106
106
 
107
+ function steeringRulesPath(): string {
108
+ return resolve(palHome(), "docs", "STEERING_RULES.md");
109
+ }
110
+
111
+ export function loadSteeringRules(): string {
112
+ return readFileSafe(steeringRulesPath());
113
+ }
114
+
107
115
  /**
108
116
  * All semi-static context sources in load order.
109
117
  * Adding one entry here is the only change needed to extend coverage to all consumers.
110
118
  */
111
119
  export function getSemiStaticSources(): SemiStaticSource[] {
112
120
  const memory = paths.memory();
113
- const home = palHome();
114
121
  return [
115
122
  {
116
123
  path: resolve(memory, "self-model", "current.md"),
@@ -157,9 +164,9 @@ export function getSemiStaticSources(): SemiStaticSource[] {
157
164
  description: "PAL recent failure lessons",
158
165
  },
159
166
  {
160
- path: resolve(home, "docs", "STEERING_RULES.md"),
167
+ path: steeringRulesPath(),
161
168
  writesDigest: false,
162
- load: () => readFileSafe(resolve(home, "docs", "STEERING_RULES.md")),
169
+ load: loadSteeringRules,
163
170
  slug: "steering",
164
171
  description: "PAL steering rules",
165
172
  },
@@ -989,8 +989,11 @@ export function removePalContextFiles(dir: string, suffix: string): string[] {
989
989
  return removed;
990
990
  }
991
991
 
992
- /** Remove PAL skill symlinks from ~/.pal/skills/ and ~/.claude/skills/ */
993
- export function removeSkills(claudeSkillsDir: string): string[] {
992
+ /**
993
+ * Remove one agent's PAL skill links. ~/.pal/skills/<name> and ~/.agents/skills
994
+ * are shared by every installed agent, so a per-agent uninstall leaves them.
995
+ */
996
+ export function removeSkills(agentSkillsDir: string): string[] {
994
997
  const skillsDir = assets.skills();
995
998
  if (!existsSync(skillsDir)) return [];
996
999
 
@@ -998,24 +1001,15 @@ export function removeSkills(claudeSkillsDir: string): string[] {
998
1001
  for (const name of readdirSync(skillsDir)) {
999
1002
  if (!existsSync(resolve(skillsDir, name, "SKILL.md"))) continue;
1000
1003
 
1001
- for (const link of [resolve(palSkillsDir(), name), resolve(claudeSkillsDir, name)]) {
1002
- try {
1003
- unlinkSync(link);
1004
- } catch {
1005
- /* already gone */
1006
- }
1004
+ try {
1005
+ unlinkSync(resolve(agentSkillsDir, name));
1006
+ } catch {
1007
+ /* already gone */
1007
1008
  }
1008
1009
  removed.push(name);
1009
1010
  log.detail(`Removed skill: ${name}`);
1010
1011
  }
1011
1012
 
1012
- // Remove ~/.agents/skills/ → ~/.pal/skills/ symlink
1013
- try {
1014
- unlinkSync(resolve(platform.agentsDir(), "skills"));
1015
- } catch {
1016
- /* gone */
1017
- }
1018
-
1019
1013
  return removed;
1020
1014
  }
1021
1015
 
@@ -7,7 +7,7 @@ import { existsSync, readFileSync, statSync, unlinkSync, writeFileSync } from "n
7
7
  import { resolve } from "node:path";
8
8
  import { platform } from "../../hooks/lib/paths";
9
9
  import { getSemiStaticSources } from "../../hooks/lib/semi-static";
10
- import { log, removeAgentsFromOpencode, removePalDocs, removeSkills } from "../lib";
10
+ import { log, removeAgentsFromOpencode, removePalDocs } from "../lib";
11
11
  import { palHomePattern, removePalHomeAllow } from "./permission";
12
12
 
13
13
  const OC_GLOBAL_DIR = platform.opencodeDir() || "";
@@ -28,11 +28,6 @@ try {
28
28
  log.info("No PAL plugin found");
29
29
  }
30
30
 
31
- // --- Remove skills ---
32
- const removed = removeSkills(resolve(PAL_CLAUDE_DIR, "skills"));
33
- if (removed.length > 0)
34
- log.success(`Removed ${removed.length} skill(s): ${removed.join(", ")}`);
35
-
36
31
  // --- Remove agents ---
37
32
  const removedAgents = removeAgentsFromOpencode(resolve(OC_GLOBAL_DIR, "agents"));
38
33
  if (removedAgents.length > 0)