@gitgov/core 2.7.0 → 2.7.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,7 +1,7 @@
1
1
  import { S as SessionStore } from './session_store-I4Z6PW2c.js';
2
2
  import { k as ISessionManager, a as GitGovSession, A as ActorState, S as SyncPreferencesUpdate, K as KeyProvider, h as FileLister, F as FsFileListerOptions, i as FileListOptions, j as FileStats, G as GitGovConfig } from './index-LULVRsCZ.js';
3
- import { q as IIdentityAdapter, u as IdentityAdapterDependencies, S as SyncStateModuleDependencies, p as IEventStream } from './sync_state-Bn_LogJ2.js';
4
- import { A as ActorPayload, d as ActorRecord, G as GitGovRecord, m as ExecutionRecord, z as RecordStores, f as AgentRecord } from './record_projection.types-Dz9YU3r9.js';
3
+ import { q as IIdentityAdapter, u as IdentityAdapterDependencies, S as SyncStateModuleDependencies, p as IEventStream } from './sync_state-C2a2RuBQ.js';
4
+ import { A as ActorPayload, d as ActorRecord, G as GitGovRecord, l as ExecutionRecord, y as RecordStores, f as AgentRecord } from './record_projection.types-D9NkQbL_.js';
5
5
 
6
6
  /**
7
7
  * SessionManager - Local Session State Manager
package/dist/src/fs.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { R as RecordStore, I as IdEncoder, a as IRecordProjector, G as GitGovRecord, b as IRecordProjection, c as IndexData, P as ProjectionContext } from './record_projection.types-Dz9YU3r9.js';
2
- export { D as DEFAULT_ID_ENCODER } from './record_projection.types-Dz9YU3r9.js';
1
+ import { R as RecordStore, I as IdEncoder, a as IRecordProjector, G as GitGovRecord, b as IRecordProjection, c as IndexData, P as ProjectionContext } from './record_projection.types-D9NkQbL_.js';
2
+ export { D as DEFAULT_ID_ENCODER } from './record_projection.types-D9NkQbL_.js';
3
3
  import { C as ConfigStore, G as GitGovConfig, a as GitGovSession, I as IGitModule, b as GitModuleDependencies, E as ExecOptions, c as ExecResult, d as ChangedFile, e as GetCommitHistoryOptions, f as CommitInfo, g as CommitAuthor } from './index-LULVRsCZ.js';
4
4
  export { F as FsFileListerOptions } from './index-LULVRsCZ.js';
5
- import { C as ConfigManager, I as ILintModule, L as LintOptions, a as LintReport, F as FixRecordOptions, b as FixReport, R as RecordStores, c as LintRecordContext, d as LintResult, e as ISyncStateModule, S as SyncStateModuleDependencies, f as StateDeltaFile, g as ConflictDiff, h as IntegrityViolation, A as AuditStateOptions, i as AuditStateReport, j as SyncStatePushOptions, k as SyncStatePushResult, l as SyncStatePullOptions, m as SyncStatePullResult, n as SyncStateResolveOptions, o as SyncStateResolveResult, p as IEventStream } from './sync_state-Bn_LogJ2.js';
5
+ import { C as ConfigManager, I as ILintModule, L as LintOptions, a as LintReport, F as FixRecordOptions, b as FixReport, R as RecordStores, c as LintRecordContext, d as LintResult, e as ISyncStateModule, S as SyncStateModuleDependencies, f as StateDeltaFile, g as ConflictDiff, h as IntegrityViolation, A as AuditStateOptions, i as AuditStateReport, j as SyncStatePushOptions, k as SyncStatePushResult, l as SyncStatePullOptions, m as SyncStatePullResult, n as SyncStateResolveOptions, o as SyncStateResolveResult, p as IEventStream } from './sync_state-C2a2RuBQ.js';
6
6
  import { S as SessionStore } from './session_store-I4Z6PW2c.js';
7
- import { S as SessionManager, I as IProjectInitializer, E as EnvironmentValidation, F as FsWorktreeSyncStateDependencies, a as FsWorktreeSyncStateConfig, b as IAgentRunner, P as ProtocolHandlerRegistry, A as AgentRunnerDependencies, R as RunOptions, c as AgentResponse } from './agent_runner-CHDkBfPZ.js';
8
- export { f as FsFileLister, d as FsKeyProvider, e as FsKeyProviderOptions } from './agent_runner-CHDkBfPZ.js';
7
+ import { S as SessionManager, I as IProjectInitializer, E as EnvironmentValidation, F as FsWorktreeSyncStateDependencies, a as FsWorktreeSyncStateConfig, b as IAgentRunner, P as ProtocolHandlerRegistry, A as AgentRunnerDependencies, R as RunOptions, c as AgentResponse } from './agent_runner-DijNVjaF.js';
8
+ export { f as FsFileLister, d as FsKeyProvider, e as FsKeyProviderOptions } from './agent_runner-DijNVjaF.js';
9
9
 
10
10
  /**
11
11
  * Serializer for FsRecordStore - allows custom serialization
@@ -313,6 +313,10 @@ declare class FsLintModule implements IFsLintModule {
313
313
  * Delegates to LintModule.lintRecord() for pure validation.
314
314
  */
