snipara-companion 1.3.0 → 1.3.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.
- package/README.md +11 -0
- package/dist/index.d.ts +46 -2
- package/dist/index.js +285 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,6 +112,14 @@ The mental model is intentionally close to Git:
|
|
|
112
112
|
| `git format-patch` | `snipara-companion handoff` |
|
|
113
113
|
| `git checkout` | `snipara-companion workflow resume` |
|
|
114
114
|
|
|
115
|
+
`snipara-companion final-commit` closes the local workflow and asks the hosted
|
|
116
|
+
API only for the final Team Sync handoff. The CLI sends a compact summary with a
|
|
117
|
+
longer timeout, retries once with a shorter summary on transient hosted failures,
|
|
118
|
+
and then records a local fallback handoff in `.snipara/team-sync/session.json`
|
|
119
|
+
if the hosted call still times out. A hosted final-commit timeout does not modify
|
|
120
|
+
Git state. Custom final-commit categories are namespaced under `final-commit`
|
|
121
|
+
before the hosted call so they stay on the handoff-only path.
|
|
122
|
+
|
|
115
123
|
## Verification Plans
|
|
116
124
|
|
|
117
125
|
Use `verify` when an agent asks what to prove before handoff or release:
|
|
@@ -489,6 +497,7 @@ project API key, the same commands also call the hosted Team Sync surfaces:
|
|
|
489
497
|
- `team-sync handoff` records the local handoff and publishes the hosted handoff capsule.
|
|
490
498
|
- `team-sync what-changed` keeps local counters but also loads the hosted What Changed For Me surface.
|
|
491
499
|
- `team-sync resume` and `workflow resume` append the latest hosted handoff plus checkpoint-aware resume context when available.
|
|
500
|
+
- `team-sync sweep` archives local work items after 14 days without update by default; use `--dry-run` to review before changing the local continuity file.
|
|
492
501
|
- Hosted MCP also exposes `snipara_resume_context` for agents that want the same continuity bundle directly: latest handoff match, What Changed, active decisions, execution-memory, and an optional task-scoped work brief.
|
|
493
502
|
|
|
494
503
|
Typical flow:
|
|
@@ -497,6 +506,7 @@ Typical flow:
|
|
|
497
506
|
snipara-companion team-sync start-work --summary "add invite permissions" --files apps/web/src/lib/auth/permissions.ts
|
|
498
507
|
snipara-companion team-sync handoff --summary "moved project access check" --next "run permissions tests before merge" --attention proof
|
|
499
508
|
snipara-companion team-sync what-changed
|
|
509
|
+
snipara-companion team-sync sweep --dry-run
|
|
500
510
|
snipara-companion workflow resume --include-session-context
|
|
501
511
|
snipara-companion workflow phase-start implement-permissions
|
|
502
512
|
```
|
|
@@ -584,6 +594,7 @@ Semantics:
|
|
|
584
594
|
- `snipara-companion team-sync start-work` = keeps the local session file and fetches the hosted Start Work Brief when the workspace has project auth
|
|
585
595
|
- `snipara-companion team-sync handoff` = keeps the local handoff record and publishes the hosted handoff capsule when project auth is available
|
|
586
596
|
- `snipara-companion team-sync what-changed` = prints the local state summary and the hosted What Changed For Me response when configured
|
|
597
|
+
- `snipara-companion team-sync sweep` = archives stale local work items after an inactivity threshold; default is 14 days and `--dry-run` previews the cleanup
|
|
587
598
|
- `snipara-companion team-sync resume` = reloads local carryover plus the hosted latest handoff and checkpoint-aware resume guidance when available
|
|
588
599
|
- `snipara-companion final-commit` / `workflow final-commit` = final hosted commit for the managed workflow
|
|
589
600
|
- `snipara-companion code symbol-card` = direct paid Context `snipara_code_symbol_card` for an important symbol before editing, with an agent guidance summary before raw JSON
|
package/dist/index.d.ts
CHANGED
|
@@ -949,6 +949,8 @@ declare class RLMClient {
|
|
|
949
949
|
category?: string;
|
|
950
950
|
outcome?: "completed" | "partial" | "blocked" | "abandoned";
|
|
951
951
|
filesTouched?: string[];
|
|
952
|
+
persistTypes?: string[];
|
|
953
|
+
handoffOnly?: boolean;
|
|
952
954
|
}): Promise<Record<string, unknown>>;
|
|
953
955
|
journalAppend(text: string, tags?: string[]): Promise<JournalAppendResult>;
|
|
954
956
|
}
|
|
@@ -1209,6 +1211,7 @@ interface AgenticWorkStatus {
|
|
|
1209
1211
|
teamSync: {
|
|
1210
1212
|
activeWorkCount: number;
|
|
1211
1213
|
staleWorkCount: number;
|
|
1214
|
+
archivedWorkCount: number;
|
|
1212
1215
|
handoffCount: number;
|
|
1213
1216
|
latestHandoff?: {
|
|
1214
1217
|
summary: string;
|
|
@@ -1501,7 +1504,7 @@ declare function getAutomationStatus(projectDir?: string): AutomationStatusResul
|
|
|
1501
1504
|
|
|
1502
1505
|
declare const TEAM_SYNC_STATE_RELATIVE_PATH: string;
|
|
1503
1506
|
type TeamSyncAttention = "note" | "watch" | "review" | "proof";
|
|
1504
|
-
type TeamSyncWorkStatus = "active" | "completed";
|
|
1507
|
+
type TeamSyncWorkStatus = "active" | "completed" | "archived";
|
|
1505
1508
|
interface TeamSyncRecordInput {
|
|
1506
1509
|
summary: string;
|
|
1507
1510
|
files?: string[];
|
|
@@ -1524,6 +1527,8 @@ interface TeamSyncWorkRecord {
|
|
|
1524
1527
|
updatedAt: string;
|
|
1525
1528
|
completedAt?: string;
|
|
1526
1529
|
completionReason?: string;
|
|
1530
|
+
archivedAt?: string;
|
|
1531
|
+
archiveReason?: string;
|
|
1527
1532
|
}
|
|
1528
1533
|
interface TeamSyncHandoffRecord {
|
|
1529
1534
|
id: string;
|
|
@@ -1545,18 +1550,50 @@ interface TeamSyncSummary {
|
|
|
1545
1550
|
activeWorkCount: number;
|
|
1546
1551
|
staleWorkCount: number;
|
|
1547
1552
|
completedWorkCount: number;
|
|
1553
|
+
archivedWorkCount: number;
|
|
1548
1554
|
handoffCount: number;
|
|
1549
1555
|
files: string[];
|
|
1550
1556
|
latestActiveWork?: TeamSyncWorkRecord;
|
|
1551
1557
|
latestStaleWork?: TeamSyncWorkRecord;
|
|
1552
1558
|
latestCompletedWork?: TeamSyncWorkRecord;
|
|
1559
|
+
latestArchivedWork?: TeamSyncWorkRecord;
|
|
1553
1560
|
latestHandoff?: TeamSyncHandoffRecord;
|
|
1554
1561
|
}
|
|
1562
|
+
interface TeamSyncCommandOptions {
|
|
1563
|
+
id?: string;
|
|
1564
|
+
summary?: string;
|
|
1565
|
+
files?: string[];
|
|
1566
|
+
branch?: string;
|
|
1567
|
+
actor?: string;
|
|
1568
|
+
next?: string;
|
|
1569
|
+
attention?: string;
|
|
1570
|
+
risk?: string;
|
|
1571
|
+
since?: string;
|
|
1572
|
+
dir?: string;
|
|
1573
|
+
includeSessionContext?: boolean;
|
|
1574
|
+
emitOrchestratorHandoff?: boolean;
|
|
1575
|
+
autoRouteOrchestrator?: boolean;
|
|
1576
|
+
orchestratorPolicySource?: string;
|
|
1577
|
+
output?: string;
|
|
1578
|
+
days?: string;
|
|
1579
|
+
dryRun?: boolean;
|
|
1580
|
+
json?: boolean;
|
|
1581
|
+
}
|
|
1555
1582
|
interface HostedAttempt<T> {
|
|
1556
1583
|
status: "skipped" | "ok" | "error";
|
|
1557
1584
|
data?: T;
|
|
1558
1585
|
error?: string;
|
|
1559
1586
|
}
|
|
1587
|
+
interface TeamSyncSweepResult {
|
|
1588
|
+
action: "sweep";
|
|
1589
|
+
statePath: string;
|
|
1590
|
+
dryRun: boolean;
|
|
1591
|
+
thresholdDays: number;
|
|
1592
|
+
thresholdMs: number;
|
|
1593
|
+
archivedCount: number;
|
|
1594
|
+
archivedWork: TeamSyncWorkRecord[];
|
|
1595
|
+
summary: TeamSyncSummary;
|
|
1596
|
+
}
|
|
1560
1597
|
interface AgenticHandoffArtifact {
|
|
1561
1598
|
version: "snipara.agentic_handoff.v1";
|
|
1562
1599
|
generatedAt: string;
|
|
@@ -1581,10 +1618,17 @@ declare function buildTeamSyncStartWorkRecord(input: TeamSyncRecordInput): TeamS
|
|
|
1581
1618
|
declare function buildTeamSyncHandoffRecord(input: TeamSyncRecordInput): TeamSyncHandoffRecord;
|
|
1582
1619
|
declare function createEmptyTeamSyncState(now?: Date): TeamSyncState;
|
|
1583
1620
|
declare function buildTeamSyncSummary(state: TeamSyncState, since?: Date, now?: Date): TeamSyncSummary;
|
|
1621
|
+
declare function archiveInactiveTeamSyncWork(state: TeamSyncState, options?: {
|
|
1622
|
+
now?: Date;
|
|
1623
|
+
thresholdMs?: number;
|
|
1624
|
+
dryRun?: boolean;
|
|
1625
|
+
}): TeamSyncSweepResult["archivedWork"];
|
|
1626
|
+
declare function autoArchiveTeamSyncState(rootDir?: string, now?: Date): TeamSyncSweepResult["archivedWork"];
|
|
1584
1627
|
declare function loadTeamSyncState(rootDir?: string): TeamSyncState;
|
|
1585
1628
|
declare function saveTeamSyncState(state: TeamSyncState, rootDir?: string): void;
|
|
1586
1629
|
declare function getTeamSyncStatePath(rootDir?: string): string;
|
|
1587
1630
|
declare function buildAgenticHandoffMarkdown(artifact: AgenticHandoffArtifact): string;
|
|
1631
|
+
declare function teamSyncSweepCommand(options: TeamSyncCommandOptions): Promise<void>;
|
|
1588
1632
|
|
|
1589
1633
|
interface JournalCheckpointPayload {
|
|
1590
1634
|
action: string;
|
|
@@ -1773,4 +1817,4 @@ interface WrittenOrchestratorHandoff {
|
|
|
1773
1817
|
declare function buildOrchestratorHandoff(options: OrchestratorHandoffOptions): OrchestratorHandoffArtifact;
|
|
1774
1818
|
declare function writeOrchestratorHandoff(options: OrchestratorHandoffOptions): WrittenOrchestratorHandoff;
|
|
1775
1819
|
|
|
1776
|
-
export { AUTOMATION_MANIFEST_RELATIVE_PATH, AutomationInstallConflictError, AutomationUnsupportedHookBundleError, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, TEAM_SYNC_STATE_RELATIVE_PATH, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildJournalCheckpointEntry, buildOnboardFolderManifest, buildOrchestratorHandoff, buildProjectIntelligenceBrief, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, collectSyncDocuments, collectSyncDocumentsInput, createClient, createEmptyTeamSyncState, createLocalQueryCache, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, extractCommandFromToolInput, extractFilesFromToolInput, formatOrchestratorRecommendationReason, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getConfigPath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, installAutomationBundle, listProjectsForApiKey, loadAutomationManifest, loadConfig, loadTeamSyncState, normalizeGuardTag, normalizeWorkflowPlanInput, projectIntelligenceBriefCommand, resolveQueryFromToolInput, runMemoryGuardCheck, saveConfig, saveTeamSyncState, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, verifyCommand, writeOrchestratorHandoff };
|
|
1820
|
+
export { AUTOMATION_MANIFEST_RELATIVE_PATH, AutomationInstallConflictError, AutomationUnsupportedHookBundleError, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, TEAM_SYNC_STATE_RELATIVE_PATH, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, archiveInactiveTeamSyncWork, autoArchiveTeamSyncState, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildJournalCheckpointEntry, buildOnboardFolderManifest, buildOrchestratorHandoff, buildProjectIntelligenceBrief, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, collectSyncDocuments, collectSyncDocumentsInput, createClient, createEmptyTeamSyncState, createLocalQueryCache, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, extractCommandFromToolInput, extractFilesFromToolInput, formatOrchestratorRecommendationReason, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getConfigPath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, installAutomationBundle, listProjectsForApiKey, loadAutomationManifest, loadConfig, loadTeamSyncState, normalizeGuardTag, normalizeWorkflowPlanInput, projectIntelligenceBriefCommand, resolveQueryFromToolInput, runMemoryGuardCheck, saveConfig, saveTeamSyncState, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, teamSyncSweepCommand, verifyCommand, writeOrchestratorHandoff };
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,8 @@ __export(index_exports, {
|
|
|
38
38
|
TEAM_SYNC_STATE_RELATIVE_PATH: () => TEAM_SYNC_STATE_RELATIVE_PATH,
|
|
39
39
|
WORKFLOW_PLANS_RELATIVE_DIR: () => WORKFLOW_PLANS_RELATIVE_DIR,
|
|
40
40
|
WORKFLOW_STATE_RELATIVE_PATH: () => WORKFLOW_STATE_RELATIVE_PATH,
|
|
41
|
+
archiveInactiveTeamSyncWork: () => archiveInactiveTeamSyncWork,
|
|
42
|
+
autoArchiveTeamSyncState: () => autoArchiveTeamSyncState,
|
|
41
43
|
buildAgenticHandoffMarkdown: () => buildAgenticHandoffMarkdown,
|
|
42
44
|
buildAgenticTimeline: () => buildAgenticTimeline,
|
|
43
45
|
buildAgenticWorkStatus: () => buildAgenticWorkStatus,
|
|
@@ -91,6 +93,7 @@ __export(index_exports, {
|
|
|
91
93
|
saveTeamSyncState: () => saveTeamSyncState,
|
|
92
94
|
shouldSuggestOrchestratorForWorkflow: () => shouldSuggestOrchestratorForWorkflow,
|
|
93
95
|
shouldSuggestRuntimeForWorkflow: () => shouldSuggestRuntimeForWorkflow,
|
|
96
|
+
teamSyncSweepCommand: () => teamSyncSweepCommand,
|
|
94
97
|
verifyCommand: () => verifyCommand,
|
|
95
98
|
writeOrchestratorHandoff: () => writeOrchestratorHandoff
|
|
96
99
|
});
|
|
@@ -1301,7 +1304,8 @@ var RLMClient = class {
|
|
|
1301
1304
|
category: args.category,
|
|
1302
1305
|
outcome: args.outcome || "completed",
|
|
1303
1306
|
files_touched: args.filesTouched || [],
|
|
1304
|
-
persist_types: ["decision", "learning", "workflow"]
|
|
1307
|
+
persist_types: args.persistTypes ?? ["decision", "learning", "workflow"],
|
|
1308
|
+
...args.handoffOnly !== void 0 ? { handoff_only: args.handoffOnly } : {}
|
|
1305
1309
|
});
|
|
1306
1310
|
}
|
|
1307
1311
|
async journalAppend(text, tags) {
|
|
@@ -7049,6 +7053,7 @@ async function appendJournalCheckpoint(payload) {
|
|
|
7049
7053
|
// src/commands/team-sync.ts
|
|
7050
7054
|
var TEAM_SYNC_STATE_RELATIVE_PATH = path12.join(".snipara", "team-sync", "session.json");
|
|
7051
7055
|
var TEAM_SYNC_STALE_WORK_MS = 48 * 60 * 60 * 1e3;
|
|
7056
|
+
var TEAM_SYNC_AUTO_ARCHIVE_WORK_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
7052
7057
|
function buildTeamSyncStartWorkRecord(input) {
|
|
7053
7058
|
const createdAt = (input.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
7054
7059
|
const files = normalizeFiles(input.files);
|
|
@@ -7094,6 +7099,7 @@ function buildTeamSyncSummary(state, since, now = /* @__PURE__ */ new Date()) {
|
|
|
7094
7099
|
const activeWork = work.filter((item) => item.status === "active" && !isStaleWork(item, now));
|
|
7095
7100
|
const staleWork = work.filter((item) => item.status === "active" && isStaleWork(item, now));
|
|
7096
7101
|
const completedWork = work.filter((item) => item.status === "completed");
|
|
7102
|
+
const archivedWork = work.filter((item) => item.status === "archived");
|
|
7097
7103
|
const files = /* @__PURE__ */ new Set();
|
|
7098
7104
|
for (const item of [...work, ...handoffs]) {
|
|
7099
7105
|
for (const file of item.files) {
|
|
@@ -7104,14 +7110,45 @@ function buildTeamSyncSummary(state, since, now = /* @__PURE__ */ new Date()) {
|
|
|
7104
7110
|
activeWorkCount: activeWork.length,
|
|
7105
7111
|
staleWorkCount: staleWork.length,
|
|
7106
7112
|
completedWorkCount: completedWork.length,
|
|
7113
|
+
archivedWorkCount: archivedWork.length,
|
|
7107
7114
|
handoffCount: handoffs.length,
|
|
7108
7115
|
files: Array.from(files).sort(),
|
|
7109
7116
|
latestActiveWork: activeWork[activeWork.length - 1],
|
|
7110
7117
|
latestStaleWork: staleWork[staleWork.length - 1],
|
|
7111
7118
|
latestCompletedWork: completedWork[completedWork.length - 1],
|
|
7119
|
+
latestArchivedWork: archivedWork[archivedWork.length - 1],
|
|
7112
7120
|
latestHandoff: handoffs[handoffs.length - 1]
|
|
7113
7121
|
};
|
|
7114
7122
|
}
|
|
7123
|
+
function archiveInactiveTeamSyncWork(state, options = {}) {
|
|
7124
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
7125
|
+
const nowIso2 = now.toISOString();
|
|
7126
|
+
const thresholdMs = options.thresholdMs ?? TEAM_SYNC_AUTO_ARCHIVE_WORK_MS;
|
|
7127
|
+
const thresholdDays = Math.round(thresholdMs / (24 * 60 * 60 * 1e3));
|
|
7128
|
+
const candidates = state.work.filter(
|
|
7129
|
+
(item) => item.status === "active" && now.getTime() - getWorkTimestamp(item) > thresholdMs
|
|
7130
|
+
);
|
|
7131
|
+
if (!options.dryRun) {
|
|
7132
|
+
for (const item of candidates) {
|
|
7133
|
+
item.status = "archived";
|
|
7134
|
+
item.updatedAt = nowIso2;
|
|
7135
|
+
item.archivedAt = nowIso2;
|
|
7136
|
+
item.archiveReason = `No update for ${thresholdDays} day(s)`;
|
|
7137
|
+
}
|
|
7138
|
+
if (candidates.length > 0) {
|
|
7139
|
+
state.updatedAt = nowIso2;
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
7142
|
+
return candidates;
|
|
7143
|
+
}
|
|
7144
|
+
function autoArchiveTeamSyncState(rootDir = process.cwd(), now = /* @__PURE__ */ new Date()) {
|
|
7145
|
+
const state = loadTeamSyncState(rootDir);
|
|
7146
|
+
const archivedWork = archiveInactiveTeamSyncWork(state, { now });
|
|
7147
|
+
if (archivedWork.length > 0) {
|
|
7148
|
+
saveTeamSyncState(state, rootDir);
|
|
7149
|
+
}
|
|
7150
|
+
return archivedWork;
|
|
7151
|
+
}
|
|
7115
7152
|
function loadTeamSyncState(rootDir = process.cwd()) {
|
|
7116
7153
|
const statePath = getTeamSyncStatePath(rootDir);
|
|
7117
7154
|
if (!fs13.existsSync(statePath)) {
|
|
@@ -7137,6 +7174,7 @@ function getTeamSyncStatePath(rootDir = process.cwd()) {
|
|
|
7137
7174
|
async function teamSyncStartWorkCommand(options) {
|
|
7138
7175
|
const rootDir = resolveRootDir(options.dir);
|
|
7139
7176
|
const state = loadTeamSyncState(rootDir);
|
|
7177
|
+
archiveInactiveTeamSyncWork(state);
|
|
7140
7178
|
const branch = normalizeOptionalString(options.branch) ?? readGitValue2(rootDir, ["branch", "--show-current"]);
|
|
7141
7179
|
const record = buildTeamSyncStartWorkRecord({
|
|
7142
7180
|
summary: options.summary ?? "",
|
|
@@ -7202,6 +7240,7 @@ async function teamSyncStartWorkCommand(options) {
|
|
|
7202
7240
|
}
|
|
7203
7241
|
async function teamSyncHandoffCommand(options) {
|
|
7204
7242
|
const rootDir = resolveRootDir(options.dir);
|
|
7243
|
+
autoArchiveTeamSyncState(rootDir);
|
|
7205
7244
|
const payload = await createTeamSyncHandoffPayload(rootDir, {
|
|
7206
7245
|
...options,
|
|
7207
7246
|
summary: options.summary ?? ""
|
|
@@ -7210,6 +7249,7 @@ async function teamSyncHandoffCommand(options) {
|
|
|
7210
7249
|
}
|
|
7211
7250
|
async function createTeamSyncHandoffPayload(rootDir, options) {
|
|
7212
7251
|
const state = loadTeamSyncState(rootDir);
|
|
7252
|
+
archiveInactiveTeamSyncWork(state);
|
|
7213
7253
|
const record = buildTeamSyncHandoffRecord({
|
|
7214
7254
|
summary: options.summary,
|
|
7215
7255
|
files: options.files,
|
|
@@ -7459,6 +7499,10 @@ async function teamSyncWhatChangedCommand(options) {
|
|
|
7459
7499
|
const rootDir = resolveRootDir(options.dir);
|
|
7460
7500
|
const since = parseSince(options.since);
|
|
7461
7501
|
const state = loadTeamSyncState(rootDir);
|
|
7502
|
+
const archivedWork = archiveInactiveTeamSyncWork(state);
|
|
7503
|
+
if (archivedWork.length > 0) {
|
|
7504
|
+
saveTeamSyncState(state, rootDir);
|
|
7505
|
+
}
|
|
7462
7506
|
const summary = buildTeamSyncSummary(state, since);
|
|
7463
7507
|
const hosted = await maybeGetHostedWhatChanged(rootDir, {
|
|
7464
7508
|
since: since?.toISOString(),
|
|
@@ -7506,10 +7550,14 @@ async function teamSyncWhatChangedCommand(options) {
|
|
|
7506
7550
|
async function teamSyncCompleteWorkCommand(options) {
|
|
7507
7551
|
const rootDir = resolveRootDir(options.dir);
|
|
7508
7552
|
const state = loadTeamSyncState(rootDir);
|
|
7553
|
+
const archivedWork = archiveInactiveTeamSyncWork(state);
|
|
7509
7554
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7510
7555
|
const activeOrStale = state.work.filter((item) => item.status === "active");
|
|
7511
7556
|
const record = options.id ? activeOrStale.find((item) => item.id === options.id) : activeOrStale[activeOrStale.length - 1];
|
|
7512
7557
|
if (!record) {
|
|
7558
|
+
if (archivedWork.length > 0) {
|
|
7559
|
+
saveTeamSyncState(state, rootDir);
|
|
7560
|
+
}
|
|
7513
7561
|
throw new Error(
|
|
7514
7562
|
options.id ? `No active Team Sync work item found for id ${options.id}` : "No active Team Sync work item to complete"
|
|
7515
7563
|
);
|
|
@@ -7545,6 +7593,10 @@ async function teamSyncCompleteWorkCommand(options) {
|
|
|
7545
7593
|
async function teamSyncResumeCommand(options) {
|
|
7546
7594
|
const rootDir = resolveRootDir(options.dir);
|
|
7547
7595
|
const state = loadTeamSyncState(rootDir);
|
|
7596
|
+
const archivedWork = archiveInactiveTeamSyncWork(state);
|
|
7597
|
+
if (archivedWork.length > 0) {
|
|
7598
|
+
saveTeamSyncState(state, rootDir);
|
|
7599
|
+
}
|
|
7548
7600
|
const summary = buildTeamSyncSummary(state);
|
|
7549
7601
|
const hosted = await maybeGetHostedResume(rootDir, {
|
|
7550
7602
|
task: summary.latestActiveWork?.summary ?? summary.latestHandoff?.summary,
|
|
@@ -7592,6 +7644,31 @@ async function teamSyncResumeCommand(options) {
|
|
|
7592
7644
|
options.json
|
|
7593
7645
|
);
|
|
7594
7646
|
}
|
|
7647
|
+
async function teamSyncSweepCommand(options) {
|
|
7648
|
+
const rootDir = resolveRootDir(options.dir);
|
|
7649
|
+
const thresholdDays = parsePositiveDays(options.days ?? "14");
|
|
7650
|
+
const thresholdMs = thresholdDays * 24 * 60 * 60 * 1e3;
|
|
7651
|
+
const state = loadTeamSyncState(rootDir);
|
|
7652
|
+
const archivedWork = archiveInactiveTeamSyncWork(state, {
|
|
7653
|
+
thresholdMs,
|
|
7654
|
+
dryRun: Boolean(options.dryRun)
|
|
7655
|
+
});
|
|
7656
|
+
if (!options.dryRun && archivedWork.length > 0) {
|
|
7657
|
+
saveTeamSyncState(state, rootDir);
|
|
7658
|
+
}
|
|
7659
|
+
const summary = buildTeamSyncSummary(state);
|
|
7660
|
+
const payload = {
|
|
7661
|
+
action: "sweep",
|
|
7662
|
+
statePath: getTeamSyncStatePath(rootDir),
|
|
7663
|
+
dryRun: Boolean(options.dryRun),
|
|
7664
|
+
thresholdDays,
|
|
7665
|
+
thresholdMs,
|
|
7666
|
+
archivedCount: archivedWork.length,
|
|
7667
|
+
archivedWork,
|
|
7668
|
+
summary
|
|
7669
|
+
};
|
|
7670
|
+
printTeamSyncSweepResult(payload, options.json);
|
|
7671
|
+
}
|
|
7595
7672
|
function printTeamSyncResult(payload, json) {
|
|
7596
7673
|
if (json) {
|
|
7597
7674
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -7604,6 +7681,7 @@ function printTeamSyncResult(payload, json) {
|
|
|
7604
7681
|
console.log(`Active work: ${summary.activeWorkCount}`);
|
|
7605
7682
|
console.log(`Stale work: ${summary.staleWorkCount}`);
|
|
7606
7683
|
console.log(`Completed work: ${summary.completedWorkCount}`);
|
|
7684
|
+
console.log(`Archived work: ${summary.archivedWorkCount}`);
|
|
7607
7685
|
console.log(`Handoffs: ${summary.handoffCount}`);
|
|
7608
7686
|
if (summary.files.length > 0) {
|
|
7609
7687
|
console.log(`Files: ${summary.files.slice(0, 8).join(", ")}`);
|
|
@@ -7617,6 +7695,9 @@ function printTeamSyncResult(payload, json) {
|
|
|
7617
7695
|
if (summary.latestCompletedWork) {
|
|
7618
7696
|
console.log(`Latest completed work: ${summary.latestCompletedWork.summary}`);
|
|
7619
7697
|
}
|
|
7698
|
+
if (summary.latestArchivedWork) {
|
|
7699
|
+
console.log(`Latest archived work: ${summary.latestArchivedWork.summary}`);
|
|
7700
|
+
}
|
|
7620
7701
|
if (summary.latestHandoff) {
|
|
7621
7702
|
console.log(`Latest handoff: ${summary.latestHandoff.summary}`);
|
|
7622
7703
|
if (summary.latestHandoff.next) {
|
|
@@ -7666,6 +7747,25 @@ function printTeamSyncResult(payload, json) {
|
|
|
7666
7747
|
}
|
|
7667
7748
|
}
|
|
7668
7749
|
}
|
|
7750
|
+
function printTeamSyncSweepResult(payload, json) {
|
|
7751
|
+
if (json) {
|
|
7752
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
7753
|
+
return;
|
|
7754
|
+
}
|
|
7755
|
+
console.log(payload.dryRun ? "Team Sync sweep preview" : "Team Sync sweep completed");
|
|
7756
|
+
console.log(`State: ${payload.statePath}`);
|
|
7757
|
+
console.log(`Threshold: ${payload.thresholdDays} day(s) without update`);
|
|
7758
|
+
console.log(`Archived work: ${payload.archivedCount}`);
|
|
7759
|
+
if (payload.archivedWork.length > 0) {
|
|
7760
|
+
console.log(
|
|
7761
|
+
`Items: ${formatList(
|
|
7762
|
+
payload.archivedWork.map((item) => item.summary),
|
|
7763
|
+
6
|
|
7764
|
+
)}`
|
|
7765
|
+
);
|
|
7766
|
+
}
|
|
7767
|
+
console.log(`Remaining stale work: ${payload.summary.staleWorkCount}`);
|
|
7768
|
+
}
|
|
7669
7769
|
function printHostedWorkBrief(brief) {
|
|
7670
7770
|
console.log("");
|
|
7671
7771
|
console.log("Hosted Start Work Brief");
|
|
@@ -8054,13 +8154,22 @@ function normalizeWorkRecord(record) {
|
|
|
8054
8154
|
files: normalizeFiles(parsed.files),
|
|
8055
8155
|
branch: normalizeOptionalString(parsed.branch),
|
|
8056
8156
|
actor: normalizeOptionalString(parsed.actor),
|
|
8057
|
-
status: parsed.status === "completed"
|
|
8157
|
+
status: parsed.status === "completed" || parsed.status === "archived" ? parsed.status : "active",
|
|
8058
8158
|
createdAt,
|
|
8059
8159
|
updatedAt,
|
|
8060
8160
|
completedAt: normalizeOptionalString(parsed.completedAt),
|
|
8061
|
-
completionReason: normalizeOptionalString(parsed.completionReason)
|
|
8161
|
+
completionReason: normalizeOptionalString(parsed.completionReason),
|
|
8162
|
+
archivedAt: normalizeOptionalString(parsed.archivedAt),
|
|
8163
|
+
archiveReason: normalizeOptionalString(parsed.archiveReason)
|
|
8062
8164
|
};
|
|
8063
8165
|
}
|
|
8166
|
+
function parsePositiveDays(value) {
|
|
8167
|
+
const days = Number.parseInt(value, 10);
|
|
8168
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
8169
|
+
throw new Error("--days must be a positive integer");
|
|
8170
|
+
}
|
|
8171
|
+
return days;
|
|
8172
|
+
}
|
|
8064
8173
|
function parseSince(value) {
|
|
8065
8174
|
if (!value) return void 0;
|
|
8066
8175
|
const date = new Date(value);
|
|
@@ -8126,6 +8235,11 @@ var import_chalk5 = __toESM(require("chalk"));
|
|
|
8126
8235
|
var DEFAULT_SESSION_CONTEXT_TOKENS = 1e3;
|
|
8127
8236
|
var DEFAULT_FULL_WORKFLOW_CRITICAL_TOKENS = 2e3;
|
|
8128
8237
|
var DEFAULT_SHARED_CONTEXT_TOKENS = 2e3;
|
|
8238
|
+
var TASK_COMMIT_TIMEOUT_MS = 3e4;
|
|
8239
|
+
var FINAL_COMMIT_TIMEOUT_MS = 9e4;
|
|
8240
|
+
var FINAL_COMMIT_RETRY_TIMEOUT_MS = 45e3;
|
|
8241
|
+
var FINAL_COMMIT_SUMMARY_MAX_CHARS = 1200;
|
|
8242
|
+
var FINAL_COMMIT_RETRY_SUMMARY_MAX_CHARS = 600;
|
|
8129
8243
|
var SHARED_CONTEXT_INTENT_PATTERN = /\b(standard|standards|convention|conventions|guideline|guidelines|best practice|best practices|policy|policies|compliance|compliant|security rules|team rules|style guide|playbook|checklist)\b/i;
|
|
8130
8244
|
var DOCUMENT_SYNC_FORMATS = {
|
|
8131
8245
|
".adoc": { kind: "DOC", format: "adoc" },
|
|
@@ -8361,6 +8475,52 @@ function toPreview(value, maxLength = 160) {
|
|
|
8361
8475
|
}
|
|
8362
8476
|
return "n/a";
|
|
8363
8477
|
}
|
|
8478
|
+
function positiveIntegerEnv(name, fallback) {
|
|
8479
|
+
const value = process.env[name];
|
|
8480
|
+
if (!value) {
|
|
8481
|
+
return fallback;
|
|
8482
|
+
}
|
|
8483
|
+
const parsed = Number.parseInt(value, 10);
|
|
8484
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
8485
|
+
}
|
|
8486
|
+
function compactWhitespace(value) {
|
|
8487
|
+
return value.replace(/\s+/g, " ").trim();
|
|
8488
|
+
}
|
|
8489
|
+
function truncateText(value, maxLength) {
|
|
8490
|
+
const normalized = compactWhitespace(value);
|
|
8491
|
+
if (normalized.length <= maxLength) {
|
|
8492
|
+
return normalized;
|
|
8493
|
+
}
|
|
8494
|
+
const suffix = " ... [truncated locally for hosted final-commit]";
|
|
8495
|
+
return `${normalized.slice(0, Math.max(0, maxLength - suffix.length)).trimEnd()}${suffix}`;
|
|
8496
|
+
}
|
|
8497
|
+
function buildHostedFinalCommitSummary(args) {
|
|
8498
|
+
const prefix = args.workflowId ? `Workflow ${args.workflowId}
|
|
8499
|
+
Final commit
|
|
8500
|
+
` : "";
|
|
8501
|
+
const budget = Math.max(80, args.maxLength - prefix.length);
|
|
8502
|
+
return `${prefix}${truncateText(args.summary, budget)}`;
|
|
8503
|
+
}
|
|
8504
|
+
function hostedCommitErrorMessage(error) {
|
|
8505
|
+
return error instanceof Error ? error.message : String(error);
|
|
8506
|
+
}
|
|
8507
|
+
function shouldRetryHostedFinalCommit(error) {
|
|
8508
|
+
const message = hostedCommitErrorMessage(error).toLowerCase();
|
|
8509
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
8510
|
+
return true;
|
|
8511
|
+
}
|
|
8512
|
+
return /abort|timeout|timed out|network|fetch|econn|etimedout|http 5\d\d/.test(message);
|
|
8513
|
+
}
|
|
8514
|
+
function isFinalCommitCategory(category) {
|
|
8515
|
+
return Boolean(category?.toLowerCase().includes("final-commit"));
|
|
8516
|
+
}
|
|
8517
|
+
function normalizeFinalCommitCategory(category) {
|
|
8518
|
+
const normalized = compactWhitespace(category ?? "");
|
|
8519
|
+
if (!normalized) {
|
|
8520
|
+
return "final-commit";
|
|
8521
|
+
}
|
|
8522
|
+
return isFinalCommitCategory(normalized) ? normalized : `final-commit:${normalized}`;
|
|
8523
|
+
}
|
|
8364
8524
|
function getPlanStepDisplayTitle(step, index = 0) {
|
|
8365
8525
|
if (typeof step === "string") {
|
|
8366
8526
|
return toPreview(step);
|
|
@@ -10068,6 +10228,12 @@ function printSessionBootstrap(result, options) {
|
|
|
10068
10228
|
function printTaskCommitResult(result) {
|
|
10069
10229
|
printKeyValue("Tool:", "snipara_end_of_task_commit");
|
|
10070
10230
|
printCompactObject(result, ["stored", "skipped", "status", "message"]);
|
|
10231
|
+
const handoff = isRecord6(result.team_sync_handoff) ? result.team_sync_handoff : null;
|
|
10232
|
+
if (handoff) {
|
|
10233
|
+
const status = typeof handoff.status === "string" ? handoff.status : "unknown";
|
|
10234
|
+
const memoryId = typeof handoff.memory_id === "string" ? ` (${handoff.memory_id})` : "";
|
|
10235
|
+
printKeyValue("Team Sync handoff:", `${status}${memoryId}`);
|
|
10236
|
+
}
|
|
10071
10237
|
console.log("");
|
|
10072
10238
|
printJson(result);
|
|
10073
10239
|
}
|
|
@@ -11559,6 +11725,7 @@ function buildSuggestedAgenticNextAction(state, risks) {
|
|
|
11559
11725
|
function buildAgenticWorkStatus(cwd = process.cwd()) {
|
|
11560
11726
|
const state = readWorkflowState2(cwd);
|
|
11561
11727
|
const git = readLocalGitState(cwd);
|
|
11728
|
+
autoArchiveTeamSyncState(cwd);
|
|
11562
11729
|
const teamSyncState = loadTeamSyncState(cwd);
|
|
11563
11730
|
const teamSyncSummary = buildTeamSyncSummary(teamSyncState);
|
|
11564
11731
|
const latestHandoff = latestTeamSyncHandoff(teamSyncState.handoffs);
|
|
@@ -11606,6 +11773,7 @@ function buildAgenticWorkStatus(cwd = process.cwd()) {
|
|
|
11606
11773
|
teamSync: {
|
|
11607
11774
|
activeWorkCount: teamSyncSummary.activeWorkCount,
|
|
11608
11775
|
staleWorkCount: teamSyncSummary.staleWorkCount,
|
|
11776
|
+
archivedWorkCount: teamSyncSummary.archivedWorkCount,
|
|
11609
11777
|
handoffCount: teamSyncSummary.handoffCount,
|
|
11610
11778
|
...latestHandoff ? {
|
|
11611
11779
|
latestHandoff: {
|
|
@@ -11656,6 +11824,7 @@ function printAgenticWorkStatus(status) {
|
|
|
11656
11824
|
console.log(import_chalk5.default.bold("Team Sync"));
|
|
11657
11825
|
console.log(`Active work: ${status.teamSync.activeWorkCount}`);
|
|
11658
11826
|
console.log(`Stale work: ${status.teamSync.staleWorkCount}`);
|
|
11827
|
+
console.log(`Archived work: ${status.teamSync.archivedWorkCount}`);
|
|
11659
11828
|
console.log(`Handoffs: ${status.teamSync.handoffCount}`);
|
|
11660
11829
|
if (status.teamSync.latestHandoff) {
|
|
11661
11830
|
console.log(`Latest handoff: ${toPreview(status.teamSync.latestHandoff.summary, 120)}`);
|
|
@@ -12068,7 +12237,7 @@ function printWorkflowTeamSyncResume(result) {
|
|
|
12068
12237
|
}
|
|
12069
12238
|
async function commitTaskMemory(options) {
|
|
12070
12239
|
ensureConfigured();
|
|
12071
|
-
const client = createClient(
|
|
12240
|
+
const client = createClient(TASK_COMMIT_TIMEOUT_MS);
|
|
12072
12241
|
return client.endOfTaskCommit({
|
|
12073
12242
|
summary: options.summary,
|
|
12074
12243
|
category: options.category,
|
|
@@ -12076,6 +12245,101 @@ async function commitTaskMemory(options) {
|
|
|
12076
12245
|
filesTouched: options.files
|
|
12077
12246
|
});
|
|
12078
12247
|
}
|
|
12248
|
+
function recordLocalFinalCommitHandoff(options) {
|
|
12249
|
+
const rootDir = process.cwd();
|
|
12250
|
+
autoArchiveTeamSyncState(rootDir);
|
|
12251
|
+
const state = loadTeamSyncState(rootDir);
|
|
12252
|
+
const record = buildTeamSyncHandoffRecord({
|
|
12253
|
+
summary: truncateText(options.summary, FINAL_COMMIT_SUMMARY_MAX_CHARS),
|
|
12254
|
+
files: options.files,
|
|
12255
|
+
attention: options.outcome === "completed" ? "watch" : "proof",
|
|
12256
|
+
next: options.outcome === "completed" ? "Review this local fallback handoff before starting follow-up work." : "Resolve the blocker captured in this local fallback handoff."
|
|
12257
|
+
});
|
|
12258
|
+
state.handoffs.push(record);
|
|
12259
|
+
state.updatedAt = record.createdAt;
|
|
12260
|
+
saveTeamSyncState(state, rootDir);
|
|
12261
|
+
return {
|
|
12262
|
+
status: "local_fallback",
|
|
12263
|
+
record_id: record.id,
|
|
12264
|
+
state_path: getTeamSyncStatePath(rootDir),
|
|
12265
|
+
category: "team_sync_handoff",
|
|
12266
|
+
source_session_id: "local-companion-fallback",
|
|
12267
|
+
files: record.files,
|
|
12268
|
+
error: options.error
|
|
12269
|
+
};
|
|
12270
|
+
}
|
|
12271
|
+
async function commitFinalTaskMemory(options) {
|
|
12272
|
+
ensureConfigured();
|
|
12273
|
+
const category = normalizeFinalCommitCategory(options.category);
|
|
12274
|
+
const attempts = [];
|
|
12275
|
+
const primarySummary = buildHostedFinalCommitSummary({
|
|
12276
|
+
workflowId: options.workflowId,
|
|
12277
|
+
summary: options.summary,
|
|
12278
|
+
maxLength: FINAL_COMMIT_SUMMARY_MAX_CHARS
|
|
12279
|
+
});
|
|
12280
|
+
const retrySummary = buildHostedFinalCommitSummary({
|
|
12281
|
+
workflowId: options.workflowId,
|
|
12282
|
+
summary: options.summary,
|
|
12283
|
+
maxLength: FINAL_COMMIT_RETRY_SUMMARY_MAX_CHARS
|
|
12284
|
+
});
|
|
12285
|
+
const callHosted = async (summary, timeoutMs) => {
|
|
12286
|
+
const client = createClient(timeoutMs);
|
|
12287
|
+
const handoffOnly = isFinalCommitCategory(category);
|
|
12288
|
+
return client.endOfTaskCommit({
|
|
12289
|
+
summary,
|
|
12290
|
+
category,
|
|
12291
|
+
outcome: options.outcome,
|
|
12292
|
+
filesTouched: options.files,
|
|
12293
|
+
persistTypes: handoffOnly ? [] : ["decision", "learning", "workflow"],
|
|
12294
|
+
handoffOnly
|
|
12295
|
+
});
|
|
12296
|
+
};
|
|
12297
|
+
try {
|
|
12298
|
+
return await callHosted(
|
|
12299
|
+
primarySummary,
|
|
12300
|
+
positiveIntegerEnv("SNIPARA_FINAL_COMMIT_TIMEOUT_MS", FINAL_COMMIT_TIMEOUT_MS)
|
|
12301
|
+
);
|
|
12302
|
+
} catch (error) {
|
|
12303
|
+
attempts.push({
|
|
12304
|
+
summary_chars: primarySummary.length,
|
|
12305
|
+
error: hostedCommitErrorMessage(error)
|
|
12306
|
+
});
|
|
12307
|
+
if (shouldRetryHostedFinalCommit(error)) {
|
|
12308
|
+
try {
|
|
12309
|
+
return await callHosted(
|
|
12310
|
+
retrySummary,
|
|
12311
|
+
positiveIntegerEnv("SNIPARA_FINAL_COMMIT_RETRY_TIMEOUT_MS", FINAL_COMMIT_RETRY_TIMEOUT_MS)
|
|
12312
|
+
);
|
|
12313
|
+
} catch (retryError) {
|
|
12314
|
+
attempts.push({
|
|
12315
|
+
summary_chars: retrySummary.length,
|
|
12316
|
+
error: hostedCommitErrorMessage(retryError)
|
|
12317
|
+
});
|
|
12318
|
+
}
|
|
12319
|
+
}
|
|
12320
|
+
}
|
|
12321
|
+
const lastError = attempts[attempts.length - 1]?.error ?? "hosted final-commit failed";
|
|
12322
|
+
const localHandoff = recordLocalFinalCommitHandoff({
|
|
12323
|
+
summary: options.summary,
|
|
12324
|
+
outcome: options.outcome,
|
|
12325
|
+
files: options.files,
|
|
12326
|
+
error: lastError
|
|
12327
|
+
});
|
|
12328
|
+
return {
|
|
12329
|
+
stored_count: 0,
|
|
12330
|
+
skipped_count: 0,
|
|
12331
|
+
candidates: [],
|
|
12332
|
+
stored_candidates: [],
|
|
12333
|
+
skipped_candidates: [],
|
|
12334
|
+
team_sync_handoff: localHandoff,
|
|
12335
|
+
hosted_final_commit: {
|
|
12336
|
+
status: "error",
|
|
12337
|
+
attempts,
|
|
12338
|
+
message: "Hosted snipara_end_of_task_commit failed; local workflow state and Team Sync fallback handoff were preserved."
|
|
12339
|
+
},
|
|
12340
|
+
message: "Hosted final-commit failed; local fallback handoff created"
|
|
12341
|
+
};
|
|
12342
|
+
}
|
|
12079
12343
|
function printJournalWarning(result) {
|
|
12080
12344
|
if (result?.status === "error" && result.error) {
|
|
12081
12345
|
console.log(`Journal checkpoint: ${result.error}`);
|
|
@@ -12149,10 +12413,11 @@ async function finalCommitCommand(options) {
|
|
|
12149
12413
|
});
|
|
12150
12414
|
const state = readWorkflowState2();
|
|
12151
12415
|
const outcome = options.outcome ?? "completed";
|
|
12152
|
-
const
|
|
12153
|
-
const result = await
|
|
12154
|
-
|
|
12155
|
-
|
|
12416
|
+
const category = normalizeFinalCommitCategory(options.category);
|
|
12417
|
+
const result = await commitFinalTaskMemory({
|
|
12418
|
+
workflowId: state?.workflowId,
|
|
12419
|
+
summary: options.summary,
|
|
12420
|
+
category,
|
|
12156
12421
|
outcome,
|
|
12157
12422
|
files: options.files
|
|
12158
12423
|
});
|
|
@@ -12162,7 +12427,7 @@ async function finalCommitCommand(options) {
|
|
|
12162
12427
|
state.currentPhaseId = outcome === "completed" ? void 0 : state.currentPhaseId;
|
|
12163
12428
|
state.updatedAt = now;
|
|
12164
12429
|
state.lastCommit = {
|
|
12165
|
-
category
|
|
12430
|
+
category,
|
|
12166
12431
|
outcome,
|
|
12167
12432
|
summary: options.summary,
|
|
12168
12433
|
committedAt: now
|
|
@@ -13171,6 +13436,14 @@ teamSync.command("complete-work").description("Close a local Team Sync work item
|
|
|
13171
13436
|
json: options.json
|
|
13172
13437
|
});
|
|
13173
13438
|
});
|
|
13439
|
+
teamSync.command("sweep").description("Archive stale local Team Sync work items after an inactivity threshold").option("--days <days>", "Archive active work with no update after this many days", "14").option("--dry-run", "Preview which work items would be archived").option("-d, --dir <directory>", "Repository directory (default: current)").option("--json", "Print raw JSON").action(async (options) => {
|
|
13440
|
+
await teamSyncSweepCommand({
|
|
13441
|
+
days: options.days,
|
|
13442
|
+
dryRun: Boolean(options.dryRun),
|
|
13443
|
+
dir: options.dir,
|
|
13444
|
+
json: options.json
|
|
13445
|
+
});
|
|
13446
|
+
});
|
|
13174
13447
|
teamSync.command("what-changed").description(
|
|
13175
13448
|
"Summarize local Team Sync state and fetch hosted What Changed For Me when available"
|
|
13176
13449
|
).option("--since <date>", "Only include records created after this ISO date").option("-d, --dir <directory>", "Repository directory (default: current)").option(
|
|
@@ -13406,6 +13679,8 @@ if (require.main === module) {
|
|
|
13406
13679
|
TEAM_SYNC_STATE_RELATIVE_PATH,
|
|
13407
13680
|
WORKFLOW_PLANS_RELATIVE_DIR,
|
|
13408
13681
|
WORKFLOW_STATE_RELATIVE_PATH,
|
|
13682
|
+
archiveInactiveTeamSyncWork,
|
|
13683
|
+
autoArchiveTeamSyncState,
|
|
13409
13684
|
buildAgenticHandoffMarkdown,
|
|
13410
13685
|
buildAgenticTimeline,
|
|
13411
13686
|
buildAgenticWorkStatus,
|
|
@@ -13459,6 +13734,7 @@ if (require.main === module) {
|
|
|
13459
13734
|
saveTeamSyncState,
|
|
13460
13735
|
shouldSuggestOrchestratorForWorkflow,
|
|
13461
13736
|
shouldSuggestRuntimeForWorkflow,
|
|
13737
|
+
teamSyncSweepCommand,
|
|
13462
13738
|
verifyCommand,
|
|
13463
13739
|
writeOrchestratorHandoff
|
|
13464
13740
|
});
|