skillwiki 0.8.1-beta.4 → 0.8.1-beta.6

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
@@ -4103,6 +4103,37 @@ function writeTest(dir) {
4103
4103
  }
4104
4104
  return { success: true, writeMs, readMs: Date.now() - readStart, size: Buffer.byteLength(payload, "utf8") };
4105
4105
  }
4106
+ var DURATION_UNIT_SECONDS = {
4107
+ ms: 1 / 1e3,
4108
+ s: 1,
4109
+ m: 60,
4110
+ h: 3600,
4111
+ d: 86400,
4112
+ w: 604800
4113
+ };
4114
+ function parseDurationSeconds(raw) {
4115
+ const input = raw.trim().toLowerCase();
4116
+ if (!input) return null;
4117
+ if (/^\d+(?:\.\d+)?$/.test(input)) {
4118
+ const num = parseFloat(input);
4119
+ return Number.isFinite(num) ? num : null;
4120
+ }
4121
+ const re = /(\d+(?:\.\d+)?)(ms|s|m|h|d|w)/g;
4122
+ let total = 0;
4123
+ let consumed = 0;
4124
+ for (const match of input.matchAll(re)) {
4125
+ const full = match[0];
4126
+ const value = parseFloat(match[1]);
4127
+ const unit = match[2];
4128
+ if (!Number.isFinite(value)) return null;
4129
+ const factor = DURATION_UNIT_SECONDS[unit];
4130
+ if (factor === void 0) return null;
4131
+ total += value * factor;
4132
+ consumed += full.length;
4133
+ }
4134
+ if (consumed !== input.length) return null;
4135
+ return total;
4136
+ }
4106
4137
  var FLAG_THRESHOLDS = {
4107
4138
  "--vfs-write-back": { min: 15, unit: "s", label: "VFS write-back window" },
4108
4139
  "--vfs-write-wait": { min: 10, unit: "s", label: "VFS write-wait" },
@@ -4495,6 +4526,73 @@ function checkS3MountPerf(resolvedPath) {
4495
4526
  `S3 FUSE mount, cache warm (rg scan: ${elapsed.toFixed(3)}s)`
4496
4527
  );
4497
4528
  }
