@klarkxy/dsh-git-commit 0.2.0 → 0.2.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.
@@ -1,5 +1,16 @@
1
- import { RpcResult } from "@klarkxy/dsh-plugin-kit/contracts";
1
+ import { ModelRoute, defaultModelRoute, normalizeModelRoute } from "@klarkxy/dsh-model-route";
2
+ import { RpcResult as RpcResult$1 } from "@klarkxy/dsh-plugin-kit/contracts";
2
3
  //#region src/contracts.d.ts
4
+ type RpcResult<T = unknown> = Extract<RpcResult$1<T>, {
5
+ ok: true;
6
+ }> | {
7
+ ok: false;
8
+ error: {
9
+ code: string;
10
+ message: string;
11
+ partial?: PartialCommitResult;
12
+ };
13
+ };
3
14
  declare const PLUGIN_NAME = "@klarkxy/dsh-git-commit";
4
15
  declare const FEATURE_ID = "git-commit";
5
16
  declare const PURPOSE_ID = "git-commit.plan";
@@ -20,12 +31,12 @@ declare const MAX_MESSAGE_CHARS = 120;
20
31
  /** git subprocess timeout. */
21
32
  declare const GIT_TIMEOUT_MS = 30000;
22
33
  declare const SETTINGS_KEY = "current";
