@piagent/platform 1.2.0 → 1.2.2

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +149 -1
  2. package/README.md +1 -1
  3. package/catalog/capabilities.json +4 -4
  4. package/docs/command-reference-vietnamese.md +15 -4
  5. package/docs/context-window-policy.md +1 -0
  6. package/docs/distribution-standard.md +7 -7
  7. package/docs/mcp-and-tools.md +49 -3
  8. package/docs/operator-manual-vietnamese.md +52 -11
  9. package/docs/publishing-for-teams.md +2 -0
  10. package/docs/quickstart-vietnamese.md +4 -2
  11. package/docs/release-install-policy.md +6 -6
  12. package/docs/security-threat-model.md +4 -3
  13. package/docs/team-onboarding.md +3 -3
  14. package/docs/usage-observability.md +49 -0
  15. package/docs-site/architecture.html +1 -1
  16. package/docs-site/commands.html +1 -1
  17. package/docs-site/content/mcp-approval.html +54 -2
  18. package/docs-site/content/quickstart.html +1 -1
  19. package/docs-site/index.html +1 -1
  20. package/docs-site/mcp-approval.html +55 -3
  21. package/docs-site/mcp-auth.html +1 -1
  22. package/docs-site/mcp-servers.html +1 -1
  23. package/docs-site/mcp.html +1 -1
  24. package/docs-site/permissions.html +1 -1
  25. package/docs-site/profiles.html +1 -1
  26. package/docs-site/quickstart.html +2 -2
  27. package/docs-site/runtime.html +1 -1
  28. package/docs-site/scope.html +1 -1
  29. package/docs-site/security.html +1 -1
  30. package/docs-site/team.html +1 -1
  31. package/docs-site/workflows.html +1 -1
  32. package/package.json +1 -1
  33. package/packages/piagent-core/README.md +2 -0
  34. package/packages/piagent-core/capabilities/capability-core.js +41 -4
  35. package/packages/piagent-core/capabilities/capability-sources.js +73 -12
  36. package/packages/piagent-core/extensions/piagent-guard.ts +539 -70
  37. package/packages/piagent-core/extensions/policy-core.js +1586 -98
  38. package/packages/piagent-core/mcp/mcp-approval-store.js +56 -15
  39. package/packages/piagent-core/mcp/mcp-auth-readiness.js +31 -3
  40. package/packages/piagent-core/mcp/mcp-command-actions.js +139 -30
  41. package/packages/piagent-core/mcp/mcp-config-layers.js +339 -6
  42. package/packages/piagent-core/mcp/mcp-import-kinds.js +240 -0
  43. package/packages/piagent-core/mcp/mcp-server-entry.js +51 -0
  44. package/packages/piagent-core/mcp/mcp-session-view.js +55 -4
  45. package/packages/piagent-core/mcp/mcp-tool-naming.js +90 -0
  46. package/packages/piagent-core/package.json +1 -1
  47. package/packages/piagent-core/prompts/be-to-fe.md +1 -0
  48. package/packages/piagent-core/prompts/piagent-commands.md +1 -0
  49. package/packages/piagent-core/prompts/platform-improve.md +1 -0
  50. package/packages/piagent-core/prompts/review.md +1 -0
  51. package/packages/piagent-core/prompts/scout.md +1 -0
  52. package/packages/piagent-core/prompts/task.md +1 -0
  53. package/scripts/configure-model-scope.sh +19 -3
  54. package/scripts/configure-subagents.sh +17 -4
  55. package/scripts/init-project.sh +15 -8
  56. package/scripts/mcp-manage.mjs +111 -22
  57. package/scripts/pi-model-catalog.sh +11 -1
  58. package/scripts/pi-session-stats.sh +27 -1
  59. package/scripts/pi-usage-history.mjs +567 -0
  60. package/scripts/quality-benchmark.sh +37 -9
  61. package/scripts/setup.sh +21 -13
  62. package/scripts/uninstall-global.sh +10 -4
  63. package/scripts/verify-local.sh +19 -0
  64. package/scripts/verify-release-identity.mjs +29 -0
package/scripts/setup.sh CHANGED
@@ -85,21 +85,24 @@ SKIP_AGENTS=false
85
85
  SKIP_REVIEW=false
86
86
  DRY_RUN=false
87
87
 
