arkaos 2.20.0 → 2.21.0
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/VERSION +1 -1
- package/arka/SKILL.md +14 -0
- package/arka/skills/flow/SKILL.md +14 -0
- package/arka/skills/forge/SKILL.md +14 -0
- package/config/hooks/_lib/workflow-classifier.sh +95 -0
- package/config/hooks/post-tool-use.ps1 +80 -0
- package/config/hooks/post-tool-use.sh +47 -0
- package/config/hooks/pre-tool-use.ps1 +190 -0
- package/config/hooks/pre-tool-use.sh +209 -0
- package/config/hooks/stop.ps1 +191 -0
- package/config/hooks/stop.sh +215 -0
- package/config/hooks/user-prompt-submit.ps1 +50 -0
- package/config/hooks/user-prompt-submit.sh +44 -15
- package/core/cognition/__pycache__/auto_documentor.cpython-313.pyc +0 -0
- package/core/cognition/auto_documentor.py +410 -0
- package/core/jobs/__init__.py +14 -3
- package/core/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/jobs/__pycache__/auto_doc_worker.cpython-313.pyc +0 -0
- package/core/jobs/auto_doc_worker.py +257 -0
- package/core/obsidian/__init__.py +30 -3
- package/core/obsidian/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/obsidian/__pycache__/cataloger.cpython-313.pyc +0 -0
- package/core/obsidian/__pycache__/relator.cpython-313.pyc +0 -0
- package/core/obsidian/__pycache__/taxonomy.cpython-313.pyc +0 -0
- package/core/obsidian/cataloger.py +251 -0
- package/core/obsidian/relator.py +241 -0
- package/core/obsidian/taxonomy.py +100 -0
- package/core/synapse/__init__.py +8 -1
- package/core/synapse/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/engine.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/kb_cache.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/layers.cpython-313.pyc +0 -0
- package/core/synapse/engine.py +15 -1
- package/core/synapse/kb_cache.py +125 -6
- package/core/synapse/layers.py +296 -0
- package/core/workflow/__pycache__/flow_enforcer.cpython-313.pyc +0 -0
- package/core/workflow/__pycache__/kb_first_decider.cpython-313.pyc +0 -0
- package/core/workflow/__pycache__/marker_cache.cpython-313.pyc +0 -0
- package/core/workflow/__pycache__/research_gate.cpython-313.pyc +0 -0
- package/core/workflow/flow_enforcer.py +283 -0
- package/core/workflow/kb_first_decider.py +63 -0
- package/core/workflow/marker_cache.py +147 -0
- package/core/workflow/research_gate.py +301 -0
- package/departments/brand/SKILL.md +14 -0
- package/departments/brand/skills/archetype-finder/SKILL.md +14 -0
- package/departments/brand/skills/colors/SKILL.md +14 -0
- package/departments/brand/skills/design-system/SKILL.md +14 -0
- package/departments/brand/skills/identity-system/SKILL.md +14 -0
- package/departments/brand/skills/logo-brief/SKILL.md +14 -0
- package/departments/brand/skills/mockup-generate/SKILL.md +14 -0
- package/departments/brand/skills/naming-evaluate/SKILL.md +14 -0
- package/departments/brand/skills/positioning-statement/SKILL.md +14 -0
- package/departments/brand/skills/primal-audit/SKILL.md +14 -0
- package/departments/brand/skills/ux-audit/SKILL.md +14 -0
- package/departments/brand/skills/voice-guide/SKILL.md +14 -0
- package/departments/brand/skills/wireframe/SKILL.md +14 -0
- package/departments/community/SKILL.md +14 -0
- package/departments/community/skills/ai-community/SKILL.md +14 -0
- package/departments/community/skills/betting-setup/SKILL.md +14 -0
- package/departments/community/skills/business-model/SKILL.md +14 -0
- package/departments/community/skills/content-calendar/SKILL.md +14 -0
- package/departments/community/skills/events-plan/SKILL.md +14 -0
- package/departments/community/skills/gamification-design/SKILL.md +14 -0
- package/departments/community/skills/growth-plan/SKILL.md +14 -0
- package/departments/community/skills/metrics-track/SKILL.md +14 -0
- package/departments/community/skills/moderation/SKILL.md +14 -0
- package/departments/community/skills/monetize-plan/SKILL.md +14 -0
- package/departments/community/skills/niche-setup/SKILL.md +14 -0
- package/departments/community/skills/onboarding-flow/SKILL.md +14 -0
- package/departments/community/skills/platform-select/SKILL.md +14 -0
- package/departments/content/SKILL.md +14 -0
- package/departments/content/skills/ai-workflow/SKILL.md +14 -0
- package/departments/content/skills/analytics/SKILL.md +14 -0
- package/departments/content/skills/calendar/SKILL.md +14 -0
- package/departments/content/skills/content-system/SKILL.md +14 -0
- package/departments/content/skills/monetization-plan/SKILL.md +14 -0
- package/departments/content/skills/newsletter-write/SKILL.md +14 -0
- package/departments/content/skills/platform-optimize/SKILL.md +14 -0
- package/departments/content/skills/repurpose-plan/SKILL.md +14 -0
- package/departments/content/skills/script-structure/SKILL.md +14 -0
- package/departments/content/skills/short-form/SKILL.md +14 -0
- package/departments/content/skills/thumbnail-package/SKILL.md +14 -0
- package/departments/content/skills/viral-design/SKILL.md +14 -0
- package/departments/content/skills/youtube-strategy/SKILL.md +14 -0
- package/departments/dev/SKILL.md +14 -0
- package/departments/dev/skills/ai-assisted-dev/SKILL.md +14 -0
- package/departments/dev/skills/architecture-design/SKILL.md +14 -0
- package/departments/dev/skills/code-review/SKILL.md +14 -0
- package/departments/dev/skills/db-design/SKILL.md +14 -0
- package/departments/dev/skills/ddd-model/SKILL.md +14 -0
- package/departments/dev/skills/demo-gif/SKILL.md +14 -0
- package/departments/dev/skills/deploy/SKILL.md +14 -0
- package/departments/dev/skills/devops-pipeline/SKILL.md +14 -0
- package/departments/dev/skills/docs/SKILL.md +14 -0
- package/departments/dev/skills/mcp/SKILL.md +14 -0
- package/departments/dev/skills/performance-audit/SKILL.md +14 -0
- package/departments/dev/skills/refactor-plan/SKILL.md +14 -0
- package/departments/dev/skills/research/SKILL.md +14 -0
- package/departments/dev/skills/security-compliance/SKILL.md +14 -0
- package/departments/dev/skills/stack-check/SKILL.md +14 -0
- package/departments/ecom/SKILL.md +14 -0
- package/departments/ecom/skills/analytics/SKILL.md +14 -0
- package/departments/ecom/skills/browse-competitor/SKILL.md +14 -0
- package/departments/ecom/skills/cart-recovery/SKILL.md +14 -0
- package/departments/ecom/skills/cro-optimize/SKILL.md +14 -0
- package/departments/ecom/skills/customer-journey/SKILL.md +14 -0
- package/departments/ecom/skills/fulfillment-plan/SKILL.md +14 -0
- package/departments/ecom/skills/marketplace-manage/SKILL.md +14 -0
- package/departments/ecom/skills/pricing-strategy/SKILL.md +14 -0
- package/departments/ecom/skills/product-launch/SKILL.md +14 -0
- package/departments/ecom/skills/rfm-segment/SKILL.md +14 -0
- package/departments/ecom/skills/social-commerce/SKILL.md +14 -0
- package/departments/ecom/skills/store-audit/SKILL.md +14 -0
- package/departments/ecom/skills/subscription-model/SKILL.md +14 -0
- package/departments/finance/SKILL.md +14 -0
- package/departments/finance/skills/budget-plan/SKILL.md +14 -0
- package/departments/finance/skills/cashflow-forecast/SKILL.md +14 -0
- package/departments/finance/skills/ciso-advisor/SKILL.md +14 -0
- package/departments/finance/skills/financial-model/SKILL.md +14 -0
- package/departments/finance/skills/pitch-deck/SKILL.md +14 -0
- package/departments/finance/skills/scenario-analysis/SKILL.md +14 -0
- package/departments/finance/skills/unit-economics/SKILL.md +14 -0
- package/departments/finance/skills/valuation-model/SKILL.md +14 -0
- package/departments/kb/SKILL.md +14 -0
- package/departments/kb/skills/ai-research/SKILL.md +14 -0
- package/departments/kb/skills/competitive-intel/SKILL.md +14 -0
- package/departments/kb/skills/knowledge-review/SKILL.md +14 -0
- package/departments/kb/skills/learn-content/SKILL.md +14 -0
- package/departments/kb/skills/moc-create/SKILL.md +14 -0
- package/departments/kb/skills/persona-build/SKILL.md +14 -0
- package/departments/kb/skills/research-plan/SKILL.md +14 -0
- package/departments/kb/skills/search-kb/SKILL.md +14 -0
- package/departments/kb/skills/source-evaluate/SKILL.md +14 -0
- package/departments/kb/skills/taxonomy-manage/SKILL.md +14 -0
- package/departments/kb/skills/write-as-persona/SKILL.md +14 -0
- package/departments/landing/SKILL.md +14 -0
- package/departments/landing/skills/ab-test/SKILL.md +14 -0
- package/departments/landing/skills/affiliate-bridge/SKILL.md +14 -0
- package/departments/landing/skills/awareness-diagnose/SKILL.md +14 -0
- package/departments/landing/skills/email-sequence/SKILL.md +14 -0
- package/departments/landing/skills/funnel-metrics/SKILL.md +14 -0
- package/departments/landing/skills/headline-write/SKILL.md +14 -0
- package/departments/landing/skills/launch-sequence/SKILL.md +14 -0
- package/departments/landing/skills/offer-create/SKILL.md +14 -0
- package/departments/landing/skills/optimize-page/SKILL.md +14 -0
- package/departments/landing/skills/page-architect/SKILL.md +14 -0
- package/departments/landing/skills/persuasion-apply/SKILL.md +14 -0
- package/departments/landing/skills/webinar-funnel/SKILL.md +14 -0
- package/departments/leadership/SKILL.md +14 -0
- package/departments/leadership/skills/change-manage/SKILL.md +14 -0
- package/departments/leadership/skills/conflict-resolve/SKILL.md +14 -0
- package/departments/leadership/skills/culture-audit/SKILL.md +14 -0
- package/departments/leadership/skills/delegation-matrix/SKILL.md +14 -0
- package/departments/leadership/skills/disc-assess/SKILL.md +14 -0
- package/departments/leadership/skills/feedback-give/SKILL.md +14 -0
- package/departments/leadership/skills/hiring-plan/SKILL.md +14 -0
- package/departments/leadership/skills/performance-review/SKILL.md +14 -0
- package/departments/marketing/SKILL.md +14 -0
- package/departments/marketing/skills/ab-test/SKILL.md +14 -0
- package/departments/marketing/skills/analytics-report/SKILL.md +14 -0
- package/departments/marketing/skills/audience-segment/SKILL.md +14 -0
- package/departments/marketing/skills/calendar-plan/SKILL.md +14 -0
- package/departments/marketing/skills/competitor-analysis/SKILL.md +14 -0
- package/departments/marketing/skills/content-audit/SKILL.md +14 -0
- package/departments/marketing/skills/email-sequence/SKILL.md +14 -0
- package/departments/marketing/skills/growth-loop/SKILL.md +14 -0
- package/departments/marketing/skills/marketing-automation/SKILL.md +14 -0
- package/departments/marketing/skills/paid-campaign/SKILL.md +14 -0
- package/departments/marketing/skills/programmatic-seo/SKILL.md +14 -0
- package/departments/marketing/skills/seo-audit/SKILL.md +14 -0
- package/departments/marketing/skills/social-strategy/SKILL.md +14 -0
- package/departments/ops/SKILL.md +14 -0
- package/departments/ops/skills/bottleneck-find/SKILL.md +14 -0
- package/departments/ops/skills/dashboard-build/SKILL.md +14 -0
- package/departments/ops/skills/gdpr-compliance/SKILL.md +14 -0
- package/departments/ops/skills/gtd-setup/SKILL.md +14 -0
- package/departments/ops/skills/integration-design/SKILL.md +14 -0
- package/departments/ops/skills/iso27001/SKILL.md +14 -0
- package/departments/ops/skills/lean-audit/SKILL.md +14 -0
- package/departments/ops/skills/metrics-dashboard/SKILL.md +14 -0
- package/departments/ops/skills/n8n-flow/SKILL.md +14 -0
- package/departments/ops/skills/quality-management/SKILL.md +14 -0
- package/departments/ops/skills/risk-management/SKILL.md +14 -0
- package/departments/ops/skills/soc2-compliance/SKILL.md +14 -0
- package/departments/ops/skills/sop-create/SKILL.md +14 -0
- package/departments/ops/skills/workflow-automate/SKILL.md +14 -0
- package/departments/ops/skills/zapier-flow/SKILL.md +14 -0
- package/departments/org/SKILL.md +14 -0
- package/departments/org/skills/compensation-plan/SKILL.md +14 -0
- package/departments/org/skills/culture-define/SKILL.md +14 -0
- package/departments/org/skills/decision-framework/SKILL.md +14 -0
- package/departments/org/skills/hiring-plan/SKILL.md +14 -0
- package/departments/org/skills/meeting-optimize/SKILL.md +14 -0
- package/departments/org/skills/onboarding-design/SKILL.md +14 -0
- package/departments/org/skills/org-design/SKILL.md +14 -0
- package/departments/org/skills/remote-setup/SKILL.md +14 -0
- package/departments/org/skills/sop-process/SKILL.md +14 -0
- package/departments/org/skills/team-assess/SKILL.md +14 -0
- package/departments/pm/SKILL.md +14 -0
- package/departments/pm/skills/backlog-groom/SKILL.md +14 -0
- package/departments/pm/skills/discovery-plan/SKILL.md +14 -0
- package/departments/pm/skills/estimate-forecast/SKILL.md +14 -0
- package/departments/pm/skills/impact-map/SKILL.md +14 -0
- package/departments/pm/skills/kanban-setup/SKILL.md +14 -0
- package/departments/pm/skills/risk-register/SKILL.md +14 -0
- package/departments/pm/skills/roadmap-build/SKILL.md +14 -0
- package/departments/pm/skills/sprint-plan/SKILL.md +14 -0
- package/departments/pm/skills/stakeholder-map/SKILL.md +14 -0
- package/departments/pm/skills/standup-run/SKILL.md +14 -0
- package/departments/pm/skills/story-write/SKILL.md +14 -0
- package/departments/saas/SKILL.md +14 -0
- package/departments/saas/skills/benchmark-compare/SKILL.md +14 -0
- package/departments/saas/skills/churn-analysis/SKILL.md +14 -0
- package/departments/saas/skills/customer-success/SKILL.md +14 -0
- package/departments/saas/skills/growth-plan/SKILL.md +14 -0
- package/departments/saas/skills/gtm-strategy/SKILL.md +14 -0
- package/departments/saas/skills/launch-execute/SKILL.md +14 -0
- package/departments/saas/skills/metrics-dashboard/SKILL.md +14 -0
- package/departments/saas/skills/micro-saas-stack/SKILL.md +14 -0
- package/departments/saas/skills/mvp-build/SKILL.md +14 -0
- package/departments/saas/skills/niche-evaluate/SKILL.md +14 -0
- package/departments/saas/skills/onboarding-optimize/SKILL.md +14 -0
- package/departments/saas/skills/plg-setup/SKILL.md +14 -0
- package/departments/saas/skills/pricing-strategy/SKILL.md +14 -0
- package/departments/saas/skills/validate-idea/SKILL.md +14 -0
- package/departments/sales/SKILL.md +14 -0
- package/departments/sales/skills/challenger-sell/SKILL.md +14 -0
- package/departments/sales/skills/deal-qualify/SKILL.md +14 -0
- package/departments/sales/skills/discovery-call/SKILL.md +14 -0
- package/departments/sales/skills/forecast-revenue/SKILL.md +14 -0
- package/departments/sales/skills/negotiate-plan/SKILL.md +14 -0
- package/departments/sales/skills/objection-handle/SKILL.md +14 -0
- package/departments/sales/skills/pipeline-manage/SKILL.md +14 -0
- package/departments/sales/skills/pricing-negotiate/SKILL.md +14 -0
- package/departments/strategy/SKILL.md +14 -0
- package/departments/strategy/skills/blue-ocean/SKILL.md +14 -0
- package/departments/strategy/skills/bmc/SKILL.md +14 -0
- package/departments/strategy/skills/board-advisor/SKILL.md +14 -0
- package/departments/strategy/skills/cto-advisor/SKILL.md +14 -0
- package/departments/strategy/skills/extract-data/SKILL.md +14 -0
- package/departments/strategy/skills/five-forces/SKILL.md +14 -0
- package/departments/strategy/skills/growth-strategy/SKILL.md +14 -0
- package/departments/strategy/skills/moat-analysis/SKILL.md +14 -0
- package/departments/strategy/skills/position/SKILL.md +14 -0
- package/departments/strategy/skills/scenario-plan/SKILL.md +14 -0
- package/installer/adapters/claude-code.js +13 -0
- package/installer/doctor.js +13 -1
- package/installer/index.js +15 -0
- package/package.json +3 -3
- package/pyproject.toml +1 -1
- package/scripts/migrate_skills_kb_first.py +137 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.21.0
|
package/arka/SKILL.md
CHANGED
|
@@ -7,6 +7,20 @@ description: >
|
|
|
7
7
|
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
<!-- arka:kb-first-prefix begin -->
|
|
11
|
+
## KB-First Research (non-negotiable)
|
|
12
|
+
|
|
13
|
+
Before any external research (Context7, WebSearch, WebFetch, Firecrawl):
|
|
14
|
+
|
|
15
|
+
1. Call `mcp__obsidian__search_notes` on the query first.
|
|
16
|
+
2. Cite relevant hits with `[[wikilinks]]` or explicitly declare a KB gap.
|
|
17
|
+
3. Only after (1) and (2) may external tools run.
|
|
18
|
+
|
|
19
|
+
The Synapse L2.5 layer pre-injects top KB matches on every user prompt;
|
|
20
|
+
treat them as your default source. External research supplements, it
|
|
21
|
+
does not replace the vault.
|
|
22
|
+
<!-- arka:kb-first-prefix end -->
|
|
23
|
+
|
|
10
24
|
# ArkaOS v2 — Main Orchestrator
|
|
11
25
|
|
|
12
26
|
> **The Operating System for AI Agent Teams**
|
|
@@ -7,6 +7,20 @@ description: >
|
|
|
7
7
|
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
<!-- arka:kb-first-prefix begin -->
|
|
11
|
+
## KB-First Research (non-negotiable)
|
|
12
|
+
|
|
13
|
+
Before any external research (Context7, WebSearch, WebFetch, Firecrawl):
|
|
14
|
+
|
|
15
|
+
1. Call `mcp__obsidian__search_notes` on the query first.
|
|
16
|
+
2. Cite relevant hits with `[[wikilinks]]` or explicitly declare a KB gap.
|
|
17
|
+
3. Only after (1) and (2) may external tools run.
|
|
18
|
+
|
|
19
|
+
The Synapse L2.5 layer pre-injects top KB matches on every user prompt;
|
|
20
|
+
treat them as your default source. External research supplements, it
|
|
21
|
+
does not replace the vault.
|
|
22
|
+
<!-- arka:kb-first-prefix end -->
|
|
23
|
+
|
|
10
24
|
# ArkaOS — Mandatory Workflow
|
|
11
25
|
|
|
12
26
|
> This flow runs on **every** user request inside an ArkaOS-managed context.
|
|
@@ -8,6 +8,20 @@ description: >
|
|
|
8
8
|
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
<!-- arka:kb-first-prefix begin -->
|
|
12
|
+
## KB-First Research (non-negotiable)
|
|
13
|
+
|
|
14
|
+
Before any external research (Context7, WebSearch, WebFetch, Firecrawl):
|
|
15
|
+
|
|
16
|
+
1. Call `mcp__obsidian__search_notes` on the query first.
|
|
17
|
+
2. Cite relevant hits with `[[wikilinks]]` or explicitly declare a KB gap.
|
|
18
|
+
3. Only after (1) and (2) may external tools run.
|
|
19
|
+
|
|
20
|
+
The Synapse L2.5 layer pre-injects top KB matches on every user prompt;
|
|
21
|
+
treat them as your default source. External research supplements, it
|
|
22
|
+
does not replace the vault.
|
|
23
|
+
<!-- arka:kb-first-prefix end -->
|
|
24
|
+
|
|
11
25
|
# The Forge — ArkaOS Intelligent Planning Engine
|
|
12
26
|
|
|
13
27
|
> **Engine:** `core/forge/` | **Plans stored:** `~/.arkaos/plans/` | **Obsidian:** `ArkaOS/Forge/`
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# ArkaOS v2 — Shared Workflow Classifier
|
|
4
|
+
#
|
|
5
|
+
# Decides whether a user prompt triggers the mandatory 13-phase flow.
|
|
6
|
+
# Used by: user-prompt-submit.sh, pre-tool-use.sh, stop.sh.
|
|
7
|
+
#
|
|
8
|
+
# Contract:
|
|
9
|
+
# arka_wf_classify "<prompt text>" → echoes "true" or "false", exits 0.
|
|
10
|
+
# arka_wf_mark_required "<session_id>" → writes marker file.
|
|
11
|
+
# arka_wf_is_required "<session_id>" → exits 0 if required, 1 otherwise.
|
|
12
|
+
# arka_wf_clear_required "<session_id>" → removes marker file.
|
|
13
|
+
#
|
|
14
|
+
# Markers live under /tmp/arkaos-wf-required/<session_id>.
|
|
15
|
+
# Python path for mark/clear: delegates to flow_enforcer.py when available,
|
|
16
|
+
# otherwise falls back to touching the marker file directly.
|
|
17
|
+
# ============================================================================
|
|
18
|
+
|
|
19
|
+
ARKA_WF_REQUIRED_DIR="${ARKA_WF_REQUIRED_DIR:-/tmp/arkaos-wf-required}"
|
|
20
|
+
|
|
21
|
+
# Reject any session_id outside [A-Za-z0-9._-]{1,128}. Protects the marker
|
|
22
|
+
# directory from path-traversal writes (CWE-22). Must stay in sync with
|
|
23
|
+
# core/workflow/flow_enforcer.py::_safe_session_id.
|
|
24
|
+
arka_wf_safe_session_id() {
|
|
25
|
+
local session_id="${1:-}"
|
|
26
|
+
[ -z "$session_id" ] && return 1
|
|
27
|
+
[ ${#session_id} -gt 128 ] && return 1
|
|
28
|
+
case "$session_id" in
|
|
29
|
+
*[!A-Za-z0-9._-]*) return 1 ;;
|
|
30
|
+
esac
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Verb + noun patterns shared with the original inline classifier in
|
|
35
|
+
# user-prompt-submit.sh. Keep in sync when adding new intent verbs.
|
|
36
|
+
ARKA_WF_VERB_PATTERN='(criar?|crie[ms]?|cria[mr]?|adicionar?|adiciona[mr]?|implementar?|implementa[mr]?|desenvolver?|desenvolve[mr]?|construir?|constru[ií]a?[mr]?|fazer?|faz[ae][mr]?|refactor(izar?)?|corrigir?|corrige[mr]?|consertar?|conserta[mr]?|create[sd]?|creating|build(s|ing)?|add(s|ed|ing)?|implement(s|ed|ing)?|develop(s|ed|ing)?|fix(es|ed|ing)?|refactor(s|ed|ing)?|make[sd]?|making)'
|
|
37
|
+
|
|
38
|
+
# Classify: returns "true" if the prompt looks like a creation/
|
|
39
|
+
# implementation/modification request, "false" otherwise.
|
|
40
|
+
# Skips: explicit slash commands (already routed) and bang shells.
|
|
41
|
+
arka_wf_classify() {
|
|
42
|
+
local text="${1:-}"
|
|
43
|
+
[ -z "$text" ] && { echo "false"; return 0; }
|
|
44
|
+
|
|
45
|
+
local first_char
|
|
46
|
+
first_char=$(printf '%s' "$text" | head -c 1)
|
|
47
|
+
if [ "$first_char" = "/" ] || [ "$first_char" = "!" ]; then
|
|
48
|
+
echo "false"
|
|
49
|
+
return 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
if echo "$text" | grep -qiE "\b${ARKA_WF_VERB_PATTERN}\b"; then
|
|
53
|
+
echo "true"
|
|
54
|
+
else
|
|
55
|
+
echo "false"
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Mark that the flow is required for this session. Safe no-op if session_id
|
|
60
|
+
# is empty or fails the allowlist check.
|
|
61
|
+
arka_wf_mark_required() {
|
|
62
|
+
local session_id="${1:-}"
|
|
63
|
+
arka_wf_safe_session_id "$session_id" || return 0
|
|
64
|
+
mkdir -p "$ARKA_WF_REQUIRED_DIR" 2>/dev/null
|
|
65
|
+
date -u +"%Y-%m-%dT%H:%M:%SZ" > "$ARKA_WF_REQUIRED_DIR/$session_id" 2>/dev/null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Test whether flow is required. Exit code 0 = required, 1 = not required.
|
|
69
|
+
arka_wf_is_required() {
|
|
70
|
+
local session_id="${1:-}"
|
|
71
|
+
arka_wf_safe_session_id "$session_id" || return 1
|
|
72
|
+
[ -f "$ARKA_WF_REQUIRED_DIR/$session_id" ]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Clear the requirement marker. Safe no-op if absent or unsafe.
|
|
76
|
+
arka_wf_clear_required() {
|
|
77
|
+
local session_id="${1:-}"
|
|
78
|
+
arka_wf_safe_session_id "$session_id" || return 0
|
|
79
|
+
rm -f "$ARKA_WF_REQUIRED_DIR/$session_id" 2>/dev/null
|
|
80
|
+
return 0
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# When invoked directly (not sourced), expose a simple CLI for ad-hoc use.
|
|
84
|
+
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|
85
|
+
case "${1:-}" in
|
|
86
|
+
classify) arka_wf_classify "${2:-}" ;;
|
|
87
|
+
mark) arka_wf_mark_required "${2:-}" ;;
|
|
88
|
+
is-required) arka_wf_is_required "${2:-}" && echo "true" || echo "false" ;;
|
|
89
|
+
clear) arka_wf_clear_required "${2:-}" ;;
|
|
90
|
+
*)
|
|
91
|
+
echo "Usage: $0 {classify <text>|mark <session_id>|is-required <session_id>|clear <session_id>}" >&2
|
|
92
|
+
exit 64
|
|
93
|
+
;;
|
|
94
|
+
esac
|
|
95
|
+
fi
|
|
@@ -120,6 +120,86 @@ if ($shouldProcessGotchas -and $null -ne $payload) {
|
|
|
120
120
|
$exitCode = if ($null -ne $payload.exit_code) { [string]$payload.exit_code } else { '0' }
|
|
121
121
|
$cwd = if ($null -ne $payload.cwd) { [string]$payload.cwd } else { '' }
|
|
122
122
|
|
|
123
|
+
# --- Flow marker cache write (v2 ALLOW accelerator) ------------------
|
|
124
|
+
# Mirror of the bash hook: detect [arka:routing] or [arka:trivial] in
|
|
125
|
+
# $payload.assistant_message and persist via core.workflow.marker_cache.
|
|
126
|
+
# Non-blocking — any failure is swallowed.
|
|
127
|
+
try {
|
|
128
|
+
$sessionIdPtu = if ($null -ne $payload.session_id) { [string]$payload.session_id } else { '' }
|
|
129
|
+
$assistantMsg = if ($null -ne $payload.assistant_message) { [string]$payload.assistant_message } else { '' }
|
|
130
|
+
if ($sessionIdPtu -and $assistantMsg) {
|
|
131
|
+
$routingRe = [regex]'(?i)\[arka:routing\]\s*([A-Za-z_-]+)\s*->\s*([A-Za-z_-]+)'
|
|
132
|
+
$trivialRe = [regex]'(?i)\[arka:trivial\]\s*\S+'
|
|
133
|
+
$markerKind = ''
|
|
134
|
+
$markerDept = ''
|
|
135
|
+
$markerLead = ''
|
|
136
|
+
$routingMatch = $routingRe.Match($assistantMsg)
|
|
137
|
+
if ($routingMatch.Success) {
|
|
138
|
+
$markerKind = 'routing'
|
|
139
|
+
$markerDept = $routingMatch.Groups[1].Value
|
|
140
|
+
$markerLead = $routingMatch.Groups[2].Value
|
|
141
|
+
} elseif ($trivialRe.IsMatch($assistantMsg)) {
|
|
142
|
+
$markerKind = 'trivial'
|
|
143
|
+
}
|
|
144
|
+
if ($markerKind) {
|
|
145
|
+
$arkaosRootPtu = $env:ARKAOS_ROOT
|
|
146
|
+
if (-not $arkaosRootPtu) {
|
|
147
|
+
$repoPathFile = Join-Path $env:USERPROFILE '.arkaos\.repo-path'
|
|
148
|
+
if (Test-Path -LiteralPath $repoPathFile) {
|
|
149
|
+
try {
|
|
150
|
+
$arkaosRootPtu = (Get-Content -Raw -LiteralPath $repoPathFile -Encoding UTF8).Trim()
|
|
151
|
+
} catch { }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (-not $arkaosRootPtu) {
|
|
155
|
+
$arkaosRootPtu = Join-Path $env:USERPROFILE '.arkaos'
|
|
156
|
+
}
|
|
157
|
+
# Locate Python (venv-first, then system).
|
|
158
|
+
$pythonForMarker = $null
|
|
159
|
+
$venvPy = Join-Path $env:USERPROFILE '.arkaos\venv\Scripts\python.exe'
|
|
160
|
+
if (Test-Path -LiteralPath $venvPy) {
|
|
161
|
+
$pythonForMarker = $venvPy
|
|
162
|
+
} else {
|
|
163
|
+
foreach ($cmd in 'python3','python','py') {
|
|
164
|
+
$resolved = Get-Command $cmd -ErrorAction SilentlyContinue
|
|
165
|
+
if ($resolved) { $pythonForMarker = $resolved.Source; break }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if ($pythonForMarker) {
|
|
169
|
+
$pyCode = @"
|
|
170
|
+
import os
|
|
171
|
+
try:
|
|
172
|
+
from core.workflow.marker_cache import write_marker
|
|
173
|
+
write_marker(
|
|
174
|
+
os.environ.get('SESSION_ID_PTU', ''),
|
|
175
|
+
os.environ.get('MARKER_KIND', ''),
|
|
176
|
+
os.environ.get('MARKER_DEPT', ''),
|
|
177
|
+
os.environ.get('MARKER_LEAD', ''),
|
|
178
|
+
)
|
|
179
|
+
except Exception:
|
|
180
|
+
pass
|
|
181
|
+
"@
|
|
182
|
+
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
183
|
+
$psi.FileName = $pythonForMarker
|
|
184
|
+
$psi.Arguments = "-c `"$($pyCode -replace '"','\"' -replace "`r?`n",'; ')`""
|
|
185
|
+
$psi.UseShellExecute = $false
|
|
186
|
+
$psi.CreateNoWindow = $true
|
|
187
|
+
$psi.RedirectStandardOutput = $true
|
|
188
|
+
$psi.RedirectStandardError = $true
|
|
189
|
+
[void]$psi.EnvironmentVariables.Add('SESSION_ID_PTU', $sessionIdPtu)
|
|
190
|
+
[void]$psi.EnvironmentVariables.Add('MARKER_KIND', $markerKind)
|
|
191
|
+
[void]$psi.EnvironmentVariables.Add('MARKER_DEPT', $markerDept)
|
|
192
|
+
[void]$psi.EnvironmentVariables.Add('MARKER_LEAD', $markerLead)
|
|
193
|
+
[void]$psi.EnvironmentVariables.Add('PYTHONPATH', $arkaosRootPtu)
|
|
194
|
+
try {
|
|
195
|
+
$proc = [System.Diagnostics.Process]::Start($psi)
|
|
196
|
+
if (-not $proc.WaitForExit(1500)) { try { $proc.Kill() } catch { } }
|
|
197
|
+
} catch { }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} catch { }
|
|
202
|
+
|
|
123
203
|
# ─── Only process when there is actually an error ─────────────────
|
|
124
204
|
$errorPattern = '(?i)(error:|fatal:|exception:|failed|ENOENT|EACCES|EPERM|panic:)'
|
|
125
205
|
if ($exitCode -eq '0' -or [string]::IsNullOrEmpty($exitCode)) {
|
|
@@ -24,6 +24,53 @@ TOOL_NAME=$(echo "$input" | jq -r '.tool_name // ""' 2>/dev/null)
|
|
|
24
24
|
TOOL_OUTPUT=$(echo "$input" | jq -r '.tool_output // ""' 2>/dev/null)
|
|
25
25
|
EXIT_CODE=$(echo "$input" | jq -r '.exit_code // "0"' 2>/dev/null)
|
|
26
26
|
CWD=$(echo "$input" | jq -r '.cwd // ""' 2>/dev/null)
|
|
27
|
+
SESSION_ID_PTU=$(echo "$input" | jq -r '.session_id // ""' 2>/dev/null)
|
|
28
|
+
ASSISTANT_MSG=$(echo "$input" | jq -r '.assistant_message // ""' 2>/dev/null)
|
|
29
|
+
|
|
30
|
+
# ─── Flow marker cache write (v2 — turn-scoped ALLOW accelerator) ───────
|
|
31
|
+
# Detect [arka:routing] or [arka:trivial] in the assistant message that
|
|
32
|
+
# accompanied this tool call, and persist it so the PreToolUse enforcer
|
|
33
|
+
# can short-circuit the transcript scan for the rest of the turn.
|
|
34
|
+
# Never blocks the hook — all failures are swallowed.
|
|
35
|
+
if [ -n "$SESSION_ID_PTU" ] && [ -n "$ASSISTANT_MSG" ] && command -v python3 &>/dev/null; then
|
|
36
|
+
_MARKER_KIND=""
|
|
37
|
+
_MARKER_DEPT=""
|
|
38
|
+
_MARKER_LEAD=""
|
|
39
|
+
if printf '%s' "$ASSISTANT_MSG" | grep -qiE '\[arka:routing\][[:space:]]*[A-Za-z_-]+[[:space:]]*->[[:space:]]*[A-Za-z_-]+'; then
|
|
40
|
+
_MARKER_KIND="routing"
|
|
41
|
+
_ROUTE_LINE=$(printf '%s' "$ASSISTANT_MSG" | grep -iEo '\[arka:routing\][[:space:]]*[A-Za-z_-]+[[:space:]]*->[[:space:]]*[A-Za-z_-]+' | head -1)
|
|
42
|
+
_MARKER_DEPT=$(printf '%s' "$_ROUTE_LINE" | sed -E 's/.*\[arka:routing\][[:space:]]*([A-Za-z_-]+).*/\1/')
|
|
43
|
+
_MARKER_LEAD=$(printf '%s' "$_ROUTE_LINE" | sed -E 's/.*->[[:space:]]*([A-Za-z_-]+).*/\1/')
|
|
44
|
+
elif printf '%s' "$ASSISTANT_MSG" | grep -qiE '\[arka:trivial\][[:space:]]*\S+'; then
|
|
45
|
+
_MARKER_KIND="trivial"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
if [ -n "$_MARKER_KIND" ]; then
|
|
49
|
+
_MARKER_ROOT="${ARKAOS_ROOT:-}"
|
|
50
|
+
if [ -z "$_MARKER_ROOT" ] && [ -f "$HOME/.arkaos/.repo-path" ]; then
|
|
51
|
+
_MARKER_ROOT=$(cat "$HOME/.arkaos/.repo-path" 2>/dev/null)
|
|
52
|
+
fi
|
|
53
|
+
[ -z "$_MARKER_ROOT" ] && _MARKER_ROOT="$HOME/.arkaos"
|
|
54
|
+
SESSION_ID_PTU="$SESSION_ID_PTU" \
|
|
55
|
+
MARKER_KIND="$_MARKER_KIND" \
|
|
56
|
+
MARKER_DEPT="$_MARKER_DEPT" \
|
|
57
|
+
MARKER_LEAD="$_MARKER_LEAD" \
|
|
58
|
+
PYTHONPATH="$_MARKER_ROOT" \
|
|
59
|
+
python3 -c "
|
|
60
|
+
import os, sys
|
|
61
|
+
try:
|
|
62
|
+
from core.workflow.marker_cache import write_marker
|
|
63
|
+
write_marker(
|
|
64
|
+
os.environ.get('SESSION_ID_PTU', ''),
|
|
65
|
+
os.environ.get('MARKER_KIND', ''),
|
|
66
|
+
os.environ.get('MARKER_DEPT', ''),
|
|
67
|
+
os.environ.get('MARKER_LEAD', ''),
|
|
68
|
+
)
|
|
69
|
+
except Exception:
|
|
70
|
+
pass
|
|
71
|
+
" 2>/dev/null || true
|
|
72
|
+
fi
|
|
73
|
+
fi
|
|
27
74
|
|
|
28
75
|
# Only process if there was an error
|
|
29
76
|
if [ "$EXIT_CODE" = "0" ] || [ -z "$EXIT_CODE" ]; then
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# ArkaOS v2 — PreToolUse Hook (Windows PowerShell)
|
|
3
|
+
#
|
|
4
|
+
# Parity with config/hooks/pre-tool-use.sh. Blocks Write/Edit/MultiEdit when
|
|
5
|
+
# the mandatory 13-phase flow is required for the session AND the assistant
|
|
6
|
+
# has not emitted a flow marker in its last 3 messages of the transcript.
|
|
7
|
+
#
|
|
8
|
+
# Delegates the decision to core/workflow/flow_enforcer.py.
|
|
9
|
+
#
|
|
10
|
+
# Exit 0 = allow (silent). Exit 2 = deny + structured hookSpecificOutput JSON.
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
14
|
+
|
|
15
|
+
# --- Read stdin JSON ---
|
|
16
|
+
$inputJson = [Console]::In.ReadToEnd()
|
|
17
|
+
if ([string]::IsNullOrWhiteSpace($inputJson)) { exit 0 }
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
$inp = $inputJson | ConvertFrom-Json
|
|
21
|
+
} catch {
|
|
22
|
+
exit 0
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
$toolName = [string]$inp.tool_name
|
|
26
|
+
$transcriptPath = [string]$inp.transcript_path
|
|
27
|
+
$sessionId = [string]$inp.session_id
|
|
28
|
+
$cwd = [string]$inp.cwd
|
|
29
|
+
|
|
30
|
+
# --- Resolve ARKAOS_ROOT ---
|
|
31
|
+
if ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
|
|
32
|
+
$repoPathFile = Join-Path $HOME ".arkaos/.repo-path"
|
|
33
|
+
if (Test-Path $repoPathFile) {
|
|
34
|
+
$env:ARKAOS_ROOT = (Get-Content $repoPathFile -Raw).Trim()
|
|
35
|
+
} elseif (Test-Path (Join-Path $HOME ".arkaos")) {
|
|
36
|
+
$env:ARKAOS_ROOT = (Join-Path $HOME ".arkaos")
|
|
37
|
+
} else {
|
|
38
|
+
$env:ARKAOS_ROOT = if ($env:ARKA_OS) { $env:ARKA_OS } else { Join-Path $HOME ".claude/skills/arkaos" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
$python = Get-Command python3 -ErrorAction SilentlyContinue
|
|
43
|
+
if (-not $python) { $python = Get-Command python -ErrorAction SilentlyContinue }
|
|
44
|
+
if (-not $python) { exit 0 }
|
|
45
|
+
|
|
46
|
+
# --- KB-first gate (Task #6, runs before flow-marker gate) ---
|
|
47
|
+
$queryHint = ""
|
|
48
|
+
if ($inp.tool_input) {
|
|
49
|
+
if ($inp.tool_input.query) { $queryHint = [string]$inp.tool_input.query }
|
|
50
|
+
elseif ($inp.tool_input.prompt) { $queryHint = [string]$inp.tool_input.prompt }
|
|
51
|
+
elseif ($inp.tool_input.url) { $queryHint = [string]$inp.tool_input.url }
|
|
52
|
+
if ($queryHint.Length -gt 500) { $queryHint = $queryHint.Substring(0, 500) }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
$researchGatePy = Join-Path $env:ARKAOS_ROOT "core/workflow/research_gate.py"
|
|
56
|
+
if (Test-Path $researchGatePy) {
|
|
57
|
+
$env:TOOL_NAME = $toolName
|
|
58
|
+
$env:SESSION_ID = $sessionId
|
|
59
|
+
$env:QUERY_HINT = $queryHint
|
|
60
|
+
|
|
61
|
+
$kbScript = @'
|
|
62
|
+
import json
|
|
63
|
+
import os
|
|
64
|
+
import sys
|
|
65
|
+
|
|
66
|
+
sys.path.insert(0, os.environ["ARKAOS_ROOT"])
|
|
67
|
+
try:
|
|
68
|
+
from core.workflow.research_gate import evaluate_research_gate, record_telemetry
|
|
69
|
+
except Exception:
|
|
70
|
+
print(json.dumps({"allow": True, "nudge": False, "reason": "kb-gate-import-failed"}))
|
|
71
|
+
sys.exit(0)
|
|
72
|
+
|
|
73
|
+
decision = evaluate_research_gate(
|
|
74
|
+
tool_name=os.environ.get("TOOL_NAME", ""),
|
|
75
|
+
session_id=os.environ.get("SESSION_ID", ""),
|
|
76
|
+
query=os.environ.get("QUERY_HINT", ""),
|
|
77
|
+
)
|
|
78
|
+
try:
|
|
79
|
+
record_telemetry(
|
|
80
|
+
session_id=os.environ.get("SESSION_ID", ""),
|
|
81
|
+
tool=os.environ.get("TOOL_NAME", ""),
|
|
82
|
+
decision=decision,
|
|
83
|
+
)
|
|
84
|
+
except Exception:
|
|
85
|
+
pass
|
|
86
|
+
print(json.dumps({
|
|
87
|
+
"allow": decision.allow,
|
|
88
|
+
"nudge": decision.nudge,
|
|
89
|
+
"reason": decision.reason,
|
|
90
|
+
"stderr_msg": decision.to_stderr_message(),
|
|
91
|
+
}))
|
|
92
|
+
'@
|
|
93
|
+
|
|
94
|
+
$kbDecisionJson = $kbScript | & $python.Source -
|
|
95
|
+
if (-not [string]::IsNullOrWhiteSpace($kbDecisionJson)) {
|
|
96
|
+
try {
|
|
97
|
+
$kbDecision = $kbDecisionJson | ConvertFrom-Json
|
|
98
|
+
} catch { $kbDecision = $null }
|
|
99
|
+
|
|
100
|
+
if ($kbDecision -and -not $kbDecision.allow) {
|
|
101
|
+
[Console]::Error.WriteLine($kbDecision.stderr_msg)
|
|
102
|
+
$denyOut = @{
|
|
103
|
+
hookSpecificOutput = @{
|
|
104
|
+
hookEventName = "PreToolUse"
|
|
105
|
+
permissionDecision = "deny"
|
|
106
|
+
permissionDecisionReason = $kbDecision.stderr_msg
|
|
107
|
+
}
|
|
108
|
+
} | ConvertTo-Json -Compress -Depth 5
|
|
109
|
+
Write-Output $denyOut
|
|
110
|
+
exit 2
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if ($kbDecision -and $kbDecision.nudge -and -not [string]::IsNullOrWhiteSpace($kbDecision.stderr_msg)) {
|
|
114
|
+
[Console]::Error.WriteLine($kbDecision.stderr_msg)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# --- Fast allow: not a flow-gated tool ---
|
|
120
|
+
if ($toolName -ne "Write" -and $toolName -ne "Edit" -and $toolName -ne "MultiEdit") {
|
|
121
|
+
exit 0
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
$enforcerPy = Join-Path $env:ARKAOS_ROOT "core/workflow/flow_enforcer.py"
|
|
125
|
+
if (-not (Test-Path $enforcerPy)) { exit 0 }
|
|
126
|
+
|
|
127
|
+
# --- Delegate to Python enforcer ---
|
|
128
|
+
$env:TOOL_NAME = $toolName
|
|
129
|
+
$env:TRANSCRIPT_PATH = $transcriptPath
|
|
130
|
+
$env:SESSION_ID = $sessionId
|
|
131
|
+
$env:CWD = $cwd
|
|
132
|
+
|
|
133
|
+
$pyScript = @'
|
|
134
|
+
import json
|
|
135
|
+
import os
|
|
136
|
+
import sys
|
|
137
|
+
|
|
138
|
+
sys.path.insert(0, os.environ["ARKAOS_ROOT"])
|
|
139
|
+
try:
|
|
140
|
+
from core.workflow.flow_enforcer import evaluate, record_telemetry
|
|
141
|
+
except Exception:
|
|
142
|
+
print(json.dumps({"allow": True, "reason": "enforcer-import-failed"}))
|
|
143
|
+
sys.exit(0)
|
|
144
|
+
|
|
145
|
+
decision = evaluate(
|
|
146
|
+
tool_name=os.environ.get("TOOL_NAME", ""),
|
|
147
|
+
transcript_path=os.environ.get("TRANSCRIPT_PATH", ""),
|
|
148
|
+
session_id=os.environ.get("SESSION_ID", ""),
|
|
149
|
+
cwd=os.environ.get("CWD", ""),
|
|
150
|
+
)
|
|
151
|
+
try:
|
|
152
|
+
record_telemetry(
|
|
153
|
+
session_id=os.environ.get("SESSION_ID", ""),
|
|
154
|
+
tool=os.environ.get("TOOL_NAME", ""),
|
|
155
|
+
decision=decision,
|
|
156
|
+
cwd=os.environ.get("CWD", ""),
|
|
157
|
+
)
|
|
158
|
+
except Exception:
|
|
159
|
+
pass
|
|
160
|
+
print(json.dumps({
|
|
161
|
+
"allow": decision.allow,
|
|
162
|
+
"reason": decision.reason,
|
|
163
|
+
"stderr_msg": decision.to_stderr_message(),
|
|
164
|
+
}))
|
|
165
|
+
'@
|
|
166
|
+
|
|
167
|
+
$decisionJson = $pyScript | & $python.Source -
|
|
168
|
+
if ([string]::IsNullOrWhiteSpace($decisionJson)) { exit 0 }
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
$decision = $decisionJson | ConvertFrom-Json
|
|
172
|
+
} catch {
|
|
173
|
+
exit 0
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if ($decision.allow) { exit 0 }
|
|
177
|
+
|
|
178
|
+
# --- Deny path ---
|
|
179
|
+
[Console]::Error.WriteLine($decision.stderr_msg)
|
|
180
|
+
|
|
181
|
+
$denyOut = @{
|
|
182
|
+
hookSpecificOutput = @{
|
|
183
|
+
hookEventName = "PreToolUse"
|
|
184
|
+
permissionDecision = "deny"
|
|
185
|
+
permissionDecisionReason = $decision.stderr_msg
|
|
186
|
+
}
|
|
187
|
+
} | ConvertTo-Json -Compress -Depth 5
|
|
188
|
+
|
|
189
|
+
Write-Output $denyOut
|
|
190
|
+
exit 2
|