prizmkit 1.1.156 → 1.1.160

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 (92) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codebuddy/settings-adapter.js +76 -25
  3. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +9 -2
  4. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +1 -1
  5. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +20 -11
  6. package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +42 -15
  7. package/bundled/dev-pipeline/scripts/update-feature-status.py +7 -0
  8. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
  9. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +1 -1
  10. package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +6 -6
  11. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +4 -3
  12. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +2 -2
  13. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -2
  14. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +115 -4
  15. package/bundled/dev-pipeline/tests/test_reset_modes.py +137 -0
  16. package/bundled/dev-pipeline/tests/test_runtime_commit.py +68 -13
  17. package/bundled/dev-pipeline/tests/test_unified_cli.py +12 -7
  18. package/bundled/rules/prizm/prizm-commit-workflow.md +7 -7
  19. package/bundled/rules/prizm/prizm-documentation.md +24 -65
  20. package/bundled/rules/prizm/prizm-progressive-loading.md +9 -8
  21. package/bundled/skills/_metadata.json +1 -1
  22. package/bundled/skills/prizmkit/SKILL.md +1 -13
  23. package/bundled/skills/prizmkit-code-review/SKILL.md +29 -10
  24. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +5 -4
  25. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +15 -0
  26. package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +61 -0
  27. package/bundled/skills/prizmkit-committer/SKILL.md +50 -38
  28. package/bundled/skills/prizmkit-deploy/SKILL.md +172 -198
  29. package/bundled/skills/prizmkit-deploy/references/capability-contract.md +137 -0
  30. package/bundled/skills/prizmkit-deploy/references/deploy-record-schema.json +1053 -0
  31. package/bundled/skills/prizmkit-deploy/references/deployment-declaration-schema.json +291 -0
  32. package/bundled/skills/prizmkit-deploy/references/legacy-migration.md +90 -0
  33. package/bundled/skills/prizmkit-deploy/references/policy-and-execution.md +170 -0
  34. package/bundled/skills/prizmkit-deploy/references/real-resource-test-policy.md +73 -0
  35. package/bundled/skills/prizmkit-deploy/references/verification-and-recovery.md +164 -0
  36. package/bundled/skills/prizmkit-deploy/scripts/validate-deploy-artifact.py +371 -0
  37. package/bundled/skills/prizmkit-implement/SKILL.md +2 -2
  38. package/bundled/skills/prizmkit-init/SKILL.md +38 -42
  39. package/bundled/skills/prizmkit-init/references/config-schema.md +11 -7
  40. package/bundled/skills/prizmkit-init/references/rules/layer-detection.md +3 -3
  41. package/bundled/skills/prizmkit-init/references/update-supplement.md +5 -5
  42. package/bundled/skills/prizmkit-plan/SKILL.md +5 -4
  43. package/bundled/skills/prizmkit-plan/assets/plan-template.md +4 -1
  44. package/bundled/skills/prizmkit-plan/references/verification-checklist.md +3 -2
  45. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +17 -11
  46. package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +95 -155
  47. package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +6 -5
  48. package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +4 -2
  49. package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +9 -10
  50. package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +6 -5
  51. package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -12
  52. package/bundled/skills/prizmkit-retrospective/SKILL.md +3 -3
  53. package/bundled/skills/prizmkit-test/SKILL.md +26 -13
  54. package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +8 -4
  55. package/bundled/skills/prizmkit-test/references/independent-test-review.md +7 -3
  56. package/bundled/skills/prizmkit-test/references/test-coverage-model.md +33 -10
  57. package/bundled/skills/prizmkit-test/references/test-report-template.md +33 -11
  58. package/bundled/skills/prizmkit-workflow/SKILL.md +33 -3
  59. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +23 -5
  60. package/bundled/templates/hooks/commit-intent-status.py +9 -41
  61. package/bundled/templates/hooks/commit-intent.json +3 -3
  62. package/bundled/templates/hooks/diff-prizm-docs.py +3 -1
  63. package/bundled/templates/hooks/prizm-pre-commit.py +32 -6
  64. package/bundled/templates/hooks/run-python-hook.cjs +44 -0
  65. package/bundled/templates/hooks/validate-prizm-docs.py +399 -173
  66. package/bundled/templates/project-memory-template.md +19 -19
  67. package/package.json +1 -1
  68. package/src/clean.js +6 -7
  69. package/src/gitignore-template.js +8 -12
  70. package/src/scaffold.js +125 -71
  71. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +0 -178
  72. package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +0 -89
  73. package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +0 -145
  74. package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +0 -109
  75. package/bundled/skills/prizmkit-deploy/references/data-safety-examples.md +0 -120
  76. package/bundled/skills/prizmkit-deploy/references/database-setup.md +0 -65
  77. package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +0 -150
  78. package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +0 -78
  79. package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +0 -49
  80. package/bundled/skills/prizmkit-deploy/references/deployment-modes.md +0 -50
  81. package/bundled/skills/prizmkit-deploy/references/direct-upload.md +0 -26
  82. package/bundled/skills/prizmkit-deploy/references/dns-setup.md +0 -42
  83. package/bundled/skills/prizmkit-deploy/references/docker-deploy.md +0 -31
  84. package/bundled/skills/prizmkit-deploy/references/firewall-setup.md +0 -37
  85. package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +0 -21
  86. package/bundled/skills/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  87. package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +0 -164
  88. package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +0 -221
  89. package/bundled/skills/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  90. package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  91. package/bundled/skills/prizmkit-deploy/references/ssh-takeover.md +0 -20
  92. package/bundled/skills/prizmkit-deploy/references/ssl-setup.md +0 -56