88
+ require_value() {
89
+ local option="$1"
90
+ local value="${2:-}"
91
+ if [[ -z "$value" || "$value" == --* ]]; then
92
+ echo "Missing value for $option" >&2
93
+ exit 2
94
+ fi
95
+ }
96
+
88
97
  while [[ $# -gt 0 ]]; do
89
98
  case "$1" in
90
99
  --profile)
91
- if [[ $# -lt 2 ]]; then
92
- echo "Missing value for --profile" >&2
93
- exit 2
94
- fi
100
+ require_value "$1" "${2:-}"
95
101
  PROFILE_INPUT="$2"
96
102
  shift 2
97
103
  ;;
98
104
  --package-source)
99
- if [[ $# -lt 2 ]]; then
100
- echo "Missing value for --package-source" >&2
101
- exit 2
102
- fi
105
+ require_value "$1" "${2:-}"
103
106
  PACKAGE_SOURCE="$2"
104
107
  shift 2
105
108
  ;;
@@ -124,7 +127,8 @@ while [[ $# -gt 0 ]]; do
124
127
  shift
125
128
  ;;
126
129
  --mcp-preset)
127
- MCP_PRESET="${2:-}"
130
+ require_value "$1" "${2:-}"
131
+ MCP_PRESET="$2"
128
132
  MCP_PRESET_EXPLICIT=true
129
133
  shift 2
130
134
  ;;
@@ -137,11 +141,13 @@ while [[ $# -gt 0 ]]; do
137
141
  shift
138
142
  ;;
139
143
  --subagents-preset)
140
- SUBAGENTS_PRESET="${2:-}"
144
+ require_value "$1" "${2:-}"
145
+ SUBAGENTS_PRESET="$2"
141
146
  shift 2
142
147
  ;;
143
148
  --subagents-model-scope)
144
- SUBAGENTS_MODEL_SCOPE="${2:-}"
149
+ require_value "$1" "${2:-}"
150
+ SUBAGENTS_MODEL_SCOPE="$2"
145
151
  shift 2
146
152
  ;;
147
153
  --with-web-access)
@@ -157,11 +163,13 @@ while [[ $# -gt 0 ]]; do
157
163
  shift
158
164
  ;;
159
165
  --model-scope)
160
- MODEL_SCOPE_PRESET="${2:-}"
166
+ require_value "$1" "${2:-}"
167
+ MODEL_SCOPE_PRESET="$2"
161
168
  shift 2
162
169
  ;;
163
170
  --default-model)
164
- DEFAULT_MODEL="${2:-}"
171
+ require_value "$1" "${2:-}"
172
+ DEFAULT_MODEL="$2"
165
173
  shift 2
166
174
  ;;
167
175
  --no-model-scope)
@@ -39,16 +39,22 @@ todos, and project memory. Those are operator data, not platform state.
39
39
  USAGE
40
40
  }
41
41
 
42
+ require_value() {
43
+ local option="$1"
44
+ local value="${2:-}"
45
+ if [[ -z "$value" || "$value" == --* ]]; then
46
+ echo "Missing value for $option" >&2
47
+ exit 2
48
+ fi
49
+ }
50
+
42
51
  while [[ $# -gt 0 ]]; do
43
52
  case "$1" in
44
53
  --apply) APPLY=true; shift ;;
45
54
  --with-addons) WITH_ADDONS=true; shift ;;
46
55
  --with-host) WITH_HOST=true; shift ;;
47
56
  --project)
