arkaos 2.20.1 → 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/post-tool-use.ps1 +80 -0
- package/config/hooks/post-tool-use.sh +47 -0
- package/config/hooks/pre-tool-use.ps1 +81 -8
- package/config/hooks/pre-tool-use.sh +81 -7
- package/config/hooks/stop.ps1 +79 -0
- package/config/hooks/stop.sh +88 -0
- package/config/hooks/user-prompt-submit.ps1 +50 -0
- package/config/hooks/user-prompt-submit.sh +24 -0
- 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 +14 -3
- 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/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/`
|
|
@@ -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
|
|
@@ -27,11 +27,6 @@ $transcriptPath = [string]$inp.transcript_path
|
|
|
27
27
|
$sessionId = [string]$inp.session_id
|
|
28
28
|
$cwd = [string]$inp.cwd
|
|
29
29
|
|
|
30
|
-
# --- Fast allow: not a gated tool ---
|
|
31
|
-
if ($toolName -ne "Write" -and $toolName -ne "Edit" -and $toolName -ne "MultiEdit") {
|
|
32
|
-
exit 0
|
|
33
|
-
}
|
|
34
|
-
|
|
35
30
|
# --- Resolve ARKAOS_ROOT ---
|
|
36
31
|
if ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
|
|
37
32
|
$repoPathFile = Join-Path $HOME ".arkaos/.repo-path"
|
|
@@ -44,13 +39,91 @@ if ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
|
|
|
44
39
|
}
|
|
45
40
|
}
|
|
46
41
|
|
|
47
|
-
$enforcerPy = Join-Path $env:ARKAOS_ROOT "core/workflow/flow_enforcer.py"
|
|
48
|
-
if (-not (Test-Path $enforcerPy)) { exit 0 }
|
|
49
|
-
|
|
50
42
|
$python = Get-Command python3 -ErrorAction SilentlyContinue
|
|
51
43
|
if (-not $python) { $python = Get-Command python -ErrorAction SilentlyContinue }
|
|
52
44
|
if (-not $python) { exit 0 }
|
|
53
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
|
+
|
|
54
127
|
# --- Delegate to Python enforcer ---
|
|
55
128
|
$env:TOOL_NAME = $toolName
|
|
56
129
|
$env:TRANSCRIPT_PATH = $transcriptPath
|
|
@@ -31,12 +31,6 @@ if command -v jq &>/dev/null; then
|
|
|
31
31
|
CWD=$(echo "$input" | jq -r '.cwd // ""' 2>/dev/null)
|
|
32
32
|
fi
|
|
33
33
|
|
|
34
|
-
# ─── Fast allow: not a gated tool
|
|
35
|
-
case "$TOOL_NAME" in
|
|
36
|
-
Write|Edit|MultiEdit) ;;
|
|
37
|
-
*) exit 0 ;;
|
|
38
|
-
esac
|
|
39
|
-
|
|
40
34
|
# ─── Resolve ARKAOS_ROOT (same rules as user-prompt-submit.sh) ──────────
|
|
41
35
|
if [ -z "${ARKAOS_ROOT:-}" ]; then
|
|
42
36
|
if [ -f "$HOME/.arkaos/.repo-path" ]; then
|
|
@@ -48,10 +42,90 @@ if [ -z "${ARKAOS_ROOT:-}" ]; then
|
|
|
48
42
|
fi
|
|
49
43
|
fi
|
|
50
44
|
|
|
51
|
-
# ─── Degrade gracefully if Python
|
|
45
|
+
# ─── Degrade gracefully if Python is unavailable ────────────────────────
|
|
52
46
|
if ! command -v python3 &>/dev/null; then
|
|
53
47
|
exit 0
|
|
54
48
|
fi
|
|
49
|
+
|
|
50
|
+
# ─── KB-first gate (Task #6, independent from flow_enforcer) ────────────
|
|
51
|
+
# Runs BEFORE the flow-marker gate so that external research tools are
|
|
52
|
+
# always KB-checked regardless of whether the tool is Write/Edit/MultiEdit.
|
|
53
|
+
# Extract the user query (if present) to feed the nudge generator.
|
|
54
|
+
QUERY_HINT=""
|
|
55
|
+
if command -v jq &>/dev/null; then
|
|
56
|
+
QUERY_HINT=$(echo "$input" | jq -r '.tool_input.query // .tool_input.prompt // .tool_input.url // ""' 2>/dev/null | head -c 500)
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if [ -f "$ARKAOS_ROOT/core/workflow/research_gate.py" ]; then
|
|
60
|
+
KB_DECISION_JSON=$(TOOL_NAME="$TOOL_NAME" \
|
|
61
|
+
SESSION_ID="$SESSION_ID" \
|
|
62
|
+
QUERY_HINT="$QUERY_HINT" \
|
|
63
|
+
ARKAOS_ROOT="$ARKAOS_ROOT" \
|
|
64
|
+
python3 - <<'PY' 2>/dev/null
|
|
65
|
+
import json
|
|
66
|
+
import os
|
|
67
|
+
import sys
|
|
68
|
+
|
|
69
|
+
sys.path.insert(0, os.environ["ARKAOS_ROOT"])
|
|
70
|
+
try:
|
|
71
|
+
from core.workflow.research_gate import evaluate_research_gate, record_telemetry
|
|
72
|
+
except Exception:
|
|
73
|
+
print(json.dumps({"allow": True, "nudge": False, "reason": "kb-gate-import-failed"}))
|
|
74
|
+
sys.exit(0)
|
|
75
|
+
|
|
76
|
+
decision = evaluate_research_gate(
|
|
77
|
+
tool_name=os.environ.get("TOOL_NAME", ""),
|
|
78
|
+
session_id=os.environ.get("SESSION_ID", ""),
|
|
79
|
+
query=os.environ.get("QUERY_HINT", ""),
|
|
80
|
+
)
|
|
81
|
+
try:
|
|
82
|
+
record_telemetry(
|
|
83
|
+
session_id=os.environ.get("SESSION_ID", ""),
|
|
84
|
+
tool=os.environ.get("TOOL_NAME", ""),
|
|
85
|
+
decision=decision,
|
|
86
|
+
)
|
|
87
|
+
except Exception:
|
|
88
|
+
pass
|
|
89
|
+
print(json.dumps({
|
|
90
|
+
"allow": decision.allow,
|
|
91
|
+
"nudge": decision.nudge,
|
|
92
|
+
"reason": decision.reason,
|
|
93
|
+
"stderr_msg": decision.to_stderr_message(),
|
|
94
|
+
}))
|
|
95
|
+
PY
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if [ -n "$KB_DECISION_JSON" ]; then
|
|
99
|
+
KB_ALLOW=$(echo "$KB_DECISION_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('allow', True))" 2>/dev/null)
|
|
100
|
+
KB_NUDGE=$(echo "$KB_DECISION_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('nudge', False))" 2>/dev/null)
|
|
101
|
+
KB_STDERR=$(echo "$KB_DECISION_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('stderr_msg',''))" 2>/dev/null)
|
|
102
|
+
|
|
103
|
+
if [ "$KB_ALLOW" != "True" ] && [ "$KB_ALLOW" != "true" ]; then
|
|
104
|
+
echo "$KB_STDERR" >&2
|
|
105
|
+
STDERR_MSG="$KB_STDERR" python3 - <<'PY'
|
|
106
|
+
import json, os
|
|
107
|
+
print(json.dumps({"hookSpecificOutput": {
|
|
108
|
+
"hookEventName": "PreToolUse",
|
|
109
|
+
"permissionDecision": "deny",
|
|
110
|
+
"permissionDecisionReason": os.environ.get("STDERR_MSG", ""),
|
|
111
|
+
}}))
|
|
112
|
+
PY
|
|
113
|
+
exit 2
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Nudge path: emit advisory to stderr, continue to flow-marker gate.
|
|
117
|
+
if [ "$KB_NUDGE" = "True" ] || [ "$KB_NUDGE" = "true" ]; then
|
|
118
|
+
[ -n "$KB_STDERR" ] && echo "$KB_STDERR" >&2
|
|
119
|
+
fi
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# ─── Fast allow: not a flow-gated tool (Write/Edit/MultiEdit) ───────────
|
|
124
|
+
case "$TOOL_NAME" in
|
|
125
|
+
Write|Edit|MultiEdit) ;;
|
|
126
|
+
*) exit 0 ;;
|
|
127
|
+
esac
|
|
128
|
+
|
|
55
129
|
if [ ! -f "$ARKAOS_ROOT/core/workflow/flow_enforcer.py" ]; then
|
|
56
130
|
exit 0
|
|
57
131
|
fi
|
package/config/hooks/stop.ps1
CHANGED
|
@@ -104,6 +104,85 @@ except Exception:
|
|
|
104
104
|
|
|
105
105
|
$pyScript | & $python.Source - | Out-Null
|
|
106
106
|
|
|
107
|
+
# ─── Auto-documentor enqueue (fire-and-forget) ─────────────────────────
|
|
108
|
+
# Queues a background job when classifier flagged flow, QG approved, and
|
|
109
|
+
# external research happened. Never blocks the Stop hook.
|
|
110
|
+
$env:SESSION_ID_VAL = $sessionId
|
|
111
|
+
$env:TRANSCRIPT_PATH_VAL = $transcriptPath
|
|
112
|
+
$env:CWD_VAL = $cwd
|
|
113
|
+
$env:ARKAOS_ROOT = $env:ARKAOS_ROOT
|
|
114
|
+
|
|
115
|
+
$autoDocScript = @'
|
|
116
|
+
import json
|
|
117
|
+
import os
|
|
118
|
+
import re
|
|
119
|
+
import sys
|
|
120
|
+
from pathlib import Path
|
|
121
|
+
|
|
122
|
+
sys.path.insert(0, os.environ.get("ARKAOS_ROOT", ""))
|
|
123
|
+
try:
|
|
124
|
+
from core.jobs.auto_doc_worker import enqueue_job
|
|
125
|
+
from core.workflow.flow_enforcer import _load_last_assistant_messages
|
|
126
|
+
except Exception:
|
|
127
|
+
sys.exit(0)
|
|
128
|
+
|
|
129
|
+
session_id = os.environ.get("SESSION_ID_VAL", "")
|
|
130
|
+
transcript_path = os.environ.get("TRANSCRIPT_PATH_VAL", "")
|
|
131
|
+
if not session_id or not transcript_path:
|
|
132
|
+
sys.exit(0)
|
|
133
|
+
|
|
134
|
+
last = ""
|
|
135
|
+
try:
|
|
136
|
+
msgs = _load_last_assistant_messages(transcript_path, n=1)
|
|
137
|
+
last = msgs[-1] if msgs else ""
|
|
138
|
+
except Exception:
|
|
139
|
+
last = ""
|
|
140
|
+
|
|
141
|
+
qg_approved = bool(re.search(r"\[arka:qg:approved\]", last, re.IGNORECASE))
|
|
142
|
+
if not qg_approved:
|
|
143
|
+
qg_log = Path.home() / ".arkaos" / "telemetry" / "qg.jsonl"
|
|
144
|
+
if qg_log.exists():
|
|
145
|
+
try:
|
|
146
|
+
for line in reversed(qg_log.read_text(encoding="utf-8").splitlines()):
|
|
147
|
+
if not line.strip():
|
|
148
|
+
continue
|
|
149
|
+
try:
|
|
150
|
+
rec = json.loads(line)
|
|
151
|
+
except Exception:
|
|
152
|
+
continue
|
|
153
|
+
if rec.get("session_id") == session_id:
|
|
154
|
+
qg_approved = rec.get("verdict", "").upper() == "APPROVED"
|
|
155
|
+
break
|
|
156
|
+
except Exception:
|
|
157
|
+
pass
|
|
158
|
+
if not qg_approved:
|
|
159
|
+
sys.exit(0)
|
|
160
|
+
|
|
161
|
+
external_markers = (
|
|
162
|
+
"WebFetch", "WebSearch", "mcp__context7", "mcp__firecrawl",
|
|
163
|
+
"http://", "https://",
|
|
164
|
+
)
|
|
165
|
+
has_external = False
|
|
166
|
+
try:
|
|
167
|
+
data = Path(transcript_path).read_text(encoding="utf-8", errors="replace")
|
|
168
|
+
has_external = any(marker in data for marker in external_markers)
|
|
169
|
+
except Exception:
|
|
170
|
+
has_external = False
|
|
171
|
+
if not has_external:
|
|
172
|
+
sys.exit(0)
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
enqueue_job(session_id, transcript_path, "APPROVED")
|
|
176
|
+
except Exception:
|
|
177
|
+
pass
|
|
178
|
+
'@
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
$autoDocScript | & $python.Source - | Out-Null
|
|
182
|
+
} catch {
|
|
183
|
+
# Swallow — enqueue is fire-and-forget.
|
|
184
|
+
}
|
|
185
|
+
|
|
107
186
|
# Belt-and-braces marker cleanup (safe even if the Python block crashed).
|
|
108
187
|
if ($sessionId -match '^[A-Za-z0-9._-]{1,128}$') {
|
|
109
188
|
Remove-Item -LiteralPath $wfMarker -ErrorAction SilentlyContinue
|
package/config/hooks/stop.sh
CHANGED
|
@@ -115,6 +115,94 @@ except Exception:
|
|
|
115
115
|
pass
|
|
116
116
|
PY
|
|
117
117
|
|
|
118
|
+
# ─── Auto-documentor enqueue (fire-and-forget) ──────────────────────────
|
|
119
|
+
# Queues a background job when:
|
|
120
|
+
# (a) the session was flagged flow-required (classifier match above),
|
|
121
|
+
# (b) Quality Gate approved — last assistant message carries
|
|
122
|
+
# `[arka:qg:approved]`, OR the most recent entry for this session
|
|
123
|
+
# in ~/.arkaos/telemetry/qg.jsonl has verdict APPROVED, AND
|
|
124
|
+
# (c) at least one external research tool was invoked this session
|
|
125
|
+
# (URL, WebFetch/WebSearch, Context7, Firecrawl in the transcript).
|
|
126
|
+
# The actual documentation runs async via `core/jobs/auto_doc_worker.py`;
|
|
127
|
+
# this block never blocks Stop — 2s Python budget, errors swallowed.
|
|
128
|
+
if command -v timeout &>/dev/null; then
|
|
129
|
+
_ARKA_AUTO_DOC_RUNNER=(timeout 2s python3 -)
|
|
130
|
+
elif command -v gtimeout &>/dev/null; then
|
|
131
|
+
_ARKA_AUTO_DOC_RUNNER=(gtimeout 2s python3 -)
|
|
132
|
+
else
|
|
133
|
+
_ARKA_AUTO_DOC_RUNNER=(python3 -)
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
SESSION_ID_VAL="$SESSION_ID" \
|
|
137
|
+
TRANSCRIPT_PATH_VAL="$TRANSCRIPT_PATH" \
|
|
138
|
+
CWD_VAL="$CWD" \
|
|
139
|
+
ARKAOS_ROOT_VAL="$ARKAOS_ROOT" \
|
|
140
|
+
"${_ARKA_AUTO_DOC_RUNNER[@]}" <<'PY' 2>/dev/null || true
|
|
141
|
+
import json
|
|
142
|
+
import os
|
|
143
|
+
import re
|
|
144
|
+
import sys
|
|
145
|
+
from pathlib import Path
|
|
146
|
+
|
|
147
|
+
sys.path.insert(0, os.environ["ARKAOS_ROOT_VAL"])
|
|
148
|
+
try:
|
|
149
|
+
from core.jobs.auto_doc_worker import enqueue_job
|
|
150
|
+
from core.workflow.flow_enforcer import _load_last_assistant_messages
|
|
151
|
+
except Exception:
|
|
152
|
+
sys.exit(0)
|
|
153
|
+
|
|
154
|
+
session_id = os.environ.get("SESSION_ID_VAL", "")
|
|
155
|
+
transcript_path = os.environ.get("TRANSCRIPT_PATH_VAL", "")
|
|
156
|
+
if not session_id or not transcript_path:
|
|
157
|
+
sys.exit(0)
|
|
158
|
+
|
|
159
|
+
last = ""
|
|
160
|
+
try:
|
|
161
|
+
msgs = _load_last_assistant_messages(transcript_path, n=1)
|
|
162
|
+
last = msgs[-1] if msgs else ""
|
|
163
|
+
except Exception:
|
|
164
|
+
last = ""
|
|
165
|
+
|
|
166
|
+
qg_approved = bool(re.search(r"\[arka:qg:approved\]", last, re.IGNORECASE))
|
|
167
|
+
if not qg_approved:
|
|
168
|
+
qg_log = Path.home() / ".arkaos" / "telemetry" / "qg.jsonl"
|
|
169
|
+
if qg_log.exists():
|
|
170
|
+
try:
|
|
171
|
+
for line in reversed(qg_log.read_text(encoding="utf-8").splitlines()):
|
|
172
|
+
if not line.strip():
|
|
173
|
+
continue
|
|
174
|
+
try:
|
|
175
|
+
rec = json.loads(line)
|
|
176
|
+
except Exception:
|
|
177
|
+
continue
|
|
178
|
+
if rec.get("session_id") == session_id:
|
|
179
|
+
qg_approved = rec.get("verdict", "").upper() == "APPROVED"
|
|
180
|
+
break
|
|
181
|
+
except Exception:
|
|
182
|
+
pass
|
|
183
|
+
if not qg_approved:
|
|
184
|
+
sys.exit(0)
|
|
185
|
+
|
|
186
|
+
# Heuristic check that some external research happened this session.
|
|
187
|
+
external_markers = (
|
|
188
|
+
"WebFetch", "WebSearch", "mcp__context7", "mcp__firecrawl",
|
|
189
|
+
"http://", "https://",
|
|
190
|
+
)
|
|
191
|
+
has_external = False
|
|
192
|
+
try:
|
|
193
|
+
data = Path(transcript_path).read_text(encoding="utf-8", errors="replace")
|
|
194
|
+
has_external = any(marker in data for marker in external_markers)
|
|
195
|
+
except Exception:
|
|
196
|
+
has_external = False
|
|
197
|
+
if not has_external:
|
|
198
|
+
sys.exit(0)
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
enqueue_job(session_id, transcript_path, "APPROVED")
|
|
202
|
+
except Exception:
|
|
203
|
+
pass
|
|
204
|
+
PY
|
|
205
|
+
|
|
118
206
|
# Belt-and-braces: remove the marker at shell level in case the Python
|
|
119
207
|
# block above crashed before reaching clear_flow_required(). Session_id
|
|
120
208
|
# is already validated by the Python helper; this shell remove is scoped
|
|
@@ -63,6 +63,56 @@ if (-not $v2Installed) {
|
|
|
63
63
|
# --- Performance timing ----------------------------------------------------
|
|
64
64
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
|
65
65
|
|
|
66
|
+
# --- Flow marker cache invalidation (v2 — new turn resets ALLOW cache) ---
|
|
67
|
+
# Runs before the Synapse bridge so a stuck Python call cannot leave a
|
|
68
|
+
# stale marker across turns. Non-blocking — all failures swallowed.
|
|
69
|
+
try {
|
|
70
|
+
$sessionIdUps = ''
|
|
71
|
+
if ($payload -and $payload.session_id) {
|
|
72
|
+
$sessionIdUps = [string]$payload.session_id
|
|
73
|
+
}
|
|
74
|
+
if ($sessionIdUps) {
|
|
75
|
+
$arkaosRootUps = $env:ARKAOS_ROOT
|
|
76
|
+
if (-not $arkaosRootUps) {
|
|
77
|
+
$repoPathFileUps = Join-Path $env:USERPROFILE '.arkaos\.repo-path'
|
|
78
|
+
if (Test-Path -LiteralPath $repoPathFileUps) {
|
|
79
|
+
try {
|
|
80
|
+
$arkaosRootUps = (Get-Content -Raw -LiteralPath $repoPathFileUps -Encoding UTF8).Trim()
|
|
81
|
+
} catch { }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (-not $arkaosRootUps) {
|
|
85
|
+
$arkaosRootUps = Join-Path $env:USERPROFILE '.arkaos'
|
|
86
|
+
}
|
|
87
|
+
$pythonForInvalidate = $null
|
|
88
|
+
$venvPyUps = Join-Path $env:USERPROFILE '.arkaos\venv\Scripts\python.exe'
|
|
89
|
+
if (Test-Path -LiteralPath $venvPyUps) {
|
|
90
|
+
$pythonForInvalidate = $venvPyUps
|
|
91
|
+
} else {
|
|
92
|
+
foreach ($cmd in 'python3','python','py') {
|
|
93
|
+
$resolvedUps = Get-Command $cmd -ErrorAction SilentlyContinue
|
|
94
|
+
if ($resolvedUps) { $pythonForInvalidate = $resolvedUps.Source; break }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if ($pythonForInvalidate) {
|
|
98
|
+
$pyCode = "import os`ntry:`n from core.workflow.marker_cache import invalidate_marker`n invalidate_marker(os.environ.get('SESSION_ID_UPS',''))`nexcept Exception:`n pass`ntry:`n from core.synapse.kb_cache import invalidate_obsidian_query`n invalidate_obsidian_query(os.environ.get('SESSION_ID_UPS',''))`nexcept Exception:`n pass"
|
|
99
|
+
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
100
|
+
$psi.FileName = $pythonForInvalidate
|
|
101
|
+
$psi.Arguments = "-c `"$($pyCode -replace '"','\"' -replace "`r?`n",'; ')`""
|
|
102
|
+
$psi.UseShellExecute = $false
|
|
103
|
+
$psi.CreateNoWindow = $true
|
|
104
|
+
$psi.RedirectStandardOutput = $true
|
|
105
|
+
$psi.RedirectStandardError = $true
|
|
106
|
+
[void]$psi.EnvironmentVariables.Add('SESSION_ID_UPS', $sessionIdUps)
|
|
107
|
+
[void]$psi.EnvironmentVariables.Add('PYTHONPATH', $arkaosRootUps)
|
|
108
|
+
try {
|
|
109
|
+
$procUps = [System.Diagnostics.Process]::Start($psi)
|
|
110
|
+
if (-not $procUps.WaitForExit(1500)) { try { $procUps.Kill() } catch { } }
|
|
111
|
+
} catch { }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch { }
|
|
115
|
+
|
|
66
116
|
# --- Sync version detection ------------------------------------------------
|
|
67
117
|
$syncNotice = ''
|
|
68
118
|
$arkaosHome = Join-Path $env:USERPROFILE '.arkaos'
|