@cryptolibertus/pi-peer 0.3.5 → 0.3.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/README.md CHANGED
@@ -19,6 +19,7 @@ pi install ./packages/pi-peer
19
19
  - Idle watcher daemon: idle peers nudge stuck inbound activations and proactively inspect open goal-board work
20
20
  - Protocol compatibility metadata (`protocolVersion`, min/max compatible versions), peer manifests, capabilities, and trust summaries in descriptors/status/list output
21
21
  - `PI_PEER_ID` runtime override for running multiple local Pi sessions
22
+ - `pi-peer-publish` skill for safe npm release checks, version bumping, tag push, publish, and verification
22
23
 
23
24
  ## Setup and health checks
24
25
 
@@ -30,7 +31,7 @@ pi install ./packages/pi-peer
30
31
  /peer cancel <message-id> "superseded"
31
32
  ```
32
33
 
33
- `/peer setup` is a guided alias for `/peer init`: it creates `.pi/peers.json` only when the file is missing, seeds protocol/capability/trust manifest metadata, and never overwrites an existing config. `/peer doctor` is read-only and checks enablement, local identity, advertised endpoint, protocol compatibility, discovered peers, warnings, and resumable disconnected tasks. `/peer reconnect` refreshes local discovery after starting or restarting another Pi session. Discovery is repo/project scoped: sessions under the same `.git` root see each other, while sessions in other repos are ignored. Outside git, the resolved cwd is used as the scope. `/peer resume` re-dispatches a disconnected message restored from `.pi/peer-messages.json`; `/peer cancel` records a local cancellation so stale work is no longer treated as active.
34
+ `/peer setup` is a guided alias for `/peer init`: it creates `.pi/peers.json` only when the file is missing, seeds protocol/capability/trust manifest metadata, and never overwrites an existing config. `/peer doctor` is read-only and checks enablement, local identity, advertised endpoint, protocol compatibility, discovered peers, warnings, and resumable disconnected tasks. `/peer reconnect` refreshes local discovery after starting or restarting another Pi session. Discovery is repo/project scoped: sessions under the same `.git` root see each other, while sessions in other repos are ignored. Outside git, the resolved cwd is used as the scope. `/peer resume` re-dispatches a disconnected message restored from `.pi/peer-messages.json`; `/peer cancel` records a local cancellation so stale work is no longer treated as active. List-style flags such as `--peer`, `--path`, and `--claim` accept comma-separated values or repeated flags.
34
35
 
35
36
  ## Flat goal board
36
37
 
@@ -93,7 +94,9 @@ npm run check
93
94
 
94
95
  ## Publish to npm
95
96
 
96
- Use this release workflow after landing package changes on `main`:
97
+ This package includes a `pi-peer-publish` Pi skill. Ask Pi to use it, or run `/skill:pi-peer-publish`, when you want an agent-guided release with safety checks, version bumping, tag push, publish, and npm verification.
98
+
99
+ Use this manual release workflow after landing package changes on `main`:
97
100
 
98
101
  ```bash
99
102
  # Keep local peer runtime state out of release commits.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptolibertus/pi-peer",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Pi package for local Pi-to-Pi peer messaging, slash commands, tools, and runtime transport.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,6 +13,7 @@
13
13
  ],
