sccc 0.3.0__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.
sccc/__init__.py ADDED
@@ -0,0 +1,15 @@
1
+ """SCCC — Skillchain Compiler-Compiler. The highest composite: AC + CoR + skills.
2
+
3
+ Same *CC shape (catch → lint → compile → package as SKILL.md). Built on the
4
+ `skillchain` module. ACCC → CORCC → SCCC.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ __version__ = "0.3.0"
9
+
10
+ from .forge import SCLanguage, StepRef, forge, lint, package, parse_sequence, resolve_steps
11
+
12
+ __all__ = [
13
+ "forge", "lint", "package", "parse_sequence", "resolve_steps",
14
+ "SCLanguage", "StepRef", "__version__",
15
+ ]
sccc/cli.py ADDED
@@ -0,0 +1,86 @@
1
+ """sccc — chain forged ACs + CoRs + regular skills into one SKILL.md rollup."""
2
+ from __future__ import annotations
3
+
4
+ from pathlib import Path
5
+ import tempfile
6
+
7
+ import click
8
+
9
+ from . import forge, lint, package, resolve_steps
10
+ from .notation import SEED_SEQUENCES
11
+
12
+ _STUB_SKILL = """---
13
+ name: summarize
14
+ description: Condense the prior step's result into a short answer.
15
+ ---
16
+
17
+ Summarize the input into 3 sentences and state the single most important takeaway.
18
+ """
19
+
20
+
21
+ @click.group()
22
+ @click.version_option(message="sccc %(version)s")
23
+ def main() -> None:
24
+ """Skillchain Compiler-Compiler — the highest composite (AC + CoR + skills)."""
25
+
26
+
27
+ @main.command()
28
+ def demo() -> None:
29
+ """Forge AC + CoR + a regular skill, chain them into one SKILL.md rollup."""
30
+ import accc
31
+ import corcc
32
+ from corcc.notation import EINSTEIN
33
+
34
+ with tempfile.TemporaryDirectory() as tmp:
35
+ db = str(Path(tmp) / "cc.db")
36
+ skills_dir = str(Path(tmp) / "skills")
37
+ out_dir = str(Path(tmp) / "dist")
38
+
39
+ click.echo("══ 1. FORGE + PACKAGE the parts (each a SKILL.md) ══")
40
+ accc.forge("debug-attention", ["[Symptom] ⇒ [Repro] ⇒ [Hypothesis] ⇒ |Localize|"], db=db)
41
+ ac_path = accc.package("debug-attention",
42
+ "[Symptom] ⇒ [Repro] ⇒ [Hypothesis] ⇒ |Localize|", out_dir=skills_dir)
43
+ persona = corcc.forge_persona(EINSTEIN, db=db)
44
+ cor_path = corcc.package(persona, out_dir=skills_dir)
45
+ skill_path = Path(skills_dir) / "summarize" / "SKILL.md"
46
+ skill_path.parent.mkdir(parents=True, exist_ok=True)
47
+ skill_path.write_text(_STUB_SKILL, encoding="utf-8")
48
+ ac_slug, cor_slug = ac_path.parent.name, cor_path.parent.name
49
+ click.echo(f" AC → {ac_slug}/SKILL.md")
50
+ click.echo(f" CoR → {cor_slug}/SKILL.md")
51
+ click.echo(f" skill → summarize/SKILL.md (a regular skill)")
52
+
53
+ click.echo("\n══ 2. FORGE the SC sequence grammar (shape) ══")
54
+ scl = forge("debug-then-explain", SEED_SEQUENCES, db=db)
55
+ click.echo(f" forged scope={scl.scope}, {scl.rule_count} rules")
56
+
57
+ sequence = f"[ac:{ac_slug}] ⇒ [cor:{cor_slug}] ⇒ [skill:summarize] ⇒ |Answer|"
58
+ click.echo(f"\n══ 3. LINT the SC sequence (syntax) ══\n {sequence}")
59
+ v, fixes = lint(scl, sequence)
60
+ click.echo(f" → {'clean ✓' if not v else 'violations'}")
61
+
62
+ click.echo("\n══ 4. LINT a malformed sequence (dropped ⇒) ══")
63
+ bad = f"[ac:{ac_slug}] [skill:summarize] ⇒ |Answer|"
64
+ v2, fx2 = lint(scl, bad)
65
+ if v2:
66
+ click.echo(f" {bad}\n ✗ {v2[0].verdict}: expected {v2[0].expected_token!r}, "
67
+ f"found {v2[0].found_token!r}; fix insert {list(fx2[0].candidate_tokens)}")
68
+
69
+ click.echo("\n══ 5. RESOLVE steps (each must exist on disk) ══")
70
+ rows, missing = resolve_steps(sequence, skills_dir=skills_dir)
71
+ for i, kind, ref, status, path in rows:
72
+ click.echo(f" {'✓' if status=='ok' else '✗'} [{i}] {kind:5} {ref}")
73
+
74
+ click.echo("\n══ 6. PACKAGE — roll the chain up into one SKILL.md ══")
75
+ sc_path = package("debug-then-explain", sequence, out_dir=out_dir, skills_dir=skills_dir)
76
+ click.echo(f" wrote {sc_path}")
77
+ click.echo(" ── SKILL.md (rollup) ──")
78
+ click.echo("\n".join(" " + ln for ln in sc_path.read_text().splitlines()[:24]))
79
+
80
+ click.echo("\n══ 7. The capstone ══")
81
+ click.echo(" AC → CoR → SC: an attention template, a spoken reasoning chain, and a regular "
82
+ "skill, composed into ONE publishable skillchain. All SKILL.md. All syntax-checked.")
83
+
84
+
85
+ if __name__ == "__main__":
86
+ main()
sccc/forge.py ADDED
@@ -0,0 +1,106 @@
1
+ """SCCC — the Skillchain Compiler-Compiler. Composes ACCC + CORCC + regular skills.
2
+
3
+ Same *CC shape: catch the SC sequence grammar → LINT its syntax → resolve each
4
+ step to a SKILL.md package (forged AC/CoR or regular skill) → compile the rollup
5
+ to `<name>/SKILL.md`. Built on the existing `skillchain` module for indexing,
6
+ resolution, and rollup compilation. Syntax + resolution only — never content.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+ from pathlib import Path
12
+ import re
13
+
14
+ import skillchain as sc
15
+
16
+ from chaincompiler import slugify, learn # made FROM CC (CC re-exports APE's slugify/learn)
17
+ from chaincompiler import gate as cp_gate # the persistent grammar gate, re-exported by CC
18
+ from rulecatcher.db import connect
19
+
20
+ _STEP_RE = re.compile(r"\[(ac|cor|skill):([^\]]+)\]")
21
+ _HELD_RE = re.compile(r"\|([^|]+)\|")
22
+
23
+
24
+ @dataclass
25
+ class SCLanguage:
26
+ name: str
27
+ scope: str
28
+ db: str
29
+ rule_count: int
30
+
31
+
32
+ @dataclass
33
+ class StepRef:
34
+ kind: str # ac | cor | skill
35
+ ref: str # the referenced package name
36
+ slug: str # resolved package slug
37
+
38
+
39
+ def forge(name: str, sequences: list[str], *, db: str) -> SCLanguage:
40
+ """Catch + ratify the SC sequence notation grammar (shape only)."""
41
+ scope = f"sc:{name}"
42
+ with connect(db) as cx:
43
+ adopted = learn(cx, sequences, scope=scope, rule_types=("next_kind",), label=f"sc:{name}")
44
+ return SCLanguage(name=name, scope=scope, db=db, rule_count=len(adopted))
45
+
46
+
47
+ def lint(language: SCLanguage, sequence: str) -> tuple[list, list]:
48
+ """Syntax-lint an SC sequence against the ratified grammar (the *CC check)."""
49
+ with connect(language.db) as cx:
50
+ return cp_gate(cx, sequence, scope=language.scope)
51
+
52
+
53
+ def parse_sequence(sequence: str) -> tuple[list[StepRef], str | None]:
54
+ steps = [StepRef(kind=m.group(1), ref=m.group(2).strip(), slug=slugify(m.group(2).strip()))
55
+ for m in _STEP_RE.finditer(sequence)]
56
+ held = _HELD_RE.search(sequence)
57
+ return steps, (held.group(1).strip() if held else None)
58
+
59
+
60
+ def _index(skills_dir: str | None):
61
+ roots = list(sc.SKILL_ROOTS)
62
+ if skills_dir:
63
+ roots.insert(0, Path(skills_dir))
64
+ return sc.index_skills(roots=roots)
65
+
66
+
67
+ def resolve_steps(sequence: str, *, skills_dir: str | None = None) -> tuple[list, list[str]]:
68
+ """Resolve each step to a package. Returns (rows, missing)."""
69
+ steps, _ = parse_sequence(sequence)
70
+ idx = _index(skills_dir)
71
+ rows, missing = [], []
72
+ for i, step in enumerate(steps, 1):
73
+ rec = sc.resolve(step.slug, idx) or sc.resolve(step.ref, idx)
74
+ if rec:
75
+ rows.append((i, step.kind, step.ref, "ok", str(rec["path"])))
76
+ else:
77
+ rows.append((i, step.kind, step.ref, "MISSING", ""))
78
+ missing.append(f"{step.kind}:{step.ref}")
79
+ return rows, missing
80
+
81
+
82
+ def package(name: str, sequence: str, *, out_dir: str, skills_dir: str | None = None,
83
+ description: str | None = None) -> Path:
84
+ """Compile an SC sequence into a rollup `<name>/SKILL.md`.
85
+
86
+ Resolves AC/CoR/skill steps to their packages (validated present) and rolls
87
+ them up in order via the skillchain compiler.
88
+ """
89
+ steps, held = parse_sequence(sequence)
90
+ spec = {
91
+ "name": slugify(name),
92
+ # NOTE: no ": " prefix in the default — write_skill (APE) does not YAML-escape
93
+ # the description; a plain scalar containing ": " emits unparseable frontmatter.
94
+ # (The step refs keep their `kind:name` form — colon-no-space is YAML-safe.)
95
+ "description": description or (
96
+ f"Skillchain — {' → '.join(f'{s.kind}:{s.ref}' for s in steps)}"
97
+ + (f" → {held}" if held else "")
98
+ ),
99
+ "steps": [{"skill": s.slug} for s in steps],
100
+ }
101
+ idx = _index(skills_dir)
102
+ ok, _rows, missing = sc.validate(spec, idx)
103
+ if not ok:
104
+ raise ValueError(f"cannot compile SC '{name}': unresolved steps {missing}")
105
+ pkg, _deps = sc.compile_package(spec, idx, out_dir)
106
+ return pkg / "SKILL.md"
sccc/notation.py ADDED
@@ -0,0 +1,19 @@
1
+ """SC (skillchain) sequence notation.
2
+
3
+ An SC IS A sequence chaining ACs + CoRs + regular skills, converging on a result:
4
+
5
+ [ac:<name>] ⇒ [cor:<name>] ⇒ [skill:<name>] ⇒ ... ⇒ |Result|
6
+
7
+ Each `[kind:name]` step references a SKILL.md package on disk — a forged
8
+ attention chain (kind=ac), a forged chain-of-reasoning (kind=cor), or a regular
9
+ skill (kind=skill). Written in Dense Rune-Chain so it is syntax-linted like every
10
+ other *CC notation. SC is the highest composite: AC → CoR → SC.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ # Seed SC sequences (used to forge the SC notation grammar — the shape only).
15
+ SEED_SEQUENCES = [
16
+ "[ac:debug-attention] ⇒ [cor:think-like-einstein] ⇒ [skill:summarize] ⇒ |Answer|",
17
+ "[ac:debug-attention] ⇒ [skill:summarize] ⇒ |Answer|",
18
+ "[cor:think-like-einstein] ⇒ [skill:summarize] ⇒ |Answer|",
19
+ ]
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: sccc
3
+ Version: 0.3.0
4
+ Summary: Skillchain Compiler-Compiler — chains ACs + CoRs + skills into one SKILL.md
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: chaincompiler-accc==0.3.0
7
+ Requires-Dist: corcc==0.3.0
8
+ Requires-Dist: chaincompiler==0.3.0
9
+ Requires-Dist: rulecatcher==0.3.0
10
+ Requires-Dist: skillchain-compiler==0.3.0
11
+ Requires-Dist: click
@@ -0,0 +1,9 @@
1
+ sccc/__init__.py,sha256=S5yf_3tJheIVvcIKT139S_-ALgV3IyAdmNjvs7eaYhU,494
2
+ sccc/cli.py,sha256=oP-JvnjJa4N1Ju67KNMLM_2hOFAuvdkeTPVcx_SiSyo,3760
3
+ sccc/forge.py,sha256=d5NuzzSCvHCj3qgtu4N01EB1TBCn1b9uUglUhIl-V3A,4046
4
+ sccc/notation.py,sha256=JOmWBlFczK2BXjdTtYqInfwbAgSW7MIpzk9oxiLzQ-4,866
5
+ sccc-0.3.0.dist-info/METADATA,sha256=WNwg_qLx3tAo5F7AtqVkfzCUs2pXd4yr7igxgGuVvcQ,361
6
+ sccc-0.3.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
7
+ sccc-0.3.0.dist-info/entry_points.txt,sha256=8uARCuJWYrcWRRIZ2ix8ix1Qx3qJm9KaK_3utRj02RI,39
8
+ sccc-0.3.0.dist-info/top_level.txt,sha256=gbdxIxYzSZHmeSYHp-yjiU1hnnux3q43COsBFxAKhvM,5
9
+ sccc-0.3.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sccc = sccc.cli:main
@@ -0,0 +1 @@
1
+ sccc