skillwiki 0.8.10-beta.3 → 0.8.10-beta.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/dist/cli.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-TPS5XD2J.js";
15
15
 
16
16
  // src/cli.ts
17
- import { join as join46 } from "path";
17
+ import { join as join47 } from "path";
18
18
  import { Command as Command2 } from "commander";
19
19
 
20
20
  // ../shared/src/exit-codes.ts
@@ -68,7 +68,8 @@ var ExitCode = {
68
68
  USAGE: 46,
69
69
  BODY_TRUNCATION_GUARD: 47,
70
70
  SYNC_LOCK_HELD: 48,
71
- LOG_APPEND_LOCK_HELD: 49
71
+ LOG_APPEND_LOCK_HELD: 49,
72
+ FLEET_MANIFEST_INVALID: 50
72
73
  };
73
74
 
74
75
  // ../shared/src/json-output.ts
@@ -178,6 +179,57 @@ var MetaSchema = z.object({
178
179
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["provenance_projects"], message: "required when provenance != research" });
179
180
  }
180
181
  });
182
+ var hostId = z.string().regex(/^[a-z0-9][a-z0-9_-]*$/, "must be a lowercase host id");
183
+ var endpointName = z.string().min(1).regex(/^[A-Za-z0-9_.-]+$/, "must be a hostname-like token");
184
+ var ipAddress = z.string().min(1).regex(/^[0-9a-fA-F:.]+$/, "must be an IP address token");
185
+ var sshAlias = z.string().min(1).regex(/^[A-Za-z0-9_.@-]+$/, "must be an SSH alias token");
186
+ var sshUser = z.string().min(1).regex(/^[A-Za-z0-9_.-]+$/, "must be an SSH user token");
187
+ var FleetAccessProfileSchema = z.object({
188
+ status: z.enum(["local", "configured", "planned", "absent", "unknown"]),
189
+ ssh_aliases: z.array(sshAlias).optional(),
190
+ users: z.array(sshUser).optional(),
191
+ transports: z.array(z.enum(["local", "public-ip", "tailscale", "private-lan"])).min(1)
192
+ }).strict();
193
+ var FleetHostIdentitySchema = z.object({
194
+ hostnames: z.array(endpointName).min(1),
195
+ public_addresses: z.array(ipAddress).optional(),
196
+ private_addresses: z.array(ipAddress).optional(),
197
+ tailscale: z.object({
198
+ node_names: z.array(endpointName).optional(),
199
+ magicdns_names: z.array(endpointName).optional(),
200
+ addresses: z.array(ipAddress).optional()
201
+ }).strict().optional()
202
+ }).strict();
203
+ var FleetHostSchema = z.object({
204
+ class: z.enum(["dev-macos", "dev-linux", "prod-linux", "unknown"]),
205
+ role: z.enum(["leaf", "snapshotter"]),
206
+ writes_to: z.array(z.enum(["s3", "github"])).min(1),
207
+ protected: z.boolean().optional(),
208
+ identity: FleetHostIdentitySchema,
209
+ access: z.object({
210
+ from: z.record(hostId, FleetAccessProfileSchema).optional()
211
+ }).strict().optional()
212
+ }).strict();
213
+ var FleetManifestSchema = z.object({
214
+ "$schema": z.string().url().optional(),
215
+ schema_version: z.literal(1),
216
+ vault_remote: z.string().min(1),
217
+ s3_remote: z.string().min(1).optional(),
218
+ hosts: z.record(hostId, FleetHostSchema)
219
+ }).strict().superRefine((v, ctx) => {
220
+ const entries = Object.entries(v.hosts);
221
+ if (entries.length === 0) {
222
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["hosts"], message: "must contain at least one host" });
223
+ }
224
+ const snapshotters = entries.filter(([, host]) => host.role === "snapshotter").map(([id]) => id);
225
+ if (snapshotters.length !== 1) {
226
+ ctx.addIssue({
227
+ code: z.ZodIssueCode.custom,
228
+ path: ["hosts"],
229
+ message: `must contain exactly one snapshotter host, found ${snapshotters.length}`
230
+ });
231
+ }
232
+ });
181
233
  function detectSchema(fm) {
182
234
  const COMPOUND_TYPES = /* @__PURE__ */ new Set(["lesson", "pattern", "antipattern", "gotcha"]);
183
235
  if (typeof fm.type === "string" && COMPOUND_TYPES.has(fm.type) && "project" in fm) return { schema: "compound" };
@@ -793,6 +845,7 @@ import { dirname as dirname2 } from "path";
793
845
  var CONFIG_KEYS = [
794
846
  "WIKI_PATH",
795
847
  "WIKI_LANG",
848
+ "SKILLWIKI_HOST_ID",
796
849
  "AUTO_COMMIT",
797
850
  "BACKUP_ENDPOINT",
798
851
  "BACKUP_BUCKET",
@@ -3075,6 +3128,7 @@ function buildCliSurface() {
3075
3128
  program2.command("observe").requiredOption("--text <text>").option("--kind <kind>").option("--project <slug>").option("--wiki <name>");
3076
3129
  program2.command("session-brief").option("--project <slug>").option("--write").option("--wiki <name>");
3077
3130
  program2.command("ingest").requiredOption("--vault <path>").requiredOption("--type <type>").requiredOption("--title <title>").option("--tags <csv>").option("--provenance <provenance>").option("--dry-run");
3131
+ program2.command("fleet");
3078
3132
  const graphCmd = program2.commands.find((c) => c.name() === "graph");
3079
3133
  graphCmd.command("build").option("--out <path>").option("--wiki <name>");
3080
3134
  const canvasCmd2 = program2.commands.find((c) => c.name() === "canvas");
@@ -3098,6 +3152,9 @@ function buildCliSurface() {
3098
3152
  const backupCmd2 = program2.commands.find((c) => c.name() === "backup");
3099
3153
  backupCmd2.command("sync").option("--dry-run").option("--bucket <name>").option("--endpoint <url>").option("--region <region>").option("--prune").option("--wiki <name>");
3100
3154
  backupCmd2.command("restore").option("--bucket <name>").option("--endpoint <url>").option("--region <region>").option("--target <dir>").option("--wiki <name>");
3155
+ const fleetCmd2 = program2.commands.find((c) => c.name() === "fleet");
3156
+ fleetCmd2.command("validate");
3157
+ fleetCmd2.command("context").option("--file <path>").option("--host-id <id>");
3101
3158
  const surface = /* @__PURE__ */ new Map();
3102
3159
  const rootFlags = new Set(program2.options.map((o) => o.long ?? o.short).filter((f) => f != null));
3103
3160
  function walk2(cmd, prefix, parentFlags) {
@@ -9406,15 +9463,245 @@ async function loadOrBuildGraph(vault) {
9406
9463
  }
9407
9464
  }
9408
9465
 
9466
+ // src/commands/fleet.ts
9467
+ import { readFile as readFile29 } from "fs/promises";
9468
+ import { hostname as nodeHostname, userInfo } from "os";
9469
+ import { join as join45 } from "path";
9470
+ import yaml3 from "js-yaml";
9471
+ var FLEET_REL_PATH = join45("projects", "llm-wiki", "architecture", "fleet.yaml");
9472
+ async function runFleetValidate(input) {
9473
+ const loaded = await loadFleetManifest(input.file);
9474
+ if (!loaded.ok) {
9475
+ if (loaded.error === "FILE_NOT_FOUND") {
9476
+ return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: input.file }) };
9477
+ }
9478
+ const errors = fleetLoadErrors(loaded);
9479
+ return invalidFleet(errors);
9480
+ }
9481
+ const warnings = fleetWarnings(loaded.manifest);
9482
+ const snapshotter = findSnapshotter(loaded.manifest);
9483
+ return {
9484
+ exitCode: ExitCode.OK,
9485
+ result: ok({
9486
+ valid: true,
9487
+ errors: [],
9488
+ warnings,
9489
+ host_count: Object.keys(loaded.manifest.hosts).length,
9490
+ snapshotter,
9491
+ humanHint: `VALID fleet manifest (${Object.keys(loaded.manifest.hosts).length} hosts; snapshotter: ${snapshotter ?? "none"})`
9492
+ })
9493
+ };
9494
+ }
9495
+ async function runFleetContext(input) {
9496
+ const env = input.env ?? process.env;
9497
+ const home = input.home ?? env.HOME ?? "";
9498
+ const cwd = input.cwd ?? process.cwd();
9499
+ const osHostname = input.osHostname ?? safeEnvValue(env.HOSTNAME) ?? nodeHostname();
9500
+ const user = input.user ?? safeEnvValue(env.USER) ?? safeUserName();
9501
+ const vault = input.vault ?? safeEnvValue(env.WIKI_PATH);
9502
+ const file = input.file ?? (vault ? join45(vault, FLEET_REL_PATH) : void 0);
9503
+ const loaded = file ? await loadFleetManifest(file) : { ok: false, error: "FILE_NOT_FOUND" };
9504
+ if (!loaded.ok) {
9505
+ const markdown2 = formatUnknownContext({ osHostname, user, cwd, vault, reason: "fleet manifest unavailable or invalid" });
9506
+ return {
9507
+ exitCode: ExitCode.OK,
9508
+ result: ok({ manifest_loaded: false, markdown: markdown2, humanHint: markdown2 })
9509
+ };
9510
+ }
9511
+ const resolved = await resolveHostId({
9512
+ manifest: loaded.manifest,
9513
+ hostId: input.hostId,
9514
+ env,
9515
+ home,
9516
+ osHostname
9517
+ });
9518
+ if (!resolved.hostId || !loaded.manifest.hosts[resolved.hostId]) {
9519
+ const markdown2 = formatUnknownContext({ osHostname, user, cwd, vault, reason: "host identity is unresolved" });
9520
+ return {
9521
+ exitCode: ExitCode.OK,
9522
+ result: ok({ manifest_loaded: true, markdown: markdown2, humanHint: markdown2 })
9523
+ };
9524
+ }
9525
+ const markdown = formatKnownContext({
9526
+ manifest: loaded.manifest,
9527
+ hostId: resolved.hostId,
9528
+ source: resolved.source,
9529
+ osHostname,
9530
+ user,
9531
+ cwd,
9532
+ vault
9533
+ });
9534
+ return {
9535
+ exitCode: ExitCode.OK,
9536
+ result: ok({
9537
+ manifest_loaded: true,
9538
+ host_id: resolved.hostId,
9539
+ source: resolved.source,
9540
+ markdown,
9541
+ humanHint: markdown
9542
+ })
9543
+ };
9544
+ }
9545
+ async function loadFleetManifest(file) {
9546
+ let text;
9547
+ try {
9548
+ text = await readFile29(file, "utf8");
9549
+ } catch {
9550
+ return { ok: false, error: "FILE_NOT_FOUND" };
9551
+ }
9552
+ let parsed;
9553
+ try {
9554
+ parsed = yaml3.load(text, { schema: yaml3.JSON_SCHEMA });
9555
+ } catch (error) {
9556
+ return { ok: false, error: "INVALID_YAML", detail: error instanceof Error ? error.message : String(error) };
9557
+ }
9558
+ const result = FleetManifestSchema.safeParse(parsed);
9559
+ if (!result.success) {
9560
+ return { ok: false, error: "INVALID_FLEET_MANIFEST", detail: result.error.issues };
9561
+ }
9562
+ return { ok: true, manifest: result.data };
9563
+ }
9564
+ function invalidFleet(errors) {
9565
+ return {
9566
+ exitCode: ExitCode.FLEET_MANIFEST_INVALID,
9567
+ result: ok({
9568
+ valid: false,
9569
+ errors,
9570
+ warnings: [],
9571
+ host_count: 0,
9572
+ humanHint: `INVALID fleet manifest
9573
+ ${errors.map((e) => ` ${e.path || "(root)"}: ${e.message}`).join("\n")}`
9574
+ })
9575
+ };
9576
+ }
9577
+ function fleetLoadErrors(loaded) {
9578
+ if (loaded.error === "INVALID_YAML") {
9579
+ return [{ path: "", message: `invalid YAML: ${String(loaded.detail ?? "parse failed")}` }];
9580
+ }
9581
+ if (loaded.error === "INVALID_FLEET_MANIFEST" && Array.isArray(loaded.detail)) {
9582
+ return loaded.detail.map((issue) => {
9583
+ const zodIssue = issue;
9584
+ return {
9585
+ path: (zodIssue.path ?? []).join("."),
9586
+ message: zodIssue.message ?? "invalid value"
9587
+ };
9588
+ });
9589
+ }
9590
+ return [{ path: "", message: loaded.error }];
9591
+ }
9592
+ function fleetWarnings(manifest) {
9593
+ const warnings = [];
9594
+ for (const [id, host] of Object.entries(manifest.hosts)) {
9595
+ if (host.role === "snapshotter" && host.protected !== true) {
9596
+ warnings.push(`snapshotter host '${id}' is not protected=true`);
9597
+ }
9598
+ }
9599
+ return warnings;
9600
+ }
9601
+ function findSnapshotter(manifest) {
9602
+ return Object.entries(manifest.hosts).find(([, host]) => host.role === "snapshotter")?.[0];
9603
+ }
9604
+ async function resolveHostId(input) {
9605
+ if (input.hostId) return { hostId: input.hostId, source: "host-id" };
9606
+ if (input.env.SKILLWIKI_HOST_ID) return { hostId: input.env.SKILLWIKI_HOST_ID, source: "SKILLWIKI_HOST_ID" };
9607
+ if (input.env.AGENT_HOST_ID) return { hostId: input.env.AGENT_HOST_ID, source: "AGENT_HOST_ID" };
9608
+ if (input.home) {
9609
+ const dotenv = await parseDotenvFile(join45(input.home, ".skillwiki", ".env"));
9610
+ if (dotenv.SKILLWIKI_HOST_ID) {
9611
+ return { hostId: dotenv.SKILLWIKI_HOST_ID, source: "~/.skillwiki/.env:SKILLWIKI_HOST_ID" };
9612
+ }
9613
+ }
9614
+ if (input.env.VS_HOSTNAME) return { hostId: input.env.VS_HOSTNAME, source: "VS_HOSTNAME" };
9615
+ const hostname = input.osHostname.trim();
9616
+ if (hostname) {
9617
+ if (input.manifest.hosts[hostname]) return { hostId: hostname, source: "hostname" };
9618
+ const byHostname = Object.entries(input.manifest.hosts).find(([, host]) => host.identity.hostnames.includes(hostname));
9619
+ if (byHostname) return { hostId: byHostname[0], source: "hostname" };
9620
+ }
9621
+ return {};
9622
+ }
9623
+ function formatKnownContext(input) {
9624
+ const host = input.manifest.hosts[input.hostId];
9625
+ const protectedValue = host.protected === true ? "true" : "false";
9626
+ const writesTo = host.writes_to.join(", ");
9627
+ const selfAliases = collectSelfAliases(input.manifest, input.hostId);
9628
+ const outbound = collectOutboundHosts(input.manifest, input.hostId);
9629
+ const guidance = input.hostId === "macos-dev" ? "use declared SSH aliases for remote work when needed; do not assume undeclared hosts have reciprocal SSH access." : `this session is already on \`${input.hostId}\`; do not SSH to self aliases unless the user explicitly asks. Do not assume outbound SSH to other fleet hosts is configured.`;
9630
+ return [
9631
+ "## Runtime Host Context",
9632
+ "",
9633
+ `- Current machine: \`${input.hostId}\`${input.source ? ` (source: \`${input.source}\`)` : ""}`,
9634
+ `- OS hostname: ${formatMaybe(input.osHostname)}`,
9635
+ `- User: ${formatMaybe(input.user)}`,
9636
+ `- Workspace: ${formatMaybe(input.cwd)}`,
9637
+ `- Vault: ${formatMaybe(input.vault)}`,
9638
+ `- Fleet role: \`${host.role}\`; protected: \`${protectedValue}\`; writes_to: \`${writesTo}\``,
9639
+ `- Self SSH aliases known in fleet: ${formatList(selfAliases)}`,
9640
+ `- Declared outbound SSH from this source: ${outbound.length > 0 ? formatList(outbound) : "none"}`,
9641
+ `- Guidance: ${guidance}`
9642
+ ].join("\n");
9643
+ }
9644
+ function formatUnknownContext(input) {
9645
+ return [
9646
+ "## Runtime Host Context",
9647
+ "",
9648
+ "- Current machine: unknown",
9649
+ `- OS hostname: ${formatMaybe(input.osHostname)}`,
9650
+ `- User: ${formatMaybe(input.user)}`,
9651
+ `- Workspace: ${formatMaybe(input.cwd)}`,
9652
+ `- Vault: ${formatMaybe(input.vault)}`,
9653
+ "- Fleet role: unknown",
9654
+ "- Self SSH aliases known in fleet: unknown",
9655
+ "- Declared outbound SSH from this source: unknown",
9656
+ `- Guidance: ${input.reason}; do not assume local vs remote role. Inspect runtime or ask before SSH/deploy/sync work.`
9657
+ ].join("\n");
9658
+ }
9659
+ function collectSelfAliases(manifest, hostId2) {
9660
+ const aliases = [];
9661
+ const host = manifest.hosts[hostId2];
9662
+ const access = host?.access?.from ?? {};
9663
+ for (const profile of Object.values(access)) {
9664
+ for (const alias of profile.ssh_aliases ?? []) aliases.push(alias);
9665
+ }
9666
+ return [...new Set(aliases)];
9667
+ }
9668
+ function collectOutboundHosts(manifest, sourceHostId) {
9669
+ const hosts = [];
9670
+ for (const [targetId, target] of Object.entries(manifest.hosts)) {
9671
+ if (targetId === sourceHostId) continue;
9672
+ const profile = target.access?.from?.[sourceHostId];
9673
+ if (profile && (profile.status === "configured" || profile.status === "local")) {
9674
+ hosts.push(targetId);
9675
+ }
9676
+ }
9677
+ return hosts.sort();
9678
+ }
9679
+ function formatList(values) {
9680
+ return values.length > 0 ? values.map((v) => `\`${v}\``).join(", ") : "none";
9681
+ }
9682
+ function formatMaybe(value) {
9683
+ return value && value.trim().length > 0 ? `\`${value}\`` : "unknown";
9684
+ }
9685
+ function safeEnvValue(value) {
9686
+ return value && value.trim().length > 0 ? value : void 0;
9687
+ }
9688
+ function safeUserName() {
9689
+ try {
9690
+ return userInfo().username;
9691
+ } catch {
9692
+ return "";
9693
+ }
9694
+ }
9695
+
9409
9696
  // src/utils/auto-commit.ts
9410
9697
  import { existsSync as existsSync19 } from "fs";
9411
- import { join as join45 } from "path";
9698
+ import { join as join46 } from "path";
9412
9699
  async function postCommit(vault, exitCode) {
9413
9700
  if (exitCode !== 0) return;
9414
9701
  const home = process.env.HOME ?? "";
9415
9702
  const dotenv = await parseDotenvFile(configPath(home));
9416
9703
  if (dotenv["AUTO_COMMIT"] === "false") return;
9417
- if (!existsSync19(join45(vault, ".git"))) return;
9704
+ if (!existsSync19(join46(vault, ".git"))) return;
9418
9705
  const lastOps = readLastOp(vault);
9419
9706
  if (lastOps.length === 0) return;
9420
9707
  const porcelain = git(vault, ["status", "--porcelain"]);
@@ -9465,7 +9752,7 @@ program.command("validate <file>").description("validate vault page frontmatter
9465
9752
  emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
9466
9753
  });
9467
9754
  program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path (default: <vault>/.skillwiki/graph.json)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
9468
- const out = opts.out ?? join46(vault, ".skillwiki", "graph.json");
9755
+ const out = opts.out ?? join47(vault, ".skillwiki", "graph.json");
9469
9756
  emit(await runGraphBuild({ vault, out }), vault);
9470
9757
  });
