1 #![forbid(unsafe_code)]2 //! f0rge --skill / skill: the contract, from spec/schema.md only.3 use crate::CliError;4 5 pub fn help() -> &'static str {6 "f0rge skill: contract\nusage: f0rge [--skill|skill]\nprints schema v1 contract\ndocs: spec/schema.md §Skill\ncontract: f0rge --skill\n"7 }8 9 /// Contract text: <=30 lines, <=1000 bytes. Schema v1 decisions only.10 /// SKILL_TEXT is the single source of truth; skill/skill.md body must equal it.11 pub const SKILL_TEXT: &str = "f0rge v1: CONTRACT (not help)\n\12 id: uuid4 lowercase dashes; never changes\n\13 number: rank (created,uuid); derived never stored\n\14 files: one file per entity; command tree mirrors folder tree\n\15 tree: issue<->issues/ pr<->prs/ task<->tasks/ ci<->ci/ wiki<->wiki/\n\16 frontmatter: strict --- fences; unknown field warning; missing required error\n\17 git: .forge/ committed with repo; PR=git branch from worktree\n\18 ci: steps are scripts; run in filename order; first nonzero exit code=fail; pass|fail|running|cancelled\n\19 merge: CI-gates patch in scratch worktree; never touches main/branches; prints conflicts, never resolves; you integrate (ff) + delete branch\n\20 never delete: close/archive only; archive to .forge/archive/\n\21 wiki: files under wiki/; edit in place/stdin\n\22 spec: spec/schema.md frozen truth; labels.md/milestones.md registries\n\23 usage: f0rge <cmd> [--json] [args]; init makes .forge/ idempotent; --jq via jq; never parse prose\n\24 json: compact fixed order; empty []/{}\n\25 install: f0rge release install [ver|main]\n";26 27 /// No sub-verbs (#36). Stub for API uniformity.28 #[allow(dead_code)]29 pub fn verb_help(_verb: &str) -> Option<&'static str> {30 None31 }32 33 pub fn run(args: &[String], _fg: &f0rge_core::Forge) -> Result<(), CliError> {34 for a in args {35 if a == "-h" || a == "--help" {36 crate::output::out(help());37 return Ok(());38 }39 if a.starts_with('-') {40 return Err(CliError::Usage(format!("unknown flag: {a} (try: f0rge skill -h)")));41 }42 }43 if !args.is_empty() {44 return Err(CliError::Usage("skill takes no args (try: f0rge skill -h)".to_string()));45 }46 crate::output::out(SKILL_TEXT);47 Ok(())48 }