@jenga-ai/agent 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +7 -3
  2. package/agents/developer.md +82 -2
  3. package/agents/scrum-master.md +140 -21
  4. package/agents/tester.md +90 -8
  5. package/hooks/on_session_end.sh +171 -20
  6. package/package.json +1 -1
  7. package/scripts/check-permission-level.sh +107 -0
  8. package/scripts/check-publicignore-match.sh +122 -0
  9. package/scripts/check-worktree-liveness.sh +193 -0
  10. package/scripts/generate-rapport-manifest.sh +43 -0
  11. package/scripts/idea_manager.sh +47 -0
  12. package/scripts/install-worktree-commit-guard.sh +134 -0
  13. package/scripts/jenga-permission-level-switch.sh +109 -0
  14. package/scripts/smoke-harness.sh +139 -0
  15. package/scripts/validate-board.sh +62 -0
  16. package/scripts/with-lock.sh +158 -0
  17. package/scripts/worktree-remove-guard.sh +204 -0
  18. package/skills/clearify/SKILL.md +52 -0
  19. package/skills/commit/SKILL.md +13 -4
  20. package/skills/distribute/CONFIG_SCHEMA.md +60 -2
  21. package/skills/do/SKILL.md +48 -11
  22. package/skills/doc-sync/SKILL.md +16 -0
  23. package/skills/doc-sync/assets/doc_targets.md +11 -0
  24. package/skills/idea/SKILL.md +56 -0
  25. package/skills/idea/assets/idea_handoff_template.md +26 -0
  26. package/skills/idea/assets/idea_template.md +3 -0
  27. package/skills/init/SKILL.md +100 -7
  28. package/skills/init/assets/directory_structure.txt +1 -0
  29. package/skills/init/assets/workflow_template.json +1 -1
  30. package/skills/init/scripts/apply-project-visibility.sh +176 -0
  31. package/skills/init/scripts/detect-existing-codebase.sh +166 -0
  32. package/skills/init/scripts/init.sh +30 -1
  33. package/skills/jenga/SKILL.md +160 -17
  34. package/skills/jenga/scripts/board-scan.sh +238 -0
  35. package/skills/jenga/scripts/cascade-resolve.sh +297 -0
  36. package/skills/jenga/scripts/render-confirmation.sh +679 -0
  37. package/skills/jenga/scripts/render-picker.sh +439 -0
  38. package/skills/jenga/scripts/resolve-id.sh +367 -0
  39. package/skills/jenga-permission-level/SKILL.md +81 -0
  40. package/skills/proceed/SKILL.md +1 -1
  41. package/skills/publish/SKILL.md +8 -5
  42. package/skills/publish/assets/ci-contract.md +2 -2
  43. package/skills/publish/assets/ownership-matrix.md +1 -1
  44. package/skills/publish/scripts/finalize_changelog.sh +115 -0
  45. package/skills/publish/scripts/generate_release_notes.sh +475 -28
  46. package/skills/publish/scripts/npm_ci_pipeline.sh +44 -6
  47. package/skills/publish/scripts/publish_deploy.sh +38 -8
  48. package/skills/publish/scripts/run_gates.sh +2 -2
  49. package/skills/reconcile/SKILL.md +117 -5
  50. package/skills/reconcile/scripts/detect-unlinked-code.sh +741 -0
  51. package/skills/skillify/assets/init-new/assets/directory_structure.txt +5 -1
  52. package/skills/spinoff/SKILL.md +12 -7
  53. package/skills/todo/SKILL.md +2 -0
  54. package/skills/uncharted/SKILL.md +711 -0
  55. package/skills/uncharted/assets/SEGMENT_PROPOSAL_TEMPLATE.md +129 -0
  56. package/skills/uncharted/assets/UNDERSTANDING_DOC_TEMPLATE.md +160 -0
  57. package/skills/uncharted/scripts/apply-subsystem-cap.sh +573 -0
  58. package/skills/uncharted/scripts/detect-dependencies.sh +732 -0
  59. package/skills/uncharted/scripts/detect-tests.sh +553 -0
  60. package/skills/uncharted/scripts/discover-subsystems.sh +1029 -0
  61. package/skills/uncharted/scripts/enumerate-target.sh +470 -0
  62. package/skills/uncharted/scripts/import-source.sh +517 -0
  63. package/skills/uncharted/scripts/inspect-provenance.sh +573 -0
  64. package/skills/uncharted/scripts/resolve-segment-target.sh +640 -0
  65. package/skills/uncharted/scripts/run-engine.sh +655 -0
  66. package/skills/uncharted/scripts/validate-proposed-items.sh +125 -0
  67. package/skills/uncharted/scripts/write-backfilled-epics.sh +498 -0
  68. package/skills/wtf/SKILL.md +20 -0
  69. package/templates/CHANGELOG_TEMPLATE.md +13 -0
  70. package/templates/PROBLEM_RAPPORT_TEMPLATE.md +4 -1
  71. package/templates/SCRUM_BOARD_SCHEMA.md +157 -10
  72. package/templates/permission-levels/README.md +73 -0
  73. package/templates/permission-levels/level-1-locked.json +71 -0
  74. package/templates/permission-levels/level-2-guarded.json +64 -0
  75. package/templates/permission-levels/level-3-standard.json +62 -0
  76. package/templates/permission-levels/level-4-elevated.json +60 -0
  77. package/templates/permission-levels/level-5-unrestricted.json +58 -0
  78. package/skills/convert/SKILL.md +0 -124
  79. package/skills/convert/convert_cli.py +0 -235
  80. package/skills/convert/tests/sample.csv +0 -4
  81. package/skills/convert/tests/sample.json +0 -5
  82. package/skills/convert/tests/sample.jsonl +0 -3
  83. package/skills/convert/tests/sample.yaml +0 -18
  84. package/skills/convert/tests/sample_obj.csv +0 -2
  85. package/skills/convert/tests/sample_obj.json +0 -9
  86. package/skills/mirror-public/SKILL.md +0 -237
  87. package/skills/mirror-public/assets/config.json +0 -5
  88. package/skills/mirror-public/scripts/mirror.sh +0 -374
  89. package/skills/self-sync/SKILL.md +0 -73
  90. package/skills/self-sync/scripts/run.js +0 -136
  91. package/skills/strategy/SKILL.md +0 -312
