@vigolium/piolium 0.0.1
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/LICENSE +21 -0
- package/README.md +117 -0
- package/agents/access-auditor.md +300 -0
- package/agents/assumption-breaker.md +154 -0
- package/agents/attack-designer.md +116 -0
- package/agents/code-scanner.md +139 -0
- package/agents/concurrency-auditor.md +238 -0
- package/agents/confirm-writer.md +257 -0
- package/agents/context-reviewer.md +274 -0
- package/agents/cross-verifier.md +165 -0
- package/agents/cve-scout.md +381 -0
- package/agents/env-builder.md +282 -0
- package/agents/env-profiler.md +205 -0
- package/agents/evidence-collector.md +140 -0
- package/agents/finding-grader.md +142 -0
- package/agents/finding-writer.md +148 -0
- package/agents/flow-tracer.md +106 -0
- package/agents/goal-backtracer.md +146 -0
- package/agents/history-miner.md +467 -0
- package/agents/independent-verifier.md +118 -0
- package/agents/intent-mapper.md +183 -0
- package/agents/longshot-collector.md +128 -0
- package/agents/longshot-prober.md +126 -0
- package/agents/patch-auditor.md +73 -0
- package/agents/poc-author.md +124 -0
- package/agents/poc-runner.md +194 -0
- package/agents/probe-lead.md +269 -0
- package/agents/red-challenger.md +101 -0
- package/agents/report-composer.md +208 -0
- package/agents/review-adjudicator.md +216 -0
- package/agents/spec-auditor.md +155 -0
- package/agents/taint-tracer.md +265 -0
- package/agents/test-locator.md +209 -0
- package/agents/threat-modeler.md +132 -0
- package/agents/variant-scanner.md +108 -0
- package/agents/variant-spotter.md +110 -0
- package/bin/piolium.mjs +376 -0
- package/extensions/piolium/_vendor/yaml.bundle.d.mts +6 -0
- package/extensions/piolium/_vendor/yaml.bundle.mjs +139 -0
- package/extensions/piolium/agent-runner.ts +322 -0
- package/extensions/piolium/agents.ts +266 -0
- package/extensions/piolium/audit-state.ts +522 -0
- package/extensions/piolium/bundled-resources.ts +97 -0
- package/extensions/piolium/candidate-scan.ts +966 -0
- package/extensions/piolium/command-target.ts +177 -0
- package/extensions/piolium/console-stream.ts +57 -0
- package/extensions/piolium/export-results.ts +380 -0
- package/extensions/piolium/findings.ts +448 -0
- package/extensions/piolium/heartbeat.ts +182 -0
- package/extensions/piolium/help.ts +234 -0
- package/extensions/piolium/index.ts +1865 -0
- package/extensions/piolium/longshot.ts +530 -0
- package/extensions/piolium/matcher-suggestions.ts +196 -0
- package/extensions/piolium/matcher-utils.ts +83 -0
- package/extensions/piolium/modes/balanced.ts +750 -0
- package/extensions/piolium/modes/confirm-bootstrap.ts +186 -0
- package/extensions/piolium/modes/confirm.ts +697 -0
- package/extensions/piolium/modes/deep.ts +917 -0
- package/extensions/piolium/modes/diff.ts +177 -0
- package/extensions/piolium/modes/lite.ts +540 -0
- package/extensions/piolium/modes/longshot.ts +595 -0
- package/extensions/piolium/modes/merge.ts +204 -0
- package/extensions/piolium/modes/phase-runner.ts +267 -0
- package/extensions/piolium/modes/reinvest.ts +546 -0
- package/extensions/piolium/modes/revisit.ts +279 -0
- package/extensions/piolium/modes.ts +48 -0
- package/extensions/piolium/phase-labels.ts +123 -0
- package/extensions/piolium/phase-status-strip.ts +92 -0
- package/extensions/piolium/prompt-prefix-editor.ts +39 -0
- package/extensions/piolium/providers/anthropic-vertex.ts +836 -0
- package/extensions/piolium/recon.ts +409 -0
- package/extensions/piolium/result-stats.ts +105 -0
- package/extensions/piolium/retry.ts +120 -0
- package/extensions/piolium/scheduler.ts +212 -0
- package/extensions/piolium/secrets.ts +368 -0
- package/extensions/piolium/tools/web-tools.ts +148 -0
- package/package.json +77 -0
- package/skills/agentic-actions-auditor/SKILL.md +327 -0
- package/skills/agentic-actions-auditor/references/action-profiles.md +186 -0
- package/skills/agentic-actions-auditor/references/cross-file-resolution.md +209 -0
- package/skills/agentic-actions-auditor/references/foundations.md +94 -0
- package/skills/agentic-actions-auditor/references/vector-a-env-var-intermediary.md +77 -0
- package/skills/agentic-actions-auditor/references/vector-b-direct-expression-injection.md +83 -0
- package/skills/agentic-actions-auditor/references/vector-c-cli-data-fetch.md +83 -0
- package/skills/agentic-actions-auditor/references/vector-d-pr-target-checkout.md +88 -0
- package/skills/agentic-actions-auditor/references/vector-e-error-log-injection.md +88 -0
- package/skills/agentic-actions-auditor/references/vector-f-subshell-expansion.md +82 -0
- package/skills/agentic-actions-auditor/references/vector-g-eval-of-ai-output.md +91 -0
- package/skills/agentic-actions-auditor/references/vector-h-dangerous-sandbox-configs.md +102 -0
- package/skills/agentic-actions-auditor/references/vector-i-wildcard-allowlists.md +88 -0
- package/skills/audit/SKILL.md +562 -0
- package/skills/audit/assets/icon.svg +7 -0
- package/skills/audit/hooks/scripts/validate_phase_output.py +550 -0
- package/skills/audit/references/adversarial-review.md +148 -0
- package/skills/audit/references/architecture-aware-sast.md +306 -0
- package/skills/audit/references/audit-workflow.md +737 -0
- package/skills/audit/references/chamber-protocol.md +384 -0
- package/skills/audit/references/creative-attack-modes.md +221 -0
- package/skills/audit/references/deep-analysis.md +273 -0
- package/skills/audit/references/domain-attack-playbooks.md +1129 -0
- package/skills/audit/references/knowledge-base-template.md +513 -0
- package/skills/audit/references/real-env-validation.md +191 -0
- package/skills/audit/references/report-templates.md +417 -0
- package/skills/audit/references/triage-and-prereqs.md +134 -0
- package/skills/audit/scripts/consolidate_drafts.py +554 -0
- package/skills/audit/scripts/partition_findings.py +152 -0
- package/skills/audit/scripts/rg-hotspots.sh +121 -0
- package/skills/audit/scripts/stamp_file_state.py +349 -0
- package/skills/code-reviewer/SKILL.md +65 -0
- package/skills/codeql/SKILL.md +281 -0
- package/skills/codeql/references/build-fixes.md +90 -0
- package/skills/codeql/references/diagnostic-query-templates.md +339 -0
- package/skills/codeql/references/extension-yaml-format.md +209 -0
- package/skills/codeql/references/important-only-suite.md +153 -0
- package/skills/codeql/references/language-details.md +207 -0
- package/skills/codeql/references/macos-arm64e-workaround.md +179 -0
- package/skills/codeql/references/performance-tuning.md +111 -0
- package/skills/codeql/references/quality-assessment.md +172 -0
- package/skills/codeql/references/ruleset-catalog.md +63 -0
- package/skills/codeql/references/run-all-suite.md +92 -0
- package/skills/codeql/references/sarif-processing.md +79 -0
- package/skills/codeql/references/threat-models.md +51 -0
- package/skills/codeql/workflows/build-database.md +280 -0
- package/skills/codeql/workflows/create-data-extensions.md +261 -0
- package/skills/codeql/workflows/run-analysis.md +301 -0
- package/skills/differential-review/SKILL.md +220 -0
- package/skills/differential-review/adversarial.md +203 -0
- package/skills/differential-review/methodology.md +234 -0
- package/skills/differential-review/patterns.md +300 -0
- package/skills/differential-review/reporting.md +369 -0
- package/skills/fp-check/SKILL.md +125 -0
- package/skills/fp-check/references/bug-class-verification.md +114 -0
- package/skills/fp-check/references/deep-verification.md +143 -0
- package/skills/fp-check/references/evidence-templates.md +91 -0
- package/skills/fp-check/references/false-positive-patterns.md +115 -0
- package/skills/fp-check/references/gate-reviews.md +27 -0
- package/skills/fp-check/references/standard-verification.md +78 -0
- package/skills/insecure-defaults/SKILL.md +117 -0
- package/skills/insecure-defaults/references/examples.md +409 -0
- package/skills/last30days/SKILL.md +444 -0
- package/skills/sarif-parsing/SKILL.md +483 -0
- package/skills/sarif-parsing/resources/jq-queries.md +162 -0
- package/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
- package/skills/security-threat-model/LICENSE.txt +201 -0
- package/skills/security-threat-model/SKILL.md +81 -0
- package/skills/security-threat-model/agents/openai.yaml +4 -0
- package/skills/security-threat-model/references/prompt-template.md +255 -0
- package/skills/security-threat-model/references/security-controls-and-assets.md +32 -0
- package/skills/semgrep/SKILL.md +212 -0
- package/skills/semgrep/references/rulesets.md +162 -0
- package/skills/semgrep/references/scan-modes.md +110 -0
- package/skills/semgrep/references/scanner-task-prompt.md +140 -0
- package/skills/semgrep/scripts/merge_sarif.py +203 -0
- package/skills/semgrep/workflows/scan-workflow.md +311 -0
- package/skills/semgrep-rule-creator/SKILL.md +168 -0
- package/skills/semgrep-rule-creator/references/quick-reference.md +202 -0
- package/skills/semgrep-rule-creator/references/workflow.md +240 -0
- package/skills/semgrep-rule-variant-creator/SKILL.md +205 -0
- package/skills/semgrep-rule-variant-creator/references/applicability-analysis.md +250 -0
- package/skills/semgrep-rule-variant-creator/references/language-syntax-guide.md +324 -0
- package/skills/semgrep-rule-variant-creator/references/workflow.md +518 -0
- package/skills/sharp-edges/SKILL.md +292 -0
- package/skills/sharp-edges/references/auth-patterns.md +252 -0
- package/skills/sharp-edges/references/case-studies.md +274 -0
- package/skills/sharp-edges/references/config-patterns.md +333 -0
- package/skills/sharp-edges/references/crypto-apis.md +190 -0
- package/skills/sharp-edges/references/lang-c.md +205 -0
- package/skills/sharp-edges/references/lang-csharp.md +285 -0
- package/skills/sharp-edges/references/lang-go.md +270 -0
- package/skills/sharp-edges/references/lang-java.md +263 -0
- package/skills/sharp-edges/references/lang-javascript.md +269 -0
- package/skills/sharp-edges/references/lang-kotlin.md +265 -0
- package/skills/sharp-edges/references/lang-php.md +245 -0
- package/skills/sharp-edges/references/lang-python.md +274 -0
- package/skills/sharp-edges/references/lang-ruby.md +273 -0
- package/skills/sharp-edges/references/lang-rust.md +272 -0
- package/skills/sharp-edges/references/lang-swift.md +287 -0
- package/skills/sharp-edges/references/language-specific.md +588 -0
- package/skills/spec-to-code-compliance/SKILL.md +357 -0
- package/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
- package/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
- package/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
- package/skills/supply-chain-risk-auditor/SKILL.md +67 -0
- package/skills/supply-chain-risk-auditor/resources/results-template.md +41 -0
- package/skills/variant-analysis/METHODOLOGY.md +327 -0
- package/skills/variant-analysis/SKILL.md +142 -0
- package/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
- package/skills/variant-analysis/resources/codeql/go.ql +69 -0
- package/skills/variant-analysis/resources/codeql/java.ql +71 -0
- package/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
- package/skills/variant-analysis/resources/codeql/python.ql +80 -0
- package/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
- package/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
- package/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
- package/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
- package/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
- package/skills/variant-analysis/resources/variant-report-template.md +75 -0
- package/skills/vuln-report/SKILL.md +137 -0
- package/skills/vuln-report/agents/openai.yaml +4 -0
- package/skills/vuln-report/references/report-template.md +135 -0
- package/skills/wooyun-legacy/SKILL.md +367 -0
- package/skills/wooyun-legacy/references/bank-penetration.md +222 -0
- package/skills/wooyun-legacy/references/checklists/command-execution-checklist.md +119 -0
- package/skills/wooyun-legacy/references/checklists/csrf-checklist.md +74 -0
- package/skills/wooyun-legacy/references/checklists/file-upload-checklist.md +108 -0
- package/skills/wooyun-legacy/references/checklists/info-disclosure-checklist.md +114 -0
- package/skills/wooyun-legacy/references/checklists/logic-flaws-checklist.md +95 -0
- package/skills/wooyun-legacy/references/checklists/misconfig-checklist.md +124 -0
- package/skills/wooyun-legacy/references/checklists/path-traversal-checklist.md +87 -0
- package/skills/wooyun-legacy/references/checklists/rce-checklist.md +93 -0
- package/skills/wooyun-legacy/references/checklists/sql-injection-checklist.md +97 -0
- package/skills/wooyun-legacy/references/checklists/ssrf-checklist.md +99 -0
- package/skills/wooyun-legacy/references/checklists/unauthorized-access-checklist.md +89 -0
- package/skills/wooyun-legacy/references/checklists/weak-password-checklist.md +115 -0
- package/skills/wooyun-legacy/references/checklists/xss-checklist.md +103 -0
- package/skills/wooyun-legacy/references/checklists/xxe-checklist.md +130 -0
- package/skills/wooyun-legacy/references/info-disclosure.md +975 -0
- package/skills/wooyun-legacy/references/logic-flaws.md +721 -0
- package/skills/wooyun-legacy/references/path-traversal.md +1191 -0
- package/skills/wooyun-legacy/references/telecom-penetration.md +156 -0
- package/skills/wooyun-legacy/references/unauthorized-access.md +980 -0
- package/skills/wooyun-legacy/references/xss.md +746 -0
- package/skills/zeroize-audit/SKILL.md +371 -0
- package/skills/zeroize-audit/configs/c.yaml +21 -0
- package/skills/zeroize-audit/configs/default.yaml +128 -0
- package/skills/zeroize-audit/configs/rust.yaml +83 -0
- package/skills/zeroize-audit/prompts/report_template.md +238 -0
- package/skills/zeroize-audit/prompts/system.md +163 -0
- package/skills/zeroize-audit/prompts/task.md +97 -0
- package/skills/zeroize-audit/references/compile-commands.md +231 -0
- package/skills/zeroize-audit/references/detection-strategy.md +191 -0
- package/skills/zeroize-audit/references/ir-analysis.md +252 -0
- package/skills/zeroize-audit/references/mcp-analysis.md +221 -0
- package/skills/zeroize-audit/references/poc-generation.md +470 -0
- package/skills/zeroize-audit/references/rust-zeroization-patterns.md +867 -0
- package/skills/zeroize-audit/schemas/input.json +83 -0
- package/skills/zeroize-audit/schemas/output.json +140 -0
- package/skills/zeroize-audit/tools/analyze_asm.sh +202 -0
- package/skills/zeroize-audit/tools/analyze_cfg.py +381 -0
- package/skills/zeroize-audit/tools/analyze_heap.sh +211 -0
- package/skills/zeroize-audit/tools/analyze_ir_semantic.py +429 -0
- package/skills/zeroize-audit/tools/diff_ir.sh +135 -0
- package/skills/zeroize-audit/tools/diff_rust_mir.sh +189 -0
- package/skills/zeroize-audit/tools/emit_asm.sh +67 -0
- package/skills/zeroize-audit/tools/emit_ir.sh +77 -0
- package/skills/zeroize-audit/tools/emit_rust_asm.sh +178 -0
- package/skills/zeroize-audit/tools/emit_rust_ir.sh +150 -0
- package/skills/zeroize-audit/tools/emit_rust_mir.sh +158 -0
- package/skills/zeroize-audit/tools/extract_compile_flags.py +284 -0
- package/skills/zeroize-audit/tools/generate_poc.py +1329 -0
- package/skills/zeroize-audit/tools/mcp/apply_confidence_gates.py +113 -0
- package/skills/zeroize-audit/tools/mcp/check_mcp.sh +68 -0
- package/skills/zeroize-audit/tools/mcp/normalize_mcp_evidence.py +125 -0
- package/skills/zeroize-audit/tools/scripts/check_llvm_patterns.py +481 -0
- package/skills/zeroize-audit/tools/scripts/check_mir_patterns.py +554 -0
- package/skills/zeroize-audit/tools/scripts/check_rust_asm.py +424 -0
- package/skills/zeroize-audit/tools/scripts/check_rust_asm_aarch64.py +300 -0
- package/skills/zeroize-audit/tools/scripts/check_rust_asm_x86.py +283 -0
- package/skills/zeroize-audit/tools/scripts/find_dangerous_apis.py +375 -0
- package/skills/zeroize-audit/tools/scripts/semantic_audit.py +923 -0
- package/skills/zeroize-audit/tools/track_dataflow.sh +196 -0
- package/skills/zeroize-audit/tools/validate_rust_toolchain.sh +298 -0
- package/skills/zeroize-audit/workflows/phase-0-preflight.md +150 -0
- package/skills/zeroize-audit/workflows/phase-1-source-analysis.md +144 -0
- package/skills/zeroize-audit/workflows/phase-2-compiler-analysis.md +139 -0
- package/skills/zeroize-audit/workflows/phase-3-interim-report.md +46 -0
- package/skills/zeroize-audit/workflows/phase-4-poc-generation.md +46 -0
- package/skills/zeroize-audit/workflows/phase-5-poc-validation.md +136 -0
- package/skills/zeroize-audit/workflows/phase-6-final-report.md +44 -0
- package/skills/zeroize-audit/workflows/phase-7-test-generation.md +42 -0
- package/themes/piolium-srcery.json +94 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: variant-scanner
|
|
3
|
+
tools: Glob, Grep, Read, Bash, Agent
|
|
4
|
+
model: sonnet
|
|
5
|
+
color: green
|
|
6
|
+
permissionMode: bypassPermissions
|
|
7
|
+
effort: low
|
|
8
|
+
description: Phase 12 per-finding variant analysis agent that takes a confirmed vulnerability and searches for structural variants using the attack pattern registry's detection signatures, CodeQL on-demand queries, DFD/CFD slice analysis including Phase 10 Addendum discoveries, and chamber variant candidates
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
You are a variant hunter for Phase 12 of a security audit. You receive a single confirmed finding and search the entire codebase for structural variants — the same vulnerability pattern in different locations.
|
|
12
|
+
|
|
13
|
+
## Inputs
|
|
14
|
+
|
|
15
|
+
You receive:
|
|
16
|
+
- **Finding path**: `archon/findings-draft/<phase>-<NNN>-<slug>.md`
|
|
17
|
+
- **NNN range**: your assigned finding ID range for variant drafts
|
|
18
|
+
- **KB path**: `archon/attack-surface/knowledge-base-report.md`
|
|
19
|
+
|
|
20
|
+
## Context Loading
|
|
21
|
+
|
|
22
|
+
1. Read the finding draft to understand the root cause and code pattern
|
|
23
|
+
2. Read `archon/attack-pattern-registry.json` — find the matching pattern entry
|
|
24
|
+
3. Read `## Phase 10 Addendum` in the KB — new attack surfaces discovered during chamber debates
|
|
25
|
+
4. Check `archon/chamber-workspace/*/variant-candidates/` for pre-identified candidates
|
|
26
|
+
5. Read `archon/codeql-artifacts/entry-points.json` and `sinks.json` for structurally similar
|
|
27
|
+
entry/sink combinations
|
|
28
|
+
|
|
29
|
+
## Variant Search Strategy
|
|
30
|
+
|
|
31
|
+
### 1. Registry-Driven Search
|
|
32
|
+
If the attack pattern registry has a `detection_signature` for this pattern:
|
|
33
|
+
- Run the CodeQL query against `archon/codeql-artifacts/db/`
|
|
34
|
+
- Run the Semgrep rule against the codebase
|
|
35
|
+
- Run the grep pattern across the codebase
|
|
36
|
+
- Each match is a variant candidate
|
|
37
|
+
|
|
38
|
+
### 2. AST-Level Structural Search
|
|
39
|
+
Write and run a CodeQL query that searches for the same AST-level structure:
|
|
40
|
+
```bash
|
|
41
|
+
codeql query run \
|
|
42
|
+
--database=archon/codeql-artifacts/db/ \
|
|
43
|
+
--output=archon/tmp/variant.bqrs \
|
|
44
|
+
-- archon/codeql-queries/variant-<slug>.ql
|
|
45
|
+
codeql bqrs decode --format=json archon/tmp/variant.bqrs
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Flow Shape Search
|
|
49
|
+
Look for the same flow shape (source type -> transformation pattern -> sink type) in:
|
|
50
|
+
- Sibling components sharing the same framework
|
|
51
|
+
- Alternate transports (HTTP, WebSocket, gRPC, CLI)
|
|
52
|
+
- Background job consumers processing the same data
|
|
53
|
+
|
|
54
|
+
### 4. Phase 10 Addendum Targets
|
|
55
|
+
Read the `## Phase 10 Addendum` for newly discovered attack surfaces. Check if the confirmed
|
|
56
|
+
finding's pattern appears on any of these new surfaces.
|
|
57
|
+
|
|
58
|
+
### 5. Chamber Variant Candidates
|
|
59
|
+
Check `archon/chamber-workspace/*/variant-candidates/` for pre-identified candidates
|
|
60
|
+
matching this finding's root cause.
|
|
61
|
+
|
|
62
|
+
## Variant Validation
|
|
63
|
+
|
|
64
|
+
For each candidate variant:
|
|
65
|
+
1. Confirm the same root cause is present (not just syntactic similarity)
|
|
66
|
+
2. Confirm attacker-controlled input reaches the variant location
|
|
67
|
+
3. Confirm no blocking protection exists that was absent in the original
|
|
68
|
+
4. Assign severity (start at MEDIUM; upgrade to HIGH for remote + trust boundary + no preconditions; CRITICAL for RCE/auth bypass + unauthenticated + internet-facing)
|
|
69
|
+
|
|
70
|
+
Only retain variants rated **Medium or higher**.
|
|
71
|
+
|
|
72
|
+
## Output
|
|
73
|
+
|
|
74
|
+
Write each confirmed variant to `archon/findings-draft/p12-<NNN>-<slug>.md` using this template:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Phase: 10
|
|
78
|
+
Sequence: NNN
|
|
79
|
+
Slug: <slug>
|
|
80
|
+
Verdict: VALID
|
|
81
|
+
Rationale: <one-sentence>
|
|
82
|
+
Severity-Original: <MEDIUM|HIGH|CRITICAL>
|
|
83
|
+
PoC-Status: pending
|
|
84
|
+
Origin-Finding: <path to original finding>
|
|
85
|
+
Origin-Pattern: <attack pattern registry ID>
|
|
86
|
+
|
|
87
|
+
## Summary
|
|
88
|
+
## Location
|
|
89
|
+
## Attacker Control
|
|
90
|
+
## Trust Boundary Crossed
|
|
91
|
+
## Impact
|
|
92
|
+
## Evidence
|
|
93
|
+
## Reproduction Steps
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Fields:
|
|
97
|
+
- `Phase: 10`
|
|
98
|
+
- `Verdict: VALID`
|
|
99
|
+
- Reference the original finding as the pattern source
|
|
100
|
+
- Include code path evidence
|
|
101
|
+
|
|
102
|
+
Update `archon/attack-pattern-registry.json` — append each confirmed variant to
|
|
103
|
+
the pattern's `confirmed_instances`.
|
|
104
|
+
|
|
105
|
+
## Completion
|
|
106
|
+
|
|
107
|
+
When all search strategies are exhausted, report to the orchestrator:
|
|
108
|
+
"Variant analysis complete for <finding-slug>. Variants found: <count>."
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: variant-spotter
|
|
3
|
+
tools: Glob, Grep, Read, Bash
|
|
4
|
+
model: sonnet
|
|
5
|
+
color: cyan
|
|
6
|
+
permissionMode: bypassPermissions
|
|
7
|
+
effort: low
|
|
8
|
+
background: true
|
|
9
|
+
description: Phase 10 Review Chamber concurrent variant hunter that monitors debate transcripts for confirmed vulnerability patterns and immediately searches for structural variants in sibling components, alternate transports, and adjacent enforcement paths, front-loading Phase 12 variant analysis while chamber context is hot
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
You are a concurrent variant hunter operating alongside a Review Chamber debate. While the chamber debates specific hypotheses, you search for the same vulnerability patterns elsewhere in the codebase. Your work front-loads Phase 12 variant analysis.
|
|
13
|
+
|
|
14
|
+
## Your Chamber Assignment
|
|
15
|
+
|
|
16
|
+
Read the chamber's `debate.md` to understand:
|
|
17
|
+
- Which threat cluster the chamber is investigating
|
|
18
|
+
- Confirmed findings (look for `Verdict: VALID` entries in Synthesis rounds)
|
|
19
|
+
|
|
20
|
+
## Monitoring Protocol
|
|
21
|
+
|
|
22
|
+
1. Read `archon/chamber-workspace/<chamber-id>/debate.md` after each round marker appears (`## Round N`). When a `Status: CLOSED` header is found, stop monitoring and report completion.
|
|
23
|
+
2. When a hypothesis receives `Verdict: VALID`, extract:
|
|
24
|
+
- The root cause pattern (e.g., "ObjectInputStream.readObject() without filter")
|
|
25
|
+
- The affected code location
|
|
26
|
+
- The detection approach used by the Tracer
|
|
27
|
+
3. Also read `archon/attack-pattern-registry.json` for patterns from other chambers
|
|
28
|
+
|
|
29
|
+
## Variant Search Strategy
|
|
30
|
+
|
|
31
|
+
For each confirmed pattern:
|
|
32
|
+
|
|
33
|
+
### 1. Grep-Based Discovery
|
|
34
|
+
Search the entire codebase for the same code pattern:
|
|
35
|
+
```bash
|
|
36
|
+
# Example: find all ObjectInputStream.readObject() calls
|
|
37
|
+
grep -rn "ObjectInputStream.*readObject" --include="*.java" .
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. CodeQL Structural Search
|
|
41
|
+
If a detection signature exists in the attack pattern registry, run it:
|
|
42
|
+
```bash
|
|
43
|
+
codeql query run \
|
|
44
|
+
--database=archon/codeql-artifacts/db/ \
|
|
45
|
+
--output=archon/tmp/variant-search.bqrs \
|
|
46
|
+
-- archon/codeql-queries/on-demand-variant-<slug>.ql
|
|
47
|
+
codeql bqrs decode --format=json archon/tmp/variant-search.bqrs
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Sibling Component Check
|
|
51
|
+
If the confirmed finding is in component A, check components B, C, D that share the same:
|
|
52
|
+
- Trust boundary
|
|
53
|
+
- Data flow pattern
|
|
54
|
+
- Framework usage
|
|
55
|
+
- Dependency
|
|
56
|
+
|
|
57
|
+
### 4. Alternate Transport Check
|
|
58
|
+
If the confirmed finding is via HTTP, check the same logic via:
|
|
59
|
+
- WebSocket
|
|
60
|
+
- gRPC
|
|
61
|
+
- GraphQL
|
|
62
|
+
- CLI interface
|
|
63
|
+
- Background job/queue consumer
|
|
64
|
+
|
|
65
|
+
## Output
|
|
66
|
+
|
|
67
|
+
Write each variant candidate to its own file:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
archon/chamber-workspace/<chamber-id>/variant-candidates/<slug>.md
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Format:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
# Variant Candidate: <title>
|
|
77
|
+
|
|
78
|
+
Origin-Finding: <finding draft path of the original confirmed vulnerability>
|
|
79
|
+
Origin-Pattern: <attack pattern registry ID if exists>
|
|
80
|
+
|
|
81
|
+
## Location
|
|
82
|
+
File: <path>
|
|
83
|
+
Function: <name>
|
|
84
|
+
Line: <number>
|
|
85
|
+
|
|
86
|
+
## Similarity
|
|
87
|
+
- Same root cause: <yes/no, explanation>
|
|
88
|
+
- Same code pattern: <yes/no, grep evidence>
|
|
89
|
+
- Same trust boundary: <yes/no>
|
|
90
|
+
- Same attacker-reachable: <unknown — needs Tracer verification>
|
|
91
|
+
|
|
92
|
+
## Quick Assessment
|
|
93
|
+
<Brief assessment of whether this looks like a real variant or a false match.
|
|
94
|
+
Note: this is a preliminary assessment, NOT a verdict. The Synthesizer or Phase 12
|
|
95
|
+
will make the final determination.>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Scope Rules
|
|
99
|
+
|
|
100
|
+
- Search the ENTIRE codebase, not just the chamber's assigned DFD slices
|
|
101
|
+
- Do NOT participate in the debate — you read transcripts but never write to debate.md
|
|
102
|
+
- Do NOT issue verdicts on variants — write candidates for the Synthesizer to evaluate
|
|
103
|
+
- Prioritize patterns confirmed at HIGH or CRITICAL severity
|
|
104
|
+
- Skip patterns where the detection signature has already been run by SAST (Phase 4 coverage)
|
|
105
|
+
|
|
106
|
+
## Handoff to Phase 12
|
|
107
|
+
|
|
108
|
+
Variant candidates not processed by the Synthesizer before chamber closure are preserved in
|
|
109
|
+
`archon/chamber-workspace/<chamber-id>/variant-candidates/` for Phase 12 variant analysis
|
|
110
|
+
to consume as its starting target list.
|
package/bin/piolium.mjs
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import {
|
|
5
|
+
chmodSync,
|
|
6
|
+
copyFileSync,
|
|
7
|
+
existsSync,
|
|
8
|
+
mkdirSync,
|
|
9
|
+
readFileSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
statSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
} from "node:fs";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
const DEFAULT_PROVIDER = "openai-codex";
|
|
19
|
+
const DEFAULT_MODEL = "gpt-5.5";
|
|
20
|
+
const DEFAULT_THINKING_LEVEL = "high";
|
|
21
|
+
const DEFAULT_THEME = "piolium-srcery";
|
|
22
|
+
|
|
23
|
+
const PACKAGE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
24
|
+
|
|
25
|
+
function main(argv) {
|
|
26
|
+
const paths = resolvePaths();
|
|
27
|
+
const [command, ...rest] = argv;
|
|
28
|
+
|
|
29
|
+
if (command === "--help" || command === "-h") {
|
|
30
|
+
printHelp();
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
if (command === "doctor") {
|
|
34
|
+
bootstrapConfig(paths, { syncEmptyAuth: true });
|
|
35
|
+
return runDoctor(paths);
|
|
36
|
+
}
|
|
37
|
+
if (command === "auth") {
|
|
38
|
+
bootstrapConfig(paths);
|
|
39
|
+
return runAuthCommand(paths, rest);
|
|
40
|
+
}
|
|
41
|
+
if (command === "reset-auth") {
|
|
42
|
+
bootstrapConfig(paths, { createAuth: false });
|
|
43
|
+
return resetAuth(paths);
|
|
44
|
+
}
|
|
45
|
+
if (command === "login") {
|
|
46
|
+
bootstrapConfig(paths);
|
|
47
|
+
return runPi(["/login", ...rest], paths);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
bootstrapConfig(paths, { syncEmptyAuth: true });
|
|
51
|
+
return runPi(command === "--" ? rest : argv, paths);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resolvePaths() {
|
|
55
|
+
const homeDir = expandHome(process.env.PIOLIUM_HOME || join(homedir(), ".piolium"));
|
|
56
|
+
const packageDir = resolve(expandHome(process.env.PIOLIUM_PACKAGE_DIR || PACKAGE_DIR));
|
|
57
|
+
const agentDir = resolve(expandHome(process.env.PIOLIUM_AGENT_DIR || join(homeDir, "agent")));
|
|
58
|
+
const sessionDir = resolve(
|
|
59
|
+
expandHome(process.env.PIOLIUM_SESSION_DIR || join(agentDir, "session")),
|
|
60
|
+
);
|
|
61
|
+
const sourcePiAgentDir = resolve(
|
|
62
|
+
expandHome(process.env.PIOLIUM_SOURCE_PI_AGENT_DIR || join(homedir(), ".pi", "agent")),
|
|
63
|
+
);
|
|
64
|
+
return {
|
|
65
|
+
homeDir,
|
|
66
|
+
packageDir,
|
|
67
|
+
agentDir,
|
|
68
|
+
sessionDir,
|
|
69
|
+
settingsPath: join(agentDir, "settings.json"),
|
|
70
|
+
authPath: join(agentDir, "auth.json"),
|
|
71
|
+
sourcePiSettingsPath: join(sourcePiAgentDir, "settings.json"),
|
|
72
|
+
sourcePiAuthPath: join(sourcePiAgentDir, "auth.json"),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function expandHome(value) {
|
|
77
|
+
if (value === "~") return homedir();
|
|
78
|
+
if (value.startsWith("~/")) return join(homedir(), value.slice(2));
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function bootstrapConfig(paths, options = {}) {
|
|
83
|
+
const { createAuth = true, syncEmptyAuth = false } = options;
|
|
84
|
+
mkdirSync(paths.agentDir, { recursive: true });
|
|
85
|
+
mkdirSync(paths.sessionDir, { recursive: true });
|
|
86
|
+
ensureSettings(paths);
|
|
87
|
+
if (createAuth) ensureEmptyAuth(paths);
|
|
88
|
+
if (syncEmptyAuth) syncEmptyAuthFromPi(paths);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function ensureSettings(paths) {
|
|
92
|
+
const current = readJsonObject(paths.settingsPath, { strict: true }) || {};
|
|
93
|
+
const source = readJsonObject(paths.sourcePiSettingsPath) || {};
|
|
94
|
+
const next = { ...current };
|
|
95
|
+
const packages = Array.isArray(next.packages) ? [...next.packages] : [];
|
|
96
|
+
if (
|
|
97
|
+
!packages.some((entry) =>
|
|
98
|
+
packageEntryMatches(entry, paths.packageDir, dirname(paths.settingsPath)),
|
|
99
|
+
)
|
|
100
|
+
) {
|
|
101
|
+
packages.unshift(paths.packageDir);
|
|
102
|
+
next.packages = packages;
|
|
103
|
+
}
|
|
104
|
+
for (const key of ["defaultProvider", "defaultModel", "defaultThinkingLevel", "theme"]) {
|
|
105
|
+
if (next[key] !== undefined) continue;
|
|
106
|
+
if (source[key] !== undefined) next[key] = source[key];
|
|
107
|
+
}
|
|
108
|
+
next.defaultProvider ??= DEFAULT_PROVIDER;
|
|
109
|
+
next.defaultModel ??= DEFAULT_MODEL;
|
|
110
|
+
next.defaultThinkingLevel ??= DEFAULT_THINKING_LEVEL;
|
|
111
|
+
next.theme ??= DEFAULT_THEME;
|
|
112
|
+
next.sessionDir ??= paths.sessionDir;
|
|
113
|
+
writeJsonObjectIfChanged(paths.settingsPath, current, next, 0o600);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function packageEntryMatches(entry, packageDir, baseDir) {
|
|
117
|
+
const value = typeof entry === "string" ? entry : entry?.source;
|
|
118
|
+
if (typeof value !== "string") return false;
|
|
119
|
+
const resolved = isAbsolute(expandHome(value))
|
|
120
|
+
? resolve(expandHome(value))
|
|
121
|
+
: resolve(baseDir, expandHome(value));
|
|
122
|
+
return resolved === packageDir;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function ensureEmptyAuth(paths) {
|
|
126
|
+
if (existsSync(paths.authPath)) return;
|
|
127
|
+
writeFileSync(paths.authPath, "{}\n", "utf8");
|
|
128
|
+
chmodIfPossible(paths.authPath, 0o600);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function syncEmptyAuthFromPi(paths) {
|
|
132
|
+
if (!isEmptyAuthFile(paths.authPath) || !existsSync(paths.sourcePiAuthPath)) return;
|
|
133
|
+
if (isEmptyAuthFile(paths.sourcePiAuthPath)) return;
|
|
134
|
+
console.warn(
|
|
135
|
+
`[piolium] warning: ${paths.authPath} is empty; syncing auth from ${paths.sourcePiAuthPath}.`,
|
|
136
|
+
);
|
|
137
|
+
copyAuthFile(paths.sourcePiAuthPath, paths.authPath, "Synced");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function runAuthCommand(paths, args) {
|
|
141
|
+
const [command, ...rest] = args;
|
|
142
|
+
if (command === "import") return importAuth(paths, rest);
|
|
143
|
+
if (command === "sync") return syncAuth(paths, rest);
|
|
144
|
+
if (command === "path") {
|
|
145
|
+
console.log(paths.authPath);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
console.error(
|
|
149
|
+
"Usage: piolium auth sync | piolium auth import [--force] [--from <auth.json>] | piolium auth path",
|
|
150
|
+
);
|
|
151
|
+
return 2;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function importAuth(paths, args) {
|
|
155
|
+
let sourcePath = paths.sourcePiAuthPath;
|
|
156
|
+
let force = false;
|
|
157
|
+
for (let i = 0; i < args.length; i++) {
|
|
158
|
+
const arg = args[i];
|
|
159
|
+
if (arg === "--force") {
|
|
160
|
+
force = true;
|
|
161
|
+
} else if (arg === "--from" && args[i + 1]) {
|
|
162
|
+
sourcePath = resolve(expandHome(args[++i]));
|
|
163
|
+
} else if (arg?.startsWith("--from=")) {
|
|
164
|
+
sourcePath = resolve(expandHome(arg.slice("--from=".length)));
|
|
165
|
+
} else {
|
|
166
|
+
console.error(`Unknown auth import argument: ${arg}`);
|
|
167
|
+
return 2;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!existsSync(sourcePath)) {
|
|
171
|
+
console.error(`No source auth file found at ${sourcePath}`);
|
|
172
|
+
return 1;
|
|
173
|
+
}
|
|
174
|
+
const targetExists = existsSync(paths.authPath);
|
|
175
|
+
if (targetExists && !force && !isEmptyAuthFile(paths.authPath)) {
|
|
176
|
+
console.error(
|
|
177
|
+
`${paths.authPath} already contains credentials. Re-run with --force to replace it.`,
|
|
178
|
+
);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
181
|
+
mkdirSync(dirname(paths.authPath), { recursive: true });
|
|
182
|
+
copyFileSync(sourcePath, paths.authPath);
|
|
183
|
+
chmodIfPossible(paths.authPath, 0o600);
|
|
184
|
+
console.log(`Imported auth into ${paths.authPath}`);
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function syncAuth(paths, args) {
|
|
189
|
+
if (args.length > 0) {
|
|
190
|
+
console.error("Usage: piolium auth sync");
|
|
191
|
+
return 2;
|
|
192
|
+
}
|
|
193
|
+
return copyAuthFile(paths.sourcePiAuthPath, paths.authPath, "Synced");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function copyAuthFile(sourcePath, targetPath, verb) {
|
|
197
|
+
if (!existsSync(sourcePath)) {
|
|
198
|
+
console.error(`No source auth file found at ${sourcePath}`);
|
|
199
|
+
return 1;
|
|
200
|
+
}
|
|
201
|
+
if (resolve(sourcePath) === resolve(targetPath)) {
|
|
202
|
+
console.log(`Auth already points at ${targetPath}`);
|
|
203
|
+
return 0;
|
|
204
|
+
}
|
|
205
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
206
|
+
copyFileSync(sourcePath, targetPath);
|
|
207
|
+
chmodIfPossible(targetPath, 0o600);
|
|
208
|
+
console.log(`${verb} auth from ${sourcePath} into ${targetPath}`);
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function resetAuth(paths) {
|
|
213
|
+
if (existsSync(paths.authPath)) rmSync(paths.authPath, { force: true });
|
|
214
|
+
ensureEmptyAuth(paths);
|
|
215
|
+
console.log(`Reset auth at ${paths.authPath}`);
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function runDoctor(paths) {
|
|
220
|
+
const piPath = resolveCommand(process.env.PIOLIUM_PI_BIN || "pi");
|
|
221
|
+
const authState = authStatus(paths.authPath);
|
|
222
|
+
const settings = readJsonObject(paths.settingsPath);
|
|
223
|
+
const hasPackage =
|
|
224
|
+
!!settings &&
|
|
225
|
+
Array.isArray(settings.packages) &&
|
|
226
|
+
settings.packages.some((entry) =>
|
|
227
|
+
packageEntryMatches(entry, paths.packageDir, dirname(paths.settingsPath)),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
console.log("Piolium standalone");
|
|
231
|
+
console.log(` home: ${paths.homeDir}`);
|
|
232
|
+
console.log(
|
|
233
|
+
` package: ${existsSync(paths.packageDir) ? "ok" : "missing"} ${paths.packageDir}`,
|
|
234
|
+
);
|
|
235
|
+
console.log(` agent: ${paths.agentDir}`);
|
|
236
|
+
console.log(` sessions: ${paths.sessionDir}`);
|
|
237
|
+
console.log(` settings: ${hasPackage ? "ok" : "missing package entry"} ${paths.settingsPath}`);
|
|
238
|
+
console.log(` auth: ${authState} ${paths.authPath}`);
|
|
239
|
+
console.log(` pi: ${piPath || "not found"}`);
|
|
240
|
+
if (!piPath) return 1;
|
|
241
|
+
return existsSync(paths.packageDir) && hasPackage ? 0 : 1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function runPi(args, paths) {
|
|
245
|
+
const piCommand = process.env.PIOLIUM_PI_BIN || "pi";
|
|
246
|
+
const finalArgs = hasSessionDirArg(args) ? args : ["--session-dir", paths.sessionDir, ...args];
|
|
247
|
+
const consoleStream = defaultConsoleStreamEnv(finalArgs);
|
|
248
|
+
const result = spawnSync(piCommand, finalArgs, {
|
|
249
|
+
stdio: "inherit",
|
|
250
|
+
env: {
|
|
251
|
+
...process.env,
|
|
252
|
+
PI_CODING_AGENT_DIR: paths.agentDir,
|
|
253
|
+
...(consoleStream === undefined ? {} : { PIOLIUM_CONSOLE_STREAM: consoleStream }),
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
if (result.error) {
|
|
257
|
+
console.error(`Failed to run ${piCommand}: ${result.error.message}`);
|
|
258
|
+
return 1;
|
|
259
|
+
}
|
|
260
|
+
return result.status ?? 1;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function defaultConsoleStreamEnv(args) {
|
|
264
|
+
if (process.env.PIOLIUM_CONSOLE_STREAM !== undefined) return process.env.PIOLIUM_CONSOLE_STREAM;
|
|
265
|
+
return hasPioliumPrompt(args) ? "1" : undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function hasPioliumPrompt(args) {
|
|
269
|
+
for (let i = 0; i < args.length; i++) {
|
|
270
|
+
const arg = args[i];
|
|
271
|
+
if ((arg === "-p" || arg === "--prompt") && args[i + 1]?.includes("/piolium-")) return true;
|
|
272
|
+
if ((arg.startsWith("-p=") || arg.startsWith("--prompt=")) && arg.includes("/piolium-")) {
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function hasSessionDirArg(args) {
|
|
280
|
+
return args.some((arg) => arg === "--session-dir" || arg.startsWith("--session-dir="));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function readJsonObject(path, options = {}) {
|
|
284
|
+
if (!existsSync(path)) return undefined;
|
|
285
|
+
try {
|
|
286
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
287
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
|
|
288
|
+
} catch (error) {
|
|
289
|
+
if (options.strict) {
|
|
290
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
291
|
+
throw new Error(`Invalid JSON in ${path}: ${message}`);
|
|
292
|
+
}
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function writeJsonObjectIfChanged(path, before, after, mode) {
|
|
298
|
+
const beforeText = JSON.stringify(before, null, 2);
|
|
299
|
+
const afterText = `${JSON.stringify(after, null, 2)}\n`;
|
|
300
|
+
if (existsSync(path) && `${beforeText}\n` === afterText) return;
|
|
301
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
302
|
+
writeFileSync(path, afterText, "utf8");
|
|
303
|
+
chmodIfPossible(path, mode);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function isEmptyAuthFile(path) {
|
|
307
|
+
try {
|
|
308
|
+
const text = readFileSync(path, "utf8").trim();
|
|
309
|
+
return text === "" || text === "{}";
|
|
310
|
+
} catch {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function authStatus(path) {
|
|
316
|
+
if (!existsSync(path)) return "missing";
|
|
317
|
+
if (isEmptyAuthFile(path)) return "empty";
|
|
318
|
+
try {
|
|
319
|
+
const size = statSync(path).size;
|
|
320
|
+
return size > 0 ? "configured" : "empty";
|
|
321
|
+
} catch {
|
|
322
|
+
return "unknown";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function chmodIfPossible(path, mode) {
|
|
327
|
+
try {
|
|
328
|
+
chmodSync(path, mode);
|
|
329
|
+
} catch {
|
|
330
|
+
// Best effort only. Some filesystems ignore POSIX modes.
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function resolveCommand(command) {
|
|
335
|
+
if (command.includes("/") && existsSync(command)) return command;
|
|
336
|
+
const result = spawnSync("sh", ["-c", `command -v "$1"`, "sh", command], {
|
|
337
|
+
encoding: "utf8",
|
|
338
|
+
});
|
|
339
|
+
return result.status === 0 ? result.stdout.trim() : undefined;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function printHelp() {
|
|
343
|
+
console.log(`piolium - isolated Pi launcher for Piolium
|
|
344
|
+
|
|
345
|
+
Usage:
|
|
346
|
+
piolium [pi args...]
|
|
347
|
+
piolium login
|
|
348
|
+
piolium doctor
|
|
349
|
+
piolium auth sync
|
|
350
|
+
piolium auth import [--force] [--from <auth.json>]
|
|
351
|
+
piolium auth path
|
|
352
|
+
piolium reset-auth
|
|
353
|
+
|
|
354
|
+
Environment:
|
|
355
|
+
PIOLIUM_HOME Default: ~/.piolium
|
|
356
|
+
PIOLIUM_PACKAGE_DIR Default: directory containing this package
|
|
357
|
+
PIOLIUM_AGENT_DIR Default: ~/.piolium/agent
|
|
358
|
+
PIOLIUM_SESSION_DIR Default: ~/.piolium/agent/session
|
|
359
|
+
PIOLIUM_SOURCE_PI_AGENT_DIR Default: ~/.pi/agent
|
|
360
|
+
PIOLIUM_PI_BIN Default: pi
|
|
361
|
+
|
|
362
|
+
Examples:
|
|
363
|
+
piolium
|
|
364
|
+
piolium -p "/piolium-balanced --fresh"
|
|
365
|
+
piolium auth sync
|
|
366
|
+
piolium auth import
|
|
367
|
+
`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const exitCode = main(process.argv.slice(2));
|
|
372
|
+
process.exit(exitCode);
|
|
373
|
+
} catch (error) {
|
|
374
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Hand-written shim for the bundled `yaml` package (extensions/piolium/_vendor/yaml.bundle.mjs).
|
|
2
|
+
// We only consume `parse` and `stringify`; everything else is intentionally
|
|
3
|
+
// omitted to keep the surface minimal.
|
|
4
|
+
|
|
5
|
+
export function parse(src: string, options?: unknown): unknown;
|
|
6
|
+
export function stringify(value: unknown, options?: { lineWidth?: number; [k: string]: unknown }): string;
|