315
315
  lintRecord(record: GitGovRecord, context: LintRecordContext): LintResult[];
316
+ /**
317
+ * Delegates to LintModule.lintRecordReferences() for prefix validation.
318
+ */
319
+ lintRecordReferences(record: GitGovRecord, context: LintRecordContext): LintResult[];
316
320
  /**
317
321
  * Delegates to LintModule.fixRecord() for pure fix.
318
322
  */
@@ -1244,13 +1248,19 @@ declare class FsWorktreeSyncStateModule implements ISyncStateModule {
1244
1248
  getWorktreePath(): string;
1245
1249
  /** [WTSYNC-A1..A6] Ensures worktree exists and is healthy */
1246
1250
  ensureWorktree(): Promise<void>;
1251
+ /**
1252
+ * [WTSYNC-A7] Remove .gitignore from state branch if it exists.
1253
+ * The worktree module filters files in code (shouldSyncFile()), not via .gitignore.
1254
+ * Legacy state branches initialized by FsSyncState may have a .gitignore — remove it.
1255
+ */
1256
+ private removeLegacyGitignore;
1247
1257
  /** Check worktree health */
1248
1258
  private checkWorktreeHealth;
1249
1259
  /** Remove worktree cleanly */
1250
1260
  private removeWorktree;
1251
- /** [WTSYNC-B1..B14] Push local state to remote */
1261
+ /** [WTSYNC-B1..B16] Push local state to remote */
1252
1262
  pushState(options: SyncStatePushOptions): Promise<SyncStatePushResult>;
1253
- /** [WTSYNC-C1..C8] Pull remote state */
1263
+ /** [WTSYNC-C1..C9] Pull remote state */
1254
1264
  pullState(options?: SyncStatePullOptions): Promise<SyncStatePullResult>;
1255
1265
  /** [WTSYNC-D1..D7] Resolve rebase conflict */
1256
1266
  resolveConflict(options: SyncStateResolveOptions): Promise<SyncStateResolveResult>;
@@ -1276,6 +1286,12 @@ declare class FsWorktreeSyncStateModule implements ISyncStateModule {
1276
1286
  private execGit;
1277
1287
  /** Execute git command in worktree context (throws on non-zero exit) */
1278
1288
  private execInWorktree;
1289
+ /**
1290
+ * [WTSYNC-B16] Check if local gitgov-state has commits not present on remote.
1291
+ * Returns { ahead: true } if local has unpushed commits or remote branch doesn't exist.
1292
+ * Also returns { remoteExists } to let caller decide whether reconciliation is needed.
1293
+ */
1294
+ private isLocalAheadOfRemote;
1279
1295
  /** Calculate file delta (uncommitted changes in worktree) */
1280
1296
  private calculateFileDelta;
1281
1297
  /** [WTSYNC-B4/B9/B10/B11] Stage only syncable files from delta (adds, mods, and deletions) */
package/dist/src/fs.js CHANGED
@@ -1798,20 +1798,10 @@ var embedded_metadata_schema_default = {
1798
1798
  "execution",
1799
1799
  "changelog",
1800
1800
  "feedback",
1801
- "cycle",
1802
- "custom"
1801
+ "cycle"
1803
1802
  ],
1804
1803
  description: "The type of the record contained in the payload."
1805
1804
  },
1806
- schemaUrl: {
1807
- type: "string",
1808
- description: "Optional URL to a custom schema for the payload."
1809
- },
1810
- schemaChecksum: {
1811
- type: "string",
1812
- pattern: "^[a-fA-F0-9]{64}$",
1813
- description: "Optional SHA-256 checksum of the custom schema."
1814
- },
1815
1805
  payloadChecksum: {
1816
1806
  type: "string",
1817
1807
  pattern: "^[a-fA-F0-9]{64}$",
@@ -2035,32 +2025,6 @@ var embedded_metadata_schema_default = {
2035
2025
  }
2036
2026
  },
2037
2027
  else: false
2038
- },
2039
- {
2040
- if: {
2041
- properties: {
2042
- header: {
2043
- type: "object",
2044
- properties: {
2045
- type: {
2046
- const: "custom"
2047
- }
2048
- }
2049
- }
2050
- }
2051
- },
2052
- then: {
2053
- properties: {
2054
- header: {
2055
- type: "object",
2056
- required: [
2057
- "schemaUrl",
2058
- "schemaChecksum"
2059
- ]
2060
- }
2061
- }
2062
- },
2063
- else: false
2064
2028
  }
