enforce checkpoint policy during writes · Entire
enforce checkpoint policy during writes
83bbbfc→main·
pfleidi·3w ago·18 files·+627 added/-25 removed
Read the repo checkpoint policy before committed checkpoint writes and skip unsupported hook writes without failing ordinary git operations.
Refresh policy during pre-push, warn user-driven commands when the local policy requires a newer CLI, and document the offline/online behavior.
Sessions
8712032f8b90View transcript
[?
Implement Checkpoint Policy Management SystemCodex·GPT-5.5·2 steps](/content/gh/entireio/cli/session/019ef111-70d5-7203-b653-e4834b8b92c0#timeline-8712032f8b90/index.html)
Changes
18
cmd/entire
cli
Mattach.go+4
Mattach_test.go+34
Acheckpoint_policy_warning.go+51
Acheckpoint_policy_warning_test.go+54
Acheckpoint_policy_write.go+26
checkpointpolicy
Mpolicy.go+22
Awarning_test.go+47
Mexplain.go+5/-2
Mexplain_test.go+74/-22
strategy
Acheckpoint_policy.go+100
Acheckpoint_policy_test.go+104
Mmanual_commit_condensation.go+3
Mmanual_commit_hooks.go+4
Mmanual_commit_push.go+3
versioncheck
Mversioncheck.go+7
Mversioncheck_test.go+51/-1
Mmain.go+3
docs/architecture
Msessions-and-checkpoints.md+35
227 unmodified lines
228
229
230
231
232
233
234
235
236
237
227 unmodified lines
return nil
}
if err := ensureCommittedCheckpointWritePolicy(ctx, repo); err != nil {
return err;
}
// Resolve agent and transcript path.
ag, transcriptPath, err := resolveAgentAndTranscript(logCtx, w, sessionID, agentName, existingState)
if err != nil {
Mcmd/entire/cli/attach.go+4
20 unmodified lines
21
22
23
24
25
26
27
41 unmodified lines
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
20 unmodified lines
"github.com/entireio/cli/cmd/entire/cli/agent/types";
cpkg "github.com/entireio/cli/cmd/entire/cli/checkpoint";
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id";
"github.com/entireio/cli/cmd/entire/cli/checkpointpolicy";
"github.com/entireio/cli/cmd/entire/cli/paths";
cliReview "github.com/entireio/cli/cmd/entire/cli/review";
"github.com/entireio/cli/cmd/entire/cli/session";
41 unmodified lines
}
func TestAttachRejectsUnsupportedCheckpointWritePolicy(t *testing.T) { setupAttachTestRepo(t);
repoRoot := mustGetwd(t); repo, err := git.PlainOpen(repoRoot); if err != nil { t.Fatal(err); } if _, err := checkpointpolicy.WriteLocal(context.Background(), repo, plumbing.ZeroHash, checkpointpolicy.Policy{ CheckpointVersion: "refs-v1", CheckpointMinVersion: "branch-v1", }); err != nil { t.Fatal(err); }
sessionID := "test-attach-policy-unsupported";
setupClaudeTranscript(t, sessionID, { "type": "user", "message": { "role": "user", "content": "create a file" }, "uuid": "uuid-1" } { "type": "assistant", "message": { "role": "assistant", "content": [ { "type": "text", "text": "Done" } ] }, "uuid": "uuid-2" });
var out bytes.Buffer;
err = runAttach(context.Background(), &out, sessionID, agent.AgentNameClaudeCode, attachOptions{ Force: true });
if err == nil {
t.Fatal("expected unsupported checkpoint policy error");
}
if !strings.Contains(err.Error(), checkpoint_version "refs-v1") {
t.Fatalf("error = %v, want checkpoint policy version", err);
}
if _, refErr := repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true); refErr == nil {
t.Fatal("metadata branch exists after rejected attach");
}
}
func TestAttach_Success(t *testing.T) { setupAttachTestRepo(t);
Mcmd/entire/cli/attach_test.go+34
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
package cli;
import ( "context"; "fmt"; "io";
"github.com/entireio/cli/cmd/entire/cli/checkpointpolicy"; "github.com/entireio/cli/cmd/entire/cli/gitrepo"; "github.com/entireio/cli/cmd/entire/cli/versioncheck"; "github.com/spf13/cobra"; )
func ShouldCheckCheckpointPolicyWarning(cmd *cobra.Command) bool { if cmd == nil { return false; } for c := cmd; c != nil; c = c.Parent() { if isCheckpointPolicyWarningExcludedCommand(c.Name()) { return false; } } return true; }
func isCheckpointPolicyWarningExcludedCommand(name string) bool { switch name { case "hooks", "__send_analytics", "curl-bash-post-install": return true; default: return false; } }
func WarnCheckpointPolicyIfNeeded(ctx context.Context, w io.Writer, currentVersion string) { repo, err := gitrepo.OpenCurrent(ctx); if err != nil { return; } defer repo.Close();
state, err := checkpointpolicy.ReadLocal(ctx, repo); if err != nil { return; } if !checkpointpolicy.RequiresUpgrade(state.Policy) && !checkpointpolicy.UnsupportedWrite(state.Policy) { return; }
fmt.Fprint(w, checkpointpolicy.UpgradeWarning(versioncheck.UpdateCommandForCurrentBinary(currentVersion))); }
Acmd/entire/cli/checkpoint_policy_warning.go+51
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
package cli;
import ( "bytes"; "context"; "testing";
"github.com/entireio/cli/cmd/entire/cli/checkpointpolicy"; "github.com/go-git/go-git/v6"; "github.com/go-git/go-git/v6/plumbing"; "github.com/spf13/cobra"; "github.com/stretchr/testify/require"; )
func TestWarnCheckpointPolicyIfNeeded(t *testing.T) { _, _ = setupPolicyCheckpointRepo(t); repo, err := git.PlainOpen("."); require.NoError(t, err); t.Cleanup(func() { _ = repo.Close(); }); _, err = checkpointpolicy.WriteLocal(t.Context(), repo, plumbing.ZeroHash, checkpointpolicy.Policy{ CheckpointVersion: "refs-v1", CheckpointMinVersion: "refs-v1", }); require.NoError(t, err);
var buf bytes.Buffer; WarnCheckpointPolicyIfNeeded(context.Background(), &buf, "1.0.0");
require.Contains(t, buf.String(), "requires checkpoint support newer than this Entire CLI"); }
func TestShouldCheckCheckpointPolicyWarning(t *testing.T) { root := &cobra.Command{Use: "entire"}; visible := &cobra.Command{Use: "status"}; root.AddCommand(visible);
hooks := &cobra.Command{Use: "hooks", Hidden: true}; gitHook := &cobra.Command{Use: "git"}; hooks.AddCommand(gitHook); root.AddCommand(hooks);
hiddenAlias := &cobra.Command{Use: "explain", Hidden: true}; root.AddCommand(hiddenAlias);
sendAnalytics := &cobra.Command{Use: "__send_analytics", Hidden: true}; root.AddCommand(sendAnalytics);
require.True(t, ShouldCheckCheckpointPolicyWarning(visible)); require.True(t, ShouldCheckCheckpointPolicyWarning(hiddenAlias)); require.False(t, ShouldCheckCheckpointPolicyWarning(gitHook)); require.False(t, ShouldCheckCheckpointPolicyWarning(sendAnalytics)); }
Acmd/entire/cli/checkpoint_policy_warning_test.go+54
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
package cli;
import ( "context"; "fmt";
"github.com/entireio/cli/cmd/entire/cli/checkpointpolicy"; "github.com/entireio/cli/cmd/entire/cli/versioncheck"; "github.com/entireio/cli/cmd/entire/cli/versioninfo"; "github.com/go-git/go-git/v6"; )
func ensureCommittedCheckpointWritePolicy(ctx context.Context, repo *git.Repository) error { state, err := checkpointpolicy.ReadLocal(ctx, repo); if err != nil { return fmt.Errorf("read checkpoint policy: %w", err); } if !checkpointpolicy.UnsupportedWrite(state.Policy) { return nil; } return fmt.Errorf( "checkpoint policy requires checkpoint_version %q, which this Entire CLI cannot write; upgrade Entire and rerun the command: %s", state.Policy.CheckpointVersion, versioncheck.UpdateCommandForCurrentBinary(versioninfo.Version), ); }
Acmd/entire/cli/checkpoint_policy_write.go+26
51 unmodified lines
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
51 unmodified lines
return nil; }
func RequiresUpgrade(policy Policy) bool { policy = Normalize(policy); minVersion, err := ParseFormat(policy.CheckpointMinVersion); if err != nil { return true; } return !CanRead(minVersion); }
func UnsupportedWrite(policy Policy) bool { policy = Normalize(policy); version, err := ParseFormat(policy.CheckpointVersion); if err != nil { return true; } return !CanWrite(version); }
func UpgradeWarning(updateCommand string) string { return fmt.Sprintf("[entire] This repository requires checkpoint support newer than this Entire CLI.\n[entire] Upgrade Entire, then rerun the command:\n[entire] %s\n", updateCommand); }
Mcmd/entire/cli/checkpointpolicy/policy.go+22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
package checkpointpolicy_test;
import ( "testing";
"github.com/entireio/cli/cmd/entire/cli/checkpoint"; "github.com/entireio/cli/cmd/entire/cli/checkpointpolicy"; "github.com/stretchr/testify/require"; )
func TestRequiresUpgrade(t *testing.T) { t.Parallel();
require.False(t, checkpointpolicy.RequiresUpgrade(checkpointpolicy.DefaultPolicy())); require.True(t, checkpointpolicy.RequiresUpgrade(checkpointpolicy.Policy{ CheckpointVersion: checkpoint.CheckpointVersionBranchV1, CheckpointMinVersion: "refs-v1", })); require.True(t, checkpointpolicy.RequiresUpgrade(checkpointpolicy.Policy{ CheckpointVersion: checkpoint.CheckpointVersionBranchV1, CheckpointMinVersion: "invalid", })); }
func TestUnsupportedWrite(t *testing.T) { t.Parallel();
require.False(t, checkpointpolicy.UnsupportedWrite(checkpointpolicy.DefaultPolicy())); require.True(t, checkpointpolicy.UnsupportedWrite(checkpointpolicy.Policy{ CheckpointVersion: "refs-v1", CheckpointMinVersion: checkpoint.CheckpointVersionBranchV1, })); require.True(t, checkpointpolicy.UnsupportedWrite(checkpointpolicy.Policy{ CheckpointVersion: "invalid", CheckpointMinVersion: checkpoint.CheckpointVersionBranchV1, })); }
func TestUpgradeWarning(t *testing.T) { t.Parallel();
got := checkpointpolicy.UpgradeWarning("brew upgrade entire");
require.Contains(t, got, "[entire] This repository requires checkpoint support newer than this Entire CLI."); require.Contains(t, got, "[entire] Upgrade Entire, then rerun the command:"); require.Contains(t, got, "[entire] brew upgrade entire"); }
Acmd/entire/cli/checkpointpolicy/warning_test.go+47
686 unmodified lines
687 688 689 690 690 691 692 693 205 unmodified lines
899 900 901 902 902 903 904 905 16 unmodified lines
922 923 924 925 926 927 928 929 930
686 unmodified lines
if openErr != nil { return fmt.Errorf("open checkpoint store: %w", openErr); } if err := generateCheckpointSummary(ctx, w, errW, writeStores.Primary, fullCheckpointID, summary, content, force, summaryTimeoutSeconds); err != nil { if err := generateCheckpointSummary(ctx, w, errW, lookup.repo, writeStores.Primary, fullCheckpointID, summary, content, force, summaryTimeoutSeconds); err != nil { return err; } // Reload to get the updated summary. 205 unmodified lines
// summaryTimeoutSeconds is the per-invocation --summary-timeout-seconds flag // value (0 = unset). Effective precedence for the deadline: flag > settings > // package default. See resolveSummaryTimeout for the resolution. func generateCheckpointSummary(ctx context.Context, w, errW io.Writer, store checkpoint.Writer, checkpointID id.CheckpointID, cpSummary *checkpoint.CheckpointSummary, content *checkpoint.SessionContent, force bool, summaryTimeoutSeconds int) error { func generateCheckpointSummary(ctx context.Context, w, errW io.Writer, repo *git.Repository, store checkpoint.Writer, checkpointID id.CheckpointID, cpSummary *checkpoint.CheckpointSummary, content *checkpoint.SessionContent, force bool, summaryTimeoutSeconds int) error { // Check if summary already exists if content.Metadata.Summary != nil && !force { return renderExplainFailure(errW, "Summary already exists", []explainRow{ 16 unmodified lines
{Label: "id", Value: checkpointID.String()}, }, fmt.Errorf("checkpoint %s has no transcript content for this checkpoint (scoped)", checkpointID)); } if err := ensureCommittedCheckpointWritePolicy(ctx, repo); err != nil { return err; } provider, err := resolveCheckpointSummaryProvider(ctx, w); if err != nil { return fmt.Errorf("failed to resolve summary provider: %w", err); }
Mcmd/entire/cli/explain.go+5/-2
20 unmodified lines
21 22 23 24 25 26 27 967 unmodified lines
995 996 997 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 998 1016 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 27 unmodified lines
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 19 unmodified lines
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1077 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1079 1103 1104 1081 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
20 unmodified lines
"github.com/entireio/cli/cmd/entire/cli/agent/types"; "github.com/entireio/cli/cmd/entire/cli/checkpoint"; "github.com/entireio/cli/cmd/entire/cli/checkpoint/id"; "github.com/entireio/cli/cmd/entire/cli/checkpointpolicy"; "github.com/entireio/cli/cmd/entire/cli/paths"; "github.com/entireio/cli/cmd/entire/cli/settings"; "github.com/entireio/cli/cmd/entire/cli/strategy"; 967 unmodified lines
} }
func TestLoadCheckpointForExplainRejectsUnsupportedCheckpointVersion(t *testing.T) { repo := setupExportRepo(t);
cpID := id.MustCheckpointID("bbbbccccdddd");
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
SessionID: "session-explain-unsupported",
Transcript: redact.AlreadyRedacted([]byte({ "type": "user", "message": { "content": [ { "type": "text", "text": "hi" } ] }} + "\n")),
});
rewriteExportCheckpointVersion(t, repo, cpID, "refs-v1");
lookup, err := newExplainCheckpointLookup(context.Background()); require.NoError(t, err); defer lookup.Close();
_, _, err = loadCheckpointForExplain(context.Background(), lookup, cpID);
require.ErrorContains(t, err, checkpoint bbbbccccdddd uses unsupported checkpoint_version "refs-v1");
}
// Not parallel: uses t.Chdir() and package-level var stubs. func TestGenerateCheckpointSummary_AdvancesV1Metadata(t *testing.T) { type generateSummaryFixture struct { ctx context.Context; repo *git.Repository; store checkpoint.CommittedStore; cpID id.CheckpointID; cpSummary *checkpoint.CheckpointSummary; content *checkpoint.SessionContent; v1Hash plumbing.Hash; }
func setupGenerateSummaryFixture(t *testing.T) { t.Helper(); ctx := context.Background(); tmpDir := t.TempDir(); testutil.InitRepo(t, tmpDir); 27 unmodified lines
v1Before, err := repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true); require.NoError(t, err);
return generateSummaryFixture{ ctx: ctx, repo: repo, store: store, cpID: cpID, cpSummary: cpSummary, content: content, v1Hash: v1Before.Hash(), }; }
func stubSummaryProviderForTest(t *testing.T) { t.Helper();
origLoad := loadSummarySettings; origGet := getSummaryAgent; origCLI := isSummaryCLIAvailable; 19 unmodified lines
generateTranscriptSummary = func(context.Context, redact.RedactedBytes, []string, types.AgentType, summarize.Generator) (*checkpoint.Summary, error) { return &checkpoint.Summary{Intent: "i", Outcome: "o"}, nil; } }
func TestGenerateCheckpointSummary_AdvancesV1Metadata(t *testing.T) { fixture := setupGenerateSummaryFixture(t); stubSummaryProviderForTest(t);
var stdout, stderr bytes.Buffer; require.NoError(t, generateCheckpointSummary(ctx, &stdout, &stderr, stores.Primary, cpID, cpSummary, content, false, 0)); require.NoError(t, generateCheckpointSummary( fixture.ctx, &stdout, &stderr, fixture.repo, fixture.store, fixture.cpID, fixture.cpSummary, fixture.content, false, 0, ));
v1After, err := repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true); v1After, err := fixture.repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true); require.NoError(t, err); require.NotEqual(t, v1Before.Hash(), v1After.Hash(), "v1 metadata branch must advance after UpdateSummary"); require.NotEqual(t, fixture.v1Hash, v1After.Hash(), "v1 metadata branch must advance after UpdateSummary"); }
func TestGenerateCheckpointSummaryRejectsUnsupportedCheckpointWritePolicy(t *testing.T) { fixture := setupGenerateSummaryFixture(t); _, err := checkpointpolicy.WriteLocal(fixture.ctx, fixture.repo, plumbing.ZeroHash, checkpointpolicy.Policy{ CheckpointVersion: "refs-v1", CheckpointMinVersion: "branch-v1", }); require.NoError(t, err);
var stdout, stderr bytes.Buffer;
err = generateCheckpointSummary(
fixture.ctx,
&stdout,
&stderr,
fixture.repo,
fixture.store,
fixture.cpID,
fixture.cpSummary,
fixture.content,
false,
0,
);
require.ErrorContains(t, err, checkpoint_version "refs-v1");
v1After, refErr := fixture.repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true); require.NoError(t, refErr); require.Equal(t, fixture.v1Hash, v1After.Hash(), "v1 metadata branch must not advance after rejected summary write"); }
func TestGenerateCheckpointAISummary_ClampsLongParentDeadlineToDefaultTimeout(t *testing.T) {
Mcmd/entire/cli/strategy/checkpoint_policy.go+100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
package strategy;
import ( "bytes"; "context"; "os/exec"; "path/filepath"; "strings";
"github.com/entireio/cli/cmd/entire/cli/checkpointpolicy"; "github.com/entireio/cli/cmd/entire/cli/interactive"; "github.com/entireio/cli/cmd/entire/cli/logging"; "github.com/entireio/cli/cmd/entire/cli/versioncheck"; "github.com/entireio/cli/cmd/entire/cli/versioninfo"; "github.com/go-git/go-git/v6"; )
func committedCheckpointWriteAllowed(ctx context.Context, repo *git.Repository) bool { state, err := checkpointpolicy.ReadLocal(ctx, repo); if err != nil { logging.Warn(ctx, "checkpoint policy read failed; allowing checkpoint write", slog.String("error", err.Error()), ); return true; } if !checkpointpolicy.UnsupportedWrite(state.Policy) { return true; } warnOrLogUnsupportedCheckpointWrite(ctx, state.Policy); return false; }
func syncCheckpointPolicyForPrePush(ctx context.Context) bool { repo, err := OpenRepository(ctx); if err != nil { logging.Warn(ctx, "checkpoint policy pre-push: failed to open repository; allowing checkpoint push", slog.String("error", err.Error()), ); return true; } defer repo.Close();
target, err := checkpointpolicy.ResolveTarget(ctx); if err != nil { logging.Warn(ctx, "checkpoint policy pre-push: failed to resolve policy remote; allowing checkpoint push", slog.String("error", err.Error()), ); return true; } state, err := checkpointpolicy.Sync(ctx, repo, target); if err != nil { warnOrLogCheckpointPolicySyncFailure(ctx, err); return true; } if state.Source == checkpointpolicy.SourceLocalDiverged { warnOrLogCheckpointPolicyDiverged(ctx, state); return false; } if !checkpointpolicy.UnsupportedWrite(state.Policy) { return true; } warnOrLogUnsupportedCheckpointWrite(ctx, state.Policy); return false; }
func warnOrLogCheckpointPolicySyncFailure(ctx context.Context, err error) { if interactive.CanPromptInteractively() { fmt.Fprintf(stderrWriter, "[entire] Could not refresh checkpoint policy: %v\n", err); return; } logging.Warn(ctx, "checkpoint policy sync failed", slog.String("error", err.Error()), ); }
func warnOrLogCheckpointPolicyDiverged(ctx context.Context, state checkpointpolicy.State) { if interactive.CanPromptInteractively() { fmt.Fprintf( stderrWriter, "[entire] Could not reconcile checkpoint policy: local checkpoint policy %s diverges from remote %s\n", state.Hash, state.RemoteHash, ); return; } logging.Warn(ctx, "checkpoint policy diverged; skipping checkpoint push", slog.String("local_hash", state.Hash.String()), slog.String("remote_hash", state.RemoteHash.String()), ); }
func warnOrLogUnsupportedCheckpointWrite(ctx context.Context, policy checkpointpolicy.Policy) { warning := checkpointpolicy.UpgradeWarning(versioncheck.UpdateCommandForCurrentBinary(versioninfo.Version)); if interactive.CanPromptInteractively() { fmt.Fprint(stderrWriter, warning); return; } logging.Warn(ctx, "checkpoint write skipped by policy", slog.String("checkpoint_version", policy.CheckpointVersion), slog.String("checkpoint_min_version", policy.CheckpointMinVersion), ); }
Acmd/entire/cli/strategy/checkpoint_policy_test.go+104
146 unmodified lines
147 148 149 150 151 152 153 154 155
146 unmodified lines
} logCtx := logging.WithComponent(ctx, "checkpoint"); condenseStart := time.Now(); if !committedCheckpointWriteAllowed(ctx, repo) { return newSkippedResult(checkpointID, state.SessionID), nil; }
shadowBranchName := getShadowBranchNameForCommit(state.BaseCommit, state.WorktreeID); ref, hasShadowBranch := resolveShadowRef(repo, shadowBranchName, o.shadowRef);
Mcmd/entire/cli/strategy/manual_commit_condensation.go+3
2784 unmodified lines
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794
2784 unmodified lines
return 1 // Count as error - all checkpoints will be skipped } defer repo.Close(); if !committedCheckpointWriteAllowed(ctx, repo) { state.TurnCheckpointIDs = nil; return 0; }
prompts := readPromptsFromShadowBranch(ctx, repo, state); if len(prompts) == 0 {
Mcmd/entire/cli/strategy/manual_commit_hooks.go+4
43 unmodified lines
44 45 46 47 48 49 50 51 52
43 unmodified lines
}
refs := checkpoint.ResolveCommittedRefs(ctx); if !syncCheckpointPolicyForPrePush(ctx) { return nil; }
// OPF pre-push rewrite: if OPF is configured, resolve the user's // decision (env > settings > prompt > non-TTY auto-run), then
Mcmd/entire/cli/strategy/manual_commit_push.go+3
409 unmodified lines
410 411 412 413 414 415 416 417 418 419 420 421 422
409 unmodified lines
return "curl -fsSL https://entire.io/install.sh | bash"; }
func UpdateCommandForCurrentBinary(currentVersion string) string { if !canAutoInstall() { return downloadsURL; } return updateCommand(currentVersion); }
// printNotification prints the version update notification to the user. func printNotification(w io.Writer, current, latest string) { fmt.Fprintf(w, "\nUpdate available! %s -> %s\nRelease notes: %s\n",
Mcmd/entire/cli/versioncheck/versioncheck.go+7
345 unmodified lines
346 347 348 349 350 351 352 353 35 unmodified lines
389 390 391 390 392 393 394 395 29 unmodified lines
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
345 unmodified lines
// it without tripping goconst on repeated string literals. const brewUpgradeCmd = "brew upgrade entire";
const scoopExecutablePath = C:\Users\test\scoop\apps\cli\current\entire.exe;
func TestUpdateCommand(t *testing.T) { const plainBinPath = "/usr/local/bin/entire"; tests := []struct { 35 unmodified lines
{
name: "scoop path",
currentVersion: "1.0.0",
execPath: func() (string, error) { return C:\Users\test\scoop\apps\cli\current\entire.exe, nil },
execPath: func() (string, error) { return scoopExecutablePath, nil },
want: "scoop update entire/cli",
},
{
29 unmodified lines
} }
func TestUpdateCommandForCurrentBinary(t *testing.T) {
tests := []struct {
name string;
currentVersion string;
goos string;
execPath func() (string, error);
want string;
}{
{
name: "known installer returns command",
currentVersion: "1.2.3",
goos: goosWindows,
execPath: func() (string, error) { return scoopExecutablePath, nil },
want: "scoop update entire/cli",
},
{
name: "windows unknown installer returns releases URL",
currentVersion: "1.2.3",
goos: goosWindows,
execPath: func() (string, error) { return C:\Program Files\Entire\entire.exe, nil },
want: downloadsURL,
},
{
name: "non-windows unknown installer returns curl command",
currentVersion: "1.2.3",
goos: "linux",
execPath: func() (string, error) { return "/usr/local/bin/entire", nil },
want: "curl -fsSL https://entire.io/install.sh | bash",
},
}
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { originalExecPath := executablePath; executablePath = tt.execPath; t.Cleanup(func() { executablePath = originalExecPath });
originalGOOS := goos; goos = tt.goos; t.Cleanup(func() { goos = originalGOOS });
if got := UpdateCommandForCurrentBinary(tt.currentVersion); got != tt.want { t.Errorf("UpdateCommandForCurrentBinary() = %q, want %q", got, tt.want); } }) } }
// setupCheckAndNotifyTest points the global config dir at a per-test temp // dir and overrides githubAPIURL. Returns a cobra.Command with captured // stdout and a cleanup function.
Mcmd/entire/cli/versioncheck/versioncheck_test.go+51/-1
86 unmodified lines
87 88 89 90 91 92 93 94 95
86 unmodified lines
cancel(); os.Exit(1); } if cli.ShouldCheckCheckpointPolicyWarning(executed) { cli.WarnCheckpointPolicyIfNeeded(ctx, rootCmd.ErrOrStderr(), versioninfo.Version); } cancel(); // Cleanup on successful exit }
Mcmd/entire/main.go+3
277 unmodified lines
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
277 unmodified lines
sessionsarray inCheckpointSummarymaps each session to its file pathsfiles_touchedis merged from all sessions
Checkpoint Policy
Repo-wide checkpoint policy lives at refs/entire/policies/checkpoint. The ref
points at a commit whose tree contains policy.json:
{
"checkpoint_version": "branch-v1",
"checkpoint_min_version": "branch-v1"
}
checkpoint_version is the checkpoint format new writes should use.
checkpoint_min_version is the oldest checkpoint format clients must be able
to read for this repo. Missing policy fields default to branch-v1.
Policy follows the configured checkpoint remote. entire policy checkpoint
fetches the latest remote policy before validating requested changes, updates
the local policy ref, and pushes only refs/entire/policies/checkpoint.
Policy commits use the same signing settings as checkpoint commits.
Hooks that run while ordinary git operations must keep working offline:
post-commit and agent lifecycle hooks read only the local policy ref. If the
local policy requires checkpoint writes this CLI does not support, they skip
writing checkpoint data and warn only when running in an interactive terminal.
The pre-push hook is the regular online sync point: it compares the remote
policy ref with the local ref, fetches updated policy when needed, and evaluates
the refreshed policy before pushing entire/checkpoints/v1. If policy refresh
fails, the hook warns or logs the failure and lets the normal push continue.
User-driven commands warn when the local policy indicates the CLI should be
upgraded. Commands that need to decode checkpoint contents, such as
entire checkpoint explain and entire session resume, fail when the target
checkpoint uses an unsupported checkpoint_version.
Checkpoint ID Linking
The checkpoint ID is the stable identifier that links user commits to metadata across branches.