@sayknow-cli/coding-agent 0.2.4 → 0.2.6

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 (150) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/types/cli/migrate-cli.d.ts +20 -0
  3. package/dist/types/cli/update-cli.d.ts +3 -0
  4. package/dist/types/commands/migrate.d.ts +33 -0
  5. package/dist/types/config/keybindings.d.ts +4 -0
  6. package/dist/types/config/model-registry.d.ts +3 -0
  7. package/dist/types/config/models-config-schema.d.ts +5 -0
  8. package/dist/types/config/settings-schema.d.ts +27 -0
  9. package/dist/types/harness-control-plane/storage.d.ts +2 -1
  10. package/dist/types/hooks/skill-state.d.ts +12 -4
  11. package/dist/types/lsp/startup-events.d.ts +1 -0
  12. package/dist/types/migrate/action-planner.d.ts +11 -0
  13. package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
  14. package/dist/types/migrate/adapters/codex.d.ts +5 -0
  15. package/dist/types/migrate/adapters/index.d.ts +45 -0
  16. package/dist/types/migrate/adapters/opencode.d.ts +2 -0
  17. package/dist/types/migrate/executor.d.ts +2 -0
  18. package/dist/types/migrate/mcp-mapper.d.ts +20 -0
  19. package/dist/types/migrate/report.d.ts +18 -0
  20. package/dist/types/migrate/skill-normalizer.d.ts +27 -0
  21. package/dist/types/migrate/types.d.ts +126 -0
  22. package/dist/types/modes/components/custom-editor.d.ts +1 -1
  23. package/dist/types/modes/components/welcome.d.ts +3 -1
  24. package/dist/types/modes/interactive-mode.d.ts +3 -0
  25. package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -0
  26. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
  27. package/dist/types/research-plan/index.d.ts +1 -0
  28. package/dist/types/research-plan/ledger.d.ts +33 -0
  29. package/dist/types/rlm/artifacts.d.ts +1 -1
  30. package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
  31. package/dist/types/skc-runtime/deep-interview-recorder.d.ts +2 -0
  32. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +2 -2
  33. package/dist/types/skc-runtime/goal-mode-request.d.ts +1 -1
  34. package/dist/types/skc-runtime/session-layout.d.ts +59 -0
  35. package/dist/types/skc-runtime/session-resolution.d.ts +47 -0
  36. package/dist/types/skc-runtime/state-graph.d.ts +1 -1
  37. package/dist/types/skc-runtime/state-runtime.d.ts +5 -4
  38. package/dist/types/skc-runtime/state-schema.d.ts +2 -0
  39. package/dist/types/skc-runtime/state-writer.d.ts +36 -7
  40. package/dist/types/skc-runtime/tmux-sessions.d.ts +2 -0
  41. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +7 -4
  42. package/dist/types/skc-runtime/workflow-command-ref.d.ts +1 -1
  43. package/dist/types/skc-runtime/workflow-manifest.d.ts +1 -1
  44. package/dist/types/skill-state/active-state.d.ts +6 -11
  45. package/dist/types/skill-state/canonical-skills.d.ts +3 -0
  46. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +5 -0
  47. package/dist/types/skill-state/workflow-hud.d.ts +2 -0
  48. package/dist/types/task/spawn-gate.d.ts +1 -10
  49. package/package.json +7 -7
  50. package/scripts/build-binary.ts +0 -7
  51. package/src/cli/migrate-cli.ts +106 -0
  52. package/src/cli/setup-cli.ts +14 -1
  53. package/src/cli/update-cli.ts +53 -3
  54. package/src/cli.ts +1 -0
  55. package/src/commands/deep-interview.ts +2 -2
  56. package/src/commands/launch.ts +1 -1
  57. package/src/commands/migrate.ts +46 -0
  58. package/src/commands/state.ts +2 -1
  59. package/src/commands/team.ts +7 -3
  60. package/src/config/model-registry.ts +9 -2
  61. package/src/config/model-resolver.ts +13 -2
  62. package/src/config/models-config-schema.ts +1 -0
  63. package/src/config/settings-schema.ts +17 -0
  64. package/src/coordinator-mcp/policy.ts +10 -2
  65. package/src/defaults/skc/extensions/grok-cli-vendor/biome.json +0 -1
  66. package/src/defaults/skc/skills/deep-interview/SKILL.md +30 -24
  67. package/src/defaults/skc/skills/ralplan/SKILL.md +10 -4
  68. package/src/defaults/skc/skills/team/SKILL.md +51 -47
  69. package/src/defaults/skc/skills/ultragoal/SKILL.md +17 -13
  70. package/src/exec/bash-executor.ts +3 -1
  71. package/src/extensibility/custom-commands/loader.ts +0 -7
  72. package/src/extensibility/skc-plugins/injection.ts +23 -4
  73. package/src/extensibility/skc-plugins/state.ts +16 -1
  74. package/src/harness-control-plane/storage.ts +14 -4
  75. package/src/hooks/native-skill-hook.ts +38 -12
  76. package/src/hooks/skill-state.ts +178 -83
  77. package/src/internal-urls/docs-index.generated.ts +11 -9
  78. package/src/lsp/startup-events.ts +24 -0
  79. package/src/migrate/action-planner.ts +318 -0
  80. package/src/migrate/adapters/claude-code.ts +39 -0
  81. package/src/migrate/adapters/codex.ts +70 -0
  82. package/src/migrate/adapters/index.ts +277 -0
  83. package/src/migrate/adapters/opencode.ts +52 -0
  84. package/src/migrate/executor.ts +81 -0
  85. package/src/migrate/mcp-mapper.ts +152 -0
  86. package/src/migrate/report.ts +104 -0
  87. package/src/migrate/skill-normalizer.ts +80 -0
  88. package/src/migrate/types.ts +163 -0
  89. package/src/modes/bridge/bridge-mode.ts +2 -2
  90. package/src/modes/components/custom-editor.ts +30 -20
  91. package/src/modes/components/welcome.ts +20 -9
  92. package/src/modes/controllers/input-controller.ts +21 -3
  93. package/src/modes/interactive-mode.ts +27 -19
  94. package/src/modes/prompt-action-autocomplete.ts +11 -1
  95. package/src/modes/rpc/rpc-mode.ts +2 -2
  96. package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
  97. package/src/prompts/agents/init.md +1 -1
  98. package/src/prompts/system/plan-mode-active.md +1 -1
  99. package/src/prompts/tools/ast-grep.md +1 -1
  100. package/src/prompts/tools/search.md +1 -1
  101. package/src/prompts/tools/task.md +1 -2
  102. package/src/research-plan/index.ts +1 -0
  103. package/src/research-plan/ledger.ts +177 -0
  104. package/src/rlm/artifacts.ts +12 -3
  105. package/src/rlm/index.ts +7 -0
  106. package/src/runtime-mcp/config-writer.ts +46 -0
  107. package/src/session/agent-session.ts +43 -41
  108. package/src/session/session-manager.ts +19 -2
  109. package/src/setup/hermes/templates/operator-instructions.v1.md +8 -0
  110. package/src/setup/hermes-setup.ts +1 -1
  111. package/src/skc-runtime/deep-interview-recorder.ts +51 -18
  112. package/src/skc-runtime/deep-interview-runtime.ts +49 -23
  113. package/src/skc-runtime/goal-mode-request.ts +26 -11
  114. package/src/skc-runtime/launch-tmux.ts +68 -15
  115. package/src/skc-runtime/ralplan-runtime.ts +79 -50
  116. package/src/skc-runtime/session-layout.ts +180 -0
  117. package/src/skc-runtime/session-resolution.ts +217 -0
  118. package/src/skc-runtime/state-graph.ts +1 -2
  119. package/src/skc-runtime/state-migrations.ts +1 -0
  120. package/src/skc-runtime/state-runtime.ts +237 -114
  121. package/src/skc-runtime/state-schema.ts +2 -0
  122. package/src/skc-runtime/state-writer.ts +310 -42
  123. package/src/skc-runtime/team-runtime.ts +43 -19
  124. package/src/skc-runtime/tmux-sessions.ts +43 -2
  125. package/src/skc-runtime/ultragoal-guard.ts +45 -2
  126. package/src/skc-runtime/ultragoal-runtime.ts +121 -41
  127. package/src/skc-runtime/workflow-command-ref.ts +1 -2
  128. package/src/skc-runtime/workflow-manifest.ts +1 -2
  129. package/src/skill-state/active-state.ts +116 -129
  130. package/src/skill-state/canonical-skills.ts +4 -0
  131. package/src/skill-state/deep-interview-mutation-guard.ts +238 -111
  132. package/src/skill-state/workflow-hud.ts +4 -2
  133. package/src/skill-state/workflow-state-contract.ts +3 -3
  134. package/src/slash-commands/builtin-registry.ts +8 -4
  135. package/src/system-prompt.ts +11 -9
  136. package/src/task/agents.ts +1 -22
  137. package/src/task/index.ts +1 -41
  138. package/src/task/spawn-gate.ts +1 -38
  139. package/src/task/types.ts +1 -1
  140. package/src/tools/ask.ts +34 -12
  141. package/src/tools/ast-edit.ts +2 -2
  142. package/src/tools/computer.ts +58 -4
  143. package/src/utils/edit-mode.ts +1 -1
  144. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
  145. package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
  146. package/src/prompts/agents/explore.md +0 -58
  147. package/src/prompts/agents/plan.md +0 -49
  148. package/src/prompts/agents/reviewer.md +0 -141
  149. package/src/prompts/agents/task.md +0 -16
  150. package/src/prompts/review-request.md +0 -70
