Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
647c2ca
chore(harness): update generated harness
IvanLarinDev Jul 9, 2026
c0e10b1
fix(sorter): skip same-folder drop operations
IvanLarinDev Jul 9, 2026
e57dc51
chore(dropwheel): merge verified harness and sorter fixes
IvanLarinDev Jul 9, 2026
a5571a1
fix(text): avoid directory-name drop collisions
IvanLarinDev Jul 9, 2026
f279424
chore(dropwheel): merge text drop collision fix
IvanLarinDev Jul 9, 2026
9eceb44
fix(watcher): cancel queued work on stop
IvanLarinDev Jul 9, 2026
9595985
chore(dropwheel): merge watcher stop fix
IvanLarinDev Jul 9, 2026
98f7985
fix(watcher): gate queued sort after stop
IvanLarinDev Jul 9, 2026
f9d1735
chore(dropwheel): merge watcher stop race guard
IvanLarinDev Jul 9, 2026
cee2d28
fix(overlay): normalize virtual sorter roots
IvanLarinDev Jul 9, 2026
87768e3
test(watcher): add autosort collision regression
IvanLarinDev Jul 9, 2026
32e6373
chore(dropwheel): merge overlay root fix
IvanLarinDev Jul 9, 2026
afa0552
chore(dropwheel): merge watcher collision test
IvanLarinDev Jul 9, 2026
fe9fad2
fix(config): preserve config on unknown enum load
IvanLarinDev Jul 9, 2026
0aa30ee
fix(config): merge unknown enum config load
IvanLarinDev Jul 9, 2026
6ea7545
Merge remote-tracking branch 'origin/main'
IvanLarinDev Jul 9, 2026
b60c4fc
feat(overlay): add link quick-access targets
IvanLarinDev Jul 9, 2026
401b20d
fix(overlay): prioritize link drops over text saves
IvanLarinDev Jul 9, 2026
82c26fb
fix(overlay): handle saved messages chat drops
IvanLarinDev Jul 9, 2026
0f80897
fix(overlay): accept bare telegram links
IvanLarinDev Jul 9, 2026
1f888da
fix(overlay): use compatible add-target drag effect
IvanLarinDev Jul 9, 2026
599a833
fix(overlay): open telegram links in desktop app
IvanLarinDev Jul 9, 2026
75947d7
feat(overlay): stage telegram drops on clipboard
IvanLarinDev Jul 9, 2026
c3e3b05
fix(overlay): paste telegram drops into topic
IvanLarinDev Jul 9, 2026
a247351
fix(overlay): accept move-only telegram text drops
IvanLarinDev Jul 9, 2026
a32c791
fix(overlay): accept delayed telegram text drops
IvanLarinDev Jul 9, 2026
b387999
feat(overlay): enrich browser URL targets
IvanLarinDev Jul 10, 2026
32724a2
chore(dropwheel): merge telegram quick access target
IvanLarinDev Jul 10, 2026
b939ed2
docs(readme): document link and telegram targets
IvanLarinDev Jul 10, 2026
d3c2e92
chore(version): set project version v0.12.0
IvanLarinDev Jul 10, 2026
91c5b22
chore(version): v0.12.0
IvanLarinDev Jul 10, 2026
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
10 changes: 5 additions & 5 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Git hooks и скрипты ДОЛЖНЫ быть LFCRLF в shebang (`#!/usr/bin/env node\r`)
# ломает запуск на macOS/Linux ("node\r: not found"). Форсим LF независимо от autocrlf.
# Git hooks and scripts must stay LF; CRLF in a shebang (`#!/usr/bin/env node\r`)
# breaks macOS/Linux execution ("node\r: not found"). Force LF regardless of autocrlf.
hooks/*.js text eol=lf
hooks/**/*.js text eol=lf
install.js text eol=lf
*.sh text eol=lf