48
- if [[ $# -lt 2 || -z "${2:-}" ]]; then
49
- echo "Missing value for --project" >&2
50
- exit 2
51
- fi
57
+ require_value "$1" "${2:-}"
52
58
  PROJECT_PATH="$2"
53
59
  shift 2
54
60
  ;;
@@ -164,6 +164,7 @@ required_files=(
164
164
  "$ROOT/scripts/quality-benchmark.sh"
165
165
  "$ROOT/scripts/runtime-policy-smoke.sh"
166
166
  "$ROOT/scripts/pi-session-stats.sh"
167
+ "$ROOT/scripts/pi-usage-history.mjs"
167
168
  "$ROOT/scripts/pi-auto.sh"
168
169
  "$ROOT/scripts/pi-model-catalog.sh"
169
170
  "$ROOT/scripts/configure-model-scope.sh"
@@ -469,6 +470,23 @@ require_documented "piagent-capabilities" "$ROOT/README.md" "$ROOT/docs/capabili
469
470
  require_documented ".pi-subagents/" "$ROOT/.gitignore" "$ROOT/docs/subagents-and-multiagent.md" "$ROOT/docs/distribution-standard.md" "$ROOT/scripts/init-project.sh"
470
471
  test -s "$ROOT/tests/policy-core.test.mjs"
471
472
 
473
+ # Every gate below this line is a grep, and grep skips a file it decides is
474
+ # binary. One control byte written into a string literal — a NUL used as a key
475
+ # separator is the easy way to do it by accident — takes the whole file out of
476
+ # every one of them, and out of the diff a reviewer reads on a pull request. The
477
+ # file still runs, so nothing else notices. Escapes carry the same bytes and keep
478
+ # the file readable.
479
+ non_text_sources="$(
480
+ cd "$ROOT" && git ls-files -z -- '*.js' '*.mjs' '*.ts' '*.json' '*.md' '*.sh' '*.html' '*.css' \
481
+ | LC_ALL=C xargs -0 -I{} sh -c 'grep -qI "" "{}" 2>/dev/null || echo "{}"'
482
+ )"
483
+ if [[ -n "$non_text_sources" ]]; then
484
+ echo "Source files contain control bytes, so grep-based gates and diffs skip them:"
485
+ echo "$non_text_sources" | sed 's/^/ /'
486
+ echo "Write the byte as an escape (\\u0000, \\x03) instead of embedding it."
487
+ exit 1
488
+ fi
489
+
472
490
  public_wording_pattern="$(
473
491
  node --input-type=module <<'NODE'
474
492
  const terms = [
@@ -527,6 +545,7 @@ node --check "$ROOT/packages/piagent-core/capabilities/capability-core.js" >/dev
527
545
  node --check "$ROOT/packages/piagent-core/capabilities/capability-sources.js" >/dev/null
528
546
  node --check "$ROOT/scripts/capability-catalog.mjs" >/dev/null
529
547
  node --check "$ROOT/scripts/piagent-cli.mjs" >/dev/null
548
+ node --check "$ROOT/scripts/pi-usage-history.mjs" >/dev/null
530
549
  node --check "$ROOT/scripts/migrate-project-state.mjs" >/dev/null
531
550
  node --check "$ROOT/scripts/import-agent-instructions.mjs" >/dev/null
532
551
  node --check "$ROOT/scripts/check-runtime-advisories.mjs" >/dev/null
@@ -80,6 +80,35 @@ for (const page of docsPages) {
80
80
  if (!html.includes(`${expectedTag} docs`)) fail(`docs-site/${page} version badge does not identify ${expectedTag}`);
81
81
  }
82
82
 
83
+ // A version written into an install command does not come from the build, so it
84
+ // goes stale silently and keeps telling readers to install the previous release.
85
+ // The badge check above cannot see these: they are sentences, not generated
86
+ // markup.
87
+ //
88
+ // Only the command shapes are matched, not every version-looking string. Prose
89
+ // naming an old release is usually saying something true about history — when a
90
+ // behaviour arrived, which release a mistake shipped in — and rewriting those to
91
+ // the current number would make them false. Files that exist to list past
92
+ // versions are exempt outright.
93
+ const VERSION_HISTORY_FILES = new Set(["CHANGELOG.md", "docs/publishing-for-teams.md"]);
94
+ const RELEASE_TAG_MENTION = /(?:@piagent\/platform@|Vt-mmm\/piagent@v?|--version )(\d+\.\d+\.\d+)/g;
95
+
96
+ function proseFiles() {
97
+ const files = fs.readdirSync(path.join(root, "docs")).filter((name) => name.endsWith(".md")).map((name) => `docs/${name}`);
98
+ files.push("README.md");
99
+ for (const name of fs.readdirSync(path.join(root, "docs-site", "content"))) {
100
+ if (name.endsWith(".html")) files.push(`docs-site/content/${name}`);
101
+ }
102
+ return files.filter((file) => !VERSION_HISTORY_FILES.has(file));
103
+ }
104
+
105
+ for (const file of proseFiles()) {
106
+ const text = fs.readFileSync(path.join(root, file), "utf8");
107
+ for (const [mention, named] of text.matchAll(RELEASE_TAG_MENTION)) {
108
+ if (named !== version) fail(`${file} tells the reader to install ${named} (${mention.trim()}), but this release is ${version}`);
109
+ }
110
+ }
111
+
83
112
  if (options.tag) {
84
113
  if (options.tag !== expectedTag) fail(`release tag ${options.tag} does not match package version ${expectedTag}`);
85
114
  if (!/^[0-9a-fA-F]{40}$/.test(options.commit)) fail("--commit must be a 40-character commit SHA");