@jenga-ai/agent 1.1.0 → 1.2.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.
- package/README.md +7 -3
- package/agents/developer.md +82 -2
- package/agents/scrum-master.md +140 -21
- package/agents/tester.md +90 -8
- package/hooks/on_session_end.sh +171 -20
- package/package.json +1 -1
- package/scripts/check-permission-level.sh +107 -0
- package/scripts/check-publicignore-match.sh +122 -0
- package/scripts/check-worktree-liveness.sh +193 -0
- package/scripts/generate-rapport-manifest.sh +43 -0
- package/scripts/idea_manager.sh +47 -0
- package/scripts/install-worktree-commit-guard.sh +134 -0
- package/scripts/jenga-permission-level-switch.sh +109 -0
- package/scripts/smoke-harness.sh +139 -0
- package/scripts/validate-board.sh +62 -0
- package/scripts/with-lock.sh +158 -0
- package/scripts/worktree-remove-guard.sh +204 -0
- package/skills/clearify/SKILL.md +52 -0
- package/skills/commit/SKILL.md +13 -4
- package/skills/distribute/CONFIG_SCHEMA.md +60 -2
- package/skills/do/SKILL.md +48 -11
- package/skills/doc-sync/SKILL.md +16 -0
- package/skills/doc-sync/assets/doc_targets.md +11 -0
- package/skills/idea/SKILL.md +56 -0
- package/skills/idea/assets/idea_handoff_template.md +26 -0
- package/skills/idea/assets/idea_template.md +3 -0
- package/skills/init/SKILL.md +100 -7
- package/skills/init/assets/directory_structure.txt +1 -0
- package/skills/init/assets/workflow_template.json +1 -1
- package/skills/init/scripts/apply-project-visibility.sh +176 -0
- package/skills/init/scripts/detect-existing-codebase.sh +166 -0
- package/skills/init/scripts/init.sh +30 -1
- package/skills/jenga/SKILL.md +160 -17
- package/skills/jenga/scripts/board-scan.sh +238 -0
- package/skills/jenga/scripts/cascade-resolve.sh +297 -0
- package/skills/jenga/scripts/render-confirmation.sh +679 -0
- package/skills/jenga/scripts/render-picker.sh +439 -0
- package/skills/jenga/scripts/resolve-id.sh +367 -0
- package/skills/jenga-permission-level/SKILL.md +81 -0
- package/skills/proceed/SKILL.md +1 -1
- package/skills/publish/SKILL.md +8 -5
- package/skills/publish/assets/ci-contract.md +2 -2
- package/skills/publish/assets/ownership-matrix.md +1 -1
- package/skills/publish/scripts/finalize_changelog.sh +115 -0
- package/skills/publish/scripts/generate_release_notes.sh +475 -28
- package/skills/publish/scripts/npm_ci_pipeline.sh +44 -6
- package/skills/publish/scripts/publish_deploy.sh +38 -8
- package/skills/publish/scripts/run_gates.sh +2 -2
- package/skills/reconcile/SKILL.md +117 -5
- package/skills/reconcile/scripts/detect-unlinked-code.sh +741 -0
- package/skills/skillify/assets/init-new/assets/directory_structure.txt +5 -1
- package/skills/spinoff/SKILL.md +12 -7
- package/skills/todo/SKILL.md +2 -0
- package/skills/uncharted/SKILL.md +711 -0
- package/skills/uncharted/assets/SEGMENT_PROPOSAL_TEMPLATE.md +129 -0
- package/skills/uncharted/assets/UNDERSTANDING_DOC_TEMPLATE.md +160 -0
- package/skills/uncharted/scripts/apply-subsystem-cap.sh +573 -0
- package/skills/uncharted/scripts/detect-dependencies.sh +732 -0
- package/skills/uncharted/scripts/detect-tests.sh +553 -0
- package/skills/uncharted/scripts/discover-subsystems.sh +1029 -0
- package/skills/uncharted/scripts/enumerate-target.sh +470 -0
- package/skills/uncharted/scripts/import-source.sh +517 -0
- package/skills/uncharted/scripts/inspect-provenance.sh +573 -0
- package/skills/uncharted/scripts/resolve-segment-target.sh +640 -0
- package/skills/uncharted/scripts/run-engine.sh +655 -0
- package/skills/uncharted/scripts/validate-proposed-items.sh +125 -0
- package/skills/uncharted/scripts/write-backfilled-epics.sh +498 -0
- package/skills/wtf/SKILL.md +20 -0
- package/templates/CHANGELOG_TEMPLATE.md +13 -0
- package/templates/PROBLEM_RAPPORT_TEMPLATE.md +4 -1
- package/templates/SCRUM_BOARD_SCHEMA.md +157 -10
- package/templates/permission-levels/README.md +73 -0
- package/templates/permission-levels/level-1-locked.json +71 -0
- package/templates/permission-levels/level-2-guarded.json +64 -0
- package/templates/permission-levels/level-3-standard.json +62 -0
- package/templates/permission-levels/level-4-elevated.json +60 -0
- package/templates/permission-levels/level-5-unrestricted.json +58 -0
- package/skills/convert/SKILL.md +0 -124
- package/skills/convert/convert_cli.py +0 -235
- package/skills/convert/tests/sample.csv +0 -4
- package/skills/convert/tests/sample.json +0 -5
- package/skills/convert/tests/sample.jsonl +0 -3
- package/skills/convert/tests/sample.yaml +0 -18
- package/skills/convert/tests/sample_obj.csv +0 -2
- package/skills/convert/tests/sample_obj.json +0 -9
- package/skills/mirror-public/SKILL.md +0 -237
- package/skills/mirror-public/assets/config.json +0 -5
- package/skills/mirror-public/scripts/mirror.sh +0 -374
- package/skills/self-sync/SKILL.md +0 -73
- package/skills/self-sync/scripts/run.js +0 -136
- 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
|
+
}
|
package/skills/convert/SKILL.md
DELETED
|
@@ -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,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
|