knowzcode 0.3.7 → 0.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knowzcode",
3
- "version": "0.3.7",
3
+ "version": "0.5.2",
4
4
  "description": "Platform-agnostic AI development methodology with TDD, quality gates, and structured workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,15 +1,15 @@
1
- {
2
- "name": "alias-resolver",
3
- "version": "0.3.7",
4
- "description": "Resolves friendly natural-language aliases to KnowzCode canonical values (phase, audit, plan, workgroup_type).",
5
- "parameters": [
6
- {"name": "domain", "type": "string", "required": true},
7
- {"name": "text", "type": "string", "required": false}
8
- ],
9
- "actions": [
10
- {
11
- "type": "python",
12
- "code": "domain = (inputs.get('domain') or '').strip().lower()\ntext = (inputs.get('text') or '').strip().lower()\nresult = {'value': None}\nphase_map = {\n '1a': {'agent': 'analyst', 'prompt': 'knowzcode/prompts/[LOOP_1A]__Propose_Change_Set.md'},\n '1b': {'agent': 'architect', 'prompt': 'knowzcode/prompts/[LOOP_1B]__Draft_Specs.md'},\n '2a': {'agent': 'builder', 'prompt': 'knowzcode/prompts/[LOOP_2A]__Implement_Change_Set.md'},\n '2b': {'agent': 'reviewer', 'prompt': 'knowzcode/prompts/[LOOP_2B]__Verify_Implementation.md'},\n '3': {'agent': 'closer', 'prompt': 'knowzcode/prompts/[LOOP_3]__Finalize_And_Commit.md'}\n}\nphase_synonyms = {\n '1a': ['1a','loop 1a','analyze','analysis','impact','scope','change set','proposal'],\n '1b': ['1b','loop 1b','spec','specs','draft','design','blueprint'],\n '2a': ['2a','loop 2a','implement','implementation','build','code','develop'],\n '2b': ['2b','loop 2b','verify','verification','audit','test','qa','review'],\n '3': ['3','loop 3','final','finalize','finalization','commit','wrap up','close']\n}\naudit_map = {\n 'spec': 'knowzcode/prompts/Spec_Verification_Checkpoint.md',\n 'implementation': 'knowzcode/prompts/[LOOP_2B]__Verify_Implementation.md',\n 'architecture': None,\n 'security': None,\n 'integration': None\n}\naudit_synonyms = {\n 'spec': ['spec','specs','specification','checkpoint'],\n 'implementation': ['implementation','code','verify implementation','loop 2b'],\n 'architecture': ['architecture','arch','diagram','flowchart','structure'],\n 'security': ['security','sec','owasp','vulnerability'],\n 'integration': ['integration','holistic','system','end to end','e2e']\n}\nworkgroup_map = {'feat': 'feat','feature': 'feat','fix': 'fix','bug': 'fix','bugfix': 'fix','refactor': 'refactor','cleanup': 'refactor','issue': 'issue','incident': 'issue'}\nif domain == 'phase':\n if not text:\n key = '1a'\n else:\n key = None\n for canonical, synonyms in phase_synonyms.items():\n if text == canonical or text in synonyms or any(s in text for s in synonyms):\n key = canonical\n break\n if key is None:\n for canonical in phase_map.keys():\n if text.replace(' ','') == canonical:\n key = canonical\n break\n if key is None:\n key = '1a'\n data = phase_map[key]\n result['value'] = key.upper()\n result['prompt'] = data['prompt']\n result['agent'] = data['agent']\n result['requires_workgroup'] = data['agent'] != 'analyst'\nelif domain == 'audit':\n if not text:\n key = 'spec'\n else:\n key = None\n for canonical, synonyms in audit_synonyms.items():\n if text == canonical or text in synonyms or any(s in text for s in synonyms):\n key = canonical\n break\n if key is None:\n key = 'spec'\n result['value'] = key\n result['prompt'] = audit_map.get(key)\n result['agent'] = 'reviewer'\nelif domain == 'plan':\n result['value'] = text or ''\n result['prompt'] = None\nelif domain == 'workgroup_type':\n if not text:\n value = 'feat'\n else:\n value = None\n for key, mapped in workgroup_map.items():\n if text == key or key in text:\n value = mapped\n break\n if value is None:\n value = workgroup_map.get(text, 'feat')\n result['value'] = value\nelse:\n result['value'] = text or ''\noutputs.update(result)\n"
13
- }
14
- ]
15
- }
1
+ {
2
+ "name": "alias-resolver",
3
+ "version": "0.5.2",
4
+ "description": "Resolves friendly natural-language aliases to KnowzCode canonical values (phase, audit, plan, workgroup_type).",
5
+ "parameters": [
6
+ {"name": "domain", "type": "string", "required": true},
7
+ {"name": "text", "type": "string", "required": false}
8
+ ],
9
+ "actions": [
10
+ {
11
+ "type": "python",
12
+ "code": "domain = (inputs.get('domain') or '').strip().lower()\ntext = (inputs.get('text') or '').strip().lower()\nresult = {'value': None}\nphase_map = {\n '1a': {'agent': 'analyst', 'prompt': 'knowzcode/prompts/[LOOP_1A]__Propose_Change_Set.md'},\n '1b': {'agent': 'architect', 'prompt': 'knowzcode/prompts/[LOOP_1B]__Draft_Specs.md'},\n '2a': {'agent': 'builder', 'prompt': 'knowzcode/prompts/[LOOP_2A]__Implement_Change_Set.md'},\n '2b': {'agent': 'reviewer', 'prompt': 'knowzcode/prompts/[LOOP_2B]__Verify_Implementation.md'},\n '3': {'agent': 'closer', 'prompt': 'knowzcode/prompts/[LOOP_3]__Finalize_And_Commit.md'}\n}\nphase_synonyms = {\n '1a': ['1a','loop 1a','analyze','analysis','impact','scope','change set','proposal'],\n '1b': ['1b','loop 1b','spec','specs','draft','design','blueprint'],\n '2a': ['2a','loop 2a','implement','implementation','build','code','develop'],\n '2b': ['2b','loop 2b','verify','verification','audit','test','qa','review'],\n '3': ['3','loop 3','final','finalize','finalization','commit','wrap up','close']\n}\naudit_map = {\n 'spec': 'knowzcode/prompts/Spec_Verification_Checkpoint.md',\n 'implementation': 'knowzcode/prompts/[LOOP_2B]__Verify_Implementation.md',\n 'architecture': None,\n 'security': None,\n 'integration': None\n}\naudit_synonyms = {\n 'spec': ['spec','specs','specification','checkpoint'],\n 'implementation': ['implementation','code','verify implementation','loop 2b'],\n 'architecture': ['architecture','arch','diagram','flowchart','structure'],\n 'security': ['security','sec','owasp','vulnerability'],\n 'integration': ['integration','holistic','system','end to end','e2e']\n}\nworkgroup_map = {'feat': 'feat','feature': 'feat','fix': 'fix','bug': 'fix','bugfix': 'fix','refactor': 'refactor','cleanup': 'refactor','issue': 'issue','incident': 'issue'}\nif domain == 'phase':\n if not text:\n key = '1a'\n else:\n key = None\n for canonical, synonyms in phase_synonyms.items():\n if text == canonical or text in synonyms or any(s in text for s in synonyms):\n key = canonical\n break\n if key is None:\n for canonical in phase_map.keys():\n if text.replace(' ','') == canonical:\n key = canonical\n break\n if key is None:\n key = '1a'\n data = phase_map[key]\n result['value'] = key.upper()\n result['prompt'] = data['prompt']\n result['agent'] = data['agent']\n result['requires_workgroup'] = data['agent'] != 'analyst'\nelif domain == 'audit':\n if not text:\n key = 'spec'\n else:\n key = None\n for canonical, synonyms in audit_synonyms.items():\n if text == canonical or text in synonyms or any(s in text for s in synonyms):\n key = canonical\n break\n if key is None:\n key = 'spec'\n result['value'] = key\n result['prompt'] = audit_map.get(key)\n result['agent'] = 'reviewer'\nelif domain == 'plan':\n result['value'] = text or ''\n result['prompt'] = None\nelif domain == 'workgroup_type':\n if not text:\n value = 'feat'\n else:\n value = None\n for key, mapped in workgroup_map.items():\n if text == key or key in text:\n value = mapped\n break\n if value is None:\n value = workgroup_map.get(text, 'feat')\n result['value'] = value\nelse:\n result['value'] = text or ''\noutputs.update(result)\n"
13
+ }
14
+ ]
15
+ }
@@ -1,12 +1,12 @@
1
- {
2
- "name": "architecture-diff",
3
- "version": "0.3.7",
4
- "description": "Highlights differences between specs and the Mermaid flowchart in knowzcode_architecture.md.",
5
- "parameters": [],
6
- "actions": [
7
- {
8
- "type": "python",
9
- "code": "from pathlib import Path\nimport re\narch = Path('knowzcode/knowzcode_architecture.md').read_text()\nspec_paths = list(Path('knowzcode/specs').glob('*.md'))\nnode_ids = {p.stem for p in spec_paths}\nmermaid_nodes = set(re.findall(r'([A-Z]{2,}_[A-Za-z0-9]+)', arch))\nmissing_in_arch = sorted(node_ids - mermaid_nodes)\nmissing_in_specs = sorted(mermaid_nodes - node_ids)\noutputs['missing_in_architecture'] = missing_in_arch\noutputs['missing_specs'] = missing_in_specs\n"
10
- }
11
- ]
12
- }
1
+ {
2
+ "name": "architecture-diff",
3
+ "version": "0.5.2",
4
+ "description": "Highlights differences between specs and the Mermaid flowchart in knowzcode_architecture.md.",
5
+ "parameters": [],
6
+ "actions": [
7
+ {
8
+ "type": "python",
9
+ "code": "from pathlib import Path\nimport re\narch = Path('knowzcode/knowzcode_architecture.md').read_text()\nspec_paths = list(Path('knowzcode/specs').glob('*.md'))\nnode_ids = {p.stem for p in spec_paths}\nmermaid_nodes = set(re.findall(r'([A-Z]{2,}_[A-Za-z0-9]+)', arch))\nmissing_in_arch = sorted(node_ids - mermaid_nodes)\nmissing_in_specs = sorted(mermaid_nodes - node_ids)\noutputs['missing_in_architecture'] = missing_in_arch\noutputs['missing_specs'] = missing_in_specs\n"
10
+ }
11
+ ]
12
+ }
@@ -1,14 +1,14 @@
1
- {
2
- "name": "check-installation-status",
3
- "version": "0.3.7",
4
- "description": "Checks if KnowzCode is initialized in the current project and reports current status",
5
-
6
- "parameters": [],
7
-
8
- "actions": [
9
- {
10
- "type": "python",
11
- "code": "from pathlib import Path\n\nknowzcode_dir = Path('knowzcode')\n\nif not knowzcode_dir.exists():\n outputs['initialized'] = False\n outputs['commands_count'] = 0\n outputs['skills_count'] = 0\n outputs['agents_count'] = 0\n outputs['has_required_files'] = False\n exit()\n\n# Check required files exist\nrequired_files = [\n 'knowzcode_loop.md',\n 'knowzcode_tracker.md',\n 'knowzcode_project.md',\n 'knowzcode_architecture.md'\n]\n\nmissing_files = [f for f in required_files if not (knowzcode_dir / f).exists()]\nhas_required_files = len(missing_files) == 0\n\n# Count components from various possible locations\n\n# Check .claude directory\nclaude_dir = Path('.claude')\ncommands_count = 0\nskills_count = 0\nagents_count = 0\n\nif claude_dir.exists():\n if (claude_dir / 'commands').exists():\n commands_count = len(list((claude_dir / 'commands').glob('*.md')))\n if (claude_dir / 'skills').exists():\n skills_count = len(list((claude_dir / 'skills').glob('*.json')))\n if (claude_dir / 'agents').exists():\n agents_count = len(list((claude_dir / 'agents').glob('*.md')))\n if (claude_dir / 'subagents').exists():\n agents_count += len(list((claude_dir / 'subagents').glob('*.yaml')))\n\n# Also check top-level directories (plugin installation)\nif Path('commands').exists():\n commands_count = max(commands_count, len(list(Path('commands').glob('*.md'))))\nif Path('skills').exists():\n skills_count = max(skills_count, len(list(Path('skills').glob('*.json'))))\nif Path('agents').exists():\n agents_count = max(agents_count, len(list(Path('agents').glob('*.md'))))\n\noutputs['initialized'] = has_required_files\noutputs['commands_count'] = commands_count\noutputs['skills_count'] = skills_count\noutputs['agents_count'] = agents_count\noutputs['has_required_files'] = has_required_files\noutputs['missing_files'] = missing_files if missing_files else None"
12
- }
13
- ]
14
- }
1
+ {
2
+ "name": "check-installation-status",
3
+ "version": "0.5.2",
4
+ "description": "Checks if KnowzCode is initialized in the current project and reports current status",
5
+
6
+ "parameters": [],
7
+
8
+ "actions": [
9
+ {
10
+ "type": "python",
11
+ "code": "from pathlib import Path\n\nknowzcode_dir = Path('knowzcode')\n\nif not knowzcode_dir.exists():\n outputs['initialized'] = False\n outputs['commands_count'] = 0\n outputs['skills_count'] = 0\n outputs['agents_count'] = 0\n outputs['has_required_files'] = False\n exit()\n\n# Check required files exist\nrequired_files = [\n 'knowzcode_loop.md',\n 'knowzcode_tracker.md',\n 'knowzcode_project.md',\n 'knowzcode_architecture.md'\n]\n\nmissing_files = [f for f in required_files if not (knowzcode_dir / f).exists()]\nhas_required_files = len(missing_files) == 0\n\n# Count components from various possible locations\n\n# Check .claude directory\nclaude_dir = Path('.claude')\ncommands_count = 0\nskills_count = 0\nagents_count = 0\n\nif claude_dir.exists():\n if (claude_dir / 'commands').exists():\n commands_count = len(list((claude_dir / 'commands').glob('*.md')))\n if (claude_dir / 'skills').exists():\n skills_count = len(list((claude_dir / 'skills').glob('*.json')))\n if (claude_dir / 'agents').exists():\n agents_count = len(list((claude_dir / 'agents').glob('*.md')))\n if (claude_dir / 'subagents').exists():\n agents_count += len(list((claude_dir / 'subagents').glob('*.yaml')))\n\n# Also check top-level directories (plugin installation)\nif Path('commands').exists():\n commands_count = max(commands_count, len(list(Path('commands').glob('*.md'))))\nif Path('skills').exists():\n skills_count = max(skills_count, len(list(Path('skills').glob('*.json'))))\nif Path('agents').exists():\n agents_count = max(agents_count, len(list(Path('agents').glob('*.md'))))\n\noutputs['initialized'] = has_required_files\noutputs['commands_count'] = commands_count\noutputs['skills_count'] = skills_count\noutputs['agents_count'] = agents_count\noutputs['has_required_files'] = has_required_files\noutputs['missing_files'] = missing_files if missing_files else None"
12
+ }
13
+ ]
14
+ }
@@ -1,12 +1,12 @@
1
- {
2
- "name": "environment-guard",
3
- "version": "0.3.7",
4
- "description": "Verifies that knowzcode/environment_context.md no longer contains placeholder brackets.",
5
- "parameters": [],
6
- "actions": [
7
- {
8
- "type": "python",
9
- "code": "from pathlib import Path\ntext = Path('knowzcode/environment_context.md').read_text()\nplaceholders = [line.strip() for line in text.splitlines() if '[' in line and ']' in line]\nif placeholders:\n raise ValueError('environment_context.md still contains placeholders: ' + ', '.join(placeholders[:5]))\n"
10
- }
11
- ]
12
- }
1
+ {
2
+ "name": "environment-guard",
3
+ "version": "0.5.2",
4
+ "description": "Verifies that knowzcode/environment_context.md no longer contains placeholder brackets.",
5
+ "parameters": [],
6
+ "actions": [
7
+ {
8
+ "type": "python",
9
+ "code": "from pathlib import Path\ntext = Path('knowzcode/environment_context.md').read_text()\nplaceholders = [line.strip() for line in text.splitlines() if '[' in line and ']' in line]\nif placeholders:\n raise ValueError('environment_context.md still contains placeholders: ' + ', '.join(placeholders[:5]))\n"
10
+ }
11
+ ]
12
+ }
@@ -1,25 +1,25 @@
1
- {
2
- "name": "generate-workgroup-id",
3
- "version": "0.3.7",
4
- "description": "Generates a WorkGroupID following the KnowzCode convention [type]-[slug]-YYYYMMDD-HHMMSS. The slug is a 2-4 word descriptor extracted from the goal.",
5
- "parameters": [
6
- {
7
- "name": "type",
8
- "type": "string",
9
- "required": true,
10
- "description": "One of feat, fix, refactor, issue"
11
- },
12
- {
13
- "name": "slug",
14
- "type": "string",
15
- "required": false,
16
- "description": "A 2-4 word kebab-case descriptor (e.g., 'auth-jwt', 'dark-mode'). If not provided, generates ID without slug."
17
- }
18
- ],
19
- "actions": [
20
- {
21
- "type": "python",
22
- "code": "import datetime\nimport re\nallowed = {'feat', 'fix', 'refactor', 'issue'}\nwg_type = inputs['type']\nif wg_type not in allowed:\n raise ValueError(f'Invalid type {wg_type!r}, expected one of {sorted(allowed)}')\ntimestamp = datetime.datetime.utcnow().strftime('%Y%m%d-%H%M%S')\nslug = inputs.get('slug', '')\nif slug:\n # Sanitize slug: lowercase, replace spaces with hyphens, remove non-alphanumeric\n slug = re.sub(r'[^a-z0-9-]', '', slug.lower().replace(' ', '-'))\n slug = re.sub(r'-+', '-', slug).strip('-')[:25] # Max 25 chars\n outputs['workgroup_id'] = f'{wg_type}-{slug}-{timestamp}'\nelse:\n outputs['workgroup_id'] = f'{wg_type}-{timestamp}'"
23
- }
24
- ]
25
- }
1
+ {
2
+ "name": "generate-workgroup-id",
3
+ "version": "0.5.2",
4
+ "description": "Generates a WorkGroupID following the KnowzCode convention [type]-[slug]-YYYYMMDD-HHMMSS. The slug is a 2-4 word descriptor extracted from the goal.",
5
+ "parameters": [
6
+ {
7
+ "name": "type",
8
+ "type": "string",
9
+ "required": true,
10
+ "description": "One of feat, fix, refactor, issue"
11
+ },
12
+ {
13
+ "name": "slug",
14
+ "type": "string",
15
+ "required": false,
16
+ "description": "A 2-4 word kebab-case descriptor (e.g., 'auth-jwt', 'dark-mode'). If not provided, generates ID without slug."
17
+ }
18
+ ],
19
+ "actions": [
20
+ {
21
+ "type": "python",
22
+ "code": "import datetime\nimport re\nallowed = {'feat', 'fix', 'refactor', 'issue'}\nwg_type = inputs['type']\nif wg_type not in allowed:\n raise ValueError(f'Invalid type {wg_type!r}, expected one of {sorted(allowed)}')\ntimestamp = datetime.datetime.utcnow().strftime('%Y%m%d-%H%M%S')\nslug = inputs.get('slug', '')\nif slug:\n # Sanitize slug: lowercase, replace spaces with hyphens, remove non-alphanumeric\n slug = re.sub(r'[^a-z0-9-]', '', slug.lower().replace(' ', '-'))\n slug = re.sub(r'-+', '-', slug).strip('-')[:25] # Max 25 chars\n outputs['workgroup_id'] = f'{wg_type}-{slug}-{timestamp}'\nelse:\n outputs['workgroup_id'] = f'{wg_type}-{timestamp}'"
23
+ }
24
+ ]
25
+ }
@@ -1,21 +1,21 @@
1
- {
2
- "name": "install-knowzcode",
3
- "version": "0.3.7",
4
- "description": "Initializes KnowzCode directory structure and required files in the current project",
5
-
6
- "parameters": [
7
- {
8
- "name": "force",
9
- "type": "boolean",
10
- "required": false,
11
- "description": "Force reinstall even if knowzcode/ exists"
12
- }
13
- ],
14
-
15
- "actions": [
16
- {
17
- "type": "python",
18
- "code": "import os\nimport json\nfrom pathlib import Path\nfrom datetime import datetime\n\n# Configuration\ntarget_dir = Path('knowzcode')\nforce = inputs.get('force', False)\n\n# Check if target exists\nif target_dir.exists() and not force:\n outputs['success'] = False\n outputs['error'] = 'knowzcode/ already exists. Use force=true to reinitialize'\n outputs['already_installed'] = True\n exit()\n\n# Create directory structure\ntarget_dir.mkdir(exist_ok=True)\n(target_dir / 'specs').mkdir(exist_ok=True)\n(target_dir / 'workgroups').mkdir(exist_ok=True)\n(target_dir / 'prompts').mkdir(exist_ok=True)\n(target_dir / 'planning').mkdir(exist_ok=True)\n\n# Create .gitignore if it doesn't exist\ngitignore_path = target_dir / '.gitignore'\nif not gitignore_path.exists():\n gitignore_content = '''# KnowzCode gitignore - protects environment-specific files\n\n# Environment-specific (contains local paths, commands)\nenvironment_context.md\n\n# Session-specific work (can be regenerated)\nworkgroups/\n\n# Personal notes and scratch files\n*.local.md\n.scratch/\n'''\n with open(gitignore_path, 'w') as f:\n f.write(gitignore_content)\n\n# Note: The actual template files (knowzcode_loop.md, etc.) should be copied\n# from the plugin template directory or created by the /kc:init command.\n# This skill creates the structure; the command copies the content.\n\noutputs['success'] = True\noutputs['target_dir'] = str(target_dir)\noutputs['directories_created'] = ['specs', 'workgroups', 'prompts', 'planning']\noutputs['gitignore_created'] = not gitignore_path.exists()\noutputs['message'] = f'KnowzCode directory structure created at {target_dir}/'"
19
- }
20
- ]
21
- }
1
+ {
2
+ "name": "install-knowzcode",
3
+ "version": "0.5.2",
4
+ "description": "Initializes KnowzCode directory structure and required files in the current project",
5
+
6
+ "parameters": [
7
+ {
8
+ "name": "force",
9
+ "type": "boolean",
10
+ "required": false,
11
+ "description": "Force reinstall even if knowzcode/ exists"
12
+ }
13
+ ],
14
+
15
+ "actions": [
16
+ {
17
+ "type": "python",
18
+ "code": "import os\nimport json\nfrom pathlib import Path\nfrom datetime import datetime\n\n# Configuration\ntarget_dir = Path('knowzcode')\nforce = inputs.get('force', False)\n\n# Check if target exists\nif target_dir.exists() and not force:\n outputs['success'] = False\n outputs['error'] = 'knowzcode/ already exists. Use force=true to reinitialize'\n outputs['already_installed'] = True\n exit()\n\n# Create directory structure\ntarget_dir.mkdir(exist_ok=True)\n(target_dir / 'specs').mkdir(exist_ok=True)\n(target_dir / 'workgroups').mkdir(exist_ok=True)\n(target_dir / 'prompts').mkdir(exist_ok=True)\n(target_dir / 'planning').mkdir(exist_ok=True)\n\n# Create .gitignore if it doesn't exist\ngitignore_path = target_dir / '.gitignore'\nif not gitignore_path.exists():\n gitignore_content = '''# KnowzCode gitignore - protects environment-specific files\n\n# Environment-specific (contains local paths, commands)\nenvironment_context.md\n\n# Session-specific work (can be regenerated)\nworkgroups/\n\n# Personal notes and scratch files\n*.local.md\n.scratch/\n'''\n with open(gitignore_path, 'w') as f:\n f.write(gitignore_content)\n\n# Note: The actual template files (knowzcode_loop.md, etc.) should be copied\n# from the plugin template directory or created by the /kc:init command.\n# This skill creates the structure; the command copies the content.\n\noutputs['success'] = True\noutputs['target_dir'] = str(target_dir)\noutputs['directories_created'] = ['specs', 'workgroups', 'prompts', 'planning']\noutputs['gitignore_created'] = not gitignore_path.exists()\noutputs['message'] = f'KnowzCode directory structure created at {target_dir}/'"
19
+ }
20
+ ]
21
+ }
@@ -1,18 +1,18 @@
1
- {
2
- "name": "load-core-context",
3
- "version": "0.3.7",
4
- "description": "Loads the KnowzCode project overview, architecture, tracker, log header, and automation manifest for downstream steps.",
5
- "parameters": [],
6
- "actions": [
7
- {
8
- "type": "read_file",
9
- "paths": [
10
- "knowzcode/knowzcode_project.md",
11
- "knowzcode/knowzcode_architecture.md",
12
- "knowzcode/knowzcode_tracker.md",
13
- "knowzcode/knowzcode_log.md",
14
- "knowzcode/automation_manifest.md"
15
- ]
16
- }
17
- ]
18
- }
1
+ {
2
+ "name": "load-core-context",
3
+ "version": "0.5.2",
4
+ "description": "Loads the KnowzCode project overview, architecture, tracker, log header, and automation manifest for downstream steps.",
5
+ "parameters": [],
6
+ "actions": [
7
+ {
8
+ "type": "read_file",
9
+ "paths": [
10
+ "knowzcode/knowzcode_project.md",
11
+ "knowzcode/knowzcode_architecture.md",
12
+ "knowzcode/knowzcode_tracker.md",
13
+ "knowzcode/knowzcode_log.md",
14
+ "knowzcode/automation_manifest.md"
15
+ ]
16
+ }
17
+ ]
18
+ }
@@ -1,15 +1,15 @@
1
- {
2
- "name": "log-entry-builder",
3
- "version": "0.3.7",
4
- "description": "Appends structured entries to knowzcode/knowzcode_log.md with KnowzCode formatting.",
5
- "parameters": [
6
- {"name": "entry_type", "type": "string", "required": true},
7
- {"name": "content", "type": "string", "required": true}
8
- ],
9
- "actions": [
10
- {
11
- "type": "python",
12
- "code": "from pathlib import Path\nentry_type = inputs['entry_type']\ncontent = inputs['content'].strip()\npath = Path('knowzcode/knowzcode_log.md')\ntext = path.read_text()\nmarker = '---\n**[NEWEST ENTRIES APPEAR HERE - DO NOT REMOVE THIS MARKER]**'\nidx = text.index(marker) + len(marker)\nnew_entry = f"\n---\n**Type:** {entry_type}\n{content}\n"\nupdated = text[:idx] + new_entry + text[idx:]\npath.write_text(updated)"
13
- }
14
- ]
15
- }
1
+ {
2
+ "name": "log-entry-builder",
3
+ "version": "0.5.2",
4
+ "description": "Appends structured entries to knowzcode/knowzcode_log.md with KnowzCode formatting.",
5
+ "parameters": [
6
+ {"name": "entry_type", "type": "string", "required": true},
7
+ {"name": "content", "type": "string", "required": true}
8
+ ],
9
+ "actions": [
10
+ {
11
+ "type": "python",
12
+ "code": "from pathlib import Path\nentry_type = inputs['entry_type']\ncontent = inputs['content'].strip()\npath = Path('knowzcode/knowzcode_log.md')\ntext = path.read_text()\nmarker = '---\n**[NEWEST ENTRIES APPEAR HERE - DO NOT REMOVE THIS MARKER]**'\nidx = text.index(marker) + len(marker)\nnew_entry = f"\n---\n**Type:** {entry_type}\n{content}\n"\nupdated = text[:idx] + new_entry + text[idx:]\npath.write_text(updated)"
13
+ }
14
+ ]
15
+ }
@@ -1,14 +1,14 @@
1
- {
2
- "name": "spec-quality-check",
3
- "version": "0.3.7",
4
- "description": "Validates KnowzCode spec files for mandatory sections. Supports new 4-section format and legacy numbered format.",
5
- "parameters": [
6
- {"name": "node_id", "type": "string", "required": true}
7
- ],
8
- "actions": [
9
- {
10
- "type": "python",
11
- "code": "from pathlib import Path\nimport re\nnode_id = inputs['node_id']\npath = Path('knowzcode/specs') / f'{node_id}.md'\nif not path.exists():\n raise FileNotFoundError(f'Spec for {node_id} not found')\ntext = path.read_text()\n\n# Check new format first\nnew_sections = ['## Rules & Decisions', '## Interfaces', '## Verification Criteria', '## Debt & Gaps']\nlegacy_sections = ['## 1. Purpose', '## 2. Dependencies & Triggers', '## 3. Interfaces', '## 4. Core Logic & Processing Steps', '## 5. Data Structures', '## 6. ARC Verification Criteria', '## 7. Technical Debt']\n\nnew_missing = [s for s in new_sections if s not in text]\nlegacy_missing = [s for s in legacy_sections if s not in text]\n\n# Use whichever format has fewer missing sections\nif len(new_missing) <= len(legacy_missing):\n outputs['format'] = 'v2'\n outputs['missing_sections'] = new_missing\nelse:\n outputs['format'] = 'legacy'\n outputs['missing_sections'] = legacy_missing\n outputs['deprecation_warning'] = 'Spec uses old numbered format. New specs should use: Rules & Decisions, Interfaces, Verification Criteria, Debt & Gaps'\n"
12
- }
13
- ]
14
- }
1
+ {
2
+ "name": "spec-quality-check",
3
+ "version": "0.5.2",
4
+ "description": "Validates KnowzCode spec files for mandatory sections. Supports new 4-section format and legacy numbered format.",
5
+ "parameters": [
6
+ {"name": "node_id", "type": "string", "required": true}
7
+ ],
8
+ "actions": [
9
+ {
10
+ "type": "python",
11
+ "code": "from pathlib import Path\nimport re\nnode_id = inputs['node_id']\npath = Path('knowzcode/specs') / f'{node_id}.md'\nif not path.exists():\n raise FileNotFoundError(f'Spec for {node_id} not found')\ntext = path.read_text()\n\n# Check new format first\nnew_sections = ['## Rules & Decisions', '## Interfaces', '## Verification Criteria', '## Debt & Gaps']\nlegacy_sections = ['## 1. Purpose', '## 2. Dependencies & Triggers', '## 3. Interfaces', '## 4. Core Logic & Processing Steps', '## 5. Data Structures', '## 6. ARC Verification Criteria', '## 7. Technical Debt']\n\nnew_missing = [s for s in new_sections if s not in text]\nlegacy_missing = [s for s in legacy_sections if s not in text]\n\n# Use whichever format has fewer missing sections\nif len(new_missing) <= len(legacy_missing):\n outputs['format'] = 'v2'\n outputs['missing_sections'] = new_missing\nelse:\n outputs['format'] = 'legacy'\n outputs['missing_sections'] = legacy_missing\n outputs['deprecation_warning'] = 'Spec uses old numbered format. New specs should use: Rules & Decisions, Interfaces, Verification Criteria, Debt & Gaps'\n"
12
+ }
13
+ ]
14
+ }
@@ -1,15 +1,15 @@
1
- {
2
- "name": "spec-template",
3
- "version": "0.3.7",
4
- "description": "Seeds or repairs KnowzCode spec files with the lean 4-section template.",
5
- "parameters": [
6
- {"name": "node_id", "type": "string", "required": true},
7
- {"name": "label", "type": "string", "required": true}
8
- ],
9
- "actions": [
10
- {
11
- "type": "python",
12
- "code": "from pathlib import Path\nfrom datetime import datetime\nnode_id = inputs['node_id']\nlabel = inputs['label']\npath = Path('knowzcode/specs') / f'{node_id}.md'\nnow = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%SZ')\ntemplate_lines = [\n f'# {node_id}: {label}',\n '',\n f'**Updated:** {now}',\n '**Status:** Draft',\n '',\n '## Rules & Decisions',\n '- [Key architectural decisions, business rules, constraints, and purpose]',\n '',\n '## Interfaces',\n '- [Public contracts: inputs, outputs, API signatures, dependencies, events]',\n '',\n '## Verification Criteria',\n '- VERIFY: [testable assertion 1]',\n '- VERIFY: [testable assertion 2]',\n '',\n '## Debt & Gaps',\n '- [Known limitations and future work, or \"None\"]',\n ''\n]\ntemplate = '\\n'.join(template_lines)\nif not path.exists():\n path.write_text(template + '\\n')\n outputs['created'] = True\nelse:\n text = path.read_text()\n new_sections = ['## Rules & Decisions', '## Interfaces', '## Verification Criteria', '## Debt & Gaps']\n if all(section in text for section in new_sections):\n outputs['created'] = False\n else:\n merged = text.strip() + '\\n\\n<!-- Template sections restored -->\\n' + template + '\\n'\n path.write_text(merged)\n outputs['created'] = False"
13
- }
14
- ]
15
- }
1
+ {
2
+ "name": "spec-template",
3
+ "version": "0.5.2",
4
+ "description": "Seeds or repairs KnowzCode spec files with the lean 4-section template.",
5
+ "parameters": [
6
+ {"name": "node_id", "type": "string", "required": true},
7
+ {"name": "label", "type": "string", "required": true}
8
+ ],
9
+ "actions": [
10
+ {
11
+ "type": "python",
12
+ "code": "from pathlib import Path\nfrom datetime import datetime\nnode_id = inputs['node_id']\nlabel = inputs['label']\npath = Path('knowzcode/specs') / f'{node_id}.md'\nnow = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%SZ')\ntemplate_lines = [\n f'# {node_id}: {label}',\n '',\n f'**Updated:** {now}',\n '**Status:** Draft',\n '',\n '## Rules & Decisions',\n '- [Key architectural decisions, business rules, constraints, and purpose]',\n '',\n '## Interfaces',\n '- [Public contracts: inputs, outputs, API signatures, dependencies, events]',\n '',\n '## Verification Criteria',\n '- VERIFY: [testable assertion 1]',\n '- VERIFY: [testable assertion 2]',\n '',\n '## Debt & Gaps',\n '- [Known limitations and future work, or \"None\"]',\n ''\n]\ntemplate = '\\n'.join(template_lines)\nif not path.exists():\n path.write_text(template + '\\n')\n outputs['created'] = True\nelse:\n text = path.read_text()\n new_sections = ['## Rules & Decisions', '## Interfaces', '## Verification Criteria', '## Debt & Gaps']\n if all(section in text for section in new_sections):\n outputs['created'] = False\n else:\n merged = text.strip() + '\\n\\n<!-- Template sections restored -->\\n' + template + '\\n'\n path.write_text(merged)\n outputs['created'] = False"
13
+ }
14
+ ]
15
+ }
@@ -1,25 +1,25 @@
1
- {
2
- "name": "spec-validator",
3
- "version": "0.3.7",
4
- "description": "Validates NodeID specification completeness and quality. Supports new 4-section format (preferred) and legacy numbered sections (deprecated).",
5
- "parameters": [
6
- {
7
- "name": "spec_path",
8
- "type": "string",
9
- "required": true,
10
- "description": "Absolute path to the spec file to validate"
11
- },
12
- {
13
- "name": "node_id",
14
- "type": "string",
15
- "required": true,
16
- "description": "NodeID being validated (for error reporting)"
17
- }
18
- ],
19
- "actions": [
20
- {
21
- "type": "python",
22
- "code": "from pathlib import Path\nimport re\n\nspec_path = Path(inputs['spec_path'])\nnode_id = inputs['node_id']\n\nif not spec_path.exists():\n outputs['valid'] = False\n outputs['errors'] = [f'Spec file does not exist: {spec_path}']\n outputs['warnings'] = []\n outputs['score'] = 0\n outputs['node_id'] = node_id\n outputs['format'] = 'missing'\n exit()\n\ncontent = spec_path.read_text()\n\nerrors = []\nwarnings = []\nscore = 100\n\n# Detect format: new 4-section or legacy numbered\nnew_sections = {\n 'rules': r'##\\s*Rules\\s*(&|and)\\s*Decisions',\n 'interfaces': r'##\\s*Interfaces',\n 'verification': r'##\\s*Verification\\s*Criteria',\n 'debt': r'##\\s*Debt\\s*(&|and)\\s*Gaps'\n}\nlegacy_sections = {\n 'purpose': r'##\\s*1\\.\\s*Purpose',\n 'deps': r'##\\s*2\\.\\s*Dependencies',\n 'interfaces': r'##\\s*3\\.\\s*Interfaces',\n 'logic': r'##\\s*4\\.\\s*Core\\s*Logic',\n 'arc': r'##\\s*(6\\.\\s*Error\\s*Handling|7\\.\\s*ARC\\s*Verification)'\n}\n\nnew_count = sum(1 for p in new_sections.values() if re.search(p, content, re.IGNORECASE))\nlegacy_count = sum(1 for p in legacy_sections.values() if re.search(p, content, re.IGNORECASE))\n\nif new_count >= legacy_count:\n spec_format = 'v2'\n # Validate new 4-section format\n required = [\n (new_sections['rules'], 'Missing \"Rules & Decisions\" section'),\n (new_sections['interfaces'], 'Missing \"Interfaces\" section'),\n (new_sections['verification'], 'Missing \"Verification Criteria\" section'),\n (new_sections['debt'], 'Missing \"Debt & Gaps\" section')\n ]\n for pattern, error_msg in required:\n if not re.search(pattern, content, re.IGNORECASE):\n errors.append(error_msg)\n score -= 15\n \n # Check VERIFY: statements (minimum 2)\n verify_section = re.search(r'##\\s*Verification\\s*Criteria(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if verify_section:\n verify_content = verify_section.group(1)\n verify_count = len(re.findall(r'VERIFY:', verify_content))\n if verify_count < 2:\n errors.append(f'Only {verify_count} VERIFY: statements found (minimum 2 required)')\n score -= 15\n else:\n errors.append('Verification Criteria section is empty or malformed')\n score -= 20\n \n # Check Rules has content\n rules_section = re.search(r'##\\s*Rules\\s*(&|and)\\s*Decisions(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if rules_section:\n rules_content = rules_section.group(2).strip()\n if len(rules_content) < 20 or re.search(r'^\\s*-\\s*\\[', rules_content):\n warnings.append('Rules & Decisions section appears to have only placeholder content')\n score -= 10\n \n # Check Interfaces has content\n iface_section = re.search(r'##\\s*Interfaces(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if iface_section:\n iface_content = iface_section.group(1).strip()\n if len(iface_content) < 20 or re.search(r'^\\s*-\\s*\\[', iface_content):\n warnings.append('Interfaces section appears to have only placeholder content')\n score -= 10\nelse:\n spec_format = 'legacy'\n warnings.append('DEPRECATED: Spec uses old numbered format. Will be migrated when next touched during finalization.')\n \n # Validate legacy format\n required = [\n (legacy_sections['purpose'], 'Missing \"1. Purpose\" section'),\n (legacy_sections['deps'], 'Missing \"2. Dependencies\" section'),\n (legacy_sections['interfaces'], 'Missing \"3. Interfaces\" section'),\n (legacy_sections['logic'], 'Missing \"4. Core Logic\" section'),\n (legacy_sections['arc'], 'Missing ARC/Error Handling section')\n ]\n for pattern, error_msg in required:\n if not re.search(pattern, content, re.IGNORECASE):\n errors.append(error_msg)\n score -= 15\n \n # Check ARC criteria (legacy format)\n arc_section = re.search(r'##\\s*7\\.\\s*ARC\\s*Verification\\s*Criteria(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if arc_section:\n arc_content = arc_section.group(1)\n criteria_count = len(re.findall(r'ARC_[A-Z]+_\\d+:', arc_content))\n if criteria_count < 3:\n errors.append(f'Only {criteria_count} testable ARC criteria found (minimum 3 required)')\n score -= 15\n else:\n errors.append('ARC Verification Criteria section is empty or malformed')\n score -= 20\n\n# Check for placeholder text (both formats)\nplaceholder_patterns = [\n (r'\\[Agent:', 'Contains [Agent: placeholder'),\n (r'\\[TODO', 'Contains [TODO] placeholder'),\n (r'\\[FILL', 'Contains [FILL] placeholder'),\n (r'\\[TBD\\]', 'Contains [TBD] placeholder'),\n (r'\\[INSERT', 'Contains [INSERT] placeholder')\n]\nfor pattern, msg in placeholder_patterns:\n if re.search(pattern, content, re.IGNORECASE):\n errors.append(msg)\n score -= 20\n break\n\n# Calculate final validation\noutputs['valid'] = (score >= 70 and len(errors) == 0)\noutputs['score'] = max(0, score)\noutputs['errors'] = errors\noutputs['warnings'] = warnings\noutputs['node_id'] = node_id\noutputs['spec_path'] = str(spec_path)\noutputs['format'] = spec_format"
23
- }
24
- ]
25
- }
1
+ {
2
+ "name": "spec-validator",
3
+ "version": "0.5.2",
4
+ "description": "Validates NodeID specification completeness and quality. Supports new 4-section format (preferred) and legacy numbered sections (deprecated).",
5
+ "parameters": [
6
+ {
7
+ "name": "spec_path",
8
+ "type": "string",
9
+ "required": true,
10
+ "description": "Absolute path to the spec file to validate"
11
+ },
12
+ {
13
+ "name": "node_id",
14
+ "type": "string",
15
+ "required": true,
16
+ "description": "NodeID being validated (for error reporting)"
17
+ }
18
+ ],
19
+ "actions": [
20
+ {
21
+ "type": "python",
22
+ "code": "from pathlib import Path\nimport re\n\nspec_path = Path(inputs['spec_path'])\nnode_id = inputs['node_id']\n\nif not spec_path.exists():\n outputs['valid'] = False\n outputs['errors'] = [f'Spec file does not exist: {spec_path}']\n outputs['warnings'] = []\n outputs['score'] = 0\n outputs['node_id'] = node_id\n outputs['format'] = 'missing'\n exit()\n\ncontent = spec_path.read_text()\n\nerrors = []\nwarnings = []\nscore = 100\n\n# Detect format: new 4-section or legacy numbered\nnew_sections = {\n 'rules': r'##\\s*Rules\\s*(&|and)\\s*Decisions',\n 'interfaces': r'##\\s*Interfaces',\n 'verification': r'##\\s*Verification\\s*Criteria',\n 'debt': r'##\\s*Debt\\s*(&|and)\\s*Gaps'\n}\nlegacy_sections = {\n 'purpose': r'##\\s*1\\.\\s*Purpose',\n 'deps': r'##\\s*2\\.\\s*Dependencies',\n 'interfaces': r'##\\s*3\\.\\s*Interfaces',\n 'logic': r'##\\s*4\\.\\s*Core\\s*Logic',\n 'arc': r'##\\s*(6\\.\\s*Error\\s*Handling|7\\.\\s*ARC\\s*Verification)'\n}\n\nnew_count = sum(1 for p in new_sections.values() if re.search(p, content, re.IGNORECASE))\nlegacy_count = sum(1 for p in legacy_sections.values() if re.search(p, content, re.IGNORECASE))\n\nif new_count >= legacy_count:\n spec_format = 'v2'\n # Validate new 4-section format\n required = [\n (new_sections['rules'], 'Missing \"Rules & Decisions\" section'),\n (new_sections['interfaces'], 'Missing \"Interfaces\" section'),\n (new_sections['verification'], 'Missing \"Verification Criteria\" section'),\n (new_sections['debt'], 'Missing \"Debt & Gaps\" section')\n ]\n for pattern, error_msg in required:\n if not re.search(pattern, content, re.IGNORECASE):\n errors.append(error_msg)\n score -= 15\n \n # Check VERIFY: statements (minimum 2)\n verify_section = re.search(r'##\\s*Verification\\s*Criteria(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if verify_section:\n verify_content = verify_section.group(1)\n verify_count = len(re.findall(r'VERIFY:', verify_content))\n if verify_count < 2:\n errors.append(f'Only {verify_count} VERIFY: statements found (minimum 2 required)')\n score -= 15\n else:\n errors.append('Verification Criteria section is empty or malformed')\n score -= 20\n \n # Check Rules has content\n rules_section = re.search(r'##\\s*Rules\\s*(&|and)\\s*Decisions(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if rules_section:\n rules_content = rules_section.group(2).strip()\n if len(rules_content) < 20 or re.search(r'^\\s*-\\s*\\[', rules_content):\n warnings.append('Rules & Decisions section appears to have only placeholder content')\n score -= 10\n \n # Check Interfaces has content\n iface_section = re.search(r'##\\s*Interfaces(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if iface_section:\n iface_content = iface_section.group(1).strip()\n if len(iface_content) < 20 or re.search(r'^\\s*-\\s*\\[', iface_content):\n warnings.append('Interfaces section appears to have only placeholder content')\n score -= 10\nelse:\n spec_format = 'legacy'\n warnings.append('DEPRECATED: Spec uses old numbered format. Will be migrated when next touched during finalization.')\n \n # Validate legacy format\n required = [\n (legacy_sections['purpose'], 'Missing \"1. Purpose\" section'),\n (legacy_sections['deps'], 'Missing \"2. Dependencies\" section'),\n (legacy_sections['interfaces'], 'Missing \"3. Interfaces\" section'),\n (legacy_sections['logic'], 'Missing \"4. Core Logic\" section'),\n (legacy_sections['arc'], 'Missing ARC/Error Handling section')\n ]\n for pattern, error_msg in required:\n if not re.search(pattern, content, re.IGNORECASE):\n errors.append(error_msg)\n score -= 15\n \n # Check ARC criteria (legacy format)\n arc_section = re.search(r'##\\s*7\\.\\s*ARC\\s*Verification\\s*Criteria(.+?)(?=##|$)', content, re.DOTALL | re.IGNORECASE)\n if arc_section:\n arc_content = arc_section.group(1)\n criteria_count = len(re.findall(r'ARC_[A-Z]+_\\d+:', arc_content))\n if criteria_count < 3:\n errors.append(f'Only {criteria_count} testable ARC criteria found (minimum 3 required)')\n score -= 15\n else:\n errors.append('ARC Verification Criteria section is empty or malformed')\n score -= 20\n\n# Check for placeholder text (both formats)\nplaceholder_patterns = [\n (r'\\[Agent:', 'Contains [Agent: placeholder'),\n (r'\\[TODO', 'Contains [TODO] placeholder'),\n (r'\\[FILL', 'Contains [FILL] placeholder'),\n (r'\\[TBD\\]', 'Contains [TBD] placeholder'),\n (r'\\[INSERT', 'Contains [INSERT] placeholder')\n]\nfor pattern, msg in placeholder_patterns:\n if re.search(pattern, content, re.IGNORECASE):\n errors.append(msg)\n score -= 20\n break\n\n# Calculate final validation\noutputs['valid'] = (score >= 70 and len(errors) == 0)\noutputs['score'] = max(0, score)\noutputs['errors'] = errors\noutputs['warnings'] = warnings\noutputs['node_id'] = node_id\noutputs['spec_path'] = str(spec_path)\noutputs['format'] = spec_format"
23
+ }
24
+ ]
25
+ }
@@ -1,12 +1,12 @@
1
- {
2
- "name": "tracker-scan",
3
- "version": "0.3.7",
4
- "description": "Extracts NodeID statuses and WorkGroup assignments from the KnowzCode tracker.",
5
- "parameters": [],
6
- "actions": [
7
- {
8
- "type": "python",
9
- "code": "from pathlib import Path\ntext = Path('knowzcode/knowzcode_tracker.md').read_text()\nrows = []\nfor line in text.splitlines():\n if line.startswith('|') and '`' in line:\n cols = [c.strip() for c in line.strip('|').split('|')]\n if len(cols) >= 9 and cols[2] != 'Node ID':\n rows.append({'status': cols[0], 'workgroup_id': cols[1], 'node_id': cols[2].strip('`'), 'notes': cols[8]})\noutputs['rows'] = rows\n"
10
- }
11
- ]
12
- }
1
+ {
2
+ "name": "tracker-scan",
3
+ "version": "0.5.2",
4
+ "description": "Extracts NodeID statuses and WorkGroup assignments from the KnowzCode tracker.",
5
+ "parameters": [],
6
+ "actions": [
7
+ {
8
+ "type": "python",
9
+ "code": "from pathlib import Path\ntext = Path('knowzcode/knowzcode_tracker.md').read_text()\nrows = []\nfor line in text.splitlines():\n if line.startswith('|') and '`' in line:\n cols = [c.strip() for c in line.strip('|').split('|')]\n if len(cols) >= 9 and cols[2] != 'Node ID':\n rows.append({'status': cols[0], 'workgroup_id': cols[1], 'node_id': cols[2].strip('`'), 'notes': cols[8]})\noutputs['rows'] = rows\n"
10
+ }
11
+ ]
12
+ }
@@ -1,28 +1,28 @@
1
- {
2
- "name": "tracker-update",
3
- "version": "0.3.7",
4
- "description": "Applies validated updates to knowzcode/knowzcode_tracker.md while preserving table structure.",
5
- "parameters": [
6
- {
7
- "name": "updates",
8
- "type": "array",
9
- "items": {
10
- "type": "object",
11
- "properties": {
12
- "node_id": {"type": "string"},
13
- "status": {"type": "string"},
14
- "workgroup_id": {"type": "string"},
15
- "notes": {"type": "string"}
16
- },
17
- "required": ["node_id"]
18
- },
19
- "required": true
20
- }
21
- ],
22
- "actions": [
23
- {
24
- "type": "python",
25
- "code": "from pathlib import Path\npath = Path('knowzcode/knowzcode_tracker.md')\ntext = path.read_text()\nlines = text.splitlines()\nheader_idx = next(i for i, line in enumerate(lines) if line.startswith('| Status |'))\ntable = lines[header_idx:]\nrows = [line for line in table if line.startswith('|')]\nupdates = {u['node_id']: u for u in inputs['updates']}\nnew_rows = []\nfor row in rows:\n parts = [p.strip() for p in row.strip('|').split('|')]\n if not parts or parts[2] == 'Node ID':\n new_rows.append(row)\n continue\n node_id = parts[2].strip('`')\n if node_id in updates:\n upd = updates[node_id]\n status = upd.get('status', parts[0].strip())\n workgroup = upd.get('workgroup_id', parts[1].strip())\n notes = upd.get('notes', parts[8].strip())\n new_row = f\"| {status} | {workgroup} | `{node_id}` | {parts[3]} | {parts[4]} | {parts[5]} | {parts[6]} | {parts[7]} | {notes} |\"\n new_rows.append(new_row)\n updates.pop(node_id)\n else:\n new_rows.append(row)\nif updates:\n missing = ', '.join(sorted(updates.keys()))\n raise ValueError(f\"NodeIDs {missing} not found in tracker table\")\nlines[header_idx:] = new_rows + lines[header_idx + len(rows):]\npath.write_text('\\n'.join(lines) + '\\n')"
26
- }
27
- ]
28
- }
1
+ {
2
+ "name": "tracker-update",
3
+ "version": "0.5.2",
4
+ "description": "Applies validated updates to knowzcode/knowzcode_tracker.md while preserving table structure.",
5
+ "parameters": [
6
+ {
7
+ "name": "updates",
8
+ "type": "array",
9
+ "items": {
10
+ "type": "object",
11
+ "properties": {
12
+ "node_id": {"type": "string"},
13
+ "status": {"type": "string"},
14
+ "workgroup_id": {"type": "string"},
15
+ "notes": {"type": "string"}
16
+ },
17
+ "required": ["node_id"]
18
+ },
19
+ "required": true
20
+ }
21
+ ],
22
+ "actions": [
23
+ {
24
+ "type": "python",
25
+ "code": "from pathlib import Path\npath = Path('knowzcode/knowzcode_tracker.md')\ntext = path.read_text()\nlines = text.splitlines()\nheader_idx = next(i for i, line in enumerate(lines) if line.startswith('| Status |'))\ntable = lines[header_idx:]\nrows = [line for line in table if line.startswith('|')]\nupdates = {u['node_id']: u for u in inputs['updates']}\nnew_rows = []\nfor row in rows:\n parts = [p.strip() for p in row.strip('|').split('|')]\n if not parts or parts[2] == 'Node ID':\n new_rows.append(row)\n continue\n node_id = parts[2].strip('`')\n if node_id in updates:\n upd = updates[node_id]\n status = upd.get('status', parts[0].strip())\n workgroup = upd.get('workgroup_id', parts[1].strip())\n notes = upd.get('notes', parts[8].strip())\n new_row = f\"| {status} | {workgroup} | `{node_id}` | {parts[3]} | {parts[4]} | {parts[5]} | {parts[6]} | {parts[7]} | {notes} |\"\n new_rows.append(new_row)\n updates.pop(node_id)\n else:\n new_rows.append(row)\nif updates:\n missing = ', '.join(sorted(updates.keys()))\n raise ValueError(f\"NodeIDs {missing} not found in tracker table\")\nlines[header_idx:] = new_rows + lines[header_idx + len(rows):]\npath.write_text('\\n'.join(lines) + '\\n')"
26
+ }
27
+ ]
28
+ }
@@ -1,14 +1,14 @@
1
- {
2
- "name": "validate-installation",
3
- "version": "0.3.7",
4
- "description": "Validates that KnowzCode installation completed successfully with required directories and files",
5
-
6
- "parameters": [],
7
-
8
- "actions": [
9
- {
10
- "type": "python",
11
- "code": "from pathlib import Path\nimport json\n\n# Check for knowzcode directory (the primary installation target)\nknowzcode_dir = Path('knowzcode')\nerrors = []\nwarnings = []\n\n# Check directory exists\nif not knowzcode_dir.exists():\n errors.append('knowzcode/ directory not found')\n outputs['valid'] = False\n outputs['errors'] = errors\n outputs['warnings'] = warnings\n outputs['commands_count'] = 0\n outputs['skills_count'] = 0\n outputs['agents_count'] = 0\n exit()\n\n# Check required knowzcode files\nrequired_files = [\n 'knowzcode_loop.md',\n 'knowzcode_tracker.md',\n 'knowzcode_project.md',\n 'knowzcode_architecture.md'\n]\n\nfor required_file in required_files:\n if not (knowzcode_dir / required_file).exists():\n errors.append(f'Missing required file: knowzcode/{required_file}')\n\n# Check required subdirectories\nrequired_dirs = [\n 'specs',\n 'workgroups',\n 'prompts'\n]\n\nfor subdir in required_dirs:\n if not (knowzcode_dir / subdir).exists():\n warnings.append(f'Missing directory: knowzcode/{subdir}')\n\n# Check .claude directory for commands/agents (plugin or local installation)\nclaude_dir = Path('.claude')\ncommands_count = 0\nskills_count = 0\nagents_count = 0\n\nif claude_dir.exists():\n if (claude_dir / 'commands').exists():\n commands_count = len(list((claude_dir / 'commands').glob('*.md')))\n if (claude_dir / 'skills').exists():\n skills_count = len(list((claude_dir / 'skills').glob('*.json')))\n if (claude_dir / 'agents').exists():\n agents_count = len(list((claude_dir / 'agents').glob('*.md')))\n if (claude_dir / 'subagents').exists():\n agents_count += len(list((claude_dir / 'subagents').glob('*.yaml')))\n\n# Also check top-level commands/skills/agents (plugin installation)\nif Path('commands').exists():\n commands_count = max(commands_count, len(list(Path('commands').glob('*.md'))))\nif Path('skills').exists():\n skills_count = max(skills_count, len(list(Path('skills').glob('*.json'))))\nif Path('agents').exists():\n agents_count = max(agents_count, len(list(Path('agents').glob('*.md'))))\n\n# Expected minimums\nif commands_count < 5:\n warnings.append(f'Expected at least 5 commands, found {commands_count}')\nif agents_count < 10:\n warnings.append(f'Expected at least 10 agents, found {agents_count}')\n\noutputs['valid'] = len(errors) == 0\noutputs['errors'] = errors\noutputs['warnings'] = warnings\noutputs['commands_count'] = commands_count\noutputs['skills_count'] = skills_count\noutputs['agents_count'] = agents_count"
12
- }
13
- ]
14
- }
1
+ {
2
+ "name": "validate-installation",
3
+ "version": "0.5.2",
4
+ "description": "Validates that KnowzCode installation completed successfully with required directories and files",
5
+
6
+ "parameters": [],
7
+
8
+ "actions": [
9
+ {
10
+ "type": "python",
11
+ "code": "from pathlib import Path\nimport json\n\n# Check for knowzcode directory (the primary installation target)\nknowzcode_dir = Path('knowzcode')\nerrors = []\nwarnings = []\n\n# Check directory exists\nif not knowzcode_dir.exists():\n errors.append('knowzcode/ directory not found')\n outputs['valid'] = False\n outputs['errors'] = errors\n outputs['warnings'] = warnings\n outputs['commands_count'] = 0\n outputs['skills_count'] = 0\n outputs['agents_count'] = 0\n exit()\n\n# Check required knowzcode files\nrequired_files = [\n 'knowzcode_loop.md',\n 'knowzcode_tracker.md',\n 'knowzcode_project.md',\n 'knowzcode_architecture.md'\n]\n\nfor required_file in required_files:\n if not (knowzcode_dir / required_file).exists():\n errors.append(f'Missing required file: knowzcode/{required_file}')\n\n# Check required subdirectories\nrequired_dirs = [\n 'specs',\n 'workgroups',\n 'prompts'\n]\n\nfor subdir in required_dirs:\n if not (knowzcode_dir / subdir).exists():\n warnings.append(f'Missing directory: knowzcode/{subdir}')\n\n# Check .claude directory for commands/agents (plugin or local installation)\nclaude_dir = Path('.claude')\ncommands_count = 0\nskills_count = 0\nagents_count = 0\n\nif claude_dir.exists():\n if (claude_dir / 'commands').exists():\n commands_count = len(list((claude_dir / 'commands').glob('*.md')))\n if (claude_dir / 'skills').exists():\n skills_count = len(list((claude_dir / 'skills').glob('*.json')))\n if (claude_dir / 'agents').exists():\n agents_count = len(list((claude_dir / 'agents').glob('*.md')))\n if (claude_dir / 'subagents').exists():\n agents_count += len(list((claude_dir / 'subagents').glob('*.yaml')))\n\n# Also check top-level commands/skills/agents (plugin installation)\nif Path('commands').exists():\n commands_count = max(commands_count, len(list(Path('commands').glob('*.md'))))\nif Path('skills').exists():\n skills_count = max(skills_count, len(list(Path('skills').glob('*.json'))))\nif Path('agents').exists():\n agents_count = max(agents_count, len(list(Path('agents').glob('*.md'))))\n\n# Expected minimums\nif commands_count < 5:\n warnings.append(f'Expected at least 5 commands, found {commands_count}')\nif agents_count < 10:\n warnings.append(f'Expected at least 10 agents, found {agents_count}')\n\noutputs['valid'] = len(errors) == 0\noutputs['errors'] = errors\noutputs['warnings'] = warnings\noutputs['commands_count'] = commands_count\noutputs['skills_count'] = skills_count\noutputs['agents_count'] = agents_count"
12
+ }
13
+ ]
14
+ }