@askdkc/kiokuko 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +91 -112
- package/README.ko.md +90 -102
- package/README.md +103 -260
- package/README.zh-CN.md +88 -102
- package/dist/agent-file/atomic-write.d.ts +90 -3
- package/dist/agent-file/atomic-write.d.ts.map +1 -1
- package/dist/agent-file/atomic-write.js +990 -14
- package/dist/agent-file/atomic-write.js.map +1 -1
- package/dist/agent-file/managed-block.d.ts +12 -1
- package/dist/agent-file/managed-block.d.ts.map +1 -1
- package/dist/agent-file/managed-block.js +49 -4
- package/dist/agent-file/managed-block.js.map +1 -1
- package/dist/agent-file/render.d.ts +1 -1
- package/dist/agent-file/render.d.ts.map +1 -1
- package/dist/agent-file/render.js +10 -7
- package/dist/agent-file/render.js.map +1 -1
- package/dist/akinator/agent-task.d.ts +14 -24
- package/dist/akinator/agent-task.d.ts.map +1 -1
- package/dist/akinator/agent-task.js +460 -103
- package/dist/akinator/agent-task.js.map +1 -1
- package/dist/akinator/capabilities.d.ts +52 -7
- package/dist/akinator/capabilities.d.ts.map +1 -1
- package/dist/akinator/capabilities.js +226 -28
- package/dist/akinator/capabilities.js.map +1 -1
- package/dist/akinator/capability-binding.d.ts +11 -0
- package/dist/akinator/capability-binding.d.ts.map +1 -0
- package/dist/akinator/capability-binding.js +56 -0
- package/dist/akinator/capability-binding.js.map +1 -0
- package/dist/akinator/domain.js +2 -2
- package/dist/akinator/domain.js.map +1 -1
- package/dist/akinator/knowledge-path.d.ts.map +1 -1
- package/dist/akinator/knowledge-path.js +409 -39
- package/dist/akinator/knowledge-path.js.map +1 -1
- package/dist/akinator/orchestrator.d.ts +3 -4
- package/dist/akinator/orchestrator.d.ts.map +1 -1
- package/dist/akinator/orchestrator.js +1 -4
- package/dist/akinator/orchestrator.js.map +1 -1
- package/dist/akinator/service.d.ts +0 -4
- package/dist/akinator/service.d.ts.map +1 -1
- package/dist/akinator/service.js +19 -35
- package/dist/akinator/service.js.map +1 -1
- package/dist/akinator/skill-discovery-attempt.d.ts +20 -0
- package/dist/akinator/skill-discovery-attempt.d.ts.map +1 -0
- package/dist/akinator/skill-discovery-attempt.js +390 -0
- package/dist/akinator/skill-discovery-attempt.js.map +1 -0
- package/dist/akinator/store.d.ts.map +1 -1
- package/dist/akinator/store.js +107 -52
- package/dist/akinator/store.js.map +1 -1
- package/dist/akinator/types.d.ts +0 -12
- package/dist/akinator/types.d.ts.map +1 -1
- package/dist/bin/kiokuko.js +0 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +561 -144
- package/dist/cli.js.map +1 -1
- package/dist/client/server-client.d.ts +5 -3
- package/dist/client/server-client.d.ts.map +1 -1
- package/dist/client/server-client.js +486 -181
- package/dist/client/server-client.js.map +1 -1
- package/dist/commands/agent.d.ts +2 -0
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +861 -86
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/backup.d.ts +2 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +64 -8
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/doctor.d.ts +5 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +70 -26
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/export.d.ts +0 -4
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +191 -32
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/import.d.ts +10 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +592 -113
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +19 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +569 -22
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/purge.d.ts.map +1 -1
- package/dist/commands/purge.js +3 -0
- package/dist/commands/purge.js.map +1 -1
- package/dist/commands/setup.d.ts +34 -8
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +418 -86
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skills.d.ts +9 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +317 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/use.d.ts +10 -2
- package/dist/commands/use.d.ts.map +1 -1
- package/dist/commands/use.js +851 -73
- package/dist/commands/use.js.map +1 -1
- package/dist/config/paths.d.ts +11 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +64 -29
- package/dist/config/paths.js.map +1 -1
- package/dist/config/project-config.d.ts +1 -0
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +70 -32
- package/dist/config/project-config.js.map +1 -1
- package/dist/context/broker.d.ts +30 -14
- package/dist/context/broker.d.ts.map +1 -1
- package/dist/context/broker.js +628 -150
- package/dist/context/broker.js.map +1 -1
- package/dist/context/delivery.d.ts +8 -22
- package/dist/context/delivery.d.ts.map +1 -1
- package/dist/context/delivery.js +204 -152
- package/dist/context/delivery.js.map +1 -1
- package/dist/context/feedback.d.ts +11 -12
- package/dist/context/feedback.d.ts.map +1 -1
- package/dist/context/feedback.js +250 -268
- package/dist/context/feedback.js.map +1 -1
- package/dist/context/origin.d.ts +9 -0
- package/dist/context/origin.d.ts.map +1 -0
- package/dist/context/origin.js +15 -0
- package/dist/context/origin.js.map +1 -0
- package/dist/context/ranking.d.ts +4 -13
- package/dist/context/ranking.d.ts.map +1 -1
- package/dist/context/ranking.js +21 -5
- package/dist/context/ranking.js.map +1 -1
- package/dist/context/recommendations.d.ts +0 -5
- package/dist/context/recommendations.d.ts.map +1 -1
- package/dist/context/recommendations.js +0 -1
- package/dist/context/recommendations.js.map +1 -1
- package/dist/context/run-state.d.ts +26 -0
- package/dist/context/run-state.d.ts.map +1 -0
- package/dist/context/run-state.js +399 -0
- package/dist/context/run-state.js.map +1 -0
- package/dist/context/scoped-broker.d.ts +19 -6
- package/dist/context/scoped-broker.d.ts.map +1 -1
- package/dist/context/scoped-broker.js +530 -131
- package/dist/context/scoped-broker.js.map +1 -1
- package/dist/context/selection-state.d.ts +19 -0
- package/dist/context/selection-state.d.ts.map +1 -0
- package/dist/context/selection-state.js +250 -0
- package/dist/context/selection-state.js.map +1 -0
- package/dist/db/adapter.d.ts +5 -3
- package/dist/db/adapter.d.ts.map +1 -1
- package/dist/db/adapter.js +6 -3
- package/dist/db/adapter.js.map +1 -1
- package/dist/db/capabilities.d.ts.map +1 -1
- package/dist/db/capabilities.js +34 -16
- package/dist/db/capabilities.js.map +1 -1
- package/dist/db/connection.d.ts +8 -0
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +55 -26
- package/dist/db/connection.js.map +1 -1
- package/dist/db/migrate.d.ts +28 -7
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +106 -78
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/sqlite-retry.d.ts +11 -0
- package/dist/db/sqlite-retry.d.ts.map +1 -0
- package/dist/db/sqlite-retry.js +66 -0
- package/dist/db/sqlite-retry.js.map +1 -0
- package/dist/db/transaction.d.ts +13 -0
- package/dist/db/transaction.d.ts.map +1 -1
- package/dist/db/transaction.js +53 -24
- package/dist/db/transaction.js.map +1 -1
- package/dist/db/upgrade-backup.d.ts +58 -2
- package/dist/db/upgrade-backup.d.ts.map +1 -1
- package/dist/db/upgrade-backup.js +757 -28
- package/dist/db/upgrade-backup.js.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/gateway/agent-service.d.ts +4 -1
- package/dist/gateway/agent-service.d.ts.map +1 -1
- package/dist/gateway/agent-service.js +71 -58
- package/dist/gateway/agent-service.js.map +1 -1
- package/dist/gateway/checkpoint-service.d.ts +1 -0
- package/dist/gateway/checkpoint-service.d.ts.map +1 -1
- package/dist/gateway/checkpoint-service.js +47 -24
- package/dist/gateway/checkpoint-service.js.map +1 -1
- package/dist/ledger/archive.d.ts +1 -4
- package/dist/ledger/archive.d.ts.map +1 -1
- package/dist/ledger/archive.js +134 -54
- package/dist/ledger/archive.js.map +1 -1
- package/dist/ledger/maintenance.d.ts +0 -11
- package/dist/ledger/maintenance.d.ts.map +1 -1
- package/dist/ledger/maintenance.js +41 -44
- package/dist/ledger/maintenance.js.map +1 -1
- package/dist/ledger/projection.d.ts +0 -1
- package/dist/ledger/projection.d.ts.map +1 -1
- package/dist/ledger/projection.js.map +1 -1
- package/dist/ledger/promotion.d.ts +0 -9
- package/dist/ledger/promotion.d.ts.map +1 -1
- package/dist/ledger/promotion.js.map +1 -1
- package/dist/ledger/query.d.ts +1 -15
- package/dist/ledger/query.d.ts.map +1 -1
- package/dist/ledger/query.js.map +1 -1
- package/dist/ledger/store.d.ts +0 -1
- package/dist/ledger/store.d.ts.map +1 -1
- package/dist/ledger/store.js +11 -8
- package/dist/ledger/store.js.map +1 -1
- package/dist/ledger/types.d.ts +0 -4
- package/dist/ledger/types.d.ts.map +1 -1
- package/dist/ledger/types.js.map +1 -1
- package/dist/ledger/validate.d.ts.map +1 -1
- package/dist/ledger/validate.js +0 -5
- package/dist/ledger/validate.js.map +1 -1
- package/dist/mcp/bounded-stdio-transport.d.ts +23 -0
- package/dist/mcp/bounded-stdio-transport.d.ts.map +1 -0
- package/dist/mcp/bounded-stdio-transport.js +109 -0
- package/dist/mcp/bounded-stdio-transport.js.map +1 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +111 -75
- package/dist/mcp/server.js.map +1 -1
- package/dist/memory/audit.d.ts +0 -1
- package/dist/memory/audit.d.ts.map +1 -1
- package/dist/memory/audit.js +0 -1
- package/dist/memory/audit.js.map +1 -1
- package/dist/memory/curator.d.ts +45 -1
- package/dist/memory/curator.d.ts.map +1 -1
- package/dist/memory/curator.js +290 -68
- package/dist/memory/curator.js.map +1 -1
- package/dist/memory/entries.d.ts +12 -2
- package/dist/memory/entries.d.ts.map +1 -1
- package/dist/memory/entries.js +198 -114
- package/dist/memory/entries.js.map +1 -1
- package/dist/memory/federated-retrieval.d.ts +78 -0
- package/dist/memory/federated-retrieval.d.ts.map +1 -0
- package/dist/memory/federated-retrieval.js +441 -0
- package/dist/memory/federated-retrieval.js.map +1 -0
- package/dist/memory/hybrid-retrieval.d.ts +5 -11
- package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
- package/dist/memory/hybrid-retrieval.js +78 -58
- package/dist/memory/hybrid-retrieval.js.map +1 -1
- package/dist/memory/lifecycle.d.ts.map +1 -1
- package/dist/memory/lifecycle.js +17 -13
- package/dist/memory/lifecycle.js.map +1 -1
- package/dist/memory/portability.d.ts +10 -0
- package/dist/memory/portability.d.ts.map +1 -0
- package/dist/memory/portability.js +44 -0
- package/dist/memory/portability.js.map +1 -0
- package/dist/memory/rebuild-search.d.ts +5 -0
- package/dist/memory/rebuild-search.d.ts.map +1 -1
- package/dist/memory/rebuild-search.js +101 -76
- package/dist/memory/rebuild-search.js.map +1 -1
- package/dist/memory/retrieval-query.d.ts +0 -5
- package/dist/memory/retrieval-query.d.ts.map +1 -1
- package/dist/memory/retrieval-query.js +0 -5
- package/dist/memory/retrieval-query.js.map +1 -1
- package/dist/memory/retrieval.d.ts +11 -0
- package/dist/memory/retrieval.d.ts.map +1 -1
- package/dist/memory/retrieval.js +34 -120
- package/dist/memory/retrieval.js.map +1 -1
- package/dist/memory/revisions.d.ts +76 -1
- package/dist/memory/revisions.d.ts.map +1 -1
- package/dist/memory/revisions.js +539 -35
- package/dist/memory/revisions.js.map +1 -1
- package/dist/memory/scoped-memory.d.ts +22 -13
- package/dist/memory/scoped-memory.d.ts.map +1 -1
- package/dist/memory/scoped-memory.js +248 -139
- package/dist/memory/scoped-memory.js.map +1 -1
- package/dist/memory/secrets.d.ts +2 -0
- package/dist/memory/secrets.d.ts.map +1 -1
- package/dist/memory/secrets.js +36 -0
- package/dist/memory/secrets.js.map +1 -1
- package/dist/memory/structured-memory.d.ts +8 -1
- package/dist/memory/structured-memory.d.ts.map +1 -1
- package/dist/memory/structured-memory.js +74 -20
- package/dist/memory/structured-memory.js.map +1 -1
- package/dist/memory/workspaces.d.ts +9 -0
- package/dist/memory/workspaces.d.ts.map +1 -1
- package/dist/memory/workspaces.js +67 -0
- package/dist/memory/workspaces.js.map +1 -1
- package/dist/package-version.d.ts +2 -0
- package/dist/package-version.d.ts.map +1 -0
- package/dist/package-version.js +7 -0
- package/dist/package-version.js.map +1 -0
- package/dist/repository/binding.d.ts +5 -0
- package/dist/repository/binding.d.ts.map +1 -1
- package/dist/repository/binding.js +117 -17
- package/dist/repository/binding.js.map +1 -1
- package/dist/repository/framework-version.d.ts +8 -0
- package/dist/repository/framework-version.d.ts.map +1 -0
- package/dist/repository/framework-version.js +29 -0
- package/dist/repository/framework-version.js.map +1 -0
- package/dist/repository/identity-value.d.ts +4 -0
- package/dist/repository/identity-value.d.ts.map +1 -0
- package/dist/repository/identity-value.js +24 -0
- package/dist/repository/identity-value.js.map +1 -0
- package/dist/repository/identity.d.ts.map +1 -1
- package/dist/repository/identity.js +2 -0
- package/dist/repository/identity.js.map +1 -1
- package/dist/repository/project-fingerprint.d.ts +33 -0
- package/dist/repository/project-fingerprint.d.ts.map +1 -0
- package/dist/repository/project-fingerprint.js +429 -0
- package/dist/repository/project-fingerprint.js.map +1 -0
- package/dist/repository/remote-url.d.ts +0 -1
- package/dist/repository/remote-url.d.ts.map +1 -1
- package/dist/repository/remote-url.js +0 -1
- package/dist/repository/remote-url.js.map +1 -1
- package/dist/runtime-version.d.ts +2 -1
- package/dist/runtime-version.d.ts.map +1 -1
- package/dist/runtime-version.js +21 -4
- package/dist/runtime-version.js.map +1 -1
- package/dist/serialization/boundary-json.d.ts +20 -0
- package/dist/serialization/boundary-json.d.ts.map +1 -0
- package/dist/serialization/boundary-json.js +129 -0
- package/dist/serialization/boundary-json.js.map +1 -0
- package/dist/serialization/envelope.js +1 -1
- package/dist/serialization/envelope.js.map +1 -1
- package/dist/serialization/validate.d.ts +7 -0
- package/dist/serialization/validate.d.ts.map +1 -1
- package/dist/serialization/validate.js +53 -13
- package/dist/serialization/validate.js.map +1 -1
- package/dist/server/app.js +1 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/http.d.ts +4 -3
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +90 -50
- package/dist/server/http.js.map +1 -1
- package/dist/server/idempotency.d.ts +0 -6
- package/dist/server/idempotency.d.ts.map +1 -1
- package/dist/server/idempotency.js.map +1 -1
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/router.js +21 -4
- package/dist/server/router.js.map +1 -1
- package/dist/server/routes/agent-capability-gate.d.ts +40 -0
- package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
- package/dist/server/routes/agent-capability-gate.js +182 -0
- package/dist/server/routes/agent-capability-gate.js.map +1 -0
- package/dist/server/routes/agent-events.d.ts.map +1 -1
- package/dist/server/routes/agent-events.js +8 -1
- package/dist/server/routes/agent-events.js.map +1 -1
- package/dist/server/routes/agent-intake.d.ts.map +1 -1
- package/dist/server/routes/agent-intake.js +10 -2
- package/dist/server/routes/agent-intake.js.map +1 -1
- package/dist/server/routes/agent-promotions.d.ts.map +1 -1
- package/dist/server/routes/agent-promotions.js +5 -2
- package/dist/server/routes/agent-promotions.js.map +1 -1
- package/dist/server/routes/agent-runs.d.ts.map +1 -1
- package/dist/server/routes/agent-runs.js +18 -4
- package/dist/server/routes/agent-runs.js.map +1 -1
- package/dist/server/routes/request-binding.d.ts +5 -0
- package/dist/server/routes/request-binding.d.ts.map +1 -0
- package/dist/server/routes/request-binding.js +49 -0
- package/dist/server/routes/request-binding.js.map +1 -0
- package/dist/server/routes/task5-support.d.ts +1 -8
- package/dist/server/routes/task5-support.d.ts.map +1 -1
- package/dist/server/routes/task5-support.js +1 -17
- package/dist/server/routes/task5-support.js.map +1 -1
- package/dist/server/routes/task5.d.ts.map +1 -1
- package/dist/server/routes/task5.js +106 -36
- package/dist/server/routes/task5.js.map +1 -1
- package/dist/server/write-queue.js +2 -2
- package/dist/server/write-queue.js.map +1 -1
- package/dist/setup/claude-config.d.ts +2 -1
- package/dist/setup/claude-config.d.ts.map +1 -1
- package/dist/setup/claude-config.js +54 -4
- package/dist/setup/claude-config.js.map +1 -1
- package/dist/setup/client-detection.d.ts +7 -2
- package/dist/setup/client-detection.d.ts.map +1 -1
- package/dist/setup/client-detection.js +27 -9
- package/dist/setup/client-detection.js.map +1 -1
- package/dist/setup/hermes-config.d.ts +2 -1
- package/dist/setup/hermes-config.d.ts.map +1 -1
- package/dist/setup/hermes-config.js +53 -12
- package/dist/setup/hermes-config.js.map +1 -1
- package/dist/setup/legacy-client-cleanup.d.ts +6 -0
- package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
- package/dist/setup/legacy-client-cleanup.js +152 -0
- package/dist/setup/legacy-client-cleanup.js.map +1 -0
- package/dist/setup/managed-text.d.ts.map +1 -1
- package/dist/setup/managed-text.js +11 -1
- package/dist/setup/managed-text.js.map +1 -1
- package/dist/setup/opencode-config.d.ts +2 -1
- package/dist/setup/opencode-config.d.ts.map +1 -1
- package/dist/setup/opencode-config.js +57 -5
- package/dist/setup/opencode-config.js.map +1 -1
- package/dist/setup/render.d.ts +2 -1
- package/dist/setup/render.d.ts.map +1 -1
- package/dist/setup/render.js +91 -17
- package/dist/setup/render.js.map +1 -1
- package/dist/setup/standard-skills.d.ts +16 -2
- package/dist/setup/standard-skills.d.ts.map +1 -1
- package/dist/setup/standard-skills.js +37 -13
- package/dist/setup/standard-skills.js.map +1 -1
- package/dist/setup/strict-json.d.ts +7 -0
- package/dist/setup/strict-json.d.ts.map +1 -0
- package/dist/setup/strict-json.js +98 -0
- package/dist/setup/strict-json.js.map +1 -0
- package/dist/setup/strict-toml.d.ts +7 -0
- package/dist/setup/strict-toml.d.ts.map +1 -0
- package/dist/setup/strict-toml.js +470 -0
- package/dist/setup/strict-toml.js.map +1 -0
- package/dist/skills/cache.d.ts +15 -0
- package/dist/skills/cache.d.ts.map +1 -0
- package/dist/skills/cache.js +19 -0
- package/dist/skills/cache.js.map +1 -0
- package/dist/skills/candidate-ranking.d.ts +15 -0
- package/dist/skills/candidate-ranking.d.ts.map +1 -0
- package/dist/skills/candidate-ranking.js +52 -0
- package/dist/skills/candidate-ranking.js.map +1 -0
- package/dist/skills/chunking.d.ts +11 -0
- package/dist/skills/chunking.d.ts.map +1 -0
- package/dist/skills/chunking.js +291 -0
- package/dist/skills/chunking.js.map +1 -0
- package/dist/skills/config.d.ts +19 -0
- package/dist/skills/config.d.ts.map +1 -0
- package/dist/skills/config.js +103 -0
- package/dist/skills/config.js.map +1 -0
- package/dist/skills/discovery-service.d.ts +26 -0
- package/dist/skills/discovery-service.d.ts.map +1 -0
- package/dist/skills/discovery-service.js +921 -0
- package/dist/skills/discovery-service.js.map +1 -0
- package/dist/skills/external-transport.d.ts +2 -0
- package/dist/skills/external-transport.d.ts.map +1 -0
- package/dist/skills/external-transport.js +30 -0
- package/dist/skills/external-transport.js.map +1 -0
- package/dist/skills/find.d.ts +16 -0
- package/dist/skills/find.d.ts.map +1 -0
- package/dist/skills/find.js +58 -0
- package/dist/skills/find.js.map +1 -0
- package/dist/skills/gap-detection.d.ts +23 -0
- package/dist/skills/gap-detection.d.ts.map +1 -0
- package/dist/skills/gap-detection.js +62 -0
- package/dist/skills/gap-detection.js.map +1 -0
- package/dist/skills/import-preparation.d.ts +4 -0
- package/dist/skills/import-preparation.d.ts.map +1 -0
- package/dist/skills/import-preparation.js +20 -0
- package/dist/skills/import-preparation.js.map +1 -0
- package/dist/skills/materialization-authority.d.ts +11 -0
- package/dist/skills/materialization-authority.d.ts.map +1 -0
- package/dist/skills/materialization-authority.js +92 -0
- package/dist/skills/materialization-authority.js.map +1 -0
- package/dist/skills/materialization-service.d.ts +22 -0
- package/dist/skills/materialization-service.d.ts.map +1 -0
- package/dist/skills/materialization-service.js +101 -0
- package/dist/skills/materialization-service.js.map +1 -0
- package/dist/skills/official-catalog.d.ts +31 -0
- package/dist/skills/official-catalog.d.ts.map +1 -0
- package/dist/skills/official-catalog.js +110 -0
- package/dist/skills/official-catalog.js.map +1 -0
- package/dist/skills/providers/schema.d.ts +30 -0
- package/dist/skills/providers/schema.d.ts.map +1 -0
- package/dist/skills/providers/schema.js +354 -0
- package/dist/skills/providers/schema.js.map +1 -0
- package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
- package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
- package/dist/skills/providers/skills-sh-compat.js +71 -0
- package/dist/skills/providers/skills-sh-compat.js.map +1 -0
- package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
- package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
- package/dist/skills/providers/skills-sh-v1.js +134 -0
- package/dist/skills/providers/skills-sh-v1.js.map +1 -0
- package/dist/skills/query-builder.d.ts +18 -0
- package/dist/skills/query-builder.d.ts.map +1 -0
- package/dist/skills/query-builder.js +93 -0
- package/dist/skills/query-builder.js.map +1 -0
- package/dist/skills/source/errors.d.ts +9 -0
- package/dist/skills/source/errors.d.ts.map +1 -0
- package/dist/skills/source/errors.js +15 -0
- package/dist/skills/source/errors.js.map +1 -0
- package/dist/skills/source/frontmatter.d.ts +9 -0
- package/dist/skills/source/frontmatter.d.ts.map +1 -0
- package/dist/skills/source/frontmatter.js +77 -0
- package/dist/skills/source/frontmatter.js.map +1 -0
- package/dist/skills/source/github-fetcher.d.ts +20 -0
- package/dist/skills/source/github-fetcher.d.ts.map +1 -0
- package/dist/skills/source/github-fetcher.js +292 -0
- package/dist/skills/source/github-fetcher.js.map +1 -0
- package/dist/skills/source/snapshot-validator.d.ts +28 -0
- package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
- package/dist/skills/source/snapshot-validator.js +186 -0
- package/dist/skills/source/snapshot-validator.js.map +1 -0
- package/dist/skills/store.d.ts +181 -0
- package/dist/skills/store.d.ts.map +1 -0
- package/dist/skills/store.js +1710 -0
- package/dist/skills/store.js.map +1 -0
- package/dist/skills/types.d.ts +169 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/web/i18n.d.ts +56 -8
- package/dist/web/i18n.d.ts.map +1 -1
- package/dist/web/i18n.js +224 -32
- package/dist/web/i18n.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +458 -42
- package/dist/web/server.js.map +1 -1
- package/dist/web/ui.d.ts +4 -0
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +697 -61
- package/dist/web/ui.js.map +1 -1
- package/migrations/008_federated_memory.sql +46 -0
- package/migrations/009_external_skill_discovery.sql +126 -0
- package/package.json +6 -3
- package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
- package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
- package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
- package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
- package/templates/AGENTS.md +8 -7
- package/dist/client/runtime-discovery.d.ts +0 -15
- package/dist/client/runtime-discovery.d.ts.map +0 -1
- package/dist/client/runtime-discovery.js +0 -45
- package/dist/client/runtime-discovery.js.map +0 -1
- package/dist/commands/call.d.ts +0 -7
- package/dist/commands/call.d.ts.map +0 -1
- package/dist/commands/call.js +0 -10
- package/dist/commands/call.js.map +0 -1
- package/dist/commands/link.d.ts +0 -6
- package/dist/commands/link.d.ts.map +0 -1
- package/dist/commands/link.js +0 -6
- package/dist/commands/link.js.map +0 -1
- package/dist/commands/promote.d.ts +0 -6
- package/dist/commands/promote.d.ts.map +0 -1
- package/dist/commands/promote.js +0 -6
- package/dist/commands/promote.js.map +0 -1
- package/dist/commands/read.d.ts +0 -6
- package/dist/commands/read.d.ts.map +0 -1
- package/dist/commands/read.js +0 -4
- package/dist/commands/read.js.map +0 -1
- package/dist/commands/recall.d.ts +0 -6
- package/dist/commands/recall.d.ts.map +0 -1
- package/dist/commands/recall.js +0 -4
- package/dist/commands/recall.js.map +0 -1
- package/dist/commands/record.d.ts +0 -6
- package/dist/commands/record.d.ts.map +0 -1
- package/dist/commands/record.js +0 -4
- package/dist/commands/record.js.map +0 -1
- package/dist/commands/search.d.ts +0 -6
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js +0 -4
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/supersede.d.ts +0 -6
- package/dist/commands/supersede.d.ts.map +0 -1
- package/dist/commands/supersede.js +0 -6
- package/dist/commands/supersede.js.map +0 -1
- package/dist/knowledge/sources.d.ts +0 -72
- package/dist/knowledge/sources.d.ts.map +0 -1
- package/dist/knowledge/sources.js +0 -388
- package/dist/knowledge/sources.js.map +0 -1
- package/dist/setup/opencode-evidence.d.ts +0 -37
- package/dist/setup/opencode-evidence.d.ts.map +0 -1
- package/dist/setup/opencode-evidence.js +0 -58
- package/dist/setup/opencode-evidence.js.map +0 -1
- package/dist/setup/opencode-loop-guard.d.ts +0 -9
- package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
- package/dist/setup/opencode-loop-guard.js +0 -248
- package/dist/setup/opencode-loop-guard.js.map +0 -1
package/dist/web/ui.js
CHANGED
|
@@ -10,6 +10,93 @@ const WEB_I18N_CONFIG = JSON.stringify({
|
|
|
10
10
|
.replaceAll('>', '\\u003e')
|
|
11
11
|
.replaceAll('\u2028', '\\u2028')
|
|
12
12
|
.replaceAll('\u2029', '\\u2029');
|
|
13
|
+
/** Strict client-boundary decoder for the bounded external-skill list shape. */
|
|
14
|
+
export function externalSkillListItemIsValid(value) {
|
|
15
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
16
|
+
return false;
|
|
17
|
+
const skill = value;
|
|
18
|
+
const fields = new Set([
|
|
19
|
+
'skillId', 'provider', 'sourceType', 'sourceLocator', 'slug', 'name', 'installUrl',
|
|
20
|
+
'officialStatus', 'duplicate', 'installs', 'state', 'sourceWorkspace', 'sourceCommit',
|
|
21
|
+
'snapshotHash', 'metadata', 'auditStatus', 'generation', 'firstSeenAt', 'lastSeenAt',
|
|
22
|
+
'lastCheckedAt', 'disabledAt',
|
|
23
|
+
]);
|
|
24
|
+
const text = (item, maximum) => typeof item === 'string'
|
|
25
|
+
&& item.length >= 1 && item.length <= maximum && item === item.trim() && !/[\u0000-\u001f\u007f]/u.test(item);
|
|
26
|
+
const timestamp = (item) => {
|
|
27
|
+
if (typeof item !== 'string')
|
|
28
|
+
return false;
|
|
29
|
+
const parsed = Date.parse(item);
|
|
30
|
+
return Number.isFinite(parsed) && new Date(parsed).toISOString() === item;
|
|
31
|
+
};
|
|
32
|
+
const metadata = skill.metadata;
|
|
33
|
+
const sourceLocator = skill.sourceLocator;
|
|
34
|
+
const slug = skill.slug;
|
|
35
|
+
const sourceCommit = skill.sourceCommit;
|
|
36
|
+
const snapshotHash = skill.snapshotHash;
|
|
37
|
+
const disabledAt = skill.disabledAt;
|
|
38
|
+
const officialStatus = skill.officialStatus;
|
|
39
|
+
const state = skill.state;
|
|
40
|
+
const auditStatus = skill.auditStatus;
|
|
41
|
+
if (Object.keys(skill).length !== fields.size || Object.keys(skill).some((field) => !fields.has(field))
|
|
42
|
+
|| !text(skill.skillId, 500) || !text(skill.provider, 50) || !/^[A-Za-z0-9_.-]+$/u.test(skill.provider)
|
|
43
|
+
|| skill.sourceType !== 'github'
|
|
44
|
+
|| typeof sourceLocator !== 'string' || !/^[a-z0-9_.-]{1,100}\/[a-z0-9_.-]{1,100}$/u.test(sourceLocator)
|
|
45
|
+
|| typeof slug !== 'string' || !/^[A-Za-z0-9_.\-/]{1,240}$/u.test(slug)
|
|
46
|
+
|| slug.split('/').some((part) => part === '' || part === '.' || part === '..')
|
|
47
|
+
|| skill.skillId !== `github:${sourceLocator}:${slug}`
|
|
48
|
+
|| !text(skill.name, 500)
|
|
49
|
+
|| skill.installUrl !== null && skill.installUrl !== `https://github.com/${sourceLocator}`
|
|
50
|
+
|| typeof officialStatus !== 'string'
|
|
51
|
+
|| !['curated', 'catalog-verified', 'owner-verified', 'registry-only', 'unknown'].includes(officialStatus)
|
|
52
|
+
|| typeof skill.duplicate !== 'boolean'
|
|
53
|
+
|| typeof skill.installs !== 'number' || !Number.isSafeInteger(skill.installs) || skill.installs < 0
|
|
54
|
+
|| typeof state !== 'string'
|
|
55
|
+
|| !['discovered', 'imported', 'blocked', 'stale', 'disabled'].includes(state)
|
|
56
|
+
|| !text(skill.sourceWorkspace, 240)
|
|
57
|
+
|| sourceCommit !== null && (typeof sourceCommit !== 'string' || !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/u.test(sourceCommit))
|
|
58
|
+
|| snapshotHash !== null && (typeof snapshotHash !== 'string' || !/^[0-9a-f]{64}$/u.test(snapshotHash))
|
|
59
|
+
|| (sourceCommit === null) !== (snapshotHash === null)
|
|
60
|
+
|| typeof metadata !== 'object' || metadata === null || Array.isArray(metadata)
|
|
61
|
+
|| Object.keys(metadata).length !== 2 || !Object.hasOwn(metadata, 'documents') || !Object.hasOwn(metadata, 'technology')
|
|
62
|
+
|| typeof metadata.documents !== 'number'
|
|
63
|
+
|| !Number.isSafeInteger(metadata.documents)
|
|
64
|
+
|| metadata.documents < 0
|
|
65
|
+
|| metadata.documents > 64
|
|
66
|
+
|| metadata.technology !== null && !text(metadata.technology, 500)
|
|
67
|
+
|| typeof auditStatus !== 'string'
|
|
68
|
+
|| !['not-required', 'passed', 'failed', 'unavailable'].includes(auditStatus)
|
|
69
|
+
|| typeof skill.generation !== 'number' || !Number.isSafeInteger(skill.generation) || skill.generation < 1
|
|
70
|
+
|| !timestamp(skill.firstSeenAt) || !timestamp(skill.lastSeenAt) || !timestamp(skill.lastCheckedAt)
|
|
71
|
+
|| disabledAt !== null && !timestamp(disabledAt)
|
|
72
|
+
|| skill.firstSeenAt > skill.lastSeenAt
|
|
73
|
+
|| skill.firstSeenAt > skill.lastCheckedAt
|
|
74
|
+
|| disabledAt !== null && disabledAt < skill.firstSeenAt
|
|
75
|
+
|| sourceCommit === null && (['imported', 'disabled'].includes(state) || disabledAt !== null)
|
|
76
|
+
|| sourceCommit !== null && !['imported', 'disabled', 'stale', 'blocked'].includes(state)
|
|
77
|
+
|| state === 'imported' && disabledAt !== null
|
|
78
|
+
|| state === 'disabled' && disabledAt === null
|
|
79
|
+
|| sourceCommit === null && (metadata.documents !== 0 || metadata.technology !== null)
|
|
80
|
+
|| sourceCommit !== null && (metadata.documents === 0 || !text(metadata.technology, 500)))
|
|
81
|
+
return false;
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
/** Strict client-boundary decoder for one external-skill mapping summary. */
|
|
85
|
+
export function externalSkillEntrySummaryIsValid(value) {
|
|
86
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
87
|
+
return false;
|
|
88
|
+
const entry = value;
|
|
89
|
+
const fields = new Set(['entryId', 'revision', 'sourcePath', 'chunkIndex', 'primary', 'active']);
|
|
90
|
+
return Object.keys(entry).length === fields.size
|
|
91
|
+
&& Object.keys(entry).every((field) => fields.has(field))
|
|
92
|
+
&& typeof entry.entryId === 'string' && entry.entryId.length >= 1 && entry.entryId.length <= 500 && entry.entryId === entry.entryId.trim()
|
|
93
|
+
&& typeof entry.revision === 'number' && Number.isSafeInteger(entry.revision) && entry.revision >= 1
|
|
94
|
+
&& typeof entry.sourcePath === 'string' && entry.sourcePath.length >= 1 && entry.sourcePath.length <= 2_000
|
|
95
|
+
&& /^[A-Za-z0-9_.\-/]+$/u.test(entry.sourcePath) && !entry.sourcePath.startsWith('/')
|
|
96
|
+
&& !entry.sourcePath.split('/').some((part) => part === '' || part === '.' || part === '..')
|
|
97
|
+
&& typeof entry.chunkIndex === 'number' && Number.isSafeInteger(entry.chunkIndex) && entry.chunkIndex >= 0
|
|
98
|
+
&& typeof entry.primary === 'boolean' && typeof entry.active === 'boolean';
|
|
99
|
+
}
|
|
13
100
|
export const WEB_HTML = String.raw `<!doctype html>
|
|
14
101
|
<html lang="en">
|
|
15
102
|
<head>
|
|
@@ -65,11 +152,18 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
65
152
|
.entry-card:hover,.entry-card.selected { border-color:#93c5fd; box-shadow:0 8px 20px rgba(37,99,235,.10); }
|
|
66
153
|
.entry-meta { display:flex; gap:7px; align-items:center; flex-wrap:wrap; color:var(--muted); font-size:12px; }
|
|
67
154
|
.badge { border-radius:999px; padding:3px 8px; background:#f1f5f9; color:#475569; font-weight:700; }
|
|
155
|
+
.badge.origin-project { background:#dbeafe; color:#1d4ed8; }
|
|
156
|
+
.badge.origin-ecosystem { background:#dcfce7; color:#166534; }
|
|
157
|
+
.badge.origin-global { background:#fef3c7; color:#92400e; }
|
|
68
158
|
.badge.verified { background:#dcfce7; color:#166534; }
|
|
69
159
|
.badge.candidate { background:#fef3c7; color:#92400e; }
|
|
70
160
|
.badge.superseded { background:#fee2e2; color:#991b1b; }
|
|
71
161
|
.entry-card h3 { margin:9px 0 6px; font-size:16px; }
|
|
72
162
|
.snippet { margin:0; color:var(--muted); display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; white-space:pre-wrap; }
|
|
163
|
+
.federated-card { border-left:4px solid #22c55e; }
|
|
164
|
+
.federated-card.global { border-left-color:#f59e0b; }
|
|
165
|
+
.federated-source,.selection-reasons { margin-top:8px; color:var(--muted); font-size:12px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
166
|
+
.federated-detail { display:grid; gap:12px; }
|
|
73
167
|
.tags { display:flex; gap:6px; flex-wrap:wrap; margin-top:10px; }
|
|
74
168
|
.tag { border:0; background:transparent; color:var(--accent); font-size:12px; padding:0; }
|
|
75
169
|
.tag:hover { text-decoration:underline; }
|
|
@@ -106,19 +200,44 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
106
200
|
.curator-close { display:grid; place-items:center; flex:0 0 auto; width:44px; height:44px; border:1px solid var(--line); border-radius:12px; background:var(--panel); color:var(--muted); font-size:26px; line-height:1; }
|
|
107
201
|
.curator-close:hover { border-color:#93c5fd; background:var(--accent-soft); color:var(--accent); }
|
|
108
202
|
.curator-status { margin:0 0 12px; }
|
|
203
|
+
.curator-filters { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:8px; margin:0 0 14px; padding:12px; border:1px solid var(--line); border-radius:12px; background:var(--surface); }
|
|
204
|
+
.curator-filter { display:grid; gap:4px; color:var(--muted); font-size:11px; font-weight:800; }
|
|
205
|
+
.curator-filter-check { display:flex; align-items:center; gap:6px; color:var(--muted); font-size:12px; font-weight:700; }
|
|
206
|
+
.curator-filter-check input { width:16px; height:16px; }
|
|
207
|
+
.curator-filter-tags { grid-column:1 / -1; display:flex; flex-wrap:wrap; gap:7px; padding-top:4px; }
|
|
208
|
+
.curator-filter-tags .tag.active { font-weight:800; text-decoration:underline; }
|
|
109
209
|
.curator-list { display:grid; gap:12px; }
|
|
110
210
|
.curator-card { border:1px solid var(--line); border-radius:14px; padding:16px; background:var(--panel); }
|
|
111
|
-
.curator-card.selected { border-color:#93c5fd; box-shadow:0 8px 20px rgba(37,99,235,.10); }
|
|
112
|
-
.curator-select { display:flex; gap:8px; align-items:center; color:var(--muted); font-size:13px; font-weight:700; }
|
|
113
|
-
.curator-select input { width:17px; height:17px; accent-color:#2563eb; }
|
|
114
211
|
.curator-workspace { overflow-wrap:anywhere; }
|
|
115
212
|
.curator-card h3 { margin:8px 0; font-size:17px; }
|
|
116
213
|
.curator-overview { margin:8px 0 12px; color:var(--muted); white-space:pre-wrap; line-height:1.55; }
|
|
214
|
+
.curator-card-actions { display:flex; flex-wrap:wrap; gap:8px; margin:12px 0 0; }
|
|
215
|
+
.curator-review-details { margin-top:12px; }
|
|
117
216
|
.curator-draft { margin:12px 0; padding:12px; border:1px solid var(--line); border-radius:12px; background:var(--surface); }
|
|
118
217
|
.curator-draft h4 { margin:0 0 10px; font-size:14px; }
|
|
119
218
|
.curator-draft-label { margin:10px 0 4px; color:var(--muted); font-size:12px; font-weight:700; }
|
|
120
219
|
.curator-draft-value { margin:0; white-space:pre-wrap; overflow-wrap:anywhere; font:inherit; font-size:13px; line-height:1.5; }
|
|
121
220
|
.curator-reasons { color:var(--muted); font-size:12px; white-space:pre-wrap; }
|
|
221
|
+
.curator-confirm-modal { position:absolute; inset:0; z-index:2; display:grid; place-items:center; padding:24px; background:rgba(15,23,42,.58); }
|
|
222
|
+
.curator-confirm-dialog { width:min(680px,calc(100vw - 32px)); max-height:min(760px,calc(100vh - 48px)); display:flex; flex-direction:column; min-height:0; background:var(--panel); box-shadow:0 28px 90px rgba(15,23,42,.34); }
|
|
223
|
+
.curator-confirm-dialog .panel-body { min-height:0; overflow-y:auto; }
|
|
224
|
+
.curator-confirm-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin:0 0 14px; }
|
|
225
|
+
.curator-confirm-field { min-width:0; padding:11px 12px; border:1px solid var(--line); border-radius:12px; background:var(--surface); }
|
|
226
|
+
.curator-confirm-field dt { margin:0 0 5px; color:var(--muted); font-size:12px; font-weight:800; }
|
|
227
|
+
.curator-confirm-field dd { margin:0; overflow-wrap:anywhere; white-space:pre-wrap; }
|
|
228
|
+
.curator-confirm-draft { max-height:280px; overflow:auto; margin:0; padding:12px; border:1px solid var(--line); border-radius:12px; background:var(--surface); white-space:pre-wrap; overflow-wrap:anywhere; font:inherit; font-size:13px; line-height:1.5; }
|
|
229
|
+
.curator-confirm-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:14px; }
|
|
230
|
+
.skill-dialog { width:min(1040px,calc(100vw - 32px)); max-height:min(860px,calc(100vh - 48px)); display:flex; flex-direction:column; min-height:0; background:rgba(255,255,255,.96); box-shadow:0 28px 90px rgba(15,23,42,.28); }
|
|
231
|
+
.skill-dialog .panel-body { min-height:0; overflow-y:auto; }
|
|
232
|
+
.skill-list { display:grid; gap:12px; }
|
|
233
|
+
.skill-card { border:1px solid var(--line); border-radius:14px; padding:16px; background:var(--panel); }
|
|
234
|
+
.skill-card h3 { margin:8px 0; font-size:17px; overflow-wrap:anywhere; }
|
|
235
|
+
.skill-card-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:8px; margin-top:12px; }
|
|
236
|
+
.skill-field { min-width:0; padding:10px 11px; border:1px solid var(--line); border-radius:10px; background:var(--surface); }
|
|
237
|
+
.skill-field dt { margin:0 0 4px; color:var(--muted); font-size:11px; font-weight:800; }
|
|
238
|
+
.skill-field dd { margin:0; overflow-wrap:anywhere; white-space:pre-wrap; font-size:13px; }
|
|
239
|
+
.skill-card-actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
|
|
240
|
+
.skill-source-link { color:var(--accent); overflow-wrap:anywhere; }
|
|
122
241
|
@keyframes curator-backdrop-in { from { opacity:0; } to { opacity:1; } }
|
|
123
242
|
@keyframes curator-backdrop-out { from { opacity:1; } to { opacity:0; } }
|
|
124
243
|
@keyframes curator-dialog-in { from { opacity:0; transform:translateY(10px) scale(.98); } to { opacity:1; transform:translateY(0) scale(1); } }
|
|
@@ -128,7 +247,7 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
128
247
|
}
|
|
129
248
|
@media (max-width:680px) { .operator-grid { grid-template-columns:1fr; } }
|
|
130
249
|
@media (max-width:1050px) { .layout { grid-template-columns:180px minmax(280px,1fr); } .editor-panel { grid-column:1 / -1; } }
|
|
131
|
-
@media (max-width:680px) { .shell { padding:16px; } .topbar { display:block; position:relative; } .brand { padding-right:56px; } .topbar-side { margin-top:16px; align-self:auto; } .language-picker { position:absolute; top:0; right:0; } .toolbar { justify-content:stretch; margin-top:0; } .topbar-side .control,.topbar-side .search { flex:1 1 100%; width:100%; } .search { min-width:0; } .layout { grid-template-columns:1fr; } .genres-panel { order:0; } .list-panel { order:1; } .editor-panel { order:2; } .entry-list { max-height:none; } .curator-dialog-head { flex-wrap:wrap; } .curator-header-actions { flex:1 1 100%; width:100%; margin-left:0; } .curator-actions { justify-content:flex-end; } }
|
|
250
|
+
@media (max-width:680px) { .shell { padding:16px; } .topbar { display:block; position:relative; } .brand { padding-right:56px; } .topbar-side { margin-top:16px; align-self:auto; } .language-picker { position:absolute; top:0; right:0; } .toolbar { justify-content:stretch; margin-top:0; } .topbar-side .control,.topbar-side .search { flex:1 1 100%; width:100%; } .search { min-width:0; } .layout { grid-template-columns:1fr; } .genres-panel { order:0; } .list-panel { order:1; } .editor-panel { order:2; } .entry-list { max-height:none; } .curator-dialog-head { flex-wrap:wrap; } .curator-header-actions { flex:1 1 100%; width:100%; margin-left:0; } .curator-actions { justify-content:flex-end; } .curator-confirm-grid { grid-template-columns:1fr; } .curator-confirm-actions { flex-direction:column-reverse; } .curator-confirm-actions .button { width:100%; } }
|
|
132
251
|
</style>
|
|
133
252
|
</head>
|
|
134
253
|
<body>
|
|
@@ -150,6 +269,7 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
150
269
|
<select id="workspace" class="control" aria-label="Workspace" data-i18n-aria-label="workspaceLabel"></select>
|
|
151
270
|
<input id="search" class="search" type="search" placeholder="Search memory…" aria-label="Search memory…" data-i18n-placeholder="searchPlaceholder" data-i18n-aria-label="searchPlaceholder">
|
|
152
271
|
<button id="curator-button" class="button" type="button" data-i18n="curator">Curator</button>
|
|
272
|
+
<button id="external-skills-button" class="button" type="button" data-i18n="openExternalSkills">External Skills</button>
|
|
153
273
|
<button id="refresh" class="button" type="button" data-i18n="refresh">Refresh</button>
|
|
154
274
|
</div>
|
|
155
275
|
</div>
|
|
@@ -188,14 +308,52 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
188
308
|
</div>
|
|
189
309
|
<div class="panel-body">
|
|
190
310
|
<p id="curator-description" class="subtitle" data-i18n="curatorDescription">Review reusable knowledge candidates and add them to global memory.</p>
|
|
191
|
-
<div id="curator-
|
|
311
|
+
<div id="curator-filters" class="curator-filters" aria-label="Curator filters"></div>
|
|
312
|
+
<div class="curator-selection-summary"><span id="curator-result-count" class="curator-selection-count">0 candidates</span></div>
|
|
192
313
|
<div id="curator-status" class="status" role="status" aria-live="polite"></div>
|
|
193
314
|
<div id="curator-list" class="curator-list"></div>
|
|
194
315
|
</div>
|
|
195
316
|
</section>
|
|
317
|
+
<div id="curator-confirm-modal" class="curator-confirm-modal" hidden>
|
|
318
|
+
<section id="curator-confirm-panel" class="panel curator-confirm-dialog" role="alertdialog" aria-modal="true" aria-labelledby="curator-confirm-title" aria-describedby="curator-confirm-description">
|
|
319
|
+
<div class="panel-head">
|
|
320
|
+
<h2 id="curator-confirm-title" data-i18n="curatorConfirmTitle">Confirm Global memory addition</h2>
|
|
321
|
+
</div>
|
|
322
|
+
<div class="panel-body">
|
|
323
|
+
<p id="curator-confirm-description" class="subtitle" data-i18n="curatorConfirmDescription">Verify the source, applicability, and complete regenerated draft.</p>
|
|
324
|
+
<dl class="curator-confirm-grid">
|
|
325
|
+
<div class="curator-confirm-field"><dt data-i18n="curatorConfirmSource">Source project</dt><dd id="curator-confirm-source"></dd></div>
|
|
326
|
+
<div class="curator-confirm-field"><dt data-i18n="curatorConfirmSkill">Skill</dt><dd id="curator-confirm-skill"></dd></div>
|
|
327
|
+
<div class="curator-confirm-field"><dt data-i18n="curatorConfirmApplicability">Applicability</dt><dd id="curator-confirm-applicability"></dd></div>
|
|
328
|
+
</dl>
|
|
329
|
+
<h3 data-i18n="curatorConfirmDraft">Draft to add</h3>
|
|
330
|
+
<pre id="curator-confirm-draft" class="curator-confirm-draft"></pre>
|
|
331
|
+
<div id="curator-confirm-status" class="status curator-status" role="status" aria-live="polite"></div>
|
|
332
|
+
<div class="curator-confirm-actions">
|
|
333
|
+
<button id="curator-confirm-cancel" class="button" type="button" data-i18n="curatorCancel">Cancel</button>
|
|
334
|
+
<button id="curator-confirm-submit" class="button primary" type="button" data-i18n="curatorConfirmAction">Add this draft to Global</button>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</section>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
<div id="external-skills-modal" class="curator-modal" hidden>
|
|
341
|
+
<section id="external-skills-panel" class="panel skill-dialog" role="dialog" aria-modal="true" aria-labelledby="external-skills-title" aria-describedby="external-skills-description">
|
|
342
|
+
<div class="panel-head curator-dialog-head">
|
|
343
|
+
<div class="curator-heading"><h2 id="external-skills-title" data-i18n="externalSkills">External Skills</h2><span class="badge" data-i18n="trustBadge">stored data is untrusted / non-actionable</span></div>
|
|
344
|
+
<div class="curator-header-actions"><button id="external-skills-refresh" class="button" type="button" data-i18n="externalSkillsRefresh">Refresh</button><button id="external-skills-close" class="curator-close" type="button" aria-label="Close External Skills" data-i18n-aria-label="externalSkillsClose"><span aria-hidden="true">×</span></button></div>
|
|
345
|
+
</div>
|
|
346
|
+
<div class="panel-body">
|
|
347
|
+
<p id="external-skills-description" class="subtitle" data-i18n="externalSkillsDescription">Review fetched skills as untrusted reference data. Nothing here installs software or runs scripts.</p>
|
|
348
|
+
<div id="external-skills-status" class="status" role="status" aria-live="polite"></div>
|
|
349
|
+
<div id="external-skills-list" class="skill-list"></div>
|
|
350
|
+
</div>
|
|
351
|
+
</section>
|
|
196
352
|
</div>
|
|
197
353
|
<script>
|
|
198
354
|
const i18n = ${WEB_I18N_CONFIG};
|
|
355
|
+
const validExternalSkillListItem = (${externalSkillListItemIsValid.toString()});
|
|
356
|
+
const validExternalSkillEntrySummary = (${externalSkillEntrySummaryIsValid.toString()});
|
|
199
357
|
const localeStorageKey = 'kiokuko.web.locale';
|
|
200
358
|
const normalizeLocale = (value) => {
|
|
201
359
|
if (typeof value !== 'string') return null;
|
|
@@ -207,7 +365,14 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
207
365
|
if (language === 'zh' && (parts.length === 1 || parts.includes('hans') || parts.includes('cn') || parts.includes('sg'))) return 'zh-CN';
|
|
208
366
|
return null;
|
|
209
367
|
};
|
|
210
|
-
const
|
|
368
|
+
const isStorageAccessError = (error) => typeof DOMException !== 'undefined' && error instanceof DOMException;
|
|
369
|
+
const readStoredLocale = () => {
|
|
370
|
+
try { return localStorage.getItem(localeStorageKey); }
|
|
371
|
+
catch (error) {
|
|
372
|
+
if (!isStorageAccessError(error)) throw error;
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
};
|
|
211
376
|
const browserLocales = Array.isArray(navigator.languages) ? navigator.languages : [navigator.language];
|
|
212
377
|
const localeCandidates = [new URLSearchParams(location.search).get('lang'), readStoredLocale(), ...browserLocales];
|
|
213
378
|
const initialLocale = localeCandidates.map(normalizeLocale).find(Boolean) || i18n.defaultLocale;
|
|
@@ -217,7 +382,8 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
217
382
|
const botModes = [
|
|
218
383
|
['bot:common', 'bot.common'], ['bot:researcher', 'bot.researcher'], ['bot:builder', 'bot.builder'], ['bot:reviewer', 'bot.reviewer'], ['bot:devops', 'bot.devops'], ['bot:writer', 'bot.writer'], ['bot:analyst', 'bot.analyst']
|
|
219
384
|
];
|
|
220
|
-
const
|
|
385
|
+
const curatorUrl = new URLSearchParams(location.search);
|
|
386
|
+
const state = { locale: initialLocale, workspace: '', kind: 'all', tag: '', query: '', entries: [], recallItems: [], tags: [], selected: null, selectedRecall: null, runs: [], selectedRun: null, curatorCandidates: [], curatorGlobalized: new Set(), curatorNextCursor: null, curatorTotalApproximate: 0, curatorOpen: false, curatorPreviousFocus: null, curatorPendingCandidate: null, curatorConfirmationTrigger: null, curatorGlobalizeBusy: false, externalSkills: [], externalSkillsOpen: false, externalSkillsPreviousFocus: null, externalSkillsBusy: false, externalSkillsPendingDisable: null, localizedStatus: null, curatorSearch: curatorUrl.get('search') || '', curatorProject: curatorUrl.get('project') || '', curatorTags: new Set(curatorUrl.getAll('tag')), curatorFramework: curatorUrl.get('framework') || '', curatorLanguage: curatorUrl.get('language') || '', curatorMemoryClass: curatorUrl.get('memoryClass') || '', curatorTier: curatorUrl.get('tier') || '', curatorReady: curatorUrl.get('ready') === 'true', curatorIncludeGlobalized: curatorUrl.get('includeGlobalized') === 'true', curatorFacets: null };
|
|
221
387
|
const $ = (id) => document.getElementById(id);
|
|
222
388
|
const t = (key, parameters = {}) => {
|
|
223
389
|
const template = i18n.messages[state.locale]?.[key] ?? i18n.messages[i18n.defaultLocale]?.[key] ?? key;
|
|
@@ -230,6 +396,7 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
230
396
|
const setI18nText = (element, key) => { element.dataset.i18n = key; element.textContent = t(key); return element; };
|
|
231
397
|
const labelForKind = (kind) => { const item = kinds.find(([value]) => value === kind); return item ? t(item[1]) : kind; };
|
|
232
398
|
const labelForStatus = (status) => i18n.messages[state.locale]?.['status.' + status] ?? status;
|
|
399
|
+
const labelForOrigin = (origin) => t(origin === 'ecosystem' ? 'originEcosystem' : origin === 'global' ? 'originGlobal' : 'originProject');
|
|
233
400
|
const updateEditorState = () => {
|
|
234
401
|
const element = $('editor-state');
|
|
235
402
|
if (state.selected) { delete element.dataset.i18n; element.dataset.i18nStatus = state.selected.status; element.textContent = labelForStatus(state.selected.status); }
|
|
@@ -264,9 +431,10 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
264
431
|
};
|
|
265
432
|
const selectLocale = (value) => {
|
|
266
433
|
state.locale = normalizeLocale(value) || i18n.defaultLocale;
|
|
267
|
-
try { localStorage.setItem(localeStorageKey, state.locale); }
|
|
434
|
+
try { localStorage.setItem(localeStorageKey, state.locale); }
|
|
435
|
+
catch (error) { if (!isStorageAccessError(error)) throw error; }
|
|
268
436
|
setLanguageMenuOpen(false, true);
|
|
269
|
-
applyTranslations(); renderFilters(); renderEntries(); renderRuns(); renderRunDetail(); renderCurator(); updateEditorState();
|
|
437
|
+
applyTranslations(); renderFilters(); renderEntries(); renderRuns(); renderRunDetail(); renderCurator(); renderExternalSkills(); updateEditorState();
|
|
270
438
|
};
|
|
271
439
|
const applyTranslations = () => {
|
|
272
440
|
document.documentElement.lang = state.locale;
|
|
@@ -280,10 +448,24 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
280
448
|
renderLanguageMenu();
|
|
281
449
|
if (state.localizedStatus) showStatus(state.localizedStatus.plural ? tp(state.localizedStatus.key, state.localizedStatus.count) : t(state.localizedStatus.key, state.localizedStatus.parameters), state.localizedStatus.error);
|
|
282
450
|
};
|
|
451
|
+
const apiError = (value) => {
|
|
452
|
+
const rawCode = value?.error?.code;
|
|
453
|
+
const rawMessage = value?.error?.message;
|
|
454
|
+
const code = typeof rawCode === 'string' && /^[A-Z][A-Z0-9_]{0,63}$/.test(rawCode) ? rawCode : 'REQUEST_FAILED';
|
|
455
|
+
const normalizedMessage = typeof rawMessage === 'string' ? rawMessage.replace(/[\u0000-\u001f\u007f]+/g, ' ').trim().slice(0, 300) : '';
|
|
456
|
+
const error = new Error(normalizedMessage || t('requestFailed'));
|
|
457
|
+
error.code = code;
|
|
458
|
+
return error;
|
|
459
|
+
};
|
|
460
|
+
const apiErrorText = (error) => {
|
|
461
|
+
const code = error instanceof Error && typeof error.code === 'string' && /^[A-Z][A-Z0-9_]{0,63}$/.test(error.code) ? error.code : 'REQUEST_FAILED';
|
|
462
|
+
const normalizedMessage = error instanceof Error ? error.message.replace(/[\u0000-\u001f\u007f]+/g, ' ').trim().slice(0, 300) : '';
|
|
463
|
+
return '[' + code + '] ' + (normalizedMessage || t('requestFailed'));
|
|
464
|
+
};
|
|
283
465
|
const api = async (path, options) => {
|
|
284
466
|
const response = await fetch(path, options);
|
|
285
467
|
const value = await response.json();
|
|
286
|
-
if (!response.ok) throw
|
|
468
|
+
if (!response.ok) throw apiError(value);
|
|
287
469
|
return value;
|
|
288
470
|
};
|
|
289
471
|
const escapeTags = (value) => value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
@@ -298,6 +480,55 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
298
480
|
if (blocked) appMain.setAttribute('aria-hidden', 'true');
|
|
299
481
|
else appMain.removeAttribute('aria-hidden');
|
|
300
482
|
};
|
|
483
|
+
function restoreCuratorUrl() {
|
|
484
|
+
const params = new URLSearchParams(location.search);
|
|
485
|
+
state.curatorSearch = params.get('search') || '';
|
|
486
|
+
state.curatorProject = params.get('project') || '';
|
|
487
|
+
state.curatorTags = new Set(params.getAll('tag'));
|
|
488
|
+
state.curatorFramework = params.get('framework') || '';
|
|
489
|
+
state.curatorLanguage = params.get('language') || '';
|
|
490
|
+
state.curatorMemoryClass = params.get('memoryClass') || '';
|
|
491
|
+
state.curatorTier = params.get('tier') || '';
|
|
492
|
+
state.curatorReady = params.get('ready') === 'true';
|
|
493
|
+
state.curatorIncludeGlobalized = params.get('includeGlobalized') === 'true';
|
|
494
|
+
}
|
|
495
|
+
function syncCuratorUrl(push = false) {
|
|
496
|
+
const params = new URLSearchParams(location.search);
|
|
497
|
+
for (const key of ['search', 'project', 'framework', 'language', 'memoryClass', 'tier', 'ready', 'includeGlobalized', 'tag']) params.delete(key);
|
|
498
|
+
if (state.curatorSearch) params.set('search', state.curatorSearch);
|
|
499
|
+
if (state.curatorProject) params.set('project', state.curatorProject);
|
|
500
|
+
if (state.curatorFramework) params.set('framework', state.curatorFramework);
|
|
501
|
+
if (state.curatorLanguage) params.set('language', state.curatorLanguage);
|
|
502
|
+
if (state.curatorMemoryClass) params.set('memoryClass', state.curatorMemoryClass);
|
|
503
|
+
if (state.curatorTier) params.set('tier', state.curatorTier);
|
|
504
|
+
if (state.curatorReady) params.set('ready', 'true');
|
|
505
|
+
if (state.curatorIncludeGlobalized) params.set('includeGlobalized', 'true');
|
|
506
|
+
for (const tag of state.curatorTags) params.append('tag', tag);
|
|
507
|
+
const nextUrl = location.pathname + (params.toString() ? '?' + params.toString() : '');
|
|
508
|
+
if (push) history.pushState(null, '', nextUrl); else history.replaceState(null, '', nextUrl);
|
|
509
|
+
}
|
|
510
|
+
function curatorFilterSelect(label, values, value, onChange) {
|
|
511
|
+
const wrapper = document.createElement('label'); wrapper.className = 'curator-filter';
|
|
512
|
+
const text = document.createElement('span'); text.textContent = label;
|
|
513
|
+
const select = document.createElement('select');
|
|
514
|
+
const all = document.createElement('option'); all.value = ''; all.textContent = 'All'; select.append(all);
|
|
515
|
+
for (const item of values || []) { const option = document.createElement('option'); option.value = item.value || item.workspace; option.textContent = item.name || item.value || item.workspace; select.append(option); }
|
|
516
|
+
select.value = value || ''; select.addEventListener('change', () => onChange(select.value)); wrapper.append(text, select); return wrapper;
|
|
517
|
+
}
|
|
518
|
+
function renderCuratorFilters() {
|
|
519
|
+
const root = $('curator-filters'); if (!root) return;
|
|
520
|
+
const facets = state.curatorFacets || {};
|
|
521
|
+
const search = document.createElement('input'); search.type = 'search'; search.placeholder = 'Search candidates'; search.value = state.curatorSearch; search.addEventListener('input', () => { state.curatorSearch = search.value.trim(); clearTimeout(state.curatorSearchTimer); state.curatorSearchTimer = setTimeout(() => { syncCuratorUrl(true); loadCurator(); }, 180); });
|
|
522
|
+
const project = curatorFilterSelect('Project', facets.projects, state.curatorProject, (value) => { state.curatorProject = value; syncCuratorUrl(true); loadCurator(); });
|
|
523
|
+
const framework = curatorFilterSelect('Framework', facets.frameworks, state.curatorFramework, (value) => { state.curatorFramework = value; syncCuratorUrl(true); loadCurator(); });
|
|
524
|
+
const language = curatorFilterSelect('Language', facets.languages, state.curatorLanguage, (value) => { state.curatorLanguage = value; syncCuratorUrl(true); loadCurator(); });
|
|
525
|
+
const memoryClass = curatorFilterSelect('Memory class', facets.memoryClasses, state.curatorMemoryClass, (value) => { state.curatorMemoryClass = value; syncCuratorUrl(true); loadCurator(); });
|
|
526
|
+
const readiness = curatorFilterSelect('Readiness', [{ value: 'portable', name: 'Portable' }, { value: 'repeated', name: 'Repeated' }, { value: 'observed', name: 'Observed' }], state.curatorTier, (value) => { state.curatorTier = value; syncCuratorUrl(true); loadCurator(); });
|
|
527
|
+
const ready = document.createElement('label'); ready.className = 'curator-filter-check'; const readyInput = document.createElement('input'); readyInput.type = 'checkbox'; readyInput.checked = state.curatorReady; readyInput.addEventListener('change', () => { state.curatorReady = readyInput.checked; syncCuratorUrl(true); loadCurator(); }); ready.append(readyInput, document.createTextNode('Skill-ready'));
|
|
528
|
+
const globalized = document.createElement('label'); globalized.className = 'curator-filter-check'; const globalizedInput = document.createElement('input'); globalizedInput.type = 'checkbox'; globalizedInput.checked = state.curatorIncludeGlobalized; globalizedInput.addEventListener('change', () => { state.curatorIncludeGlobalized = globalizedInput.checked; syncCuratorUrl(true); loadCurator(); }); globalized.append(globalizedInput, document.createTextNode('Show already globalized'));
|
|
529
|
+
const tags = document.createElement('div'); tags.className = 'curator-filter-tags'; for (const facet of facets.tags || []) { const button = document.createElement('button'); button.type = 'button'; button.className = 'tag' + (state.curatorTags.has(facet.value) ? ' active' : ''); button.textContent = '#' + facet.value + ' (' + facet.count + ')'; button.addEventListener('click', () => { if (state.curatorTags.has(facet.value)) state.curatorTags.delete(facet.value); else state.curatorTags.add(facet.value); syncCuratorUrl(true); loadCurator(); }); tags.append(button); }
|
|
530
|
+
root.replaceChildren(search, project, framework, language, memoryClass, readiness, ready, globalized, tags);
|
|
531
|
+
}
|
|
301
532
|
function openCurator() {
|
|
302
533
|
if (state.curatorOpen) { $('curator-close')?.focus(); return; }
|
|
303
534
|
state.curatorPreviousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
@@ -309,6 +540,8 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
309
540
|
requestAnimationFrame(() => $('curator-close')?.focus());
|
|
310
541
|
}
|
|
311
542
|
function closeCurator() {
|
|
543
|
+
if (state.curatorGlobalizeBusy) return;
|
|
544
|
+
if (state.curatorPendingCandidate) closeCuratorConfirmation(false);
|
|
312
545
|
const modal = $('curator-modal');
|
|
313
546
|
if (modal.hidden) return;
|
|
314
547
|
state.curatorOpen = false;
|
|
@@ -340,6 +573,242 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
340
573
|
else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
|
|
341
574
|
}
|
|
342
575
|
|
|
576
|
+
const setExternalSkillsStatus = (message, error = false) => {
|
|
577
|
+
const element = $('external-skills-status');
|
|
578
|
+
element.textContent = message;
|
|
579
|
+
element.className = error ? 'status notice error curator-status' : 'status curator-status';
|
|
580
|
+
};
|
|
581
|
+
function openExternalSkills() {
|
|
582
|
+
if (state.externalSkillsOpen) { $('external-skills-close')?.focus(); return; }
|
|
583
|
+
state.externalSkillsPreviousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
584
|
+
state.externalSkillsOpen = true;
|
|
585
|
+
const modal = $('external-skills-modal');
|
|
586
|
+
modal.classList.remove('is-closing');
|
|
587
|
+
setCuratorBackgroundBlocked(true);
|
|
588
|
+
modal.hidden = false;
|
|
589
|
+
requestAnimationFrame(() => $('external-skills-close')?.focus());
|
|
590
|
+
}
|
|
591
|
+
function closeExternalSkills() {
|
|
592
|
+
if (state.externalSkillsBusy) return;
|
|
593
|
+
const modal = $('external-skills-modal');
|
|
594
|
+
if (modal.hidden) return;
|
|
595
|
+
state.externalSkillsOpen = false;
|
|
596
|
+
state.externalSkillsPendingDisable = null;
|
|
597
|
+
modal.classList.add('is-closing');
|
|
598
|
+
let finished = false;
|
|
599
|
+
const finish = () => {
|
|
600
|
+
if (finished) return;
|
|
601
|
+
finished = true;
|
|
602
|
+
modal.hidden = true;
|
|
603
|
+
modal.classList.remove('is-closing');
|
|
604
|
+
setCuratorBackgroundBlocked(false);
|
|
605
|
+
const previousFocus = state.externalSkillsPreviousFocus;
|
|
606
|
+
state.externalSkillsPreviousFocus = null;
|
|
607
|
+
if (previousFocus?.isConnected) previousFocus.focus(); else $('external-skills-button')?.focus();
|
|
608
|
+
};
|
|
609
|
+
modal.addEventListener('animationend', (event) => { if (event.target === modal) finish(); }, { once: true });
|
|
610
|
+
window.setTimeout(finish, 220);
|
|
611
|
+
}
|
|
612
|
+
function handleExternalSkillsKeydown(event) {
|
|
613
|
+
if (event.key === 'Escape') { event.preventDefault(); closeExternalSkills(); return; }
|
|
614
|
+
if (event.key !== 'Tab') return;
|
|
615
|
+
const modal = $('external-skills-modal');
|
|
616
|
+
const focusable = [...modal.querySelectorAll('button:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])')];
|
|
617
|
+
if (!focusable.length) { event.preventDefault(); return; }
|
|
618
|
+
const first = focusable[0]; const last = focusable.at(-1);
|
|
619
|
+
if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
|
|
620
|
+
else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
|
|
621
|
+
}
|
|
622
|
+
function skillField(labelKey, value) {
|
|
623
|
+
const field = document.createElement('div'); field.className = 'skill-field';
|
|
624
|
+
const label = document.createElement('dt'); setI18nText(label, labelKey);
|
|
625
|
+
const content = document.createElement('dd'); content.textContent = value || t('unknown');
|
|
626
|
+
field.append(label, content); return field;
|
|
627
|
+
}
|
|
628
|
+
function externalSkillButton(attribute, skillId) {
|
|
629
|
+
return [...document.querySelectorAll('[' + attribute + ']')].find((element) => element.getAttribute(attribute) === skillId);
|
|
630
|
+
}
|
|
631
|
+
function externalSkillSourceUrl(skill) {
|
|
632
|
+
return /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/.test(skill.sourceLocator) ? 'https://github.com/' + skill.sourceLocator : null;
|
|
633
|
+
}
|
|
634
|
+
function renderExternalSkills() {
|
|
635
|
+
if (!state.externalSkillsOpen) return;
|
|
636
|
+
const root = $('external-skills-list');
|
|
637
|
+
if (!state.externalSkills.length) { const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'externalSkillsEmpty'); root.replaceChildren(empty); return; }
|
|
638
|
+
root.replaceChildren(...state.externalSkills.map((skill) => {
|
|
639
|
+
const card = document.createElement('article'); card.className = 'skill-card';
|
|
640
|
+
const meta = document.createElement('div'); meta.className = 'entry-meta';
|
|
641
|
+
const stateBadge = document.createElement('span'); stateBadge.className = 'badge ' + (skill.state === 'disabled' ? 'superseded' : skill.state === 'imported' ? 'verified' : 'candidate'); stateBadge.textContent = skill.state;
|
|
642
|
+
const official = document.createElement('span'); official.className = 'badge'; official.textContent = skill.officialStatus;
|
|
643
|
+
meta.append(stateBadge, official);
|
|
644
|
+
const heading = document.createElement('h3'); heading.textContent = skill.name;
|
|
645
|
+
const fields = document.createElement('dl'); fields.className = 'skill-card-grid';
|
|
646
|
+
fields.append(
|
|
647
|
+
skillField('externalSkillsSource', skill.sourceLocator + '/' + skill.slug),
|
|
648
|
+
skillField('externalSkillsCommit', skill.sourceCommit ? skill.sourceCommit.slice(0, 12) : null),
|
|
649
|
+
skillField('externalSkillsSnapshot', skill.snapshotHash ? skill.snapshotHash.slice(0, 12) : null),
|
|
650
|
+
skillField('externalSkillsDocuments', String(skill.metadata?.documents ?? 0)),
|
|
651
|
+
skillField('externalSkillsFirstSeen', skill.firstSeenAt),
|
|
652
|
+
skillField('externalSkillsLastChecked', skill.lastCheckedAt),
|
|
653
|
+
skillField('externalSkillsTechnology', skill.metadata?.technology ?? skill.name),
|
|
654
|
+
skillField('externalSkillsAudit', skill.auditStatus),
|
|
655
|
+
skillField('externalSkillsState', skill.state),
|
|
656
|
+
);
|
|
657
|
+
const notice = document.createElement('div'); notice.className = 'notice'; setI18nText(notice, 'externalSkillsUntrusted');
|
|
658
|
+
const actions = document.createElement('div'); actions.className = 'skill-card-actions';
|
|
659
|
+
const sourceUrl = externalSkillSourceUrl(skill);
|
|
660
|
+
if (sourceUrl) { const source = document.createElement('a'); source.className = 'button'; source.href = sourceUrl; source.target = '_blank'; source.rel = 'noopener noreferrer'; setI18nText(source, 'externalSkillsSourceUrl'); actions.append(source); }
|
|
661
|
+
const refresh = document.createElement('button'); refresh.type = 'button'; refresh.className = 'button'; refresh.setAttribute('data-external-skill-refresh', skill.skillId); setI18nText(refresh, 'externalSkillsRefresh'); refresh.disabled = state.externalSkillsBusy; refresh.addEventListener('click', () => externalSkillAction(skill.skillId, 'refresh')); actions.append(refresh);
|
|
662
|
+
const action = skill.state === 'disabled' ? 'enable' : skill.state === 'imported' ? 'disable' : null;
|
|
663
|
+
if (action === 'disable' && state.externalSkillsPendingDisable === skill.skillId) {
|
|
664
|
+
const confirmation = document.createElement('div'); confirmation.className = 'notice'; confirmation.textContent = t('externalSkillsDisableConfirm');
|
|
665
|
+
const confirm = document.createElement('button'); confirm.type = 'button'; confirm.className = 'button primary'; confirm.setAttribute('data-external-skill-confirm', skill.skillId); setI18nText(confirm, 'externalSkillsDisable'); confirm.disabled = state.externalSkillsBusy; confirm.addEventListener('click', () => externalSkillAction(skill.skillId, action, true));
|
|
666
|
+
const cancel = document.createElement('button'); cancel.type = 'button'; cancel.className = 'button'; setI18nText(cancel, 'curatorCancel'); cancel.disabled = state.externalSkillsBusy; cancel.addEventListener('click', () => { state.externalSkillsPendingDisable = null; renderExternalSkills(); requestAnimationFrame(() => externalSkillButton('data-external-skill-toggle', skill.skillId)?.focus()); });
|
|
667
|
+
actions.append(confirmation, confirm, cancel);
|
|
668
|
+
} else if (action !== null) {
|
|
669
|
+
const toggle = document.createElement('button'); toggle.type = 'button'; toggle.className = 'button primary'; toggle.setAttribute('data-external-skill-toggle', skill.skillId); setI18nText(toggle, action === 'enable' ? 'externalSkillsEnable' : 'externalSkillsDisable'); toggle.disabled = state.externalSkillsBusy; toggle.addEventListener('click', () => externalSkillAction(skill.skillId, action)); actions.append(toggle);
|
|
670
|
+
}
|
|
671
|
+
const mapping = document.createElement('div'); mapping.className = 'detail-text'; mapping.hidden = true;
|
|
672
|
+
const viewEntries = document.createElement('button'); viewEntries.type = 'button'; viewEntries.className = 'button'; viewEntries.setAttribute('aria-expanded', 'false'); setI18nText(viewEntries, 'externalSkillsViewEntries'); viewEntries.disabled = state.externalSkillsBusy; viewEntries.addEventListener('click', async () => {
|
|
673
|
+
viewEntries.disabled = true;
|
|
674
|
+
try {
|
|
675
|
+
const detail = externalSkillDetail(await api('/api/skills/' + encodeURIComponent(skill.skillId)), skill.skillId);
|
|
676
|
+
if (detail === null) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
677
|
+
const entries = detail.entries;
|
|
678
|
+
mapping.textContent = entries.length ? entries.map((entry) => entry.sourcePath + '#' + entry.chunkIndex + ' → ' + entry.entryId + '@' + entry.revision + (entry.active ? '' : ' (inactive)')).join('\n') : t('externalSkillsNoEntries');
|
|
679
|
+
mapping.hidden = false;
|
|
680
|
+
viewEntries.setAttribute('aria-expanded', 'true');
|
|
681
|
+
} catch {
|
|
682
|
+
mapping.textContent = '';
|
|
683
|
+
mapping.hidden = true;
|
|
684
|
+
viewEntries.setAttribute('aria-expanded', 'false');
|
|
685
|
+
setExternalSkillsStatus(t('externalSkillsFailure'), true);
|
|
686
|
+
}
|
|
687
|
+
finally { viewEntries.disabled = state.externalSkillsBusy; }
|
|
688
|
+
});
|
|
689
|
+
actions.append(viewEntries);
|
|
690
|
+
card.append(meta, heading, fields, notice, actions, mapping); return card;
|
|
691
|
+
}));
|
|
692
|
+
}
|
|
693
|
+
async function reloadExternalSkills() {
|
|
694
|
+
const skills = [];
|
|
695
|
+
const skillIds = new Set();
|
|
696
|
+
const cursors = new Set();
|
|
697
|
+
let cursor = null;
|
|
698
|
+
for (let page = 0; page < 100; page += 1) {
|
|
699
|
+
const result = await api('/api/skills?limit=200' + (cursor === null ? '' : '&cursor=' + encodeURIComponent(cursor)));
|
|
700
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)
|
|
701
|
+
|| Object.keys(result).length !== 5
|
|
702
|
+
|| result.untrusted !== true
|
|
703
|
+
|| !Array.isArray(result.skills) || result.skills.length > 200
|
|
704
|
+
|| !Number.isSafeInteger(result.count) || result.count !== result.skills.length
|
|
705
|
+
|| typeof result.truncated !== 'boolean'
|
|
706
|
+
|| result.nextCursor !== null && typeof result.nextCursor !== 'string') throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
707
|
+
if (skills.length + result.skills.length > 20_000) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
708
|
+
for (const skill of result.skills) {
|
|
709
|
+
if (!validExternalSkillListItem(skill) || skillIds.has(skill.skillId)) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
710
|
+
skillIds.add(skill.skillId); skills.push(skill);
|
|
711
|
+
}
|
|
712
|
+
if (!result.truncated) {
|
|
713
|
+
if (result.nextCursor !== null) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
714
|
+
state.externalSkills = skills;
|
|
715
|
+
renderExternalSkills();
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
if (result.skills.length === 0 || typeof result.nextCursor !== 'string' || result.nextCursor.length === 0 || cursors.has(result.nextCursor)) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
719
|
+
cursors.add(result.nextCursor); cursor = result.nextCursor;
|
|
720
|
+
}
|
|
721
|
+
throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
722
|
+
}
|
|
723
|
+
function externalSkillDetail(result, expectedSkillId) {
|
|
724
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)
|
|
725
|
+
|| Object.keys(result).length !== 4 || result.untrusted !== true
|
|
726
|
+
|| !validExternalSkillListItem(result.skill) || result.skill.skillId !== expectedSkillId
|
|
727
|
+
|| !Array.isArray(result.entries) || result.entries.length > 200
|
|
728
|
+
|| typeof result.entriesTruncated !== 'boolean'
|
|
729
|
+
|| result.entriesTruncated && result.entries.length !== 200
|
|
730
|
+
|| result.skill.sourceCommit === null && result.entries.length !== 0) return null;
|
|
731
|
+
const entryIds = new Set(); const mappingIds = new Set();
|
|
732
|
+
for (const entry of result.entries) {
|
|
733
|
+
const mappingId = validExternalSkillEntrySummary(entry) ? entry.sourcePath + '\u0000' + entry.chunkIndex : null;
|
|
734
|
+
if (mappingId === null || entryIds.has(entry.entryId) || mappingIds.has(mappingId)) return null;
|
|
735
|
+
entryIds.add(entry.entryId); mappingIds.add(mappingId);
|
|
736
|
+
}
|
|
737
|
+
return { skill: result.skill, entries: result.entries, entriesTruncated: result.entriesTruncated };
|
|
738
|
+
}
|
|
739
|
+
async function reloadExternalSkill(skillId) {
|
|
740
|
+
const detail = externalSkillDetail(await api('/api/skills/' + encodeURIComponent(skillId)), skillId);
|
|
741
|
+
if (detail === null) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
742
|
+
const index = state.externalSkills.findIndex((skill) => skill.skillId === skillId);
|
|
743
|
+
if (index < 0) throw apiError({ error: { code: 'INVALID_RESPONSE', message: t('requestFailed') } });
|
|
744
|
+
state.externalSkills[index] = detail.skill;
|
|
745
|
+
renderExternalSkills();
|
|
746
|
+
}
|
|
747
|
+
async function externalSkillAction(skillId, action, confirmed = false) {
|
|
748
|
+
if (state.externalSkillsBusy) return;
|
|
749
|
+
if (action === 'disable' && !confirmed) { state.externalSkillsPendingDisable = skillId; renderExternalSkills(); requestAnimationFrame(() => externalSkillButton('data-external-skill-confirm', skillId)?.focus()); return; }
|
|
750
|
+
state.externalSkillsPendingDisable = null;
|
|
751
|
+
state.externalSkillsBusy = true;
|
|
752
|
+
$('external-skills-refresh').disabled = true;
|
|
753
|
+
$('external-skills-panel').setAttribute('aria-busy', 'true');
|
|
754
|
+
setExternalSkillsStatus(action === 'refresh' ? t('externalSkillsRefreshing') : t('externalSkillsLoading'));
|
|
755
|
+
renderExternalSkills();
|
|
756
|
+
try {
|
|
757
|
+
let actionError = null;
|
|
758
|
+
try {
|
|
759
|
+
await api('/api/skills/' + encodeURIComponent(skillId) + '/' + action, { method: 'POST' });
|
|
760
|
+
} catch (error) {
|
|
761
|
+
actionError = error;
|
|
762
|
+
}
|
|
763
|
+
let reloadError = null;
|
|
764
|
+
try {
|
|
765
|
+
await reloadExternalSkill(skillId);
|
|
766
|
+
} catch (error) {
|
|
767
|
+
reloadError = error;
|
|
768
|
+
}
|
|
769
|
+
if (reloadError) {
|
|
770
|
+
state.externalSkills = [];
|
|
771
|
+
state.externalSkillsPendingDisable = null;
|
|
772
|
+
}
|
|
773
|
+
if (actionError) {
|
|
774
|
+
const reloadFailure = reloadError ? ' / ' + apiErrorText(reloadError) : '';
|
|
775
|
+
setExternalSkillsStatus(apiErrorText(actionError) + reloadFailure, true);
|
|
776
|
+
} else if (reloadError) {
|
|
777
|
+
setExternalSkillsStatus(apiErrorText(reloadError), true);
|
|
778
|
+
} else {
|
|
779
|
+
setExternalSkillsStatus(t(action === 'disable' ? 'externalSkillsDisabled' : action === 'enable' ? 'externalSkillsEnabled' : 'externalSkillsRefreshed'));
|
|
780
|
+
}
|
|
781
|
+
} finally {
|
|
782
|
+
state.externalSkillsBusy = false;
|
|
783
|
+
$('external-skills-refresh').disabled = false;
|
|
784
|
+
$('external-skills-panel').removeAttribute('aria-busy');
|
|
785
|
+
renderExternalSkills();
|
|
786
|
+
requestAnimationFrame(() => externalSkillButton(action === 'refresh' ? 'data-external-skill-refresh' : 'data-external-skill-toggle', skillId)?.focus());
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
async function loadExternalSkills(open = true) {
|
|
790
|
+
if (state.externalSkillsBusy) return;
|
|
791
|
+
if (open) openExternalSkills();
|
|
792
|
+
state.externalSkills = [];
|
|
793
|
+
state.externalSkillsPendingDisable = null;
|
|
794
|
+
state.externalSkillsBusy = true;
|
|
795
|
+
$('external-skills-refresh').disabled = true;
|
|
796
|
+
renderExternalSkills();
|
|
797
|
+
setExternalSkillsStatus(t('externalSkillsLoading'));
|
|
798
|
+
$('external-skills-panel').setAttribute('aria-busy', 'true');
|
|
799
|
+
try {
|
|
800
|
+
await reloadExternalSkills();
|
|
801
|
+
setExternalSkillsStatus('');
|
|
802
|
+
} catch (error) {
|
|
803
|
+
setExternalSkillsStatus(t('externalSkillsOffline') + ' ' + apiErrorText(error), true);
|
|
804
|
+
} finally {
|
|
805
|
+
$('external-skills-panel').removeAttribute('aria-busy');
|
|
806
|
+
state.externalSkillsBusy = false;
|
|
807
|
+
$('external-skills-refresh').disabled = false;
|
|
808
|
+
renderExternalSkills();
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
343
812
|
function filterButton(key, label, count, active, onClick) {
|
|
344
813
|
const button = document.createElement('button');
|
|
345
814
|
button.type = 'button';
|
|
@@ -369,10 +838,34 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
369
838
|
if (tagButtons.length > 0) root.append(filterGroup(t('crossTagFilterTitle'), tagButtons));
|
|
370
839
|
}
|
|
371
840
|
|
|
841
|
+
function renderFederatedItems() {
|
|
842
|
+
const list = $('entry-list');
|
|
843
|
+
list.replaceChildren(...state.recallItems.map((item) => {
|
|
844
|
+
const card = document.createElement('article'); card.className = 'entry-card federated-card ' + (item.origin === 'global' ? 'global' : '');
|
|
845
|
+
const meta = document.createElement('div'); meta.className = 'entry-meta';
|
|
846
|
+
const origin = document.createElement('span'); origin.className = 'badge origin-' + item.origin; origin.textContent = labelForOrigin(item.origin);
|
|
847
|
+
const kind = document.createElement('span'); kind.className = 'badge'; kind.textContent = labelForKind(item.kind);
|
|
848
|
+
const status = document.createElement('span'); status.className = 'badge ' + item.status; status.textContent = labelForStatus(item.status);
|
|
849
|
+
meta.append(origin, kind, status);
|
|
850
|
+
const title = document.createElement('h3'); title.textContent = item.title;
|
|
851
|
+
const snippet = document.createElement('p'); snippet.className = 'snippet'; snippet.textContent = item.snippet;
|
|
852
|
+
const source = document.createElement('div'); source.className = 'federated-source';
|
|
853
|
+
const sourceLines = [];
|
|
854
|
+
if (item.sourceWorkspace) sourceLines.push(t('sourceWorkspace', { workspace: item.sourceWorkspace }));
|
|
855
|
+
if (item.sourceProject) sourceLines.push(t('sourceProject', { project: item.sourceProject }));
|
|
856
|
+
source.textContent = sourceLines.join('\n');
|
|
857
|
+
const tags = document.createElement('div'); tags.className = 'tags'; item.tags.forEach((tag) => { const tagItem = document.createElement('span'); tagItem.className = 'tag'; tagItem.textContent = '#' + tag; tags.append(tagItem); });
|
|
858
|
+
const reasons = document.createElement('div'); reasons.className = 'selection-reasons'; reasons.textContent = [t('selectionReasons'), ...item.selectionReasons.map((reason) => '• ' + reason)].join('\n');
|
|
859
|
+
card.append(meta, title, snippet, source, tags, reasons); card.addEventListener('click', () => { state.selected = null; state.selectedRecall = item; renderEntries(); renderEditor(); }); return card;
|
|
860
|
+
}));
|
|
861
|
+
}
|
|
862
|
+
|
|
372
863
|
function renderEntries() {
|
|
373
|
-
|
|
374
|
-
$('
|
|
864
|
+
const displayed = state.recallItems.length > 0 ? state.recallItems.length : state.entries.length;
|
|
865
|
+
$('result-count').textContent = tp('entryCount', displayed);
|
|
866
|
+
$('list-title').textContent = state.recallItems.length > 0 ? t('entriesTitle') : (state.tag ? '#' + state.tag : (state.kind === 'all' ? t('entriesTitle') : labelForKind(state.kind)));
|
|
375
867
|
const list = $('entry-list');
|
|
868
|
+
if (state.recallItems.length > 0) { renderFederatedItems(); return; }
|
|
376
869
|
if (!state.entries.length) {
|
|
377
870
|
const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'noEntries'); list.replaceChildren(empty); return;
|
|
378
871
|
}
|
|
@@ -390,7 +883,26 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
390
883
|
}));
|
|
391
884
|
}
|
|
392
885
|
|
|
886
|
+
function renderFederatedDetail() {
|
|
887
|
+
const editor = $('editor'); const item = state.selectedRecall;
|
|
888
|
+
if (!item) return;
|
|
889
|
+
const origin = document.createElement('span'); origin.className = 'badge origin-' + item.origin; origin.textContent = labelForOrigin(item.origin);
|
|
890
|
+
const heading = document.createElement('h3'); heading.textContent = item.title;
|
|
891
|
+
const meta = document.createElement('div'); meta.className = 'entry-meta'; meta.append(origin);
|
|
892
|
+
if (item.sourceWorkspace) { const source = document.createElement('span'); source.className = 'badge'; source.textContent = t('sourceWorkspace', { workspace: item.sourceWorkspace }); meta.append(source); }
|
|
893
|
+
if (item.sourceProject) { const source = document.createElement('span'); source.className = 'badge'; source.textContent = t('sourceProject', { project: item.sourceProject }); meta.append(source); }
|
|
894
|
+
const notice = document.createElement('div'); notice.className = 'notice'; notice.textContent = t('federatedReadOnly');
|
|
895
|
+
const detail = document.createElement('div'); detail.className = 'federated-detail';
|
|
896
|
+
const snippet = document.createElement('div'); snippet.className = 'detail-text'; snippet.textContent = item.snippet;
|
|
897
|
+
const reasons = detailBlock('selectionReasons', item.selectionReasons.join('\n'));
|
|
898
|
+
const tags = detailBlock('commaSeparatedTags', item.tags.map((tag) => '#' + tag).join(' '));
|
|
899
|
+
detail.append(snippet, reasons, tags);
|
|
900
|
+
const stateBadge = $('editor-state'); delete stateBadge.dataset.i18n; delete stateBadge.dataset.i18nStatus; stateBadge.textContent = labelForOrigin(item.origin);
|
|
901
|
+
editor.replaceChildren(meta, heading, notice, detail);
|
|
902
|
+
}
|
|
903
|
+
|
|
393
904
|
function renderEditor() {
|
|
905
|
+
if (state.selectedRecall) { renderFederatedDetail(); return; }
|
|
394
906
|
const editor = $('editor');
|
|
395
907
|
const entry = state.selected;
|
|
396
908
|
updateEditorState();
|
|
@@ -418,34 +930,106 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
418
930
|
}); editor.replaceChildren(form);
|
|
419
931
|
}
|
|
420
932
|
|
|
421
|
-
async function selectEntry(id) { try { const result = await api('/api/entries/' + encodeURIComponent(id) + '?workspace=' + encodeURIComponent(state.workspace)); state.selected = result.entry; renderEntries(); renderEditor(); } catch (error) { setStatus(error.message, true); } }
|
|
933
|
+
async function selectEntry(id) { try { const result = await api('/api/entries/' + encodeURIComponent(id) + '?workspace=' + encodeURIComponent(state.workspace)); state.selectedRecall = null; state.selected = result.entry; renderEntries(); renderEditor(); } catch (error) { setStatus(error.message, true); } }
|
|
422
934
|
|
|
423
935
|
const curatorCandidateKey = (candidate) => candidate.workspace + '\u0000' + candidate.entryId;
|
|
424
936
|
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
937
|
+
function setCuratorConfirmationStatus(message, error = false) {
|
|
938
|
+
const element = $('curator-confirm-status');
|
|
939
|
+
element.textContent = message;
|
|
940
|
+
element.className = error ? 'status notice error curator-status' : 'status curator-status';
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
function openCuratorConfirmation(candidate, trigger) {
|
|
944
|
+
if (state.curatorGlobalizeBusy || state.curatorGlobalized.has(curatorCandidateKey(candidate))) return;
|
|
945
|
+
state.curatorPendingCandidate = candidate;
|
|
946
|
+
state.curatorConfirmationTrigger = trigger instanceof HTMLElement ? trigger : null;
|
|
947
|
+
$('curator-confirm-source').textContent = candidate.projectName || candidate.workspace;
|
|
948
|
+
$('curator-confirm-skill').textContent = candidate.skillName;
|
|
949
|
+
$('curator-confirm-applicability').textContent = candidate.applicability ? JSON.stringify(candidate.applicability, null, 2) : t('curatorApplicabilityNone');
|
|
950
|
+
$('curator-confirm-draft').textContent = [
|
|
951
|
+
t('curatorDraftTitle') + '\n' + candidate.draft.title,
|
|
952
|
+
t('curatorDraftSummary') + '\n' + candidate.draft.summary,
|
|
953
|
+
t('curatorDraftBody') + '\n' + candidate.draft.body,
|
|
954
|
+
t('curatorDraftVersion') + '\n' + candidate.draft.version,
|
|
955
|
+
].join('\n\n');
|
|
956
|
+
setCuratorConfirmationStatus('');
|
|
957
|
+
const panel = $('curator-panel');
|
|
958
|
+
panel.inert = true;
|
|
959
|
+
panel.setAttribute('aria-hidden', 'true');
|
|
960
|
+
const submit = $('curator-confirm-submit');
|
|
961
|
+
submit.disabled = false;
|
|
962
|
+
setI18nText(submit, 'curatorConfirmAction');
|
|
963
|
+
$('curator-confirm-cancel').disabled = false;
|
|
964
|
+
$('curator-confirm-modal').hidden = false;
|
|
965
|
+
requestAnimationFrame(() => submit.focus());
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function closeCuratorConfirmation(restoreFocus = true) {
|
|
969
|
+
if (state.curatorGlobalizeBusy) return;
|
|
970
|
+
$('curator-confirm-modal').hidden = true;
|
|
971
|
+
const panel = $('curator-panel');
|
|
972
|
+
panel.inert = false;
|
|
973
|
+
panel.removeAttribute('aria-hidden');
|
|
974
|
+
const trigger = state.curatorConfirmationTrigger;
|
|
975
|
+
state.curatorPendingCandidate = null;
|
|
976
|
+
state.curatorConfirmationTrigger = null;
|
|
977
|
+
setCuratorConfirmationStatus('');
|
|
978
|
+
if (restoreFocus) requestAnimationFrame(() => {
|
|
979
|
+
if (trigger?.isConnected) trigger.focus();
|
|
980
|
+
else $('curator-close')?.focus();
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
function handleCuratorConfirmationKeydown(event) {
|
|
985
|
+
event.stopPropagation();
|
|
986
|
+
if (event.key === 'Escape') { event.preventDefault(); closeCuratorConfirmation(); return; }
|
|
987
|
+
if (event.key !== 'Tab') return;
|
|
988
|
+
const panel = $('curator-confirm-panel');
|
|
989
|
+
const focusable = [...panel.querySelectorAll('button:not([disabled]), [tabindex]:not([tabindex="-1"])')];
|
|
990
|
+
if (!focusable.length) { event.preventDefault(); return; }
|
|
991
|
+
const first = focusable[0];
|
|
992
|
+
const last = focusable.at(-1);
|
|
993
|
+
if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
|
|
994
|
+
else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
async function globalizePendingCurator() {
|
|
998
|
+
const candidate = state.curatorPendingCandidate;
|
|
999
|
+
if (!candidate || state.curatorGlobalizeBusy) return;
|
|
1000
|
+
state.curatorGlobalizeBusy = true;
|
|
1001
|
+
const panel = $('curator-confirm-panel');
|
|
1002
|
+
const cancel = $('curator-confirm-cancel');
|
|
1003
|
+
const submit = $('curator-confirm-submit');
|
|
1004
|
+
panel.setAttribute('aria-busy', 'true');
|
|
1005
|
+
cancel.disabled = true;
|
|
1006
|
+
submit.disabled = true;
|
|
1007
|
+
setI18nText(submit, 'curatorGlobalizing');
|
|
1008
|
+
setCuratorConfirmationStatus(t('curatorGlobalizing'));
|
|
1009
|
+
try {
|
|
1010
|
+
await api('/api/curator/globalize?workspace=' + encodeURIComponent(candidate.workspace), {
|
|
1011
|
+
method: 'POST',
|
|
1012
|
+
headers: { 'content-type': 'application/json' },
|
|
1013
|
+
body: JSON.stringify({ workspace: candidate.workspace, entryId: candidate.entryId, expectedRevision: candidate.revision }),
|
|
1014
|
+
});
|
|
1015
|
+
state.curatorGlobalized.add(curatorCandidateKey(candidate));
|
|
1016
|
+
state.curatorGlobalizeBusy = false;
|
|
1017
|
+
closeCuratorConfirmation(false);
|
|
1018
|
+
await loadCurator();
|
|
1019
|
+
await loadEntries();
|
|
1020
|
+
setLocalizedStatus('curatorAdded');
|
|
1021
|
+
setCuratorStatus(t('curatorAdded'));
|
|
1022
|
+
requestAnimationFrame(() => $('curator-close')?.focus());
|
|
1023
|
+
} catch (error) {
|
|
1024
|
+
const message = error instanceof Error ? error.message : t('curatorGlobalizeFailed');
|
|
1025
|
+
setCuratorConfirmationStatus(t('curatorGlobalizeFailed') + ' ' + message, true);
|
|
1026
|
+
} finally {
|
|
1027
|
+
state.curatorGlobalizeBusy = false;
|
|
1028
|
+
panel.removeAttribute('aria-busy');
|
|
1029
|
+
cancel.disabled = false;
|
|
1030
|
+
submit.disabled = false;
|
|
1031
|
+
setI18nText(submit, 'curatorConfirmAction');
|
|
443
1032
|
}
|
|
444
|
-
state.curatorSelected.clear();
|
|
445
|
-
await loadCurator();
|
|
446
|
-
await loadEntries();
|
|
447
|
-
if (added > 0 && failed === 0) { setLocalizedStatus('curatorBatchAdded', { count: added }); setCuratorStatus(t('curatorBatchAdded', { count: added })); }
|
|
448
|
-
else if (added > 0) { setLocalizedStatus('curatorBatchPartial', { added, failed }, true); setCuratorStatus(t('curatorBatchPartial', { added, failed }), true); }
|
|
449
1033
|
}
|
|
450
1034
|
|
|
451
1035
|
function renderCurator() {
|
|
@@ -453,25 +1037,16 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
453
1037
|
const modal = $('curator-modal');
|
|
454
1038
|
modal.hidden = false;
|
|
455
1039
|
const root = $('curator-list');
|
|
456
|
-
|
|
457
|
-
$('curator-selection-count').textContent = t('curatorSelected', { count: state.curatorSelected.size });
|
|
1040
|
+
$('curator-result-count').textContent = t('curatorResultCount', { count: state.curatorTotalApproximate || state.curatorCandidates.length });
|
|
458
1041
|
const actionRoot = $('curator-actions'); actionRoot.replaceChildren();
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
clearSelection.addEventListener('click', () => { state.curatorSelected.clear(); renderCurator(); });
|
|
463
|
-
const apply = document.createElement('button'); apply.type = 'button'; apply.className = 'button primary'; setI18nText(apply, 'curatorApplySelected'); apply.disabled = state.curatorSelected.size === 0;
|
|
464
|
-
apply.addEventListener('click', () => applySelectedCurator());
|
|
465
|
-
actionRoot.append(selectAll, clearSelection, apply);
|
|
1042
|
+
if (state.curatorNextCursor) {
|
|
1043
|
+
const more = document.createElement('button'); more.type = 'button'; more.className = 'button'; setI18nText(more, 'curatorLoadMore'); more.addEventListener('click', () => loadCurator(true)); actionRoot.append(more);
|
|
1044
|
+
}
|
|
466
1045
|
if (!state.curatorCandidates.length) { const empty = document.createElement('div'); empty.className = 'editor-empty'; setI18nText(empty, 'noCuratorCandidates'); root.replaceChildren(empty); return; }
|
|
467
|
-
const cards = state.curatorCandidates.map((candidate) => {
|
|
1046
|
+
const cards = state.curatorCandidates.map((candidate, index) => {
|
|
468
1047
|
const card = document.createElement('article'); card.className = 'curator-card';
|
|
469
1048
|
const candidateKey = curatorCandidateKey(candidate);
|
|
470
1049
|
const done = state.curatorGlobalized.has(candidateKey);
|
|
471
|
-
const selectLabel = document.createElement('label'); selectLabel.className = 'curator-select';
|
|
472
|
-
const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = state.curatorSelected.has(candidateKey); checkbox.disabled = done;
|
|
473
|
-
checkbox.addEventListener('change', () => { if (checkbox.checked) state.curatorSelected.add(candidateKey); else state.curatorSelected.delete(candidateKey); renderCurator(); });
|
|
474
|
-
const selectText = document.createElement('span'); selectText.textContent = done ? t('globalized') : t('curatorSelectSkill'); selectLabel.append(checkbox, selectText);
|
|
475
1050
|
const meta = document.createElement('div'); meta.className = 'entry-meta';
|
|
476
1051
|
const kind = document.createElement('span'); kind.className = 'badge'; kind.textContent = labelForKind(candidate.kind);
|
|
477
1052
|
const score = document.createElement('span'); score.className = 'badge'; score.textContent = t('curatorScore', { score: candidate.score });
|
|
@@ -480,6 +1055,7 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
480
1055
|
if (candidate.knowledge && candidate.knowledge.skillReady) { const ready = document.createElement('span'); ready.className = 'badge'; setI18nText(ready, 'curatorSkillReady'); meta.append(ready); }
|
|
481
1056
|
const heading = document.createElement('h3'); heading.textContent = candidate.skillName;
|
|
482
1057
|
const overview = document.createElement('div'); overview.className = 'curator-overview'; overview.textContent = candidate.overview.join('\n');
|
|
1058
|
+
const tags = document.createElement('div'); tags.className = 'tags'; (candidate.tags || []).forEach((tag) => { const tagItem = document.createElement('span'); tagItem.className = 'tag'; tagItem.textContent = '#' + tag; tags.append(tagItem); });
|
|
483
1059
|
const knowledge = document.createElement('div'); knowledge.className = 'curator-reasons'; knowledge.textContent = candidate.knowledge ? [
|
|
484
1060
|
t('curatorEvidence', { hits: candidate.knowledge.qualifiedHits, runs: candidate.knowledge.independentRuns, workspaces: candidate.knowledge.independentWorkspaces }),
|
|
485
1061
|
t('curatorSilo', { value: candidate.knowledge.averageCompleteness }),
|
|
@@ -506,22 +1082,52 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
506
1082
|
draft.append(label, content);
|
|
507
1083
|
}
|
|
508
1084
|
const reasons = document.createElement('div'); reasons.className = 'curator-reasons'; reasons.textContent = [...(candidate.reasons || []), ...(candidate.warnings || []).map((warning) => t('curatorWarning', { warning }))].join('\n');
|
|
509
|
-
|
|
510
|
-
|
|
1085
|
+
const details = document.createElement('div'); details.id = 'curator-review-' + index; details.className = 'curator-review-details'; details.hidden = true; details.append(knowledge, draft, reasons);
|
|
1086
|
+
const actions = document.createElement('div'); actions.className = 'curator-card-actions';
|
|
1087
|
+
const review = document.createElement('button'); review.type = 'button'; review.className = 'button'; review.setAttribute('aria-controls', details.id); review.setAttribute('aria-expanded', 'false'); setI18nText(review, 'curatorReview');
|
|
1088
|
+
review.addEventListener('click', () => { details.hidden = !details.hidden; review.setAttribute('aria-expanded', String(!details.hidden)); setI18nText(review, details.hidden ? 'curatorReview' : 'curatorHideReview'); });
|
|
1089
|
+
const globalize = document.createElement('button'); globalize.type = 'button'; globalize.className = 'button primary'; globalize.disabled = done; setI18nText(globalize, done ? 'globalized' : 'curatorGlobalizeCandidate');
|
|
1090
|
+
globalize.addEventListener('click', () => openCuratorConfirmation(candidate, globalize));
|
|
1091
|
+
actions.append(review, globalize);
|
|
1092
|
+
card.append(meta, heading, overview, tags, actions, details); return card;
|
|
511
1093
|
});
|
|
512
|
-
root.replaceChildren(
|
|
1094
|
+
root.replaceChildren(...cards);
|
|
513
1095
|
}
|
|
514
1096
|
|
|
515
|
-
async function loadCurator() {
|
|
516
|
-
|
|
1097
|
+
async function loadCurator(append = false) {
|
|
1098
|
+
// Keep the documented legacy URL shape recognizable for clients: /api/curator/candidates?limit=50
|
|
1099
|
+
if (!append) {
|
|
1100
|
+
openCurator();
|
|
1101
|
+
state.curatorCandidates = [];
|
|
1102
|
+
state.curatorNextCursor = null;
|
|
1103
|
+
state.curatorTotalApproximate = 0;
|
|
1104
|
+
} else if (!state.curatorNextCursor) return;
|
|
517
1105
|
const panel = $('curator-panel');
|
|
518
1106
|
panel.setAttribute('aria-busy', 'true');
|
|
519
1107
|
setCuratorStatus(t('curatorLoading'));
|
|
520
1108
|
try {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
1109
|
+
if (!append) {
|
|
1110
|
+
const facetParams = new URLSearchParams({ workspace: 'all' });
|
|
1111
|
+
if (state.curatorIncludeGlobalized) facetParams.set('includeGlobalized', 'true');
|
|
1112
|
+
const facetResult = await api('/api/curator/facets?' + facetParams);
|
|
1113
|
+
state.curatorFacets = facetResult.facets || {};
|
|
1114
|
+
renderCuratorFilters();
|
|
1115
|
+
}
|
|
1116
|
+
const params = new URLSearchParams({ workspace: 'all', limit: '50' });
|
|
1117
|
+
if (state.curatorProject) params.set('project', state.curatorProject);
|
|
1118
|
+
if (state.curatorSearch) params.set('search', state.curatorSearch);
|
|
1119
|
+
if (state.curatorFramework) params.set('framework', state.curatorFramework);
|
|
1120
|
+
if (state.curatorLanguage) params.set('language', state.curatorLanguage);
|
|
1121
|
+
if (state.curatorMemoryClass) params.set('memoryClass', state.curatorMemoryClass);
|
|
1122
|
+
if (state.curatorTier) params.set('tier', state.curatorTier);
|
|
1123
|
+
if (state.curatorReady) params.set('skillReadyOnly', 'true');
|
|
1124
|
+
if (state.curatorIncludeGlobalized) params.set('includeGlobalized', 'true');
|
|
1125
|
+
for (const tag of state.curatorTags) params.append('tag', tag);
|
|
1126
|
+
if (append && state.curatorNextCursor) params.set('cursor', state.curatorNextCursor);
|
|
1127
|
+
const result = await api('/api/curator/candidates?' + params);
|
|
1128
|
+
state.curatorCandidates = append ? [...state.curatorCandidates, ...(result.candidates || [])] : (result.candidates || []);
|
|
1129
|
+
state.curatorNextCursor = result.nextCursor || null;
|
|
1130
|
+
state.curatorTotalApproximate = Number(result.totalApproximate || state.curatorCandidates.length);
|
|
525
1131
|
setCuratorStatus('');
|
|
526
1132
|
renderCurator();
|
|
527
1133
|
}
|
|
@@ -582,7 +1188,29 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
582
1188
|
} catch (error) { setStatus(error.message, true); }
|
|
583
1189
|
}
|
|
584
1190
|
|
|
585
|
-
async function loadEntries() {
|
|
1191
|
+
async function loadEntries() {
|
|
1192
|
+
if (!state.workspace) return;
|
|
1193
|
+
try {
|
|
1194
|
+
const params = new URLSearchParams({ workspace: state.workspace });
|
|
1195
|
+
if (state.kind !== 'all') params.set('kind', state.kind);
|
|
1196
|
+
if (state.tag) params.set('tag', state.tag);
|
|
1197
|
+
if (state.query) params.set('q', state.query);
|
|
1198
|
+
const result = await api('/api/entries?' + params);
|
|
1199
|
+
state.entries = result.entries;
|
|
1200
|
+
state.recallItems = [];
|
|
1201
|
+
state.selectedRecall = null;
|
|
1202
|
+
if (state.query && state.kind === 'all' && !state.tag) {
|
|
1203
|
+
const recallParams = new URLSearchParams({ workspace: state.workspace, q: state.query, limit: '100' });
|
|
1204
|
+
const recalled = await api('/api/memory/recall?' + recallParams);
|
|
1205
|
+
state.recallItems = recalled.combined?.items || [];
|
|
1206
|
+
state.selected = null;
|
|
1207
|
+
} else if (state.selected && !state.entries.some((entry) => entry.id === state.selected.id)) state.selected = null;
|
|
1208
|
+
renderEntries(); renderFilters();
|
|
1209
|
+
if (!state.recallItems.length && !state.selected && state.entries[0]) await selectEntry(state.entries[0].id);
|
|
1210
|
+
else renderEditor();
|
|
1211
|
+
setLocalizedCountStatus('displayedCount', state.recallItems.length || result.entries.length);
|
|
1212
|
+
} catch (error) { setStatus(error.message, true); }
|
|
1213
|
+
}
|
|
586
1214
|
async function loadTags() { if (!state.workspace) return; try { const result = await api('/api/tags?workspace=' + encodeURIComponent(state.workspace)); state.tags = result.tags; renderFilters(); } catch (error) { setStatus(error.message, true); } }
|
|
587
1215
|
async function loadWorkspaces() { try { const result = await api('/api/workspaces'); const select = $('workspace'); select.replaceChildren(...result.workspaces.map((item) => { const option = document.createElement('option'); option.value = item.workspace; option.textContent = (item.displayName || item.workspace) + ' (' + item.count + ')'; return option; })); if (!state.workspace && result.workspaces[0]) state.workspace = result.workspaces[0].workspace; select.value = state.workspace; if (state.workspace) { await loadTags(); await loadEntries(); await loadRuns(); } if (state.curatorOpen) await loadCurator(); else if (!state.workspace) setLocalizedStatus('noWorkspace', {}, true); } catch (error) { setStatus(error.message, true); } }
|
|
588
1216
|
$('language-toggle').addEventListener('click', () => {
|
|
@@ -606,10 +1234,18 @@ export const WEB_HTML = String.raw `<!doctype html>
|
|
|
606
1234
|
});
|
|
607
1235
|
document.addEventListener('click', (event) => { if (!$('language-picker')?.contains(event.target)) setLanguageMenuOpen(false); });
|
|
608
1236
|
document.addEventListener('focusin', (event) => { if (!$('language-picker')?.contains(event.target)) setLanguageMenuOpen(false); });
|
|
609
|
-
$('workspace').addEventListener('change', (event) => { if (state.curatorOpen) closeCurator(); state.workspace = event.target.value; state.selected = null; state.selectedRun = null; state.runs = []; state.tag = ''; state.curatorCandidates = []; state.
|
|
1237
|
+
$('workspace').addEventListener('change', (event) => { if (state.curatorOpen) closeCurator(); if (state.externalSkillsOpen) closeExternalSkills(); state.workspace = event.target.value; state.selected = null; state.selectedRecall = null; state.selectedRun = null; state.runs = []; state.tag = ''; state.curatorCandidates = []; state.curatorGlobalized = new Set(); state.curatorNextCursor = null; state.curatorTotalApproximate = 0; state.curatorOpen = false; loadTags().then(loadEntries).then(loadRuns); });
|
|
610
1238
|
$('curator-button').addEventListener('click', () => loadCurator());
|
|
611
1239
|
$('curator-close').addEventListener('click', () => closeCurator());
|
|
1240
|
+
$('external-skills-button').addEventListener('click', () => loadExternalSkills());
|
|
1241
|
+
$('external-skills-close').addEventListener('click', () => closeExternalSkills());
|
|
1242
|
+
$('external-skills-refresh').addEventListener('click', () => loadExternalSkills(false));
|
|
1243
|
+
$('curator-confirm-cancel').addEventListener('click', () => closeCuratorConfirmation());
|
|
1244
|
+
$('curator-confirm-submit').addEventListener('click', () => globalizePendingCurator());
|
|
1245
|
+
$('curator-confirm-modal').addEventListener('keydown', handleCuratorConfirmationKeydown);
|
|
612
1246
|
$('curator-modal').addEventListener('keydown', handleCuratorKeydown);
|
|
1247
|
+
$('external-skills-modal').addEventListener('keydown', handleExternalSkillsKeydown);
|
|
1248
|
+
window.addEventListener('popstate', () => { restoreCuratorUrl(); if (state.curatorOpen) loadCurator(); });
|
|
613
1249
|
$('refresh').addEventListener('click', () => loadWorkspaces());
|
|
614
1250
|
let searchTimer; $('search').addEventListener('input', (event) => { clearTimeout(searchTimer); state.query = event.target.value.trim(); searchTimer = setTimeout(() => loadEntries(), 180); });
|
|
615
1251
|
applyTranslations();
|