git-repokit 0.9.10__py3-none-any.whl
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.
- git_repokit-0.9.10.dist-info/METADATA +422 -0
- git_repokit-0.9.10.dist-info/RECORD +174 -0
- git_repokit-0.9.10.dist-info/WHEEL +5 -0
- git_repokit-0.9.10.dist-info/entry_points.txt +2 -0
- git_repokit-0.9.10.dist-info/licenses/LICENSE +9 -0
- git_repokit-0.9.10.dist-info/top_level.txt +1 -0
- repokit/__init__.py +8 -0
- repokit/__main__.py +12 -0
- repokit/__version__.py +4 -0
- repokit/_vendor/__init__.py +0 -0
- repokit/_vendor/ailib/__init__.py +1 -0
- repokit/_vendor/ailib/analyzer.py +177 -0
- repokit/_vendor/ailib/backend.py +95 -0
- repokit/_vendor/ailib/cache.py +97 -0
- repokit/_vendor/ailib/parsers.py +52 -0
- repokit/_vendor/ailib/transports/__init__.py +16 -0
- repokit/_vendor/ailib/transports/cli.py +312 -0
- repokit/_vendor/ailib/transports/openai_compat.py +383 -0
- repokit/_vendor/ailib/transports/prompt_file.py +41 -0
- repokit/_vendor/ailib/types.py +224 -0
- repokit/auth_integration.py +244 -0
- repokit/badges.py +183 -0
- repokit/branch_utils.py +364 -0
- repokit/cli.py +2997 -0
- repokit/common_kit.py +202 -0
- repokit/config.py +686 -0
- repokit/defaults.py +220 -0
- repokit/directory_analyzer.py +1244 -0
- repokit/directory_profiles.py +423 -0
- repokit/git_config.py +370 -0
- repokit/github_create.py +142 -0
- repokit/github_setup.py +248 -0
- repokit/guardrails.py +707 -0
- repokit/history_cleaner.py +449 -0
- repokit/history_protection.py +434 -0
- repokit/hooks/pre-commit-guardrails +122 -0
- repokit/hooks/pre-commit-template +28 -0
- repokit/layers.py +510 -0
- repokit/licenses/0bsd.txt +14 -0
- repokit/licenses/LICENSES.md +27 -0
- repokit/licenses/__init__.py +142 -0
- repokit/licenses/agpl-3.0.txt +661 -0
- repokit/licenses/all-rights-reserved.txt +10 -0
- repokit/licenses/apache-2.0.txt +201 -0
- repokit/licenses/bsd-2-clause.txt +24 -0
- repokit/licenses/bsd-3-clause.txt +28 -0
- repokit/licenses/bsl-1.0.txt +23 -0
- repokit/licenses/cc-by-4.0.txt +395 -0
- repokit/licenses/cc-by-sa-4.0.txt +427 -0
- repokit/licenses/cc0-1.0.txt +121 -0
- repokit/licenses/epl-2.0.txt +277 -0
- repokit/licenses/gpl-2.0.txt +339 -0
- repokit/licenses/gpl-3.0.txt +674 -0
- repokit/licenses/isc.txt +15 -0
- repokit/licenses/lgpl-2.1.txt +504 -0
- repokit/licenses/lgpl-3.0.txt +165 -0
- repokit/licenses/mit.txt +21 -0
- repokit/licenses/mpl-2.0.txt +373 -0
- repokit/licenses/unlicense.txt +24 -0
- repokit/readme_blocks.py +112 -0
- repokit/remote_integration.py +627 -0
- repokit/repo_manager.py +2796 -0
- repokit/template_engine.py +391 -0
- repokit/templates/ai/claude/CLAUDE-nested.md.template +25 -0
- repokit/templates/ai/claude/CLAUDE.md.template +98 -0
- repokit/templates/ai/claude/instructions/step1_context_rebuilder.md +33 -0
- repokit/templates/ai/claude/instructions/step2_dev_workflow_process.md +67 -0
- repokit/templates/ai/claude/instructions/step3_context_bridge.md +52 -0
- repokit/templates/common/CHANGELOG.md.template +15 -0
- repokit/templates/common/CONTRIBUTING.md.template +31 -0
- repokit/templates/common/README.md.template +30 -0
- repokit/templates/common/gitattributes.template +17 -0
- repokit/templates/common/gitignore.template +141 -0
- repokit/templates/extras/FUNDING.yml.template +13 -0
- repokit/templates/extras/ROADMAP.md.template +17 -0
- repokit/templates/extras/dependabot.yml.template +22 -0
- repokit/templates/extras/one-offs-README.md.template +28 -0
- repokit/templates/extras/platform-support.md.template +11 -0
- repokit/templates/extras/pull_request_template.md.template +25 -0
- repokit/templates/extras/release-template.md.template +34 -0
- repokit/templates/extras/settings.json.template +11 -0
- repokit/templates/extras/stale.yml.template +14 -0
- repokit/templates/github/CODEOWNERS.template +11 -0
- repokit/templates/github/ISSUE_TEMPLATE/bug-report.md.template +29 -0
- repokit/templates/github/ISSUE_TEMPLATE/feature-request.md.template +19 -0
- repokit/templates/github/issues/notes.md.template +18 -0
- repokit/templates/github/issues/roadmap.md.template +15 -0
- repokit/templates/hooks/pre-commit.template +64 -0
- repokit/templates/layers/archetypes/any/claude-plugin/.claude-plugin/marketplace.json +20 -0
- repokit/templates/layers/archetypes/any/claude-plugin/plugin/.claude-plugin/plugin.json +15 -0
- repokit/templates/layers/archetypes/any/claude-plugin/plugin/README.md +28 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/.github/workflows/ci-c-cpp.yml +24 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/.repokit-common.toml.rkappend +4 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/.vscode/launch.json +29 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/.vscode/tasks.json +26 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/CMakeLists.txt +47 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/CMakePresets.json +23 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/cmake/GenerateStamp.cmake +45 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/src/main.cpp +27 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/tests/test_version.cpp +20 -0
- repokit/templates/layers/archetypes/c-cpp/cmake-app/vcpkg.json +5 -0
- repokit/templates/layers/archetypes/c-cpp/minimal/.vscode/launch.json +27 -0
- repokit/templates/layers/archetypes/c-cpp/minimal/Makefile +10 -0
- repokit/templates/layers/archetypes/c-cpp/minimal/build.bat +7 -0
- repokit/templates/layers/archetypes/c-cpp/minimal/src/__RK_SNAKE__.c +26 -0
- repokit/templates/layers/archetypes/c-cpp/msbuild/.vscode/launch.json +17 -0
- repokit/templates/layers/archetypes/c-cpp/msbuild/.vscode/tasks.json +20 -0
- repokit/templates/layers/archetypes/c-cpp/msbuild/__RK_PROJECT__.sln +19 -0
- repokit/templates/layers/archetypes/c-cpp/msbuild/__RK_PROJECT__.vcxproj +41 -0
- repokit/templates/layers/archetypes/c-cpp/msbuild/src/main.cpp +26 -0
- repokit/templates/layers/archetypes/js-ts/claude-plugin/.repokit-common.toml +28 -0
- repokit/templates/layers/archetypes/js-ts/claude-plugin/.vscode/launch.json +34 -0
- repokit/templates/layers/archetypes/js-ts/claude-plugin/plugin/hooks/hooks.json +15 -0
- repokit/templates/layers/archetypes/js-ts/claude-plugin/plugin/hooks/scripts/session-start.mjs +23 -0
- repokit/templates/layers/archetypes/js-ts/claude-plugin/plugin/tests/manifest.test.js +30 -0
- repokit/templates/layers/archetypes/js-ts/node/.repokit-common.toml.rkappend +6 -0
- repokit/templates/layers/archetypes/js-ts/node/package.json +13 -0
- repokit/templates/layers/archetypes/js-ts/node-package/.github/workflows/release.yml +39 -0
- repokit/templates/layers/archetypes/js-ts/node-package/package.json +32 -0
- repokit/templates/layers/archetypes/js-ts/node-package/src/index.ts +13 -0
- repokit/templates/layers/archetypes/js-ts/node-package/tests/index.test.ts +11 -0
- repokit/templates/layers/archetypes/js-ts/script/.vscode/launch.json +34 -0
- repokit/templates/layers/archetypes/js-ts/script/__RK_PROJECT__.js +37 -0
- repokit/templates/layers/archetypes/js-ts/script/tests/version.test.js +26 -0
- repokit/templates/layers/archetypes/js-ts/ts/package.json +18 -0
- repokit/templates/layers/archetypes/js-ts/ts/tsconfig.json +15 -0
- repokit/templates/layers/archetypes/python/claude-plugin/.github/workflows/ci-python.yml +44 -0
- repokit/templates/layers/archetypes/python/claude-plugin/.repokit-common.toml +21 -0
- repokit/templates/layers/archetypes/python/claude-plugin/.vscode/launch.json +33 -0
- repokit/templates/layers/archetypes/python/claude-plugin/VERSION +1 -0
- repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/hooks.json +15 -0
- repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/scripts/run-hook.mjs +42 -0
- repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/scripts/session_start.py +31 -0
- repokit/templates/layers/archetypes/python/claude-plugin/plugin/tests/test_manifest.py +42 -0
- repokit/templates/layers/archetypes/python/pypi/.github/workflows/release.yml +63 -0
- repokit/templates/layers/archetypes/python/pypi/.vscode/launch.json +43 -0
- repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/__init__.py +5 -0
- repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/__main__.py +6 -0
- repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/_version.py +96 -0
- repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/cli.py +18 -0
- repokit/templates/layers/archetypes/python/pypi/pyproject.toml +71 -0
- repokit/templates/layers/archetypes/python/pypi/tests/conftest.py +11 -0
- repokit/templates/layers/archetypes/python/pypi/tests/test_version.py +50 -0
- repokit/templates/layers/archetypes/python/script/.github/workflows/ci-python.yml +43 -0
- repokit/templates/layers/archetypes/python/script/.repokit-common.toml +14 -0
- repokit/templates/layers/archetypes/python/script/.vscode/launch.json +33 -0
- repokit/templates/layers/archetypes/python/script/VERSION +1 -0
- repokit/templates/layers/archetypes/python/script/__RK_PROJECT__.py +40 -0
- repokit/templates/layers/archetypes/python/script/tests/test_version.py +25 -0
- repokit/templates/layers/archetypes/python/setuppy/requirements.txt +8 -0
- repokit/templates/layers/archetypes/python/setuppy/setup.py +23 -0
- repokit/templates/layers/languages/c-cpp/.gitignore.rkappend +20 -0
- repokit/templates/layers/languages/c-cpp/.repokit-common.toml +7 -0
- repokit/templates/layers/languages/c-cpp/include/__RK_SNAKE__/version.h +20 -0
- repokit/templates/layers/languages/c-cpp/src/app.rc +25 -0
- repokit/templates/layers/languages/js-ts/.editorconfig +15 -0
- repokit/templates/layers/languages/js-ts/.github/workflows/ci-js-ts.yml +41 -0
- repokit/templates/layers/languages/js-ts/.gitignore.rkappend +13 -0
- repokit/templates/layers/languages/js-ts/.repokit-common.toml +19 -0
- repokit/templates/layers/languages/js-ts/.vscode/launch.json +24 -0
- repokit/templates/layers/languages/js-ts/VERSION +1 -0
- repokit/templates/layers/languages/python/.github/workflows/ci-python.yml +76 -0
- repokit/templates/layers/languages/python/.gitignore.rkappend +15 -0
- repokit/templates/layers/languages/python/.vscode/launch.json +33 -0
- repokit/templates/layers/manifest.toml +302 -0
- repokit/templates/vault/CLAUDE.md +29 -0
- repokit/templates/vault/claude/_maps/MOC-project.md +15 -0
- repokit/templates/vault/claude/_oracle/backlinks.md +3 -0
- repokit/templates/vault/claude/_oracle/concepts.md +12 -0
- repokit/templates/vault/claude/_oracle/manifest.md +10 -0
- repokit/templates/vault/claude/_todo/ACTIVE-WORK.md +18 -0
- repokit/templates/vault/claude/_todo/OPEN-LOOPS.md +14 -0
- repokit/utils.py +316 -0
- repokit/vault.py +248 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__RK_PROJECT__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "__RK_DESCRIPTION__",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/src/index.js",
|
|
10
|
+
"types": "./dist/src/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/src/index.d.ts",
|
|
14
|
+
"import": "./dist/src/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/src"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p .",
|
|
22
|
+
"typecheck": "tsc --noEmit -p .",
|
|
23
|
+
"test": "tsc -p . && node --test",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "^5.6.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* __RK_DESCRIPTION__
|
|
3
|
+
*
|
|
4
|
+
* The package's public surface. Everything exported here is what
|
|
5
|
+
* `import ... from "__RK_PROJECT__"` gives a consumer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const name = "__RK_PROJECT__";
|
|
9
|
+
|
|
10
|
+
/** A first function to replace with the package's work. */
|
|
11
|
+
export function greet(who = "world"): string {
|
|
12
|
+
return `Hello, ${who}, from ${name}.`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { greet, name } from "../src/index.js";
|
|
4
|
+
|
|
5
|
+
test("the package names itself", () => {
|
|
6
|
+
assert.equal(name, "__RK_PROJECT__");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test("greet greets", () => {
|
|
10
|
+
assert.equal(greet("tests"), `Hello, tests, from ${name}.`);
|
|
11
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "__RK_PROJECT__.js --version",
|
|
6
|
+
"type": "node",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"program": "${workspaceFolder}/__RK_PROJECT__.js",
|
|
9
|
+
"args": ["--version"],
|
|
10
|
+
"cwd": "${workspaceFolder}",
|
|
11
|
+
"console": "integratedTerminal",
|
|
12
|
+
"skipFiles": ["<node_internals>/**"]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "node: current file",
|
|
16
|
+
"type": "node",
|
|
17
|
+
"request": "launch",
|
|
18
|
+
"program": "${file}",
|
|
19
|
+
"cwd": "${workspaceFolder}",
|
|
20
|
+
"console": "integratedTerminal",
|
|
21
|
+
"skipFiles": ["<node_internals>/**"]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "npm test",
|
|
25
|
+
"type": "node",
|
|
26
|
+
"request": "launch",
|
|
27
|
+
"runtimeExecutable": "npm",
|
|
28
|
+
"runtimeArgs": ["test"],
|
|
29
|
+
"cwd": "${workspaceFolder}",
|
|
30
|
+
"console": "integratedTerminal",
|
|
31
|
+
"skipFiles": ["<node_internals>/**"]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// __RK_DESCRIPTION__
|
|
3
|
+
//
|
|
4
|
+
// A plain script: one file, run with node, no build step and no dependencies.
|
|
5
|
+
// The version lives in the VERSION file beside this module (git-repokit-common's
|
|
6
|
+
// version tool keeps it, package.json, the CHANGELOG and the tags in step).
|
|
7
|
+
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
|
|
12
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
export function readVersion() {
|
|
15
|
+
try {
|
|
16
|
+
return readFileSync(join(HERE, "VERSION"), "utf8").trim() || "0.0.0+unknown";
|
|
17
|
+
} catch {
|
|
18
|
+
return "0.0.0+unknown";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function main(argv = process.argv.slice(2)) {
|
|
23
|
+
if (argv.includes("--version") || argv.includes("-V")) {
|
|
24
|
+
console.log(readVersion());
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
28
|
+
console.log("usage: __RK_PROJECT__ [--version] [--help]\n\n__RK_DESCRIPTION__");
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
console.log("Hello from __RK_PROJECT__. Replace this with the script's work.");
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
36
|
+
process.exit(main());
|
|
37
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// The script answers --version with the VERSION file's content, and --help exits 0.
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
+
const SCRIPT = join(ROOT, "__RK_PROJECT__.js");
|
|
11
|
+
|
|
12
|
+
function run(...args) {
|
|
13
|
+
return spawnSync(process.execPath, [SCRIPT, ...args], { cwd: ROOT, encoding: "utf8" });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
test("--version matches the VERSION file", () => {
|
|
17
|
+
const r = run("--version");
|
|
18
|
+
assert.equal(r.status, 0, r.stderr);
|
|
19
|
+
assert.equal(r.stdout.trim(), readFileSync(join(ROOT, "VERSION"), "utf8").trim());
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("--help exits cleanly and names the script", () => {
|
|
23
|
+
const r = run("--help");
|
|
24
|
+
assert.equal(r.status, 0, r.stderr);
|
|
25
|
+
assert.match(r.stdout, /__RK_PROJECT__/);
|
|
26
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__RK_PROJECT__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "__RK_DESCRIPTION__",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc -p .",
|
|
12
|
+
"typecheck": "tsc --noEmit -p .",
|
|
13
|
+
"test": "tsc -p . && node --test"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.6.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"rootDir": ".",
|
|
12
|
+
"outDir": "dist"
|
|
13
|
+
},
|
|
14
|
+
"include": ["src", "tests"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: CI (Claude Code plugin, Python hooks)
|
|
2
|
+
|
|
3
|
+
# The plugin has no package to install: every hook script must compile, the
|
|
4
|
+
# node launcher must parse, and the plugin's tests run with pytest.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ main ]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [ main ]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, windows-latest]
|
|
19
|
+
python-version: ['3.10', '3.12']
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v7
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
uses: actions/setup-python@v7
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
|
|
29
|
+
- name: Set up Node
|
|
30
|
+
uses: actions/setup-node@v7
|
|
31
|
+
with:
|
|
32
|
+
node-version: '22'
|
|
33
|
+
|
|
34
|
+
- name: Compile the hooks and check the launcher
|
|
35
|
+
shell: bash
|
|
36
|
+
run: |
|
|
37
|
+
python -m py_compile plugin/hooks/scripts/*.py
|
|
38
|
+
node --check plugin/hooks/scripts/run-hook.mjs
|
|
39
|
+
|
|
40
|
+
- name: Run the plugin's tests
|
|
41
|
+
shell: bash
|
|
42
|
+
run: |
|
|
43
|
+
python -m pip install --upgrade pip pytest
|
|
44
|
+
python -m pytest plugin/tests -v
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# git-repokit-common settings for __RK_PROJECT__, a Claude Code plugin with Python hooks.
|
|
2
|
+
#
|
|
3
|
+
# The plugin lives in plugin/ with its own README for the marketplace; this
|
|
4
|
+
# root holds the repository's tooling. The version lives in VERSION; the
|
|
5
|
+
# vendored tool at scripts/repokit-common/ keeps the plugin manifest in step.
|
|
6
|
+
# "human" tags (v0.1.0) match the version Claude Code reads from
|
|
7
|
+
# plugin/.claude-plugin/plugin.json. A push runs the plugin's own tests.
|
|
8
|
+
|
|
9
|
+
[tool.repokit-common]
|
|
10
|
+
version-source = "VERSION"
|
|
11
|
+
changelog = "CHANGELOG.md"
|
|
12
|
+
repo-url = "https://github.com/__RK_ORG__/__RK_PROJECT__"
|
|
13
|
+
tag-prefix = "v"
|
|
14
|
+
tag-format = "human"
|
|
15
|
+
private-patterns = ["private/", "local/", ".env"]
|
|
16
|
+
test-command = "python -m pytest plugin/tests -q"
|
|
17
|
+
|
|
18
|
+
[[tool.repokit-common.extra-targets]]
|
|
19
|
+
path = "plugin/.claude-plugin/plugin.json"
|
|
20
|
+
type = "json"
|
|
21
|
+
field = "version"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Hook: session_start.py (type the event JSON, then Ctrl+Z Enter / Ctrl+D)",
|
|
6
|
+
"type": "debugpy",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"program": "${workspaceFolder}/plugin/hooks/scripts/session_start.py",
|
|
9
|
+
"cwd": "${workspaceFolder}",
|
|
10
|
+
"env": { "__RK_MACRO___DEBUG": "1" },
|
|
11
|
+
"console": "integratedTerminal",
|
|
12
|
+
"justMyCode": false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "pytest: plugin tests",
|
|
16
|
+
"type": "debugpy",
|
|
17
|
+
"request": "launch",
|
|
18
|
+
"module": "pytest",
|
|
19
|
+
"args": ["plugin/tests", "-q"],
|
|
20
|
+
"cwd": "${workspaceFolder}",
|
|
21
|
+
"console": "integratedTerminal",
|
|
22
|
+
"justMyCode": false
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "Python: current file",
|
|
26
|
+
"type": "debugpy",
|
|
27
|
+
"request": "launch",
|
|
28
|
+
"program": "${file}",
|
|
29
|
+
"console": "integratedTerminal",
|
|
30
|
+
"justMyCode": false
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Launch one of this plugin's Python hooks: node run-hook.mjs <script.py>
|
|
3
|
+
//
|
|
4
|
+
// Claude Code always has node (it is a node app), but `python3 || python` in
|
|
5
|
+
// hooks.json depends on the shell the hook runs under, which differs by
|
|
6
|
+
// platform. This launcher finds a Python 3 the platform's way round, runs the
|
|
7
|
+
// named script beside it with the event passed through on stdin, and returns
|
|
8
|
+
// its exit code. A missing Python or script is reported on stderr and exits 0,
|
|
9
|
+
// so a broken hook never blocks the session. Modelled on
|
|
10
|
+
// claude-session-logger's run-hook.mjs; the script name is an argument here,
|
|
11
|
+
// so one launcher serves every hook.
|
|
12
|
+
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const NAME = "__RK_PROJECT__";
|
|
20
|
+
const script = join(HERE, process.argv[2] || "session_start.py");
|
|
21
|
+
|
|
22
|
+
function findPython() {
|
|
23
|
+
const candidates = process.platform === "win32" ? ["python", "python3", "py"] : ["python3", "python"];
|
|
24
|
+
for (const cmd of candidates) {
|
|
25
|
+
const r = spawnSync(cmd, ["--version"], { stdio: "pipe", timeout: 5000 });
|
|
26
|
+
const out = `${r.stdout || ""}${r.stderr || ""}`;
|
|
27
|
+
if (r.status === 0 && out.includes("Python 3")) return cmd;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const python = findPython();
|
|
33
|
+
if (!python) {
|
|
34
|
+
process.stderr.write(`[${NAME}] Python 3 not found; install it and put python3 (or python) on PATH.\n`);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
if (!existsSync(script)) {
|
|
38
|
+
process.stderr.write(`[${NAME}] hook script not found: ${script}\n`);
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
const r = spawnSync(python, [script], { stdio: "inherit", timeout: 60000 });
|
|
42
|
+
process.exit(r.status || 0);
|
repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/scripts/session_start.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""SessionStart hook for __RK_PROJECT__.
|
|
2
|
+
|
|
3
|
+
Claude Code runs this (through run-hook.mjs) when a session starts and passes
|
|
4
|
+
the event as JSON on stdin. Anything printed to stdout as JSON with
|
|
5
|
+
"additionalContext" reaches the session; an empty object is a no-op. Replace
|
|
6
|
+
the body with the plugin's work; keep it quick (the hooks.json timeout is 10
|
|
7
|
+
seconds).
|
|
8
|
+
"""
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> int:
|
|
15
|
+
try:
|
|
16
|
+
raw = sys.stdin.read()
|
|
17
|
+
event = json.loads(raw) if raw.strip() else {}
|
|
18
|
+
except (ValueError, OSError):
|
|
19
|
+
event = {}
|
|
20
|
+
output = {}
|
|
21
|
+
if os.environ.get("__RK_MACRO___DEBUG"):
|
|
22
|
+
output["additionalContext"] = (
|
|
23
|
+
f"__RK_PROJECT__ saw a {event.get('hook_event_name', 'SessionStart')} event "
|
|
24
|
+
f"(source: {event.get('source', 'unknown')})."
|
|
25
|
+
)
|
|
26
|
+
sys.stdout.write(json.dumps(output))
|
|
27
|
+
return 0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == "__main__":
|
|
31
|
+
sys.exit(main())
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""The plugin's manifests parse, agree with VERSION, and the hook answers --
|
|
2
|
+
directly and through the node launcher Claude Code runs."""
|
|
3
|
+
import json
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
PLUGIN = Path(__file__).resolve().parents[1]
|
|
12
|
+
ROOT = PLUGIN.parent
|
|
13
|
+
SCRIPTS = PLUGIN / "hooks" / "scripts"
|
|
14
|
+
EVENT = json.dumps({"hook_event_name": "SessionStart", "source": "startup"})
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_plugin_json_names_the_plugin_and_carries_version():
|
|
18
|
+
manifest = json.loads((PLUGIN / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8"))
|
|
19
|
+
assert manifest["name"] == "__RK_PROJECT__"
|
|
20
|
+
assert manifest["version"] == (ROOT / "VERSION").read_text(encoding="utf-8").strip()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_marketplace_lists_this_plugin_from_plugin_folder():
|
|
24
|
+
market = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8"))
|
|
25
|
+
assert any(p["source"] == "./plugin" and p["name"] == "__RK_PROJECT__" for p in market["plugins"])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_the_session_start_hook_returns_json():
|
|
29
|
+
hooks = json.loads((PLUGIN / "hooks" / "hooks.json").read_text(encoding="utf-8"))
|
|
30
|
+
assert "SessionStart" in hooks["hooks"]
|
|
31
|
+
r = subprocess.run([sys.executable, str(SCRIPTS / "session_start.py")], input=EVENT,
|
|
32
|
+
capture_output=True, text=True, timeout=30)
|
|
33
|
+
assert r.returncode == 0, r.stderr
|
|
34
|
+
json.loads(r.stdout)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.mark.skipif(shutil.which("node") is None, reason="node is not on PATH")
|
|
38
|
+
def test_the_node_launcher_runs_the_python_hook():
|
|
39
|
+
r = subprocess.run(["node", str(SCRIPTS / "run-hook.mjs"), "session_start.py"], input=EVENT,
|
|
40
|
+
capture_output=True, text=True, timeout=60)
|
|
41
|
+
assert r.returncode == 0, r.stderr
|
|
42
|
+
json.loads(r.stdout)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Triggered when a GitHub Release is PUBLISHED -- not on tag push. This makes
|
|
4
|
+
# "publish a release" the single deliberate ship action: force-moving or
|
|
5
|
+
# re-pushing a tag (e.g. amending a released commit) never re-fires PyPI, so
|
|
6
|
+
# we don't get spurious "400 File already exists" failures. The release event
|
|
7
|
+
# checks out the release's tag, so the right version is built.
|
|
8
|
+
on:
|
|
9
|
+
release:
|
|
10
|
+
types: [published]
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
# Skip on the template repo itself (no pyproject.toml until instantiated)
|
|
19
|
+
if: github.repository != 'DazzleTools/git-repokit-template'
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v7
|
|
27
|
+
with:
|
|
28
|
+
python-version: '3.11'
|
|
29
|
+
|
|
30
|
+
- name: Install build dependencies
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install --upgrade pip
|
|
33
|
+
pip install build
|
|
34
|
+
|
|
35
|
+
- name: Build package
|
|
36
|
+
run: python -m build
|
|
37
|
+
|
|
38
|
+
- name: Check package
|
|
39
|
+
run: |
|
|
40
|
+
pip install twine
|
|
41
|
+
twine check dist/*
|
|
42
|
+
|
|
43
|
+
- uses: actions/upload-artifact@v7
|
|
44
|
+
with:
|
|
45
|
+
name: dist
|
|
46
|
+
path: dist/
|
|
47
|
+
|
|
48
|
+
publish:
|
|
49
|
+
needs: build
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
environment: pypi
|
|
52
|
+
|
|
53
|
+
permissions:
|
|
54
|
+
id-token: write
|
|
55
|
+
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/download-artifact@v8
|
|
58
|
+
with:
|
|
59
|
+
name: dist
|
|
60
|
+
path: dist/
|
|
61
|
+
|
|
62
|
+
- name: Publish to PyPI
|
|
63
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "__RK_PROJECT__ --version",
|
|
6
|
+
"type": "debugpy",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"module": "__RK_SNAKE__",
|
|
9
|
+
"args": ["--version"],
|
|
10
|
+
"cwd": "${workspaceFolder}",
|
|
11
|
+
"console": "integratedTerminal",
|
|
12
|
+
"justMyCode": false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "Python: current file",
|
|
16
|
+
"type": "debugpy",
|
|
17
|
+
"request": "launch",
|
|
18
|
+
"program": "${file}",
|
|
19
|
+
"console": "integratedTerminal",
|
|
20
|
+
"justMyCode": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "pytest: tests",
|
|
24
|
+
"type": "debugpy",
|
|
25
|
+
"request": "launch",
|
|
26
|
+
"module": "pytest",
|
|
27
|
+
"args": ["tests", "-q"],
|
|
28
|
+
"cwd": "${workspaceFolder}",
|
|
29
|
+
"console": "integratedTerminal",
|
|
30
|
+
"justMyCode": false
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "pytest: current file",
|
|
34
|
+
"type": "debugpy",
|
|
35
|
+
"request": "launch",
|
|
36
|
+
"module": "pytest",
|
|
37
|
+
"args": ["${file}", "-q"],
|
|
38
|
+
"cwd": "${workspaceFolder}",
|
|
39
|
+
"console": "integratedTerminal",
|
|
40
|
+
"justMyCode": false
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Version information for __RK_PROJECT__.
|
|
3
|
+
|
|
4
|
+
This file is the canonical source for version numbers.
|
|
5
|
+
The __version__ string is automatically updated by git hooks
|
|
6
|
+
with build metadata (branch, build number, date, commit hash).
|
|
7
|
+
|
|
8
|
+
Format: MAJOR.MINOR.PATCH[-PHASE]_BRANCH_BUILD-YYYYMMDD-COMMITHASH
|
|
9
|
+
Example: 0.1.0_main_1-20260101-a1b2c3d4
|
|
10
|
+
|
|
11
|
+
To sync versions: python scripts/repokit-common/sync-versions.py
|
|
12
|
+
To bump version: python scripts/repokit-common/sync-versions.py --bump patch
|
|
13
|
+
|
|
14
|
+
Version levels:
|
|
15
|
+
PROJECT_PHASE: Global project maturity (prealpha -> alpha -> beta -> stable).
|
|
16
|
+
Changes rarely, when the overall project hits a threshold.
|
|
17
|
+
PHASE: Per-MINOR feature set maturity (alpha -> beta -> "" for stable).
|
|
18
|
+
Drops when a MINOR's feature set is complete.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# Version components - edit these for version bumps
|
|
22
|
+
MAJOR = 0
|
|
23
|
+
MINOR = 1
|
|
24
|
+
PATCH = 0
|
|
25
|
+
PHASE = "" # Per-MINOR feature set: "" (stable), "alpha", "beta", "rc1", etc.
|
|
26
|
+
PRE_RELEASE_NUM = 1 # PEP 440 pre-release number (e.g., a1, b2)
|
|
27
|
+
|
|
28
|
+
# Project-level phase (independent of version phase)
|
|
29
|
+
PROJECT_PHASE = "" # "prealpha", "alpha", "beta", "stable", or ""
|
|
30
|
+
|
|
31
|
+
# Auto-updated by git hooks - do not edit manually
|
|
32
|
+
__version__ = "0.1.0"
|
|
33
|
+
__app_name__ = "__RK_PROJECT__"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_version():
|
|
37
|
+
"""Return the full version string including branch and build info."""
|
|
38
|
+
return __version__
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_base_version():
|
|
42
|
+
"""Return the semantic version string (MAJOR.MINOR.PATCH[-PHASE])."""
|
|
43
|
+
if "_" in __version__:
|
|
44
|
+
return __version__.split("_")[0]
|
|
45
|
+
base = f"{MAJOR}.{MINOR}.{PATCH}"
|
|
46
|
+
if PHASE:
|
|
47
|
+
base = f"{base}-{PHASE}"
|
|
48
|
+
return base
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_display_version():
|
|
52
|
+
"""Return a human-friendly version string with project phase.
|
|
53
|
+
|
|
54
|
+
Example: 'PREALPHA 0.1.0-alpha' or 'BETA 0.5.1' or '1.0.0'
|
|
55
|
+
"""
|
|
56
|
+
base = get_base_version()
|
|
57
|
+
if PROJECT_PHASE and PROJECT_PHASE != "stable":
|
|
58
|
+
return f"{PROJECT_PHASE.upper()} {base}"
|
|
59
|
+
return base
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_pip_version():
|
|
63
|
+
"""
|
|
64
|
+
Return PEP 440 compliant version for pip/setuptools.
|
|
65
|
+
|
|
66
|
+
Converts our version format to PEP 440:
|
|
67
|
+
- Main branch: 0.1.0_main_3-20260404-hash -> 0.1.0
|
|
68
|
+
- Dev branch: 0.1.0_dev_3-20260404-hash -> 0.1.0.dev3
|
|
69
|
+
- Alpha: 0.1.0-alpha_main_3 -> 0.1.0a1
|
|
70
|
+
"""
|
|
71
|
+
base = f"{MAJOR}.{MINOR}.{PATCH}"
|
|
72
|
+
|
|
73
|
+
# Map phase to PEP 440 pre-release segment
|
|
74
|
+
phase_map = {"alpha": f"a{PRE_RELEASE_NUM}", "beta": f"b{PRE_RELEASE_NUM}"}
|
|
75
|
+
if PHASE:
|
|
76
|
+
base += phase_map.get(PHASE, PHASE)
|
|
77
|
+
|
|
78
|
+
if "_" not in __version__:
|
|
79
|
+
return base
|
|
80
|
+
|
|
81
|
+
parts = __version__.split("_")
|
|
82
|
+
branch = parts[1] if len(parts) > 1 else "unknown"
|
|
83
|
+
|
|
84
|
+
if branch == "main":
|
|
85
|
+
return base
|
|
86
|
+
else:
|
|
87
|
+
build_info = "_".join(parts[2:]) if len(parts) > 2 else ""
|
|
88
|
+
build_num = build_info.split("-")[0] if "-" in build_info else "0"
|
|
89
|
+
return f"{base}.dev{build_num}"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# For convenience in imports
|
|
93
|
+
VERSION = get_version()
|
|
94
|
+
BASE_VERSION = get_base_version()
|
|
95
|
+
PIP_VERSION = get_pip_version()
|
|
96
|
+
DISPLAY_VERSION = get_display_version()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Command-line entry point for __RK_PROJECT__ (the `__RK_PROJECT__` command)."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from ._version import __app_name__, get_display_version
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
9
|
+
parser = argparse.ArgumentParser(prog=__app_name__, description="__RK_DESCRIPTION__")
|
|
10
|
+
parser.add_argument("--version", action="version", version=f"{__app_name__} {get_display_version()}")
|
|
11
|
+
return parser
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main(argv=None) -> int:
|
|
15
|
+
args = build_parser().parse_args(argv)
|
|
16
|
+
del args # nothing to do yet: replace this with the tool's work
|
|
17
|
+
print(f"{__app_name__} {get_display_version()}")
|
|
18
|
+
return 0
|