Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,20 @@ jobs:
- name: Run tests (nextest)
# thread-language's napi-* features conflict with tree-sitter-parsing at runtime;
# run it separately with only the compatible feature set.
# On Linux and Windows, run all tests (Docker is available for testcontainers).
if: runner.os != 'macOS'
run: |
cargo nextest run --workspace --exclude thread-language --all-features --no-fail-fast
cargo nextest run -p thread-language --features all-parsers,matching --no-fail-fast
- name: Run tests (nextest, macOS - skip Docker-dependent tests)
# macOS GitHub Actions runners (Apple Silicon) do not have Docker,
# so we exclude the incremental_postgres_tests that use testcontainers
# to spin up Postgres containers.
if: runner.os == 'macOS'
run: |
cargo nextest run --workspace --exclude thread-language --all-features --no-fail-fast \
-E "not (package(thread-flow) and binary(incremental_postgres_tests))"
cargo nextest run -p thread-language --features all-parsers,matching --no-fail-fast
- name: Run doc tests
run: |
cargo test --doc --workspace --exclude thread-language --all-features
Expand All @@ -119,6 +130,133 @@ jobs:
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install clang for WASM C compilation
run: sudo apt-get update -qq && sudo apt-get install -y clang
- name: Set up C header stubs for wasm32-unknown-unknown
# tree-sitter 0.25+ compiles C sources that #include standard C library headers
# (stdio.h, stdlib.h, string.h, etc.). The wasm32-unknown-unknown target has no OS
# and therefore no libc headers. We provide minimal stubs so the code compiles;
# actual implementations (malloc, memcpy, etc.) come from the wasm runtime / Rust.
run: |
CLANG_RES=$(clang --print-resource-dir)
STUBS=/tmp/wasm-stubs
mkdir -p "$STUBS"

# Use Python to write the stub files cleanly without heredoc indentation issues.
python3 - << 'PYEOF'
import os
STUBS = '/tmp/wasm-stubs'
stubs = {}

stubs['stdio.h'] = """\
#pragma once
#include <stddef.h>
#include <stdarg.h>
typedef void FILE;
#define stderr ((FILE*)0)
#define stdout ((FILE*)0)
#define stdin ((FILE*)0)
#define EOF (-1)
static inline int fprintf(FILE *f, const char *fmt, ...) { (void)f; (void)fmt; return 0; }
static inline int vfprintf(FILE *f, const char *fmt, va_list ap) { (void)f; (void)fmt; (void)ap; return 0; }
static inline int printf(const char *fmt, ...) { (void)fmt; return 0; }
static inline int snprintf(char *s, size_t n, const char *fmt, ...) { (void)s; (void)n; (void)fmt; return 0; }
static inline int sprintf(char *s, const char *fmt, ...) { (void)s; (void)fmt; return 0; }
static inline int fputc(int c, FILE *f) { (void)f; return c; }
static inline int fputs(const char *s, FILE *f) { (void)s; (void)f; return 0; }
static inline int fflush(FILE *f) { (void)f; return 0; }
"""

stubs['stdlib.h'] = """\
#pragma once
#include <stddef.h>
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
extern void *malloc(size_t size);
extern void *calloc(size_t count, size_t size);
extern void *realloc(void *ptr, size_t size);
extern void free(void *ptr);
extern void abort(void);
extern void exit(int status);
static inline int abs(int x) { return x < 0 ? -x : x; }
"""

stubs['string.h'] = """\
#pragma once
#include <stddef.h>
extern void *memcpy(void *dest, const void *src, size_t n);
extern void *memmove(void *dest, const void *src, size_t n);
extern void *memset(void *s, int c, size_t n);
extern int memcmp(const void *s1, const void *s2, size_t n);
extern void *memchr(const void *s, int c, size_t n);
extern size_t strlen(const char *s);
extern int strcmp(const char *s1, const char *s2);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern char *strcpy(char *dest, const char *src);
extern char *strncpy(char *dest, const char *src, size_t n);
extern char *strcat(char *dest, const char *src);
extern char *strncat(char *dest, const char *src, size_t n);
extern char *strchr(const char *s, int c);
extern char *strrchr(const char *s, int c);
extern char *strstr(const char *haystack, const char *needle);
"""