@@ -4,30 +4,30 @@
4
4
  This project uses PrizmKit with the Prizm documentation system for AI-optimized progressive context loading.
5
5
 
6
6
  ### Progressive Loading Protocol
7
- - ON SESSION START: Always read `.prizmkit/prizm-docs/root.prizm` first (L0 project map)
8
- - ON RESUME (feature/bugfix directory has session-summary.md): Read session-summary.md first for prior context, then load only L1/L2 for modules mentioned in it
9
- - ON TASK: Read L1 (`.prizmkit/prizm-docs/<module>.prizm`) for relevant modules referenced in MODULE_INDEX or MODULE_GROUPS. If entries have keyword tags (e.g., `[login, jwt, oauth]`), match user's task against tags to prioritize which modules to load.
10
- - ON FILE EDIT: Read L2 (`.prizmkit/prizm-docs/<module>/<submodule>.prizm`) before modifying files. Pay attention to TRAPS and DECISIONS.
11
- - NEVER load all .prizm docs at once. Load only what is needed for the current task.
12
-
13
- ### Auto-Update Protocol
14
- - BEFORE EVERY COMMIT: Update affected `.prizmkit/prizm-docs/` files
15
- - Platform hooks (rules or UserPromptSubmit) will remind you automatically
16
- - Use `/prizmkit-committer` for the complete commit workflow
7
+ - ON SESSION START: Read exact `.prizmkit/prizm-docs/root.prizm` first when it exists; it alone is L0.
8
+ - ON TASK: Read only relevant direct-child L1 documents (`.prizmkit/prizm-docs/<module>.prizm`) selected through MODULE_INDEX or MODULE_GROUPS pointers.
9
+ - ON FILE EDIT: Read the complete relevant nested L2 and complete parent/child documents needed to resolve its SUBDIRS or DETAILS pointer. Grep-only fragments are insufficient modification context.
10
+ - IF L2 IS ABSENT: Inspect bounded target source and narrowly implicated contracts without creating a placeholder; documentation creation belongs to Retrospective or explicit repair.
11
+ - NEVER load all `.prizm` docs at once, load unrelated modules, or create L3.
12
+
13
+ ### Framework Directory and Maintenance Protocol
14
+ - `.prizmkit/**` is the PrizmKit framework directory; owning capabilities may read/write their exact managed artifacts.
15
+ - The project alone controls whether framework paths are ignored, untracked, or tracked. Do not add, remove, force-add, stage, commit, or interpret `.gitignore` entries as documentation maintenance.
16
+ - Run `/prizmkit-retrospective` after validated changes when structure, interfaces, dependencies, behavior, or durable knowledge changed; it never owns staging/commit.
17
+ - Use `/prizmkit-committer` for an exact commit operation. A Git-visible `.prizmkit/**` intended path receives ordinary exact-manifest and Secret checks; ignored paths remain absent.
17
18
 
18
19
  ### Doc Format Rules
19
20
  - All `.prizm` files use KEY: value format, not prose
20
- - Size limits: L0 = 4KB, L1 = 4KB, L2 = 5KB
21
+ - Path levels and raw UTF-8 limits: exact `root.prizm` = L0/4096B; other direct `.prizm` children = L1/4096B; nested `.prizm` documents = L2/5120B
21
22
  - Arrow notation (->) indicates load pointers to other .prizm docs
22
23
  - Memory files must not contain CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, or `.prizmkit/specs` / `.prizmkit/dev-pipeline` artifact paths
23
- - Update durable sections in place; git history is the change log
24
- - No date/time fields git is the authoritative source for temporal info
25
-
26
- ### Creating New L2 Docs
27
- - When you first modify files in a sub-module that has no L2 doc:
28
- 1. Read the source files in that sub-module
29
- 2. Generate a new L2 `.prizm` file following Prizm specification
30
- 3. Add a pointer in the parent L1 doc's SUBDIRS section
24
+ - Update durable sections in place; temporal and workflow history stays outside Prizm memory
25
+ - No date/time fields and no Git-history requirement
26
+
27
+ ### Missing L2 Fallback
28
+ - When relevant L2 is absent, inspect only bounded source needed for the current modification.
29
+ - Do not create a placeholder merely because source was read or changed.
30
+ - Retrospective or explicit documentation repair may later write a complete Value-Gate-qualified L2 and resolving parent pointer after identity, ownership, capacity, and format checks pass.
31
31
 