14
14
  "files": [
15
15
  "extensions",
16
+ "skills",
16
17
  "src",
17
18
  "README.md",
18
19
  "LICENSE"
@@ -32,6 +33,9 @@
32
33
  "pi": {
33
34
  "extensions": [
34
35
  "extensions/pi-peer/index.ts"
36
+ ],
37
+ "skills": [
38
+ "skills"
35
39
  ]
36
40
  },
37
41
  "engines": {
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: pi-peer-publish
3
+ description: Publish @cryptolibertus/pi-peer to npm safely. Use when the user asks to publish, release, npm publish, bump the package version, or verify/package/push an npm release for this pi-peer package.
4
+ ---
5
+
6
+ # Pi peer publish
7
+
8
+ This skill publishes `@cryptolibertus/pi-peer` from the repository root.
9
+
10
+ ## Safety rules
11
+
12
+ - Never publish with uncommitted source changes unless the user explicitly asks to include them and they have been committed first.
13
+ - Never commit `.pi/`, local peer runtime state, npm debug logs, or generated tarballs.
14
+ - Stop before `npm publish` unless the user has explicitly asked to publish now in the current conversation. If they only asked to prepare a release, stop after the dry run and show the exact publish command.
15
+ - If `npm whoami` fails, stop and ask the user to authenticate with `npm login` or configure an automation token outside the chat.
16
+ - For scoped packages, always publish with `--access public` unless `package.json` says otherwise.
17
+
18
+ ## Workflow
19
+
20
+ 1. Inspect release state:
21
+ ```bash
22
+ git status --short --branch
23
+ git remote get-url origin
24
+ git branch --show-current
25
+ npm whoami
26
+ npm view @cryptolibertus/pi-peer version --json
27
+ node -p "require('./package.json').version"
28
+ ```
29
+
30
+ 2. Ensure local peer state will not be committed:
31
+ ```bash
32
+ grep -qxF '.pi/' .git/info/exclude 2>/dev/null || echo '.pi/' >> .git/info/exclude
33
+ ```
34
+
35
+ 3. Verify package quality and tarball contents:
36
+ ```bash
37
+ npm run check
38
+ npm pack --dry-run
39
+ ```
40
+
41
+ 4. Choose the version bump:
42
+ - Default to `patch` for small fixes and docs.
43
+ - Use `minor` only for new user-facing capabilities.
44
+ - Use `major` only for breaking changes, and ask the user first.
45
+
46
+ 5. Bump, commit, and tag using npm so `package.json`, `package-lock.json` if present, and the git tag stay consistent:
47
+ ```bash
48
+ npm version patch
49
+ ```
50
+
51
+ 6. Push the release commit and tag:
52
+ ```bash
53
+ git push origin HEAD --follow-tags
54
+ ```
55
+
56
+ 7. Publish:
57
+ ```bash
58
+ npm publish --access public
59
+ ```
60
+
61
+ 8. Verify the published package:
62
+ ```bash
63
+ npm view @cryptolibertus/pi-peer version
64
+ npm view @cryptolibertus/pi-peer dist-tags --json
65
+ ```
66
+
67
+ ## Failure handling
68
+
69
+ - If `npm version` fails because the working tree is dirty, inspect `git status --short`; commit intended changes or revert accidental/generated files before retrying.
70
+ - If the tag already exists locally or remotely, compare the package version with `npm view`. Do not force-push tags. Pick the next valid version instead.
71
+ - If `npm publish` says the version already exists, do not retry the same version. Verify with `npm view`, then bump to the next patch version if the user still wants to publish.
72
+ - If tests fail, stop and fix the failure before bumping or publishing.
73
+
74
+ ## Final response
75
+
76
+ Report:
77
+
78
+ - Package name and version published
79
+ - Commit hash and tag pushed
80
+ - Verification commands with exit status
81
+ - npm package URL
82
+ - Any skipped step or blocker
@@ -251,11 +251,13 @@ function parsePeerGoalCommand(parsed, flags, positionals) {
251
251
  }
252
252
 
253
253
  function stringFlag(value, fallback) {
254
+ if (Array.isArray(value)) return stringFlag(value.at(-1), fallback);
254
255
  if (typeof value === "string" && value.trim()) return value.trim();
255
256
  return fallback;
256
257
  }
257
258
 
258
259
  function positiveIntegerFlag(value) {
260
+ if (Array.isArray(value)) return positiveIntegerFlag(value.at(-1));
259
261
  if (value === undefined || value === true) return undefined;
260
262
  const number = Number(value);
261
263
  return Number.isInteger(number) && number > 0 ? number : undefined;
@@ -288,7 +290,9 @@ function capabilitiesFromFlags(flags = {}) {
288
290
  }
289
291
 
290
292
  function listFlag(value) {
291
- if (Array.isArray(value)) return [...new Set(value.map((item) => String(item).trim()).filter(Boolean))];
292
- if (typeof value !== "string" || !value.trim()) return [];
293
- return [...new Set(value.split(",").map((item) => item.trim()).filter(Boolean))];
293
+ const values = Array.isArray(value) ? value : [value];
294
+ return [...new Set(values.flatMap((item) => {
295
+ if (typeof item !== "string") return [];
296
+ return item.split(",").map((part) => part.trim()).filter(Boolean);
297
+ }))];
294
298
  }
package/src/utils.mjs CHANGED
@@ -58,21 +58,22 @@ export function parseFlags(args) {
58
58
  const [rawKey, rawValue] = arg.slice(2).split(/=(.*)/s, 2);
59
59
  const key = rawKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
60
60
  if (rawValue !== undefined) {
61
- flags[key] = rawValue;
61
+ appendFlagValue(flags, key, rawValue);
62
62
  continue;
63
63
  }
64
64
  const next = args[i + 1];
65
65
  if (next !== undefined && !next.startsWith("--")) {
66
- flags[key] = next;
66
+ appendFlagValue(flags, key, next);
67
67
  i += 1;
68
68
  } else {
69
- flags[key] = true;
69
+ appendFlagValue(flags, key, true);
70
70
  }
71
71
  }
72
72
  return { flags, positionals };
73
73
  }
74
74
 
75
75
  export function flagEnabled(value) {
76
+ if (Array.isArray(value)) return flagEnabled(value.at(-1));
76
77
  if (value === true) return true;
77
78
  if (typeof value === "number") return Number.isFinite(value) && value !== 0;
78
79
  if (typeof value === "string") {
@@ -81,3 +82,11 @@ export function flagEnabled(value) {
81
82
  }
82
83
  return false;
83
84
  }
85
+
86
+ function appendFlagValue(flags, key, value) {
87
+ if (Object.prototype.hasOwnProperty.call(flags, key)) {
88
+ flags[key] = Array.isArray(flags[key]) ? [...flags[key], value] : [flags[key], value];
89
+ } else {
90
+ flags[key] = value;
91
+ }
92
+ }