9471
9758
  var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
@@ -9837,6 +10124,22 @@ program.command("ingest <source>").description("ingest a source URL or local fil
9837
10124
  dryRun: !!opts.dryRun
9838
10125
  }), opts.vault);
9839
10126
  });
10127
+ var fleetCmd = program.command("fleet").description("manage fleet topology metadata");
10128
+ fleetCmd.command("validate <file>").description("validate a fleet manifest").action(async (file) => {
10129
+ emit(await runFleetValidate({ file }));
10130
+ });
10131
+ fleetCmd.command("context [vault]").description("render compact Runtime Host Context for SessionStart").option("--file <path>", "fleet manifest path").option("--host-id <id>", "explicit current fleet host id").action(async (vault, opts) => {
10132
+ emit(await runFleetContext({
10133
+ vault,
10134
+ file: opts.file,
10135
+ hostId: opts.hostId,
10136
+ env: process.env,
10137
+ home: process.env.HOME ?? "",
10138
+ cwd: process.cwd(),
10139
+ osHostname: process.env.HOSTNAME,
10140
+ user: process.env.USER
10141
+ }));
10142
+ });
9840
10143
  for (const w of getDeprecatedWarnings(process.env.HOME ?? "")) {
9841
10144
  process.stderr.write(w + "\n");
9842
10145
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.8.10-beta.3",
3
+ "version": "0.8.10-beta.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.8.10-beta.3",
3
+ "version": "0.8.10-beta.4",
4
4
  "skills": "./",
5
5
  "description": "Project-aware Karpathy-style knowledge base for Claude Code: 18 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.8.10-beta.3",
3
+ "version": "0.8.10-beta.4",
4
4
  "description": "Project-aware Karpathy-style knowledge base for Codex with 18 prompt-only skills backed by the deterministic skillwiki CLI.",
5
5
  "author": {
6
6
  "name": "karlorz",
@@ -183,6 +183,43 @@ build_dynamic_session_memory() {
183
183
  return 0
184
184
  }
185
185
 
186
+ build_runtime_host_context() {
187
+ local vault
188
+ vault=$(resolve_vault_path_for_session)
189
+
190
+ if command -v skillwiki >/dev/null 2>&1; then
191
+ local context
192
+ if [[ -n "$vault" && -d "$vault" ]]; then
193
+ context=$(skillwiki --human fleet context "$vault" 2>/dev/null || true)
194
+ else
195
+ context=$(skillwiki --human fleet context 2>/dev/null || true)
196
+ fi
197
+ if [[ "$context" == *"## Runtime Host Context"* ]]; then
198
+ printf '%s' "$context"
199
+ return 0
200
+ fi
201
+ fi
202
+
203
+ local os_hostname
204
+ local current_user
205
+ os_hostname=$(hostname -s 2>/dev/null || hostname 2>/dev/null || printf '')
206
+ current_user=$(id -un 2>/dev/null || printf '%s' "${USER:-}")
207
+
208
+ cat <<EOF
209
+ ## Runtime Host Context
210
+
211
+ - Current machine: unknown
212
+ - OS hostname: \`${os_hostname:-unknown}\`
213
+ - User: \`${current_user:-unknown}\`
214
+ - Workspace: \`${PWD}\`
215
+ - Vault: \`${vault:-unknown}\`
216
+ - Fleet role: unknown
217
+ - Self SSH aliases known in fleet: unknown
218
+ - Declared outbound SSH from this source: unknown
219
+ - Guidance: host identity is unresolved; do not assume local vs remote role. Inspect runtime or ask before SSH/deploy/sync work.
220
+ EOF
221
+ }
222
+
186
223
  escape_for_json() {
187
224
  local s="$1"
188
225
  s="${s//\\/\\\\}"
@@ -219,12 +256,18 @@ build_skillwiki_session_context() {
219
256
  local skill_content="$1"
220
257
  local project_prd_context
221
258
  local dynamic_session_memory
259
+ local runtime_host_context
222
260
  local session_context
223
261
 
224
262
  project_prd_context=$(build_project_prd_context)
225
263
  dynamic_session_memory=$(build_dynamic_session_memory)
264
+ runtime_host_context=$(build_runtime_host_context)
226
265
 
227
266
  session_context=$'### Skillwiki Activation\n\nSkillwiki is active for this workspace. Below are the capability guidelines for local reference:'
267
+ if [[ -n "$runtime_host_context" ]]; then
268
+ session_context+=$'\n\n'
269
+ session_context+="$runtime_host_context"
270
+ fi
228
271
  if [[ -n "$dynamic_session_memory" ]]; then
229
272
  session_context+=$'\n\n'
230
273
  session_context+="$dynamic_session_memory"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.8.10-beta.3",
3
+ "version": "0.8.10-beta.4",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",