Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/affiliation-rating-resolver/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// context-v/specs/Augment-From-Affiliations.md.

import { onMount } from 'svelte';
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
import ColumnMapper from './components/ColumnMapper.svelte';
import { normalizeRatingRecord, guessMapping, MAPPING_NONE } from './lib/normalize';
import {
Expand All @@ -23,7 +23,7 @@
import type { RatingFieldMapping, RatingNormRecord, AffiliationDetail, Link, CorpusEntry } from './lib/types';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();
const ACTIVE_RECORD_SET_KEY = 'augment-it:active-record-set';
const MAPPING_KEY_PREFIX = 'augment-it:affiliation-rating-resolver:mapping:';

Expand Down
6 changes: 2 additions & 4 deletions apps/chat/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// is established independently (no shared workspace singleton).

import { onMount } from 'svelte';
import { workspace } from '@augment-it/workspace';
import { workspace, resolveWsUrl } from '@augment-it/workspace';
import CharacterCastRow from './CharacterCastRow.svelte';
import ChatSurface from './ChatSurface.svelte';

Expand All @@ -15,9 +15,7 @@
// even when mounted inside the shell, so it needs the same env-configured
// WS_URL the shell and corpora-curator each read (rsbuild inlines
// PUBLIC_-prefixed vars into import.meta.env at build time).
const WS_URL =
((import.meta as { env?: Record<string, string> }).env?.PUBLIC_WS_URL as string | undefined) ||
'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

let connectionStatus = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');

Expand Down
4 changes: 2 additions & 2 deletions apps/corpora-curator/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts">
import { onMount } from 'svelte';
import { workspace } from '@augment-it/workspace';
import { workspace, resolveWsUrl } from '@augment-it/workspace';
import { curation } from './curation.svelte';
import CorpusPicker from './CorpusPicker.svelte';
import SourceList from './SourceList.svelte';
import SourceDetail from './SourceDetail.svelte';

const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

onMount(() => {
curation.init();
Expand Down
6 changes: 2 additions & 4 deletions apps/corpora-curator/src/curation.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// $state is assigned in the constructor (not as a class-field initializer) to
// match the workspace package's placement-invariant note about field lowering.

import { workspace, WORKSPACE_CHANGED_EVENT, type WorkspaceSummary } from '@augment-it/workspace';
import { workspace, WORKSPACE_CHANGED_EVENT, type WorkspaceSummary, resolveWsUrl } from '@augment-it/workspace';
import type { ExtractKind, Source, Strategy } from './types';

const TOKEN_KEY = 'augment-it:session-token';
Expand All @@ -18,9 +18,7 @@
// shell and chat each read (rsbuild inlines PUBLIC_-prefixed vars into
// import.meta.env at build time — applies to plain .ts modules too, not
// just .svelte files).
const WS_URL =
((import.meta as { env?: Record<string, string> }).env?.PUBLIC_WS_URL as string | undefined) ||
'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

Check failure on line 21 in apps/corpora-curator/src/curation.svelte.ts

View workflow job for this annotation

GitHub Actions / unit tests

test/curation.test.ts

Error: [vitest] No "resolveWsUrl" export is defined on the "@augment-it/workspace" mock. Did you forget to return it from "vi.mock"? If you need to partially mock a module, you can use "importOriginal" helper inside: vi.mock(import("@augment-it/workspace"), async (importOriginal) => { const actual = await importOriginal() return { ...actual, // your mocked methods } }) ❯ src/curation.svelte.ts:21:16 ❯ test/curation.test.ts:28:22
// Stores "<type>:<slug>" since gh #88 — uniqueness is (type, slug), so a bare
// slug can restore the wrong corpus once a workspace holds both. Bare slugs
// from before #88 still resolve; see loadStrategies().
Expand Down
1 change: 0 additions & 1 deletion apps/enhanced-records-list/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
onMount(() => {
const TOKEN_KEY = 'augment_it_session_token';
workspace.connect({
url: 'ws://localhost:3001/ws',
getToken: () => localStorage.getItem(TOKEN_KEY),
saveToken: (t) => localStorage.setItem(TOKEN_KEY, t),
onStatus: (s) => {
Expand Down
4 changes: 2 additions & 2 deletions apps/org-workbench/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// from person-db-resolver. See context-v/specs/Augment-From-DB-Flow.md.

import { onMount } from 'svelte';
import { workspace } from '@augment-it/workspace';
import { workspace, resolveWsUrl } from '@augment-it/workspace';
import OrgSearch from './OrgSearch.svelte';
import OrgCard from './OrgCard.svelte';
import OrgCreateInline from './OrgCreateInline.svelte';
Expand All @@ -17,7 +17,7 @@
import type { OrgDetail, OrgSuggestion } from './lib/types';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();
// Restore the last-worked org on remount (HMR, flow switch, tab reopen).
const ACTIVE_ORG_KEY = 'augment-it:org-workbench:active-org';
// Cross-remote focused-entity broadcast — the chat rail includes it in
Expand Down
4 changes: 2 additions & 2 deletions apps/pack-runner/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
import {
BUNDLES, getBundle, packDisplayName, inferEntityNameField,
PACK_PALETTE_META,
Expand All @@ -23,7 +23,7 @@
let rowPackFired = $state<Record<string, Set<string>>>({});

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

// Remember the user's last record-set + column picks so re-entry doesn't
// require re-selecting everything. Keys keep the augment-it prefix per
Expand Down
4 changes: 2 additions & 2 deletions apps/person-db-resolver/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// context-v/plans/Person-Aware-Canonical-Resolver-Extension.md.

import { onMount } from 'svelte';
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
import RecordCard from './components/RecordCard.svelte';
import ColumnMapper from './components/ColumnMapper.svelte';
import PersonCandidateList from './components/PersonCandidateList.svelte';
Expand Down Expand Up @@ -35,7 +35,7 @@
} from './lib/types';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();
const ACTIVE_RECORD_SET_KEY = 'augment-it:active-record-set';
const MAPPING_KEY_PREFIX = 'augment-it:person-db-resolver:mapping:';
// Per-record-set "where I left off" — restored on every selectRecordSet()
Expand Down
4 changes: 2 additions & 2 deletions apps/prompt-template-manager/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts">
import { onMount } from 'svelte';
import { workspace, type PromptTemplate, type PromptTool } from '@augment-it/workspace';
import { workspace, type PromptTemplate, type PromptTool, resolveWsUrl } from '@augment-it/workspace';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();
const TOKEN_RE = /\{\{\s*([^{}]+?)\s*\}\}/g;

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
Expand Down
4 changes: 2 additions & 2 deletions apps/record-collector/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts">
import { onMount } from 'svelte';
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
import RecordSetsList from './components/RecordSetsList.svelte';
import { formatFieldValue } from './logic/format';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
let selectedId = $state<string | null>(null);
Expand Down
4 changes: 2 additions & 2 deletions apps/record-db-resolver/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
// context-v/specs/Record-DB-Resolver.md.

import { onMount } from 'svelte';
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
import RecordCard from './components/RecordCard.svelte';
import CandidateList from './components/CandidateList.svelte';
import { normalizeRecord, buildCrm } from './lib/normalize';
import { fetchCandidates, searchOrgs, applyResolution, updateOrg, updateOpportunity, stampRow } from './lib/resolver-client';
import type { Candidate, OrgSuggestion, ApplyResult } from './lib/types';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();
const ACTIVE_RECORD_SET_KEY = 'augment-it:active-record-set';

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
Expand Down
4 changes: 2 additions & 2 deletions apps/records-surface/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts">
import { onMount } from 'svelte';
import { workspace } from '@augment-it/workspace';
import { workspace, resolveWsUrl } from '@augment-it/workspace';
import RecordsList from './components/RecordsList.svelte';
import { records } from './state/records.svelte';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');

Expand Down
5 changes: 2 additions & 3 deletions apps/request-reviewer/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
type RecordSet,
type Row,
type PreviewResult,
type Coverage,
} from '@augment-it/workspace';
type Coverage, resolveWsUrl } from '@augment-it/workspace';

// Each remote owns its own workspace singleton + WebSocket — no `shared`
// federation block (see the 2026-05-21_03 changelog).
const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');

Expand Down
5 changes: 2 additions & 3 deletions apps/response-reviewer/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
type ResponseFlag,
type Row,
type HelpfulLink,
type SocialProfile,
} from '@augment-it/workspace';
type SocialProfile, resolveWsUrl } from '@augment-it/workspace';
import ConfidencePill from '@augment-it/shared-ui/ConfidencePill.svelte';
import { MOCK_PACKS_FIXTURE } from './fixtures/mock-packs';
import ConnectorPalette from './ConnectorPalette.svelte';
Expand All @@ -18,7 +17,7 @@
// Each remote owns its own workspace singleton + WebSocket — no `shared`
// federation block (see the 2026-05-21_03 changelog).
const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

const FLAGS: ResponseFlag[] = ['good', 'partial', 'wrong', 'needs-rerun', 'needs-human'];

Expand Down
4 changes: 2 additions & 2 deletions apps/search-and-add/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// See context-v/specs/Augment-From-DB-Flow.md §Phase 3.

import { onMount } from 'svelte';
import { workspace } from '@augment-it/workspace';
import { workspace, resolveWsUrl } from '@augment-it/workspace';
import TermBar from './TermBar.svelte';
import ProviderPalette from './ProviderPalette.svelte';
import ResultsList from './ResultsList.svelte';
Expand All @@ -19,7 +19,7 @@
import type { ConnectorInfo, ConnectorResult } from './lib/types';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
let client = $state<string>('reach-edu');
Expand Down
4 changes: 2 additions & 2 deletions apps/search-results/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
// See context-v/specs/Search-Results-Queue-Remote.md.

import { onMount } from 'svelte';
import { workspace } from '@augment-it/workspace';
import { workspace, resolveWsUrl } from '@augment-it/workspace';
import SearchCard from './SearchCard.svelte';
import { dismissSearch, listSearches } from './lib/search-client';
import type { SearchCard as SearchCardT } from './lib/types';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();

let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
let client = $state<string>('reach-edu');
Expand Down
4 changes: 2 additions & 2 deletions apps/sort-filter-lens/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// Spec: ../../../context-v/specs/Records-Surface-Sort-Step-and-UI.md

import { onMount } from 'svelte';
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
import {
type SortSpec,
type SortKey,
Expand All @@ -21,7 +21,7 @@
} from './sort-spec';

const TOKEN_KEY = 'augment-it:session-token';
const WS_URL = 'ws://localhost:3001/ws';
const WS_URL = resolveWsUrl();
const ACTIVE_RECORD_SET_KEY = 'augment-it:active-record-set';
const CLIENT_ID = 'reach-edu';

Expand Down
1 change: 1 addition & 0 deletions packages/workspace/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { workspace, WORKSPACE_CHANGED_EVENT } from './state.svelte';
export { bootMark, bootSummary } from './boot-timing';
export { createAdapter } from './adapter';
export { createTransport } from './transport';
export { resolveWsUrl, resolveHttpBase, DEFAULT_WS_URL } from './ws-url';
export { suggest } from './anticipation';
export type { Suggestion } from './anticipation';
export { MODELS, DEFAULT_MODEL, DEFAULT_MAX_TOKENS } from './models';
Expand Down
3 changes: 2 additions & 1 deletion packages/workspace/src/state.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// rule in https://svelte.dev/e/state_invalid_placement.

import { createTransport, type ChatTurnReply, type ChatTurnRequest, type Transport, type TransportConfig } from './transport';
import { resolveWsUrl } from './ws-url';
import { bootMark, bootSummary } from './boot-timing';
import type { ActiveView, JobEvent, PromptTemplate, RecordSet, Row, ServerFrame, UserContext, WorkspaceSummary } from './types';

Expand Down Expand Up @@ -264,7 +265,7 @@ class AugmentItWorkspace {
*/
connect(config: Omit<TransportConfig, 'onFrame'>): void {
if (this.transport) return;
console.info('[workspace] connect →', config.url);
console.info('[workspace] connect →', config.url ?? resolveWsUrl());
const userOnStatus = config.onStatus;
this.transport = createTransport({
...config,
Expand Down
16 changes: 13 additions & 3 deletions packages/workspace/src/transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ import type {
ServerFrame,
} from './types';
import { bootMark } from './boot-timing';
import { resolveWsUrl } from './ws-url';

export type TransportConfig = {
url: string; // e.g. 'ws://localhost:3001/ws'
/**
* Workspace-service WS endpoint. OPTIONAL — omit it and the endpoint is
* resolved from PUBLIC_WS_URL via resolveWsUrl(). Callers should omit it;
* passing a literal is how every remote ended up hardcoded to localhost.
*/
url?: string;
getToken: () => string | null;
saveToken: (token: string) => void;
onFrame: (frame: ServerFrame) => void; // called for event/session/result frames
Expand Down Expand Up @@ -118,9 +124,13 @@ export function createTransport(config: TransportConfig): Transport {

function connect(): void {
const token = config.getToken();
// Resolved per attempt, not captured once: a caller that omits `url`
// gets the build's PUBLIC_WS_URL, which is the path every remote
// should take.
const base = config.url ?? resolveWsUrl();
const url = token
? `${config.url}?token=${encodeURIComponent(token)}`
: config.url;
? `${base}?token=${encodeURIComponent(token)}`
: base;

bootMark('ws:connect-start');
config.onStatus?.('connecting');
Expand Down
39 changes: 39 additions & 0 deletions packages/workspace/src/ws-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Where workspace-service's WebSocket lives.
//
// This is the ONE place the endpoint is decided. It exists because it used
// to be decided in sixteen places: every remote declared its own
// `const WS_URL = 'ws://localhost:3001/ws'` and never read the environment,
// so on augment.didi.sh they each dialled the *visitor's* laptop and showed
// an empty surface behind a `closed` badge. Local dev hid it perfectly —
// the operator's machine really is running workspace-service on :3001.
// See [[Every-Remote-Hardcodes-The-Workspace-WS-To-Localhost-So-Prod-Loads-No-Data]].
//
// rsbuild inlines PUBLIC_-prefixed vars into import.meta.env at BUILD time,
// and it does so for plain .ts modules too — not just .svelte files. This
// module is consumed as source (packages/workspace has `main: ./src/index.ts`),
// so each app's own build substitutes its own PUBLIC_WS_URL here. Changing
// the value therefore requires a rebuild, never just a restart.

/** Dev fallback: the local docker-compose workspace-service. */
export const DEFAULT_WS_URL = 'ws://localhost:3001/ws';

/**
* The workspace WebSocket endpoint for this build.
*
* Prod must set `PUBLIC_WS_URL=wss://ws.augment.didi.sh/ws`. Note the `wss`:
* an insecure `ws://` socket opened from an `https://` page is blocked as
* mixed content, so a plain `ws://` value cannot work in production even
* when the host is right.
*/
export function resolveWsUrl(): string {
const fromEnv = (import.meta as { env?: Record<string, string> }).env?.PUBLIC_WS_URL;
return (typeof fromEnv === 'string' && fromEnv.length > 0 ? fromEnv : DEFAULT_WS_URL);
}

/**
* The matching HTTP origin for the same service — `ws(s)://host/ws` →
* `http(s)://host`. Used for plain fetches like `/config`.
*/
export function resolveHttpBase(wsUrl: string = resolveWsUrl()): string {
return wsUrl.replace(/^ws/, 'http').replace(/\/ws$/, '');
}
Loading
Loading