@getfamiliar/shared 0.1.8 → 0.1.10

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.
@@ -121,11 +121,11 @@ export interface AgentRunRow {
121
121
  */
122
122
  readonly calltype: AgentRunCallType | null;
123
123
  /**
124
- * Number of retry attempts already made. Bumped each time
125
- * `AgentRunner` postpones the row due to a retryable inference
126
- * error. Compared against the per-handler `maxRetries` cap on
127
- * each subsequent attempt; once `retry_count >= cap` the run
128
- * settles `failed` instead of being postponed again.
124
+ * Number of retries already made. Bumped each time `AgentRunner`
125
+ * postpones the row due to a retryable inference error. Compared
126
+ * against the `maxRetries` cap (retries after the first attempt)
127
+ * whenever an attempt fails retryably; once `retry_count >= cap`
128
+ * the run settles `failed` instead of being postponed again.
129
129
  */
130
130
  readonly retryCount: number;
131
131
  /**
@@ -0,0 +1,15 @@
1
+ /**
2
+ * HTTP header carrying the shared secret every bastion caller must
3
+ * present. The host daemon generates (or reads from `core.bastionToken`)
4
+ * the token at startup; the agent container receives it through its
5
+ * passed config, host-side CLI commands read it from
6
+ * `tmp/.bastion-token`. Requests without a matching header are answered
7
+ * with `401` before any route runs.
8
+ *
9
+ * Deliberately a custom header rather than `Authorization`: the LLM
10
+ * SDKs already send `Authorization` / `x-api-key` placeholders on
11
+ * `/llm/` that the reverse proxy replaces, and a non-simple header
12
+ * forces a CORS preflight the bastion never answers, which keeps
13
+ * browser pages on the host from reaching it.
14
+ */
15
+ export declare const BASTION_TOKEN_HEADER = "x-familiar-bastion-token";
@@ -0,0 +1,15 @@
1
+ /**
2
+ * HTTP header carrying the shared secret every bastion caller must
3
+ * present. The host daemon generates (or reads from `core.bastionToken`)
4
+ * the token at startup; the agent container receives it through its
5
+ * passed config, host-side CLI commands read it from
6
+ * `tmp/.bastion-token`. Requests without a matching header are answered
7
+ * with `401` before any route runs.
8
+ *
9
+ * Deliberately a custom header rather than `Authorization`: the LLM
10
+ * SDKs already send `Authorization` / `x-api-key` placeholders on
11
+ * `/llm/` that the reverse proxy replaces, and a non-simple header
12
+ * forces a CORS preflight the bastion never answers, which keeps
13
+ * browser pages on the host from reaching it.
14
+ */
15
+ export const BASTION_TOKEN_HEADER = "x-familiar-bastion-token";
@@ -18,6 +18,16 @@ export interface HandlerPath {
18
18
  /** User-facing slash form, e.g. `/chat/telegram/index`. */
19
19
  readonly slashPath: string;
20
20
  }
21
+ /**
22
+ * Whether a workspace-relative path lies inside the top-level `skills/`
23
+ * folder. Shared by host (catalog, cron scheduler, `cron list`) and
24
+ * container (`HandlerFile.load`) so every side agrees that skills are
25
+ * never handlers.
26
+ *
27
+ * @param relativePath Workspace-relative posix path, e.g. `skills/jira-issue/SKILL.md`.
28
+ * @returns `true` when the first path segment is `skills`.
29
+ */
30
+ export declare function isUnderSkillsFolder(relativePath: string): boolean;
21
31
  /**
22
32
  * Read-only view over the `workspace/` directory's handler files.
23
33
  *
@@ -9,11 +9,24 @@ import { matchesAnyGlob } from "./PathGlob.js";
9
9
  */
10
10
  const RESERVED_ROOT_FILES = new Set(["SOUL.md", "CONTEXT.md"]);
11
11
  /**
12
- * Workspace subtrees that contain markdown but never handlers.
13
- * `skills/<name>/SKILL.md` is a shared recipe loaded via `fs_read`,
14
- * not an agent entry point.
12
+ * Top-level workspace folder holding shared recipes
13
+ * (`skills/<name>/SKILL.md`). Skills are pure context loaded via
14
+ * `fs_read`, never agent entry points — so nothing under this folder
15
+ * is ever listed, resolved, loaded or cron-scheduled as a handler.
15
16
  */
16
- const RESERVED_TOP_DIRS = new Set(["skills"]);
17
+ const SKILLS_FOLDER = "skills";
18
+ /**
19
+ * Whether a workspace-relative path lies inside the top-level `skills/`
20
+ * folder. Shared by host (catalog, cron scheduler, `cron list`) and
21
+ * container (`HandlerFile.load`) so every side agrees that skills are
22
+ * never handlers.
23
+ *
24
+ * @param relativePath Workspace-relative posix path, e.g. `skills/jira-issue/SKILL.md`.
25
+ * @returns `true` when the first path segment is `skills`.
26
+ */
27
+ export function isUnderSkillsFolder(relativePath) {
28
+ return relativePath.split("/")[0] === SKILLS_FOLDER;
29
+ }
17
30
  /**
18
31
  * Read-only view over the `workspace/` directory's handler files.
19
32
  *
@@ -86,6 +99,11 @@ export class HandlerCatalog {
86
99
  const relPosix = rel.split(path.sep).join("/");
87
100
  const absolute = path.join(this.workspaceDir, rel);
88
101
  if (await fileExists(absolute)) {
102
+ // Skills are shared recipes, never handlers — mirror the
103
+ // container's `HandlerFile.load` guard.
104
+ if (isUnderSkillsFolder(relPosix)) {
105
+ return null;
106
+ }
89
107
  // A file under `core.writablePaths` is never a handler, even
90
108
  // when it exists — mirror the container's `HandlerFile.load`
91
109
  // guard so host-side callers agree it does not resolve.
@@ -114,7 +132,7 @@ async function walkMarkdown(dir, segments, out, workspaceDir, writablePathGlobs)
114
132
  }
115
133
  for (const entry of entries) {
116
134
  if (entry.isDirectory()) {
117
- if (segments.length === 0 && RESERVED_TOP_DIRS.has(entry.name)) {
135
+ if (segments.length === 0 && entry.name === SKILLS_FOLDER) {
118
136
  continue;
119
137
  }
120
138
  await walkMarkdown(path.join(dir, entry.name), [...segments, entry.name], out, workspaceDir, writablePathGlobs);
package/build/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type { AgentRunCallType, AgentRunPatch, AgentRunRow, AgentRunState, NewAgentRun, } from "./AgentRun.js";
2
2
  export { AgentRunBus, type AgentRunUnsubscribe } from "./AgentRunBus.js";
3
+ export { BASTION_TOKEN_HEADER } from "./BastionAuth.js";
3
4
  export { buildCalendarEventId, type CalendarApi, type CalendarAttachmentMeta, type CalendarAttendee, type CalendarChangePayload, type CalendarEventRow, type CalendarEventType, type CalendarImportance, type CalendarProvider, type CalendarResponseStatus, type CalendarRow, type CalendarSensitivity, type CalendarShowAs, type CalendarType, type CreateEventInput, type FindEventsQuery, type NewCalendarEvent, parseCalendarEventId, type UpdateEventInput, type UpsertCalendarInput, } from "./Calendar.js";
4
5
  export type { ChatFilter, ChatMessage, ChatRole, NewChatMessage } from "./ChatMessage.js";
5
6
  export { type ChatHandler, ChatMessageBus, type ChatUnsubscribe } from "./ChatMessageBus.js";
@@ -10,7 +11,7 @@ export type { EventFile, EventFilter, EventPatch, EventRow, EventState, NewEvent
10
11
  export { EVENT_PRIORITY } from "./Event.js";
11
12
  export { DuplicateIdempotencyKeyError, EventBus } from "./EventBus.js";
12
13
  export { estimateTokens } from "./estimateTokens.js";
13
- export { HandlerCatalog, type HandlerPath } from "./HandlerCatalog.js";
14
+ export { HandlerCatalog, type HandlerPath, isUnderSkillsFolder } from "./HandlerCatalog.js";
14
15
  export type { InferenceEventRow, InferenceOutcome, NewInferenceEvent, } from "./InferenceEvent.js";
15
16
  export { InferenceEventBus } from "./InferenceEventBus.js";
16
17
  export { type CreateLoggerOptions, createLogger, jsonStdoutStream, type Logger, type LogLevel, type LogStream, prettyStdoutStream, } from "./logging/Logger.js";
package/build/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  export { AgentRunBus } from "./AgentRunBus.js";
2
+ export { BASTION_TOKEN_HEADER } from "./BastionAuth.js";
2
3
  export { buildCalendarEventId, parseCalendarEventId, } from "./Calendar.js";
3
4
  export { ChatMessageBus } from "./ChatMessageBus.js";
4
5
  export { parseCron } from "./CronExpression.js";
5
6
  export { EVENT_PRIORITY } from "./Event.js";
6
7
  export { DuplicateIdempotencyKeyError, EventBus } from "./EventBus.js";
7
8
  export { estimateTokens } from "./estimateTokens.js";
8
- export { HandlerCatalog } from "./HandlerCatalog.js";
9
+ export { HandlerCatalog, isUnderSkillsFolder } from "./HandlerCatalog.js";
9
10
  export { InferenceEventBus } from "./InferenceEventBus.js";
10
11
  export { createLogger, jsonStdoutStream, prettyStdoutStream, } from "./logging/Logger.js";
11
12
  export { buildMailId, parseMailId, } from "./Mail.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@getfamiliar/shared",
3
3
  "type": "module",
4
- "version": "0.1.8",
4
+ "version": "0.1.10",
5
5
  "description": "Familiar — shared types and bus-state client between host and container.",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -22,7 +22,7 @@
22
22
  "build"
23
23
  ],
24
24
  "engines": {
25
- "node": ">=24"
25
+ "node": ">=22"
26
26
  },
27
27
  "scripts": {
28
28
  "build": "tsc",
@@ -51,7 +51,7 @@
51
51
  "devDependencies": {
52
52
  "@biomejs/biome": "^2.4.12",
53
53
  "@types/luxon": "^3.7.1",
54
- "@types/node": "^25.6.0",
54
+ "@types/node": "^22",
55
55
  "@types/pg": "^8.11.10",
56
56
  "typescript": "^6.0.3"
57
57
  },