@@ -28,6 +28,32 @@ export declare function addMCPServer(filePath: string, name: string, config: MCP
28
28
  * @throws Error if validation fails
29
29
  */
30
30
  export declare function updateMCPServer(filePath: string, name: string, config: MCPServerConfig): Promise<void>;
31
+ /**
32
+ * Result of an {@link upsertMCPServer} call.
33
+ * - `added`: server did not exist and was written.
34
+ * - `updated`: server existed and was overwritten because `force` was set.
35
+ * - `skipped`: server existed and `force` was not set, so nothing was written.
36
+ */
37
+ export type UpsertMCPServerResult = {
38
+ status: "added";
39
+ } | {
40
+ status: "updated";
41
+ } | {
42
+ status: "skipped";
43
+ reason: "exists";
44
+ };
45
+ /**
46
+ * Add an MCP server, or overwrite an existing one only when `force` is set.
47
+ *
48
+ * Collision-aware wrapper over {@link addMCPServer} / {@link updateMCPServer} used by
49
+ * `skc migrate`. Never connects to the server. Reuses the underlying writers so the
50
+ * rest of the config file (including `disabledServers`) is preserved on update.
51
+ *
52
+ * @throws Error if the server name or config is invalid (validated before any write).
53
+ */
54
+ export declare function upsertMCPServer(filePath: string, name: string, config: MCPServerConfig, options?: {
55
+ force?: boolean;
56
+ }): Promise<UpsertMCPServerResult>;
31
57
  /**
32
58
  * Remove an MCP server from a config file.
33
59
  *
@@ -84,6 +84,8 @@ export declare function ensureDeepInterviewStateShape(value: unknown): DeepInter
84
84
  export declare function projectCompactState(value: unknown, options?: {
85
85
  lastN?: number;
86
86
  }): DeepInterviewCompactState;
87
+ /** Refresh the best-effort HUD cache from persisted deep-interview state. */
88
+ export declare function syncDeepInterviewRecorderHud(cwd: string, statePath: string, sessionId: string | undefined): Promise<void>;
87
89
  /** Record an `answered` shell for one round (append-or-merge by durable key). */
88
90
  export declare function appendOrMergeDeepInterviewRound(cwd: string, statePath: string, input: DeepInterviewAnswerInput, options?: {
89
91
  sessionId?: string;
@@ -13,12 +13,12 @@ export interface DeepInterviewCommandResult {
13
13
  stdout?: string;
14
14
  stderr?: string;
15
15
  }
16
- export declare function deepInterviewStatePath(cwd: string, sessionId: string | undefined): string;
16
+ export declare function deepInterviewStatePath(cwd: string, sessionId?: string): string;
17
17
  export interface ResolvedDeepInterviewSpecWriteArgs {
18
18
  stage: "final";
19
19
  slug: string;
20
20
  spec: string;
21
- sessionId?: string;
21
+ sessionId: string;
22
22
  json: boolean;
23
23
  deliberate: boolean;
24
24
  handoff?: "ralplan";
@@ -30,7 +30,7 @@ export type CurrentSessionGoalModeWriteResult = {
30
30
  sessionFile: string;
31
31
  };
32
32
  export declare function isUltragoalCreateGoalsInvocation(args: readonly string[]): boolean;
33
- export declare function readUltragoalSkcObjective(cwd: string): Promise<{
33
+ export declare function readUltragoalSkcObjective(cwd: string, sessionId?: string | null): Promise<{
34
34
  objective: string;
35
35
  goalsPath: string;
36
36
  }>;
@@ -0,0 +1,59 @@
1
+ export declare const SKC_DIR = ".skc";
2
+ export declare const SKC_SESSION_PREFIX = "_session-";
3
+ export declare const SKC_SESSION_ACTIVITY_FILE = ".session-activity.json";
4
+ /** Source that produced a resolved SKC session id, for audit/diagnostics. */
5
+ export type SkcSessionSource = "flag" | "payload" | "env" | "latest";
6
+ export interface SkcSessionContext {
7
+ skcSessionId: string;
8
+ sessionRoot: string;
9
+ source: SkcSessionSource;
10
+ }
11
+ /**
12
+ * Encode a session id into a single safe path segment. Matches the historical
13
+ * encoding used across the runtimes so ids round-trip identically:
14
+ * `encodeURIComponent` plus dot-escaping (dots are legal in filenames but we
15
+ * avoid `.`/`..` traversal ambiguity).
16
+ */
17
+ export declare function encodeSessionSegment(value: string): string;
18
+ /** Inverse of {@link encodeSessionSegment}. */
19
+ export declare function decodeSessionSegment(segment: string): string;
20
+ /** Throw when a session id is missing or blank; never let blank suppress callers. */
21
+ export declare function assertNonEmptySkcSessionId(value: string | undefined, source: string): asserts value is string;
22
+ /**
23
+ * Assert a value is safe to use as a single path segment: non-blank and free of
24
+ * path separators or `.`/`..` traversal. Use for already-safe identifiers
25
+ * (skill modes, slugs) where we want identical filenames but fail closed on
26
+ * traversal rather than silently normalizing out of the intended directory.
27
+ */
28
+ export declare function assertSafePathComponent(value: string, label: string): void;
29
+ /** The shared `.skc/` root (holds shared config; never session-scoped). */
30
+ export declare function skcRoot(cwd: string): string;
31
+ /** The per-session root directory: `<cwd>/.skc/_session-{encodedId}`. */
32
+ export declare function sessionRoot(cwd: string, skcSessionId: string): string;
33
+ /** Directory name (no path) for a session id, e.g. `_session-abc`. */
34
+ export declare function sessionDirName(skcSessionId: string): string;
35
+ /** Return the decoded session id for a `_session-*` directory name, else undefined. */
36
+ export declare function sessionIdFromDirName(name: string): string | undefined;
37
+ /** Authoritative per-session activity marker path. */
38
+ export declare function sessionActivityPath(cwd: string, skcSessionId: string): string;
39
+ export declare function sessionStateDir(cwd: string, skcSessionId: string): string;
40
+ export declare function sessionSpecsDir(cwd: string, skcSessionId: string): string;
41
+ export declare function sessionPlansDir(cwd: string, skcSessionId: string): string;
42
+ export declare function sessionUltragoalDir(cwd: string, skcSessionId: string): string;
43
+ export declare function sessionAuditDir(cwd: string, skcSessionId: string): string;
44
+ export declare function sessionReportsDir(cwd: string, skcSessionId: string): string;
45
+ export declare function sessionLogsDir(cwd: string, skcSessionId: string): string;
46
+ export declare function sessionRuntimeDir(cwd: string, skcSessionId: string): string;
47
+ export declare function sessionRlmDir(cwd: string, skcSessionId: string): string;
48
+ export declare function activeStateDir(cwd: string, skcSessionId: string): string;
49
+ export declare function activeSnapshotPath(cwd: string, skcSessionId: string): string;
50
+ export declare function activeEntryPath(cwd: string, skcSessionId: string, skill: string): string;
51
+ export declare function modeStatePath(cwd: string, skcSessionId: string, mode: string): string;
52
+ export declare function auditPath(cwd: string, skcSessionId: string): string;
53
+ export declare function transactionJournalPath(cwd: string, skcSessionId: string, mutationId: string): string;
54
+ export declare function teamStateRoot(cwd: string, skcSessionId: string): string;
55
+ export declare function workflowGatePath(cwd: string, skcSessionId: string, gateId: string): string;
56
+ export declare function harnessStateRoot(cwd: string, skcSessionId: string): string;
57
+ export declare function coordinatorMcpStateRoot(cwd: string, skcSessionId: string): string;
58
+ export declare function tmuxRuntimeSessionPath(cwd: string, skcSessionId: string, slug: string): string;
59
+ export declare function rlmArtifactRoot(cwd: string, skcSessionId: string, rlmSessionId: string): string;
@@ -0,0 +1,47 @@
1
+ import { type SkcSessionContext, type SkcSessionSource } from "./session-layout";
2
+ /** Window within which two activity timestamps are treated as an ambiguous tie. */
3
+ export declare const LATEST_SESSION_TIE_WINDOW_MS = 1000;
4
+ export interface SessionIdSources {
5
+ /** Raw `--session-id` value: `undefined` = flag absent; `""` = present-but-blank (invalid). */
6
+ flagValue?: string | undefined;
7
+ payloadSessionId?: unknown;
8
+ envSessionId?: string | undefined;
9
+ }
10
+ export declare class SessionResolutionError extends Error {
11
+ readonly code: "blank_flag" | "no_session" | "ambiguous" | "missing_for_write";
12
+ constructor(message: string, code: "blank_flag" | "no_session" | "ambiguous" | "missing_for_write");
13
+ }
14
+ interface ResolvedFromSources {
15
+ skcSessionId: string;
16
+ source: SkcSessionSource;
17
+ }
18
+ /**
19
+ * Resolve a session id from explicit sources only (flag -> payload -> env).
20
+ * Returns `undefined` when none is present. A blank explicit flag throws.
21
+ */
22
+ export declare function resolveSessionIdFromSources(sources: SessionIdSources): ResolvedFromSources | undefined;
23
+ /** Resolve session context for a WRITE command. Errors when no explicit id is present. */
24
+ export declare function resolveSkcSessionForWrite(cwd: string, sources: SessionIdSources): SkcSessionContext;
25
+ /**
26
+ * Resolve session context for a READ/STATUS/CLEAR command. Falls back to the
27
+ * latest active session by activity marker when no explicit id is present.
28
+ */
29
+ export declare function resolveSkcSessionForRead(cwd: string, sources: SessionIdSources): Promise<SkcSessionContext>;
30
+ /**
31
+ * Scan `.skc/_session-*` directories and select the most-recently-active one by
32
+ * its activity marker. Never uses raw directory mtime. Throws on zero candidates
33
+ * or an ambiguous tie.
34
+ */
35
+ export declare function detectLatestSession(cwd: string): Promise<SkcSessionContext>;
36
+ export interface ActivityMarkerInfo {
37
+ writer: string;
38
+ /** Relative generated path that was just written, for diagnostics. */
39
+ path?: string;
40
+ }
41
+ /**
42
+ * Best-effort write of the per-session activity marker. State-command callers
43
+ * MUST treat a thrown error as a command failure (auto-detect depends on it);
44
+ * non-critical writers may swallow it.
45
+ */
46
+ export declare function writeSessionActivityMarker(cwd: string, skcSessionId: string, info: ActivityMarkerInfo): Promise<void>;
47
+ export {};
@@ -1,4 +1,4 @@
1
- import type { CanonicalSkcWorkflowSkill } from "../skill-state/active-state";
1
+ import { type CanonicalSkcWorkflowSkill } from "../skill-state/canonical-skills";
2
2
  export type StateGraphSkill = CanonicalSkcWorkflowSkill | "all";
3
3
  export type StateGraphFormat = "ascii" | "mermaid" | "dot";
4
4
  export declare function renderStateGraph(skill: StateGraphSkill, format?: string): string;
@@ -2,9 +2,9 @@ import { type CanonicalSkcWorkflowSkill } from "../skill-state/active-state";
2
2
  /**
3
3
  * Native implementation of the `skc state read|write|clear` command surface.
4
4
  *
5
- * Simple file-receipt operations against `.skc/state/[sessions/<id>/]<mode>-state.json` and
6
- * `.skc/state/[sessions/<id>/]skill-active-state.json`. This is the sanctioned CLI mediator for
7
- * the mutation-guarded `.skc/state` ACL — agents call it instead of editing those files directly.
5
+ * Simple file-receipt operations against session-scoped state under
6
+ * `.skc/_session-{id}/state/`. This is the sanctioned CLI mediator for
7
+ * mutation-guarded SKC state — agents call it instead of editing those files directly.
8
8
  */
9
9
  export interface StateCommandResult {
10
10
  status: number;
@@ -24,12 +24,13 @@ export interface StateCommandResult {
24
24
  export declare function reconcileWorkflowSkillState(options: {
25
25
  cwd: string;
26
26
  mode: CanonicalSkcWorkflowSkill;
27
- sessionId: string | undefined;
27
+ sessionId?: string;
28
28
  threadId?: string;
29
29
  turnId?: string;
30
30
  active: boolean;
31
31
  phase: string;
32
32
  payload: Record<string, unknown>;
33
+ sourceRevision?: number;
33
34
  }): Promise<{
34
35
  stateFile: string;
35
36
  }>;
@@ -84,6 +84,7 @@ export declare const WorkflowStateEnvelopeSchema: z.ZodObject<{
84
84
  computed_at: z.ZodString;
85
85
  }, z.core.$loose>>;
86
86
  }, z.core.$loose>>;
87
+ state_revision: z.ZodOptional<z.ZodNumber>;
87
88
  }, z.core.$loose>;
88
89
  /**
89
90
  * Strict receipt required on WRITE (post checksum-stamping). Anchored to the
@@ -164,6 +165,7 @@ export declare const RequiredOnWriteEnvelopeSchema: z.ZodObject<{
164
165
  computed_at: z.ZodString;
165
166
  }, z.core.$loose>;
166
167
  }, z.core.$loose>;
168
+ state_revision: z.ZodOptional<z.ZodNumber>;
167
169
  }, z.core.$loose>;
168
170
  /** Per-skill mode state consumed by hooks / the mutation guard. */
169
171
  export declare const ModeStateSchema: z.ZodObject<{
@@ -11,7 +11,7 @@ import { type AuditEntry, type CanonicalSkcWorkflowSkill, type WorkflowStateMuta
11
11
  * supplied mutation context. No lockfiles are used; isolation is by atomic rename,
12
12
  * append, O_EXCL creates, conditional deletes, per-entry active-state files,
13
13
  * and derived active-state snapshots.
14
- * Transaction journals are per mutation id under `.skc/state/transactions/`;
14
+ * Transaction journals are per mutation id under the session state transactions directory;
15
15
  * they are recovery evidence only, never global locks or waiters, so stale
16
16
  * journals do not block unrelated state reads or writes.
17
17
  */
@@ -24,9 +24,14 @@ export interface StateWriterReceiptContext {
24
24
  sessionId?: string;
25
25
  mutationId?: string;
26
26
  nowIso?: string;
27
+ verb?: string;
28
+ fromPhase?: string;
29
+ toPhase?: string;
30
+ forced?: boolean;
27
31
  }
28
32
  export interface StateWriterAuditContext {
29
33
  cwd?: string;
34
+ sessionId?: string;
30
35
  category: WriterCategory;
31
36
  verb: string;
32
37
  owner: WorkflowStateMutationOwner;
@@ -52,10 +57,25 @@ export interface WorkflowTransactionJournal {
52
57
  paths: string[];
53
58
  steps: string[];
54
59
  }
60
+ export type StateWritePolicy = "source" | "cache";
61
+ export interface GuardedStateWriterOptions extends StateWriterOptions {
62
+ policy: StateWritePolicy;
63
+ expectedRevision?: number;
64
+ sourceRevision?: number;
65
+ }
66
+ export type GuardedWriteResult = {
67
+ path: string;
68
+ written: true;
69
+ } | {
70
+ path: string;
71
+ written: false;
72
+ reason: "stale-skip";
73
+ };
55
74
  export interface StateWriterOptions {
56
75
  cwd?: string;
57
76
  receipt?: StateWriterReceiptContext;
58
77
  audit?: StateWriterAuditContext;
78
+ sourceRevision?: number;
59
79
  /**
60
80
  * Cross-process lock tuning for read-modify-write paths that route through
61
81
  * `withWorkflowStateLock` / `updateJsonAtomic`. Omit for the hardened
@@ -63,6 +83,12 @@ export interface StateWriterOptions {
63
83
  */
64
84
  lock?: FileLockOptions;
65
85
  }
86
+ export declare class StateWriteConflictError extends Error {
87
+ readonly path: string;
88
+ readonly expectedRevision: number;
89
+ readonly persistedRevision: number;
90
+ constructor(path: string, expectedRevision: number, persistedRevision: number);
91
+ }
66
92
  export interface DeleteIfOwnedOptions extends StateWriterOptions {
67
93
  predicate?: (current: unknown) => boolean | Promise<boolean>;
68
94
  }
@@ -113,6 +139,9 @@ export declare function readExistingStateForMutation(filePath: string): Promise<
113
139
  export declare function workflowEnvelopeContentSha256(value: unknown): string;
114
140
  export declare function stampWorkflowEnvelopeChecksum<T>(value: T, filePath: string, computedAt?: string): T;
115
141
  export declare function detectWorkflowEnvelopeIntegrityMismatch(filePath: string): Promise<WorkflowEnvelopeIntegrityMismatch | undefined>;
142
+ export declare function persistedStateRevision(value: unknown): number;
143
+ export declare function writeGuardedJsonAtomic(targetPath: string, value: unknown, options: GuardedStateWriterOptions): Promise<GuardedWriteResult>;
144
+ export declare function writeGuardedWorkflowEnvelopeAtomic(targetPath: string, value: unknown, options: GuardedStateWriterOptions): Promise<GuardedWriteResult>;
116
145
  export declare function writeJsonAtomic(targetPath: string, value: unknown, options?: StateWriterOptions): Promise<string>;
117
146
  export declare function writeWorkflowEnvelopeAtomic(targetPath: string, value: unknown, options?: StateWriterOptions): Promise<string>;
118
147
  export declare function writeTextAtomic(targetPath: string, text: string, options?: StateWriterOptions): Promise<string>;
@@ -178,8 +207,7 @@ export declare function createJsonNoClobber(targetPath: string, value: unknown,
178
207
  export declare function deleteIfOwned(targetPath: string, predicateOrOptions?: ((current: unknown) => boolean | Promise<boolean>) | DeleteIfOwnedOptions): Promise<DeleteResult>;
179
208
  export declare function removeFileAudited(targetPath: string, options?: StateWriterOptions): Promise<DeleteResult>;
180
209
  /**
181
- * Active entry files under `.skc/state/active/<skill>.json` and
182
- * `.skc/state/sessions/<id>/active/<skill>.json` are authoritative. The
210
+ * Active entry files under `.skc/_session-{id}/state/active/<skill>.json` are authoritative. The
183
211
  * adjacent `skill-active-state.json` file is only a derived cache rebuilt from
184
212
  * those entries, so concurrent snapshot rebuilds can race without losing any
185
213
  * writer's per-skill state.
@@ -196,14 +224,15 @@ export declare function softDelete(targetPath: string, meta: Record<string, unkn
196
224
  export declare function hardPruneJson(targetPaths: readonly string[], selector: HardPruneSelector, options?: StateWriterOptions): Promise<string[]>;
197
225
  export declare function hardPrune(targets: readonly GenericHardPruneTarget[], selector: GenericHardPruneSelector, options?: StateWriterOptions): Promise<string[]>;
198
226
  export declare function forceOverwrite(targetPath: string, rawValue: unknown, options?: ForceOverwriteOptions): Promise<string>;
199
- export declare function appendAuditEntry(cwd: string, entry: AuditEntry): Promise<string>;
200
- export declare function readWorkflowTransactionJournal(cwd: string, mutationId: string): Promise<WorkflowTransactionJournal | undefined>;
227
+ export declare function appendAuditEntry(cwd: string, sessionIdOrEntry: string | AuditEntry, maybeEntry?: AuditEntry): Promise<string>;
228
+ export declare function readWorkflowTransactionJournal(cwd: string, sessionId: string, mutationId: string): Promise<WorkflowTransactionJournal | undefined>;
201
229
  export declare function beginWorkflowTransactionJournal(input: {
202
230
  cwd: string;
231
+ sessionId: string;
203
232
  mutationId: string;
204
233
  caller?: CanonicalSkcWorkflowSkill;
205
234
  callee?: CanonicalSkcWorkflowSkill;
206
235
  paths: string[];
207
236
  }): Promise<string>;
208
- export declare function updateWorkflowTransactionJournal(cwd: string, mutationId: string, patch: Partial<WorkflowTransactionJournal>): Promise<string>;
209
- export declare function completeWorkflowTransactionJournal(cwd: string, mutationId: string): Promise<void>;
237
+ export declare function updateWorkflowTransactionJournal(cwd: string, sessionId: string, mutationId: string, patch: Partial<WorkflowTransactionJournal>): Promise<string>;
238
+ export declare function completeWorkflowTransactionJournal(cwd: string, sessionId: string, mutationId: string): Promise<void>;
@@ -32,6 +32,8 @@ export declare function listSkcTmuxSessions(env?: NodeJS.ProcessEnv): SkcTmuxSes
32
32
  /** @internal */
33
33
  export declare function listTmuxSessionsForGc(env?: NodeJS.ProcessEnv): SkcTmuxSessionsForGc;
34
34
  export declare function findSkcTmuxSessionByBranch(branch: string, env?: NodeJS.ProcessEnv, project?: string | null): SkcTmuxSessionStatus | undefined;
35
+ export declare function findSkcTmuxSessionByName(sessionName: string, env?: NodeJS.ProcessEnv): SkcTmuxSessionStatus | undefined;
36
+ export declare function findSkcTmuxSessionByScope(project: string, branch: string | null | undefined, env?: NodeJS.ProcessEnv): SkcTmuxSessionStatus | undefined;
35
37
  export declare function statusSkcTmuxSession(sessionName: string, env?: NodeJS.ProcessEnv): SkcTmuxSessionStatus;
36
38
  export declare function createSkcTmuxSession(env?: NodeJS.ProcessEnv): SkcTmuxSessionStatus;
37
39
  /** @internal */
@@ -23,6 +23,7 @@ export interface UltragoalPlan {
23
23
  goals: UltragoalGoal[];
24
24
  createdAt: string;
25
25
  updatedAt: string;
26
+ [key: string]: unknown;
26
27
  }
27
28
  export type UltragoalReceiptKind = "per-goal" | "final-aggregate";
28
29
  export interface UltragoalCompletionVerification {
@@ -79,8 +80,8 @@ interface JsonObject {
79
80
  [key: string]: unknown;
80
81
  }
81
82
  export declare function hashStructuredValue(value: unknown): string;
82
- export declare function getUltragoalPaths(cwd: string): UltragoalPaths;
83
- export declare function readUltragoalLedger(cwd: string): Promise<UltragoalLedgerEvent[]>;
83
+ export declare function getUltragoalPaths(cwd: string, sessionId?: string | null): UltragoalPaths;
84
+ export declare function readUltragoalLedger(cwd: string, sessionId?: string | null): Promise<UltragoalLedgerEvent[]>;
84
85
  export declare function computeUltragoalPlanGeneration(input: {
85
86
  plan: UltragoalPlan;
86
87
  ledger: readonly UltragoalLedgerEvent[];
@@ -93,13 +94,14 @@ export declare function computeUltragoalPlanGeneration(input: {
93
94
  planGeneration: string;
94
95
  basis: UltragoalCompletionVerification["basis"];
95
96
  };
96
- export declare function readUltragoalPlan(cwd: string): Promise<UltragoalPlan | null>;
97
- export declare function getUltragoalStatus(cwd: string): Promise<UltragoalStatusSummary>;
97
+ export declare function readUltragoalPlan(cwd: string, sessionId?: string | null): Promise<UltragoalPlan | null>;
98
+ export declare function getUltragoalStatus(cwd: string, sessionId?: string | null): Promise<UltragoalStatusSummary>;
98
99
  export declare function buildUltragoalHudSummary(summary: UltragoalStatusSummary, latestLedger?: UltragoalLedgerEvent): WorkflowHudSummary;
99
100
  export declare function createUltragoalPlan(input: {
100
101
  cwd: string;
101
102
  brief: string;
102
103
  skcGoalMode?: UltragoalSkcGoalMode;
104
+ sessionId?: string | null;
103
105
  }): Promise<UltragoalPlan>;
104
106
  export interface UltragoalRunCompletionState {
105
107
  requiredGoals: UltragoalGoal[];
@@ -115,6 +117,7 @@ export declare function getUltragoalRunCompletionState(plan: UltragoalPlan, opti
115
117
  export declare function startNextUltragoalGoal(input: {
116
118
  cwd: string;
117
119
  retryFailed?: boolean;
120
+ sessionId?: string | null;
118
121
  }): Promise<{
119
122
  plan: UltragoalPlan;
120
123
  goal?: UltragoalGoal;
@@ -1,4 +1,4 @@
1
- import type { CanonicalSkcWorkflowSkill } from "../skill-state/active-state";
1
+ import { type CanonicalSkcWorkflowSkill } from "../skill-state/canonical-skills";
2
2
  export type CommandRefVisibility = "public" | "hidden" | "planned";
3
3
  export type CommandRefIncludeWhen = "implemented-only" | "planned";
4
4
  export interface CommandRefCommand {
@@ -3,7 +3,7 @@
3
3
  * Any JSON manifest projection is derived from this module and must never be
4
4
  * hand-edited.
5
5
  */
6
- import type { CanonicalSkcWorkflowSkill } from "../skill-state/active-state";
6
+ import { type CanonicalSkcWorkflowSkill } from "../skill-state/canonical-skills";
7
7
  export interface WorkflowState {
8
8
  id: string;
9
9
  initial?: boolean;
@@ -1,7 +1,7 @@
1
+ import { CANONICAL_SKC_WORKFLOW_SKILLS, type CanonicalSkcWorkflowSkill } from "./canonical-skills";
1
2
  import type { WorkflowStateReceipt } from "./workflow-state-contract";
2
3
  export declare const SKILL_ACTIVE_STATE_FILE = "skill-active-state.json";
3
- export declare const CANONICAL_SKC_WORKFLOW_SKILLS: readonly ["deep-interview", "ralplan", "ultragoal", "team"];
4
- export type CanonicalSkcWorkflowSkill = (typeof CANONICAL_SKC_WORKFLOW_SKILLS)[number];
4
+ export { CANONICAL_SKC_WORKFLOW_SKILLS, type CanonicalSkcWorkflowSkill };
5
5
  export type WorkflowHudSeverity = "info" | "warning" | "blocked" | "error" | "success";
6
6
  export interface WorkflowHudChip {
7
7
  label: string;
@@ -44,6 +44,7 @@ export interface SkillActiveEntry {
44
44
  handoff_to?: string;
45
45
  handoff_at?: string;
46
46
  active_subskills?: ActiveSubskillEntry[];
47
+ source_state_revision?: number;
47
48
  }
48
49
  export interface SkillActiveState {
49
50
  version?: number;
@@ -65,7 +66,7 @@ export interface SkillActiveState {
65
66
  }
66
67
  export interface SkillActiveStatePaths {
67
68
  rootPath: string;
68
- sessionPath?: string;
69
+ sessionPath: string;
69
70
  }
70
71
  export interface SyncSkillActiveStateOptions {
71
72
  cwd: string;
@@ -83,6 +84,7 @@ export interface SyncSkillActiveStateOptions {
83
84
  handoff_to?: string;
84
85
  handoff_at?: string;
85
86
  active_subskills?: ActiveSubskillEntry[];
87
+ sourceRevision?: number;
86
88
  }
87
89
  export declare function normalizeWorkflowHudSummary(raw: unknown): WorkflowHudSummary | undefined;
88
90
  export declare function isCanonicalSkcWorkflowSkill(skill: string): skill is CanonicalSkcWorkflowSkill;
@@ -102,13 +104,6 @@ export interface ApplyHandoffOptions {
102
104
  strict?: boolean;
103
105
  }
104
106
  /**
105
- * Atomically apply a workflow-skill handoff to both the session-scoped and
106
- * root `skill-active-state.json` files in a single write per file.
107
- *
108
- * Write order: **session first, root last**. The session file is the
109
- * source of truth for HUD; the root aggregate must never lead the session
110
- * during a handoff window. Each file is rewritten once with caller demoted
111
- * to `active:false` (preserving `handoff_to`/`handoff_at` lineage) and
112
- * callee promoted to `active:true` (with `handoff_from`/`handoff_at`).
107
+ * Atomically apply a workflow-skill handoff to the session-scoped active state.
113
108
  */
114
109
  export declare function applyHandoffToActiveState(options: ApplyHandoffOptions): Promise<void>;
@@ -0,0 +1,3 @@
1
+ /** Native-free canonical SKC workflow skill identifiers. */
2
+ export declare const CANONICAL_SKC_WORKFLOW_SKILLS: readonly ["deep-interview", "ralplan", "ultragoal", "team"];
3
+ export type CanonicalSkcWorkflowSkill = (typeof CANONICAL_SKC_WORKFLOW_SKILLS)[number];
@@ -1,6 +1,8 @@
1
1
  import type { AgentTool } from "@sayknow-cli/agent-core";
2
2
  export declare const DEEP_INTERVIEW_MUTATION_BLOCK_MESSAGE = "Deep-interview phase boundary: continue gathering context/questions/risks and emit a handoff/spec before code edits. Mutation tools and patch execution are blocked while deep-interview is active; finalize specs through `skc deep-interview --write --stage final` or hand off to an execution phase.";
3
3
  export declare const WORKFLOW_STATE_MUTATION_BLOCK_MESSAGE = ".skc workflow state and artifacts are runtime-owned. Agent mutation tools cannot edit `.skc/**`; use the sanctioned `skc` CLI instead.";
4
+ export declare const RALPLAN_MUTATION_BLOCK_MESSAGE = "Ralplan planning phase boundary: keep refining the consensus plan and persist plan artifacts through `skc ralplan --write` (stage scratch files under a temp dir if needed). Product-code mutation tools and patch execution are blocked while ralplan is active; mutate only after the plan is approved and execution begins.";
5
+ export declare const ULTRAGOAL_GOAL_PLANNING_MUTATION_BLOCK_MESSAGE = "Ultragoal goal-planning phase boundary: finish goal planning and record goals through `skc ultragoal` before editing code. Product-code mutation tools and patch execution are blocked until goal planning completes and execution begins.";
4
6
  type ToolWithEditMode = AgentTool & {
5
7
  mode?: unknown;
6
8
  customWireName?: unknown;
@@ -30,4 +32,7 @@ export declare function assertDeepInterviewMutationRawPathsAllowed(input: {
30
32
  }): Promise<void>;
31
33
  export declare function getDeepInterviewMutationDecision(input: DeepInterviewMutationGuardInput): Promise<DeepInterviewMutationDecision>;
32
34
  export declare function assertDeepInterviewMutationAllowed(input: DeepInterviewMutationGuardInput): Promise<void>;
35
+ export declare const getWorkflowMutationDecision: typeof getDeepInterviewMutationDecision;
36
+ export declare const assertWorkflowMutationAllowed: typeof assertDeepInterviewMutationAllowed;
37
+ export declare const assertWorkflowMutationRawPathsAllowed: typeof assertDeepInterviewMutationRawPathsAllowed;
33
38
  export {};
@@ -39,6 +39,8 @@ interface UltragoalHudState extends WorkflowGateHudState {
39
39
  event?: string;
40
40
  goalId?: string;
41
41
  timestamp?: string;
42
+ kind?: string;
43
+ evidence?: string;
42
44
  };
43
45
  updatedAt?: string;
44
46
  }
@@ -1,6 +1,6 @@
1
1
  /** The hard, locked batch threshold enforced by the runtime gate. */
2
2
  export declare const DEFAULT_SPAWN_THRESHOLD = 4;
3
- /** The justification a large batch or reviewer-spawned explorer must supply to pass the hard gate. */
3
+ /** The justification a large batch must supply to pass the hard gate. */
4
4
  export interface SpawnPlanReceipt {
5
5
  whyParallel: string;
6
6
  whyNotLocal: string;
@@ -14,14 +14,6 @@ export interface SpawnGateRequest {
14
14
  /** The spawn-plan receipt, when provided. */
15
15
  plan?: SpawnPlanReceipt;
16
16
  }
17
- export interface ReviewerExploreGateRequest {
18
- /** Agent type/name doing the spawning, when known. */
19
- spawningAgentType?: string | null;
20
- /** Target agent type/name requested by the task call. */
21
- targetAgent: string;
22
- /** The spawn-plan receipt, when provided. */
23
- plan?: SpawnPlanReceipt;
24
- }
25
17
  export type SpawnGateOutcome = "allowed" | "rejected";
26
18
  export interface SpawnGateDecision {
27
19
  outcome: SpawnGateOutcome;
@@ -35,4 +27,3 @@ export interface SpawnGateDecision {
35
27
  export declare function findMissingPlanFields(plan: SpawnPlanReceipt | undefined): string[];
36
28
  export declare function decide(childCount: number, threshold: number, plan: SpawnPlanReceipt | undefined): SpawnGateDecision;
37
29
  export declare function evaluateSpawnGate(request: SpawnGateRequest): SpawnGateDecision;
38
- export declare function evaluateReviewerExploreGate(request: ReviewerExploreGateRequest): SpawnGateDecision;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@sayknow-cli/coding-agent",
4
- "version": "0.2.4",
4
+ "version": "0.2.6",
5
5
  "description": "Sayknow-CLI CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/jaybeyond/Sayknow_CLI",
7
7
  "author": "jaybeyond",
@@ -51,12 +51,12 @@
51
51
  "@agentclientprotocol/sdk": "0.21.0",
52
52
  "@babel/parser": "^7.29.3",
53
53
  "@mozilla/readability": "^0.6.0",
54
- "@sayknow-cli/stats": "0.2.4",
55
- "@sayknow-cli/agent-core": "0.2.4",
56
- "@sayknow-cli/ai": "0.2.4",
57
- "@sayknow-cli/natives": "0.2.4",
58
- "@sayknow-cli/tui": "0.2.4",
59
- "@sayknow-cli/utils": "0.2.4",
54
+ "@sayknow-cli/stats": "0.2.6",
55
+ "@sayknow-cli/agent-core": "0.2.6",
56
+ "@sayknow-cli/ai": "0.2.6",
57
+ "@sayknow-cli/natives": "0.2.6",
58
+ "@sayknow-cli/tui": "0.2.6",
59
+ "@sayknow-cli/utils": "0.2.6",
60
60
  "@puppeteer/browsers": "^2.13.0",
61
61
  "@types/turndown": "5.0.6",
62
62
  "@xterm/headless": "^6.0.0",
@@ -5,12 +5,6 @@ import * as path from "node:path";
5
5
  const packageDir = path.join(import.meta.dir, "..");
6
6
  const outputPath = path.join(packageDir, "dist", "skc");
7
7
  const nativeDir = path.join(packageDir, "..", "natives", "native");
8
- // Lazy native tokenizer entrypoint. `agent-core/compaction` loads this from
9
- // the explicit native entrypoint instead of a package-name dynamic require of
10
- // `@sayknow-cli/natives`, because those fail inside Bun standalone `$bunfs`.
11
- // Listing the module here makes the absolute target path exist in the compiled
12
- // bunfs.
13
- const nativeTokenizerEntrypoint = "../natives/native/index.js";
14
8
 
15
9
  function shouldAdhocSignDarwinBinary(): boolean {
16
10
  return process.platform === "darwin";
@@ -72,7 +66,6 @@ async function main(): Promise<void> {
72
66
  "../stats/src/sync-worker.ts",
73
67
  "./src/tools/browser/tab-worker-entry.ts",
74
68
  "./src/eval/js/worker-entry.ts",
75
- nativeTokenizerEntrypoint,
76
69
  "--outfile",
77
70
  "dist/skc",
78
71
  ],