@@ -0,0 +1,58 @@
1
+ {
2
+ "defaultMode": "acceptEdits",
3
+ "env": {
4
+ "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
5
+ },
6
+ "autoMode": {
7
+ "allow": [
8
+ "$defaults",
9
+ "Bash(bash skills/mirror-public/scripts/mirror.sh*)"
10
+ ]
11
+ },
12
+ "permissions": {
13
+ "allow": [
14
+ "Bash(*)"
15
+ ],
16
+ "deny": [
17
+ "Bash(dd *)",
18
+ "Bash(mkfs *)",
19
+ "Bash(shred *)",
20
+ "Bash(truncate *)",
21
+ "Bash(sudo *)",
22
+ "Bash(su *)"
23
+ ]
24
+ },
25
+ "hooks": {
26
+ "WorktreeCreate": [
27
+ {
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "NAME=$(jq -r '.name')\n. \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\"\nDIR=\"$JENGA_PROJECT_DIR/.claude/worktrees/$NAME\"\ngit worktree add \"$DIR\" -b \"$NAME\" 2>&1\necho \"$DIR\"\n"
32
+ }
33
+ ]
34
+ }
35
+ ],
36
+ "WorktreeRemove": [
37
+ {
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "\"$(git rev-parse --show-toplevel)/scripts/worktree-remove-guard.sh\"\n"
42
+ }
43
+ ]
44
+ }
45
+ ],
46
+ "SessionEnd": [
47
+ {
48
+ "hooks": [
49
+ {
50
+ "type": "command",
51
+ "async": true,
52
+ "command": ". \"$(git rev-parse --show-toplevel)/lib/resolve-project-dir.sh\" && \"$JENGA_PROJECT_DIR\"/.claude/hooks/on_session_end.sh"
53
+ }
54
+ ]
55
+ }
56
+ ]
57
+ }
58
+ }
@@ -1,124 +0,0 @@
1
- ---
2
- name: convert
3
- description: Convert JSON, JSONL, YAML, or YML dataset files to CSV format. Pass-through for files already in CSV. Flattens nested structures using dot-notation.
4
- keywords:
5
- - convert
6
- - csv
7
- - json to csv
8
- - yaml to csv
9
- - dataset format
10
- examples:
11
- - "convert this JSON file to CSV"
12
- - "convert my dataset to CSV format"
13
- ---
14
-
15
- # Convert — Dataset File Converter
16
-
17
- ## What It Does
18
-
19
- `/convert` takes a dataset file in JSON, JSONL, YAML, or YML format and outputs a clean CSV file ready for use in `/train` jobs.
20
-
21
- - **Auto-detects** the input format from the file extension
22
- - **Flattens** nested objects using dot-notation (e.g. `{"user": {"age": 30}}` → column `user.age`)
23
- - **Pass-through**: if the input is already `.csv`, it is returned unchanged
24
- - **Warns** if the top-level structure is an object `{}` instead of an array `[]`, and asks for confirmation before converting
25
-
26
- Output is written to the **same directory** as the input file, with a `.csv` extension.
27
-
28
- ---
29
-
30
- ## Invocation
31
-
32
- ```bash
33
- python skills/convert/convert_cli.py <path-to-file>
34
- ```
35
-
36
- Or, when invoked through the Copilot CLI:
37
-
38
- ```
39
- /convert <path-to-file>
40
- ```
41
-
42
- ---
43
-
44
- ## Supported Formats
45
-
46
- | Extension | Description |
47
- |---------------|--------------------------------------------------|
48
- | `.json` | JSON array `[{...}, ...]` or object `{...}` |
49
- | `.jsonl` | JSON Lines — one JSON object per line |
50
- | `.yaml`/`.yml`| YAML array of records or mapping |
51
- | `.csv` | Already CSV — returned as-is (no conversion) |
52
-
53
- ---
54
-
55
- ## Examples
56
-
57
- ### JSON array → CSV
58
-
59
- ```bash
60
- python skills/convert/convert_cli.py data/train.json
61
- # Output: data/train.csv
62
- ```
63
-
64
- ### JSONL with nested structures → CSV
65
-
66
- Input `data/train.jsonl`:
67
- ```
68
- {"id": 1, "user": {"name": "Alice", "age": 30}, "label": "pos"}
69
- {"id": 2, "user": {"name": "Bob", "age": 25}, "label": "neg"}
70
- ```
71
-
72
- Output `data/train.csv`:
73
- ```
74
- id,user.name,user.age,label
75
- 1,Alice,30,pos
76
- 2,Bob,25,neg
77
- ```
78
-
79
- ### YAML → CSV
80
-
81
- ```bash
82
- python skills/convert/convert_cli.py data/train.yaml
83
- # Output: data/train.csv
84
- ```
85
-
86
- ### CSV pass-through
87
-
88
- ```bash
89
- python skills/convert/convert_cli.py data/train.csv
90
- # ✅ Input is already CSV — no conversion needed: /path/to/data/train.csv
91
- ```
92
-
93
- ### JSON object (top-level `{}`)
94
-
95
- When the file's top-level structure is an object rather than an array, the tool warns:
96
-
97
- ```
98
- ⚠️ Warning: 'config.json' has a top-level object ({...}), not an array ([...]).
99
- The tool will create a single-row CSV where each top-level key becomes a column.
100
- Proceed? [y/N]
101
- ```
102
-
103
- ---
104
-
105
- ## Dot-Notation Flattening
106
-
107
- Nested dicts are flattened recursively:
108
-
109
- | Input JSON | CSV column | Value |
110
- |-----------------------------------------|----------------|-------|
111
- | `{"user": {"name": "Alice"}}` | `user.name` | Alice |
112
- | `{"user": {"address": {"city": "NYC"}}}` | `user.address.city` | NYC |
113
- | `{"tags": ["ml", "nlp"]}` | `tags` | `["ml", "nlp"]` (JSON string) |
114
-
115
- Lists nested within records are preserved as JSON strings.
116
-
117
- ---
118
-
119
- ## Notes
120
-
121
- - Requires `pyyaml` for YAML/YML support: `pip install pyyaml`
122
- - Standard library only for JSON and JSONL (no extra dependencies)
123
- - Columns are ordered by first appearance across all records
124
- - Records missing a key will have an empty cell in that column
@@ -1,235 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- convert_cli.py — Dataset file converter for ML training jobs.
4
-
5
- Usage:
6
- python convert_cli.py <path-to-file>
7
-
8
- Supported input formats:
9
- .json — JSON array of records (or object, with confirmation)
10
- .jsonl — JSON Lines (one record per line)
11
- .yaml — YAML array of records (or object, with confirmation)
12
- .yml — same as .yaml
13
- .csv — pass-through (returned as-is, no conversion)
14
-
15
- Output:
16
- Written to the same directory as the input file with a .csv extension.
17
- e.g. data/train.json → data/train.csv
18
- """
19
- import csv
20
- import json
21
- import sys
22
- from pathlib import Path
23
-
24
- try:
25
- import yaml
26
- _YAML_AVAILABLE = True
27
- except ImportError:
28
- _YAML_AVAILABLE = False
29
-
30
- SUPPORTED_EXTENSIONS = {".json", ".jsonl", ".yaml", ".yml", ".csv"}
31
-
32
-
33
- # ---------------------------------------------------------------------------
34
- # Flattening
35
- # ---------------------------------------------------------------------------
36
-
37
- def _flatten(record, prefix=""):
38
- """
39
- Recursively flatten a nested dict using dot-notation keys.
40
- Non-dict values (including lists) are kept as-is (lists become JSON strings).
41
- """
42
- out = {}
43
- for k, v in record.items():
44
- full_key = f"{prefix}.{k}" if prefix else k
45
- if isinstance(v, dict):
46
- out.update(_flatten(v, full_key))
47
- elif isinstance(v, list):
48
- out[full_key] = json.dumps(v)
49
- else:
50
- out[full_key] = v
51
- return out
52
-
53
-
54
- def flatten_records(records):
55
- """Flatten a list of dicts. Returns a list of flat dicts."""
56
- return [_flatten(r) if isinstance(r, dict) else {"value": r} for r in records]
57
-
58
-
59
- # ---------------------------------------------------------------------------
60
- # Loaders
61
- # ---------------------------------------------------------------------------
62
-
63
- def load_json(path):
64
- with open(path, encoding="utf-8") as f:
65
- data = json.load(f)
66
- return data
67
-
68
-
69
- def load_jsonl(path):
70
- records = []
71
- with open(path, encoding="utf-8") as f:
72
- for lineno, line in enumerate(f, 1):
73
- line = line.strip()
74
- if not line:
75
- continue
76
- try:
77
- records.append(json.loads(line))
78
- except json.JSONDecodeError as e:
79
- print(f"⚠️ Skipping line {lineno} — JSON parse error: {e}")
80
- return records
81
-
82
-
83
- def load_yaml(path):
84
- if not _YAML_AVAILABLE:
85
- print("❌ PyYAML is not installed. Install it with: pip install pyyaml")
86
- sys.exit(1)
87
- with open(path, encoding="utf-8") as f:
88
- data = yaml.safe_load(f)
89
- return data
90
-
91
-
92
- # ---------------------------------------------------------------------------
93
- # Top-level structure sniff + normalisation
94
- # ---------------------------------------------------------------------------
95
-
96
- def _confirm_object_conversion(path, yes=False):
97
- """
98
- Warn the user that the top-level structure is a dict (not a list),
99
- and ask whether to proceed by treating each top-level key as a column.
100
- Returns True to proceed, False to abort.
101
- When yes=True, auto-confirms without prompting (for non-interactive use).
102
- """
103
- print(f"\n⚠️ Warning: '{path.name}' has a top-level object ({{...}}), not an array ([...]).")
104
- print(" The tool will create a single-row CSV where each top-level key becomes a column.")
105
- if yes:
106
- print(" Auto-confirming (--yes flag set).")
107
- return True
108
- try:
109
- answer = input(" Proceed? [y/N] ").strip().lower()
110
- except EOFError:
111
- answer = "n"
112
- return answer in ("y", "yes")
113
-
114
-
115
- def normalise_to_records(data, path, yes=False):
116
- """
117
- Ensure data is a list of dicts.
118
- - list → used directly
119
- - dict → warn + confirm, then wrap as [data]
120
- - other → error
121
- When yes=True, dict top-level is auto-confirmed.
122
- """
123
- if isinstance(data, list):
124
- return data
125
- if isinstance(data, dict):
126
- if not _confirm_object_conversion(path, yes=yes):
127
- print("❌ Conversion aborted by user.")
128
- sys.exit(0)
129
- return [data]
130
- print(f"❌ Unsupported top-level type '{type(data).__name__}'. Expected a list or dict.")
131
- sys.exit(1)
132
-
133
-
134
- # ---------------------------------------------------------------------------
135
- # Writer
136
- # ---------------------------------------------------------------------------
137
-
138
- def write_csv(records, output_path):
139
- """Write a list of flat dicts to a CSV file."""
140
- if not records:
141
- print(f"⚠️ No records to write — creating empty CSV at {output_path}")
142
- output_path.write_text("")
143
- return
144
-
145
- # Build a unified ordered fieldset (preserving first-seen order)
146
- fieldnames = list(dict.fromkeys(k for r in records for k in r))
147
-
148
- with open(output_path, "w", newline="", encoding="utf-8") as f:
149
- writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")
150
- writer.writeheader()
151
- writer.writerows(records)
152
-
153
- print(f"✅ Converted → {output_path} ({len(records)} row{'s' if len(records) != 1 else ''})")
154
-
155
-
156
- # ---------------------------------------------------------------------------
157
- # Main conversion entry point
158
- # ---------------------------------------------------------------------------
159
-
160
- def convert(input_path_str, yes=False):
161
- """
162
- Convert the given file to CSV.
163
- Returns the output path (str), or the input path for .csv pass-through.
164
- When yes=True, object top-level confirmation is auto-accepted.
165
- """
166
- path = Path(input_path_str).resolve()
167
-
168
- if not path.exists():
169
- print(f"❌ File not found: {path}")
170
- sys.exit(1)
171
-
172
- ext = path.suffix.lower()
173
-
174
- if ext not in SUPPORTED_EXTENSIONS:
175
- print(f"❌ Unsupported file extension '{ext}'.")
176
- print(f" Supported: {', '.join(sorted(SUPPORTED_EXTENSIONS))}")
177
- sys.exit(1)
178
-
179
- # Pass-through for CSV
180
- if ext == ".csv":
181
- print(f"✅ Input is already CSV — no conversion needed: {path}")
182
- return str(path)
183
-
184
- # Load data based on format
185
- if ext == ".json":
186
- data = load_json(path)
187
- elif ext == ".jsonl":
188
- data = load_jsonl(path)
189
- # JSONL is already a list of records
190
- records = flatten_records(normalise_to_records(data, path, yes=yes))
191
- output_path = path.with_suffix(".csv")
192
- write_csv(records, output_path)
193
- return str(output_path)
194
- elif ext in (".yaml", ".yml"):
195
- data = load_yaml(path)
196
- else:
197
- print(f"❌ Extension '{ext}' reached conversion without a handler — this is a bug.")
198
- sys.exit(1)
199
-
200
- records = flatten_records(normalise_to_records(data, path, yes=yes))
201
- output_path = path.with_suffix(".csv")
202
- write_csv(records, output_path)
203
- return str(output_path)
204
-
205
-
206
- # ---------------------------------------------------------------------------
207
- # CLI entry point
208
- # ---------------------------------------------------------------------------
209
-
210
- def main():
211
- args = [a for a in sys.argv[1:] if a not in ("-h", "--help")]
212
- help_requested = "-h" in sys.argv or "--help" in sys.argv
213
- yes = "--yes" in args or "--no-confirm" in args
214
- file_args = [a for a in args if not a.startswith("--")]
215
-
216
- if help_requested or len(file_args) != 1:
217
- print("Usage: python convert_cli.py <path-to-file> [--yes]")
218
- print()
219
- print("Supported formats: .json, .jsonl, .yaml, .yml, .csv")
220
- print()
221
- print("Options:")
222
- print(" --yes, --no-confirm Auto-confirm object-to-CSV conversion (non-interactive)")
223
- print()
224
- print("Examples:")
225
- print(" python convert_cli.py data/train.json")
226
- print(" python convert_cli.py data/train.jsonl --yes")
227
- print(" python convert_cli.py data/train.yaml")
228
- print(" python convert_cli.py data/train.csv # pass-through")
229
- sys.exit(0 if help_requested else 1)
230
-
231
- convert(file_args[0], yes=yes)
232
-
233
-
234
- if __name__ == "__main__":
235
- main()
@@ -1,4 +0,0 @@
1
- id,text,meta.source,meta.lang,label
2
- 1,The movie was great,twitter,en,positive
3
- 2,Terrible experience,reddit,en,negative
4
- 3,Pretty average overall,twitter,en,neutral
@@ -1,5 +0,0 @@
1
- [
2
- {"id": 1, "user": {"name": "Alice", "age": 30}, "label": "positive", "tags": ["ml", "nlp"]},
3
- {"id": 2, "user": {"name": "Bob", "age": 25}, "label": "negative", "tags": ["cv"]},
4
- {"id": 3, "user": {"name": "Carol", "age": 35}, "label": "positive", "tags": []}
5
- ]
@@ -1,3 +0,0 @@
1
- {"id": 1, "user": {"name": "Alice", "age": 30}, "score": 0.95, "label": "pos"}
2
- {"id": 2, "user": {"name": "Bob", "age": 25}, "score": 0.72, "label": "neg"}
3
- {"id": 3, "user": {"name": "Carol", "age": 35}, "score": 0.88, "label": "pos", "extra": {"source": "web"}}
@@ -1,18 +0,0 @@
1
- - id: 1
2
- text: "The movie was great"
3
- meta:
4
- source: twitter
5
- lang: en
6
- label: positive
7
- - id: 2
8
- text: "Terrible experience"
9
- meta:
10
- source: reddit
11
- lang: en
12
- label: negative
13
- - id: 3
14
- text: "Pretty average overall"
15
- meta:
16
- source: twitter
17
- lang: en
18
- label: neutral
@@ -1,2 +0,0 @@
1
- name,age,address.city,address.zip,active
2
- Alice,30,New York,10001,True
@@ -1,9 +0,0 @@
1
- {
2
- "name": "Alice",
3
- "age": 30,
4
- "address": {
5
- "city": "New York",
6
- "zip": "10001"
7
- },
8
- "active": true
9
- }