# Конфиги — тоже LF: иначе на Windows (autocrlf=true) рабочая копия становится CRLF,
# и `node hooks/doctor.js`, читающий рабочее дерево, даёт ложный FAIL (в индексе и на
# Linux-CI всё равно LF). Пинним форматы явно.
# Config files are LF too: otherwise Windows with autocrlf=true can make the working
# tree CRLF, and `node hooks/doctor.js` reads the working tree and reports a false
# FAIL even when the index and Linux CI are LF. Pin these formats explicitly.
*.toml text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
Expand Down
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Code owners for this target repository.
# No owner is configured yet, so the installed ruleset keeps code-owner
# review disabled and relies on the regular approving-review requirement.
# Re-run install.js with --code-owner @org/team or edit this file and
# enable require_code_owner_review in .github/rulesets/main.json.
22 changes: 16 additions & 6 deletions .github/rulesets/main.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
{
"_comment": "Versioned GitHub branch ruleset the REAL enforcement layer (server-side, cannot be skipped by `git ... --no-verify` or by editing local hooks). Apply with: node hooks/apply-ruleset.js. NOTE: private repos need GitHub Pro/Team/Enterprise for rulesets; on Free make the repo public or upgrade (BACKLOG P0-0). require_code_owner_review is FALSE on purpose: a solo maintainer cannot approve their own PR — enabling it would deadlock main. integration_id 15368 pins the required check to GitHub Actions: without it ANYONE with write access can satisfy the check by posting a fake commit status named 'verify' via the API.",
"_comment": "Installed GitHub branch ruleset for llm-dev-harness: the server-side gate that local hooks cannot replace. It requires PRs, the GitHub Actions verify check pinned by integration_id, and blocks force-push/delete on main. Code-owner review is disabled because install.js was run without --code-owner; the regular approving-review requirement remains enabled. Re-run install.js with --code-owner @org/team to require CODEOWNERS review.",
"name": "protect-main",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["refs/heads/main", "refs/heads/master"],
"include": [
"refs/heads/main",
"refs/heads/master"
],
"exclude": []
}
},
"rules": [
{ "type": "deletion" },
{ "type": "non_fast_forward" },
{
"type": "deletion"
},
{
"type": "non_fast_forward"
},
{
"type": "pull_request",
"parameters": {
"required_approving_review_count": 0,
"required_approving_review_count": 1,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": false,
Expand All @@ -27,7 +34,10 @@
"parameters": {
"strict_required_status_checks_policy": true,
"required_status_checks": [
{ "context": "verify", "integration_id": 15368 }
{
"context": "verify",
"integration_id": 15368
}
]
}
}
Expand Down
101 changes: 93 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,107 @@
name: CI
name: verify
# CI mirror of the local harness - the SAME checks, server-side where local hooks and
# `--no-verify` cannot skip them. The job id `verify` is the context referenced by the
# branch ruleset (.github/rulesets/main.json -> required_status_checks). Renaming the job
# means updating the ruleset too.
#
# On GitHub Free + private this workflow RUNS and reports status but cannot be *required*
# (rulesets need Pro/Team or a public repo - see BACKLOG P0-0).
#
# Actions are pinned to full commit SHAs. The trailing comment keeps Dependabot's
# github-actions updater able to identify the source action and desired major.

on:
# Push runs only on main for post-merge control. Branches are checked through PRs;
# otherwise every PR commit would run CI twice (push + pull_request).
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
verify:
runs-on: windows-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
with:
fetch-depth: 0

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # actions/setup-node@v6
with:
node-version: "22"

- uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # actions/setup-dotnet@v5
with:
dotnet-version: "10.0.x"

- uses: actions/setup-dotnet@v5
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # actions/setup-go@v6
with:
dotnet-version: 10.0.x
go-version: "1.24.x"

# Doctor catches bootstrap drift before the required check can go green by name only.
- name: Doctor (harness contract)
run: node hooks/doctor.js

# Secrets - gitleaks. Install from the Go module instead of gitleaks-action:
# the action's Windows asset resolver requested a non-existent .tar.gz.
- name: Secret scan (gitleaks)
shell: bash
env:
GITLEAKS_VERSION: "v8.24.3"
GITLEAKS_CONFIG: ".gitleaks.toml"
run: |
go install github.com/zricethezav/gitleaks/v8@$GITLEAKS_VERSION
gitleaks detect --source . --config "$GITLEAKS_CONFIG" --redact --no-banner

# Conventional Commits across the PR's commits - cocogitto (`cog check`).
# cocogitto-action is Linux-only; install the Windows binary explicitly.
- name: Install cocogitto
if: github.event_name == 'pull_request'
shell: bash
env:
COG_VERSION: "7.0.0"
COG_SHA256: "074f68f05d270da5c0d69d3e234ec362bec4c6e3189c21d1c948d038603655d7"
run: |
curl -fsSL -o cog.tar.gz "https://github.com/cocogitto/cocogitto/releases/download/$COG_VERSION/cocogitto-$COG_VERSION-x86_64-pc-windows-msvc.tar.gz"
echo "$COG_SHA256 cog.tar.gz" | sha256sum -c -
tar -xzf cog.tar.gz
"$PWD/x86_64-pc-windows-msvc/cog.exe" --version

# `cog.toml` is release-tag aware, but PR checks must also work before the
# first release tag exists. Use the PR base SHA explicitly instead of
# relying on from_latest_tag.
- name: Conventional commit range
if: github.event_name == 'pull_request'
shell: bash
run: ./x86_64-pc-windows-msvc/cog.exe check "${{ github.event.pull_request.base.sha }}..HEAD" --ignore-merge-commits

# Executable VERIFY: auto-detects stacks and runs lint/build/test fail-fast.
# For this repo that runs the harness self-test suite (node hooks/test.js).
- name: VERIFY (verify.js)
run: node hooks/verify.js

- name: Build
run: dotnet build src/Dropwheel -c Release
# AgentShield is an offline security scan of agent configuration: secrets,
# broad tool/MCP permissions, hook injections, and unsafe CLAUDE.md/AGENTS.md
# patterns. The version is pinned rather than using a floating tag/action, in
# the same supply-chain spirit as action SHA pinning. We do not use `--opus`;
# the baseline scan runs offline without a key. It is advisory for now
# (continue-on-error) while we collect false-positive data on our configs.
# Later: remove continue-on-error and add this as a second required check.
- name: AgentShield (agent-config security scan, advisory)
continue-on-error: true
shell: bash
env:
AGENTSHIELD_VERSION: "1.4.0"
AGENTSHIELD_INTEGRITY: "sha512-R98OO1Ujyk2lezDLb+iQmMhF6FwTJCHajy3G4FCB6x7wkSTqR9f8+eAelC5KDzYDsGSbc0sOZvjXOOPRBtMpDg=="
NPM_CONFIG_IGNORE_SCRIPTS: "true"
run: |
node -e "const {execFileSync}=require('child_process'); const got=execFileSync('npm',['view','ecc-agentshield@'+process.env.AGENTSHIELD_VERSION,'dist.integrity'],{encoding:'utf8'}).trim(); if(got!==process.env.AGENTSHIELD_INTEGRITY){ console.error('ecc-agentshield integrity mismatch: '+got); process.exit(1); }"
npx --yes ecc-agentshield@$AGENTSHIELD_VERSION scan --path .

- name: Test
run: dotnet test tests/Dropwheel.Tests -c Release
# DESIGN-gate: UI changes require an approved mockup set touched in the same diff.
- name: DESIGN-gate
if: github.event_name == 'pull_request'
run: node hooks/design-gate.js --strict --base ${{ github.event.pull_request.base.sha }}
2 changes: 1 addition & 1 deletion .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# .gitleaks.toml gitleaks config (replaces hooks/secret-scan.js).
# .gitleaks.toml - gitleaks config (replaces hooks/secret-scan.js).
# Uses the full default ruleset (100+ high-precision detectors) and layers a small allowlist.
# Inline exception on a line: gitleaks:allow (legacy `secret-scan:allow` also honored below).

Expand Down
Loading
Loading