32
32
  ### Available Commands
33
33
  Run `/prizmkit` to see all available PrizmKit commands.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.156",
3
+ "version": "1.1.160",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/clean.js CHANGED
@@ -5,13 +5,12 @@ import { loadMetadata, loadRulesMetadata } from './metadata.js';
5
5
  import { readManifest } from './manifest.js';
6
6
  import { privateProjectMemoryFile, projectMemoryFile } from './platforms.js';
7
7
 
8
+ // Cleanup owns only deterministic private host-memory entries. Existing
9
+ // `.prizmkit/**` ignore policy is project-owned and must remain untouched.
8
10
  const PRIZMKIT_GITIGNORE_HEADERS = new Set([
9
- '# PrizmKit',
10
- '# PrizmKit 运行时全部产物(state/、prizm-docs/、.env、logs 等)',
11
+ '# PrizmKit private host memory',
11
12
  ]);
12
13
  const PRIZMKIT_GITIGNORE_ENTRIES = new Set([
13
- '.prizmkit/',
14
- '.prizmkit/*',
15
14
  'CLAUDE.private.md',
16
15
  'AGENTS.private.md',
17
16
  'CODEBUDDY.private.md',
@@ -298,7 +297,7 @@ export async function runClean(directory, options = {}) {
298
297
  results.push(await cleanMarkedProjectMemory(projectRoot, privateMemoryFile, dryRun));
299
298
  }
300
299
 
301
- // ── .gitignore cleanup ────────────────────────────────────────────────────
300
+ // ── Private host-memory .gitignore cleanup (never `.prizmkit/**`) ─────────
302
301
  const gitignoreResult = await cleanGitignore(projectRoot, dryRun);
303
302
 
304
303
  // ── Global team (optional) ────────────────────────────────────────────────
@@ -326,9 +325,9 @@ export async function runClean(directory, options = {}) {
326
325
 
327
326
  if (gitignoreResult.updated) {
328
327
  if (gitignoreResult.reason === 'dry_run') {
329
- console.log(chalk.gray(' [dry-run] 将更新 .gitignore(移除 PrizmKit 段)'));
328
+ console.log(chalk.gray(' [dry-run] 将更新 .gitignore(仅移除私有主机记忆条目)'));
330
329
  } else {
331
- console.log(chalk.green(' ✓ 已更新 .gitignore(移除 PrizmKit 段)'));
330
+ console.log(chalk.green(' ✓ 已更新 .gitignore(仅移除私有主机记忆条目)'));
332
331
  }
333
332
  }
334
333
 
@@ -1,22 +1,18 @@
1
1
  /**
2
- * .gitignore 模板
3
- * 为新创建的 PrizmKit 项目生成合适的 .gitignore 内容。
2
+ * Generate only explicit private host-memory ignores.
3
+ *
4
+ * `.prizmkit/**` tracking policy is project-controlled: this module never adds,
5
+ * removes, or interprets framework-directory ignore entries.
4
6
  */
5
7
 
6
8
  /**
7
- * 生成 .gitignore 内容
8
- * @param {Object} options - { pipeline: boolean }
9
+ * @param {Object} options - { privateMemoryFiles?: string[] }
9
10
  * @returns {string}
10
11
  */
11
12
  export function generateGitignore(options = {}) {
12
13
  const privateMemoryFiles = Array.isArray(options.privateMemoryFiles)
13
- ? options.privateMemoryFiles.filter(Boolean)
14
+ ? [...new Set(options.privateMemoryFiles.filter(Boolean))]
14
15
  : [];
15
- const lines = [
16
- '# PrizmKit',
17
- '.prizmkit/*',
18
- ...privateMemoryFiles,
19
- ];
20
-
21
- return [...new Set(lines)].join('\n');
16
+ if (privateMemoryFiles.length === 0) return '';
17
+ return ['# PrizmKit private host memory', ...privateMemoryFiles].join('\n');
22
18
  }
package/src/scaffold.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * 全部使用 Copy 模式(不使用 symlink),项目完全独立于框架仓库。
5
5
  * 通过 adapters 转换 core/ 资源为平台特定格式。
6
6
  * 不安装框架开发文件(docs、tests、scripts 等)。
7
- * 自动生成 .gitignore。
7
+ * 仅按显式平台需要合并私有记忆文件 ignore;`.prizmkit/**` Git 策略由项目控制。
8
8
  */
9
9
 
10
10
  import chalk from 'chalk';
@@ -381,6 +381,57 @@ export async function installSkills(platform, skills, projectRoot, dryRun, runti
381
381
  * Skill-owned references now provide inline reviewer/implementation subagent contracts.
382
382
  */
383
383
 
384
+ const MANAGED_HOOK_MARKERS = [
385
+ '.prizmkit/scripts/commit-intent-status.py',
386
+ '.prizmkit/scripts/post-command-prizm-drift.py',
387
+ 'PRIZMKIT_DOC_UPDATE_REQUIRED',
388
+ 'PrizmKit: .prizmkit/prizm-docs found',
389
+ ];
390
+
391
+ function isManagedHookEntry(entry) {
392
+ let serialized = '';
393
+ try {
394
+ serialized = JSON.stringify(entry);
395
+ } catch {
396
+ return false;
397
+ }
398
+ return MANAGED_HOOK_MARKERS.some(marker => serialized.includes(marker));
399
+ }
400
+
401
+ export function mergeManagedHooks(existingHooks = {}, managedHooks = {}) {
402
+ if (!existingHooks || typeof existingHooks !== 'object' || Array.isArray(existingHooks)) {
403
+ throw new Error('Cannot preserve malformed user hooks: hooks must be an object');
404
+ }
405
+ const merged = {};
406
+ for (const [event, entries] of Object.entries(existingHooks)) {
407
+ if (!Array.isArray(entries)) {
408
+ throw new Error(`Cannot preserve malformed user hooks: ${event} must be an array`);
409
+ }
410
+ merged[event] = entries.filter(entry => !isManagedHookEntry(entry));
411
+ }
412
+ for (const [event, entries] of Object.entries(managedHooks || {})) {
413
+ if (!Array.isArray(entries)) {
414
+ throw new Error(`Managed hook template is invalid: ${event} must be an array`);
415
+ }
416
+ const preserved = Array.isArray(merged[event]) ? merged[event] : [];
417
+ merged[event] = [...preserved, ...entries];
418
+ }
419
+ return merged;
420
+ }
421
+
422
+ async function readUserSettings(settingsPath) {
423
+ if (!await fs.pathExists(settingsPath)) return {};
424
+ try {
425
+ const value = await fs.readJSON(settingsPath);
426
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
427
+ throw new Error('settings root must be an object');
428
+ }
429
+ return value;
430
+ } catch (error) {
431
+ throw new Error(`Cannot preserve malformed user settings at ${settingsPath}: ${error.message}`);
432
+ }
433
+ }
434
+
384
435
  /**
385
436
  * 安装平台配置文件(settings/hooks/rules)
386
437
  */
@@ -412,11 +463,16 @@ export async function installSettings(platform, projectRoot, options, dryRun, ru
412
463
 
413
464
  await fs.ensureDir(path.dirname(settingsPath));
414
465
 
415
- // Read hook definition from unified template.
466
+ // Replace only deterministic managed hook entries and preserve user settings/hooks.
416
467
  const templatesDir = getTemplatesDir();
417
468
  const hookTemplate = await fs.readJSON(path.join(templatesDir, 'hooks', 'commit-intent.json'));
469
+ const existingSettings = await readUserSettings(settingsPath);
470
+ const settings = {
471
+ ...existingSettings,
472
+ hooks: mergeManagedHooks(existingSettings.hooks, hookTemplate.hooks),
473
+ };
418
474
 
419
- await fs.writeFile(settingsPath, JSON.stringify(hookTemplate, null, 2));
475
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
420
476
  console.log(chalk.green(` ✓ .codebuddy/settings.json`));
421
477
 
422
478
  // Install rules for CodeBuddy
@@ -466,26 +522,37 @@ export async function installSettings(platform, projectRoot, options, dryRun, ru
466
522
  'Bash(jq *)',
467
523
  ];
468
524
 
525
+ const settingsPath = path.join(claudeDir, 'settings.json');
526
+ const existingSettings = await readUserSettings(settingsPath);
527
+ const existingPermissions = existingSettings.permissions && typeof existingSettings.permissions === 'object'
528
+ ? existingSettings.permissions
529
+ : {};
530
+ const mergedPermissions = [...new Set([
531
+ ...(Array.isArray(existingPermissions.allow) ? existingPermissions.allow : []),
532
+ ...permissions,
533
+ ])];
534
+ const managedHooks = {
535
+ ...hookTemplate.hooks,
536
+ SessionStart: [
537
+ {
538
+ matcher: 'startup',
539
+ hooks: [
540
+ {
541
+ type: 'command',
542
+ command: 'test -f .prizmkit/prizm-docs/root.prizm && echo "PrizmKit: .prizmkit/prizm-docs found. Read exact root.prizm for project context." || echo "PrizmKit: No .prizmkit/prizm-docs found. Run /prizmkit-init to bootstrap."',
543
+ },
544
+ ],
545
+ },
546
+ ],
547
+ };
469
548
  const settings = {
470
- permissions: { allow: permissions },
471
- hooks: {
472
- ...hookTemplate.hooks,
473
- SessionStart: [
474
- {
475
- matcher: 'startup',
476
- hooks: [
477
- {
478
- type: 'command',
479
- command: 'test -f .prizmkit/prizm-docs/root.prizm && echo "PrizmKit: .prizmkit/prizm-docs found. Read root.prizm for project context." || echo "PrizmKit: No .prizmkit/prizm-docs found. Run /prizmkit-init to bootstrap."',
480
- },
481
- ],
482
- },
483
- ],
484
- },
549
+ ...existingSettings,
550
+ permissions: { ...existingPermissions, allow: mergedPermissions },
551
+ hooks: mergeManagedHooks(existingSettings.hooks, managedHooks),
485
552
  };
486
553
 
487
554
  await fs.writeFile(
488
- path.join(claudeDir, 'settings.json'),
555
+ settingsPath,
489
556
  JSON.stringify(settings, null, 2)
490
557
  );
491
558
  console.log(chalk.green(` ✓ .claude/settings.json`));
@@ -553,59 +620,33 @@ function escapeRegExp(value) {
553
620
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
554
621
  }
555
622
 
556
- function ensureTrailingNewline(value) {
557
- return value.endsWith('\n') ? value : `${value}\n`;
558
- }
559
-
560
- function buildStandalonePrizmHook(templateContent) {
561
- const content = templateContent.trimEnd();
562
- const firstNewline = content.indexOf('\n');
563
-
564
- if (content.startsWith('#!') && firstNewline !== -1) {
565
- return [
566
- content.slice(0, firstNewline),
567
- PRIZMKIT_HOOK_MARKER_START,
568
- content.slice(firstNewline + 1),
569
- PRIZMKIT_HOOK_MARKER_END,
570
- '',
571
- ].join('\n');
572
- }
573
-
574
- return [
575
- PRIZMKIT_HOOK_MARKER_START,
576
- content,
577
- PRIZMKIT_HOOK_MARKER_END,
578
- '',
579
- ].join('\n');
580
- }
581
-
582
623
  function buildShellPythonLauncherHook() {
583
624
  return [
584
625
  PRIZMKIT_HOOK_MARKER_START,
585
- '# PrizmKit Python validation launcher',
586
- 'PRIZMKIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || PRIZMKIT_ROOT=""',
587
- 'if [ -n "$PRIZMKIT_ROOT" ] && [ -f "$PRIZMKIT_ROOT/.prizmkit/prizm-docs/root.prizm" ]; then',
588
- ' PRIZMKIT_VALIDATE="$PRIZMKIT_ROOT/.prizmkit/scripts/validate-prizm-docs.py"',
589
- ' [ -f "$PRIZMKIT_VALIDATE" ] || PRIZMKIT_VALIDATE="$PRIZMKIT_ROOT/.prizmkit/dev-pipeline/scripts/validate-prizm-docs.py"',
590
- ' if [ -f "$PRIZMKIT_VALIDATE" ]; then',
591
- ' if command -v python3 >/dev/null 2>&1; then',
592
- ' python3 "$PRIZMKIT_VALIDATE" --staged || exit $?',
593
- ' elif command -v python >/dev/null 2>&1; then',
594
- ' python "$PRIZMKIT_VALIDATE" --staged || exit $?',
595
- ' elif command -v py >/dev/null 2>&1; then',
596
- ' py -3 "$PRIZMKIT_VALIDATE" --staged || exit $?',
597
- ' else',
598
- ' echo "PrizmKit: Python 3 is required for .prizm docs validation." >&2',
599
- ' exit 1',
600
- ' fi',
601
- ' fi',
626
+ '# PrizmKit host-neutral staged documentation validation',
627
+ 'PRIZMKIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0',
628
+ 'PRIZMKIT_RUNNER="$PRIZMKIT_ROOT/.prizmkit/scripts/run-python-hook.cjs"',
629
+ 'PRIZMKIT_PRE_COMMIT="$PRIZMKIT_ROOT/.prizmkit/scripts/prizm-pre-commit.py"',
630
+ 'if [ -f "$PRIZMKIT_RUNNER" ] && [ -f "$PRIZMKIT_PRE_COMMIT" ] && command -v node >/dev/null 2>&1; then',
631
+ ' node "$PRIZMKIT_RUNNER" "$PRIZMKIT_PRE_COMMIT" || exit $?',
632
+ 'elif git diff --cached --quiet -- .prizmkit/prizm-docs; then',
633
+ ' :',
634
+ 'else',
635
+ ' echo "PrizmKit: staged Prizm documents require the installed host-neutral validator launcher." >&2',
636
+ ' exit 1',
602
637
  'fi',
603
638
  PRIZMKIT_HOOK_MARKER_END,
604
639
  '',
605
640
  ].join('\n');
606
641
  }
607
642
 
643
+ function buildStandalonePrizmHook(templateContent) {
644
+ void templateContent;
645
+ return `#!/bin/sh\n${buildShellPythonLauncherHook()}`;
646
+ }
647
+
608
648
  function buildAppendedPrizmHook(templateContent, userHookContent) {
649
+ void templateContent;
609
650
  if (/^#!.*\bpython[0-9.]*\b/i.test(userHookContent)) {
610
651
  return [
611
652
  PRIZMKIT_HOOK_MARKER_START,
@@ -613,13 +654,15 @@ function buildAppendedPrizmHook(templateContent, userHookContent) {
613
654
  'prizmkit_root_result = subprocess.run(["git", "rev-parse", "--show-toplevel"], text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False)',
614
655
  'if prizmkit_root_result.returncode == 0:',
615
656
  ' prizmkit_root = pathlib.Path(prizmkit_root_result.stdout.strip())',
616
- ' prizmkit_validate = prizmkit_root / ".prizmkit/scripts/validate-prizm-docs.py"',
617
- ' if not prizmkit_validate.is_file():',
618
- ' prizmkit_validate = prizmkit_root / ".prizmkit/dev-pipeline/scripts/validate-prizm-docs.py"',
619
- ' if prizmkit_validate.is_file():',
620
- ' prizmkit_result = subprocess.run([sys.executable, str(prizmkit_validate), "--staged"], cwd=prizmkit_root, check=False)',
657
+ ' prizmkit_pre_commit = prizmkit_root / ".prizmkit/scripts/prizm-pre-commit.py"',
658
+ ' prizmkit_diff = subprocess.run(["git", "diff", "--cached", "--quiet", "--", ".prizmkit/prizm-docs"], cwd=prizmkit_root, check=False)',
659
+ ' if prizmkit_pre_commit.is_file():',
660
+ ' prizmkit_result = subprocess.run([sys.executable, str(prizmkit_pre_commit)], cwd=prizmkit_root, check=False)',
621
661
  ' if prizmkit_result.returncode != 0:',
622
662
  ' raise SystemExit(prizmkit_result.returncode)',
663
+ ' elif prizmkit_diff.returncode != 0:',
664
+ ' print("PrizmKit: staged Prizm documents require the installed validator.", file=sys.stderr)',
665
+ ' raise SystemExit(1)',
623
666
  PRIZMKIT_HOOK_MARKER_END,
624
667
  '',
625
668
  ].join('\n');
@@ -630,7 +673,10 @@ function buildAppendedPrizmHook(templateContent, userHookContent) {
630
673
 
631
674
  function insertPrizmHookIntoUserHook(userHookContent, prizmHookBlock) {
632
675
  const content = userHookContent.trimEnd();
633
- const terminalSuccessExitPattern = /(^|\n)([ \t]*exit[ \t]+0[ \t]*(?:#.*)?)[ \t]*$/;
676
+ const isPython = /^#!.*\bpython[0-9.]*\b/i.test(content);
677
+ const terminalSuccessExitPattern = isPython
678
+ ? /(^|\n)([ \t]*(?:sys\.exit\(0\)|raise[ \t]+SystemExit\(0\)|exit\(0\))[ \t]*(?:#.*)?)[ \t]*$/
679
+ : /(^|\n)([ \t]*exit[ \t]+0[ \t]*(?:#.*)?)[ \t]*$/;
634
680
  const match = content.match(terminalSuccessExitPattern);
635
681
 
636
682
  if (!match) {
@@ -760,9 +806,11 @@ export async function installPrizmkitScripts(projectRoot, dryRun, runtime = 'pyt
760
806
 
761
807
  const scripts = [
762
808
  'validate-prizm-docs.py',
809
+ 'prizm-pre-commit.py',
763
810
  'diff-prizm-docs.py',
764
811
  'commit-intent-status.py',
765
812
  'post-command-prizm-drift.py',
813
+ 'run-python-hook.cjs',
766
814
  ];
767
815
  const legacyManagedScripts = [
768
816
  'validate-prizm-docs.sh',
@@ -1277,8 +1325,13 @@ export async function installGitignore(projectRoot, options = {}, dryRun) {
1277
1325
  privateMemoryFiles: options.privateMemoryFiles || [],
1278
1326
  });
1279
1327
 
1328
+ if (!templateContent) {
1329
+ if (dryRun) console.log(chalk.gray(' [dry-run] .gitignore (no managed private-memory entries)'));
1330
+ return;
1331
+ }
1332
+
1280
1333
  if (dryRun) {
1281
- console.log(chalk.gray(` [dry-run] .gitignore`));
1334
+ console.log(chalk.gray(` [dry-run] .gitignore (private host memory only)`));
1282
1335
  return;
1283
1336
  }
1284
1337
 
@@ -1291,14 +1344,15 @@ export async function installGitignore(projectRoot, options = {}, dryRun) {
1291
1344
 
1292
1345
  if (missing.length > 0) {
1293
1346
  const separator = existing.endsWith('\n') ? '' : '\n';
1294
- const header = existingLines.has('# PrizmKit') ? '' : '# PrizmKit\n';
1347
+ const managedHeader = '# PrizmKit private host memory';
1348
+ const header = existingLines.has(managedHeader) ? '' : `${managedHeader}\n`;
1295
1349
  await fs.appendFile(targetPath, separator + '\n' + header + missing.join('\n') + '\n');
1296
1350
  console.log(chalk.green(` ✓ .gitignore (added ${missing.length} entries)`));
1297
1351
  } else {
1298
1352
  console.log(chalk.green(' ✓ .gitignore (up-to-date)'));
1299
1353
  }
1300
1354
  } else {
1301
- await fs.writeFile(targetPath, templateContent);
1355
+ await fs.writeFile(targetPath, `${templateContent}\n`);
1302
1356
  console.log(chalk.green(' ✓ .gitignore'));
1303
1357
  }
1304
1358
  }
@@ -1,178 +0,0 @@
1
- # PrizmKit Workflow State Protocol
2
-
3
- `workflow-state.json` is lifecycle metadata for one formal requirement. It preserves stage handoff, orchestrator ownership, and resume information without replacing skill-owned artifacts or any host-owned execution checkpoint.
4
-
5
- ## Location and Identity
6
-
7
- The state filename uses the validated exact basename of `artifact_dir` without a second slug transformation:
8
-
9
- ```text
10
- .prizmkit/state/workflows/<requirement-identity>.json
11
- ```
12
-
13
- An existing state path whose recorded `artifact_dir` differs from the active artifact is a blocking collision; never overwrite, merge, or suffix it automatically. The active `artifact_dir` is preserved exactly across every stage:
14
-
15
- ```text
16
- .prizmkit/specs/<requirement-slug>/
17
- .prizmkit/bugfix/<bug-id>/
18
- .prizmkit/refactor/<refactor-id>/
19
- ```
20
-
21
- Never select another recent plan when resuming. Any external execution checkpoint remains separate from this state. Never merge, substitute, or infer one schema from the other.
22
-
23
- ## Authority
24
-
25
- The state file is an index, not the authority for stage completion:
26
-
27
- | Information | Authority |
28
- |---|---|
29
- | Requirement goals and acceptance criteria | `{artifact_dir}/spec.md` |
30
- | Implementation tasks and completion | `{artifact_dir}/plan.md` plus current workspace |
31
- | Review findings and result | `{artifact_dir}/review-report.md` |
32
- | Test semantics and native execution | `{artifact_dir}/test-report.md` |
33
- | Terminal testing result | `{artifact_dir}/test-result.json` |
34
- | Retrospective completion | `{artifact_dir}/retrospective-result.json` |
35
- | Durable architecture knowledge | `.prizmkit/prizm-docs/` |
36
- | Local commit | Git history and runtime- or user-verified commit identity |
37
- | Current stage, orchestrator, and resume entry | Workflow state |
38
- | External orchestration progress | External host checkpoint |
39
-
40
- Every consumer compares workflow state with the skill-owned artifacts and current workspace. Missing or stale state is reconstructed from those sources and is never accepted as success by itself.
41
-
42
- ## Schema
43
-
44
- ```json
45
- {
46
- "schema_version": 1,
47
- "artifact_dir": ".prizmkit/specs/example",
48
- "orchestrator": "prizmkit-workflow",
49
- "stage": "test",
50
- "status": "completed",
51
- "stage_result": "TEST_PASS",
52
- "completed_stages": ["plan", "implement", "code-review", "test"],
53
- "repair_scope": null,
54
- "repair_round": 0,
55
- "next_stage": "retrospective",
56
- "resume_from": "prizmkit-retrospective"
57
- }
58
- ```
59
-
60
- ### Fields
61
-
62
- | Field | Meaning |
63
- |---|---|
64
- | `schema_version` | State schema version. |
65
- | `artifact_dir` | Generic requirement artifact root reused by every stage. |
66
- | `orchestrator` | Semantic coordinator identifier, or null for direct stage use. |
67
- | `stage` | Stage that most recently wrote state. |
68
- | `status` | Lifecycle status: `pending`, `in_progress`, `completed`, `failed`, or `skipped`. |
69
- | `stage_result` | Coordinator-recorded lifecycle result mapped from a validated atomic result and its required artifacts, such as `PLAN_READY`, `IMPLEMENTED`, `REVIEW_PASS`, `REVIEW_NEEDS_FIXES`, `TEST_*`, `RETRO_COMPLETE`, or `COMMITTED`. |
70
- | `completed_stages` | Ordered stages completed for this requirement. |
71
- | `repair_scope` | Optional caller-owned routing scope. The test skill reports high-risk repairs through `test-result.json` instead of scheduling another stage. |
72
- | `repair_round` | Optional outer cross-stage repair round, from 0 through 3. It is not a test-internal repair counter. |
73
- | `next_stage` | Next semantic stage, or null when stopped. |
74
- | `resume_from` | Exact atomic skill that can resume, or null when none is selected. |
75
-
76
- `status` and `stage_result` are deliberately separate. Lifecycle status values must never be replaced with domain result values.
77
-
78
- ## Lifecycle and Result Mappings
79
-
80
- ```text
81
- PLAN_READY
82
- → IMPLEMENTED
83
- → REVIEW_PASS
84
- → TEST_PASS
85
- → RETRO_COMPLETE
86
- → COMMIT_PENDING
87
- → COMMITTED
88
- ```
89
-
90
- No formal stage is silently optional. Domain artifacts map to workflow state as follows:
91
-
92
- ```text
93
- plan PLAN_READY → status=completed, stage_result=PLAN_READY
94
- plan PLAN_BLOCKED → status=failed, stage_result=PLAN_BLOCKED
95
- implementation IMPLEMENTED → status=completed, stage_result=IMPLEMENTED
96
- implementation repair/block → status=failed, stage_result=IMPLEMENT_REPAIR or IMPLEMENT_BLOCKED
97
- review-report PASS → status=completed, stage_result=REVIEW_PASS
98
- review-report NEEDS_FIXES → status=failed, stage_result=REVIEW_NEEDS_FIXES
99
- test-result TEST_PASS → status=completed, stage_result=TEST_PASS
100
- test-result TEST_NEEDS_FIXES → status=failed, stage_result=TEST_NEEDS_FIXES
101
- test-result TEST_BLOCKED → status=failed, stage_result=TEST_BLOCKED
102
- retrospective outcome=RETRO_COMPLETE, result=DOCS_UPDATED → status=completed, stage_result=RETRO_COMPLETE
103
- retrospective outcome=RETRO_COMPLETE, result=NO_DOC_CHANGE → status=completed, stage_result=RETRO_COMPLETE
104
- retrospective outcome=RETRO_BLOCKED → status=failed, stage_result=RETRO_BLOCKED
105
- runtime commit preparation → status=in_progress, stage_result=COMMIT_PENDING
106
- local commit confirmed → status=completed, stage_result=COMMITTED
107
- commit blocked → status=failed, stage_result=COMMIT_BLOCKED
108
- ```
109
-
110
- `DOCS_UPDATED` and `NO_DOC_CHANGE` remain retrospective artifact `result` values. The workflow `stage_result` is the retrospective stage result `RETRO_COMPLETE`.
111
-
112
- `TEST_PASS` requires both `test-report.md` and a consistent `test-result.json`. No manifest, attestation, evidence package, or test-internal checkpoint is part of this contract.
113
-
114
- ## Non-Pass Results and Routing Boundary
115
-
116
- `prizmkit-test` performs its own bounded failure repair and review loops before returning. The test skill never invokes another lifecycle stage.
117
-
118
- ```text
119
- TEST_NEEDS_FIXES
120
- → a known correction remains
121
- → caller decides whether and how to arrange another invocation
122
-
123
- TEST_BLOCKED
124
- → truth, input, safe environment, or reliable execution prevents a verdict
125
- → never make speculative production edits
126
- → caller or external host owns recovery policy
127
- ```
128
-
129
- A test result is not an AI CLI session classification. `TEST_NEEDS_FIXES` and `TEST_BLOCKED` must not be rewritten as crash or infrastructure failure merely because they stop lifecycle progression.
130
-
131
- Any outer repair or continuation policy is independently owned by the caller and cannot alter the test report. The Main-Agent test review limit of ten rounds, independent Test Reviewer limit of five responses, and execution-failure repair limit of three rounds are internal to one test invocation and do not update outer counters.
132
-
133
- ## Orchestrator Ownership and Handoff
134
-
135
- 1. An atomic stage performs only its own stage, writes its truthful result and artifact paths, and returns control.
136
- 2. When `orchestrator` is non-null, only that orchestrator invokes the next skill.
137
- 3. Direct atomic use returns only its local result and artifacts; it does not report or select another invocation.
138
- 4. Every handoff preserves the same `artifact_dir`.
139
- 5. External automation invokes atomic stages directly and does not nest the composite workflow.
140
- 6. Workflow state never replaces or absorbs an external host checkpoint.
141
-
142
- ## Commit Execution Ownership
143
-
144
- Interactive execution:
145
-
146
- ```text
147
- committer previews intended files and message
148
- → waits for explicit current-user confirmation
149
- → stages, creates, and verifies the local commit
150
- ```
151
-
152
- Pipeline execution:
153
-
154
- ```text
155
- external coordinator validates its required gates and supplies exact readiness evidence
156
- → committer validates only that evidence and writes an exact runtime-commit-request.json
157
- → external coordinator maps COMMIT_REQUEST_READY to its checkpoint's in_progress/COMMIT_PENDING state
158
- → Python runtime validates the request, commits, verifies Git, and writes checkpoint completed/COMMITTED
159
- → remote publication remains separate
160
- ```
161
-
162
- The preparation request is data for runtime validation, not prompt-level authorization. The committer must not stage, commit, or predeclare COMMITTED in pipeline preparation mode.
163
-
164
- ## Recovery
165
-
166
- When state is missing, stale, or inconsistent:
167
-
168
- 1. Reuse current context, then read `spec.md` and `plan.md` only when needed.
169
- 2. Inspect task markers and current workspace.
170
- 3. Read the current review report when needed to establish review authority.
171
- 4. Validate that `test-report.md` and terminal `test-result.json` exist, agree, and reflect the claimed result.
172
- 5. Validate `retrospective-result.json` when retrospective is claimed complete.
173
- 6. Verify the commit when commit is claimed complete.
174
- 7. Let an active external host validate its own checkpoint independently.
175
- 8. Reconstruct the latest safe predecessor and report the reconstruction.
176
- 9. Continue only from the first incomplete or invalid stage.
177
-
178
- Stale state never bypasses review, testing, retrospective, commit preparation/execution, or external checkpoint enforcement.