stubs['time.h'] = """\
#pragma once
#include <stdint.h>
typedef uint64_t time_t;
typedef uint64_t clock_t;
#define CLOCKS_PER_SEC ((clock_t)1000000)
static inline time_t time(time_t *t) { if (t) *t = 0; return 0; }
static inline clock_t clock(void) { return 0; }
"""

stubs['ctype.h'] = """\
#pragma once
static inline int isalpha(int c) { return (c>='a'&&c<='z')||(c>='A'&&c<='Z'); }
static inline int isdigit(int c) { return c>='0'&&c<='9'; }
static inline int isalnum(int c) { return isalpha(c)||isdigit(c); }
static inline int isspace(int c) { return c==' '||c=='\\t'||c=='\\n'||c=='\\r'||c=='\\f'||c=='\\v'; }
static inline int isupper(int c) { return c>='A'&&c<='Z'; }
static inline int islower(int c) { return c>='a'&&c<='z'; }
static inline int toupper(int c) { return islower(c)?c-('a'-'A'):c; }
static inline int tolower(int c) { return isupper(c)?c+('a'-'A'):c; }
static inline int isprint(int c) { return c>=' '&&c<='~'; }
static inline int iscntrl(int c) { return c<' '||c==127; }
static inline int isxdigit(int c) { return isdigit(c)||(c>='a'&&c<='f')||(c>='A'&&c<='F'); }
static inline int ispunct(int c) { return isprint(c)&&!isalnum(c)&&c!=' '; }
"""

stubs['wctype.h'] = """\
#pragma once
#include <stdint.h>
typedef uint32_t wint_t;
#define WEOF ((wint_t)-1)
static inline int iswspace(wint_t c) { return c==' '||c=='\\t'||c=='\\n'||c=='\\r'||c=='\\f'||c=='\\v'; }
static inline int iswalpha(wint_t c) { return (c>='a'&&c<='z')||(c>='A'&&c<='Z'); }
static inline int iswdigit(wint_t c) { return c>='0'&&c<='9'; }
static inline int iswalnum(wint_t c) { return iswalpha(c)||iswdigit(c); }
static inline int iswupper(wint_t c) { return c>='A'&&c<='Z'; }
static inline int iswlower(wint_t c) { return c>='a'&&c<='z'; }
static inline int iswprint(wint_t c) { return c>=' '&&c<='~'; }
static inline int iswpunct(wint_t c) { return iswprint(c)&&!iswalnum(c)&&c!=' '; }
static inline wint_t towlower(wint_t c) { return iswupper(c)?c+('a'-'A'):c; }
static inline wint_t towupper(wint_t c) { return iswlower(c)?c-('a'-'A'):c; }
"""

stubs['assert.h'] = """\
#pragma once
#define assert(x) ((void)(x))
"""

for name, content in stubs.items():
path = os.path.join(STUBS, name)
with open(path, 'w') as f:
f.write(content)
print(f' wrote {path}')
PYEOF