4529
+ var MAX_DIR_CACHE_TIME_SECONDS = 15 * 60;
4530
+ function formatDurationForHumans(seconds) {
4531
+ if (!Number.isFinite(seconds)) return `${seconds}s`;
4532
+ if (seconds >= 3600) return `${(seconds / 3600).toFixed(1)}h`;
4533
+ if (seconds >= 60) return `${(seconds / 60).toFixed(1)}m`;
4534
+ if (seconds >= 1) return `${seconds.toFixed(1)}s`;
4535
+ return `${Math.round(seconds * 1e3)}ms`;
4536
+ }
4537
+ function checkS3MountFreshness(resolvedPath) {
4538
+ if (!resolvedPath) {
4539
+ return check("pass", "s3_mount_freshness", "S3 visibility freshness", "No vault path \u2014 check skipped");
4540
+ }
4541
+ const fuse = detectFuseMount(resolvedPath);
4542
+ if (!fuse) {
4543
+ return check("pass", "s3_mount_freshness", "S3 visibility freshness", "local disk \u2014 check skipped");
4544
+ }
4545
+ const pid = findRcloneMountPid();
4546
+ if (pid === null) {
4547
+ return check(
4548
+ "warn",
4549
+ "s3_mount_freshness",
4550
+ "S3 visibility freshness",
4551
+ `S3 FUSE mount (${fuse.mountPoint}) but no rclone process found \u2014 cannot audit --dir-cache-time`
4552
+ );
4553
+ }
4554
+ const flags = parseRcloneFlags(pid);
4555
+ if (flags.size === 0) {
4556
+ return check(
4557
+ "warn",
4558
+ "s3_mount_freshness",
4559
+ "S3 visibility freshness",
4560
+ `rclone PID ${pid} found but could not parse flags`
4561
+ );
4562
+ }
4563
+ const raw = flags.get("--dir-cache-time");
4564
+ if (!raw) {
4565
+ return check(
4566
+ "pass",
4567
+ "s3_mount_freshness",
4568
+ "S3 visibility freshness",
4569
+ "PID " + pid + ": --dir-cache-time not set (rclone default 5m, within <=15m SLA)"
4570
+ );
4571
+ }
4572
+ const seconds = parseDurationSeconds(raw);
4573
+ if (seconds === null) {
4574
+ return check(
4575
+ "warn",
4576
+ "s3_mount_freshness",
4577
+ "S3 visibility freshness",
4578
+ `PID ${pid}: could not parse --dir-cache-time=${raw}`
4579
+ );
4580
+ }
4581
+ if (seconds > MAX_DIR_CACHE_TIME_SECONDS) {
4582
+ return check(
4583
+ "warn",
4584
+ "s3_mount_freshness",
4585
+ "S3 visibility freshness",
4586
+ `PID ${pid}: --dir-cache-time=${raw} (${formatDurationForHumans(seconds)}) exceeds 15m SLA \u2014 external S3 changes may remain invisible`
4587
+ );
4588
+ }
4589
+ return check(
4590
+ "pass",
4591
+ "s3_mount_freshness",
4592
+ "S3 visibility freshness",
4593
+ `PID ${pid}: --dir-cache-time=${raw} (${formatDurationForHumans(seconds)}), within <=15m SLA`
4594
+ );
4595
+ }
4498
4596
  function checkRcloneFlagAudit(resolvedPath) {
4499
4597
  if (!resolvedPath) {
4500
4598
  return check("pass", "rclone_flags", "rclone VFS flags", "No vault path \u2014 check skipped");
@@ -4518,11 +4616,8 @@ function checkRcloneFlagAudit(resolvedPath) {
4518
4616
  warnings.push(`${flag} not set (default may be unsafe)`);
4519
4617
  continue;
4520
4618
  }
4521
- const value = parseFloat(raw);
4522
- if (isNaN(value)) continue;
4523
- let inSeconds = value;
4524
- if (raw.endsWith("h")) inSeconds = value * 3600;
4525
- else if (raw.endsWith("m")) inSeconds = value * 60;
4619
+ const inSeconds = parseDurationSeconds(raw);
4620
+ if (inSeconds === null) continue;
4526
4621
  const thresholdSec = threshold.unit === "h" ? threshold.min * 3600 : threshold.unit === "m" ? threshold.min * 60 : threshold.min;
4527
4622
  if (inSeconds < thresholdSec) {
4528
4623
  warnings.push(`${flag}=${raw} (recommended \u2265${threshold.min}${threshold.unit})`);
@@ -5057,6 +5152,7 @@ async function runDoctor(input) {
5057
5152
  checks.push(checkSyncLastPush(resolvedPath));
5058
5153
  checks.push(checkDotStoreClean(resolvedPath));
5059
5154
  checks.push(checkS3MountPerf(resolvedPath));
5155
+ checks.push(checkS3MountFreshness(resolvedPath));
5060
5156
  checks.push(checkRcloneFlagAudit(resolvedPath));
5061
5157
  checks.push(checkRcloneVersion(resolvedPath, vsConfig.installed));
5062
5158
  checks.push(checkWriteTest(resolvedPath));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.8.1-beta.4",
3
+ "version": "0.8.1-beta.6",
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.1-beta.4",
3
+ "version": "0.8.1-beta.6",
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.1-beta.4",
3
+ "version": "0.8.1-beta.6",
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",
@@ -21,7 +21,7 @@ escape_for_json() {
21
21
  }
22
22
 
23
23
  skill_escaped=$(escape_for_json "$skill_content")
24
- session_context="<EXTREMELY_IMPORTANT>\nYou have skillwiki.\n\n**Below is the full content of your 'skillwiki:using-skillwiki' skill - your introduction to the skillwiki skills. For all other skills, use the 'Skill' tool:**\n\n${skill_escaped}\n</EXTREMELY_IMPORTANT>"
24
+ session_context="### Skillwiki Activation\n\nSkillwiki is active for this workspace. Below are the capability guidelines for local reference:\n\n${skill_escaped}"
25
25
 
26
26
  # Uses printf instead of heredoc to work around bash 5.3+ heredoc hang.
27
27
  printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.8.1-beta.4",
3
+ "version": "0.8.1-beta.6",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",
@@ -3,16 +3,15 @@ version: 0.2.2
3
3
  name: using-skillwiki
4
4
  description: Invoke at session start or when knowledge-base tasks arise — maps skillwiki skills, dev-loop alignment, and PRD/TDD routing with plan-mode gate checks
5
5
  ---
6
- <SUBAGENT-STOP>
7
- If you were dispatched as a subagent to execute a specific task, skip this skill.
8
- </SUBAGENT-STOP>
6
+ *Note: If executing as a background subagent, skip this skill section.*
7
+
9
8
  # using-skillwiki
10
9
  You have skillwiki — a project-aware Karpathy-style knowledge base for Claude Code.
11
10
 
12
11
  ## Last Hook Gate (SessionStart)
13
12
 
14
- This skill is injected by the plugin SessionStart hook on `startup|clear|compact`.
15
- Treat this section as the final gate before planning work:
13
+ This skill is activated by the plugin during `startup|clear|compact` lifecycle events.
14
+ Use this section as procedural planning guidelines:
16
15
 
17
16
  1. If the task requires spec/plan work, route through PRD skills (not built-in plan mode).
18
17
  2. If `prd_layer` is `superpowers` or `tdd`, ensure `EnterPlanMode` is gated (`wiki-gate-plan-mode on` or `status` if uncertain).