@dannylee1020/kkt 0.5.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.
Files changed (50) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +275 -0
  3. package/assets/kkt-readme-modern.png +0 -0
  4. package/bin/kkt-install.mjs +25 -0
  5. package/cmd/kkt/main.go +15 -0
  6. package/go.mod +3 -0
  7. package/internal/workflow/cli.go +349 -0
  8. package/internal/workflow/cli_test.go +1266 -0
  9. package/internal/workflow/guardrails.go +900 -0
  10. package/internal/workflow/init.go +164 -0
  11. package/internal/workflow/init_test.go +113 -0
  12. package/internal/workflow/operations.go +1855 -0
  13. package/internal/workflow/validation_commands.go +291 -0
  14. package/internal/workflow/workspace.go +802 -0
  15. package/internal/workflow/workspace_test.go +285 -0
  16. package/package.json +45 -0
  17. package/scripts/install-cli.sh +210 -0
  18. package/scripts/install.sh +644 -0
  19. package/skills/kkt/SKILL.md +74 -0
  20. package/skills/kkt/references/discovery-tooling.md +53 -0
  21. package/skills/kkt/references/feature-optimization-model.md +120 -0
  22. package/skills/kkt/references/kkt-kernel.md +58 -0
  23. package/skills/kkt/references/layered-modeling-methods.md +101 -0
  24. package/skills/kkt/references/plan-assimilation.md +46 -0
  25. package/skills/kkt/references/schemas.md +231 -0
  26. package/skills/kkt/references/state-contract.md +76 -0
  27. package/skills/kkt-loop/SKILL.md +99 -0
  28. package/skills/kkt-loop/references/discovery-tooling.md +53 -0
  29. package/skills/kkt-loop/references/feature-optimization-model.md +120 -0
  30. package/skills/kkt-loop/references/kkt-kernel.md +58 -0
  31. package/skills/kkt-loop/references/layered-modeling-methods.md +101 -0
  32. package/skills/kkt-loop/references/plan-assimilation.md +46 -0
  33. package/skills/kkt-loop/references/schemas.md +231 -0
  34. package/skills/kkt-loop/references/state-contract.md +76 -0
  35. package/skills/kkt-model/SKILL.md +76 -0
  36. package/skills/kkt-model/references/discovery-tooling.md +53 -0
  37. package/skills/kkt-model/references/feature-optimization-model.md +120 -0
  38. package/skills/kkt-model/references/kkt-kernel.md +58 -0
  39. package/skills/kkt-model/references/layered-modeling-methods.md +101 -0
  40. package/skills/kkt-model/references/plan-assimilation.md +46 -0
  41. package/skills/kkt-model/references/schemas.md +231 -0
  42. package/skills/kkt-model/references/state-contract.md +76 -0
  43. package/skills/kkt-run/SKILL.md +62 -0
  44. package/skills/kkt-run/references/discovery-tooling.md +53 -0
  45. package/skills/kkt-run/references/feature-optimization-model.md +120 -0
  46. package/skills/kkt-run/references/kkt-kernel.md +58 -0
  47. package/skills/kkt-run/references/layered-modeling-methods.md +101 -0
  48. package/skills/kkt-run/references/plan-assimilation.md +46 -0
  49. package/skills/kkt-run/references/schemas.md +231 -0
  50. package/skills/kkt-run/references/state-contract.md +76 -0