echo "CFLAGS_wasm32_unknown_unknown=-I${STUBS} -I${CLANG_RES}/include" >> "$GITHUB_ENV"
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
- name: Build WASM (dev)
Expand Down Expand Up @@ -163,6 +301,9 @@ jobs:
name: Security Audit
needs: quick-checks
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
steps:
- uses: actions/checkout@v4
with:
Expand Down
30 changes: 30 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,33 @@ path = ["claudedocs/**", "crates/**/claudedocs/**"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Knitli Inc. <knitli@knit.li>"
SPDX-License-Identifier = "MIT OR Apache-2.0"

[[annotations]]
path = [".claude/plugins/**", "ctx-plugin/**"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Knitli Inc. <knitli@knit.li>"
SPDX-License-Identifier = "MIT OR Apache-2.0"

[[annotations]]
path = [".vscode/**"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Knitli Inc. <knitli@knit.li>"
SPDX-License-Identifier = "MIT OR Apache-2.0"

[[annotations]]
path = ["crates/flow/benches/bench_graph_traversal.rs"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Knitli Inc. <knitli@knit.li>"
SPDX-License-Identifier = "AGPL-3.0-or-later"

[[annotations]]
path = ["get_comments.js"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Knitli Inc. <knitli@knit.li>"
SPDX-License-Identifier = "MIT OR Apache-2.0"

[[annotations]]
path = ["specs/**"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Knitli Inc. <knitli@knit.li>"
SPDX-License-Identifier = "MIT OR Apache-2.0"
1 change: 1 addition & 0 deletions crates/ast-engine/src/tree_sitter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ fn parse_lang(
///
/// ```rust,no_run
/// # use thread_ast_engine::tree_sitter::StrDoc;
/// # use thread_ast_engine::Doc;
/// # #[derive(Clone, Debug)]
/// # struct JavaScript;
/// # impl thread_ast_engine::Language for JavaScript {
Expand Down
3 changes: 3 additions & 0 deletions crates/flow/benches/bench_graph_traversal.rs.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: AGPL-3.0-or-later
6 changes: 3 additions & 3 deletions crates/flow/src/incremental/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl DependencyGraph {
/// ));
///
/// // Change C -> affects B and A
/// let changed = RapidSet::from([PathBuf::from("C")]);
/// let changed: RapidSet<PathBuf> = [PathBuf::from("C")].into_iter().collect();
/// let affected = graph.find_affected_files(&changed);
/// assert!(affected.contains(&PathBuf::from("A")));
/// assert!(affected.contains(&PathBuf::from("B")));
Expand Down Expand Up @@ -325,9 +325,9 @@ impl DependencyGraph {
/// PathBuf::from("B"), PathBuf::from("C"), DependencyType::Import,
/// ));
///
/// let files = RapidSet::from([
/// let files: RapidSet<PathBuf> = [
/// PathBuf::from("A"), PathBuf::from("B"), PathBuf::from("C"),
/// ]);
/// ].into_iter().collect();
/// let sorted = graph.topological_sort(&files).unwrap();
/// // C should come before B, B before A
/// let pos_a = sorted.iter().position(|p| p == &PathBuf::from("A")).unwrap();
Expand Down
1 change: 0 additions & 1 deletion crates/flow/src/incremental/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ pub enum InvalidationError {
/// ```rust
/// use thread_flow::incremental::invalidation::InvalidationDetector;
/// use thread_flow::incremental::DependencyGraph;
/// use thread_utilities::RapishSet;
/// use std::path::PathBuf;
///
/// let graph = DependencyGraph::new();
Expand Down
4 changes: 2 additions & 2 deletions crates/flow/src/incremental/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
//! AnalysisDefFingerprint, DependencyEdge, DependencyType,
//! };
//! use thread_flow::incremental::graph::DependencyGraph;
//! use thread_utilities::RapidSet;
//! use std::path::PathBuf;
//! use std::collections::HashSet;
//!
//! // Create a dependency graph
//! let mut graph = DependencyGraph::new();
Expand All @@ -51,7 +51,7 @@
//! });
//!
//! // Find files affected by a change to utils.rs
//! let changed = HashSet::from([PathBuf::from("src/utils.rs")]);
//! let changed: RapidSet<PathBuf> = [PathBuf::from("src/utils.rs")].into_iter().collect();
//! let affected = graph.find_affected_files(&changed);
//! assert!(affected.contains(&PathBuf::from("src/main.rs")));
//! ```
Expand Down
2 changes: 1 addition & 1 deletion crates/flow/src/incremental/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ impl AnalysisDefFingerprint {
/// use thread_utilities::RapidSet;
/// use std::path::PathBuf;
///
/// let sources = RapidSet::from([PathBuf::from("dep.rs")]);
/// let sources: RapidSet<PathBuf> = [PathBuf::from("dep.rs")].into_iter().collect();
/// let fp = AnalysisDefFingerprint::with_sources(b"content", sources);
/// assert_eq!(fp.source_files.len(), 1);
/// ```
Expand Down
3 changes: 3 additions & 0 deletions ctx-plugin/.claude-plugin/plugin.json.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/PLAN.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/README.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/agents/claim-validator.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/agents/context-auditor.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/commands/ctx-check.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/commands/ctx-discover.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/commands/ctx-drift.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/commands/ctx-fix.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/commands/ctx.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/cross-client/.codex/SKILL.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/cross-client/.cursor/rules/ctx-audit.mdc.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/cross-client/AGENTS.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/hooks/session-stop-reminder.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/install.sh.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions ctx-plugin/skills/context-hygiene.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions get_comments.js.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
3 changes: 3 additions & 0 deletions specs/thread-context-doctor-spec.md.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>

SPDX-License-Identifier: MIT OR Apache-2.0
Loading