archymedes-cli 2.0.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.
@@ -0,0 +1,67 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
13
+ var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
21
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
22
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ if (canCache)
30
+ cache.set(mod, to);
31
+ return to;
32
+ };
33
+ var __toCommonJS = (from) => {
34
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
35
+ if (entry)
36
+ return entry;
37
+ entry = __defProp({}, "__esModule", { value: true });
38
+ if (from && typeof from === "object" || typeof from === "function") {
39
+ for (var key of __getOwnPropNames(from))
40
+ if (!__hasOwnProp.call(entry, key))
41
+ __defProp(entry, key, {
42
+ get: __accessProp.bind(from, key),
43
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
44
+ });
45
+ }
46
+ __moduleCache.set(from, entry);
47
+ return entry;
48
+ };
49
+ var __moduleCache;
50
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
51
+ var __returnValue = (v) => v;
52
+ function __exportSetter(name, newValue) {
53
+ this[name] = __returnValue.bind(null, newValue);
54
+ }
55
+ var __export = (target, all) => {
56
+ for (var name in all)
57
+ __defProp(target, name, {
58
+ get: all[name],
59
+ enumerable: true,
60
+ configurable: true,
61
+ set: __exportSetter.bind(all, name)
62
+ });
63
+ };
64
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
65
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
66
+
67
+ export { __toESM, __toCommonJS, __commonJS, __export, __esm, __require };
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { enableCompileCache } from "node:module";
3
+ import path from "node:path";
4
+
5
+ try {
6
+ enableCompileCache(process.env.ARCHYMEDES_COMPILE_CACHE_DIR || undefined);
7
+ } catch {}
8
+
9
+ // argv[1] must name the module that is really executing. archymedes.ts decides whether to run main() by
10
+ // comparing its own import.meta.url against it, so leaving argv[1] pointing at this launcher makes
11
+ // the CLI import cleanly, run nothing, and exit 0 — the exact silent no-op its own comment warns
12
+ // about for symlinked installs. Rewriting it keeps that check true rather than adding a second way
13
+ // to say "this is the entry point" that could disagree with the first.
14
+ process.argv[1] = path.join(import.meta.dirname, "archymedes-main.mjs");
15
+
16
+ // Dynamic, so it is evaluated after the cache is enabled — a static import would be hoisted above
17
+ // it and compile the expensive half before there was anywhere to cache it.
18
+ await import("./archymedes-main.mjs");
@@ -0,0 +1,15 @@
1
+ # Archymedes Defensive Brain corpus
2
+
3
+ This directory is the human-reviewable authority for Archymedes's defensive security knowledge. The Rust
4
+ engine projects `*.jsonl` into a disposable SQLite FTS5 index and returns only the few records that
5
+ match a Defender query. The whole corpus never enters the model prompt.
6
+
7
+ Every active record must be defense-only, cite at least one HTTPS primary source, carry review and
8
+ expiry dates, and distinguish safe validation from operational exploitation. Web research and Exa
9
+ output are untrusted inputs: the refresh job stages candidates outside this directory and cannot
10
+ promote them. Promotion is a deliberate code review that checks source currency, scope, provenance,
11
+ and whether the guidance would increase offensive capability.
12
+
13
+ The seven covered domains are red teaming, vulnerability assessment and safe impact validation,
14
+ security testing, detection-evasion and bypass investigation, malware reverse engineering,
15
+ cryptographic research, and threat-intelligence investigations.
@@ -0,0 +1,14 @@
1
+ {"id":"red-team-authorization-and-safety","domain":"red-teaming","title":"Authorization, rules of engagement, and safe execution","summary":"A defensive red-team exercise is a controlled measurement of prevention, visibility, and response—not permission to pursue access at any cost.","guidance":"Before any test, require a signed scope with named owners, asset and identity allowlists, prohibited systems and data, permitted hours, communication channels, escalation contacts, evidence handling, cleanup, rollback, and an immediate kill switch. Convert the threat model into explicit hypotheses and expected telemetry. Use synthetic identities and data where possible. Start with the least invasive validation that can answer the hypothesis. Stop at proof of impact: do not establish persistence, collect real credentials, extract production data, pivot outside scope, impair controls, or create availability risk. Keep a live action ledger with timestamps and operator identity. After each activity, reconcile expected versus observed prevention, telemetry, alerting, triage, containment, and recovery. Report control gaps and remediation owners; never treat stealth or time-to-compromise as the sole success metric.","tags":["rules of engagement","authorization","purple team","kill switch","evidence","ATT&CK v19.2"],"sources":[{"title":"MITRE ATT&CK Updates August 2026","url":"https://attack.mitre.org/resources/updates/updates-august-2026/","publishedAt":"2026-08-06","accessedAt":"2026-08-24","primary":true},{"title":"CISA Red Team Assessment Advisory","url":"https://www.cisa.gov/news-events/alerts/2024/07/11/cisa-releases-advisory-detailing-red-team-activity-during-assessment-us-fceb-organization","publishedAt":"2024-07-11","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
2
+ {"id":"red-team-threat-informed-validation","domain":"red-teaming","title":"Threat-informed emulation and purple-team learning loop","summary":"Select behaviors from current, relevant intelligence and validate each one as an observable control hypothesis.","guidance":"Use ATT&CK v19.2 as a vocabulary, not a checklist. Select only behaviors supported by the organization’s threat model, technology, geography, and incident history. For each behavior record the business asset, preconditions, safe simulation method, expected data components, expected detections, expected responder action, success criteria, and cleanup. Prefer benign or vendor-provided validation artifacts over custom payloads. Instrument first and capture baseline noise. Execute one controlled variable at a time, pause for the blue team to investigate, then compare endpoint, identity, cloud, network, application, and control-plane evidence. Classify the result as prevented, observed, alerted, investigated, contained, recovered, or unknown. Unknown is a telemetry gap requiring follow-up, not a pass. Retest after remediation and preserve ATT&CK version identifiers so mappings do not silently drift.","tags":["threat-informed defense","ATT&CK Navigator","detection strategies","purple team","control validation"],"sources":[{"title":"MITRE ATT&CK Data and Tools v19.2","url":"https://attack.mitre.org/resources/attack-data-and-tools/","publishedAt":"2026-08-06","accessedAt":"2026-08-24","primary":true},{"title":"MITRE ATT&CK Version History","url":"https://attack.mitre.org/resources/versions/","publishedAt":"2026-08-06","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
3
+ {"id":"vulnerability-discovery-and-validation","domain":"vulnerability-assessment","title":"Evidence-led vulnerability discovery and safe validation","summary":"Combine inventory, authenticated testing, code review, configuration review, and manual confirmation without weaponizing findings.","guidance":"Confirm authorization and the exact deployed version before testing. Build an asset inventory that includes APIs, identities, cloud resources, build systems, dependencies, data flows, and third-party boundaries. Prefer authenticated scanners and configuration APIs, then manually validate likely findings against source, runtime configuration, and deployment context. Use OWASP ASVS 5.0 as verifiable application requirements and WSTG as a testing framework. For exploitation questions, reproduce only in an isolated clone or vendor-provided lab with synthetic data. Demonstrate the minimum observable impact and stop; do not retrieve real records, harvest secrets, persist, pivot, or publish a working exploit. Preserve request/response evidence with sensitive values redacted, state assumptions, identify false-positive conditions, and include a regression test or deterministic verification step with every remediation.","tags":["OWASP ASVS 5.0","WSTG","authenticated scanning","manual validation","safe proof of impact"],"sources":[{"title":"OWASP Application Security Verification Standard 5.0.0","url":"https://github.com/OWASP/ASVS/releases/tag/v5.0.0","publishedAt":"2025-05-30","accessedAt":"2026-08-24","primary":true},{"title":"OWASP Web Security Testing Guide","url":"https://owasp.org/www-project-web-security-testing-guide/","publishedAt":null,"accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
4
+ {"id":"vulnerability-risk-prioritization","domain":"vulnerability-assessment","title":"Current exploitability and environment-aware prioritization","summary":"Prioritize remediation with local exposure and impact, confirmed exploitation, EPSS, and CVSS v4 Threat and Environmental metrics—not a base score alone.","guidance":"Normalize product, version, CPE/package, deployment, ownership, internet exposure, privilege boundary, data sensitivity, safety impact, and compensating controls. Check the vendor advisory and CISA Known Exploited Vulnerabilities catalog for authoritative exploitation status. Use EPSS as a probability signal, not proof, and retain its score date because it changes daily. Publish CVSS v4 vectors rather than naked numbers; enrich Base with Threat and Environmental metrics using the organization’s deployment facts. Raise priority for reachable identity, edge, control-plane, CI/CD, and total-control paths. A patch-only workflow is insufficient when exploitation may have occurred: preserve logs and artifacts, hunt for compromise indicators, rotate exposed credentials, and validate recovery. Record why an item was deferred and when the decision expires.","tags":["CVSS v4.0","EPSS v4","CISA KEV","environmental metrics","compromise assessment"],"sources":[{"title":"FIRST CVSS v4.0 Consumer Implementation Guide","url":"https://www.first.org/cvss/v4.0/implementation-guide","publishedAt":"2026-01-06","accessedAt":"2026-08-24","primary":true},{"title":"FIRST Exploit Prediction Scoring System","url":"https://www.first.org/epss/","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"CISA Known Exploited Vulnerabilities Catalog","url":"https://www.cisa.gov/known-exploited-vulnerabilities-catalog","publishedAt":null,"accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-10-24","confidence":"high","defenseOnly":true}
5
+ {"id":"detection-evasion-gap-analysis","domain":"detection-and-bypass-investigation","title":"Detection evasion and bypass investigation as control-gap analysis","summary":"Reproduce suspected bypasses only as authorized, benign control tests and turn every result into telemetry and mitigation improvements.","guidance":"Treat evasion and bypass as questions about control assumptions, not recipes to operationalize. State the expected control decision and data source before testing. Reproduce with a benign equivalent in an isolated or canary environment, one variable at a time, without disabling production controls or concealing activity from exercise owners. Capture raw endpoint, identity, network, cloud, application, and control-plane telemetry. Separate failures into visibility, collection, normalization, correlation, prevention, alert routing, triage, containment, and recovery. ATT&CK v19 split the former Enterprise Defense Evasion tactic into Stealth and Defense Impairment; use the current mapping and detection strategies while retaining legacy mappings only for migration. Document the exact product/version/policy, safe reproduction evidence, affected scope, compensating controls, detection content, and regression validation. Do not provide payload transformations, anti-analysis instructions, or steps for bypassing a named live control.","tags":["Stealth","Defense Impairment","ATT&CK v19.2","telemetry gap","control validation","DET0900"],"sources":[{"title":"MITRE ATT&CK Updates April 2026","url":"https://attack.mitre.org/resources/updates/updates-april-2026/","publishedAt":"2026-04-28","accessedAt":"2026-08-24","primary":true},{"title":"MITRE Detection of Defense Impairment DET0900","url":"https://attack.mitre.org/detectionstrategies/DET0900/","publishedAt":"2026-04-16","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
6
+ {"id":"detection-engineering-quality-loop","domain":"detection-and-bypass-investigation","title":"Detection engineering quality and regression loop","summary":"A useful detection is observable, testable, scoped, explainable, and connected to a response action.","guidance":"Begin with an adversary behavior and a defensible data contract: event producer, collection path, fields, identity resolution, retention, clock quality, and known loss modes. Write the analytic in platform-neutral logic before translating it to a query language. Include positive fixtures, nearby benign fixtures, missing-field cases, volume expectations, and a response runbook. Measure precision, recall where ground truth exists, time to signal, event cost, and analyst handling time. Validate across relevant operating systems, cloud tenants, identities, and versions. Favor behavior chains and invariants over fragile single indicators. Monitor schema drift and silence: a rule that stops receiving events can be more dangerous than one that fires noisily. Version the mapping, query, fixtures, thresholds, exceptions, and ATT&CK release together; rerun validation after sensor, parser, policy, or product upgrades.","tags":["detection engineering","data contracts","regression testing","false positives","schema drift","response runbook"],"sources":[{"title":"MITRE ATT&CK Data and Tools v19.2","url":"https://attack.mitre.org/resources/attack-data-and-tools/","publishedAt":"2026-08-06","accessedAt":"2026-08-24","primary":true},{"title":"MITRE D3FEND","url":"https://d3fend.mitre.org/","publishedAt":null,"accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
7
+ {"id":"malware-reverse-engineering-lab","domain":"malware-reverse-engineering","title":"Isolated malware triage and reverse-engineering workflow","summary":"Protect analysts and evidence first; progress from metadata and static capability identification to tightly controlled dynamic observation only when justified.","guidance":"Work only with lawfully obtained samples and an approved case identifier. Record cryptographic hashes, acquisition source, timestamps, container metadata, and chain of custody before opening content. Use a dedicated disposable lab with snapshots, no trusted credentials, no production mounts, no shared clipboard, controlled or simulated networking, and explicit egress capture. Begin with format validation, signatures, strings, imports, resources, packer indicators, and capability classification. Use maintained analyzers such as Ghidra and capa, keeping tool versions and rule versions in evidence. Move to dynamic observation only if static work cannot answer a defensive question; monitor process, file, registry/configuration, memory, and network effects and revert the snapshot afterward. Never execute a sample on the analyst workstation, connect it to production, provide it real credentials, or modify it to improve stealth, persistence, propagation, or impact.","tags":["malware triage","Ghidra","capa","isolated lab","chain of custody","static analysis"],"sources":[{"title":"Mandiant capa","url":"https://github.com/mandiant/capa","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"Mandiant capa v9.4.0","url":"https://github.com/mandiant/capa/releases/tag/v9.4.0","publishedAt":"2026-04-14","accessedAt":"2026-08-24","primary":true},{"title":"NSA Ghidra","url":"https://github.com/NationalSecurityAgency/ghidra","publishedAt":null,"accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-10-24","confidence":"high","defenseOnly":true}
8
+ {"id":"malware-analysis-to-defense","domain":"malware-reverse-engineering","title":"Convert malware analysis into durable defensive outcomes","summary":"Analysis is complete when it improves prevention, detection, scoping, and recovery—not when every function is understood.","guidance":"Frame questions before analysis: affected platforms, execution prerequisites, persistence evidence, command-and-control behaviors, credential or data access, lateral movement dependencies, and recoverable artifacts. Distinguish observed behavior from inferred capability and from family attribution. Extract indicators with context, stability, first/last seen, and confidence; avoid overfitting to hashes or infrastructure that changes quickly. Build behavior-based detections and safe fixtures, map only supported ATT&CK behaviors, and document visibility prerequisites. Search the environment using approved telemetry and preserve negative findings as scoped observations, not proof of absence. Share only sanitized indicators under the correct TLP marking. If an analysis plugin can send sample-derived data or prompts to an external service, require explicit case authorization and data-handling review before enabling it.","tags":["behavioral detection","YARA-X","capa","ATT&CK mapping","indicator lifecycle","analysis privacy"],"sources":[{"title":"VirusTotal YARA-X","url":"https://github.com/VirusTotal/yara-x","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"Mandiant XRefer","url":"https://github.com/mandiant/xrefer","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"FIRST Traffic Light Protocol 2.0","url":"https://www.first.org/tlp/","publishedAt":"2022-08-05","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-10-24","confidence":"high","defenseOnly":true}
9
+ {"id":"cryptographic-design-review","domain":"cryptographic-research","title":"Cryptographic design and implementation review","summary":"Prefer standardized, misuse-resistant constructions and review key lifecycle, protocol binding, implementation behavior, and operational recovery together.","guidance":"Identify the security property first: confidentiality, integrity, authenticity, non-repudiation, key establishment, password storage, or randomness. Inventory algorithms, modes, parameters, protocol versions, libraries/providers, keys, certificates, HSM/KMS dependencies, trust anchors, data lifetimes, and recovery paths. Reject custom cryptography and unauthenticated encryption. Verify domain separation, nonce/IV requirements, associated-data binding, randomness, constant-time secret handling, parser/canonicalization behavior, key separation, rotation, revocation, backup, deletion, and failure behavior. Review the actual deployed provider and configuration—not only source-level algorithm names—and require known-answer/interoperability tests plus negative tests. Treat side channels, downgrade paths, certificate validation, and error oracles as system properties. Do not claim a primitive is broken from a single paper or preprint; separate mathematical, implementation, protocol, and operational evidence.","tags":["cryptographic review","key lifecycle","AEAD","crypto agility","side channels","protocol downgrade"],"sources":[{"title":"NIST Cryptographic Standards and Guidelines","url":"https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"OWASP Cryptographic Storage Cheat Sheet","url":"https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html","publishedAt":null,"accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
10
+ {"id":"post-quantum-migration","domain":"cryptographic-research","title":"Post-quantum inventory, prioritization, and migration","summary":"NIST’s first PQC standards are deployable now; migration begins with inventory, data-lifetime risk, interoperability, and crypto agility rather than an indiscriminate algorithm swap.","guidance":"Inventory where public-key cryptography is created, negotiated, stored, embedded, or validated across protocols, certificates, code signing, firmware, backups, HSMs, libraries, vendors, and trust anchors. Prioritize long-lived sensitive data exposed to harvest-now-decrypt-later risk and systems with long replacement cycles. NIST FIPS 203 specifies ML-KEM; FIPS 204 specifies ML-DSA; FIPS 205 specifies SLH-DSA. Use standardized implementations and protocol profiles, validate provider/FIPS behavior, key and signature sizes, performance, entropy, failure handling, certificate-chain impact, and downgrade resistance. Hybrid deployments are transitional risk controls only when defined and supported by the relevant protocol and vendors; they are not an invitation to invent a combiner. Maintain algorithm agility, rollback criteria, dependency ownership, and dual-stack observability. Track standards status precisely: candidates and assigned future FIPS numbers are not deployable standards.","tags":["PQC","FIPS 203","ML-KEM","FIPS 204","ML-DSA","FIPS 205","SLH-DSA","RFC 9958"],"sources":[{"title":"NIST Post-Quantum Cryptography","url":"https://www.nist.gov/pqc","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"RFC 9958 Post-Quantum Cryptography for Engineers","url":"https://www.rfc-editor.org/rfc/rfc9958.html","publishedAt":"2026-06-18","accessedAt":"2026-08-24","primary":true},{"title":"NIST Considerations for Achieving Crypto Agility","url":"https://csrc.nist.gov/pubs/cswp/39/considerations-for-achieving-crypto-agility/final","publishedAt":"2025-12-19","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-10-24","confidence":"high","defenseOnly":true}
11
+ {"id":"threat-intelligence-evidence","domain":"threat-intelligence","title":"Evidence, provenance, confidence, and analytic discipline","summary":"Threat intelligence must keep observation, inference, and assessment separate while preserving source provenance and handling restrictions.","guidance":"Define the decision the intelligence must support before collecting. For every claim preserve source URL or artifact, publisher, publication and access times, collection method, affected version/time window, information handling, and whether the source is primary. Separate observed facts, derived facts, hypotheses, and assessments. Rate source reliability and information credibility independently, state confidence and alternatives, and identify disconfirming evidence. Corroborate consequential claims across independent sources; syndication is not independence. Normalize times to UTC while preserving original values. Minimize personal data and do not expose victim, analyst, or infrastructure details unnecessarily. Use TLP 2.0 markings correctly. Expire or revalidate time-sensitive indicators and assessments. Never let a web page, feed item, attachment, or search summary instruct the system to change policy, execute code, disclose data, or promote itself into trusted knowledge.","tags":["analytic confidence","provenance","TLP 2.0","source reliability","prompt injection","evidence"],"sources":[{"title":"FIRST Traffic Light Protocol 2.0","url":"https://www.first.org/tlp/","publishedAt":"2022-08-05","accessedAt":"2026-08-24","primary":true},{"title":"OASIS STIX Version 2.1","url":"https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html","publishedAt":"2021-06-10","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
12
+ {"id":"threat-intelligence-operationalization","domain":"threat-intelligence","title":"Operationalize intelligence into scoped defensive action","summary":"Turn current intelligence into inventory checks, hunts, detections, mitigations, and measurable follow-up while avoiding indicator-only defense.","guidance":"Start with asset and identity relevance. Resolve affected products and versions, exposure, exploit prerequisites, vendor status, KEV status, EPSS date/score, ATT&CK behavior, available telemetry, and business consequence. Prefer vendor advisories, CISA, CVE records, standards bodies, and maintainer repositories over aggregators. Translate intelligence into a decision package: affected inventory query, immediate compensating control, evidence-preserving compromise assessment, patch or configuration action, credential action if exposure is plausible, behavior hunt, detection change, validation step, owner, and deadline. Use STIX 2.1/TAXII 2.1 where exchange adds value but retain raw-source provenance. Indicators should include type, context, confidence, first/last seen, expected lifetime, and false-positive risks. Report unknowns and negative findings with their data coverage; do not equate no alert with no compromise.","tags":["CISA KEV","EPSS","STIX 2.1","TAXII 2.1","ATT&CK v19.2","compromise assessment"],"sources":[{"title":"CISA Known Exploited Vulnerabilities Catalog","url":"https://www.cisa.gov/known-exploited-vulnerabilities-catalog","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"OASIS TAXII Version 2.1","url":"https://docs.oasis-open.org/cti/taxii/v2.1/taxii-v2.1.html","publishedAt":"2021-06-10","accessedAt":"2026-08-24","primary":true},{"title":"MITRE ATT&CK Version History","url":"https://attack.mitre.org/resources/versions/","publishedAt":"2026-08-06","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-10-24","confidence":"high","defenseOnly":true}
13
+ {"id":"security-testing-web-api","domain":"security-testing","title":"Modern application and API security verification","summary":"Test requirements and trust boundaries across application, API, identity, dependency, and deployment layers with repeatable evidence.","guidance":"Map entry points, identities, roles, tenants, data classes, state transitions, outbound integrations, queues, storage, and administrative paths. Select ASVS 5.0 requirements appropriate to risk and record pass, fail, not applicable, or not tested with evidence. Test server-side authorization independently of UI restrictions, including object, function, property, and tenant boundaries. Validate parser differences, request normalization, business invariants, concurrency/idempotency, file/archive handling, server-side requests, webhook authenticity and replay, token audience/issuer/lifetime, secret boundaries, error disclosure, logging, and abuse controls. Use synthetic accounts and data. Keep automated scanner results provisional until manually confirmed. For every finding include the vulnerable trust boundary, preconditions, minimum safe proof, affected versions, remediation principle, regression test, and residual risk.","tags":["ASVS 5.0","API security","authorization","business logic","tenant isolation","regression"],"sources":[{"title":"OWASP Application Security Verification Standard 5.0.0","url":"https://github.com/OWASP/ASVS/releases/tag/v5.0.0","publishedAt":"2025-05-30","accessedAt":"2026-08-24","primary":true},{"title":"OWASP Web Security Testing Guide","url":"https://owasp.org/www-project-web-security-testing-guide/","publishedAt":null,"accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
14
+ {"id":"security-testing-cloud-supply-chain","domain":"security-testing","title":"Cloud, identity, CI/CD, and software supply-chain testing","summary":"Treat developer identity, build provenance, cloud control planes, and artifact promotion as first-class security boundaries.","guidance":"Inventory human and workload identities, federation, service principals, token issuers, permission boundaries, emergency access, CI runners, build secrets, registries, signing, provenance, artifact promotion, and deployment controllers. Review effective permissions and trust policies rather than labels. Verify short-lived credentials, audience and subject constraints, protected environments, branch/tag protections, dependency pinning, isolated untrusted builds, secret non-exposure, artifact immutability, signature/provenance verification, and separation between build and deploy authority. Test with benign canary artifacts and synthetic identities; never place live secrets in logs or untrusted jobs. Monitor control-plane changes, token issuance, policy changes, unusual artifact publication, and deployment provenance failures. A successful build is not supply-chain assurance: validate the identity and materials that produced the exact artifact deployed.","tags":["cloud security","workload identity","CI/CD","SLSA","provenance","artifact signing"],"sources":[{"title":"SLSA Specification","url":"https://slsa.dev/spec/v1.2/","publishedAt":null,"accessedAt":"2026-08-24","primary":true},{"title":"NIST Secure Software Development Framework SP 800-218","url":"https://csrc.nist.gov/pubs/sp/800/218/final","publishedAt":"2022-02-03","accessedAt":"2026-08-24","primary":true}],"reviewedAt":"2026-08-24","expiresAt":"2026-11-24","confidence":"high","defenseOnly":true}
@@ -0,0 +1,400 @@
1
+ import {
2
+ NO_COLOR_PALETTE
3
+ } from "./archymedes-jecyxv5c.mjs";
4
+ import {
5
+ __require
6
+ } from "./archymedes-x67v3n58.mjs";
7
+
8
+ // packages/archymedes-cli/src/editor-screen.tsx
9
+ import { useInput, useState } from "@termuijs/jsx";
10
+ import { Box, Text } from "@termuijs/widgets";
11
+
12
+ // packages/archymedes-cli/src/editor.ts
13
+ function initialEditorState(path, content, viewportRows = 20) {
14
+ const lines = content.split(`
15
+ `);
16
+ return {
17
+ path,
18
+ lines,
19
+ cursor: { row: 0, col: 0 },
20
+ mode: "normal",
21
+ scroll: 0,
22
+ viewportRows: Math.max(1, viewportRows),
23
+ dirty: false,
24
+ history: [],
25
+ future: [],
26
+ search: { query: "", typing: false }
27
+ };
28
+ }
29
+ function editorContent(state) {
30
+ return state.lines.join(`
31
+ `);
32
+ }
33
+ function clamp(state) {
34
+ const row = Math.max(0, Math.min(state.lines.length - 1, state.cursor.row));
35
+ const limit = state.mode === "insert" ? state.lines[row].length : Math.max(0, state.lines[row].length - 1);
36
+ const col = Math.max(0, Math.min(limit, state.cursor.col));
37
+ let scroll = state.scroll;
38
+ if (row < scroll)
39
+ scroll = row;
40
+ if (row >= scroll + state.viewportRows)
41
+ scroll = row - state.viewportRows + 1;
42
+ scroll = Math.max(0, Math.min(scroll, Math.max(0, state.lines.length - 1)));
43
+ return { ...state, cursor: { row, col }, scroll };
44
+ }
45
+ function checkpoint(state) {
46
+ return {
47
+ ...state,
48
+ history: [...state.history, { lines: [...state.lines], cursor: { ...state.cursor } }].slice(-200),
49
+ future: []
50
+ };
51
+ }
52
+ var WORD = /[A-Za-z0-9_]/;
53
+ function wordForward(line, col) {
54
+ let index = col;
55
+ while (index < line.length && WORD.test(line[index]))
56
+ index += 1;
57
+ while (index < line.length && !WORD.test(line[index]))
58
+ index += 1;
59
+ return index;
60
+ }
61
+ function wordBack(line, col) {
62
+ let index = Math.max(0, col - 1);
63
+ while (index > 0 && !WORD.test(line[index]))
64
+ index -= 1;
65
+ while (index > 0 && WORD.test(line[index - 1]))
66
+ index -= 1;
67
+ return index;
68
+ }
69
+ function keyToEditorAction(key, character, state) {
70
+ const name = key.name ?? "";
71
+ const isEnter = name === "return" || name === "enter";
72
+ const isEscape = name === "escape";
73
+ if (key.ctrl && name === "s")
74
+ return { kind: "save" };
75
+ if (key.ctrl && (name === "q" || name === "c"))
76
+ return { kind: "quit" };
77
+ if (state.search.typing) {
78
+ if (isEscape)
79
+ return { kind: "searchCommit" };
80
+ if (isEnter)
81
+ return { kind: "searchNext" };
82
+ if (name === "backspace")
83
+ return { kind: "searchBackspace" };
84
+ if (character && character.length === 1 && character >= " ")
85
+ return { kind: "searchType", character };
86
+ return { kind: "none" };
87
+ }
88
+ if (state.mode === "insert") {
89
+ if (isEscape)
90
+ return { kind: "normal" };
91
+ if (isEnter)
92
+ return { kind: "newline" };
93
+ if (name === "backspace")
94
+ return { kind: "backspace" };
95
+ if (name === "up")
96
+ return { kind: "move", rows: -1 };
97
+ if (name === "down")
98
+ return { kind: "move", rows: 1 };
99
+ if (name === "left")
100
+ return { kind: "move", cols: -1 };
101
+ if (name === "right")
102
+ return { kind: "move", cols: 1 };
103
+ if (name === "tab")
104
+ return { kind: "type", character: " " };
105
+ if (character && character.length === 1 && character >= " ")
106
+ return { kind: "type", character };
107
+ return { kind: "none" };
108
+ }
109
+ if (state.pending === "d")
110
+ return name === "d" || character === "d" ? { kind: "deleteLine" } : { kind: "normal" };
111
+ if (state.pending === "g")
112
+ return name === "g" || character === "g" ? { kind: "jump", to: "fileStart" } : { kind: "normal" };
113
+ if (isEscape)
114
+ return { kind: "normal" };
115
+ if (name === "up" || character === "k")
116
+ return { kind: "move", rows: -1 };
117
+ if (name === "down" || character === "j")
118
+ return { kind: "move", rows: 1 };
119
+ if (name === "left" || character === "h")
120
+ return { kind: "move", cols: -1 };
121
+ if (name === "right" || character === "l")
122
+ return { kind: "move", cols: 1 };
123
+ if (name === "pageup")
124
+ return { kind: "move", rows: -state.viewportRows };
125
+ if (name === "pagedown")
126
+ return { kind: "move", rows: state.viewportRows };
127
+ if (character === "0" || name === "home")
128
+ return { kind: "jump", to: "lineStart" };
129
+ if (character === "$" || name === "end")
130
+ return { kind: "jump", to: "lineEnd" };
131
+ if (character === "G")
132
+ return { kind: "jump", to: "fileEnd" };
133
+ if (character === "w")
134
+ return { kind: "jump", to: "wordForward" };
135
+ if (character === "b")
136
+ return { kind: "jump", to: "wordBack" };
137
+ if (character === "i")
138
+ return { kind: "insert" };
139
+ if (character === "a")
140
+ return { kind: "insert", at: "after" };
141
+ if (character === "I")
142
+ return { kind: "insert", at: "lineStart" };
143
+ if (character === "A")
144
+ return { kind: "insert", at: "lineEnd" };
145
+ if (character === "o")
146
+ return { kind: "insert", at: "below" };
147
+ if (character === "O")
148
+ return { kind: "insert", at: "above" };
149
+ if (character === "x")
150
+ return { kind: "deleteChar" };
151
+ if (character === "u")
152
+ return { kind: "undo" };
153
+ if (key.ctrl && name === "r")
154
+ return { kind: "redo" };
155
+ if (character === "/")
156
+ return { kind: "search" };
157
+ if (character === "n")
158
+ return { kind: "searchNext" };
159
+ if (character === "d" || character === "g")
160
+ return { kind: "pending", key: character };
161
+ return { kind: "none" };
162
+ }
163
+ function applyEditorAction(state, action) {
164
+ const plain = (next) => ({ state: clamp({ ...next, pending: undefined }), effect: undefined });
165
+ const line = state.lines[state.cursor.row] ?? "";
166
+ switch (action.kind) {
167
+ case "move":
168
+ return plain({
169
+ ...state,
170
+ message: undefined,
171
+ cursor: { row: state.cursor.row + (action.rows ?? 0), col: state.cursor.col + (action.cols ?? 0) }
172
+ });
173
+ case "jump": {
174
+ const targets = {
175
+ lineStart: { row: state.cursor.row, col: 0 },
176
+ lineEnd: { row: state.cursor.row, col: line.length },
177
+ fileStart: { row: 0, col: 0 },
178
+ fileEnd: { row: state.lines.length - 1, col: 0 },
179
+ wordForward: { row: state.cursor.row, col: wordForward(line, state.cursor.col) },
180
+ wordBack: { row: state.cursor.row, col: wordBack(line, state.cursor.col) }
181
+ };
182
+ return plain({ ...state, message: undefined, cursor: targets[action.to] });
183
+ }
184
+ case "insert": {
185
+ if (action.at === "below" || action.at === "above") {
186
+ const at = action.at === "below" ? state.cursor.row + 1 : state.cursor.row;
187
+ const next = checkpoint(state);
188
+ const lines = [...state.lines];
189
+ lines.splice(at, 0, "");
190
+ return plain({ ...next, lines, dirty: true, mode: "insert", cursor: { row: at, col: 0 } });
191
+ }
192
+ const col = action.at === "after" ? state.cursor.col + 1 : action.at === "lineStart" ? 0 : action.at === "lineEnd" ? line.length : state.cursor.col;
193
+ return plain({ ...state, mode: "insert", message: undefined, cursor: { row: state.cursor.row, col } });
194
+ }
195
+ case "normal":
196
+ return plain({ ...state, mode: "normal", message: undefined });
197
+ case "type": {
198
+ const next = checkpoint(state);
199
+ const lines = [...state.lines];
200
+ lines[state.cursor.row] = line.slice(0, state.cursor.col) + action.character + line.slice(state.cursor.col);
201
+ return plain({ ...next, lines, dirty: true, cursor: { row: state.cursor.row, col: state.cursor.col + action.character.length } });
202
+ }
203
+ case "newline": {
204
+ const next = checkpoint(state);
205
+ const lines = [...state.lines];
206
+ lines.splice(state.cursor.row, 1, line.slice(0, state.cursor.col), line.slice(state.cursor.col));
207
+ return plain({ ...next, lines, dirty: true, cursor: { row: state.cursor.row + 1, col: 0 } });
208
+ }
209
+ case "backspace": {
210
+ if (state.cursor.col === 0 && state.cursor.row === 0)
211
+ return plain(state);
212
+ const next = checkpoint(state);
213
+ const lines = [...state.lines];
214
+ if (state.cursor.col === 0) {
215
+ const previous = lines[state.cursor.row - 1];
216
+ lines.splice(state.cursor.row - 1, 2, previous + line);
217
+ return plain({ ...next, lines, dirty: true, cursor: { row: state.cursor.row - 1, col: previous.length } });
218
+ }
219
+ lines[state.cursor.row] = line.slice(0, state.cursor.col - 1) + line.slice(state.cursor.col);
220
+ return plain({ ...next, lines, dirty: true, cursor: { row: state.cursor.row, col: state.cursor.col - 1 } });
221
+ }
222
+ case "deleteChar": {
223
+ if (line.length === 0)
224
+ return plain(state);
225
+ const next = checkpoint(state);
226
+ const lines = [...state.lines];
227
+ lines[state.cursor.row] = line.slice(0, state.cursor.col) + line.slice(state.cursor.col + 1);
228
+ return plain({ ...next, lines, dirty: true });
229
+ }
230
+ case "deleteLine": {
231
+ const next = checkpoint(state);
232
+ const lines = [...state.lines];
233
+ lines.splice(state.cursor.row, 1);
234
+ return plain({ ...next, lines: lines.length > 0 ? lines : [""], dirty: true, cursor: { row: state.cursor.row, col: 0 } });
235
+ }
236
+ case "undo": {
237
+ const previous = state.history.at(-1);
238
+ if (!previous)
239
+ return plain({ ...state, message: "nothing to undo" });
240
+ return plain({
241
+ ...state,
242
+ lines: previous.lines,
243
+ cursor: previous.cursor,
244
+ history: state.history.slice(0, -1),
245
+ future: [...state.future, { lines: [...state.lines], cursor: { ...state.cursor } }],
246
+ dirty: true,
247
+ message: undefined
248
+ });
249
+ }
250
+ case "redo": {
251
+ const next = state.future.at(-1);
252
+ if (!next)
253
+ return plain({ ...state, message: "nothing to redo" });
254
+ return plain({
255
+ ...state,
256
+ lines: next.lines,
257
+ cursor: next.cursor,
258
+ future: state.future.slice(0, -1),
259
+ history: [...state.history, { lines: [...state.lines], cursor: { ...state.cursor } }],
260
+ dirty: true,
261
+ message: undefined
262
+ });
263
+ }
264
+ case "save":
265
+ return { state: clamp({ ...state, dirty: false, message: `saved ${state.path}`, pending: undefined }), effect: { kind: "save" } };
266
+ case "quit":
267
+ return { state, effect: { kind: "quit" } };
268
+ case "search":
269
+ return plain({ ...state, search: { query: "", typing: true }, message: undefined });
270
+ case "searchType":
271
+ return plain({ ...state, search: { ...state.search, query: state.search.query + action.character } });
272
+ case "searchBackspace":
273
+ return plain({ ...state, search: { ...state.search, query: state.search.query.slice(0, -1) } });
274
+ case "searchCommit":
275
+ return plain({ ...state, search: { ...state.search, typing: false } });
276
+ case "searchNext": {
277
+ const query = state.search.query;
278
+ if (!query)
279
+ return plain({ ...state, search: { ...state.search, typing: false } });
280
+ const order = [...state.lines.keys()].map((offset) => (state.cursor.row + offset) % state.lines.length);
281
+ for (const [index, row] of order.entries()) {
282
+ const from = index === 0 ? state.cursor.col + 1 : 0;
283
+ const found = state.lines[row].indexOf(query, from);
284
+ if (found >= 0) {
285
+ return plain({ ...state, cursor: { row, col: found }, search: { ...state.search, typing: false }, message: undefined });
286
+ }
287
+ }
288
+ return plain({ ...state, search: { ...state.search, typing: false }, message: `no match for "${query}"` });
289
+ }
290
+ case "pending":
291
+ return { state: { ...state, pending: action.key }, effect: undefined };
292
+ default:
293
+ return plain(state);
294
+ }
295
+ }
296
+ function editorKeyBar(state, columns = Number.POSITIVE_INFINITY) {
297
+ if (state.search.typing)
298
+ return `/${state.search.query} enter next esc done`;
299
+ if (state.mode === "insert")
300
+ return "esc normal ^S save ^Q quit";
301
+ const hints = [
302
+ { text: "i insert" },
303
+ { text: "o new line" },
304
+ { text: "x del" },
305
+ { text: "dd del line" },
306
+ { text: "u undo" },
307
+ { text: "/ find" },
308
+ { text: "^S save", essential: true },
309
+ { text: "^Q quit", essential: true }
310
+ ];
311
+ const optional = hints.filter((hint) => !hint.essential);
312
+ for (let dropped = 0;dropped <= optional.length; dropped += 1) {
313
+ const keep = new Set(optional.slice(0, optional.length - dropped));
314
+ const bar = hints.filter((hint) => hint.essential || keep.has(hint)).map((hint) => hint.text).join(" ");
315
+ if (bar.length <= columns)
316
+ return bar;
317
+ }
318
+ return "^S save ^Q quit";
319
+ }
320
+ function editorStatus(state) {
321
+ const position = `${state.cursor.row + 1}:${state.cursor.col + 1}`;
322
+ return `${state.path}${state.dirty ? " [+]" : ""} ${state.mode} ${position} ${state.lines.length} lines`;
323
+ }
324
+ function visibleEditorLines(state) {
325
+ return state.lines.slice(state.scroll, state.scroll + state.viewportRows).map((text, offset) => ({ number: state.scroll + offset + 1, text }));
326
+ }
327
+ function composeEditorFrame(state, columns, accent) {
328
+ const gutter = String(state.lines.length).length;
329
+ const clip = (text) => text.length <= columns ? text : text.slice(0, Math.max(0, columns - 1));
330
+ return [
331
+ { text: clip(editorStatus(state)), bold: true, ...accent ? { color: accent } : {} },
332
+ ...visibleEditorLines(state).map((entry) => ({
333
+ text: clip(`${String(entry.number).padStart(gutter, " ")} ${caretInto(entry.text, entry.number - 1 === state.cursor.row ? state.cursor.col : undefined)}`)
334
+ })),
335
+ { text: clip(state.message ?? editorKeyBar(state, columns)), dim: true }
336
+ ];
337
+ }
338
+ function caretInto(text, cursorCol) {
339
+ if (cursorCol === undefined)
340
+ return text;
341
+ const padded = text.length > cursorCol ? text : text.padEnd(cursorCol + 1, " ");
342
+ return `${padded.slice(0, cursorCol)}█${padded.slice(cursorCol + 1)}`;
343
+ }
344
+
345
+ // packages/archymedes-cli/src/editor-screen.tsx
346
+ import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
347
+ var Panel = Box;
348
+ var Line = Text;
349
+ var CHROME_ROWS = 2;
350
+ function EditorScreen({ columns, rows, path, content, onExit, palette = NO_COLOR_PALETTE }) {
351
+ const [state, setState] = useState(() => initialEditorState(path, content, Math.max(1, rows - CHROME_ROWS)));
352
+ useInput((input, key) => {
353
+ setState((current) => {
354
+ const action = keyToEditorAction({ name: key?.key, ctrl: key?.ctrl, shift: key?.shift }, input, current);
355
+ const { state: next, effect } = applyEditorAction(current, action);
356
+ if (effect?.kind === "save")
357
+ onExit(editorContent(next));
358
+ else if (effect?.kind === "quit")
359
+ onExit(undefined);
360
+ return next;
361
+ });
362
+ });
363
+ const frame = composeEditorFrame(state, columns, palette.accent);
364
+ return /* @__PURE__ */ jsxDEV(Panel, {
365
+ flexDirection: "column",
366
+ width: columns,
367
+ height: rows,
368
+ children: frame.map((line, index) => /* @__PURE__ */ jsxDEV(Line, {
369
+ bold: line.bold,
370
+ dimColor: line.dim,
371
+ color: line.color,
372
+ children: line.text
373
+ }, `row-${index}`, false, undefined, this))
374
+ }, undefined, false, undefined, this);
375
+ }
376
+ async function runEditorScreen(options) {
377
+ const { renderApp } = await import("@termuijs/jsx");
378
+ return new Promise((resolve) => {
379
+ let settled = false;
380
+ const finish = (saved) => {
381
+ if (settled)
382
+ return;
383
+ settled = true;
384
+ resolve(saved);
385
+ };
386
+ renderApp(EditorScreen, {
387
+ columns: options.columns,
388
+ rows: options.rows,
389
+ path: options.path,
390
+ content: options.content,
391
+ palette: options.palette,
392
+ onExit: finish,
393
+ fullscreen: true
394
+ }).catch(() => finish(undefined));
395
+ });
396
+ }
397
+ export {
398
+ runEditorScreen,
399
+ EditorScreen
400
+ };