kenaz 0.3.2 → 0.3.3
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/core/.agents/skills/typesafe-ai/LICENSE +21 -21
- package/core/.agents/skills/typesafe-ai/SKILL.md +149 -149
- package/core/.claude/commands/Ansuz.md +19 -30
- package/core/.claude/hooks/_ansuz-conversation.js +1 -0
- package/core/.claude/hooks/_ansuz-conversation.test.js +6 -0
- package/core/.claude/hooks/_run-user-prompt.js +0 -4
- package/core/.claude/hooks/_run-user-prompt.test.js +2 -3
- package/core/.claude/hooks/session-init.ps1 +49 -49
- package/core/.claude/settings.json +0 -37
- package/core/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -26
- package/core/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -97
- package/core/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -101
- package/core/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -31
- package/core/.claude/skills/ui-ux-pro-max/data/products.csv +96 -96
- package/core/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -45
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -54
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -54
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -50
- package/core/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -68
- package/core/.claude/skills/ui-ux-pro-max/data/typography.csv +57 -57
- package/core/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
- package/core/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
- package/core/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -31
- package/core/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -253
- package/core/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -1067
- package/core/.claude/skills/ui-ux-pro-max/scripts/search.py +106 -106
- package/core/.collaboration/core/task-api.js +3 -8
- package/core/.formation/tests/hello.txt +2 -2
- package/core/.formation/tools/prompt.js +58 -5
- package/core/.formation/tools/prompt.test.js +29 -0
- package/core/.kenaz/claude-hooks-manifest.json +16 -16
- package/core/.kenaz/knowledge/ladybug_2c51da1e_shadow_file_frame_group.patch +163 -163
- package/core/.kenaz/knowledge/ladybug_30cf85690e_shadow_page_read_during_checkpoint.patch +393 -393
- package/core/.kenaz/knowledge/ladybug_7a17858d3a_node_group_delete_lock.patch +102 -102
- package/core/.kenaz/knowledge/ladybug_926a0ba1_column_checkpoint.patch +412 -412
- package/core/.kenaz/knowledge/ladybug_a346c4c4b6_pk_index_header_pages.patch +144 -144
- package/core/.kenaz/knowledge/ladybug_ba5f38815b_csr_node_group.patch +86 -86
- package/core/.kenaz/muninn_episode_write.ps1 +17 -17
- package/core/.kenaz/specialist/field_report_watermark.json +1 -1
- package/core/.kenaz/specialist/memory_guard_fired.json +1 -1
- package/core/.kenaz/specialist/memory_guard_trigger_cache.json +1 -1
- package/core/.kenaz/specialist/t1777_probe.txt +1 -1
- package/core/.matrix/index.matrix +5 -5
- package/core/.specialist/Ansuz/RULES.md +6 -10
- package/core/.specialist/tools/__tests__/task-2218-boot-session-id.test.js +17 -1
- package/core/.specialist/tools/__tests__/task-2222-session-identity-interleave.test.js +17 -1
- package/core/.specialist/tools/__tests__/task-2254-handoff-archive-contract.test.js +6 -5
- package/core/.specialist/tools/ansuz-boot-fast.js +44 -100
- package/core/.specialist/tools/ansuz-boot-fast.test.js +45 -1
- package/core/KENAZ_CORE_VERSION +1 -1
- package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +355 -355
- package/core/dev/JEV_INTEGRATION_PLAN.md +189 -189
- package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +13 -13
- package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +9 -9
- package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +14 -14
- package/core/dev/design/matrix_v2_EXAMPLE.matrix +67 -67
- package/core/dev/jev-eval/ACTIVE_CORRECTION.md +52 -52
- package/core/dev/jev-eval/CONTEXT_REVIEW.md +31 -31
- package/core/dev/jev-eval/EVALUATION_STATUS.md +39 -39
- package/core/dev/jev-eval/HISTORICAL_CORPUS.md +33 -33
- package/core/dev/jev-eval/README.md +99 -99
- package/core/dev/jev-eval/THALAMUS_RANKING.md +58 -58
- package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +32 -32
- package/core/dev/jev-eval/reports/context-review-2026-09-20.json +48 -48
- package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +52 -52
- package/core/dev/pipeline/SELF_ENHANCEMENT_STATUS.json.bak +47 -47
- package/core/dev/pipeline/tasks/.gitkeep +1 -1
- package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +27 -27
- package/core/dev/plans/ANSUZ_SLIM_PLAN.md +68 -0
- package/core/dev/scripts/init_git.sh +0 -0
- package/core/dev/scripts/init_project.sh +0 -0
- package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +536 -536
- package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +1978 -1978
- package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +140 -140
- package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +173 -173
- package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +168 -168
- package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +126 -126
- package/core/dev/scripts/multi_agent_scheduler.sh +0 -0
- package/core/dev/scripts/run_once.sh +0 -0
- package/core/dev/scripts/setup_mcp.sh +0 -0
- package/core/dev/scripts/setup_rag.sh +0 -0
- package/core/dev/scripts/start_dev_agent.sh +0 -0
- package/core/dev/scripts/start_multi_agent.sh +0 -0
- package/core/dev/scripts/sync_task_queue.sh +0 -0
- package/core/k-cli/dist/alaya/run.js +91 -0
- package/core/k-cli/dist/core/output.js +24 -0
- package/core/k-cli/dist/core/process.js +38 -0
- package/core/k-cli/dist/core/project.js +80 -0
- package/core/k-cli/dist/core/spawn.js +268 -0
- package/core/k-cli/dist/core/types.js +2 -0
- package/core/k-cli/dist/dashboard/update.js +53 -0
- package/core/k-cli/dist/dashboard/version.js +20 -0
- package/core/k-cli/dist/dispatch/run.js +241 -0
- package/core/k-cli/dist/dispatch/status.js +103 -0
- package/core/k-cli/dist/index.js +283 -0
- package/core/k-cli/dist/project/initialize.js +301 -0
- package/core/k-cli/dist/project/install.js +89 -0
- package/core/k-cli/dist/project/status.js +138 -0
- package/core/k-cli/dist/specialist/list.js +100 -0
- package/core/k-cli/dist/specialist/run.js +93 -0
- package/core/k-cli/dist/task/create.js +194 -0
- package/core/k-cli/dist/task/delete.js +98 -0
- package/core/k-cli/dist/task/get.js +55 -0
- package/core/k-cli/dist/task/list.js +58 -0
- package/core/k-cli/dist/task/submit.js +156 -0
- package/core/k-cli/dist/ygg/run.js +51 -0
- package/core/k-cli/node_modules/.bin/yaml +16 -0
- package/core/k-cli/node_modules/.bin/yaml.cmd +17 -0
- package/core/k-cli/node_modules/.bin/yaml.ps1 +28 -0
- package/core/k-cli/node_modules/.package-lock.json +23 -0
- package/core/k-cli/node_modules/yaml/LICENSE +13 -0
- package/core/k-cli/node_modules/yaml/README.md +172 -0
- package/core/k-cli/node_modules/yaml/bin.mjs +11 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/composer.js +217 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +223 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/core/k-cli/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
- package/core/k-cli/node_modules/yaml/browser/dist/doc/Document.js +335 -0
- package/core/k-cli/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
- package/core/k-cli/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
- package/core/k-cli/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
- package/core/k-cli/node_modules/yaml/browser/dist/doc/directives.js +176 -0
- package/core/k-cli/node_modules/yaml/browser/dist/errors.js +57 -0
- package/core/k-cli/node_modules/yaml/browser/dist/index.js +17 -0
- package/core/k-cli/node_modules/yaml/browser/dist/log.js +11 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/Alias.js +114 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
- package/core/k-cli/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/cst.js +98 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/lexer.js +717 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
- package/core/k-cli/node_modules/yaml/browser/dist/parse/parser.js +967 -0
- package/core/k-cli/node_modules/yaml/browser/dist/public-api.js +102 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/tags.js +96 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +64 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
- package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +24 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
- package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
- package/core/k-cli/node_modules/yaml/browser/dist/util.js +11 -0
- package/core/k-cli/node_modules/yaml/browser/dist/visit.js +233 -0
- package/core/k-cli/node_modules/yaml/browser/index.js +5 -0
- package/core/k-cli/node_modules/yaml/browser/package.json +3 -0
- package/core/k-cli/node_modules/yaml/dist/cli.d.ts +8 -0
- package/core/k-cli/node_modules/yaml/dist/cli.mjs +201 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-collection.js +90 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-doc.js +45 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-node.js +112 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
- package/core/k-cli/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
- package/core/k-cli/node_modules/yaml/dist/compose/composer.d.ts +63 -0
- package/core/k-cli/node_modules/yaml/dist/compose/composer.js +222 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-end.js +39 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-scalar.js +225 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
- package/core/k-cli/node_modules/yaml/dist/compose/resolve-props.js +148 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
- package/core/k-cli/node_modules/yaml/dist/doc/Document.d.ts +141 -0
- package/core/k-cli/node_modules/yaml/dist/doc/Document.js +337 -0
- package/core/k-cli/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
- package/core/k-cli/node_modules/yaml/dist/doc/anchors.js +76 -0
- package/core/k-cli/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
- package/core/k-cli/node_modules/yaml/dist/doc/applyReviver.js +57 -0
- package/core/k-cli/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
- package/core/k-cli/node_modules/yaml/dist/doc/createNode.js +90 -0
- package/core/k-cli/node_modules/yaml/dist/doc/directives.d.ts +49 -0
- package/core/k-cli/node_modules/yaml/dist/doc/directives.js +178 -0
- package/core/k-cli/node_modules/yaml/dist/errors.d.ts +21 -0
- package/core/k-cli/node_modules/yaml/dist/errors.js +62 -0
- package/core/k-cli/node_modules/yaml/dist/index.d.ts +25 -0
- package/core/k-cli/node_modules/yaml/dist/index.js +50 -0
- package/core/k-cli/node_modules/yaml/dist/log.d.ts +3 -0
- package/core/k-cli/node_modules/yaml/dist/log.js +19 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Alias.js +116 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Collection.js +151 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Node.js +40 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Pair.js +39 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Scalar.d.ts +43 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/Scalar.js +27 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/identity.js +53 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
- package/core/k-cli/node_modules/yaml/dist/nodes/toJS.js +39 -0
- package/core/k-cli/node_modules/yaml/dist/options.d.ts +350 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst-visit.js +99 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst.d.ts +109 -0
- package/core/k-cli/node_modules/yaml/dist/parse/cst.js +112 -0
- package/core/k-cli/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
- package/core/k-cli/node_modules/yaml/dist/parse/lexer.js +719 -0
- package/core/k-cli/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
- package/core/k-cli/node_modules/yaml/dist/parse/line-counter.js +41 -0
- package/core/k-cli/node_modules/yaml/dist/parse/parser.d.ts +84 -0
- package/core/k-cli/node_modules/yaml/dist/parse/parser.js +972 -0
- package/core/k-cli/node_modules/yaml/dist/public-api.d.ts +44 -0
- package/core/k-cli/node_modules/yaml/dist/public-api.js +107 -0
- package/core/k-cli/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
- package/core/k-cli/node_modules/yaml/dist/schema/Schema.js +39 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/map.js +19 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/null.js +17 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/seq.js +19 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/schema/common/string.js +16 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/bool.js +21 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/float.js +47 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/int.js +42 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
- package/core/k-cli/node_modules/yaml/dist/schema/core/schema.js +25 -0
- package/core/k-cli/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/schema/json/schema.js +64 -0
- package/core/k-cli/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
- package/core/k-cli/node_modules/yaml/dist/schema/tags.d.ts +48 -0
- package/core/k-cli/node_modules/yaml/dist/schema/tags.js +99 -0
- package/core/k-cli/node_modules/yaml/dist/schema/types.d.ts +92 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/merge.js +68 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
- package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringify.js +132 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyNumber.js +26 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
- package/core/k-cli/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
- package/core/k-cli/node_modules/yaml/dist/test-events.d.ts +4 -0
- package/core/k-cli/node_modules/yaml/dist/test-events.js +134 -0
- package/core/k-cli/node_modules/yaml/dist/util.d.ts +16 -0
- package/core/k-cli/node_modules/yaml/dist/util.js +28 -0
- package/core/k-cli/node_modules/yaml/dist/visit.d.ts +102 -0
- package/core/k-cli/node_modules/yaml/dist/visit.js +236 -0
- package/core/k-cli/node_modules/yaml/package.json +97 -0
- package/core/k-cli/node_modules/yaml/util.js +2 -0
- package/core/plugins/kenaz/commands/Ansuz.md +19 -30
- package/core/plugins/kenaz/hooks/hooks.json +1 -5
- package/core/plugins/kenaz/hooks/kenaz-hook.js +0 -4
- package/core/plugins/kenaz/scripts/kenaz.test.js +1 -1
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/charts.csv +26 -26
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/colors.csv +97 -97
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/icons.csv +101 -101
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/landing.csv +31 -31
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/products.csv +96 -96
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/react-performance.csv +45 -45
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -54
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react.csv +54 -54
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -50
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/styles.csv +68 -68
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/typography.csv +57 -57
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/web-interface.csv +31 -31
- package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/core.py +253 -253
- package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/design_system.py +1067 -1067
- package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/search.py +106 -106
- package/lib/cli.js +36 -2
- package/lib/cli.test.js +24 -0
- package/lib/dashboard.js +10 -0
- package/package.json +6 -6
- package/core/.specialist/tools/__tests__/task-1863-boot-lease-reuse.test.js +0 -99
- package/core/.specialist/tools/__tests__/task-1977-banner-cap.test.js +0 -129
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
UI/UX Pro Max Search - BM25 search engine for UI/UX style guides
|
|
5
|
-
Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--max-results 3]
|
|
6
|
-
python search.py "<query>" --design-system [-p "Project Name"]
|
|
7
|
-
python search.py "<query>" --design-system --persist [-p "Project Name"] [--page "dashboard"]
|
|
8
|
-
|
|
9
|
-
Domains: style, prompt, color, chart, landing, product, ux, typography
|
|
10
|
-
Stacks: html-tailwind, react, nextjs
|
|
11
|
-
|
|
12
|
-
Persistence (Master + Overrides pattern):
|
|
13
|
-
--persist Save design system to design-system/MASTER.md
|
|
14
|
-
--page Also create a page-specific override file in design-system/pages/
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import argparse
|
|
18
|
-
from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack
|
|
19
|
-
from design_system import generate_design_system, persist_design_system
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def format_output(result):
|
|
23
|
-
"""Format results for Claude consumption (token-optimized)"""
|
|
24
|
-
if "error" in result:
|
|
25
|
-
return f"Error: {result['error']}"
|
|
26
|
-
|
|
27
|
-
output = []
|
|
28
|
-
if result.get("stack"):
|
|
29
|
-
output.append(f"## UI Pro Max Stack Guidelines")
|
|
30
|
-
output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}")
|
|
31
|
-
else:
|
|
32
|
-
output.append(f"## UI Pro Max Search Results")
|
|
33
|
-
output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}")
|
|
34
|
-
output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
|
|
35
|
-
|
|
36
|
-
for i, row in enumerate(result['results'], 1):
|
|
37
|
-
output.append(f"### Result {i}")
|
|
38
|
-
for key, value in row.items():
|
|
39
|
-
value_str = str(value)
|
|
40
|
-
if len(value_str) > 300:
|
|
41
|
-
value_str = value_str[:300] + "..."
|
|
42
|
-
output.append(f"- **{key}:** {value_str}")
|
|
43
|
-
output.append("")
|
|
44
|
-
|
|
45
|
-
return "\n".join(output)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if __name__ == "__main__":
|
|
49
|
-
parser = argparse.ArgumentParser(description="UI Pro Max Search")
|
|
50
|
-
parser.add_argument("query", help="Search query")
|
|
51
|
-
parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
|
|
52
|
-
parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help="Stack-specific search (html-tailwind, react, nextjs)")
|
|
53
|
-
parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
|
|
54
|
-
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
55
|
-
# Design system generation
|
|
56
|
-
parser.add_argument("--design-system", "-ds", action="store_true", help="Generate complete design system recommendation")
|
|
57
|
-
parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name for design system output")
|
|
58
|
-
parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system")
|
|
59
|
-
# Persistence (Master + Overrides pattern)
|
|
60
|
-
parser.add_argument("--persist", action="store_true", help="Save design system to design-system/MASTER.md (creates hierarchical structure)")
|
|
61
|
-
parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/pages/")
|
|
62
|
-
parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory)")
|
|
63
|
-
|
|
64
|
-
args = parser.parse_args()
|
|
65
|
-
|
|
66
|
-
# Design system takes priority
|
|
67
|
-
if args.design_system:
|
|
68
|
-
result = generate_design_system(
|
|
69
|
-
args.query,
|
|
70
|
-
args.project_name,
|
|
71
|
-
args.format,
|
|
72
|
-
persist=args.persist,
|
|
73
|
-
page=args.page,
|
|
74
|
-
output_dir=args.output_dir
|
|
75
|
-
)
|
|
76
|
-
print(result)
|
|
77
|
-
|
|
78
|
-
# Print persistence confirmation
|
|
79
|
-
if args.persist:
|
|
80
|
-
project_slug = args.project_name.lower().replace(' ', '-') if args.project_name else "default"
|
|
81
|
-
print("\n" + "=" * 60)
|
|
82
|
-
print(f"✅ Design system persisted to design-system/{project_slug}/")
|
|
83
|
-
print(f" 📄 design-system/{project_slug}/MASTER.md (Global Source of Truth)")
|
|
84
|
-
if args.page:
|
|
85
|
-
page_filename = args.page.lower().replace(' ', '-')
|
|
86
|
-
print(f" 📄 design-system/{project_slug}/pages/{page_filename}.md (Page Overrides)")
|
|
87
|
-
print("")
|
|
88
|
-
print(f"📖 Usage: When building a page, check design-system/{project_slug}/pages/[page].md first.")
|
|
89
|
-
print(f" If exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
|
|
90
|
-
print("=" * 60)
|
|
91
|
-
# Stack search
|
|
92
|
-
elif args.stack:
|
|
93
|
-
result = search_stack(args.query, args.stack, args.max_results)
|
|
94
|
-
if args.json:
|
|
95
|
-
import json
|
|
96
|
-
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
97
|
-
else:
|
|
98
|
-
print(format_output(result))
|
|
99
|
-
# Domain search
|
|
100
|
-
else:
|
|
101
|
-
result = search(args.query, args.domain, args.max_results)
|
|
102
|
-
if args.json:
|
|
103
|
-
import json
|
|
104
|
-
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
105
|
-
else:
|
|
106
|
-
print(format_output(result))
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
UI/UX Pro Max Search - BM25 search engine for UI/UX style guides
|
|
5
|
+
Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--max-results 3]
|
|
6
|
+
python search.py "<query>" --design-system [-p "Project Name"]
|
|
7
|
+
python search.py "<query>" --design-system --persist [-p "Project Name"] [--page "dashboard"]
|
|
8
|
+
|
|
9
|
+
Domains: style, prompt, color, chart, landing, product, ux, typography
|
|
10
|
+
Stacks: html-tailwind, react, nextjs
|
|
11
|
+
|
|
12
|
+
Persistence (Master + Overrides pattern):
|
|
13
|
+
--persist Save design system to design-system/MASTER.md
|
|
14
|
+
--page Also create a page-specific override file in design-system/pages/
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack
|
|
19
|
+
from design_system import generate_design_system, persist_design_system
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def format_output(result):
|
|
23
|
+
"""Format results for Claude consumption (token-optimized)"""
|
|
24
|
+
if "error" in result:
|
|
25
|
+
return f"Error: {result['error']}"
|
|
26
|
+
|
|
27
|
+
output = []
|
|
28
|
+
if result.get("stack"):
|
|
29
|
+
output.append(f"## UI Pro Max Stack Guidelines")
|
|
30
|
+
output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}")
|
|
31
|
+
else:
|
|
32
|
+
output.append(f"## UI Pro Max Search Results")
|
|
33
|
+
output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}")
|
|
34
|
+
output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
|
|
35
|
+
|
|
36
|
+
for i, row in enumerate(result['results'], 1):
|
|
37
|
+
output.append(f"### Result {i}")
|
|
38
|
+
for key, value in row.items():
|
|
39
|
+
value_str = str(value)
|
|
40
|
+
if len(value_str) > 300:
|
|
41
|
+
value_str = value_str[:300] + "..."
|
|
42
|
+
output.append(f"- **{key}:** {value_str}")
|
|
43
|
+
output.append("")
|
|
44
|
+
|
|
45
|
+
return "\n".join(output)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
parser = argparse.ArgumentParser(description="UI Pro Max Search")
|
|
50
|
+
parser.add_argument("query", help="Search query")
|
|
51
|
+
parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
|
|
52
|
+
parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help="Stack-specific search (html-tailwind, react, nextjs)")
|
|
53
|
+
parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
|
|
54
|
+
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
55
|
+
# Design system generation
|
|
56
|
+
parser.add_argument("--design-system", "-ds", action="store_true", help="Generate complete design system recommendation")
|
|
57
|
+
parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name for design system output")
|
|
58
|
+
parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system")
|
|
59
|
+
# Persistence (Master + Overrides pattern)
|
|
60
|
+
parser.add_argument("--persist", action="store_true", help="Save design system to design-system/MASTER.md (creates hierarchical structure)")
|
|
61
|
+
parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/pages/")
|
|
62
|
+
parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory)")
|
|
63
|
+
|
|
64
|
+
args = parser.parse_args()
|
|
65
|
+
|
|
66
|
+
# Design system takes priority
|
|
67
|
+
if args.design_system:
|
|
68
|
+
result = generate_design_system(
|
|
69
|
+
args.query,
|
|
70
|
+
args.project_name,
|
|
71
|
+
args.format,
|
|
72
|
+
persist=args.persist,
|
|
73
|
+
page=args.page,
|
|
74
|
+
output_dir=args.output_dir
|
|
75
|
+
)
|
|
76
|
+
print(result)
|
|
77
|
+
|
|
78
|
+
# Print persistence confirmation
|
|
79
|
+
if args.persist:
|
|
80
|
+
project_slug = args.project_name.lower().replace(' ', '-') if args.project_name else "default"
|
|
81
|
+
print("\n" + "=" * 60)
|
|
82
|
+
print(f"✅ Design system persisted to design-system/{project_slug}/")
|
|
83
|
+
print(f" 📄 design-system/{project_slug}/MASTER.md (Global Source of Truth)")
|
|
84
|
+
if args.page:
|
|
85
|
+
page_filename = args.page.lower().replace(' ', '-')
|
|
86
|
+
print(f" 📄 design-system/{project_slug}/pages/{page_filename}.md (Page Overrides)")
|
|
87
|
+
print("")
|
|
88
|
+
print(f"📖 Usage: When building a page, check design-system/{project_slug}/pages/[page].md first.")
|
|
89
|
+
print(f" If exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
|
|
90
|
+
print("=" * 60)
|
|
91
|
+
# Stack search
|
|
92
|
+
elif args.stack:
|
|
93
|
+
result = search_stack(args.query, args.stack, args.max_results)
|
|
94
|
+
if args.json:
|
|
95
|
+
import json
|
|
96
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
97
|
+
else:
|
|
98
|
+
print(format_output(result))
|
|
99
|
+
# Domain search
|
|
100
|
+
else:
|
|
101
|
+
result = search(args.query, args.domain, args.max_results)
|
|
102
|
+
if args.json:
|
|
103
|
+
import json
|
|
104
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
105
|
+
else:
|
|
106
|
+
print(format_output(result))
|
package/lib/cli.js
CHANGED
|
@@ -76,6 +76,29 @@ function prepareCodexHome(p, flags) {
|
|
|
76
76
|
|
|
77
77
|
function nodeOk() { return Number(process.versions.node.split('.')[0]) >= MIN_NODE; }
|
|
78
78
|
|
|
79
|
+
const samePath = (a, b) => {
|
|
80
|
+
const n = (x) => path.resolve(String(x || '')).replace(/\\/g, '/');
|
|
81
|
+
return process.platform === 'win32' ? n(a).toLowerCase() === n(b).toLowerCase() : n(a) === n(b);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/** Stop the kenaz-server running from exactly binPath (never by name). Returns the PIDs stopped. */
|
|
85
|
+
function stopOwnServer(binPath, adapter) {
|
|
86
|
+
if (!binPath || !adapter || typeof adapter.procs !== 'function') return [];
|
|
87
|
+
const pids = adapter.procs().filter((pr) => pr.exe && samePath(pr.exe, binPath)).map((pr) => pr.pid);
|
|
88
|
+
for (const pid of pids) { try { (adapter.kill || process.kill)(pid); } catch (_) { /* already gone */ } }
|
|
89
|
+
return pids;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Windows keeps an exe locked for a moment after its process exits: retry the copy briefly. */
|
|
93
|
+
function retryBusy(fn, tries = 10) {
|
|
94
|
+
for (let i = 1; ; i++) {
|
|
95
|
+
try { return fn(); } catch (e) {
|
|
96
|
+
if (i >= tries || !['EBUSY', 'EPERM', 'EPIPE', 'EACCES', 'ETXTBSY'].includes(e.code)) throw e;
|
|
97
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 500);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
79
102
|
function install(p, flags, out, deps = {}) {
|
|
80
103
|
const dry = !!flags['dry-run'];
|
|
81
104
|
const tag = dry ? '[dry-run] ' : '';
|
|
@@ -96,11 +119,22 @@ function install(p, flags, out, deps = {}) {
|
|
|
96
119
|
else { out(`server: no @kenazai/server-${process.platform}-${process.arch} package installed (npm install it, or pass --server-bin)`); rc = 1; }
|
|
97
120
|
}
|
|
98
121
|
if (!dry) {
|
|
122
|
+
if (srv) {
|
|
123
|
+
// Reinstall/upgrade: the kenaz-server this install manages may be running from p.bin. Windows
|
|
124
|
+
// locks a running exe (field report: "EPIPE ... being used by another process" on
|
|
125
|
+
// `npx kenaz@latest install`) and Linux refuses to overwrite one (ETXTBSY). Stop exactly that
|
|
126
|
+
// binary (exe path match, by PID); the service step below starts the new one.
|
|
127
|
+
const stopped = stopOwnServer(binPath, deps.dashboard || dash.realAdapter(p.home));
|
|
128
|
+
if (stopped.length) log(`server: stopped the running kenaz-server (PID ${stopped.join(', ')}) to replace it`);
|
|
129
|
+
}
|
|
99
130
|
fs.rmSync(p.core, { recursive: true, force: true });
|
|
100
131
|
fs.cpSync(srcCore, p.core, { recursive: true });
|
|
101
132
|
if (srv) {
|
|
102
133
|
fs.mkdirSync(p.bin, { recursive: true });
|
|
103
|
-
|
|
134
|
+
// Unix: unlink first. A running binary can be unlinked (its process keeps the old inode) but not
|
|
135
|
+
// overwritten (ETXTBSY), so this works even when the running server was not found above.
|
|
136
|
+
if (process.platform !== 'win32') fs.rmSync(binPath, { force: true });
|
|
137
|
+
retryBusy(() => fs.cpSync(srv.dir, p.bin, { recursive: true }));
|
|
104
138
|
fs.chmodSync(binPath, 0o755);
|
|
105
139
|
}
|
|
106
140
|
fs.writeFileSync(p.meta, JSON.stringify({ version: PKG.version, server: srv ? srv.version : null, serverBin: binPath, installedAt: new Date().toISOString() }, null, 2));
|
|
@@ -248,4 +282,4 @@ function run(argv, out = console.log, deps = {}) {
|
|
|
248
282
|
catch (e) { out('kenaz ' + cmd + ': ERROR ' + e.message); return 1; }
|
|
249
283
|
}
|
|
250
284
|
|
|
251
|
-
module.exports = { run, parseArgs, platformServer, paths };
|
|
285
|
+
module.exports = { run, parseArgs, platformServer, paths, stopOwnServer, retryBusy };
|
package/lib/cli.test.js
CHANGED
|
@@ -57,3 +57,27 @@ test('kenaz ygg / init pass through to the core scripts with the remaining args'
|
|
|
57
57
|
assert.match(calls[1][0].split(path.sep).join('/'), /plugins\/kenaz\/scripts\/kenaz-mode\.js$/);
|
|
58
58
|
assert.deepStrictEqual(calls[1].slice(1), ['init']);
|
|
59
59
|
});
|
|
60
|
+
|
|
61
|
+
test('reinstall stops only the kenaz-server running from the managed path (exact exe match, by PID)', () => {
|
|
62
|
+
const { stopOwnServer } = require('./cli');
|
|
63
|
+
const killed = [];
|
|
64
|
+
const bin = path.join(os.tmpdir(), 'kh', '.kenaz', 'bin', process.platform === 'win32' ? 'kenaz-server.exe' : 'kenaz-server');
|
|
65
|
+
const adapter = {
|
|
66
|
+
procs: () => [
|
|
67
|
+
{ pid: 11, exe: bin },
|
|
68
|
+
{ pid: 12, exe: path.join(os.tmpdir(), 'other', 'kenaz-server.exe') }, // same name, different path: untouched
|
|
69
|
+
{ pid: 13, exe: '' },
|
|
70
|
+
],
|
|
71
|
+
kill: (pid) => killed.push(pid),
|
|
72
|
+
};
|
|
73
|
+
assert.deepStrictEqual(stopOwnServer(bin, adapter), [11]);
|
|
74
|
+
assert.deepStrictEqual(killed, [11]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('retryBusy retries a locked copy and then succeeds; other errors are thrown at once', () => {
|
|
78
|
+
const { retryBusy } = require('./cli');
|
|
79
|
+
let n = 0;
|
|
80
|
+
assert.strictEqual(retryBusy(() => { if (++n < 3) { const e = new Error('busy'); e.code = 'EBUSY'; throw e; } return 'ok'; }, 5), 'ok');
|
|
81
|
+
assert.strictEqual(n, 3);
|
|
82
|
+
assert.throws(() => retryBusy(() => { const e = new Error('nope'); e.code = 'ENOENT'; throw e; }, 5), /nope/);
|
|
83
|
+
});
|
package/lib/dashboard.js
CHANGED
|
@@ -29,6 +29,16 @@ function realAdapter(home) {
|
|
|
29
29
|
if (r.status !== 0) return [];
|
|
30
30
|
try { const v = JSON.parse(r.stdout); return (Array.isArray(v) ? v : [v]).map((x) => ({ pid: x.ProcessId, name: x.Name || '', exe: x.ExecutablePath || '' })); } catch (_) { return []; }
|
|
31
31
|
}
|
|
32
|
+
if (process.platform === 'linux') {
|
|
33
|
+
// /proc is always there; `ps` is not (node:22-slim has no procps, so a reinstall could not
|
|
34
|
+
// find the running kenaz-server and failed with ETXTBSY).
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const d of fs.readdirSync('/proc')) {
|
|
37
|
+
if (!/^\d+$/.test(d)) continue;
|
|
38
|
+
try { const exe = fs.readlinkSync('/proc/' + d + '/exe'); out.push({ pid: Number(d), name: path.basename(exe), exe }); } catch (_) { /* gone or not ours */ }
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
32
42
|
const r = sh('ps', ['-eo', 'pid=,args=']);
|
|
33
43
|
return String(r.stdout || '').split('\n').map((l) => /^\s*(\d+)\s+(.+)$/.exec(l)).filter(Boolean)
|
|
34
44
|
.map((m) => ({ pid: Number(m[1]), name: path.basename(m[2].split(' ')[0]), exe: m[2].split(' ')[0] }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kenaz",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Install Kenaz (plugin, hooks, kenaz-server) for Claude Code and Codex: npx kenaz install",
|
|
5
5
|
"bin": {
|
|
6
6
|
"kenaz": "bin/kenaz.js"
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"test": "node --test lib/cli.test.js"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@kenazai/server-
|
|
24
|
-
"@kenazai/server-darwin-
|
|
25
|
-
"@kenazai/server-
|
|
26
|
-
"@kenazai/server-linux-x64": "0.3.
|
|
27
|
-
"@kenazai/server-
|
|
23
|
+
"@kenazai/server-win32-x64": "0.3.3",
|
|
24
|
+
"@kenazai/server-darwin-arm64": "0.3.3",
|
|
25
|
+
"@kenazai/server-darwin-x64": "0.3.3",
|
|
26
|
+
"@kenazai/server-linux-x64": "0.3.3",
|
|
27
|
+
"@kenazai/server-linux-arm64": "0.3.3"
|
|
28
28
|
},
|
|
29
29
|
"license": "UNLICENSED"
|
|
30
30
|
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// TASK_1863 — boot ghost-lease fix: re-running ansuz-boot-fast.js within the SAME
|
|
2
|
-
// conversation must reuse the existing stream lease (via stream-lease register's
|
|
3
|
-
// findLeaseByConversationId reuse path), not mint a new boot-<ts>-<pid> ghost.
|
|
4
|
-
// Isolated sandbox via CLAUDE_PROJECT_DIR (stream-lease resolveBase honors it);
|
|
5
|
-
// never touches the real repo's leases.
|
|
6
|
-
//
|
|
7
|
-
// Arms:
|
|
8
|
-
// 1 (AC#2): 3 consecutive boots, same conversation id -> readAllLeases must hold
|
|
9
|
-
// exactly ONE lease for that conversation; boots 2/3 must not print a
|
|
10
|
-
// [Multi-Ansuz] banner (no self-ghost).
|
|
11
|
-
// 2 (control): a boot under a DIFFERENT conversation id still creates its own
|
|
12
|
-
// new lease (reuse is conversation-scoped, not a global singleton).
|
|
13
|
-
//
|
|
14
|
-
// Usage: node .specialist/tools/__tests__/task-1863-boot-lease-reuse.test.js
|
|
15
|
-
// Exit 0=all pass, non-zero=at least one failure.
|
|
16
|
-
|
|
17
|
-
const { spawnSync } = require('child_process');
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
const os = require('os');
|
|
21
|
-
|
|
22
|
-
function resolveRoot() {
|
|
23
|
-
var d = path.resolve(__dirname);
|
|
24
|
-
for (var i = 0; i < 10; i++) {
|
|
25
|
-
if (fs.existsSync(path.join(d, '.kenaz')) && fs.existsSync(path.join(d, '.specialist'))) return d;
|
|
26
|
-
var parent = path.dirname(d); if (parent === d) break; d = parent;
|
|
27
|
-
}
|
|
28
|
-
if (process.env.CLAUDE_PROJECT_DIR) return process.env.CLAUDE_PROJECT_DIR;
|
|
29
|
-
throw new Error('Cannot resolve repo root from ' + __dirname);
|
|
30
|
-
}
|
|
31
|
-
const WT = resolveRoot();
|
|
32
|
-
const SB = path.join(os.tmpdir(), 't1863_boot_' + process.pid);
|
|
33
|
-
const BOOT = path.join(WT, '.specialist/tools/ansuz-boot-fast.js');
|
|
34
|
-
const STREAM_LEASE = path.join(WT, '.specialist/tools/stream-lease.js');
|
|
35
|
-
const CONV1 = 'conv-t1863-boot';
|
|
36
|
-
const CONV2 = 'conv-t1863-other';
|
|
37
|
-
|
|
38
|
-
for (const d of [
|
|
39
|
-
'.kenaz/tasks/backlog', '.kenaz/tasks/active', '.kenaz/tasks/done',
|
|
40
|
-
'.kenaz/tasks/blocked', '.kenaz/tasks/cancel',
|
|
41
|
-
'.kenaz/specialist/sessions/leases',
|
|
42
|
-
]) fs.mkdirSync(path.join(SB, d), { recursive: true });
|
|
43
|
-
|
|
44
|
-
const env = { ...process.env, CLAUDE_PROJECT_DIR: SB };
|
|
45
|
-
|
|
46
|
-
const boot = (convId) => spawnSync(process.execPath, [
|
|
47
|
-
BOOT,
|
|
48
|
-
'--project-path=' + SB,
|
|
49
|
-
'--conversation-id=' + convId,
|
|
50
|
-
'--mcp-base-url=http://127.0.0.1:1', // dead port: preamble arm fails instantly, offline-safe
|
|
51
|
-
], { encoding: 'utf8', env, windowsHide: true, cwd: SB, timeout: 30000 });
|
|
52
|
-
|
|
53
|
-
// Count via the exported readAllLeases (card: do NOT re-implement lease scanning).
|
|
54
|
-
// Child process so resolveBase picks up CLAUDE_PROJECT_DIR=SB at module load.
|
|
55
|
-
const readLeases = () => {
|
|
56
|
-
const r = spawnSync(process.execPath, ['-e',
|
|
57
|
-
'const sl=require(' + JSON.stringify(STREAM_LEASE) + ');process.stdout.write(JSON.stringify(sl.readAllLeases()));',
|
|
58
|
-
], { encoding: 'utf8', env, windowsHide: true });
|
|
59
|
-
return JSON.parse(r.stdout || '[]');
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
let pass = 0, fail = 0;
|
|
63
|
-
const check = (name, cond, detail) => {
|
|
64
|
-
console.log((cond ? 'PASS' : 'FAIL') + ' | ' + name + (cond ? '' : ' | ' + detail));
|
|
65
|
-
cond ? pass++ : fail++;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// ── Arm 1: 3 boots, same conversation ──
|
|
69
|
-
const outs = [];
|
|
70
|
-
for (let i = 0; i < 3; i++) {
|
|
71
|
-
const r = boot(CONV1);
|
|
72
|
-
outs.push((r.stdout || '') + (r.stderr || ''));
|
|
73
|
-
check('boot#' + (i + 1) + ' runs (banner printed)', (r.stdout || '').includes('Ansuz'),
|
|
74
|
-
'status=' + r.status + ' | ' + ((r.stdout || '') + (r.stderr || '')).slice(0, 300));
|
|
75
|
-
}
|
|
76
|
-
const all = readLeases();
|
|
77
|
-
const mine = all.filter((l) => l.conversation_id === CONV1);
|
|
78
|
-
check('AC#2: exactly ONE lease for the conversation after 3 boots', mine.length === 1,
|
|
79
|
-
'count=' + mine.length + ' sids=' + all.map((l) => l.session_id).join(','));
|
|
80
|
-
check('boots 2+3 show no [Multi-Ansuz] self-ghost',
|
|
81
|
-
!outs[1].includes('[Multi-Ansuz]') && !outs[2].includes('[Multi-Ansuz]'),
|
|
82
|
-
'boot2/3 banner: ' + (outs[1] + outs[2]).split(String.fromCharCode(10)).filter((l) => l.includes('Multi-Ansuz') || l.includes('[live]') || l.includes('[stale]')).join(' / '));
|
|
83
|
-
|
|
84
|
-
// ── Arm 2 (control): different conversation still gets its OWN new lease ──
|
|
85
|
-
const r2 = boot(CONV2);
|
|
86
|
-
const all2 = readLeases();
|
|
87
|
-
const mine2 = all2.filter((l) => l.conversation_id === CONV2);
|
|
88
|
-
const mine1 = all2.filter((l) => l.conversation_id === CONV1);
|
|
89
|
-
check('control: new conversation creates a NEW lease (reuse is conversation-scoped)',
|
|
90
|
-
mine2.length === 1 && mine1.length === 1 && all2.length === 2,
|
|
91
|
-
'conv2=' + mine2.length + ' conv1=' + mine1.length + ' total=' + all2.length);
|
|
92
|
-
check('control: second conversation SEES the first as a live peer (banner intact)',
|
|
93
|
-
((r2.stdout || '')).includes('[Multi-Ansuz]'),
|
|
94
|
-
'no peer banner: ' + (r2.stdout || '').slice(0, 400));
|
|
95
|
-
|
|
96
|
-
fs.rmSync(SB, { recursive: true, force: true });
|
|
97
|
-
console.log('---');
|
|
98
|
-
console.log('RESULT: ' + pass + ' pass, ' + fail + ' fail');
|
|
99
|
-
process.exit(fail ? 1 : 0);
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
// TASK_1977 R3/R4(d) — ansuz-boot-fast.js handoff banner fan-out cap.
|
|
2
|
-
//
|
|
3
|
-
// MEASURED 2026-09-20: a run of 19 accumulated handoff slots printed 33.8 KB
|
|
4
|
-
// into the fast-boot banner, most repeating the same pending_decisions text.
|
|
5
|
-
// Fix: sort newest-first, print at most 3 full slots (deduped by topic
|
|
6
|
-
// prefix), fold the rest into one summary line. Archiving must still touch
|
|
7
|
-
// EVERY slot regardless of what gets rendered.
|
|
8
|
-
//
|
|
9
|
-
// Arms:
|
|
10
|
-
// 1. 5 distinct-topic fixture slots -> 3 printed in full + 1 summary line
|
|
11
|
-
// naming the other 2 topics; all 5 archived.
|
|
12
|
-
// 2. dedup case: several slots share a topic prefix -> duplicates fold
|
|
13
|
-
// into the summary instead of eating a "printed" slot.
|
|
14
|
-
//
|
|
15
|
-
// Usage: node .specialist/tools/__tests__/task-1977-banner-cap.test.js
|
|
16
|
-
// Exit 0=all pass, non-zero=at least one failure.
|
|
17
|
-
|
|
18
|
-
const { spawnSync } = require('child_process');
|
|
19
|
-
const fs = require('fs');
|
|
20
|
-
const os = require('os');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
|
|
23
|
-
function resolveRoot() {
|
|
24
|
-
let d = path.resolve(__dirname);
|
|
25
|
-
for (let i = 0; i < 10; i++) {
|
|
26
|
-
if (fs.existsSync(path.join(d, '.kenaz')) && fs.existsSync(path.join(d, '.specialist'))) return d;
|
|
27
|
-
const parent = path.dirname(d);
|
|
28
|
-
if (parent === d) break;
|
|
29
|
-
d = parent;
|
|
30
|
-
}
|
|
31
|
-
if (process.env.CLAUDE_PROJECT_DIR) return process.env.CLAUDE_PROJECT_DIR;
|
|
32
|
-
throw new Error('Cannot resolve repo root from ' + __dirname);
|
|
33
|
-
}
|
|
34
|
-
const WT = resolveRoot();
|
|
35
|
-
const BOOT = path.join(WT, '.specialist/tools/ansuz-boot-fast.js');
|
|
36
|
-
|
|
37
|
-
let pass = 0, fail = 0;
|
|
38
|
-
function check(name, cond, detail) {
|
|
39
|
-
console.log((cond ? 'PASS' : 'FAIL') + ' | ' + name + (cond ? '' : ' | ' + detail));
|
|
40
|
-
cond ? pass++ : fail++;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function makeSandbox(prefix) {
|
|
44
|
-
const sb = path.join(os.tmpdir(), prefix + '_' + process.pid + '_' + Date.now());
|
|
45
|
-
for (const d of [
|
|
46
|
-
'.kenaz/tasks/backlog', '.kenaz/tasks/active', '.kenaz/tasks/done',
|
|
47
|
-
'.kenaz/tasks/blocked', '.kenaz/tasks/cancel',
|
|
48
|
-
'.kenaz/specialist/sessions/leases',
|
|
49
|
-
'.kenaz/specialist/handoffs',
|
|
50
|
-
]) fs.mkdirSync(path.join(sb, d), { recursive: true });
|
|
51
|
-
return sb;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function writeSlot(sb, name, topic, generatedAt) {
|
|
55
|
-
const p = path.join(sb, '.kenaz/specialist/handoffs', name);
|
|
56
|
-
fs.writeFileSync(p, JSON.stringify({
|
|
57
|
-
generated_at: generatedAt,
|
|
58
|
-
isbar: {
|
|
59
|
-
situation: { current_topic: topic, pending_decisions: 'pending for ' + topic },
|
|
60
|
-
recommendation: { first_action: 'continue ' + topic },
|
|
61
|
-
assessment: { unfinished: 'unfinished ' + topic },
|
|
62
|
-
},
|
|
63
|
-
}));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function boot(sb) {
|
|
67
|
-
return spawnSync(process.execPath, [
|
|
68
|
-
BOOT,
|
|
69
|
-
'--project-path=' + sb,
|
|
70
|
-
'--conversation-id=t1977-banner-' + path.basename(sb),
|
|
71
|
-
'--mcp-base-url=http://127.0.0.1:1', // dead port: preamble arm fails instantly, offline-safe
|
|
72
|
-
], { encoding: 'utf8', env: { ...process.env, CLAUDE_PROJECT_DIR: sb }, windowsHide: true, cwd: sb, timeout: 30000 });
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ── Arm 1: 5 distinct-topic slots, oldest to newest ──
|
|
76
|
-
const sb1 = makeSandbox('t1977_banner_distinct');
|
|
77
|
-
writeSlot(sb1, 'slot-1.json', 'Topic ONE', '2026-09-15T00:00:00.000Z');
|
|
78
|
-
writeSlot(sb1, 'slot-2.json', 'Topic TWO', '2026-09-16T00:00:00.000Z');
|
|
79
|
-
writeSlot(sb1, 'slot-3.json', 'Topic THREE', '2026-09-17T00:00:00.000Z');
|
|
80
|
-
writeSlot(sb1, 'slot-4.json', 'Topic FOUR', '2026-09-18T00:00:00.000Z');
|
|
81
|
-
writeSlot(sb1, 'slot-5.json', 'Topic FIVE', '2026-09-19T00:00:00.000Z'); // newest
|
|
82
|
-
const r1 = boot(sb1);
|
|
83
|
-
const out1 = (r1.stdout || '') + (r1.stderr || '');
|
|
84
|
-
check('arm1: boot runs (banner printed)', out1.includes('Ansuz'), 'status=' + r1.status + ' | ' + out1.slice(0, 300));
|
|
85
|
-
// TASK_2280: the banner prints String(slot_file).slice(0, 8) (TASK_1988 diet),
|
|
86
|
-
// so "slot-5.json" shows as "[slot-5.j]" -- match the 8-char prefix, not the filename.
|
|
87
|
-
const fullBlocks1 =(out1.match(/📜 Handoff \[slot-\d\.j\]:/g) || []).length;
|
|
88
|
-
check('arm1: exactly 3 full slots printed', fullBlocks1 === 3, 'count=' + fullBlocks1 + '\n' + out1);
|
|
89
|
-
check('arm1: newest 3 topics printed in full (FIVE, FOUR, THREE)',
|
|
90
|
-
out1.includes('Topic FIVE') && out1.includes('Topic FOUR') && out1.includes('Topic THREE'),
|
|
91
|
-
out1);
|
|
92
|
-
check('arm1: one summary line for the remaining 2, naming their topics',
|
|
93
|
-
/2 more handoff slots archived \(topics: Topic TWO; Topic ONE\)/.test(out1),
|
|
94
|
-
out1);
|
|
95
|
-
const archiveDir1 = path.join(sb1, '.kenaz/specialist/handoff_archive');
|
|
96
|
-
const archived1 = fs.existsSync(archiveDir1) ? fs.readdirSync(archiveDir1) : [];
|
|
97
|
-
check('arm1: ALL 5 slots archived regardless of banner selection', archived1.length === 5, 'archived=' + JSON.stringify(archived1));
|
|
98
|
-
const remaining1 = fs.readdirSync(path.join(sb1, '.kenaz/specialist/handoffs'));
|
|
99
|
-
check('arm1: handoffs dir drained after archiving', remaining1.length === 0, 'remaining=' + JSON.stringify(remaining1));
|
|
100
|
-
|
|
101
|
-
// ── Arm 2: dedup -- 4 slots share a topic prefix, 1 is distinct ──
|
|
102
|
-
const sb2 = makeSandbox('t1977_banner_dedup');
|
|
103
|
-
const REPEATED_TOPIC = 'Repeated handoff topic used verbatim across several stale Codex sessions that keeps recurring';
|
|
104
|
-
writeSlot(sb2, 'dup-1.json', REPEATED_TOPIC, '2026-09-16T00:00:00.000Z');
|
|
105
|
-
writeSlot(sb2, 'dup-2.json', REPEATED_TOPIC, '2026-09-17T00:00:00.000Z');
|
|
106
|
-
writeSlot(sb2, 'dup-3.json', REPEATED_TOPIC, '2026-09-18T00:00:00.000Z'); // newest of the dupes
|
|
107
|
-
writeSlot(sb2, 'unique.json', 'A distinct one-off topic', '2026-09-15T00:00:00.000Z'); // oldest overall
|
|
108
|
-
const r2 = boot(sb2);
|
|
109
|
-
const out2 = (r2.stdout || '') + (r2.stderr || '');
|
|
110
|
-
check('arm2: boot runs (banner printed)', out2.includes('Ansuz'), 'status=' + r2.status + ' | ' + out2.slice(0, 300));
|
|
111
|
-
const fullBlocks2 = (out2.match(/📜 Handoff \[(dup-\d\.js|unique\.j)\]:/g) || []).length;
|
|
112
|
-
check('arm2: only 2 full slots printed (one per distinct topic prefix, dupes folded)', fullBlocks2 === 2, 'count=' + fullBlocks2 + '\n' + out2);
|
|
113
|
-
check('arm2: newest dupe (dup-3) is the one printed in full, not dup-1/dup-2',
|
|
114
|
-
out2.includes('📜 Handoff [dup-3.js]:') && !out2.includes('📜 Handoff [dup-1.js]:') && !out2.includes('📜 Handoff [dup-2.js]:'),
|
|
115
|
-
out2);
|
|
116
|
-
check('arm2: the distinct topic is also printed in full', out2.includes('📜 Handoff [unique.j]:'), out2);
|
|
117
|
-
check('arm2: summary line folds the 2 duplicate slots', /2 more handoff slots archived/.test(out2), out2);
|
|
118
|
-
const archiveDir2 = path.join(sb2, '.kenaz/specialist/handoff_archive');
|
|
119
|
-
const archived2 = fs.existsSync(archiveDir2) ? fs.readdirSync(archiveDir2) : [];
|
|
120
|
-
check('arm2: ALL 4 slots archived regardless of dedup folding', archived2.length === 4, 'archived=' + JSON.stringify(archived2));
|
|
121
|
-
|
|
122
|
-
// ── cleanup ──
|
|
123
|
-
for (const sb of [sb1, sb2]) {
|
|
124
|
-
try { fs.rmSync(sb, { recursive: true, force: true }); } catch { /* best-effort */ }
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
console.log('---');
|
|
128
|
-
console.log('RESULT: ' + pass + ' pass, ' + fail + ' fail');
|
|
129
|
-
process.exit(fail > 0 ? 1 : 0);
|