snipara-companion 3.2.13 → 3.2.14
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 +21 -0
- package/dist/index.js +199 -0
- package/docs/FULL_REFERENCE.md +29 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,27 @@ npx -y snipara-companion impact src/auth/session.ts --source local
|
|
|
22
22
|
npx -y snipara-companion source init .
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Companion Continuity Contract V1
|
|
26
|
+
|
|
27
|
+
Editor integrations and post-activation workflows can ask Companion for one
|
|
28
|
+
machine-readable "continue this workspace" payload:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx -y snipara-companion@latest continue-workspace --include-session-context --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The payload version is `snipara.companion.continuity.v1`. It is designed for
|
|
35
|
+
native editor commands, status bars, panels, and agent handoffs that need to
|
|
36
|
+
resume real work without rescanning or reimplementing Snipara semantics. It
|
|
37
|
+
includes project binding, session bootstrap entries and quality warnings,
|
|
38
|
+
workflow phase state, Team Sync handoff summary, passive source snapshot status,
|
|
39
|
+
session snapshot summary, stable local artifact paths, and recommended next
|
|
40
|
+
actions.
|
|
41
|
+
|
|
42
|
+
Use this after `create-snipara` activation. `create-snipara` remains the
|
|
43
|
+
canonical engine for first workspace setup; Companion owns the repeatable local
|
|
44
|
+
continuity loop after that.
|
|
45
|
+
|
|
25
46
|
Example output excerpt:
|
|
26
47
|
|
|
27
48
|
```text
|
package/dist/index.js
CHANGED
|
@@ -16928,6 +16928,7 @@ var MIN_WORKFLOW_SURFACE_TOKENS = 200;
|
|
|
16928
16928
|
var STALE_BOOTSTRAP_MEMORY_DAYS = 90;
|
|
16929
16929
|
var TASK_COMMIT_TIMEOUT_MS = 3e4;
|
|
16930
16930
|
var FINAL_COMMIT_TIMEOUT_MS = 9e4;
|
|
16931
|
+
var COMPANION_CONTINUITY_CONTRACT_VERSION = "snipara.companion.continuity.v1";
|
|
16931
16932
|
var FINAL_COMMIT_RETRY_TIMEOUT_MS = 45e3;
|
|
16932
16933
|
var FINAL_COMMIT_SUMMARY_MAX_CHARS = 1200;
|
|
16933
16934
|
var FINAL_COMMIT_RETRY_SUMMARY_MAX_CHARS = 600;
|
|
@@ -24482,6 +24483,191 @@ async function sessionBootstrapCommand(options) {
|
|
|
24482
24483
|
printSessionBootstrapQuality(buildPrintedBootstrapQuality(printedBootstrap));
|
|
24483
24484
|
}
|
|
24484
24485
|
}
|
|
24486
|
+
function emptySessionMemoriesResult() {
|
|
24487
|
+
return {
|
|
24488
|
+
critical: { memories: [], count: 0, tokens: 0 },
|
|
24489
|
+
daily: { memories: [], count: 0, tokens: 0 },
|
|
24490
|
+
total_tokens: 0
|
|
24491
|
+
};
|
|
24492
|
+
}
|
|
24493
|
+
function readLocalJsonFile(relativePath2) {
|
|
24494
|
+
const absolutePath = path20.join(process.cwd(), relativePath2);
|
|
24495
|
+
if (!fs21.existsSync(absolutePath)) {
|
|
24496
|
+
return null;
|
|
24497
|
+
}
|
|
24498
|
+
try {
|
|
24499
|
+
const parsed = JSON.parse(fs21.readFileSync(absolutePath, "utf-8"));
|
|
24500
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
24501
|
+
} catch {
|
|
24502
|
+
return null;
|
|
24503
|
+
}
|
|
24504
|
+
}
|
|
24505
|
+
function summarizeSourceSnapshot(snapshot) {
|
|
24506
|
+
if (!snapshot) {
|
|
24507
|
+
return {
|
|
24508
|
+
status: "missing",
|
|
24509
|
+
snapshotPath: path20.join(".snipara", "source", "latest.json"),
|
|
24510
|
+
nextAction: "Run snipara-companion source sync --json after meaningful local code or docs movement."
|
|
24511
|
+
};
|
|
24512
|
+
}
|
|
24513
|
+
const summary = snapshot.summary && typeof snapshot.summary === "object" && !Array.isArray(snapshot.summary) ? snapshot.summary : {};
|
|
24514
|
+
return {
|
|
24515
|
+
status: "present",
|
|
24516
|
+
snapshotPath: path20.join(".snipara", "source", "latest.json"),
|
|
24517
|
+
generatedAt: snapshot.generatedAt,
|
|
24518
|
+
revision: snapshot.revision,
|
|
24519
|
+
totalFiles: summary.totalFiles,
|
|
24520
|
+
totalBytes: summary.totalBytes,
|
|
24521
|
+
skipped: summary.skipped
|
|
24522
|
+
};
|
|
24523
|
+
}
|
|
24524
|
+
function summarizeWorkflowStateForContinuity(workflow2) {
|
|
24525
|
+
if (!workflow2) {
|
|
24526
|
+
return {
|
|
24527
|
+
status: "missing",
|
|
24528
|
+
statePath: WORKFLOW_STATE_RELATIVE_PATH,
|
|
24529
|
+
nextAction: "Run snipara-companion workflow start for multi-phase work."
|
|
24530
|
+
};
|
|
24531
|
+
}
|
|
24532
|
+
return {
|
|
24533
|
+
status: workflow2.status,
|
|
24534
|
+
workflowId: workflow2.workflowId,
|
|
24535
|
+
goal: workflow2.goal,
|
|
24536
|
+
currentPhaseId: workflow2.currentPhaseId,
|
|
24537
|
+
statePath: WORKFLOW_STATE_RELATIVE_PATH,
|
|
24538
|
+
phases: workflow2.phases.map((phase) => ({
|
|
24539
|
+
id: phase.id,
|
|
24540
|
+
title: phase.title,
|
|
24541
|
+
status: phase.status
|
|
24542
|
+
}))
|
|
24543
|
+
};
|
|
24544
|
+
}
|
|
24545
|
+
function summarizeTeamSyncForContinuity() {
|
|
24546
|
+
const state = loadTeamSyncState();
|
|
24547
|
+
const summary = buildTeamSyncSummary(state);
|
|
24548
|
+
const latestHandoff = state.handoffs.at(-1);
|
|
24549
|
+
return {
|
|
24550
|
+
statePath: path20.relative(process.cwd(), getTeamSyncStatePath()),
|
|
24551
|
+
activeWorkCount: summary.activeWorkCount,
|
|
24552
|
+
staleWorkCount: summary.staleWorkCount,
|
|
24553
|
+
completedWorkCount: summary.completedWorkCount,
|
|
24554
|
+
archivedWorkCount: summary.archivedWorkCount,
|
|
24555
|
+
handoffCount: summary.handoffCount,
|
|
24556
|
+
latestHandoff: latestHandoff ? {
|
|
24557
|
+
summary: latestHandoff.summary,
|
|
24558
|
+
next: latestHandoff.next,
|
|
24559
|
+
attention: latestHandoff.attention,
|
|
24560
|
+
createdAt: latestHandoff.createdAt
|
|
24561
|
+
} : null
|
|
24562
|
+
};
|
|
24563
|
+
}
|
|
24564
|
+
function buildCompanionContinuityPayload(args) {
|
|
24565
|
+
const config = args.configured ? loadConfig() : null;
|
|
24566
|
+
const workflow2 = readWorkflowState2();
|
|
24567
|
+
const sessionSnapshot = readSessionSnapshot();
|
|
24568
|
+
const sourceSnapshot = readLocalJsonFile(path20.join(".snipara", "source", "latest.json"));
|
|
24569
|
+
return {
|
|
24570
|
+
version: COMPANION_CONTINUITY_CONTRACT_VERSION,
|
|
24571
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24572
|
+
configured: args.configured,
|
|
24573
|
+
project: config ? {
|
|
24574
|
+
projectId: config.projectId,
|
|
24575
|
+
apiUrl: config.apiUrl,
|
|
24576
|
+
sessionId: config.sessionId
|
|
24577
|
+
} : null,
|
|
24578
|
+
artifacts: {
|
|
24579
|
+
workflowStatePath: WORKFLOW_STATE_RELATIVE_PATH,
|
|
24580
|
+
teamSyncStatePath: path20.relative(process.cwd(), getTeamSyncStatePath()),
|
|
24581
|
+
sessionSnapshotPath: path20.join(".snipara", "activity", "session.json"),
|
|
24582
|
+
sourceSnapshotPath: path20.join(".snipara", "source", "latest.json")
|
|
24583
|
+
},
|
|
24584
|
+
bootstrap: args.bootstrap,
|
|
24585
|
+
bootstrapQuality: args.bootstrapQuality,
|
|
24586
|
+
localWarmSnapshot: {
|
|
24587
|
+
storedEntries: args.warmSnapshotStoredEntries
|
|
24588
|
+
},
|
|
24589
|
+
sessionContext: {
|
|
24590
|
+
included: args.includeSessionContext,
|
|
24591
|
+
maxTokens: args.maxContextTokens
|
|
24592
|
+
},
|
|
24593
|
+
workflow: summarizeWorkflowStateForContinuity(workflow2),
|
|
24594
|
+
teamSync: summarizeTeamSyncForContinuity(),
|
|
24595
|
+
source: summarizeSourceSnapshot(sourceSnapshot),
|
|
24596
|
+
sessionSnapshot: sessionSnapshot ? {
|
|
24597
|
+
latestActivityAt: sessionSnapshot.summary.latestActivityAt,
|
|
24598
|
+
latestTitle: sessionSnapshot.summary.latestActivityTitle,
|
|
24599
|
+
latestKind: sessionSnapshot.summary.latestActivityKind,
|
|
24600
|
+
risk: sessionSnapshot.summary.risk,
|
|
24601
|
+
riskReasons: sessionSnapshot.summary.riskReasons,
|
|
24602
|
+
touchedFiles: sessionSnapshot.summary.touchedFiles,
|
|
24603
|
+
nextAction: sessionSnapshot.summary.recommendedNextAction
|
|
24604
|
+
} : null,
|
|
24605
|
+
nextActions: [
|
|
24606
|
+
{
|
|
24607
|
+
id: "open_bootstrap_brief",
|
|
24608
|
+
label: "Open bootstrap brief",
|
|
24609
|
+
command: "snipara-companion session-bootstrap --include-session-context --max-context-tokens 1000",
|
|
24610
|
+
when: "bootstrap has entries or session context is included"
|
|
24611
|
+
},
|
|
24612
|
+
{
|
|
24613
|
+
id: "refresh_source_snapshot",
|
|
24614
|
+
label: "Refresh source snapshot",
|
|
24615
|
+
command: "snipara-companion source sync --json",
|
|
24616
|
+
when: "source.status is missing or local code/docs changed"
|
|
24617
|
+
},
|
|
24618
|
+
{
|
|
24619
|
+
id: "run_impact_gate",
|
|
24620
|
+
label: "Run code impact before risky edits",
|
|
24621
|
+
command: 'snipara-companion code impact --changed-files <files> --diff-summary "next edit"',
|
|
24622
|
+
when: "the next edit is multi-file, risky, or user-visible"
|
|
24623
|
+
},
|
|
24624
|
+
{
|
|
24625
|
+
id: "commit_task_context",
|
|
24626
|
+
label: "Commit durable task context",
|
|
24627
|
+
command: 'snipara-companion task-commit --summary "<done>" --files <files>',
|
|
24628
|
+
when: "a durable phase or task is complete"
|
|
24629
|
+
}
|
|
24630
|
+
]
|
|
24631
|
+
};
|
|
24632
|
+
}
|
|
24633
|
+
async function continueWorkspaceCommand(options) {
|
|
24634
|
+
const configured = isConfigured();
|
|
24635
|
+
const resolvedContextTokens = options.maxContextTokens !== void 0 ? options.maxContextTokens : options.includeSessionContext ? DEFAULT_SESSION_CONTEXT_TOKENS : 0;
|
|
24636
|
+
let bootstrap = emptySessionMemoriesResult();
|
|
24637
|
+
let warmSnapshotStoredEntries = 0;
|
|
24638
|
+
if (configured) {
|
|
24639
|
+
const client = createClient(15e3);
|
|
24640
|
+
bootstrap = await client.getSessionMemories(options.maxCriticalTokens, resolvedContextTokens);
|
|
24641
|
+
const config = loadConfig();
|
|
24642
|
+
const warmSnapshot = createLocalQueryCache({
|
|
24643
|
+
cwd: process.cwd(),
|
|
24644
|
+
projectId: config.projectId,
|
|
24645
|
+
sessionId: config.sessionId
|
|
24646
|
+
}).storeWarmSnapshot(bootstrap);
|
|
24647
|
+
warmSnapshotStoredEntries = warmSnapshot.storedEntries;
|
|
24648
|
+
}
|
|
24649
|
+
const bootstrapQuality = buildSessionBootstrapQuality(bootstrap, {
|
|
24650
|
+
expectedMaxTokens: (options.maxCriticalTokens ?? DEFAULT_FULL_WORKFLOW_CRITICAL_TOKENS) + resolvedContextTokens
|
|
24651
|
+
});
|
|
24652
|
+
const payload = buildCompanionContinuityPayload({
|
|
24653
|
+
configured,
|
|
24654
|
+
bootstrap,
|
|
24655
|
+
bootstrapQuality,
|
|
24656
|
+
includeSessionContext: resolvedContextTokens > 0,
|
|
24657
|
+
maxContextTokens: resolvedContextTokens,
|
|
24658
|
+
warmSnapshotStoredEntries
|
|
24659
|
+
});
|
|
24660
|
+
if (options.json) {
|
|
24661
|
+
printJson2(payload);
|
|
24662
|
+
return;
|
|
24663
|
+
}
|
|
24664
|
+
console.log(import_chalk6.default.bold("Snipara Companion Continuity"));
|
|
24665
|
+
console.log(`Version: ${COMPANION_CONTINUITY_CONTRACT_VERSION}`);
|
|
24666
|
+
console.log(`Configured: ${configured ? "yes" : "no"}`);
|
|
24667
|
+
console.log(`Workflow: ${payload.workflow.status ?? "unknown"}`);
|
|
24668
|
+
console.log(`Source: ${payload.source.status ?? "unknown"}`);
|
|
24669
|
+
console.log("Next: snipara-companion continue-workspace --json for editor integrations");
|
|
24670
|
+
}
|
|
24485
24671
|
async function recallCommand(options) {
|
|
24486
24672
|
ensureConfigured();
|
|
24487
24673
|
const client = createClient(15e3);
|
|
@@ -34867,6 +35053,19 @@ program.command("session-bootstrap").description(
|
|
|
34867
35053
|
json: options.json
|
|
34868
35054
|
});
|
|
34869
35055
|
});
|
|
35056
|
+
program.command("continue-workspace").description("Print the stable Companion Continuity Contract for editor integrations").option("--max-critical-tokens <number>", "Durable memory token budget").option(
|
|
35057
|
+
"--include-session-context",
|
|
35058
|
+
"Include short-lived session carryover in addition to durable memory"
|
|
35059
|
+
).option("--max-context-tokens <number>", "Short-lived session context token budget").option("--json", "Print raw JSON").action(async (options) => {
|
|
35060
|
+
const maxCriticalTokens = options.maxCriticalTokens !== void 0 ? parseInt(options.maxCriticalTokens, 10) : void 0;
|
|
35061
|
+
const maxContextTokens = options.maxContextTokens !== void 0 ? parseInt(options.maxContextTokens, 10) : void 0;
|
|
35062
|
+
await continueWorkspaceCommand({
|
|
35063
|
+
maxCriticalTokens,
|
|
35064
|
+
maxContextTokens,
|
|
35065
|
+
includeSessionContext: Boolean(options.includeSessionContext || options.maxContextTokens),
|
|
35066
|
+
json: options.json
|
|
35067
|
+
});
|
|
35068
|
+
});
|
|
34870
35069
|
program.command("task-commit").description("Persist durable outcomes after meaningful task work, not every git commit").requiredOption("-s, --summary <summary>", "Task summary").option("-c, --category <category>", "Category").option("-o, --outcome <outcome>", "Outcome", "completed").option("-f, --files <files...>", "Files touched").option("--json", "Print raw JSON").action(async (options) => {
|
|
34871
35070
|
await taskCommitCommand({
|
|
34872
35071
|
summary: options.summary,
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -21,6 +21,35 @@ snipara-companion code impact --changed-files src/app.ts --diff-summary "next ed
|
|
|
21
21
|
snipara-companion task-commit --summary "completed durable change" --files src/app.ts
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Companion Continuity Contract V1
|
|
25
|
+
|
|
26
|
+
For editor integrations and "continue this workspace" flows, use the stable JSON
|
|
27
|
+
contract instead of rebuilding Companion internals:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
snipara-companion continue-workspace --include-session-context --json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The response version is `snipara.companion.continuity.v1`. It includes:
|
|
34
|
+
|
|
35
|
+
- `project`: configured project id, API URL, and session id when available.
|
|
36
|
+
- `bootstrap` and `bootstrapQuality`: pushed session memories plus token,
|
|
37
|
+
freshness, and warning metadata.
|
|
38
|
+
- `workflow`: active workflow id, goal, current phase, phase statuses, and local
|
|
39
|
+
state path.
|
|
40
|
+
- `teamSync`: active/stale/completed counts and latest handoff summary.
|
|
41
|
+
- `source`: passive `.snipara/source/latest.json` status; no source sync is
|
|
42
|
+
performed by this command.
|
|
43
|
+
- `sessionSnapshot`: latest local activity summary, risks, touched files, and
|
|
44
|
+
recommended next action.
|
|
45
|
+
- `artifacts` and `nextActions`: stable local paths and commands an editor can
|
|
46
|
+
surface to the user.
|
|
47
|
+
|
|
48
|
+
This contract starts after `create-snipara` has activated the workspace. Editor
|
|
49
|
+
extensions should orchestrate these commands and render the payload, not fork
|
|
50
|
+
local source scanning, First Work Brief, memory candidate, or Hosted MCP config
|
|
51
|
+
logic.
|
|
52
|
+
|
|
24
53
|
In this repository, the source currently lives in `packages/cli`, and the installed executable is `snipara-companion`.
|
|
25
54
|
|
|
26
55
|
This package complements `snipara-mcp`. It does not replace it.
|