2065
2029
  ],
2066
2030
  examples: [
@@ -3551,6 +3515,12 @@ var FsLintModule = class {
3551
3515
  lintRecord(record, context) {
3552
3516
  return this.lintModule.lintRecord(record, context);
3553
3517
  }
3518
+ /**
3519
+ * Delegates to LintModule.lintRecordReferences() for prefix validation.
3520
+ */
3521
+ lintRecordReferences(record, context) {
3522
+ return this.lintModule.lintRecordReferences(record, context);
3523
+ }
3554
3524
  /**
3555
3525
  * Delegates to LintModule.fixRecord() for pure fix.
3556
3526
  */
@@ -3803,6 +3773,14 @@ var FsLintModule = class {
3803
3773
  const namingResults = this.validateFileNaming(record, recordId, filePath, entityType);
3804
3774
  results.push(...namingResults);
3805
3775
  }
3776
+ if (options.validateReferences) {
3777
+ const refResults = this.lintModule.lintRecordReferences(record, {
3778
+ recordId,
3779
+ entityType,
3780
+ filePath
3781
+ });
3782
+ results.push(...refResults);
3783
+ }
3806
3784
  } catch (error) {
3807
3785
  if (error instanceof DetailedValidationError) {
3808
3786
  const hasAdditionalProperties = error.errors.some(
@@ -7668,7 +7646,7 @@ var FsWorktreeSyncStateModule = class {
7668
7646
  this.gitgovPath = path9__default.join(this.worktreePath, ".gitgov");
7669
7647
  }
7670
7648
  // ═══════════════════════════════════════════════
7671
- // Section A: Worktree Management (WTSYNC-A1..A6)
7649
+ // Section A: Worktree Management (WTSYNC-A1..A7)
7672
7650
  // ═══════════════════════════════════════════════
7673
7651
  /** [WTSYNC-A4] Returns the worktree path */
7674
7652
  getWorktreePath() {
@@ -7679,6 +7657,7 @@ var FsWorktreeSyncStateModule = class {
7679
7657
  const health = await this.checkWorktreeHealth();
7680
7658
  if (health.healthy) {
7681
7659
  logger7.debug("Worktree is healthy");
7660
+ await this.removeLegacyGitignore();
7682
7661
  return;
7683
7662
  }
7684
7663
  if (health.exists && !health.healthy) {
@@ -7696,6 +7675,26 @@ var FsWorktreeSyncStateModule = class {
7696
7675
  error instanceof Error ? error : void 0
7697
7676
  );
7698
7677
  }
7678
+ await this.removeLegacyGitignore();
7679
+ }
7680
+ /**
7681
+ * [WTSYNC-A7] Remove .gitignore from state branch if it exists.
7682
+ * The worktree module filters files in code (shouldSyncFile()), not via .gitignore.
7683
+ * Legacy state branches initialized by FsSyncState may have a .gitignore — remove it.
7684
+ */
7685
+ async removeLegacyGitignore() {
7686
+ const gitignorePath = path9__default.join(this.worktreePath, ".gitignore");
7687
+ if (!existsSync(gitignorePath)) return;
7688
+ logger7.info("Removing legacy .gitignore from state branch");
7689
+ try {
7690
+ await this.execInWorktree(["rm", ".gitignore"]);
7691
+ await this.execInWorktree(["commit", "-m", "gitgov: remove legacy .gitignore (filtering is in code)"]);
7692
+ } catch {
7693
+ try {
7694
+ await promises.unlink(gitignorePath);
7695
+ } catch {
7696
+ }
7697
+ }
7699
7698
  }
7700
7699
  /** Check worktree health */
7701
7700
  async checkWorktreeHealth() {
@@ -7741,9 +7740,9 @@ var FsWorktreeSyncStateModule = class {
7741
7740
  }
7742
7741
  }
7743
7742
  // ═══════════════════════════════════════════════
7744
- // Section B: Push Operations (WTSYNC-B1..B14)
7743
+ // Section B: Push Operations (WTSYNC-B1..B16)
7745
7744
  // ═══════════════════════════════════════════════
7746
- /** [WTSYNC-B1..B14] Push local state to remote */
7745
+ /** [WTSYNC-B1..B16] Push local state to remote */
7747
7746
  async pushState(options) {
7748
7747
  const { actorId, dryRun = false, force = false } = options;
7749
7748
  const log = (msg) => logger7.debug(`[pushState] ${msg}`);
@@ -7771,11 +7770,53 @@ var FsWorktreeSyncStateModule = class {
7771
7770
  const delta = rawDelta.filter((f) => shouldSyncFile2(f.file));
7772
7771
  log(`Delta: ${delta.length} syncable files (${rawDelta.length} total)`);
7773
7772
  if (delta.length === 0) {
7773
+ const { ahead: aheadOfRemote, remoteExists } = await this.isLocalAheadOfRemote();
7774
+ if (!aheadOfRemote) {
7775
+ return {
7776
+ success: true,
7777
+ filesSynced: 0,
7778
+ sourceBranch: options.sourceBranch ?? "current",
7779
+ commitHash: null,
7780
+ commitMessage: null,
7781
+ conflictDetected: false
7782
+ };
7783
+ }
7784
+ log("No uncommitted changes but local is ahead of remote \u2014 pushing existing commits");
7785
+ if (remoteExists && !force) {
7786
+ try {
7787
+ await this.execInWorktree(["pull", "--rebase", "origin", this.stateBranchName]);
7788
+ } catch (err) {
7789
+ if (await this.isRebaseInProgress()) {
7790
+ const affectedFiles = await this.getConflictedFiles();
7791
+ return {
7792
+ success: false,
7793
+ filesSynced: 0,
7794
+ sourceBranch: options.sourceBranch ?? "current",
7795
+ commitHash: null,
7796
+ commitMessage: null,
7797
+ conflictDetected: true,
7798
+ conflictInfo: {
7799
+ type: "rebase_conflict",
7800
+ affectedFiles,
7801
+ message: "Rebase conflict during push reconciliation (local ahead, no uncommitted changes)",
7802
+ resolutionSteps: [
7803
+ `Edit conflicted files in ${this.worktreePath}/.gitgov/`,
7804
+ 'Run `gitgov sync resolve --reason "..."` to finalize'
7805
+ ]
7806
+ },
7807
+ error: "Rebase conflict during push reconciliation"
7808
+ };
7809
+ }
7810
+ throw err;
7811
+ }
7812
+ }
7813
+ await this.execInWorktree(["push", "origin", this.stateBranchName]);
7814
+ const currentHead = (await this.execInWorktree(["rev-parse", "HEAD"])).trim();
7774
7815
  return {
7775
7816
  success: true,
7776
7817
  filesSynced: 0,
7777
7818
  sourceBranch: options.sourceBranch ?? "current",
7778
- commitHash: null,
7819
+ commitHash: currentHead,
7779
7820
  commitMessage: null,
7780
7821
  conflictDetected: false
7781
7822
  };
@@ -7870,9 +7911,9 @@ var FsWorktreeSyncStateModule = class {
7870
7911
  return result;
7871
7912
  }
7872
7913
  // ═══════════════════════════════════════════════
7873
- // Section C: Pull Operations (WTSYNC-C1..C8)
7914
+ // Section C: Pull Operations (WTSYNC-C1..C9)
7874
7915
  // ═══════════════════════════════════════════════
7875
- /** [WTSYNC-C1..C8] Pull remote state */
7916
+ /** [WTSYNC-C1..C9] Pull remote state */
7876
7917
  async pullState(options) {
7877
7918
  const { forceReindex = false, force = false } = options ?? {};
7878
7919
  const log = (msg) => logger7.debug(`[pullState] ${msg}`);
@@ -8298,6 +8339,33 @@ var FsWorktreeSyncStateModule = class {
8298
8339
  async execInWorktree(args, options) {
8299
8340
  return this.execGit(["-C", this.worktreePath, ...args], options);
8300
8341
  }
8342
+ /**
8343
+ * [WTSYNC-B16] Check if local gitgov-state has commits not present on remote.
8344
+ * Returns { ahead: true } if local has unpushed commits or remote branch doesn't exist.
8345
+ * Also returns { remoteExists } to let caller decide whether reconciliation is needed.
8346
+ */
8347
+ async isLocalAheadOfRemote() {
8348
+ try {
8349
+ await this.execGit(["ls-remote", "--exit-code", "origin", this.stateBranchName]);
8350
+ } catch {
8351
+ return { ahead: true, remoteExists: false };
8352
+ }
8353
+ try {
8354
+ await this.execInWorktree(["fetch", "origin", this.stateBranchName]);
8355
+ } catch {
8356
+ return { ahead: false, remoteExists: true };
8357
+ }
8358
+ try {
8359
+ const count = (await this.execInWorktree([
8360
+ "rev-list",
8361
+ `origin/${this.stateBranchName}..HEAD`,
8362
+ "--count"
8363
+ ])).trim();
8364
+ return { ahead: parseInt(count, 10) > 0, remoteExists: true };
8365
+ } catch {
8366
+ return { ahead: true, remoteExists: true };
8367
+ }
8368
+ }
8301
8369
  /** Calculate file delta (uncommitted changes in worktree) */
8302
8370
  async calculateFileDelta() {
8303
8371
  try {