@amityco/social-plus-vise 0.14.22 → 0.14.23
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/CHANGELOG.md +9 -0
- package/README.md +7 -2
- package/dist/server.js +178 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ All notable changes to `@amityco/social-plus-vise` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 0.14.23 — 2026-06-06
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Workplan orchestration CLI:** `vise workplan next`, `vise workplan status`, and `vise workplan complete` coordinate broad social requests across feed, comments, chat, and profile surfaces while recording local progress in `sp-vise/workplan.json`.
|
|
11
|
+
|
|
12
|
+
### Verified
|
|
13
|
+
- CLI regression coverage now locks next-surface selection, completion recording, and feed-to-comments progression for broad Android social workplans.
|
|
14
|
+
- Dogfooded `0.14.22` on `/Users/admin/Documents/music-player-android`: refreshed the feed contract, reached `vise check` green with 43/43 deterministic passes, synced attestations, and passed Gradle assemble/unit-test sensors.
|
|
15
|
+
|
|
7
16
|
## 0.14.22 — 2026-06-05
|
|
8
17
|
|
|
9
18
|
### Added
|
package/README.md
CHANGED
|
@@ -161,14 +161,15 @@ Aggregate: **98/99 expected feed capabilities** and **27/27 selected optional ca
|
|
|
161
161
|
|
|
162
162
|
### Current Release Validation
|
|
163
163
|
|
|
164
|
-
Version 0.14.
|
|
164
|
+
Version 0.14.23 carries current release proof around the full feed-forward, product-expectation, and validation flow:
|
|
165
165
|
|
|
166
166
|
| Surface | What was validated |
|
|
167
167
|
|---|---|
|
|
168
168
|
| **Product flow** | Local end-to-end smoke covers design extraction, plan feed-forward, blocking intake, answered init, capability check, design conformance, and sensor discovery. |
|
|
169
|
-
| **Multi-surface planning** | Broad social requests are decomposed into a `socialWorkplan` sequence for feed, comments, chat, and profile work instead of forcing a single top-level surface choice.
|
|
169
|
+
| **Multi-surface planning** | Broad social requests are decomposed into a `socialWorkplan` sequence for feed, comments, chat, and profile work instead of forcing a single top-level surface choice. `vise workplan next` tells the host agent which surface to implement next, and `vise workplan complete` records progress in `sp-vise/workplan.json`. |
|
|
170
170
|
| **Plan questions** | Plans surface blocking questions such as `design_contract_confirmation`, product-scope questions such as `feed_post_type_scope`, `feed_composer_type_scope`, `comment_tray_scope`, `chat_inbox_scope`, and `profile_identity_scope`, plus optional choices such as `feed_optional_capabilities`. Focused plans still accept `feature_surface` answers when the agent is ready to implement one surface. |
|
|
171
171
|
| **Capability-to-sensor flow** | Vise checks platform support, matches the prompt to available capabilities, offers supported features as questions, records answers, and turns selected answers into sensors in `vise check`. |
|
|
172
|
+
| **Android workplan dogfood** | A brownfield Android music-player app refreshed under `0.14.22` reached `vise check` green with **43/43 deterministic passes**, passed `vise validate`, and passed Gradle assemble/unit-test sensors. This is dogfood evidence, not a controlled multi-agent benchmark. |
|
|
172
173
|
| **Shared product expectations** | Public IDs such as `feed.target-resolved`, `feed.post-type-scope-explicit`, `comments.creation-affordance`, `chat.channel-list-order-explicit`, `community.avatar-from-sdk`, `moderation.role-gated-action`, `follow.relationship-live`, `profile.identity-from-sdk`, `profile.social-counts`, and `notifications.tray-live` stay platform-agnostic while check results retain concrete `contractRuleId` and `validator.sensorId` evidence when deterministic sensors exist. |
|
|
173
174
|
| **Rule detection** | TP-track dashboard detects **321/321 seeded rule gaps (100.0%)** in the static corpus. |
|
|
174
175
|
| **Packed-package smoke** | Packed-package and host-agent smokes exercise the release tarball path, surfaced plan questions, selected optional capability sensors, rejected design confirmation handling, and exact contract-rule evidence for shared product expectations. |
|
|
@@ -299,6 +300,9 @@ The flow above is what the skill teaches your AI agent. You — the human — dr
|
|
|
299
300
|
| `vise inspect [path]` | Detect platform, monorepo surfaces, design signals, available sensors |
|
|
300
301
|
| `vise plan [path] --request "..."` | Produce a grounded implementation plan with intake questions and docs citations |
|
|
301
302
|
| `vise plan-harness [path] --request "..."` | (Pre-planning step) Build the harness around the request |
|
|
303
|
+
| `vise workplan next [path] --request "..."` | For broad social requests, print the next uncompleted surface plus focused `plan` / `init` / verification commands |
|
|
304
|
+
| `vise workplan status [path] --request "..."` | Show the broad social workplan sequence and which surfaces are already marked complete |
|
|
305
|
+
| `vise workplan complete [path] --request "..." --surface <id>` | Record a completed workplan surface in `sp-vise/workplan.json` after `check`, `sync`, `validate`, and sensors pass |
|
|
302
306
|
| `vise init [path] --request "..." [--answer key=value]` | Write the `sp-vise/` compliance contract after blocking intake is answered; returns `needs-clarification` and exits 7 if required answers are missing |
|
|
303
307
|
| `vise blocks list --registry <path>` | Read a social.plus Block Factory registry |
|
|
304
308
|
| `vise blocks plan [path] --block <id> --registry <path>` | Plan safe block package, source-anchor, sidecar, and sensor changes |
|
|
@@ -454,6 +458,7 @@ After a successful `vise init`, your project gets a `sp-vise/` directory. If ini
|
|
|
454
458
|
| `sp-vise/intake.json` | `vise init` | The request, outcome, intake answers, remaining blocking count, design-review status (`absent`, `needs-confirmation`, `accepted`, or `rejected`), and any retrospective `--allow-unresolved-intake` acknowledgement. |
|
|
455
459
|
| `sp-vise/attestations/*.json` | `vise sync` (deterministic) or `vise attest` (host-agent / human) | Per-rule evidence: signer, confidence, rationale, cited files (with source fingerprints for drift detection). |
|
|
456
460
|
| `sp-vise/inspection.json` | `vise init` | The platform, monorepo surface, and design-token signals detected at init time. |
|
|
461
|
+
| `sp-vise/workplan.json` | `vise workplan complete` | Local progress for broad social workplans: request, completed surface IDs, outcomes, timestamps, and optional host-agent notes. |
|
|
457
462
|
| `sp-vise/design-contract.json` | `vise design extract` | The extracted design contract: declared tokens, breakpoints, advisory components, source file digests (for freshness detection), and a stable digest over design facts. |
|
|
458
463
|
| `sp-vise/design-preview.html` | `vise design extract` or `vise design preview` | Self-contained visual review of the design contract, embedded prototype when available, token swatches, and design-check conformance summary. Open this before answering `design_contract_confirmation`. |
|
|
459
464
|
| `sp-vise/design-reference.html` | `vise design reference` | Self-contained HTML design-system spec (token swatches, type samples, components). Human/VLM-readable; open in a browser alongside the app. |
|
package/dist/server.js
CHANGED
|
@@ -177,6 +177,23 @@ async function handleCli(args) {
|
|
|
177
177
|
});
|
|
178
178
|
return "exit";
|
|
179
179
|
}
|
|
180
|
+
if (command === "workplan") {
|
|
181
|
+
const sub = args[1];
|
|
182
|
+
const subArgs = args.slice(2);
|
|
183
|
+
if (sub === "next" || sub === "status") {
|
|
184
|
+
assertOnlyKnownFlags(subArgs, ["request", "surface", "surface-path", "answer"], `workplan ${sub}`);
|
|
185
|
+
console.log(JSON.stringify(await workplanStatus(subArgs), null, 2));
|
|
186
|
+
return "exit";
|
|
187
|
+
}
|
|
188
|
+
if (sub === "complete") {
|
|
189
|
+
assertOnlyKnownFlags(subArgs, ["request", "surface", "surface-path", "answer", "note"], "workplan complete");
|
|
190
|
+
console.log(JSON.stringify(await completeWorkplanSurface(subArgs), null, 2));
|
|
191
|
+
return "exit";
|
|
192
|
+
}
|
|
193
|
+
console.error(`Unknown workplan subcommand: ${sub ?? "(none)"}. Expected "next", "status", or "complete".`);
|
|
194
|
+
process.exitCode = 1;
|
|
195
|
+
return "exit";
|
|
196
|
+
}
|
|
180
197
|
if (command === "validate" || command === "validate-setup") {
|
|
181
198
|
await printToolResult(validateSetupTool, {
|
|
182
199
|
repoPath: positionalRepoPath(args.slice(1)),
|
|
@@ -442,6 +459,22 @@ Create a harness guide/sensor plan for the requested SDK integration.
|
|
|
442
459
|
Usage:
|
|
443
460
|
vise plan-harness [repoPath] --request "Add a social feed"
|
|
444
461
|
vise plan-harness apps/web --request "Set up notifications" --surface apps/web`;
|
|
462
|
+
}
|
|
463
|
+
if (command === "workplan") {
|
|
464
|
+
return `${packageName} workplan
|
|
465
|
+
|
|
466
|
+
Coordinate broad social requests across the ordered per-surface plan.
|
|
467
|
+
|
|
468
|
+
Usage:
|
|
469
|
+
vise workplan next [repoPath] --request "Add feed, comments, chat, and profile"
|
|
470
|
+
vise workplan status [repoPath] --request "Add feed, comments, chat, and profile"
|
|
471
|
+
vise workplan complete [repoPath] --request "Add feed, comments, chat, and profile" --surface feed
|
|
472
|
+
|
|
473
|
+
Notes:
|
|
474
|
+
next/status re-run the broad plan, ignore any feature_surface answer, and combine it
|
|
475
|
+
with sp-vise/workplan.json progress. complete records a host-agent progress marker;
|
|
476
|
+
run vise check, vise sync, vise validate, and vise run-sensors before marking a
|
|
477
|
+
surface complete.`;
|
|
445
478
|
}
|
|
446
479
|
if (command === "search-docs" || command === "search_docs") {
|
|
447
480
|
return `${packageName} search-docs
|
|
@@ -666,6 +699,7 @@ Usage:
|
|
|
666
699
|
vise inspect [repoPath] Inspect platform and design signals
|
|
667
700
|
vise debug [repoPath] --error ... Debug an SDK-specific runtime error and emit a repair brief
|
|
668
701
|
vise plan [repoPath] --request "..." Create an implementation plan
|
|
702
|
+
vise workplan next [repoPath] --request "..." Get the next broad-social surface to implement
|
|
669
703
|
vise init [repoPath] --request "..." Initialize compliance sidecar
|
|
670
704
|
vise check [repoPath] Check compliance contract
|
|
671
705
|
vise sync [repoPath] Persist deterministic-pass evidence
|
|
@@ -916,6 +950,148 @@ function assertOnlyKnownFlags(args, allowed, commandName) {
|
|
|
916
950
|
const allowedList = allowed.length > 0 ? `Allowed flags: ${allowed.map((flag) => `--${flag}`).join(", ")}.` : "This command takes no flags.";
|
|
917
951
|
throw new Error(`${commandName} does not accept ${unknown.join(", ")}. ${allowedList} Run \`vise ${commandName} --help\` for usage.`);
|
|
918
952
|
}
|
|
953
|
+
async function workplanStatus(args) {
|
|
954
|
+
const repoRoot = path.resolve(positionalRepoPath(args));
|
|
955
|
+
const request = requiredFlagValue(args, "request", "workplan next/status requires --request.");
|
|
956
|
+
const plan = await workplanPlan(repoRoot, request, args);
|
|
957
|
+
const sequence = socialWorkplanSequence(plan);
|
|
958
|
+
const progress = await readWorkplanProgress(repoRoot);
|
|
959
|
+
const completed = progress?.request === request ? progress.completed : [];
|
|
960
|
+
const completedIds = new Set(completed.map((item) => item.surface));
|
|
961
|
+
const nextSurface = sequence.find((surface) => !completedIds.has(surface.id));
|
|
962
|
+
if (sequence.length === 0) {
|
|
963
|
+
return {
|
|
964
|
+
status: "not-applicable",
|
|
965
|
+
reason: "The request did not produce a multi-surface social workplan. Use `vise plan` for the single-outcome flow.",
|
|
966
|
+
request,
|
|
967
|
+
progressPath: workplanProgressPath(repoRoot),
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
return {
|
|
971
|
+
status: nextSurface ? "next-surface" : "complete",
|
|
972
|
+
request,
|
|
973
|
+
progressPath: workplanProgressPath(repoRoot),
|
|
974
|
+
completed,
|
|
975
|
+
sequence: sequence.map((surface) => ({
|
|
976
|
+
id: surface.id,
|
|
977
|
+
order: surface.order,
|
|
978
|
+
outcome: surface.outcome,
|
|
979
|
+
label: surface.label,
|
|
980
|
+
completed: completedIds.has(surface.id),
|
|
981
|
+
})),
|
|
982
|
+
nextSurface: nextSurface
|
|
983
|
+
? {
|
|
984
|
+
id: nextSurface.id,
|
|
985
|
+
order: nextSurface.order,
|
|
986
|
+
outcome: nextSurface.outcome,
|
|
987
|
+
label: nextSurface.label,
|
|
988
|
+
intake: nextSurface.intake,
|
|
989
|
+
validation: nextSurface.validation,
|
|
990
|
+
commands: {
|
|
991
|
+
plan: nextSurface.planCommand,
|
|
992
|
+
init: nextSurface.initCommand,
|
|
993
|
+
check: "vise check .",
|
|
994
|
+
sync: "vise sync .",
|
|
995
|
+
validate: "vise validate .",
|
|
996
|
+
sensors: "vise run-sensors .",
|
|
997
|
+
complete: `vise workplan complete . --request ${shellQuoteForCommand(request)} --surface ${nextSurface.id}`,
|
|
998
|
+
},
|
|
999
|
+
}
|
|
1000
|
+
: undefined,
|
|
1001
|
+
nextStep: nextSurface
|
|
1002
|
+
? `Resolve the ${nextSurface.id} surface intake, run its focused plan/init command, implement it, then run check/sync/validate/sensors before marking it complete.`
|
|
1003
|
+
: "All workplan surfaces are marked complete. Run one final `vise check .`, `vise validate .`, and `vise run-sensors .` before handoff.",
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
async function completeWorkplanSurface(args) {
|
|
1007
|
+
const repoRoot = path.resolve(positionalRepoPath(args));
|
|
1008
|
+
const request = requiredFlagValue(args, "request", "workplan complete requires --request.");
|
|
1009
|
+
const surfaceId = requiredFlagValue(args, "surface", "workplan complete requires --surface <surface-id>.");
|
|
1010
|
+
const note = flagValue(args, "note");
|
|
1011
|
+
const plan = await workplanPlan(repoRoot, request, args);
|
|
1012
|
+
const sequence = socialWorkplanSequence(plan);
|
|
1013
|
+
const surface = sequence.find((item) => item.id === surfaceId);
|
|
1014
|
+
if (!surface) {
|
|
1015
|
+
throw new Error(`Surface "${surfaceId}" is not in this social workplan. Available surfaces: ${sequence.map((item) => item.id).join(", ") || "(none)"}.`);
|
|
1016
|
+
}
|
|
1017
|
+
const now = new Date().toISOString();
|
|
1018
|
+
const existing = await readWorkplanProgress(repoRoot);
|
|
1019
|
+
const base = existing?.request === request
|
|
1020
|
+
? existing
|
|
1021
|
+
: {
|
|
1022
|
+
schema_version: 1,
|
|
1023
|
+
vise_version: packageVersion,
|
|
1024
|
+
request,
|
|
1025
|
+
generated_at: now,
|
|
1026
|
+
updated_at: now,
|
|
1027
|
+
completed: [],
|
|
1028
|
+
};
|
|
1029
|
+
const withoutSurface = base.completed.filter((item) => item.surface !== surfaceId);
|
|
1030
|
+
const progress = {
|
|
1031
|
+
...base,
|
|
1032
|
+
vise_version: packageVersion,
|
|
1033
|
+
updated_at: now,
|
|
1034
|
+
completed: [
|
|
1035
|
+
...withoutSurface,
|
|
1036
|
+
{
|
|
1037
|
+
surface: surfaceId,
|
|
1038
|
+
outcome: surface.outcome,
|
|
1039
|
+
completed_at: now,
|
|
1040
|
+
...(note ? { note } : {}),
|
|
1041
|
+
},
|
|
1042
|
+
].sort((a, b) => sequenceIndex(sequence, a.surface) - sequenceIndex(sequence, b.surface)),
|
|
1043
|
+
};
|
|
1044
|
+
await writeWorkplanProgress(repoRoot, progress);
|
|
1045
|
+
const status = await workplanStatus(args);
|
|
1046
|
+
return {
|
|
1047
|
+
status: "recorded",
|
|
1048
|
+
progressPath: workplanProgressPath(repoRoot),
|
|
1049
|
+
recorded: progress.completed.find((item) => item.surface === surfaceId),
|
|
1050
|
+
nextSurface: status.nextSurface,
|
|
1051
|
+
nextStep: status.nextStep,
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
async function workplanPlan(repoRoot, request, args) {
|
|
1055
|
+
const answers = keyValueFlag(args, "answer");
|
|
1056
|
+
delete answers.feature_surface;
|
|
1057
|
+
const result = await planIntegrationTool.call({
|
|
1058
|
+
repoPath: repoRoot,
|
|
1059
|
+
request,
|
|
1060
|
+
surfacePath: flagValue(args, "surface-path"),
|
|
1061
|
+
answers,
|
|
1062
|
+
});
|
|
1063
|
+
return JSON.parse(result.content.map((item) => item.text).join("\n"));
|
|
1064
|
+
}
|
|
1065
|
+
function socialWorkplanSequence(plan) {
|
|
1066
|
+
const workplan = plan.socialWorkplan;
|
|
1067
|
+
if (!workplan || workplan.kind !== "social-multi-surface" || !Array.isArray(workplan.sequence)) {
|
|
1068
|
+
return [];
|
|
1069
|
+
}
|
|
1070
|
+
return workplan.sequence;
|
|
1071
|
+
}
|
|
1072
|
+
async function readWorkplanProgress(repoRoot) {
|
|
1073
|
+
try {
|
|
1074
|
+
return JSON.parse(await readFile(workplanProgressPath(repoRoot), "utf8"));
|
|
1075
|
+
}
|
|
1076
|
+
catch {
|
|
1077
|
+
return null;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
async function writeWorkplanProgress(repoRoot, progress) {
|
|
1081
|
+
const filePath = workplanProgressPath(repoRoot);
|
|
1082
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
1083
|
+
await writeFile(filePath, `${JSON.stringify(progress, null, 2)}\n`, "utf8");
|
|
1084
|
+
}
|
|
1085
|
+
function workplanProgressPath(repoRoot) {
|
|
1086
|
+
return path.join(repoRoot, "sp-vise", "workplan.json");
|
|
1087
|
+
}
|
|
1088
|
+
function sequenceIndex(sequence, surfaceId) {
|
|
1089
|
+
const index = sequence.findIndex((surface) => surface.id === surfaceId);
|
|
1090
|
+
return index >= 0 ? index : Number.MAX_SAFE_INTEGER;
|
|
1091
|
+
}
|
|
1092
|
+
function shellQuoteForCommand(value) {
|
|
1093
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
1094
|
+
}
|
|
919
1095
|
function ciCheckResult(result) {
|
|
920
1096
|
return {
|
|
921
1097
|
...result,
|
|
@@ -929,7 +1105,7 @@ function ciCheckResult(result) {
|
|
|
929
1105
|
};
|
|
930
1106
|
}
|
|
931
1107
|
function positionalRepoPath(args) {
|
|
932
|
-
const flagsWithValues = new Set(["request", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source"]);
|
|
1108
|
+
const flagsWithValues = new Set(["request", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source", "note"]);
|
|
933
1109
|
for (let index = 0; index < args.length; index += 1) {
|
|
934
1110
|
const arg = args[index];
|
|
935
1111
|
if (!arg) {
|
|
@@ -951,7 +1127,7 @@ function positionalRepoPath(args) {
|
|
|
951
1127
|
}
|
|
952
1128
|
function requiredPositionalText(args, message) {
|
|
953
1129
|
const values = [];
|
|
954
|
-
const flagsWithValues = new Set(["request", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source"]);
|
|
1130
|
+
const flagsWithValues = new Set(["request", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source", "note"]);
|
|
955
1131
|
for (let index = 0; index < args.length; index += 1) {
|
|
956
1132
|
const arg = args[index];
|
|
957
1133
|
if (!arg) {
|
package/package.json
CHANGED