23
- /** Plugin-page model selection. Empty provider/model means "follow the default". */
24
- interface CommitModelRoute {
25
- readonly provider: string;
26
- readonly model: string;
27
- readonly reasoningEffort?: string;
28
- }
34
+ /**
35
+ * Plugin-page model selection. Empty provider/model means "follow the default".
36
+ * The value shape, empty default, and 250/80 normalizer live in
37
+ * @klarkxy/dsh-model-route; this alias keeps the commit-specific name.
38
+ */
39
+ type CommitModelRoute = ModelRoute;
29
40
  interface GitCommitSettings {
30
41
  readonly revision: number;
31
42
  readonly model: CommitModelRoute;
@@ -36,12 +47,9 @@ interface GitCommitSettings {
36
47
  */
37
48
  readonly allowFallback: boolean;
38
49
  }
39
- declare const defaultModelRoute: () => CommitModelRoute;
40
50
  declare const defaultSettings: () => GitCommitSettings;
41
51
  /** Untrusted stored flags stay opt-in: anything but a literal true is false. */
42
52
  declare function normalizeFallback(value: unknown): boolean;
43
- /** Untrusted stored routes collapse to the default so a bad row never breaks the run. */
44
- declare function normalizeModelRoute(value: unknown): CommitModelRoute;
45
53
  interface CommitModelInfo {
46
54
  readonly provider: string;
47
55
  readonly model: string;
@@ -61,6 +69,7 @@ interface GitCommitStatus {
61
69
  readonly model?: CommitModelInfo;
62
70
  }
63
71
  interface CommitGroupResult {
72
+ /** Empty only when a created commit's hash could not be read. */
64
73
  readonly hash: string;
65
74
  readonly message: string;
66
75
  readonly files: readonly string[];
@@ -72,6 +81,30 @@ interface CommitRunResult {
72
81
  readonly fallback: boolean;
73
82
  readonly model?: CommitModelInfo;
74
83
  }
84
+ /**
85
+ * Commits that already exist when a later group fails or the run is cancelled.
86
+ * `commits` is the durable outcome; `failure` is why the rest did not run.
87
+ * A recorded commit is never rolled back and never retried by this plugin.
88
+ */
89
+ interface PartialCommitResult {
90
+ readonly branch: string;
91
+ readonly commits: readonly CommitGroupResult[];
92
+ readonly fallback: boolean;
93
+ readonly model?: CommitModelInfo;
94
+ readonly failure: {
95
+ readonly code: string;
96
+ readonly message: string;
97
+ };
98
+ readonly remaining: readonly {
99
+ readonly message: string;
100
+ readonly files: readonly string[];
101
+ }[];
102
+ /** After a rejected commit command, unchanged HEAD could not be proved; completion and ownership are unconfirmed. */
103
+ readonly uncertain?: readonly {
104
+ readonly message: string;
105
+ readonly files: readonly string[];
106
+ }[];
107
+ }
75
108
  //#endregion
76
- export { CONTRACT_VERSION, CommitGroupResult, CommitModelInfo, CommitModelRoute, CommitRunResult, DEFAULT_MAX_OUTPUT_TOKENS, FEATURE_ID, GIT_COMMIT_CLIENT_SERVICE, GIT_TIMEOUT_MS, GitCommitSettings, GitCommitStatus, MAX_MANIFEST_CHARS, MAX_MESSAGE_CHARS, MAX_UNTRACKED_PREVIEW_CHARS, PLUGIN_NAME, PROMPT_VERSION, PURPOSE_ID, RECENT_LOG_COUNT, RPC_CHANNEL, type RpcResult, SCHEMA_VERSION, SETTINGS_KEY, defaultModelRoute, defaultSettings, normalizeFallback, normalizeModelRoute };
109
+ export { CONTRACT_VERSION, CommitGroupResult, CommitModelInfo, CommitModelRoute, CommitRunResult, DEFAULT_MAX_OUTPUT_TOKENS, FEATURE_ID, GIT_COMMIT_CLIENT_SERVICE, GIT_TIMEOUT_MS, GitCommitSettings, GitCommitStatus, MAX_MANIFEST_CHARS, MAX_MESSAGE_CHARS, MAX_UNTRACKED_PREVIEW_CHARS, PLUGIN_NAME, PROMPT_VERSION, PURPOSE_ID, PartialCommitResult, RECENT_LOG_COUNT, RPC_CHANNEL, RpcResult, SCHEMA_VERSION, SETTINGS_KEY, defaultModelRoute, defaultSettings, normalizeFallback, normalizeModelRoute };
77
110
  //# sourceMappingURL=contracts.d.ts.map
package/lib/contracts.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { defaultModelRoute, normalizeModelRoute } from "@klarkxy/dsh-model-route";
1
2
  //#region src/contracts.ts
2
3
  const PLUGIN_NAME = "@klarkxy/dsh-git-commit";
3
4
  const FEATURE_ID = "git-commit";
@@ -19,10 +20,6 @@ const MAX_MESSAGE_CHARS = 120;
19
20
  /** git subprocess timeout. */
20
21
  const GIT_TIMEOUT_MS = 3e4;
21
22
  const SETTINGS_KEY = "current";
22
- const defaultModelRoute = () => ({
23
- provider: "",
24
- model: ""
25
- });
26
23
  const defaultSettings = () => ({
27
24
  revision: 0,
28
25
  model: defaultModelRoute(),
@@ -32,29 +29,6 @@ const defaultSettings = () => ({
32
29
  function normalizeFallback(value) {
33
30
  return value === true;
34
31
  }
35
- function asRecord(value) {
36
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
37
- }
38
- function asText(value) {
39
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
40
- }
41
- /** Untrusted stored routes collapse to the default so a bad row never breaks the run. */
42
- function normalizeModelRoute(value) {
43
- const row = asRecord(value);
44
- if (!row) return defaultModelRoute();
45
- const provider = asText(row.provider) ?? "";
46
- const model = asText(row.model) ?? "";
47
- const effort = asText(row.reasoningEffort);
48
- if (!provider || !model || provider.length > 250 || model.length > 250) return defaultModelRoute();
49
- return effort && effort.length <= 80 ? {
50
- provider,
51
- model,
52
- reasoningEffort: effort
53
- } : {
54
- provider,
55
- model
56
- };
57
- }
58
32
  //#endregion
59
33
  export { CONTRACT_VERSION, DEFAULT_MAX_OUTPUT_TOKENS, FEATURE_ID, GIT_COMMIT_CLIENT_SERVICE, GIT_TIMEOUT_MS, MAX_MANIFEST_CHARS, MAX_MESSAGE_CHARS, MAX_UNTRACKED_PREVIEW_CHARS, PLUGIN_NAME, PROMPT_VERSION, PURPOSE_ID, RECENT_LOG_COUNT, RPC_CHANNEL, SCHEMA_VERSION, SETTINGS_KEY, defaultModelRoute, defaultSettings, normalizeFallback, normalizeModelRoute };
60
34
 
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nexport type { RpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-git-commit'\nexport const FEATURE_ID = 'git-commit'\nexport const PURPOSE_ID = 'git-commit.plan'\nexport const RPC_CHANNEL = '/dsh-git-commit'\nexport const GIT_COMMIT_CLIENT_SERVICE = 'dshGitCommitClient'\nexport const PROMPT_VERSION = 'git-commit.v1'\nexport const SCHEMA_VERSION = 'commit-plan-json.v1'\nexport const CONTRACT_VERSION = 1\n\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 2048\n/** Total character budget for the change manifest sent to the model. */\nexport const MAX_MANIFEST_CHARS = 48_000\n/** Per-file preview cap for untracked files. */\nexport const MAX_UNTRACKED_PREVIEW_CHARS = 2_000\n/** Recent commit subjects supplied as style reference. */\nexport const RECENT_LOG_COUNT = 10\n/** Hard cap for one generated commit message line. */\nexport const MAX_MESSAGE_CHARS = 120\n/** git subprocess timeout. */\nexport const GIT_TIMEOUT_MS = 30_000\nexport const SETTINGS_KEY = 'current'\n\n/** Plugin-page model selection. Empty provider/model means \"follow the default\". */\nexport interface CommitModelRoute {\n readonly provider: string\n readonly model: string\n readonly reasoningEffort?: string\n}\n\nexport interface GitCommitSettings {\n readonly revision: number\n readonly model: CommitModelRoute\n /**\n * Opt-in single commit when the model produced no usable plan. Off by\n * default: an unplanned commit is one the user never reviewed, so a failed\n * or unusable model call rejects the run instead of writing to the index.\n */\n readonly allowFallback: boolean\n}\n\nexport const defaultModelRoute = (): CommitModelRoute => ({ provider: '', model: '' })\n\nexport const defaultSettings = (): GitCommitSettings => ({\n revision: 0, model: defaultModelRoute(), allowFallback: false,\n})\n\n/** Untrusted stored flags stay opt-in: anything but a literal true is false. */\nexport function normalizeFallback(value: unknown): boolean {\n return value === true\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined\n}\n\nfunction asText(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\n/** Untrusted stored routes collapse to the default so a bad row never breaks the run. */\nexport function normalizeModelRoute(value: unknown): CommitModelRoute {\n const row = asRecord(value)\n if (!row) return defaultModelRoute()\n const provider = asText(row.provider) ?? ''\n const model = asText(row.model) ?? ''\n const effort = asText(row.reasoningEffort)\n if (!provider || !model || provider.length > 250 || model.length > 250) return defaultModelRoute()\n return effort && effort.length <= 80 ? { provider, model, reasoningEffort: effort } : { provider, model }\n}\n\nexport interface CommitModelInfo {\n readonly provider: string\n readonly model: string\n /** 'page' is the plugin-page selection; 'default' follows the session or host chat model. */\n readonly source: 'page' | 'default'\n}\n\nexport interface GitCommitStatus {\n readonly available: boolean\n /** Machine-readable reason when unavailable: 'no-session' | 'no-cwd' | 'not-a-repo' | 'no-git'. */\n readonly reason?: string\n readonly detail?: string\n readonly root?: string\n readonly branch?: string\n readonly workspace: { readonly files: number }\n readonly model?: CommitModelInfo\n}\n\nexport interface CommitGroupResult {\n readonly hash: string\n readonly message: string\n readonly files: readonly string[]\n}\n\nexport interface CommitRunResult {\n readonly branch: string\n readonly commits: readonly CommitGroupResult[]\n /** True when the model plan was unavailable and a single fallback commit was used. */\n readonly fallback: boolean\n readonly model?: CommitModelInfo\n}\n"],"mappings":";AAGA,MAAa,cAAc;AAC3B,MAAa,aAAa;AAC1B,MAAa,aAAa;AAC1B,MAAa,cAAc;AAC3B,MAAa,4BAA4B;AACzC,MAAa,iBAAiB;AAC9B,MAAa,iBAAiB;AAC9B,MAAa,mBAAmB;AAEhC,MAAa,4BAA4B;;AAEzC,MAAa,qBAAqB;;AAElC,MAAa,8BAA8B;;AAE3C,MAAa,mBAAmB;;AAEhC,MAAa,oBAAoB;;AAEjC,MAAa,iBAAiB;AAC9B,MAAa,eAAe;AAoB5B,MAAa,2BAA6C;CAAE,UAAU;CAAI,OAAO;AAAG;AAEpF,MAAa,yBAA4C;CACvD,UAAU;CAAG,OAAO,kBAAkB;CAAG,eAAe;AAC1D;;AAGA,SAAgB,kBAAkB,OAAyB;CACzD,OAAO,UAAU;AACnB;AAEA,SAAS,SAAS,OAAqD;CACrE,OAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAAI,QAAmC,KAAA;AAC1G;AAEA,SAAS,OAAO,OAAoC;CAClD,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,KAAA;AACpE;;AAGA,SAAgB,oBAAoB,OAAkC;CACpE,MAAM,MAAM,SAAS,KAAK;CAC1B,IAAI,CAAC,KAAK,OAAO,kBAAkB;CACnC,MAAM,WAAW,OAAO,IAAI,QAAQ,KAAK;CACzC,MAAM,QAAQ,OAAO,IAAI,KAAK,KAAK;CACnC,MAAM,SAAS,OAAO,IAAI,eAAe;CACzC,IAAI,CAAC,YAAY,CAAC,SAAS,SAAS,SAAS,OAAO,MAAM,SAAS,KAAK,OAAO,kBAAkB;CACjG,OAAO,UAAU,OAAO,UAAU,KAAK;EAAE;EAAU;EAAO,iBAAiB;CAAO,IAAI;EAAE;EAAU;CAAM;AAC1G"}
1
+ {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["import { defaultModelRoute, normalizeModelRoute, type ModelRoute } from '@klarkxy/dsh-model-route'\nexport { defaultModelRoute, normalizeModelRoute }\n\n/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nimport type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = Extract<SharedRpcResult<T>, { ok: true }> | {\n ok: false\n error: { code: string; message: string; partial?: PartialCommitResult }\n}\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-git-commit'\nexport const FEATURE_ID = 'git-commit'\nexport const PURPOSE_ID = 'git-commit.plan'\nexport const RPC_CHANNEL = '/dsh-git-commit'\nexport const GIT_COMMIT_CLIENT_SERVICE = 'dshGitCommitClient'\nexport const PROMPT_VERSION = 'git-commit.v1'\nexport const SCHEMA_VERSION = 'commit-plan-json.v1'\nexport const CONTRACT_VERSION = 1\n\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 2048\n/** Total character budget for the change manifest sent to the model. */\nexport const MAX_MANIFEST_CHARS = 48_000\n/** Per-file preview cap for untracked files. */\nexport const MAX_UNTRACKED_PREVIEW_CHARS = 2_000\n/** Recent commit subjects supplied as style reference. */\nexport const RECENT_LOG_COUNT = 10\n/** Hard cap for one generated commit message line. */\nexport const MAX_MESSAGE_CHARS = 120\n/** git subprocess timeout. */\nexport const GIT_TIMEOUT_MS = 30_000\nexport const SETTINGS_KEY = 'current'\n\n/**\n * Plugin-page model selection. Empty provider/model means \"follow the default\".\n * The value shape, empty default, and 250/80 normalizer live in\n * @klarkxy/dsh-model-route; this alias keeps the commit-specific name.\n */\nexport type CommitModelRoute = ModelRoute\n\nexport interface GitCommitSettings {\n readonly revision: number\n readonly model: CommitModelRoute\n /**\n * Opt-in single commit when the model produced no usable plan. Off by\n * default: an unplanned commit is one the user never reviewed, so a failed\n * or unusable model call rejects the run instead of writing to the index.\n */\n readonly allowFallback: boolean\n}\n\nexport const defaultSettings = (): GitCommitSettings => ({\n revision: 0, model: defaultModelRoute(), allowFallback: false,\n})\n\n/** Untrusted stored flags stay opt-in: anything but a literal true is false. */\nexport function normalizeFallback(value: unknown): boolean {\n return value === true\n}\n\nexport interface CommitModelInfo {\n readonly provider: string\n readonly model: string\n /** 'page' is the plugin-page selection; 'default' follows the session or host chat model. */\n readonly source: 'page' | 'default'\n}\n\nexport interface GitCommitStatus {\n readonly available: boolean\n /** Machine-readable reason when unavailable: 'no-session' | 'no-cwd' | 'not-a-repo' | 'no-git'. */\n readonly reason?: string\n readonly detail?: string\n readonly root?: string\n readonly branch?: string\n readonly workspace: { readonly files: number }\n readonly model?: CommitModelInfo\n}\n\nexport interface CommitGroupResult {\n /** Empty only when a created commit's hash could not be read. */\n readonly hash: string\n readonly message: string\n readonly files: readonly string[]\n}\n\nexport interface CommitRunResult {\n readonly branch: string\n readonly commits: readonly CommitGroupResult[]\n /** True when the model plan was unavailable and a single fallback commit was used. */\n readonly fallback: boolean\n readonly model?: CommitModelInfo\n}\n\n/**\n * Commits that already exist when a later group fails or the run is cancelled.\n * `commits` is the durable outcome; `failure` is why the rest did not run.\n * A recorded commit is never rolled back and never retried by this plugin.\n */\nexport interface PartialCommitResult {\n readonly branch: string\n readonly commits: readonly CommitGroupResult[]\n readonly fallback: boolean\n readonly model?: CommitModelInfo\n readonly failure: { readonly code: string; readonly message: string }\n readonly remaining: readonly { readonly message: string; readonly files: readonly string[] }[]\n /** After a rejected commit command, unchanged HEAD could not be proved; completion and ownership are unconfirmed. */\n readonly uncertain?: readonly { readonly message: string; readonly files: readonly string[] }[]\n}\n"],"mappings":";;AAUA,MAAa,cAAc;AAC3B,MAAa,aAAa;AAC1B,MAAa,aAAa;AAC1B,MAAa,cAAc;AAC3B,MAAa,4BAA4B;AACzC,MAAa,iBAAiB;AAC9B,MAAa,iBAAiB;AAC9B,MAAa,mBAAmB;AAEhC,MAAa,4BAA4B;;AAEzC,MAAa,qBAAqB;;AAElC,MAAa,8BAA8B;;AAE3C,MAAa,mBAAmB;;AAEhC,MAAa,oBAAoB;;AAEjC,MAAa,iBAAiB;AAC9B,MAAa,eAAe;AAoB5B,MAAa,yBAA4C;CACvD,UAAU;CAAG,OAAO,kBAAkB;CAAG,eAAe;AAC1D;;AAGA,SAAgB,kBAAkB,OAAyB;CACzD,OAAO,UAAU;AACnB"}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { CommitRunResult, GitCommitSettings, GitCommitStatus, defaultSettings, normalizeFallback, normalizeModelRoute } from "./contracts.js";
1
+ import { CommitRunResult, GitCommitSettings, GitCommitStatus, RpcResult, defaultSettings, normalizeFallback, normalizeModelRoute } from "./contracts.js";
2
2
  import { LlmTextCaller } from "@klarkxy/dsh-plugin-kit";
3
- import { RpcResult } from "@klarkxy/dsh-plugin-kit/contracts";
4
3
  import { Context } from "@deepseek-ai/cordis";
5
4
  //#region src/git.d.ts
6
5
  interface GitRunOptions {
@@ -46,6 +45,7 @@ interface AgentStoreLike {
46
45
  }
47
46
  interface GitCommitServiceDeps {
48
47
  readonly plugin: string;
48
+ readonly onSettingsChanged?: (revision: number) => void;
49
49
  readonly llm: LlmTextCaller;
50
50
  readonly host?: unknown;
51
51
  readonly sessions: SessionStoreLike;
@@ -69,19 +69,23 @@ declare class GitCommitService {
69
69
  private settingsFailure;
70
70
  private settingsAdopted;
71
71
  private disposed;
72
+ /** Aborted on unload so an in-flight model plan receives the same signal as a cancelled request. */
73
+ private readonly lifetime;
72
74
  constructor(deps: GitCommitServiceDeps);
73
75
  /** A refreshed row wins over a pending initial read. */
74
76
  adoptSettings(next: GitCommitSettings): void;
75
77
  /** Existing synchronous snapshot API; host operations wait for initialization first. */
76
78
  getSettings(): GitCommitSettings;
77
79
  ready(): Promise<void>;
80
+ /** Request cancellation and plugin unload share one signal. A disposed service rejects before any new work. */
81
+ private workSignal;
78
82
  private waitForSettings;
79
83
  private selectedModel;
80
84
  updateSettings(patch: Omit<GitCommitSettings, 'revision'>, expectedRevision: number): Promise<GitCommitSettings>;
81
85
  start(): void;
82
86
  dispose(): Promise<void>;
83
87
  private resolveRepo;
84
- status(sessionId: string): Promise<GitCommitStatus>;
88
+ status(sessionId: string, signal?: AbortSignal): Promise<GitCommitStatus>;
85
89
  commit(sessionId: string, signal?: AbortSignal): Promise<CommitRunResult>;
86
90
  private runCommit;
87
91
  }