@@ -0,0 +1,349 @@
1
+ package workflow
2
+
3
+ import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+ "os"
8
+ "strings"
9
+ "time"
10
+ )
11
+
12
+ var Version = "dev"
13
+
14
+ const usageText = `KKT Workflow CLI
15
+
16
+ Usage:
17
+ kkt --version
18
+ kkt start plan|model|run|loop <request>
19
+ kkt status [--json] [path]
20
+ kkt next [--json] [path]
21
+ kkt show [artifact]
22
+ kkt intent|discovery|model [--method method] [content]
23
+ kkt plan|progress [content]
24
+ kkt evidence [--for criterion] [--command command] [content]
25
+ kkt notes [content]
26
+ kkt guardrails show|set|validate [content]
27
+ kkt judge --checkpoint checkpoint [--json] [path]
28
+ kkt run from-model [model-workspace]
29
+ kkt approve [scope]
30
+ kkt criteria [add|satisfy|block] [criterion]
31
+ kkt task [add|start|done|skip|block] [task]
32
+ kkt block [reason]
33
+ kkt validate [--run] [--timeout duration] [path]
34
+ kkt done [summary]
35
+ kkt resume [path]
36
+ kkt replay --check [path]
37
+ kkt uninstall [codex|claude|opencode|pi|all]
38
+
39
+ KKT skills own the workflow. This CLI handles deterministic .kkt state
40
+ scaffolding, workflow state, artifacts, evidence, validation, and cleanup.
41
+ `
42
+
43
+ func Run(args []string, stdout, stderr io.Writer) error {
44
+ if len(args) == 0 || args[0] == "help" || args[0] == "--help" {
45
+ fmt.Fprint(stdout, usageText)
46
+ return nil
47
+ }
48
+ if args[0] == "--version" {
49
+ fmt.Fprintf(stdout, "kkt %s\n", Version)
50
+ return nil
51
+ }
52
+
53
+ switch args[0] {
54
+ case "start":
55
+ return runStart(args[1:], stdout)
56
+ case "status":
57
+ return runStatus(args[1:], stdout)
58
+ case "next":
59
+ return runNext(args[1:], stdout)
60
+ case "show":
61
+ return runShow(args[1:], stdout)
62
+ case "intent", "discovery", "model", "plan", "progress", "evidence", "notes":
63
+ return runArtifact(args[0], args[1:], stdout)
64
+ case "guardrails":
65
+ return runGuardrails(args[1:], stdout)
66
+ case "judge":
67
+ return runJudge(args[1:], stdout)
68
+ case "run":
69
+ return runRun(args[1:], stdout)
70
+ case "approve":
71
+ return runApprove(args[1:], stdout)
72
+ case "criteria":
73
+ return runCriteria(args[1:], stdout)
74
+ case "task":
75
+ return runTask(args[1:], stdout)
76
+ case "block":
77
+ return runBlock(args[1:], stdout)
78
+ case "validate":
79
+ return runValidate(args[1:], stdout)
80
+ case "done":
81
+ return runDone(args[1:], stdout)
82
+ case "resume":
83
+ return runResume(args[1:], stdout)
84
+ case "replay":
85
+ return runReplay(args[1:], stdout)
86
+ case "uninstall":
87
+ return runUninstall(args[1:], stdout)
88
+ default:
89
+ return fmt.Errorf("unsupported command %q\n\n%s", args[0], usageText)
90
+ }
91
+ }
92
+
93
+ func runUninstall(args []string, stdout io.Writer) error {
94
+ if err := rejectFlags("uninstall", args); err != nil {
95
+ return err
96
+ }
97
+ if len(args) > 1 {
98
+ return errors.New("uninstall accepts at most one agent: codex, claude, opencode, pi, or all")
99
+ }
100
+ agent := strings.TrimSpace(firstArg(args))
101
+ if agent == "" {
102
+ agent = "all"
103
+ }
104
+
105
+ plans, err := UninstallPlans(agent)
106
+ if err != nil {
107
+ return err
108
+ }
109
+ for _, plan := range plans {
110
+ fmt.Fprintf(stdout, "target: %s\n", plan.Agent)
111
+ fmt.Fprintf(stdout, "file: %s\n", plan.Path)
112
+ changed, err := RemoveInstruction(plan.Path)
113
+ if err != nil {
114
+ return err
115
+ }
116
+ if changed {
117
+ fmt.Fprintln(stdout, "removed")
118
+ } else {
119
+ fmt.Fprintln(stdout, "already current")
120
+ }
121
+ }
122
+
123
+ executable, err := os.Executable()
124
+ if err != nil {
125
+ return err
126
+ }
127
+ fmt.Fprintf(stdout, "binary: %s\n", executable)
128
+ if err := os.Remove(executable); err != nil {
129
+ if os.IsNotExist(err) {
130
+ fmt.Fprintln(stdout, "already current")
131
+ return nil
132
+ }
133
+ return err
134
+ }
135
+ fmt.Fprintln(stdout, "removed")
136
+ return nil
137
+ }
138
+
139
+ func runStart(args []string, stdout io.Writer) error {
140
+ if err := rejectFlags("start", args); err != nil {
141
+ return err
142
+ }
143
+ if len(args) < 2 {
144
+ return errors.New("start requires a profile and request: plan, model, run, or loop")
145
+ }
146
+ selectedProfile := strings.TrimSpace(args[0])
147
+ request := strings.TrimSpace(strings.Join(args[1:], " "))
148
+ if request == "" {
149
+ return errors.New("start requires a request")
150
+ }
151
+
152
+ workspace, err := StartWorkflow(".", request, selectedProfile)
153
+ if err != nil {
154
+ return err
155
+ }
156
+
157
+ fmt.Fprintf(stdout, "created: %s\n", workspace.Path)
158
+ fmt.Fprintf(stdout, "profile: %s\n", workspace.Profile)
159
+ fmt.Fprintf(stdout, "next: %s\n", startInstruction(workspace.Profile))
160
+ return nil
161
+ }
162
+
163
+ func runStatus(args []string, stdout io.Writer) error {
164
+ jsonOutput, path, err := parseJSONPathArgs("status", args)
165
+ if err != nil {
166
+ return err
167
+ }
168
+ workspace, err := ResolveWorkspace(".", path)
169
+ if err != nil {
170
+ return err
171
+ }
172
+ state, err := ReadState(workspace)
173
+ if err != nil {
174
+ return err
175
+ }
176
+ report, err := statusReport(workspace, state)
177
+ if err != nil {
178
+ return err
179
+ }
180
+ if jsonOutput {
181
+ return writeJSON(stdout, report)
182
+ }
183
+ fmt.Fprintf(stdout, "workspace: %s\n", workspace)
184
+ fmt.Fprintf(stdout, "status: %s\n", state.Status)
185
+ fmt.Fprintf(stdout, "active_layer: %s\n", state.ActiveLayer)
186
+ fmt.Fprintf(stdout, "profile: %s\n", state.Profile)
187
+ fmt.Fprintf(stdout, "approval: %s\n", state.ApprovalStatus)
188
+ if report.CurrentTask != "" {
189
+ fmt.Fprintf(stdout, "current_task: %s\n", report.CurrentTask)
190
+ }
191
+ if report.Validation.OK {
192
+ fmt.Fprintln(stdout, "validation: valid")
193
+ } else {
194
+ fmt.Fprintln(stdout, "validation: invalid")
195
+ for _, issue := range report.Validation.Issues {
196
+ fmt.Fprintf(stdout, "- %s\n", issue)
197
+ }
198
+ }
199
+ if report.StaleComplete {
200
+ fmt.Fprintln(stdout, "stored_status: complete is stale")
201
+ }
202
+ return nil
203
+ }
204
+
205
+ func runNext(args []string, stdout io.Writer) error {
206
+ jsonOutput, path, err := parseJSONPathArgs("next", args)
207
+ if err != nil {
208
+ return err
209
+ }
210
+ workspace, err := ResolveWorkspace(".", path)
211
+ if err != nil {
212
+ return err
213
+ }
214
+ state, err := ReadState(workspace)
215
+ if err != nil {
216
+ return err
217
+ }
218
+ action := nextActionForWorkspace(workspace, state)
219
+ if jsonOutput {
220
+ return writeJSON(stdout, action)
221
+ }
222
+ fmt.Fprintln(stdout, action.Instruction)
223
+ return nil
224
+ }
225
+
226
+ func runValidate(args []string, stdout io.Writer) error {
227
+ options, err := parseValidateArgs(args)
228
+ if err != nil {
229
+ return err
230
+ }
231
+ workspace, err := ResolveWorkspace(".", options.Path)
232
+ if err != nil {
233
+ return err
234
+ }
235
+ if options.Run {
236
+ if err := RunRequiredValidationCommands(".", workspace, options.Timeout, stdout); err != nil {
237
+ return err
238
+ }
239
+ }
240
+ result, err := ValidateWorkspace(workspace)
241
+ if err != nil {
242
+ return err
243
+ }
244
+ if result.OK {
245
+ if err := markValidationLayerComplete(workspace); err != nil {
246
+ return err
247
+ }
248
+ if err := appendValidationEvent(workspace, result); err != nil {
249
+ return err
250
+ }
251
+ fmt.Fprintf(stdout, "valid: %s\n", workspace)
252
+ return nil
253
+ }
254
+ if err := appendValidationEvent(workspace, result); err != nil {
255
+ return err
256
+ }
257
+ fmt.Fprintf(stdout, "invalid: %s\n", workspace)
258
+ for _, issue := range result.Issues {
259
+ fmt.Fprintf(stdout, "- %s\n", issue)
260
+ }
261
+ return errors.New("workspace validation failed")
262
+ }
263
+
264
+ type validateOptions struct {
265
+ Run bool
266
+ Timeout time.Duration
267
+ Path string
268
+ }
269
+
270
+ func parseValidateArgs(args []string) (validateOptions, error) {
271
+ options := validateOptions{Timeout: 10 * time.Minute}
272
+ for i := 0; i < len(args); i++ {
273
+ arg := args[i]
274
+ switch arg {
275
+ case "--run":
276
+ options.Run = true
277
+ case "--timeout":
278
+ i++
279
+ if i >= len(args) {
280
+ return validateOptions{}, errors.New("validate --timeout requires a duration")
281
+ }
282
+ timeout, err := time.ParseDuration(args[i])
283
+ if err != nil {
284
+ return validateOptions{}, fmt.Errorf("invalid validate timeout %q: %w", args[i], err)
285
+ }
286
+ if timeout <= 0 {
287
+ return validateOptions{}, errors.New("validate timeout must be greater than zero")
288
+ }
289
+ options.Timeout = timeout
290
+ default:
291
+ if strings.HasPrefix(arg, "-") {
292
+ return validateOptions{}, fmt.Errorf("validate does not accept flag: %s", arg)
293
+ }
294
+ if options.Path != "" {
295
+ return validateOptions{}, errors.New("validate accepts at most one path")
296
+ }
297
+ options.Path = arg
298
+ }
299
+ }
300
+ return options, nil
301
+ }
302
+
303
+ func rejectFlags(command string, args []string) error {
304
+ for _, arg := range args {
305
+ if strings.HasPrefix(arg, "-") {
306
+ return fmt.Errorf("%s does not accept flags: %s", command, arg)
307
+ }
308
+ }
309
+ return nil
310
+ }
311
+
312
+ func parseJSONPathArgs(command string, args []string) (bool, string, error) {
313
+ jsonOutput := false
314
+ path := ""
315
+ for _, arg := range args {
316
+ if arg == "--json" {
317
+ jsonOutput = true
318
+ continue
319
+ }
320
+ if strings.HasPrefix(arg, "-") {
321
+ return false, "", fmt.Errorf("%s does not accept flag: %s", command, arg)
322
+ }
323
+ if path != "" {
324
+ return false, "", fmt.Errorf("%s accepts at most one path", command)
325
+ }
326
+ path = arg
327
+ }
328
+ return jsonOutput, path, nil
329
+ }
330
+
331
+ func firstArg(args []string) string {
332
+ if len(args) == 0 {
333
+ return ""
334
+ }
335
+ return args[0]
336
+ }
337
+
338
+ func startInstruction(profile string) string {
339
+ switch profile {
340
+ case "plan":
341
+ return "inspect relevant code/docs, record objective_function, files_to_modify, constraint_functions, decision_variables, and validation_proof with kkt model, then request approval before edits"
342
+ case "model":
343
+ return "record adaptive intent with kkt intent --method <method>, then inspect relevant code/docs and record discovery"
344
+ case "run":
345
+ return "record or import the selected model, run kkt judge --checkpoint model-ready, then request approval before edits"
346
+ default:
347
+ return "record adaptive intent with kkt intent --method <method>, then inspect relevant code/docs and record discovery/model/plan"
348
+ }
349
+ }